From bf7bfe5c86f2a89911054790a2b5f1a563f1d3a3 Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Tue, 10 Sep 2024 13:55:16 +0900 Subject: [PATCH] Impl. hot reloading of config and on SIGUSR1 Resolves https://git.seodisparate.com/stephenseo/c_simple_http/issues/2 --- src/arg_parse.c | 3 ++ src/arg_parse.h | 2 + src/globals.c | 1 + src/globals.h | 1 + src/main.c | 97 ++++++++++++++++++++++++++++++++++++++++++- src/signal_handling.c | 9 ++++ src/signal_handling.h | 1 + 7 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/arg_parse.c b/src/arg_parse.c index f981e83..7472be5 100644 --- a/src/arg_parse.c +++ b/src/arg_parse.c @@ -29,6 +29,7 @@ void print_usage(void) { puts(" --req-header-to-print=
(can be used multiple times)"); puts(" For example: --req-header-to-print=User-Agent"); puts(" Note that this option is case-insensitive"); + puts(" --enable-reload-config-on-change"); } Args parse_args(int argc, char **argv) { @@ -66,6 +67,8 @@ Args parse_args(int argc, char **argv) { free(header_buf); exit(1); } + } else if (strcmp(argv[0], "--enable-reload-config-on-change") == 0) { + args.flags |= 2; } else { puts("ERROR: Invalid args!\n"); print_usage(); diff --git a/src/arg_parse.h b/src/arg_parse.h index 6aef990..5943192 100644 --- a/src/arg_parse.h +++ b/src/arg_parse.h @@ -23,6 +23,8 @@ typedef struct Args { // xxxx xxx0 - enable peer addr print. // xxxx xxx1 - disable peer addr print. + // xxxx xx0x - disable listen on config file for reloading. + // xxxx xx1x - enable listen on config file for reloading. unsigned short flags; unsigned short port; // Does not need to be free'd, this should point to a string in argv. diff --git a/src/globals.c b/src/globals.c index 9262d01..26483da 100644 --- a/src/globals.c +++ b/src/globals.c @@ -17,5 +17,6 @@ #include "globals.h" int C_SIMPLE_HTTP_KEEP_RUNNING = 1; +int C_SIMPLE_HTTP_SIGUSR1_SET = 0; // vim: et ts=2 sts=2 sw=2 diff --git a/src/globals.h b/src/globals.h index 209b32e..9ce14ea 100644 --- a/src/globals.h +++ b/src/globals.h @@ -18,6 +18,7 @@ #define SEODISPARATE_COM_C_SIMPLE_HTTP_GLOBALS_H_ extern int C_SIMPLE_HTTP_KEEP_RUNNING; +extern int C_SIMPLE_HTTP_SIGUSR1_SET; #endif diff --git a/src/main.c b/src/main.c index ddc2a6b..2ba4e56 100644 --- a/src/main.c +++ b/src/main.c @@ -19,13 +19,15 @@ #include #include -// Unix includes. +// Linux/Unix includes. #include #include #include #include #include #include +#include +#include // Third party includes. #include @@ -64,6 +66,13 @@ int c_simple_http_headers_check_print(void *data, void *ud) { return 0; } +void c_simple_http_inotify_fd_cleanup(int *fd) { + if (fd && *fd >= 0) { + close(*fd); + *fd = -1; + } +} + int main(int argc, char **argv) { __attribute__((cleanup(c_simple_http_free_args))) Args args = parse_args(argc, argv); @@ -103,6 +112,34 @@ int main(int argc, char **argv) { } } + __attribute__((cleanup(c_simple_http_inotify_fd_cleanup))) + int inotify_config_fd = -1; + __attribute__((cleanup(simple_archiver_helper_cleanup_malloced))) + void *inotify_event_buf = NULL; + struct inotify_event *inotify_event = NULL; + const size_t inotify_event_buf_size = + sizeof(struct inotify_event) + NAME_MAX + 1; + if ((args.flags & 0x2) != 0) { + inotify_config_fd = inotify_init1(IN_NONBLOCK); + if (inotify_config_fd < 0) { + fprintf(stderr, "ERROR Failed to init listen on config file for hot " + "reloading! (error code \"%d\")\n", errno); + return 3; + } + + if (inotify_add_watch( + inotify_config_fd, + args.config_file, + IN_MODIFY | IN_CLOSE_WRITE) == -1) { + fprintf(stderr, "ERROR Failed to set up listen on config file for hot " + "reloading! (error code \"%d\")\n", errno); + return 4; + } + + inotify_event_buf = malloc(inotify_event_buf_size); + inotify_event = inotify_event_buf; + } + struct timespec sleep_time; sleep_time.tv_sec = 0; sleep_time.tv_nsec = C_SIMPLE_HTTP_SLEEP_NANOS; @@ -112,6 +149,7 @@ int main(int argc, char **argv) { peer_info.sin6_family = AF_INET6; signal(SIGINT, C_SIMPLE_HTTP_handle_sigint); + signal(SIGUSR1, C_SIMPLE_HTTP_handle_sigusr1); unsigned char recv_buf[C_SIMPLE_HTTP_RECV_BUF_SIZE]; @@ -121,6 +159,63 @@ int main(int argc, char **argv) { while (C_SIMPLE_HTTP_KEEP_RUNNING) { nanosleep(&sleep_time, NULL); + + if (C_SIMPLE_HTTP_SIGUSR1_SET) { + // Handle hot-reloading of config file due to SIGUSR1. + C_SIMPLE_HTTP_SIGUSR1_SET = 0; + fprintf(stderr, "NOTICE SIGUSR1, reloading config file...\n"); + c_simple_http_clean_up_parsed_config(&parsed_config); + parsed_config = c_simple_http_parse_config( + args.config_file, + "PATH", + NULL); + } + if ((args.flags & 0x2) != 0) { + // Handle hot-reloading of config file. + read_ret = + read(inotify_config_fd, inotify_event_buf, inotify_event_buf_size); + if (read_ret == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // No events, do nothing. + } else { + fprintf( + stderr, + "WARNING Error code \"%d\" on config file listen for hot " + "reloading!\n", + errno); + } + } else if (read_ret > 0) { +#ifndef NDEBUG + printf("DEBUG inotify_event->mask: %x\n", inotify_event->mask); +#endif + if ((inotify_event->mask & IN_MODIFY) != 0 + || (inotify_event->mask & IN_CLOSE_WRITE) != 0) { + fprintf(stderr, "NOTICE Config file modified, reloading...\n"); + c_simple_http_clean_up_parsed_config(&parsed_config); + parsed_config = c_simple_http_parse_config( + args.config_file, + "PATH", + NULL); + } else if ((inotify_event->mask & IN_IGNORED) != 0) { + fprintf( + stderr, + "NOTICE Config file modified (IN_IGNORED), reloading...\n"); + c_simple_http_clean_up_parsed_config(&parsed_config); + parsed_config = c_simple_http_parse_config( + args.config_file, + "PATH", + NULL); + // Re-initialize inotify. + //c_simple_http_inotify_fd_cleanup(&inotify_config_fd); + //inotify_config_fd = inotify_init1(IN_NONBLOCK); + inotify_add_watch( + inotify_config_fd, + args.config_file, + IN_MODIFY | IN_CLOSE_WRITE); + } + } + } + socket_len = sizeof(struct sockaddr_in6); ret = accept(tcp_socket, (struct sockaddr *)&peer_info, &socket_len); if (ret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { diff --git a/src/signal_handling.c b/src/signal_handling.c index dfe4340..3f64586 100644 --- a/src/signal_handling.c +++ b/src/signal_handling.c @@ -34,4 +34,13 @@ void C_SIMPLE_HTTP_handle_sigint(int signal) { } } +void C_SIMPLE_HTTP_handle_sigusr1(int signal) { + if (signal == SIGUSR1) { +#ifndef NDEBUG + puts("Handling SIGUSR1"); +#endif + C_SIMPLE_HTTP_SIGUSR1_SET = 1; + } +} + // vim: et ts=2 sts=2 sw=2 diff --git a/src/signal_handling.h b/src/signal_handling.h index 3456ebf..0237f40 100644 --- a/src/signal_handling.h +++ b/src/signal_handling.h @@ -18,6 +18,7 @@ #define SEODISPARATE_COM_C_SIMPLE_HTTP_SIGNAL_HANDLING_H_ void C_SIMPLE_HTTP_handle_sigint(int signal); +void C_SIMPLE_HTTP_handle_sigusr1(int signal); #endif