]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
signal handling.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 5 Feb 2007 16:46:40 +0000 (16:46 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 5 Feb 2007 16:46:40 +0000 (16:46 +0000)
git-svn-id: file:///svn/unbound/trunk@68 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/worker.c
daemon/worker.h
util/netevent.c
util/netevent.h

index 3666ca44bc68dcf6190e0f37b907a462d50d8d65..0252adfd8cb9e8a9539ffa2a08fa75d74f414be4 100644 (file)
@@ -51,6 +51,7 @@
 #endif
 #include <netdb.h>
 #include <errno.h>
+#include <signal.h>
 
 /** 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);
 }
index 30f17167257839d69bafe58b5aab65e9d8932686..c89885aa7ff389701bb1efdd30dbf238df00cf52 100644 (file)
@@ -79,6 +79,9 @@ struct worker {
 
        /** length of fwd_addr */
        socklen_t fwd_addrlen;
+
+       /** the signal handler */
+       struct comm_signal *comsig;
 };
 
 /**
index 1067b73306761649c4d814820dd5329119406547..5b2d81a96e2e91185d36f04f666845a60b4b7db7 100644 (file)
@@ -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);
+}
index 02ae94b1004c2dfcc2b7abb14da09a27aaf12a83..bca68557cc0c00cdd6489fc71da932a6ac27459c 100644 (file)
@@ -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 */