Impl. hot reloading of config and on SIGUSR1
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 40s

Resolves #2
This commit is contained in:
Stephen Seo 2024-09-10 13:55:16 +09:00
parent bc879408fe
commit bf7bfe5c86
7 changed files with 113 additions and 1 deletions

View file

@ -29,6 +29,7 @@ void print_usage(void) {
puts(" --req-header-to-print=<header> (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();

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -19,13 +19,15 @@
#include <stdlib.h>
#include <stdio.h>
// Unix includes.
// Linux/Unix includes.
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/inotify.h>
#include <linux/limits.h>
// Third party includes.
#include <SimpleArchiver/src/helpers.h>
@ -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)) {

View file

@ -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

View file

@ -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