]> arthur.barton.de Git - ngircd-alex.git/commitdiff
Add new 'delayed' signal handlers.
authorFlorian Westphal <fw@strlen.de>
Fri, 10 Sep 2010 22:19:01 +0000 (00:19 +0200)
committerFlorian Westphal <fw@strlen.de>
Sat, 11 Sep 2010 09:36:12 +0000 (11:36 +0200)
Allows to defer/queue signal processing for execution on the next
event dispatch call, i.e. we can perform any signal action in
normal, non-signal context.

Example uses:
- Reload everything on HUP without writing a global "SIGHUP_received"
  variable
- Dump status of internal Lists on SIGUSR1, etc.

configure.in
src/ngircd/Makefile.am
src/ngircd/conn.c
src/ngircd/ngircd.c
src/ngircd/ngircd.h
src/ngircd/parse.c
src/ngircd/proc.c
src/ngircd/sighandlers.c [new file with mode: 0644]
src/ngircd/sighandlers.h [new file with mode: 0644]

index 7c5d0b614294a98180e29fb388190e9e93bdb6d8..b7e0ea1382f17fdf96956b8d32702f27b0bae326 100644 (file)
@@ -159,7 +159,7 @@ AC_CHECK_FUNCS([ \
        bind gethostbyaddr gethostbyname gethostname inet_ntoa \
        setsid setsockopt socket strcasecmp waitpid],,AC_MSG_ERROR([required function missing!]))
 
        bind gethostbyaddr gethostbyname gethostname inet_ntoa \
        setsid setsockopt socket strcasecmp waitpid],,AC_MSG_ERROR([required function missing!]))
 
-AC_CHECK_FUNCS(getaddrinfo getnameinfo inet_aton isdigit sigaction snprintf \
+AC_CHECK_FUNCS(getaddrinfo getnameinfo inet_aton isdigit sigaction sigprocmask snprintf \
  vsnprintf strdup strlcpy strlcat strtok_r)
 
 # -- Configuration options --
  vsnprintf strdup strlcpy strlcat strtok_r)
 
 # -- Configuration options --
index 4c9d9fa09c1ce5401b720b57dbee3f6d1e8349ad..8987c852a4d87588da9582b5e93e5e71929276cf 100644 (file)
@@ -21,7 +21,7 @@ sbin_PROGRAMS = ngircd
 ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \
        conn-ssl.c conn-zip.c hash.c io.c irc.c irc-channel.c irc-info.c irc-login.c \
        irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \
 ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \
        conn-ssl.c conn-zip.c hash.c io.c irc.c irc-channel.c irc-info.c irc-login.c \
        irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \
-       match.c op.c numeric.c pam.c parse.c proc.c rendezvous.c resolve.c
+       match.c op.c numeric.c pam.c parse.c proc.c rendezvous.c resolve.c sighandlers.c
 
 ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
 
 
 ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
 
index 78a20b055ea523a1692998a45e08c9d49bc1bd42..03e2905cc5af0e1afa70f4299627d0cfbe43a373 100644 (file)
@@ -477,11 +477,6 @@ Conn_InitListeners( void )
        unsigned int created = 0;
        char *copy, *listen_addr;
 
        unsigned int created = 0;
        char *copy, *listen_addr;
 
-       if (!io_library_init(CONNECTION_POOL)) {
-               Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno));
-               return -1;
-       }
-
        assert(Conf_ListenAddress);
 
        /* can't use Conf_ListenAddress directly, see below */
        assert(Conf_ListenAddress);
 
        /* can't use Conf_ListenAddress directly, see below */
index 4d329d2ade1c89724bf975c98cb758f12fa310b0..de0b490dab81a5aa025a859ac3801c17ffb602c8 100644 (file)
@@ -29,7 +29,6 @@
 #include <time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 #include <fcntl.h>
 #include <pwd.h>
 #include <grp.h>
 #include <fcntl.h>
 #include <pwd.h>
 #include <grp.h>
@@ -46,6 +45,8 @@
 #include "lists.h"
 #include "log.h"
 #include "parse.h"
 #include "lists.h"
 #include "log.h"
 #include "parse.h"
+#include "sighandlers.h"
+#include "io.h"
 #include "irc.h"
 
 #ifdef ZEROCONF
 #include "irc.h"
 
 #ifdef ZEROCONF
@@ -56,9 +57,6 @@
 #include "ngircd.h"
 
 
 #include "ngircd.h"
 
 
-static void Initialize_Signal_Handler PARAMS(( void ));
-static void Signal_Handler PARAMS(( int Signal ));
-
 static void Show_Version PARAMS(( void ));
 static void Show_Help PARAMS(( void ));
 
 static void Show_Version PARAMS(( void ));
 static void Show_Help PARAMS(( void ));
 
@@ -292,8 +290,15 @@ main( int argc, const char *argv[] )
                 * when not running in "no daemon" mode: */
                if( ! NGIRCd_NoDaemon ) Log_InitErrorfile( );
 #endif
                 * when not running in "no daemon" mode: */
                if( ! NGIRCd_NoDaemon ) Log_InitErrorfile( );
 #endif
+               if (!io_library_init(CONNECTION_POOL)) {
+                       Log(LOG_ALERT, "Fatal: Cannot initialize IO routines: %s", strerror(errno));
+                       exit(1);
+               }
 
 
-               Initialize_Signal_Handler( );
+               if (!Signals_Init()) {
+                       Log(LOG_ALERT, "Fatal: Could not set up signal handlers: %s", strerror(errno));
+                       exit(1);
+               }
 
                /*
                 * create protocol and server identification.
 
                /*
                 * create protocol and server identification.
@@ -475,80 +480,6 @@ NGIRCd_Rehash( void )
 } /* NGIRCd_Rehash */
 
 
 } /* NGIRCd_Rehash */
 
 
-/**
- * Initialize the signal handler.
- */
-static void
-Initialize_Signal_Handler( void )
-{
-#ifdef HAVE_SIGACTION
-       struct sigaction saction;
-
-       memset( &saction, 0, sizeof( saction ));
-       saction.sa_handler = Signal_Handler;
-#ifdef SA_RESTART
-       saction.sa_flags |= SA_RESTART;
-#endif
-#ifdef SA_NOCLDWAIT
-       saction.sa_flags |= SA_NOCLDWAIT;
-#endif
-
-       sigaction(SIGINT, &saction, NULL);
-       sigaction(SIGQUIT, &saction, NULL);
-       sigaction(SIGTERM, &saction, NULL);
-       sigaction(SIGHUP, &saction, NULL);
-       sigaction(SIGCHLD, &saction, NULL);
-
-       /* we handle write errors properly; ignore SIGPIPE */
-       saction.sa_handler = SIG_IGN;
-       sigaction(SIGPIPE, &saction, NULL);
-#else
-       signal(SIGINT, Signal_Handler);
-       signal(SIGQUIT, Signal_Handler);
-       signal(SIGTERM, Signal_Handler);
-       signal(SIGHUP, Signal_Handler);
-       signal(SIGCHLD, Signal_Handler);
-
-       signal(SIGPIPE, SIG_IGN);
-#endif
-} /* Initialize_Signal_Handler */
-
-
-/**
- * Signal handler of ngIRCd.
- * This function is called whenever ngIRCd catches a signal sent by the
- * user and/or the system to it. For example SIGTERM and SIGHUP.
- * @param Signal Number of the signal to handle.
- */
-static void
-Signal_Handler( int Signal )
-{
-       switch( Signal )
-       {
-               case SIGTERM:
-               case SIGINT:
-               case SIGQUIT:
-                       /* shut down sever */
-                       NGIRCd_SignalQuit = true;
-                       break;
-               case SIGHUP:
-                       /* re-read configuration */
-                       NGIRCd_SignalRehash = true;
-                       break;
-               case SIGCHLD:
-                       /* child-process exited, avoid zombies */
-                       while (waitpid( -1, NULL, WNOHANG) > 0)
-                               ;
-                       break;
-#ifdef DEBUG
-               default:
-                       /* unbekanntes bzw. unbehandeltes Signal */
-                       Log( LOG_DEBUG, "Got signal %d! Ignored.", Signal );
-#endif
-       }
-} /* Signal_Handler */
-
-
 /**
  * Display copyright and version information of ngIRCd on the console.
  */
 /**
  * Display copyright and version information of ngIRCd on the console.
  */
index b615f2631e649ba85ae796c0fe2f681f291c72fc..bd0aed0a7b5509337a1c3c460d00c43ed4d7f9ca 100644 (file)
@@ -21,6 +21,8 @@
 
 #include "defines.h"
 
 
 #include "defines.h"
 
+#define C_ARRAY_SIZE(x)        (sizeof(x)/sizeof((x)[0]))
+
 
 GLOBAL time_t NGIRCd_Start;            /* Startzeitpunkt des Daemon */
 GLOBAL char NGIRCd_StartStr[64];
 
 GLOBAL time_t NGIRCd_Start;            /* Startzeitpunkt des Daemon */
 GLOBAL char NGIRCd_StartStr[64];
index 95c49a513db779063e79429bccec40d8363b5191..479b300450e4dcfd4f601b703bc4a573fc3f8a77 100644 (file)
@@ -120,8 +120,6 @@ static bool Validate_Args PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
 
 static bool Handle_Request PARAMS(( CONN_ID Idx, REQUEST *Req ));
 
 
 static bool Handle_Request PARAMS(( CONN_ID Idx, REQUEST *Req ));
 
-#define ARRAY_SIZE(x)  (sizeof(x)/sizeof((x)[0]))
-
 /**
  * Return the pointer to the global "IRC command structure".
  * This structure, an array of type "COMMAND" describes all the IRC commands
 /**
  * Return the pointer to the global "IRC command structure".
  * This structure, an array of type "COMMAND" describes all the IRC commands
@@ -397,7 +395,7 @@ Handle_Numeric(CLIENT *client, REQUEST *Req)
                /* This server is the target of the numeric */
                num = atoi(Req->command);
 
                /* This server is the target of the numeric */
                num = atoi(Req->command);
 
-               for (i = 0; i < (int) ARRAY_SIZE(Numerics); i++) {
+               for (i = 0; i < (int) C_ARRAY_SIZE(Numerics); i++) {
                        if (num == Numerics[i].numeric) {
                                if (!Numerics[i].function)
                                        return CONNECTED;
                        if (num == Numerics[i].numeric) {
                                if (!Numerics[i].function)
                                        return CONNECTED;
index dbcff6f1aa5cfe0edf16ac4b90aace58a681698f..614aef4c39a741044c745ac4c5e7232f1a54d2bf 100644 (file)
@@ -26,6 +26,7 @@
 #include "conn.h"
 
 #include "exp.h"
 #include "conn.h"
 
 #include "exp.h"
+#include "sighandlers.h"
 #include "proc.h"
 
 /**
 #include "proc.h"
 
 /**
@@ -67,6 +68,7 @@ Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short), int timeout
                return -1;
        case 0:
                /* New child process: */
                return -1;
        case 0:
                /* New child process: */
+               Signals_Exit();
                signal(SIGTERM, Proc_GenericSignalHandler);
                signal(SIGALRM, Proc_GenericSignalHandler);
                close(pipefds[0]);
                signal(SIGTERM, Proc_GenericSignalHandler);
                signal(SIGALRM, Proc_GenericSignalHandler);
                close(pipefds[0]);
diff --git a/src/ngircd/sighandlers.c b/src/ngircd/sighandlers.c
new file mode 100644 (file)
index 0000000..f3ce24f
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * ngIRCd -- The Next Generation IRC Daemon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * Please read the file COPYING, README and AUTHORS for more information.
+ */
+
+#include "portab.h"
+
+/**
+ * @file
+ * Signal Handlers: Actions to be performed when the program
+ * receives a signal.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "imp.h"
+#include "io.h"
+#include "log.h"
+#include "ngircd.h"
+#include "sighandlers.h"
+
+static int signalpipe[2];
+
+static void Signal_Block(int sig)
+{
+#ifdef HAVE_SIGPROCMASK
+       sigset_t set;
+
+       sigemptyset(&set);
+       sigaddset(&set, sig);
+
+       sigprocmask(SIG_BLOCK, &set, NULL);
+#endif
+}
+
+
+static void Signal_Unblock(int sig)
+{
+#ifdef HAVE_SIGPROCMASK
+       sigset_t set;
+
+       sigemptyset(&set);
+       sigaddset(&set, sig);
+
+       sigprocmask(SIG_UNBLOCK, &set, NULL);
+#endif
+}
+
+
+/**
+ * Signal handler of ngIRCd.
+ * This function is called whenever ngIRCd catches a signal sent by the
+ * user and/or the system to it. For example SIGTERM and SIGHUP.
+ *
+ * It blocks the signal and queues it for later execution by Signal_Handler_BH.
+ * @param Signal Number of the signal to handle.
+ */
+static void Signal_Handler(int Signal)
+{
+       switch (Signal) {
+       case SIGTERM:
+       case SIGINT:
+       case SIGQUIT:
+               /* shut down sever */
+               NGIRCd_SignalQuit = true;
+               return;
+       case SIGHUP:
+               /* re-read configuration */
+               NGIRCd_SignalRehash = true;
+               return;
+       case SIGCHLD:
+               /* child-process exited, avoid zombies */
+               while (waitpid( -1, NULL, WNOHANG) > 0)
+                       ;
+               return;
+       }
+
+       /*
+        * other signal: queue for later execution.
+        * This has the advantage that we are not restricted
+        * to functions that can be called safely from signal handlers.
+        */
+       if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1)
+               Signal_Block(Signal);
+} /* Signal_Handler */
+
+
+/**
+ * Signal processing handler of ngIRCd.
+ * This function is called from the main conn event loop in (io_dispatch)
+ * whenever ngIRCd has queued a signal.
+ *
+ * This function runs in normal context, not from the real signal handler,
+ * thus its not necessary to only use functions that are signal safe.
+ * @param Signal Number of the signal that was queued.
+ */
+static void Signal_Handler_BH(int Signal)
+{
+       switch (Signal) {
+#ifdef DEBUG
+       default:
+               Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
+#endif
+       }
+       Signal_Unblock(Signal);
+}
+
+static void Sig_callback(int fd, short UNUSED what)
+{
+       int sig, ret;
+       (void) what;
+
+       do {
+               ret = read(fd, &sig, sizeof(sig));
+               if (ret == sizeof(int))
+                       Signal_Handler_BH(sig);
+       } while (ret == sizeof(int));
+
+       if (ret == -1) {
+               if (errno == EAGAIN || errno == EINTR)
+                       return;
+
+               Log(LOG_EMERG, "read from signal pipe: %s", strerror(errno));
+               exit(1);
+       }
+
+       Log(LOG_EMERG, "EOF on signal pipe");
+       exit(1);
+}
+
+
+static const int signals_catch[] = { SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2 };
+/**
+ * Initialize the signal handlers, catch
+ * those signals we are interested in and sets SIGPIPE to be ignored.
+ * @return true if initialization was sucessful.
+ */
+bool Signals_Init(void)
+{
+       size_t i;
+#ifdef HAVE_SIGACTION
+       struct sigaction saction;
+#endif
+
+       if (pipe(signalpipe))
+               return false;
+
+       if (!io_setnonblock(signalpipe[0]) ||
+           !io_setnonblock(signalpipe[1]))
+               return false;
+       if (!io_setcloexec(signalpipe[0]) ||
+           !io_setcloexec(signalpipe[1]))
+               return false;
+#ifdef HAVE_SIGACTION
+       memset( &saction, 0, sizeof( saction ));
+       saction.sa_handler = Signal_Handler;
+#ifdef SA_RESTART
+       saction.sa_flags |= SA_RESTART;
+#endif
+#ifdef SA_NOCLDWAIT
+       saction.sa_flags |= SA_NOCLDWAIT;
+#endif
+
+       for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
+               sigaction(signals_catch[i], &saction, NULL);
+
+       /* we handle write errors properly; ignore SIGPIPE */
+       saction.sa_handler = SIG_IGN;
+       sigaction(SIGPIPE, &saction, NULL);
+#else
+       for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
+               signal(signals_catch[i], Signal_Handler);
+
+       signal(SIGPIPE, SIG_IGN);
+#endif
+       return io_event_create(signalpipe[0], IO_WANTREAD,
+                                       Sig_callback);
+} /* Initialize_Signal_Handler */
+
+
+/**
+ * Restores signals to their default behaviour.
+ *
+ * This should be called after a fork() in the new
+ * child prodcess, especially when we are about to call
+ * 3rd party code (e.g. PAM).
+ */
+void Signals_Exit(void)
+{
+       size_t i;
+#ifdef HAVE_SIGACTION
+       struct sigaction saction;
+
+       memset(&saction, 0, sizeof(saction));
+       saction.sa_handler = SIG_DFL;
+
+       for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
+               sigaction(signals_catch[i], &saction, NULL);
+       sigaction(SIGPIPE, &saction, NULL);
+#else
+       for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
+               sigaction(signals_catch[i], &saction, NULL);
+       signal(SIGPIPE, SIG_DFL);
+#endif
+       close(signalpipe[1]);
+       close(signalpipe[0]);
+}
+
+/* -eof- */
diff --git a/src/ngircd/sighandlers.h b/src/ngircd/sighandlers.h
new file mode 100644 (file)
index 0000000..5df8f22
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * Please read the file COPYING, README and AUTHORS for more information.
+ */
+
+#ifndef signals_included_
+#define signals_included_
+
+#include "portab.h"
+
+bool Signals_Init(void);
+void Signals_Exit(void);
+
+
+#endif