#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
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)
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;
return;
listen_delete(worker->front);
outside_network_delete(worker->back);
+ comm_signal_delete(worker->comsig);
comm_base_delete(worker->base);
free(worker);
}
/** length of fwd_addr */
socklen_t fwd_addrlen;
+
+ /** the signal handler */
+ struct comm_signal *comsig;
};
/**
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.
* @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,
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");
}
}
{
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);
+}
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.
*/
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.
*/
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 */