diff --git a/inc/lektor/net.h b/inc/lektor/net.h index 1bfb4c336682b204b12c550ccc4e9ba62aedf1b2..8759b8e402ea1c14aece87310cd61dd335103d63 100644 --- a/inc/lektor/net.h +++ b/inc/lektor/net.h @@ -52,16 +52,25 @@ struct lkt_state { char port[LKT_LINE_MAX]; struct queue queue; + /* The database */ volatile sqlite3 *db; const char *kara_prefix; + /* Internal event flags */ mpd_idle_flag mpd_idle_events; pthread_mutex_t lock; + /* Modules */ struct lkt_module window_mod; struct lkt_module repo_mod; + /* For uptime */ time_t start_date; + + /* Signal handlers for this server */ + void (*__signal_INT )(struct lkt_state *); + void (*__signal_USR1)(struct lkt_state *); + void (*__signal_USR2)(struct lkt_state *); }; /* Send a message to the connected client. */ diff --git a/src/base/commands.c b/src/base/commands.c index b52faf6cecab723bee0b64cee8ce016fca5d435a..7cf09f54390993fdf09ed61d766d8ca2d1274b5c 100644 --- a/src/base/commands.c +++ b/src/base/commands.c @@ -74,14 +74,9 @@ bool command_kill(struct lkt_state *srv, size_t c, char UNUSED *argv[LKT_MESSAGE_ARGS_MAX]) { RETURN_UNLESS(lkt_client_auth(srv, c, false), "Failed to authentificate user", false); - LOG_INFO("GENERAL", "Stopping lektord"); - MOD_PROC(srv->repo_mod, "free"); - MOD_PROC(srv->window_mod, "free"); - close(srv->fds[0].fd); - lkt_queue_free(&srv->queue); - database_close_all(); - LOG_INFO("GENERAL", "lektord will now exit"); - exit(EXIT_SUCCESS); + srv->__signal_INT(srv); + LOG_ERROR("FATAL", "The SIGINT handler returned, now exiting"); + exit(EXIT_FAILURE); } bool diff --git a/src/net/listen.c b/src/net/listen.c index efd2435b0af5cd5c9304b0683c977b1f2e74e208..172ce3b937713223271a0282722da0bcbe7516a6 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -789,6 +789,74 @@ redo: goto redo; } +/******************* + * Signal handlers * + *******************/ + +static int __lkt_signal_INT = 0; /* SIGINT => close the server */ +static int __lkt_signal_USR1 = 0; /* SIGUSR1 => not used */ +static int __lkt_signal_USR2 = 0; /* SIGUSR2 => not used */ + +static void +__signal_handler(int sig) +{ + switch (sig) { + case SIGINT: + LOG_INFO("SIGNAL", "Got signal SIGINT"); + __lkt_signal_INT = 1; + break; + + default: + LOG_WARN("SIGNAL", "Not handled signal %d", sig); + break; + } +} + +static void +__lkt_handle_INT(struct lkt_state *srv) +{ + LOG_INFO("GENERAL", "Stopping lektord"); + MOD_PROC(srv->repo_mod, "free"); + MOD_PROC(srv->window_mod, "free"); + close(srv->fds[0].fd); + lkt_queue_free(&srv->queue); + database_close_all(); + LOG_INFO("GENERAL", "lektord will now exit"); + + /* Register default handle for SIGINT, so if you double ctrl+c it exit like + * it crashed. */ + LOG_INFO("SIGNAL", "Now use default handler for SIGINT"); + signal(SIGINT, SIG_DFL); + + exit(EXIT_SUCCESS); +} + +static void +__lkt_handle_USR1(struct lkt_state UNUSED *srv) +{ +} + +static inline void +handle_signals(struct lkt_state *srv) +{ +#define __HANDLE(srv, signal) \ + if (__lkt_signal_##signal) { \ + LOG_INFO("SIGNAL", "Server in handle phase for signal SIG"#signal); \ + if (srv->__signal_##signal) \ + srv->__signal_##signal(srv); \ + else \ + LOG_WARN("SIGNAL", "No signal handler in server for SIG"#signal); \ + } + __HANDLE(srv, INT) + __HANDLE(srv, USR1) + __HANDLE(srv, USR2) +#undef __HANDLE +} + +/**************************** + * The server main function * + ****************************/ + void lkt_listen(struct lkt_state *srv) { @@ -797,6 +865,15 @@ lkt_listen(struct lkt_state *srv) srv->clients = calloc(srv->fds_max, sizeof(struct lkt_client)); memset(srv->clients, 0, srv->fds_max * sizeof(struct lkt_client)); + LOG_INFO("SIGNAL", "Register signal handlers for signals..."); + srv->__signal_INT = __lkt_handle_INT; + srv->__signal_USR1 = __lkt_handle_USR1; + srv->__signal_USR2 = NULL; + signal(SIGINT, __signal_handler); + signal(SIGUSR1, __signal_handler); + signal(SIGUSR2, __signal_handler); + LOG_INFO("SIGNAL", "Signal handlers registered"); + if ((srv->fds[0].fd = init_listening_socket(srv->host, srv->port)) < 0) return; @@ -811,6 +888,7 @@ lkt_listen(struct lkt_state *srv) /* Listen */ for (;;) { + handle_signals(srv); if (handle_network_events(srv) < 0) break; if (handle_idle_events(srv) < 0)