mirror of
https://github.com/osmarks/ngircd.git
synced 2024-12-12 09:50:29 +00:00
Add new 'delayed' signal handlers.
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.
This commit is contained in:
parent
c135d0dded
commit
1fe17e246c
@ -159,7 +159,7 @@ AC_CHECK_FUNCS([ \
|
||||
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 --
|
||||
|
@ -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 \
|
||||
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
|
||||
|
||||
|
@ -477,11 +477,6 @@ Conn_InitListeners( void )
|
||||
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 */
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
@ -46,6 +45,8 @@
|
||||
#include "lists.h"
|
||||
#include "log.h"
|
||||
#include "parse.h"
|
||||
#include "sighandlers.h"
|
||||
#include "io.h"
|
||||
#include "irc.h"
|
||||
|
||||
#ifdef ZEROCONF
|
||||
@ -56,9 +57,6 @@
|
||||
#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 ));
|
||||
|
||||
@ -292,8 +290,15 @@ main( int argc, const char *argv[] )
|
||||
* 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.
|
||||
@ -475,80 +480,6 @@ NGIRCd_Rehash( void )
|
||||
} /* 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.
|
||||
*/
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#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];
|
||||
|
@ -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 ));
|
||||
|
||||
#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
|
||||
@ -397,7 +395,7 @@ Handle_Numeric(CLIENT *client, REQUEST *Req)
|
||||
/* 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;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "conn.h"
|
||||
|
||||
#include "exp.h"
|
||||
#include "sighandlers.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: */
|
||||
Signals_Exit();
|
||||
signal(SIGTERM, Proc_GenericSignalHandler);
|
||||
signal(SIGALRM, Proc_GenericSignalHandler);
|
||||
close(pipefds[0]);
|
||||
|
220
src/ngircd/sighandlers.c
Normal file
220
src/ngircd/sighandlers.c
Normal file
@ -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- */
|
18
src/ngircd/sighandlers.h
Normal file
18
src/ngircd/sighandlers.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user