From 2a17be71ba0d6b09d0fafc0c198df528cc423b7f Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Sun, 3 May 2009 14:01:41 +0000 Subject: added signal handling without races --- ChangeLog | 4 ++ src/sig_handler.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++-------- src/sig_handler.h | 7 ++- src/uanytun.c | 38 ++++++++++------ 4 files changed, 142 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2034049..97e74a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009.??.?? -- Version 0.? + +* added signal handling without races + 2009.05.01 -- Version 0.3 * updated to new protocol specification (extended label and crypto role) diff --git a/src/sig_handler.c b/src/sig_handler.c index 6fd4b85..7a1ad74 100644 --- a/src/sig_handler.c +++ b/src/sig_handler.c @@ -36,29 +36,123 @@ #include "log.h" #include +#include +#include +#include +#include + #include "sig_handler.h" -volatile sig_atomic_t signal_exit = 0; +#include + + +static int sig_pipe_fds[2]; + -void signal_init() +static void sig_handler(int sig) { - signal(SIGINT, handle_signal); - signal(SIGQUIT, handle_signal); - signal(SIGTERM, handle_signal); - signal(SIGHUP, handle_signal); - signal(SIGUSR1, handle_signal); - signal(SIGUSR2, handle_signal); + sigset_t set; + int ret = read(sig_pipe_fds[0], &set, sizeof(sigset_t)); + if(ret != sizeof(sigset_t)) + sigemptyset(&set); + + sigaddset(&set, sig); + ret = write(sig_pipe_fds[1], &set, sizeof(sigset_t)); +} + + +int signal_init() +{ + if(pipe(sig_pipe_fds)) { + log_printf(ERROR, "signal handling init failed (pipe error: %s)", strerror(errno)); + return -1; + } + + int i; + for(i=0; i<2; ++i) { + int fd_flags = fcntl(sig_pipe_fds[i], F_GETFL); + if(fd_flags == -1) { + log_printf(ERROR, "signal handling init failed (pipe fd[%d] read flags error: %s)", i, strerror(errno)); + return -1; + } + if(fcntl(sig_pipe_fds[i], F_SETFL, fd_flags | O_NONBLOCK) == -1){ + log_printf(ERROR, "signal handling init failed (pipe fd[%d] write flags error: %s)", i, strerror(errno)); + return -1; + } + } + + struct sigaction act; + act.sa_handler = sig_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + + if((sigaction(SIGINT, &act, NULL) < 0) || + (sigaction(SIGQUIT, &act, NULL) < 0) || + (sigaction(SIGTERM, &act, NULL) < 0) || + (sigaction(SIGHUP, &act, NULL) < 0) || + (sigaction(SIGUSR1, &act, NULL) < 0) || + (sigaction(SIGUSR2, &act, NULL) < 0)) { + + log_printf(ERROR, "signal handling init failed (sigaction error: %s)", strerror(errno)); + close(sig_pipe_fds[0]); + close(sig_pipe_fds[1]); + } + + return sig_pipe_fds[0]; } -void handle_signal(int sig) +int signal_handle() { - switch(sig) { - case SIGINT: log_printf(NOTICE, "SIG-Int caught, exitting"); signal_exit = 1; break; - case SIGQUIT: log_printf(NOTICE, "SIG-Quit caught, exitting"); signal_exit = 1; break; - case SIGTERM: log_printf(NOTICE, "SIG-Term caught, exitting"); signal_exit = 1; break; - case SIGHUP: log_printf(NOTICE, "SIG-Hup caught"); break; - case SIGUSR1: log_printf(NOTICE, "SIG-Usr1 caught"); break; - case SIGUSR2: log_printf(NOTICE, "SIG-Usr2 caught"); break; - default: log_printf(NOTICE, "Signal %d caught, ignoring", sig); break; + sigset_t set, oldset, tmpset; + + sigemptyset(&tmpset); + sigaddset(&tmpset, SIGINT); + sigaddset(&tmpset, SIGQUIT); + sigaddset(&tmpset, SIGTERM); + sigaddset(&tmpset, SIGHUP); + sigaddset(&tmpset, SIGUSR1); + sigaddset(&tmpset, SIGUSR2); + sigprocmask(SIG_BLOCK, &tmpset, &oldset); + + int ret = read(sig_pipe_fds[0], &set, sizeof(sigset_t)); + if(ret != sizeof(sigset_t)) + sigemptyset(&set); + + int return_value = 0; + int sig; + for(sig=1; sig < _NSIG; ++sig) { + if(sigismember(&set, sig)) { + switch(sig) { + case SIGINT: log_printf(NOTICE, "SIG-Int caught, exitting"); return_value = 1; break; + case SIGQUIT: log_printf(NOTICE, "SIG-Quit caught, exitting"); return_value = 1; break; + case SIGTERM: log_printf(NOTICE, "SIG-Term caught, exitting"); return_value = 1; break; + case SIGHUP: log_printf(NOTICE, "SIG-Hup caught"); break; + case SIGUSR1: log_printf(NOTICE, "SIG-Usr1 caught"); break; + case SIGUSR2: log_printf(NOTICE, "SIG-Usr2 caught"); break; + default: log_printf(WARNING, "unknown signal %d caught, ignoring", sig); break; + } + sigdelset(&set, sig); + } } + + sigprocmask(SIG_SETMASK, &oldset, NULL); + return return_value; +} + +void signal_stop() +{ + struct sigaction act; + act.sa_handler = SIG_DFL; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + sigaction(SIGINT, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGUSR1, &act, NULL); + sigaction(SIGUSR2, &act, NULL); + + close(sig_pipe_fds[0]); + close(sig_pipe_fds[1]); } diff --git a/src/sig_handler.h b/src/sig_handler.h index a7779be..9fd6386 100644 --- a/src/sig_handler.h +++ b/src/sig_handler.h @@ -37,9 +37,8 @@ #include -extern volatile sig_atomic_t signal_exit; - -void signal_init(); -void handle_signal(int sig); +int signal_init(); +int signal_handle(); +void signal_stop(); #endif diff --git a/src/uanytun.c b/src/uanytun.c index c9c6c44..c20cbeb 100644 --- a/src/uanytun.c +++ b/src/uanytun.c @@ -249,7 +249,7 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt) encrypted_packet_t encrypted_packet; encrypted_packet_init(&encrypted_packet, opt->auth_tag_length_); seq_nr_t seq_nr = 0; - fd_set readfds; + fd_set readfds, readyfds; cipher_t c; auth_algo_t aa; @@ -260,36 +260,45 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt) if(ret) return ret; - signal_init(); + FD_ZERO(&readfds); + FD_SET(dev->fd_, &readfds); + FD_SET(sock->fd_, &readfds); + int nfds = dev->fd_ > sock->fd_ ? dev->fd_ : sock->fd_; + int return_value = 0; - while(!return_value) { - FD_ZERO(&readfds); - FD_SET(dev->fd_, &readfds); - FD_SET(sock->fd_, &readfds); - int nfds = dev->fd_ > sock->fd_ ? dev->fd_+1 : sock->fd_+1; + int sig_fd = signal_init(); + if(sig_fd < 0) + return_value -1; - int ret = select(nfds, &readfds, NULL, NULL, NULL); + FD_SET(sig_fd, &readfds); + nfds = (nfds < sig_fd) ? sig_fd : nfds; + + while(!return_value) { + memcpy(&readyfds, &readfds, sizeof(readyfds)); + int ret = select(nfds + 1, &readyfds, NULL, NULL, NULL); if(ret == -1 && errno != EINTR) { log_printf(ERROR, "select returned with error: %s", strerror(errno)); return_value = -1; break; } - if(!ret) + if(!ret || ret == -1) continue; - if(signal_exit) { - return_value = 1; - break; + if(FD_ISSET(sig_fd, &readyfds)) { + if(signal_handle()) { + return_value = 1; + break; + } } - if(FD_ISSET(dev->fd_, &readfds)) { + if(FD_ISSET(dev->fd_, &readyfds)) { return_value = process_tun_data(dev, sock, opt, &plain_packet, &encrypted_packet, &c, &aa, &kd, seq_nr); seq_nr++; if(return_value) break; } - if(FD_ISSET(sock->fd_, &readfds)) { + if(FD_ISSET(sock->fd_, &readyfds)) { return_value = process_sock_data(dev, sock, opt, &plain_packet, &encrypted_packet, &c, &aa, &kd, &seq_win); if(return_value) break; @@ -302,6 +311,7 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt) key_derivation_close(&kd); #endif seq_win_clear(&seq_win); + signal_stop(); return return_value; } -- cgit v1.2.3