diff options
author | David Härdeman <david@hardeman.nu> | 2020-06-22 12:35:21 +0200 |
---|---|---|
committer | David Härdeman <david@hardeman.nu> | 2020-06-22 12:35:21 +0200 |
commit | 2fe1271d25eae0f30401fb52330db3a324504952 (patch) | |
tree | 3ae0bdb7c367ebc9199f712679095e28042e27c2 | |
parent | d74bcf2dadfa4fc6c432ba0585b6dc4a77e81f0e (diff) |
Split out signal handling to a separate file
-rw-r--r-- | main.c | 168 | ||||
-rw-r--r-- | main.h | 4 | ||||
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | signal-handler.c | 193 | ||||
-rw-r--r-- | signal-handler.h | 8 |
5 files changed, 209 insertions, 165 deletions
@@ -10,14 +10,13 @@ #include <fcntl.h> #include <stdbool.h> #include <getopt.h> -#include <sys/signalfd.h> -#include <signal.h> #include <systemd/sd-daemon.h> #include <cap-ng.h> #include <pwd.h> #include <grp.h> #include "main.h" +#include "signal-handler.h" #include "uring.h" #include "config-parse.h" #include "server.h" @@ -537,26 +536,7 @@ cfg_apply() } } -struct signalfd_ev { - struct uring_task task; - struct uring_task_buf tbuf; - int pipe[2]; -}; - -static void -signalfd_free(struct uring_task *task) -{ - struct signalfd_ev *signal = container_of(task, struct signalfd_ev, task); - - assert_return(task); - - debug(DBG_SIG, "called"); - close(signal->pipe[PIPE_WR]); - cfg->signal = NULL; - xfree(signal); -} - -static void +void dump_tree() { struct server *server; @@ -568,9 +548,8 @@ dump_tree() info("Dumping Tree"); info("============"); uring_task_refdump(&cfg->task); - if (cfg->signal) - uring_task_refdump(&cfg->signal->task); uring_refdump(); + signal_refdump(); idle_refdump(); igmp_refdump(); announce_refdump(); @@ -581,145 +560,6 @@ dump_tree() info("\n\n"); } -static void -signalfd_read(struct uring_task *task, int res) -{ - struct signalfd_ev *signal = container_of(task, struct signalfd_ev, task); - struct server *server, *stmp; - static unsigned count = 0; - siginfo_t *si; - - assert_return(task); - assert_task_alive(DBG_SIG, task); - - si = (siginfo_t *)task->tbuf->buf; - if (res != sizeof(*si)) - die("error in signalfd (%i)", res); - - switch (si->si_signo) { - case SIGUSR1: { - struct dns_async *dns; - - debug(DBG_SIG, "Got a SIGUSR1"); - if (si->si_code != SI_ASYNCNL || !si->si_ptr) { - error("SIGUSR1: unexpected values in siginfo"); - goto out; - } - - dns = si->si_ptr; - if (!dns->cb) { - error("DNS callback not set"); - goto out; - } - - debug(DBG_DNS, "DNS lookup complete, dns: %p, dns->cb: %p", - dns, dns->cb); - dns->cb(dns); - break; - } - - case SIGUSR2: - debug(DBG_SIG, "got a SIGUSR2"); - dump_tree(); - break; - - case SIGTERM: - debug(DBG_SIG, "Got a SIGINT/SIGHUP"); - verbose("got a signal to quit"); - sd_notifyf(0, "STOPPING=1\nSTATUS=Received signal, exiting"); - exit(EXIT_SUCCESS); - break; - - case SIGINT: - case SIGHUP: - count++; - if (count > 5) { - dump_tree(); - exit(EXIT_FAILURE); - } - - verbose("got a signal to dump tree"); - sd_notifyf(0, "STOPPING=1\nSTATUS=Received signal, exiting"); - dump_tree(); - uring_task_destroy(&signal->task); - igmp_delete(); - announce_delete(); - idle_delete(); - server_cfg_monitor_delete(); - list_for_each_entry_safe(server, stmp, &cfg->servers, list) - server_delete(server); - uring_delete(); - return; - - default: - error("got an unknown signal: %i", si->si_signo); - break; - } - -out: - uring_tbuf_read(&signal->task, signalfd_read); -} - -static void -hack_signal_handler(int signum, siginfo_t *si, void *ucontext) -{ - ssize_t r; - - assert_return(signum > 0 && si); - - r = write(cfg->signal->pipe[PIPE_WR], si, sizeof(*si)); - if (r != sizeof(*si)) - error("write: %zi\n", r); - -} - -static void -signalfd_init() -{ - //sigset_t mask; - struct signalfd_ev *signal; - - signal = zmalloc(sizeof(*signal)); - if (!signal) - die("malloc: %m"); - - if (pipe2(signal->pipe, O_CLOEXEC) < 0) - die("pipe2: %m"); - - /* - sigfillset(&mask); - if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) - die("sigprocmask: %m"); - - sfd = signalfd(-1, &mask, SFD_CLOEXEC); - if (sfd < 0) - die("signalfd: %m"); - */ - - struct sigaction action; - sigfillset(&action.sa_mask); - action.sa_sigaction = hack_signal_handler; - action.sa_flags = SA_SIGINFO; - - sigaction(SIGINT, &action, NULL); - sigaction(SIGHUP, &action, NULL); - sigaction(SIGTERM, &action, NULL); - sigaction(SIGUSR1, &action, NULL); - sigaction(SIGUSR2, &action, NULL); - - action.sa_handler = SIG_IGN; - action.sa_flags = 0; - sigaction(SIGPIPE, &action, NULL); - - debug(DBG_SIG, "using pipe fds %i -> %i", - signal->pipe[PIPE_WR], signal->pipe[PIPE_RD]); - uring_task_init(&signal->task, "signal", uring_parent(), signalfd_free); - uring_task_set_fd(&signal->task, signal->pipe[PIPE_RD]); - uring_task_set_buf(&signal->task, &signal->tbuf); - cfg->signal = signal; - uring_tbuf_read(&signal->task, signalfd_read); -} - int main(int argc, char **argv) { @@ -750,7 +590,7 @@ main(int argc, char **argv) die("capng_apply failed"); } - signalfd_init(); + signal_init(); server_cfg_monitor_init(); @@ -100,6 +100,8 @@ do { \ #define assert_task_alive(lvl, t) assert_task_alive_or((lvl), (t), return) +void dump_tree(); + struct uring_task; /* To save typing in all the function definitions below */ @@ -147,7 +149,7 @@ struct cfg { struct uring_ev *uring; struct server_cfg_monitor *server_cfg_monitor; - struct signalfd_ev *signal; + struct signal_ev *signal; struct announce *announce; struct igmp *igmp; struct idle *idle; diff --git a/meson.build b/meson.build index 9348482..b183999 100644 --- a/meson.build +++ b/meson.build @@ -7,6 +7,7 @@ libcapng = dependency('libcap-ng') mcproxy_sources = [ 'main.c', 'uring.c', + 'signal-handler.c', 'server.c', 'server-proxy.c', 'server-config.c', diff --git a/signal-handler.c b/signal-handler.c new file mode 100644 index 0000000..e574f76 --- /dev/null +++ b/signal-handler.c @@ -0,0 +1,193 @@ +#define _GNU_SOURCE +#include <sys/signalfd.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <systemd/sd-daemon.h> + +#include "main.h" +#include "signal-handler.h" +#include "uring.h" +#include "server.h" +#include "server-config.h" +#include "config-parse.h" +#include "igmp.h" +#include "announce.h" +#include "idle.h" + +struct signal_ev { + struct uring_task task; + struct uring_task_buf tbuf; + int pipe[2]; +}; + +static void +signal_delete() +{ + assert_return(cfg->signal); + + uring_task_destroy(&cfg->signal->task); +} + +static void +signalfd_read(struct uring_task *task, int res) +{ + struct signal_ev *signal = container_of(task, struct signal_ev, task); + struct server *server, *stmp; + static unsigned count = 0; + siginfo_t *si; + + assert_return(task); + assert_task_alive(DBG_SIG, task); + + si = (siginfo_t *)task->tbuf->buf; + if (res != sizeof(*si)) + die("error in signalfd (%i)", res); + + switch (si->si_signo) { + case SIGUSR1: { + struct dns_async *dns; + + debug(DBG_SIG, "Got a SIGUSR1"); + if (si->si_code != SI_ASYNCNL || !si->si_ptr) { + error("SIGUSR1: unexpected values in siginfo"); + goto out; + } + + dns = si->si_ptr; + if (!dns->cb) { + error("DNS callback not set"); + goto out; + } + + debug(DBG_DNS, "DNS lookup complete, dns: %p, dns->cb: %p", + dns, dns->cb); + dns->cb(dns); + break; + } + + case SIGUSR2: + debug(DBG_SIG, "got a SIGUSR2"); + dump_tree(); + break; + + case SIGTERM: + debug(DBG_SIG, "Got a SIGINT/SIGHUP"); + verbose("got a signal to quit"); + sd_notifyf(0, "STOPPING=1\nSTATUS=Received signal, exiting"); + exit(EXIT_SUCCESS); + break; + + case SIGINT: + case SIGHUP: + count++; + if (count > 5) { + dump_tree(); + exit(EXIT_FAILURE); + } + + verbose("got a signal to dump tree"); + sd_notifyf(0, "STOPPING=1\nSTATUS=Received signal, exiting"); + dump_tree(); + signal_delete(); + igmp_delete(); + announce_delete(); + idle_delete(); + server_cfg_monitor_delete(); + list_for_each_entry_safe(server, stmp, &cfg->servers, list) + server_delete(server); + uring_delete(); + return; + + default: + error("got an unknown signal: %i", si->si_signo); + break; + } + +out: + uring_tbuf_read(&signal->task, signalfd_read); +} + +static void +hack_signal_handler(int signum, siginfo_t *si, void *ucontext) +{ + ssize_t r; + + assert_return(signum > 0 && si); + + r = write(cfg->signal->pipe[PIPE_WR], si, sizeof(*si)); + if (r != sizeof(*si)) + error("write: %zi\n", r); + +} + +static void +signal_free(struct uring_task *task) +{ + struct signal_ev *signal = container_of(task, struct signal_ev, task); + + assert_return(task); + + debug(DBG_SIG, "called"); + close(signal->pipe[PIPE_WR]); + cfg->signal = NULL; + xfree(signal); +} + +void +signal_refdump() +{ + assert_return(cfg->signal); + + uring_task_refdump(&cfg->signal->task); +} + +void +signal_init() +{ + //sigset_t mask; + struct signal_ev *signal; + + assert_return(!cfg->signal); + + signal = zmalloc(sizeof(*signal)); + if (!signal) + die("malloc: %m"); + + if (pipe2(signal->pipe, O_CLOEXEC) < 0) + die("pipe2: %m"); + + /* + sigfillset(&mask); + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) + die("sigprocmask: %m"); + + sfd = signalfd(-1, &mask, SFD_CLOEXEC); + if (sfd < 0) + die("signalfd: %m"); + */ + + struct sigaction action; + sigfillset(&action.sa_mask); + action.sa_sigaction = hack_signal_handler; + action.sa_flags = SA_SIGINFO; + + sigaction(SIGINT, &action, NULL); + sigaction(SIGHUP, &action, NULL); + sigaction(SIGTERM, &action, NULL); + sigaction(SIGUSR1, &action, NULL); + sigaction(SIGUSR2, &action, NULL); + + action.sa_handler = SIG_IGN; + action.sa_flags = 0; + sigaction(SIGPIPE, &action, NULL); + + debug(DBG_SIG, "using pipe fds %i -> %i", + signal->pipe[PIPE_WR], signal->pipe[PIPE_RD]); + uring_task_init(&signal->task, "signal", uring_parent(), signal_free); + uring_task_set_fd(&signal->task, signal->pipe[PIPE_RD]); + uring_task_set_buf(&signal->task, &signal->tbuf); + cfg->signal = signal; + uring_tbuf_read(&signal->task, signalfd_read); +} + diff --git a/signal-handler.h b/signal-handler.h new file mode 100644 index 0000000..e0140b3 --- /dev/null +++ b/signal-handler.h @@ -0,0 +1,8 @@ +#ifndef foosignalhfoo +#define foosignalhfoo + +void signal_refdump(); + +void signal_init(); + +#endif |