diff options
| author | Soikk | 2025-11-26 13:12:41 +0100 |
|---|---|---|
| committer | Soikk | 2025-11-26 14:48:19 +0100 |
| commit | 718c999cfcac7a84ae78b47359d05281e9fda6b3 (patch) | |
| tree | e3130d5244e3ffabe8e4dc50d88e0213a93c2861 | |
| parent | faa700d552302c0bccb988a828bed8abde2ec74f (diff) | |
| download | soikk-server-718c999cfcac7a84ae78b47359d05281e9fda6b3.tar.xz soikk-server-718c999cfcac7a84ae78b47359d05281e9fda6b3.tar.zst | |
Added reinitialization functionality
| -rwxr-xr-x | src/main.c | 129 | ||||
| -rwxr-xr-x | src/worker.c | 56 |
2 files changed, 142 insertions, 43 deletions
@@ -1,7 +1,8 @@ #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> -#include <time.h> +//#include <time.h> +#include <libgen.h> #include "str/str.h" #include "list/list.h" #include "net/net.h" @@ -11,7 +12,8 @@ #define IPC_BACKLOG 15 -config_m config; +str name; +str orig_config_file; struct { str path; str socket_file; @@ -19,6 +21,7 @@ struct { str config_file; str workers; } dir; +config_m config; http_server *server; ipc_sender *sender; struct worker { @@ -27,7 +30,8 @@ struct worker { } *workers; -static void propagate_signal(int sig, siginfo_t *info, void *ucontext){ +// TODO: waitpid here? +static void propagate_signal(int sig){ for(int i = 0; i < list_size(workers); i++){ kill(workers[i].pid, sig); } @@ -35,9 +39,9 @@ static void propagate_signal(int sig, siginfo_t *info, void *ucontext){ void deinit(void); -void quit(int sig, siginfo_t *info, void *ucontext){ +static void quit(int sig, siginfo_t *info, void *ucontext){ log_info("Terminating due to SIG%s (%s)", sigabbrev_np(sig), sigdescr_np(sig)); - propagate_signal(sig, info, ucontext); + propagate_signal(sig); deinit(); exit(0); } @@ -58,7 +62,7 @@ static void cleanup_worker(pid_t pid, int cleandir){ // TODO: look more into waitpid() // TODO: make a wrapper for sigabbrev_np -void worker_undertaker(int sig, siginfo_t *info, void *ucontext){ +static void worker_undertaker(int sig, siginfo_t *info, void *ucontext){ if(sig == SIGCHLD && list_entry_exists(workers, info->si_pid)){ switch(info->si_code){ case CLD_EXITED: @@ -93,7 +97,7 @@ void worker_undertaker(int sig, siginfo_t *info, void *ucontext){ } } -int create_server_dir(str name){ +static int create_server_dir(str name){ dir.path = dup_strs(sstr("/var/run/"), name, sstr("/")); if(!dir_exists(dir.path.ptr)){ if(mkdir(dir.path.ptr, 0777) != 0){ @@ -120,11 +124,11 @@ int create_server_dir(str name){ return 0; } -int copy_config_file(char *configfile, str dest){ - str cff = map_file(configfile); +static int copy_config_file(str configfile, str dest){ + str cff = map_file(configfile.ptr); if(cff.ptr == NULL){ - log_error("Error opening config file '%s'", configfile); - return 1;; + log_error("Error opening config file '%.*s'", configfile.len, configfile.ptr); + return 1; } FILE *cfp = fopen(dest.ptr, "w"); if(cfp == NULL){ @@ -138,9 +142,9 @@ int copy_config_file(char *configfile, str dest){ return 0; } -int write_server_socket(str socket_file, int ssocket){ +static int write_server_socket(str socket_file, int ssocket){ // TODO: how to reattach to socket? how to leave socket reattachable? look at ptrace(2) - log_info("Creating socket file in %.*s", socket_file.len, socket_file.ptr); + log_debug("Creating socket file in %.*s", socket_file.len, socket_file.ptr); int sfd = creat(socket_file.ptr, 0777); if(sfd == -1){ log_error("Error creating socket file in '%.*s': %s", socket_file.len, socket_file.ptr, strerror(errno)); @@ -154,40 +158,74 @@ int write_server_socket(str socket_file, int ssocket){ return 0; } +static void reinit(int sig, siginfo_t *info, void *ucontext){ + if(sig == SIGUSR1){ + log_info("Reinitializing server"); + propagate_signal(sig); + free_master_config(&config); + destroy_http_server(&server); + + if(copy_config_file(orig_config_file, dir.config_file)){ + log_error("Unable to create configuration file in server directory"); + quit(SIGTERM, NULL, NULL); + } + config = master_config(dir.config_file.ptr); + if(config.file.ptr == NULL){ + log_error("Unable to read config from '%.*s'", dir.config_file.len, dir.config_file.ptr); + quit(SIGTERM, NULL, NULL); + } + server = setup_http_server(config.port, config.backlog); + if(server == NULL){ + log_error("Unable to set up socket server"); + quit(SIGTERM, NULL, NULL); + } + if(write_server_socket(dir.socket_file, server->ssocket)){ + log_error("Unable to write socket to socket file"); + quit(SIGTERM, NULL, NULL); + } + + propagate_signal(SIGCONT); + } +} + int init(char *configfile){ - str file = map_file(configfile); - str name = get_key(file, sstr("name")); - unmap_file(&file); + name = dsstr(basename(configfile)); + orig_config_file = dsstr(configfile); if(create_server_dir(name) != 0){ - free_str(&name); + log_error("Unable to create server directory"); return 1; } - free_str(&name); - if(copy_config_file(configfile, dir.config_file) != 0){ + if(copy_config_file(orig_config_file, dir.config_file) != 0){ + log_error("Unable to create configuration file in server directory"); return 1; } config = master_config(dir.config_file.ptr); if(config.file.ptr == NULL){ - log_error("Unable to read config from '%s'", configfile); + log_error("Unable to read config from '%.*s'", dir.config_file.len, dir.config_file.ptr); return 1; } - //print_master_config(config); - log_info("Succesfully read master config from '%s'", configfile); + log_info("Succesfully read master config from '%.*s'", dir.config_file.len, dir.config_file.ptr); // decouple so the whole net.c doesnt get linked? server = setup_http_server(config.port, config.backlog); if(server == NULL){ - log_error("Error setting up socket server"); + log_error("Unable to set up socket server"); return 1; } if(write_server_socket(dir.socket_file, server->ssocket)){ + log_error("Unable to write socket to socket file"); return 1; } sender = setup_ipc_sender(dir.ipc_addr, IPC_BACKLOG); if(sender == NULL){ - log_error("Error setting up IPC sender"); + log_error("Unable to set up IPC sender"); return 1; } init_list(workers); + struct sigaction rnit = { .sa_sigaction = reinit, .sa_flags = SA_SIGINFO }; + if(sigaction(SIGUSR1, &rnit, NULL) == -1){ + log_error("Error setting up SIGUSR1 signal handler: %s", strerror(errno)); + return 1; + } struct sigaction chld = { .sa_sigaction = worker_undertaker, .sa_flags = SA_SIGINFO | SA_NOCLDSTOP }; if(sigaction(SIGCHLD, &chld, NULL) == -1){ log_error("Error setting up SIGCHLD signal handler: %s", strerror(errno)); @@ -208,25 +246,35 @@ int init(char *configfile){ return 0; } -void remove_server_dir(void){ - if(remove(dir.workers.ptr) != 0){ - log_error("Error removing workers directory in '%.*s': %s", dir.workers.len, dir.workers.ptr, strerror(errno)); +static void remove_server_dir(void){ + if(dir_exists(dir.workers.ptr)){ + if(remove(dir.workers.ptr) != 0){ + log_error("Error removing workers directory in '%.*s': %s", dir.workers.len, dir.workers.ptr, strerror(errno)); + } } free_str(&dir.workers); - if(remove(dir.ipc_addr.ptr) != 0){ - log_error("Error removing IPC socket '%.*s': %s", dir.ipc_addr.len, dir.ipc_addr.ptr, strerror(errno)); + if(file_exists(dir.ipc_addr.ptr)){ + if(remove(dir.ipc_addr.ptr) != 0){ + log_error("Error removing IPC socket '%.*s': %s", dir.ipc_addr.len, dir.ipc_addr.ptr, strerror(errno)); + } } free_str(&dir.ipc_addr); - if(remove(dir.config_file.ptr) != 0){ - log_error("Error removing config file in '%.*s': %s", dir.config_file.len, dir.config_file.ptr, strerror(errno)); + if(file_exists(dir.config_file.ptr)){ + if(remove(dir.config_file.ptr) != 0){ + log_error("Error removing config file in '%.*s': %s", dir.config_file.len, dir.config_file.ptr, strerror(errno)); + } } free_str(&dir.config_file); - if(remove(dir.socket_file.ptr) != 0){ - log_error("Error removing socket file in '%.*s': %s", dir.socket_file.len, dir.socket_file.ptr, strerror(errno)); + if(file_exists(dir.socket_file.ptr)){ + if(remove(dir.socket_file.ptr) != 0){ + log_error("Error removing socket file in '%.*s': %s", dir.socket_file.len, dir.socket_file.ptr, strerror(errno)); + } } free_str(&dir.socket_file); - if(remove(dir.path.ptr) != 0){ - log_error("Error removing server directory in '%.*s': %s", dir.path.len, dir.path.ptr, strerror(errno)); + if(dir_exists(dir.path.ptr)){ + if(remove(dir.path.ptr) != 0){ + log_error("Error removing server directory in '%.*s': %s", dir.path.len, dir.path.ptr, strerror(errno)); + } } free_str(&dir.path); } @@ -302,7 +350,7 @@ int main(int argc, char *argv[]){ case 'f': case 'F': pid_t nw = fork(); if(nw == 0){ - char *args[] = {"./worker.exe", config.name.ptr, "&", NULL}; + char *args[] = {"./worker.exe", name.ptr, "&", NULL}; execv("./worker.exe", args); log_error("Cannot exec worker: %s", strerror(errno)); return 1; @@ -320,10 +368,11 @@ int main(int argc, char *argv[]){ // send_ipc_message(workers[i].wsocket, HTTP, sstr("")); // } // break; - case 'R': - for(int i = 0; i < list_size(workers); i++){ - send_ipc_message(workers[i].wsocket, RESTART, sstr("")); - } + case 'r': case 'R': + kill(getpid(), SIGUSR1); + //for(int i = 0; i < list_size(workers); i++){ + // send_ipc_message(workers[i].wsocket, RESTART, sstr("")); + //} break; case 'l': case 'L': printf("|-%3d workers working for us rn-|\n", list_size(workers)); diff --git a/src/worker.c b/src/worker.c index 64403ac..87824cf 100755 --- a/src/worker.c +++ b/src/worker.c @@ -111,6 +111,51 @@ void quit(int sig, siginfo_t *info, void *ucontext){ exit(0); } +int signal_wait(int sig){ + sigset_t old, new; + sigemptyset(&new); + sigaddset(&new, sig); + if(sigprocmask(SIG_BLOCK, &new, &old) != 0){ + return 1; + } + // TODO: try with NULL + int s; + if(sigwait(&new, &s) != 0){ + return 1; + } + if(sigprocmask(SIG_SETMASK, &old, NULL) != 0){ + return 1; + } + return 0; +} + +void reinit(int sig, siginfo_t *info, void *ucontext){ + if(sig == SIGUSR1){ + log_info("Reinitializing worker"); + free_worker_config(&config); + destroy_http_worker(&worker); + + if(signal_wait(SIGCONT) != 0){ + log_error("You should probably look at signal_wait to see wtf is going on"); + } + + config = worker_config(dir.config_file.ptr); + if(config.file.ptr == NULL){ + log_error("Unable to read config from '%.*s'", dir.config_file.len, dir.config_file.ptr); + quit(SIGTERM, NULL, NULL); + } + int sfd = open(dir.socket_path.ptr, O_RDONLY); + int ssocket; + read(sfd, &ssocket, sizeof(int)); + close(sfd); + worker = setup_http_worker(ssocket, secure, config.cert, config.key); + if(worker == NULL){ + log_error("Error setting up worker server"); + quit(SIGTERM, NULL, NULL); + } + } +} + // possibly change name int read_server_dir(str name){ dir.path = dup_strs(sstr("/var/run/"), name, sstr("/")); @@ -161,8 +206,8 @@ int init(str name){ //print_worker_config(config); // TODO: remove "successful" messages or add them all log_info("Succesfully read worker config from '%.*s'", dir.config_file.len, dir.config_file.ptr); - int ssocket; int sfd = open(dir.socket_path.ptr, O_RDONLY); + int ssocket; read(sfd, &ssocket, sizeof(int)); close(sfd); worker = setup_http_worker(ssocket, secure, config.cert, config.key); @@ -175,6 +220,11 @@ int init(str name){ log_error("Can't set up ipc listener on self"); return 1; } + struct sigaction rnit = { .sa_sigaction = reinit, .sa_flags = SA_SIGINFO }; + if(sigaction(SIGUSR1, &rnit, NULL) == -1){ + log_error("Error setting up SIGUSR1 signal handler: %s", strerror(errno)); + return 1; + } struct sigaction qit = { .sa_sigaction = quit, .sa_flags = SA_SIGINFO }; if(sigaction(SIGTERM, &qit, NULL) == -1){ log_error("Error setting up SIGTERM signal handler: %s", strerror(errno)); @@ -202,10 +252,10 @@ void remove_server_dir(void){ } void deinit(void){ - destroy_ipc_listener(&listener); - destroy_http_worker(&worker); free_worker_config(&config); remove_server_dir(); + destroy_http_worker(&worker); + destroy_ipc_listener(&listener); } void print_usage(void){ |
