diff options
| author | Soikk | 2025-12-06 20:16:37 +0100 |
|---|---|---|
| committer | Soikk | 2025-12-06 20:19:18 +0100 |
| commit | a55c8ef63bb4941fdee5ddf00ed564e246c8a939 (patch) | |
| tree | eed8f07ee9c2deb5d82d9dac130ef228a0b7b705 | |
| parent | 534303b80b5304a2b29d456d6b5c7a6ac1daaf1c (diff) | |
| download | soikk-server-a55c8ef63bb4941fdee5ddf00ed564e246c8a939.tar.xz soikk-server-a55c8ef63bb4941fdee5ddf00ed564e246c8a939.tar.zst | |
Reworked worker architecture
- replaced the central socket-multiple accepts architecture thanks to SO_REUSEPORT
- removed master/worker distinctions for server and config
- fixed bug with rewrites not being read properly by multiple workers because of null characters
| -rw-r--r-- | config.example | 99 | ||||
| -rw-r--r-- | src/config/config.c | 93 | ||||
| -rw-r--r-- | src/config/config.h | 18 | ||||
| -rwxr-xr-x | src/main.c | 204 | ||||
| -rwxr-xr-x | src/net/net.c | 161 | ||||
| -rwxr-xr-x | src/net/net.h | 27 | ||||
| -rw-r--r-- | src/rewrites/rewrites.c | 3 | ||||
| -rwxr-xr-x | src/worker.c | 101 |
8 files changed, 238 insertions, 468 deletions
diff --git a/config.example b/config.example index d8a946b..06a9c26 100644 --- a/config.example +++ b/config.example @@ -12,60 +12,57 @@ logs { # ERROR stderr 144 } -# config specific to the worker -worker { - root /home/user/server/ # where the server will look for files, basically files prefix - bundle /ca/bundle/location # location of ca bundle - cert ssl/cert.pem # location of certificate - key ssl/key.pem #location of private key - http # turns https off - # https # turns https on - ipv4 # ipv4 enabled - ipv6 # ipv6 enabled - rewrites { - / test/monch.gif - /media/* localc/media/$1 - /* test/$1 - } - # rewrites rewrites.txt # file from where to read rewrites - types mime.types # file from where to read types - types { - # reading types from config directly - # description extension - type/ext ext - } +root /home/user/server/ # where the server will look for files, basically files prefix +bundle /ca/bundle/location # location of ca bundle +cert ssl/cert.pem # location of certificate +key ssl/key.pem #location of private key +http # turns https off +# https # turns https on +ipv4 # ipv4 enabled +ipv6 # ipv6 enabled +rewrites { + / test/monch.gif + /media/* localc/media/$1 + /* test/$1 +} +# rewrites rewrites.txt # file from where to read rewrites +types mime.types # file from where to read types +types { + # reading types from config directly + # description extension + type/ext ext +} - # HTTP method rules - # not implemented yet - # GET { - # # request document to server code to server - # / homepage.html 200 - # /help help.html 200 - # /* 404.html 404 - # } +# HTTP method rules +# not implemented yet +# GET { +# # request document to server code to server +# / homepage.html 200 +# /help help.html 200 +# /* 404.html 404 +# } - # same but for different method - # POST { - # # etc - # } +# same but for different method +# POST { +# # etc +# } - # custom methods - # * { - # /* / 501 - # } +# custom methods +# * { +# /* / 501 +# } - # HTTP response codes - # codes { - # # code code text - # 200 "OK" - # 404 "Not Found" - # 418 "I'm a teapot" - # 501 "Not implemented" - # # custom codes - # 711 "Double gulp cup" - # } +# HTTP response codes +# codes { +# # code code text +# 200 "OK" +# 404 "Not Found" +# 418 "I'm a teapot" +# 501 "Not implemented" +# # custom codes +# 711 "Double gulp cup" +# } - # same but can also be gotten from file - # codes codes.txt -} +# same but can also be gotten from file +# codes codes.txt diff --git a/src/config/config.c b/src/config/config.c index 4cd4835..9ed20f3 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -66,13 +66,14 @@ static void rotate_logs(str logs){ read_logs(logs); } -config_m master_config(char *filename){ - config_m conf = {0}; +config read_config(char *filename){ + config conf = {0}; conf.file = map_file(filename); if(conf.file.ptr == NULL){ log_error("Unable to open config file '%s'", filename); return conf; } + init_nlist(conf.files); int off = 0; while(off < conf.file.len){ while(off < conf.file.len && charisspace(conf.file.ptr[off])) off++; @@ -97,59 +98,6 @@ config_m master_config(char *filename){ str val = sread_delim_f(conf.file.ptr + off, charisspace, true); off += val.len; conf.backlog = (int)strtou(val); - }else if(streq(key, sstr("logs"))){ - str val = sread_delim_f(conf.file.ptr + off, charisspace, true); - off += val.len; - str logs; - if(val.ptr[0] != '{'){ - str logfile = dup_str(val); - logs = file_to_str(logfile.ptr); - free_str(&logfile); - }else{ - logs = read_delim(conf.file.ptr + off, '}'); - off += logs.len; - } - rotate_logs(logs); - free_str(&logs); - }else if(streq(key, sstr("worker"))){ - int bcount = 1; - while(off < conf.file.len && bcount > 0){ - if(conf.file.ptr[off] == '{') bcount++; - if(conf.file.ptr[off] == '}') bcount--; - off++; - } - }else if(key.len != 0){ - log_warn("Unexpected entry in configuration: '%.*s'", key.len, key.ptr); - } - while(off < conf.file.len && !charislinebreak(conf.file.ptr[off++])); - }; - - return conf; -} - -config_w worker_config(char *filename){ - config_w conf = {0}; - conf.file = map_file(filename); - if(conf.file.ptr == NULL){ - log_error("Unable to open config file '%s'", filename); - return conf; - } - init_nlist(conf.files); - int off = 0; - while(off < conf.file.len){ - while(off < conf.file.len && charisspace(conf.file.ptr[off])) off++; - if(conf.file.ptr[off] == '#'){ - while(off < conf.file.len && !charislinebreak(conf.file.ptr[off++])); - continue; - } - str key = sread_delim_f(conf.file.ptr + off, charisspace, true); - off += key.len; - while(off < conf.file.len && charisspace(conf.file.ptr[off]) && !charislinebreak(conf.file.ptr[off])) off++; - - if(streq(key, sstr("name"))){ - conf.name = sread_delim_f(conf.file.ptr + off, charisspace, true); - off += conf.name.len; - conf.file.ptr[off] = '\0'; }else if(streq(key, sstr("root"))){ conf.root = sread_delim_f(conf.file.ptr + off, charisspace, true); off += conf.root.len; @@ -243,15 +191,10 @@ str get_key(str file, str key){ return (str){0}; } -void free_master_config(config_m *conf){ +void free_config(config *conf){ conf->name = (str){0}; conf->port = (str){0}; conf->backlog = 0; - unmap_file(&conf->file); -} - -void free_worker_config(config_w *conf){ - conf->name = (str){0}; conf->root = (str){0}; conf->bundle = (str){0}; conf->cert = (str){0}; @@ -268,33 +211,12 @@ void free_worker_config(config_w *conf){ unmap_file(&conf->file); } -void print_master_config(config_m conf){ +void print_config(config conf){ printf( - "MASTER CONFIGURATION:\n" + "CONFIGURATION:\n" "\t- name: %.*s\n" "\t- port: %.*s\n" "\t- backlog: %d\n" - "\t- logs: {\n", - conf.name.len, conf.name.ptr, - conf.port.len, conf.port.ptr, - conf.backlog - ); - for(int i = 0; i < LOG_LEVEL_COUNT; i++){ - switch(i){ - case LOG_DEBUG: printf("\t\tDEBUG:\t"); break; - case LOG_INFO: printf("\t\tINFO:\t"); break; - case LOG_WARN: printf("\t\tWARN:\t"); break; - case LOG_ERROR: printf("\t\tERROR:\t"); break; - } - printf("%d files%s\n", log_get_files(i), log_get_stderr(i) ? " + stderr" : ""); - } - printf("\t}\n"); -} - -void print_worker_config(config_w conf){ - printf( - "WORKER CONFIGURATION:\n" - "\t- name: %.*s\n" "\t- root: %.*s\n" "\t- bundle: %.*s\n" "\t- cert: %.*s\n" @@ -303,6 +225,8 @@ void print_worker_config(config_w conf){ "\t- ipv4: %s\n" "\t- ipv6: %s\n", conf.name.len, conf.name.ptr, + conf.port.len, conf.name.ptr, + conf.backlog, conf.root.len, conf.root.ptr, conf.bundle.len, conf.bundle.ptr, conf.cert.len, conf.cert.ptr, @@ -325,4 +249,3 @@ void print_worker_config(config_w conf){ } printf("\t}\n"); } - diff --git a/src/config/config.h b/src/config/config.h index 70435ac..508d5ae 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -9,16 +9,11 @@ #include <errno.h> -typedef struct config_m { +typedef struct config { str file; str name; str port; int backlog; -} config_m; - -typedef struct config_w { - str file; - str name; str root; str bundle; str cert; @@ -27,18 +22,15 @@ typedef struct config_w { uint ipv4 : 1; uint ipv6 : 1; str *files; -} config_w; +} config; -config_m master_config(char *filename); -config_w worker_config(char *filename); +config read_config(char *filename); str get_key(str file, str key); -void free_master_config(config_m *conf); -void free_worker_config(config_w *conf); +void free_config(config *conf); -void print_master_config(config_m conf); -void print_worker_config(config_w conf); +void print_config(config conf); #endif
\ No newline at end of file @@ -1,24 +1,21 @@ #include <stdio.h> #include <stdlib.h> -#include <sys/wait.h> +#include <signal.h> #include <libgen.h> +#include <sys/wait.h> #include "str/str.h" -#include "list/list.h" -#include "net/net.h" #include "log/log.h" +#include "list/list.h" #include "config/config.h" -str name; -str orig_config_file; struct { + str name; str path; - str socket_file; str config_file; str workers; } dir; -config_m config; -http_server *server; +str orig_config_file; struct worker { pid_t pid; } *workers; @@ -91,16 +88,31 @@ static void worker_undertaker(int sig, siginfo_t *info, void *ucontext){ } } -static int create_server_dir(str name){ - dir.path = dup_strs(sstr("/var/run/"), name, sstr("/")); +static int create_server_dir(char *configfile){ + str cff = map_file(configfile); + if(cff.ptr == NULL){ + log_error("Error opening config file '%s'", configfile); + return 1; + } + dir.name = get_key(cff, sstr("name")); + dir.path = dup_strs(sstr("/var/run/"), dir.name, sstr("/")); if(!dir_exists(dir.path.ptr)){ if(mkdir(dir.path.ptr, 0777) != 0){ log_error("Error creating server directory in '%.*s': %s", dir.path.len, dir.path.ptr, strerror(errno)); + unmap_file(&cff); return 1; } } - dir.socket_file = dup_strs(dir.path, sstr("socket")); dir.config_file = dup_strs(dir.path, sstr("configfile")); + FILE *cfp = fopen(dir.config_file.ptr, "w"); + if(cfp == NULL){ + log_error("Error copying config file to '%.*s': %s", dir.config_file.len, dir.config_file.ptr, strerror(errno)); + unmap_file(&cff); + return 1; + } + str_to_fp(cff, cfp); + fclose(cfp); + unmap_file(&cff); dir.workers = dup_strs(dir.path, sstr("workers/")); if(!dir_exists(dir.workers.ptr)){ if(mkdir(dir.workers.ptr, 0777) != 0){ @@ -111,97 +123,54 @@ static int create_server_dir(str name){ return 0; } -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.len, configfile.ptr); - return 1; - } - FILE *cfp = fopen(dest.ptr, "w"); - if(cfp == NULL){ - log_error("Error creating config file in '%.*s': %s", dest.len, dest.ptr, strerror(errno)); - unmap_file(&cff); - return 1; +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)); + } } - str_to_fp(cff, cfp); - fclose(cfp); - unmap_file(&cff); - return 0; -} - -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_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)); - return 1; + free_str(&dir.workers); + 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)); + } } - write(sfd, &ssocket, sizeof(ssocket)); - if(close(sfd) == -1){ - log_error("Error closing the socket file '%.*s': %s", socket_file.len, socket_file.ptr, strerror(errno)); - return 1; + free_str(&dir.config_file); + 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)); + } } - return 0; + free_str(&dir.path); + free_str(&dir.name); } 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"); + str cff = map_file(orig_config_file.ptr); + FILE *cfp = fopen(dir.config_file.ptr, "w"); + if(cfp == NULL){ + log_error("Error copying config file to '%.*s': %s", dir.config_file.len, dir.config_file.ptr, strerror(errno)); + unmap_file(&cff); quit(SIGTERM, NULL, NULL); } + str_to_fp(cff, cfp); + fclose(cfp); + unmap_file(&cff); propagate_signal(SIGCONT); } } int init(char *configfile){ - name = dsstr(basename(configfile)); orig_config_file = dsstr(configfile); - if(create_server_dir(name) != 0){ + if(create_server_dir(configfile) != 0){ log_error("Unable to create server directory"); return 1; } - 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'", dir.config_file.len, dir.config_file.ptr); - return 1; - } - 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("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; - } init_list(workers); struct sigaction rnit = { .sa_sigaction = reinit, .sa_flags = SA_SIGINFO }; if(sigaction(SIGUSR1, &rnit, NULL) == -1){ @@ -228,69 +197,23 @@ int init(char *configfile){ return 0; } -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(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(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(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); -} - void deinit(void){ - free_master_config(&config); remove_server_dir(); - destroy_http_server(&server); list_free(workers); } -void print_usage(void){ - printf("server [config]\n"); -} - -void show_commands(void){ - printf( - "(case insensitive)\n" - "f: fork\n" - "s: signal\n" - "l: list\n" - "c: clear\n" - "[0-9]: turn off ssl for worker\n" - "h: help\n" - "q: quit\n" - ); -} - int main(int argc, char *argv[]){ if(argc < 2){ - print_usage(); + printf("server [config]\n"); return 1; } - int return_value = 0; + int ret = 0; if(init(argv[1]) != 0){ - return_value = 1; + ret = 1; goto DEINIT; } @@ -325,7 +248,7 @@ int main(int argc, char *argv[]){ case 'f': case 'F': pid_t nw = fork(); if(nw == 0){ - char *args[] = {"./worker.exe", name.ptr, "&", NULL}; + char *args[] = {"./worker.exe", dir.name.ptr, "&", NULL}; execv("./worker.exe", args); log_error("Cannot exec worker: %s", strerror(errno)); return 1; @@ -337,10 +260,10 @@ int main(int argc, char *argv[]){ kill(getpid(), SIGUSR1); break; case 'l': case 'L': - printf("|-%3d workers working for us rn-|\n", list_size(workers)); char *faces[] = { "(^__^)", "(·__·)", "(>__>)", "(~ _~)", "(T__T)", "(º__º)" }; + printf("|-%3d workers working for us rn-|\n", list_size(workers)); for(int i = 0; i < list_size(workers); i++){ int index = rand()%sizeof(faces)/sizeof(faces[0]); printf("| %d %s\t\t\t|\n", workers[i].pid, faces[index]); @@ -351,7 +274,14 @@ int main(int argc, char *argv[]){ system("clear"); break; case 'h': case 'H': - show_commands(); + printf( + "(case insensitive)\n" + "f: fork\n" + "l: list\n" + "c: clear\n" + "h: help\n" + "q: quit\n" + ); break; case 'q': case 'Q': while(list_size(workers) > 0){ @@ -359,17 +289,9 @@ int main(int argc, char *argv[]){ waitpid(workers[0].pid, NULL, 0); } while(wait(NULL) > 0); - close(server->ssocket); end = true; log_info("%d children remaining alive (lie)", list_size(workers)); break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if(list_size(workers) > c-'0'){ - log_info("signaling worker[%d] %d to turn off ssl", c-'0', workers[c-'0'].pid); - sigqueue(workers[c-'0'].pid, SIGRTMIN, (union sigval){.sival_int = 0}); - } - break; } } @@ -377,7 +299,7 @@ DEINIT: deinit(); log_info("Finished cleaning up"); - return return_value; + return ret; } // inspiration: https://www.youtube.com/watch?v=cEH_ipqHbUw (https://github.com/infraredCoding/cerveur) diff --git a/src/net/net.c b/src/net/net.c index f03e4f8..526d1a7 100755 --- a/src/net/net.c +++ b/src/net/net.c @@ -38,6 +38,7 @@ http_server *setup_http_server(str port, int backlog){ hs->port = dup_str(port); hs->backlog = backlog; hs->ssocket = -1; + hs->csocket = -1; int ec, val = 1; struct addrinfo *res, hints = { .ai_family = AF_INET, .ai_socktype = SOCK_STREAM, .ai_flags = AI_PASSIVE }; @@ -51,8 +52,8 @@ http_server *setup_http_server(str port, int backlog){ goto error; } - if(setsockopt(hs->ssocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))){ - log_error("server: SO_REUSEADDR: %s", strerror(errno)); + if(setsockopt(hs->ssocket, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val))){ + log_error("server: SO_REUSEPORT: %s", strerror(errno)); goto error; } @@ -80,41 +81,15 @@ void destroy_http_server(http_server **hs){ free_str(&(*hs)->port); (*hs)->backlog = 0; close((*hs)->ssocket); + (*hs)->ssocket = -1; + close((*hs)->csocket); + (*hs)->csocket = -1; free(*hs); *hs = NULL; } } -http_worker *setup_http_worker(int ssocket, int secure, str certfile, str keyfile){ - http_worker *hw = calloc(1, sizeof(http_worker)); - hw->ssocket = ssocket; - hw->csocket = -1; - hw->secure = secure; - - if(secure){ - if(setup_https(hw, certfile, keyfile) != 0){ - log_error("Setting up HTTPS"); - terminate_https(hw); - destroy_http_worker(&hw); - } - } - - return hw; -} - -void destroy_http_worker(http_worker **hw){ - if(*hw != NULL){ - (*hw)->ssocket = -1; - close((*hw)->csocket); - (*hw)->csocket = -1; - (*hw)->secure = 0; - terminate_https(*hw); - free(*hw); - *hw = NULL; - } -} - -int setup_https(http_worker *hw, str certfile, str keyfile){ +int setup_https(http_server *hs, str certfile, str keyfile){ if(certfile.len == 0){ log_error("Missing certificate file"); return 1; @@ -124,113 +99,113 @@ int setup_https(http_worker *hw, str certfile, str keyfile){ return 1; } - if(hw->ssl != NULL){ - SSL_free(hw->ssl); + if(hs->ssl != NULL){ + SSL_free(hs->ssl); } - if(hw->ssl_ctx != NULL){ - SSL_CTX_free(hw->ssl_ctx); + if(hs->ssl_ctx != NULL){ + SSL_CTX_free(hs->ssl_ctx); } - hw->ssl_ctx = SSL_CTX_new(TLS_server_method()); + hs->ssl_ctx = SSL_CTX_new(TLS_server_method()); // need to compile openssl with ktls on for this (v) to work - SSL_CTX_set_options(hw->ssl_ctx, SSL_OP_ENABLE_KTLS | SSL_OP_IGNORE_UNEXPECTED_EOF); - if(hw->ssl_ctx == NULL){ + SSL_CTX_set_options(hs->ssl_ctx, SSL_OP_ENABLE_KTLS | SSL_OP_IGNORE_UNEXPECTED_EOF); + if(hs->ssl_ctx == NULL){ return 1; } - //SSL_CTX_set_verify(hw->ssl_ctx, SSL_VERIFY_PEER, NULL); - /*if(SSL_CTX_load_verify_locations(hw->ssl_ctx, "ssl/mkarchive.net/ca_bundle.crt", NULL) <= 0){ + //SSL_CTX_set_verify(hs->ssl_ctx, SSL_VERIFY_PEER, NULL); + /*if(SSL_CTX_load_verify_locations(hs->ssl_ctx, "ssl/mkarchive.net/ca_bundle.crt", NULL) <= 0){ log_error("Verifying certificate locations"); return 1; }*/ - if(SSL_CTX_use_certificate_file(hw->ssl_ctx, certfile.ptr, SSL_FILETYPE_PEM) <= 0){ + if(SSL_CTX_use_certificate_file(hs->ssl_ctx, certfile.ptr, SSL_FILETYPE_PEM) <= 0){ log_error("Error while trying to set up certificate file"); return 1; } - if(SSL_CTX_use_PrivateKey_file(hw->ssl_ctx, keyfile.ptr, SSL_FILETYPE_PEM) <= 0 ){ + if(SSL_CTX_use_PrivateKey_file(hs->ssl_ctx, keyfile.ptr, SSL_FILETYPE_PEM) <= 0 ){ log_error("Error while trying to set up key file"); return 1; } - hw->ssl = SSL_new(hw->ssl_ctx); - if(hw->ssl == NULL){ + hs->ssl = SSL_new(hs->ssl_ctx); + if(hs->ssl == NULL){ log_error("Creating SSL*"); return 1; } - SSL_set_accept_state(hw->ssl); - hw->secure = 1; + SSL_set_accept_state(hs->ssl); + hs->secure = 1; return 0; } -void reset_https(http_worker *hw){ - if(hw != NULL){ - close(hw->csocket); - if(hw->ssl != NULL){ - SSL_free(hw->ssl); +void reset_https(http_server *hs){ + if(hs != NULL){ + close(hs->csocket); + if(hs->ssl != NULL){ + SSL_free(hs->ssl); } - hw->ssl = SSL_new(hw->ssl_ctx); - SSL_set_accept_state(hw->ssl); + hs->ssl = SSL_new(hs->ssl_ctx); + SSL_set_accept_state(hs->ssl); } } -void terminate_https(http_worker *hw){ - if(hw != NULL){ - hw->secure = 0; - if(hw->ssl != NULL){ - SSL_free(hw->ssl); - hw->ssl = NULL; +void terminate_https(http_server *hs){ + if(hs != NULL){ + hs->secure = 0; + if(hs->ssl != NULL){ + SSL_free(hs->ssl); + hs->ssl = NULL; } - if(hw->ssl_ctx != NULL){ - SSL_CTX_free(hw->ssl_ctx); - hw->ssl_ctx = NULL; + if(hs->ssl_ctx != NULL){ + SSL_CTX_free(hs->ssl_ctx); + hs->ssl_ctx = NULL; } } } -int accept_connection(http_worker *hw, char ip[INET_ADDRSTRLEN]){ +int accept_connection(http_server *hs, char ip[INET_ADDRSTRLEN]){ struct sockaddr_storage caddr; int casize = sizeof(caddr); log_info("Waiting..."); - if((hw->csocket = accept(hw->ssocket, (struct sockaddr *)&caddr, (socklen_t*)&casize)) == -1){ + if((hs->csocket = accept(hs->ssocket, (struct sockaddr *)&caddr, (socklen_t*)&casize)) == -1){ log_error("accept_connection() -> accept(): %s", strerror(errno)); return -1; } log_info("accepted"); - if(hw->secure){ - int err = SSL_set_fd(hw->ssl, hw->csocket); + if(hs->secure){ + int err = SSL_set_fd(hs->ssl, hs->csocket); if(err != 1){ - log_error("setting fd %d", hw->csocket); - return pleasesslgivemetheerror(SSL_get_error(hw->ssl, err)); + log_error("setting fd %d", hs->csocket); + return pleasesslgivemetheerror(SSL_get_error(hs->ssl, err)); } - if((err = SSL_accept(hw->ssl)) != 1){ + if((err = SSL_accept(hs->ssl)) != 1){ log_error("couldnt accept"); - return pleasesslgivemetheerror(SSL_get_error(hw->ssl, err)); + return pleasesslgivemetheerror(SSL_get_error(hs->ssl, err)); } } inet_ntop(caddr.ss_family, &(((struct sockaddr_in*)&caddr)->sin_addr), ip, INET_ADDRSTRLEN); return 0; } -static inline int worker_read(http_worker *hw, str *buf){ - return hw->secure ? - SSL_read(hw->ssl, buf->ptr+buf->len, buf->cap-buf->len) : - recv(hw->csocket, buf->ptr+buf->len, buf->cap-buf->len, 0); +static inline int server_read(http_server *hs, str *buf){ + return hs->secure ? + SSL_read(hs->ssl, buf->ptr+buf->len, buf->cap-buf->len) : + recv(hs->csocket, buf->ptr+buf->len, buf->cap-buf->len, 0); } -int receive_request(http_worker *hw, str *request){ +int receive_request(http_server *hs, str *request){ // SSL_has_pending can return 0 if you havent read any bytes yet (https://stackoverflow.com/questions/6616976/why-does-this-ssl-pending-call-always-return-zero) - struct pollfd pfd[1] = { {.fd = hw->csocket, .events = POLLIN } }; + struct pollfd pfd[1] = { {.fd = hs->csocket, .events = POLLIN } }; while(poll(pfd, 1, 100)){ if(pfd[0].revents & POLLIN){ int rb = 0; - if(hw->secure){ - if(SSL_has_pending(hw->ssl)){ - rb = worker_read(hw, request); + if(hs->secure){ + if(SSL_has_pending(hs->ssl)){ + rb = server_read(hs, request); if(rb == 0){ - return pleasesslgivemetheerror(SSL_get_error(hw->ssl, rb)); + return pleasesslgivemetheerror(SSL_get_error(hs->ssl, rb)); } } }else{ - rb = worker_read(hw, request); + rb = server_read(hs, request); if(rb == 0){ if(request->len == 0){ return -1; @@ -461,10 +436,10 @@ url sanitize_url(str rurl){ return u; } -static inline int worker_write(http_worker *hw, str buf){ - return hw->secure ? - SSL_write(hw->ssl, buf.ptr, buf.len) : - send(hw->csocket, buf.ptr, buf.len, 0); +static inline int server_write(http_server *hs, str buf){ + return hs->secure ? + SSL_write(hs->ssl, buf.ptr, buf.len) : + send(hs->csocket, buf.ptr, buf.len, 0); } // use sendfile(2). reason: @@ -472,7 +447,7 @@ static inline int worker_write(http_worker *hw, str buf){ // Because this copying is done within the kernel, sendfile() is // more efficient than the combination of read(2) and write(2), // which would require transferring data to and from user space." -void send_file(http_worker *hw, str filename){ +void send_file(http_server *hs, str filename){ log_info("requested '%.*s' -> ", filename.len, filename.ptr); uint64_t fsize = get_file_size(filename.ptr); if(fsize == 0){ @@ -497,10 +472,10 @@ void send_file(http_worker *hw, str filename){ str header = http_header_to_str(&hm); free_str(&hm.headers[1].value); - int sent = worker_write(hw, header); + int sent = server_write(hs, header); if(sent != header.len){ - if(hw->secure){ - pleasesslgivemetheerror(SSL_get_error(hw->ssl, sent)); + if(hs->secure){ + pleasesslgivemetheerror(SSL_get_error(hs->ssl, sent)); }else{ log_error("send_file: %s", strerror(errno)); } @@ -521,14 +496,14 @@ void send_file(http_worker *hw, str filename){ // we're ignoring MAX_BODY_SIZE str fuckcygwinineedsendfile = fd_to_nstr(fd, fsize); - sent = worker_write(hw, fuckcygwinineedsendfile); + sent = server_write(hs, fuckcygwinineedsendfile); free_str(&fuckcygwinineedsendfile); if(sent > 0){ fsize -= sent; }else if(sent == 0){ break; }else{ - if(hw->secure){ - pleasesslgivemetheerror(SSL_get_error(hw->ssl, sent)); + if(hs->secure){ + pleasesslgivemetheerror(SSL_get_error(hs->ssl, sent)); }else{ perror("send_file (fuck cygwin btw)"); } diff --git a/src/net/net.h b/src/net/net.h index 297e417..d23c970 100755 --- a/src/net/net.h +++ b/src/net/net.h @@ -66,36 +66,23 @@ typedef struct http_server { str port; int backlog; int ssocket; -} http_server; - -typedef struct http_worker { - int ssocket; int csocket; int secure; SSL_CTX *ssl_ctx; SSL *ssl; -} http_worker; - -#define MAX_RESPONSE_SIZE 0x0FFFFFFF -#define MAX_BODY_SIZE (MAX_RESPONSE_SIZE - 0x0FFF) - -#define insert_header(hm, h) \ - (hm).headers[(hm).hlen++] = (h) +} http_server; http_server *setup_http_server(str port, int backlog); void destroy_http_server(http_server **hs); -http_worker *setup_http_worker(int ssocket, int secure, str certfile, str keyfile); -void destroy_http_worker(http_worker **hw); - -int setup_https(http_worker *hw, str certfile, str keyfile); -void reset_https(http_worker *hw); -void terminate_https(http_worker *hw); +int setup_https(http_server*hs, str certfile, str keyfile); +void reset_https(http_server *hs); +void terminate_https(http_server *hs); -int accept_connection(http_worker *hw, char ip[INET_ADDRSTRLEN]); +int accept_connection(http_server *hs, char ip[INET_ADDRSTRLEN]); -int receive_request(http_worker *hw, str *request); +int receive_request(http_server *hs, str *request); str generate_resource(url resource, str rurl); @@ -107,6 +94,6 @@ enum http_method get_http_method(str method); url sanitize_url(str rurl); -void send_file(http_worker *hw, str filename); +void send_file(http_server *hs, str filename); #endif
\ No newline at end of file diff --git a/src/rewrites/rewrites.c b/src/rewrites/rewrites.c index 3a9a762..cf7f4f0 100644 --- a/src/rewrites/rewrites.c +++ b/src/rewrites/rewrites.c @@ -25,9 +25,6 @@ void read_url_rewrites(str file){ off += rwt.output.query.len; while(off < file.len && !charislinebreak(file.ptr[off++])); if(rwt.pattern.len != 0 && rwt.output.path.len != 0){ - rwt.pattern.ptr[rwt.pattern.len] = '\0'; - rwt.output.path.ptr[rwt.output.path.len] = '\0'; - rwt.output.query.ptr[rwt.output.query.len] = '\0'; list_push(rewrites, rwt); } } diff --git a/src/worker.c b/src/worker.c index b919b64..ce185bd 100755 --- a/src/worker.c +++ b/src/worker.c @@ -6,14 +6,13 @@ #include "config/config.h" -config_w config; struct { str path; - str socket_path; str config_file; str self; } dir; -http_worker *worker; +config conf; +http_server *server; // remove these or something int secure = 0; @@ -21,13 +20,13 @@ int secure = 0; 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)); deinit(); exit(0); } -int signal_wait(int sig){ +static int signal_wait(int sig){ sigset_t old, new; sigemptyset(&new); sigaddset(&new, sig); @@ -45,27 +44,23 @@ int signal_wait(int sig){ return 0; } -void reinit(int sig, siginfo_t *info, void *ucontext){ +static void reinit(int sig, siginfo_t *info, void *ucontext){ if(sig == SIGUSR1){ log_info("Reinitializing worker"); - free_worker_config(&config); - destroy_http_worker(&worker); + free_config(&conf); + destroy_http_server(&server); 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){ + conf = read_config(dir.config_file.ptr); + if(conf.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){ + server = setup_http_server(conf.port, conf.backlog); + if(server == NULL){ log_error("Error setting up worker server"); quit(SIGTERM, NULL, NULL); } @@ -73,17 +68,12 @@ void reinit(int sig, siginfo_t *info, void *ucontext){ } // possibly change name -int read_server_dir(str name){ +static int read_server_dir(str name){ dir.path = dup_strs(sstr("/var/run/"), name, sstr("/")); if(!dir_exists(dir.path.ptr)){ log_error("No server directory in '%.*s'", dir.path.len, dir.path.ptr); return 1; } - dir.socket_path = dup_strs(dir.path, sstr("socket")); - if(!file_exists(dir.socket_path.ptr)){ - log_error("No socket file in '%.*s'", dir.socket_path.len, dir.socket_path.ptr); - return 1; - } dir.config_file = dup_strs(dir.path, sstr("configfile")); if(!file_exists(dir.config_file.ptr)){ log_error("No config file in '%.*s'", dir.config_file.len, dir.config_file.ptr); @@ -93,10 +83,6 @@ int read_server_dir(str name){ str pid = utostr(getpid(), 10); dir.self = dup_strs(dir.path, sstr("workers/"), pid); free_str(&pid); - if(file_exists(dir.self.ptr)){ - log_error("Error creating PID record for self in '%.*s': it already exists", dir.self.len, dir.self.ptr); - return 1; - } if(creat(dir.self.ptr, 0777) == -1){ log_error("Error creating PID record for self in '%.*s': %s", dir.self.len, dir.self.ptr, strerror(errno)); return 1; @@ -104,25 +90,29 @@ int read_server_dir(str name){ return 0; } +// possibly change name +static void remove_server_dir(void){ + if(remove(dir.self.ptr) != 0){ + log_error("Error removing PID record for self in '%.*s': %s", dir.self.len, dir.self.ptr, strerror(errno)); + } + free_str(&dir.self); + free_str(&dir.config_file); + free_str(&dir.path); +} + int init(str name){ if(read_server_dir(name) != 0){ log_error("Error reading server directory"); return 1; } - config = worker_config(dir.config_file.ptr); - if(config.file.ptr == NULL){ + conf = read_config(dir.config_file.ptr); + if(conf.file.ptr == NULL){ log_error("Unable to read config from '%.*s'", dir.config_file.len, dir.config_file.ptr); return 1; } //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 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){ + server = setup_http_server(conf.port, conf.backlog); + if(server == NULL){ log_error("Error setting up worker server"); return 1; } @@ -147,30 +137,17 @@ int init(str name){ return 0; } -// possibly change name -void remove_server_dir(void){ - if(remove(dir.self.ptr) != 0){ - log_error("Error removing PID record for self in '%.*s': %s", dir.self.len, dir.self.ptr, strerror(errno)); - } - free_str(&dir.self); - free_str(&dir.path); -} - void deinit(void){ - free_worker_config(&config); + destroy_http_server(&server); + free_config(&conf); remove_server_dir(); - destroy_http_worker(&worker); -} - -void print_usage(void){ - printf("worker [server name]\n"); } int main(int argc, char **argv){ if(argc < 2){ - print_usage(); + printf("worker [server name]\n"); return 1; } @@ -187,24 +164,24 @@ int main(int argc, char **argv){ while(1){ char cip[INET_ADDRSTRLEN] = {0}; - return_value = accept_connection(worker, cip); + return_value = accept_connection(server, cip); switch(return_value){ case -1: // couldnt accept, do something ig continue; case SSL_ERROR_SSL: - reset_https(worker); + reset_https(server); log_info("continuing\n"); continue; } - log_info("socket %d accepted with ip %s", worker->csocket, cip); - return_value = receive_request(worker, &request); + log_info("socket %d accepted with ip %s", server->csocket, cip); + return_value = receive_request(server, &request); log_debug("received %d from receive_request", return_value); switch(return_value){ case -1: // couldnt accept, do something ig goto finish_request; break; case SSL_ERROR_SSL: - reset_https(worker); + reset_https(server); log_info("continuing\n"); continue; } @@ -221,13 +198,13 @@ int main(int argc, char **argv){ switch(method){ case GET: str resource = generate_resource(surl, hm.url); - send_file(worker, resource); + send_file(server, resource); //if(resource.temp == true) remove(resource.name.ptr); free_str(&resource); break; case POST: //handlePOST(request); - send(worker->csocket, "HTTP/1.1 201 Created\r\n\r\n", len("HTTP/1.1 201 Created\r\n\r\n"), 0); + send(server->csocket, "HTTP/1.1 201 Created\r\n\r\n", len("HTTP/1.1 201 Created\r\n\r\n"), 0); break; case PUT: break; @@ -243,10 +220,10 @@ finish_request: log_debug("query freed"); request.len = 0; - if(worker->secure){ - SSL_clear(worker->ssl); + if(server->secure){ + SSL_clear(server->ssl); } - close(worker->csocket); + close(server->csocket); //SSL_shutdown(config.ssl); // look into SSL_clear() |
