summaryrefslogtreecommitdiff
path: root/minecproxy/signal-handler.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-23 20:56:22 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-23 20:56:22 +0200
commitea053d96f7e89e053d4af8d39b04c5428760345f (patch)
tree8182ca73675ad3933b0f38cb48a99c69101309b4 /minecproxy/signal-handler.c
parent8c27290245b7bcc7cd2f72f3b4a7562294b43bbe (diff)
Big renaming, move some more functionality to shared lib
Diffstat (limited to 'minecproxy/signal-handler.c')
-rw-r--r--minecproxy/signal-handler.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/minecproxy/signal-handler.c b/minecproxy/signal-handler.c
new file mode 100644
index 0000000..67c2e0b
--- /dev/null
+++ b/minecproxy/signal-handler.c
@@ -0,0 +1,195 @@
+#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-parser.h"
+#include "igmp.h"
+#include "announce.h"
+#include "idle.h"
+#include "ptimer.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();
+ ptimer_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);
+}
+