From: Wouter Wijngaards Date: Mon, 5 Feb 2007 16:46:40 +0000 (+0000) Subject: signal handling. X-Git-Tag: release-0.0~57 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=988be5cc7fec12b3099a173c2f6df3c6514049ee;p=thirdparty%2Funbound.git signal handling. git-svn-id: file:///svn/unbound/trunk@68 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/worker.c b/daemon/worker.c index 3666ca44b..0252adfd8 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -51,6 +51,7 @@ #endif #include #include +#include /** timeout in seconds for UDP queries to auth servers. TODO: proper rtt */ #define UDP_QUERY_TIMEOUT 5 @@ -169,6 +170,30 @@ static int worker_handle_request(struct comm_point* c, void* arg, int error, return 0; } +/** worker signal callback */ +void worker_sighandler(int sig, void* arg) +{ + /* note that log, print, syscalls here give race conditions. */ + struct worker* worker = (struct worker*)arg; + switch(sig) { + case SIGHUP: + log_info("caught signal SIGHUP"); + comm_base_exit(worker->base); + break; + case SIGINT: + log_info("caught signal SIGINT"); + comm_base_exit(worker->base); + break; + case SIGQUIT: + log_info("caught signal SIGQUIT"); + comm_base_exit(worker->base); + break; + default: + log_err("unknown signal: %d, ignored", sig); + break; + } +} + struct worker* worker_init(const char* port, int do_ip4, int do_ip6, int do_udp, int do_tcp, size_t buffer_size, size_t numports, int base_port) @@ -180,27 +205,36 @@ struct worker* worker_init(const char* port, int do_ip4, int do_ip6, worker->base = comm_base_create(); if(!worker->base) { log_err("could not create event handling base"); + worker_delete(worker); + return NULL; + } + worker->comsig = comm_signal_create(worker->base, worker_sighandler, + worker); + if(!worker->comsig || !comm_signal_bind(worker->comsig, SIGHUP) + || !comm_signal_bind(worker->comsig, SIGINT) + || !comm_signal_bind(worker->comsig, SIGQUIT)) { + log_err("could not create signal handlers"); + worker_delete(worker); return NULL; } worker->front = listen_create(worker->base, 0, NULL, port, do_ip4, do_ip6, do_udp, do_tcp, buffer_size, worker_handle_request, worker); if(!worker->front) { - comm_base_delete(worker->base); + worker_delete(worker); log_err("could not create listening sockets"); return NULL; } worker->back = outside_network_create(worker->base, buffer_size, numports, NULL, 0, do_ip4, do_ip6, base_port); if(!worker->back) { - comm_base_delete(worker->base); log_err("could not create outgoing sockets"); return NULL; } /* init random(), large table size. */ if(!initstate(time(NULL)^getpid(), worker->rndstate, RND_STATE_SIZE)) { log_err("could not init random numbers."); - comm_base_delete(worker->base); + worker_delete(worker); return NULL; } return worker; @@ -217,6 +251,7 @@ void worker_delete(struct worker* worker) return; listen_delete(worker->front); outside_network_delete(worker->back); + comm_signal_delete(worker->comsig); comm_base_delete(worker->base); free(worker); } diff --git a/daemon/worker.h b/daemon/worker.h index 30f171672..c89885aa7 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -79,6 +79,9 @@ struct worker { /** length of fwd_addr */ socklen_t fwd_addrlen; + + /** the signal handler */ + struct comm_signal *comsig; }; /** diff --git a/util/netevent.c b/util/netevent.c index 1067b7330..5b2d81a96 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -75,6 +75,18 @@ struct internal_timer { uint8_t enabled; }; +/** + * Internal signal structure, to store signal event in. + */ +struct internal_signal { + /** libevent event type, alloced here */ + struct event ev; + /** the commpoint it is part of */ + struct comm_signal* comm; + /** next in signal list */ + struct internal_signal* next; +}; + /** * handle libevent callback for udp comm point. * @param fd: file descriptor. @@ -107,10 +119,19 @@ static void comm_point_tcp_handle_callback(int fd, short event, void* arg); * @param fd: file descriptor (always -1). * @param event: event bits from libevent: * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT. - * @param arg: the comm_point structure. + * @param arg: the comm_timer structure. */ static void comm_timer_callback(int fd, short event, void* arg); +/** + * handle libevent callback for signal comm. + * @param fd: file descriptor (used signal number). + * @param event: event bits from libevent: + * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT. + * @param arg: the internal commsignal structure. + */ +static void comm_signal_callback(int fd, short event, void* arg); + /** create a tcp handler with a parent */ static struct comm_point* comm_point_create_tcp_handler( struct comm_base *base, struct comm_point* parent, size_t bufsize, @@ -156,12 +177,17 @@ void comm_base_dispatch(struct comm_base* b) { int retval; - while(1) { - retval = event_base_dispatch(b->eb->base); - if(retval != 0) { - log_err("event_dispatch returned error %d, " - "errno is %s", retval, strerror(errno)); - } + retval = event_base_dispatch(b->eb->base); + if(retval != 0) { + fatal_exit("event_dispatch returned error %d, " + "errno is %s", retval, strerror(errno)); + } +} + +void comm_base_exit(struct comm_base* b) +{ + if(event_base_loopexit(b->eb->base, NULL) != 0) { + log_err("Could not loopexit"); } } @@ -500,3 +526,70 @@ comm_timer_is_set(struct comm_timer* timer) { return (int)timer->ev_timer->enabled; } + +struct comm_signal* comm_signal_create(struct comm_base* base, + void (*callback)(int, void*), void* cb_arg) +{ + struct comm_signal* com = (struct comm_signal*)malloc( + sizeof(struct comm_signal)); + if(!com) { + log_err("malloc failed"); + return NULL; + } + com->base = base; + com->callback = callback; + com->cb_arg = cb_arg; + com->ev_signal = NULL; + return com; +} + +static void comm_signal_callback(int sig, short event, void* arg) +{ + struct internal_signal* entry = (struct internal_signal*)arg; + if(!(event & EV_SIGNAL)) + return; + (*entry->comm->callback)(sig, entry->comm->cb_arg); +} + +int comm_signal_bind(struct comm_signal* comsig, int sig) +{ + struct internal_signal* entry = (struct internal_signal*)calloc(1, + sizeof(struct internal_signal)); + if(!entry) { + log_err("malloc failed"); + return 0; + } + log_assert(comsig); + entry->comm = comsig; + /* add signal event */ + signal_set(&entry->ev, sig, comm_signal_callback, entry); + if(event_base_set(comsig->base->eb->base, &entry->ev) != 0) { + log_err("Could not set signal base"); + free(entry); + return 0; + } + if(signal_add(&entry->ev, NULL) != 0) { + log_err("Could not add signal handler"); + free(entry); + return 0; + } + /* link into list */ + entry->next = comsig->ev_signal; + comsig->ev_signal = entry; + return 1; +} + +void comm_signal_delete(struct comm_signal* comsig) +{ + struct internal_signal* p, *np; + if(!comsig) + return; + p=comsig->ev_signal; + while(p) { + np = p->next; + signal_del(&p->ev); + free(p); + p = np; + } + free(comsig); +} diff --git a/util/netevent.h b/util/netevent.h index 02ae94b10..bca68557c 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -199,6 +199,23 @@ struct comm_timer { void* cb_arg; }; +/** + * Structure only for signal events. + */ +struct comm_signal { + /** the communication base */ + struct comm_base* base; + + /** the internal event stuff */ + struct internal_signal* ev_signal; + + /** callback function, takes signal number and user arg */ + void (*callback)(int, void*); + + /** callback user argument */ + void* cb_arg; +}; + /** * Create a new comm base. * @return: the new comm base. NULL on error. @@ -218,6 +235,12 @@ void comm_base_delete(struct comm_base* b); */ void comm_base_dispatch(struct comm_base* b); +/** + * Exit from dispatch loop. + * @param b: the communicatio base that is in dispatch(). + */ +void comm_base_exit(struct comm_base* b); + /** * Create an UDP comm point. Calls malloc. * setups the structure with the parameters you provide. @@ -327,4 +350,28 @@ void comm_timer_delete(struct comm_timer* timer); */ int comm_timer_is_set(struct comm_timer* timer); +/** + * Create a signal handler. + * @param base: communication base to use. + * @param callback: called when signal is caught. + * @param cb_arg: user argument to callback + * @return: the signal struct (bind it to a signal) or NULL on error. + */ +struct comm_signal* comm_signal_create(struct comm_base* base, + void (*callback)(int, void*), void* cb_arg); + +/** + * Bind signal struct to catch a signal. + * @param comsig: the communication point, with callback information. + * @param sig: signal number. + * @return: true on success. false on error. + */ +int comm_signal_bind(struct comm_signal* comsig, int sig); + +/** + * Delete the signal communication point. + * @param comsig: to delete. + */ +void comm_signal_delete(struct comm_signal* comsig); + #endif /* NET_EVENT_H */