summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--src/sig_handler.c128
-rw-r--r--src/sig_handler.h7
-rw-r--r--src/uanytun.c38
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 <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <errno.h>
+
#include "sig_handler.h"
-volatile sig_atomic_t signal_exit = 0;
+#include <stdio.h>
+
+
+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 <signal.h>
-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;
}