summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-22 12:35:21 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-22 12:35:21 +0200
commit2fe1271d25eae0f30401fb52330db3a324504952 (patch)
tree3ae0bdb7c367ebc9199f712679095e28042e27c2
parentd74bcf2dadfa4fc6c432ba0585b6dc4a77e81f0e (diff)
Split out signal handling to a separate file
-rw-r--r--main.c168
-rw-r--r--main.h4
-rw-r--r--meson.build1
-rw-r--r--signal-handler.c193
-rw-r--r--signal-handler.h8
5 files changed, 209 insertions, 165 deletions
diff --git a/main.c b/main.c
index c1c9f8f..f62bbc3 100644
--- a/main.c
+++ b/main.c
@@ -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();
diff --git a/main.h b/main.h
index aa3ccf1..ac3e0a2 100644
--- a/main.h
+++ b/main.h
@@ -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