From ea053d96f7e89e053d4af8d39b04c5428760345f Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 23 Jun 2020 20:56:22 +0200 Subject: Big renaming, move some more functionality to shared lib --- minecproxy/signal-handler.c | 195 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 minecproxy/signal-handler.c (limited to 'minecproxy/signal-handler.c') 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 +#include +#include +#include +#include + +#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); +} + -- cgit v1.2.3