summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSoikk2025-11-22 16:42:08 +0100
committerSoikk2025-11-22 16:42:08 +0100
commit3abcc43f1e638608b4b88bbb0ad7881d74940f8d (patch)
treed5b5e2bf93ff0bbcf3c3d860c2266516e91492c4
parentc2e397b6ee390d06f1af8921a514fdcf90e3f2fa (diff)
downloadsoikk-server-3abcc43f1e638608b4b88bbb0ad7881d74940f8d.tar.xz
soikk-server-3abcc43f1e638608b4b88bbb0ad7881d74940f8d.tar.zst
Rewrites and IPC rework
- Moved functionality to temporary server directory - Separated rewrites - Moved IPC back to signals - Added get_key() in config - Reworked receive_request() - Improved error handling
-rwxr-xr-xMakefile4
-rw-r--r--config.example16
-rw-r--r--src/config/config.c62
-rw-r--r--src/config/config.h5
-rwxr-xr-xsrc/main.c205
-rwxr-xr-xsrc/net/net.c225
-rwxr-xr-xsrc/net/net.h23
-rw-r--r--src/rewrites/rewrites.c160
-rw-r--r--src/rewrites/rewrites.h29
-rwxr-xr-xsrc/worker.c317
10 files changed, 646 insertions, 400 deletions
diff --git a/Makefile b/Makefile
index 6d0d631..32613f4 100755
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
CC = gcc
-CFLAGS = -O0 -Wall -ggdb3
+CFLAGS = -O0 -Wall -ggdb3 -D_GNU_SOURCE
LDFLAGS = -lssl -lcrypto
SRCDIR = src
@@ -12,7 +12,7 @@ else
RUNCMD = ./server.exe
endif
-OBJS = $(addprefix $(OBJDIR)/, bit.o files.o str.o log.o list.o crc64.o net.o ipc.o mime.o config.o)
+OBJS = $(addprefix $(OBJDIR)/, bit.o files.o str.o log.o list.o crc64.o net.o ipc.o mime.o rewrites.o config.o)
INCL = -I$(LIBDIR) -I$(SRCDIR)
diff --git a/config.example b/config.example
index 542dfe9..d8a946b 100644
--- a/config.example
+++ b/config.example
@@ -1,7 +1,7 @@
# lines that start with # are skipped
name website.com # name of the server. the # isnt really needed here as the config reader skips to the next line once it reads the needed value
-port 443 # port the server will be running on
-backlog 15 # backlog for the socket
+port 80 # port the server will be running on
+backlog 15 # backlog for the socket
logs {
# adds logging (for all processes) to specified files, and can turn logging to stderr off (0) or on (not 0)
# log level log file read mode
@@ -16,12 +16,18 @@ logs {
worker {
root /home/user/server/ # where the server will look for files, basically files prefix
bundle /ca/bundle/location # location of ca bundle
- cert /certificate/location # location of certificate
- key /key/location #location of private key
+ cert ssl/cert.pem # location of certificate
+ key ssl/key.pem #location of private key
http # turns https off
- https # turns https on
+ # 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
diff --git a/src/config/config.c b/src/config/config.c
index c90364f..4cd4835 100644
--- a/src/config/config.c
+++ b/src/config/config.c
@@ -69,11 +69,15 @@ static void rotate_logs(str logs){
config_m master_config(char *filename){
config_m conf = {0};
conf.file = map_file(filename);
+ if(conf.file.ptr == NULL){
+ log_error("Unable to open config file '%s'", filename);
+ return conf;
+ }
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])) off++;
+ while(off < conf.file.len && !charislinebreak(conf.file.ptr[off++]));
continue;
}
str key = sread_delim_f(conf.file.ptr + off, charisspace, true);
@@ -83,6 +87,7 @@ config_m master_config(char *filename){
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("port"))){
str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
off += val.len;
@@ -116,8 +121,7 @@ config_m master_config(char *filename){
}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])) off++;
- off++;
+ while(off < conf.file.len && !charislinebreak(conf.file.ptr[off++]));
};
return conf;
@@ -135,7 +139,7 @@ config_w worker_config(char *filename){
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])) off++;
+ while(off < conf.file.len && !charislinebreak(conf.file.ptr[off++]));
continue;
}
str key = sread_delim_f(conf.file.ptr + off, charisspace, true);
@@ -145,20 +149,23 @@ config_w worker_config(char *filename){
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"))){
- str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
- off += val.len;
- str trailslash = val.ptr[val.len-1] == '/' ? sstr("") : sstr("/");
- conf.root = dup_strs(val, trailslash);
+ conf.root = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += conf.root.len;
+ conf.file.ptr[off] = '\0';
}else if(streq(key, sstr("bundle"))){
conf.bundle = sread_delim_f(conf.file.ptr + off, charisspace, true);
off += conf.bundle.len;
+ conf.file.ptr[off] = '\0';
}else if(streq(key, sstr("cert"))){
conf.cert = sread_delim_f(conf.file.ptr + off, charisspace, true);
off += conf.cert.len;
+ conf.file.ptr[off] = '\0';
}else if(streq(key, sstr("key"))){
conf.key = sread_delim_f(conf.file.ptr + off, charisspace, true);
off += conf.key.len;
+ conf.file.ptr[off] = 0;
}else if(streq(key, sstr("https"))){
conf.secure = 1;
}else if(streq(key, sstr("http"))){
@@ -181,6 +188,20 @@ config_w worker_config(char *filename){
off += types.len;
}
read_mime_types(types);
+ }else if(streq(key, sstr("rewrites"))){
+ str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
+ off += val.len;
+ str rewrites;
+ if(val.ptr[0] != '{'){
+ str rewritesfile = dup_str(val);
+ rewrites = map_file(rewritesfile.ptr);
+ list_push(conf.files, rewrites);
+ free_str(&rewritesfile);
+ }else{
+ rewrites = sread_delim(conf.file.ptr + off, '}');
+ off += rewrites.len;
+ }
+ read_url_rewrites(rewrites);
}else if(streq(key, sstr("logs"))){
str val = sread_delim_f(conf.file.ptr + off, charisspace, true);
off += val.len;
@@ -196,13 +217,32 @@ config_w worker_config(char *filename){
rotate_logs(logs);
free_str(&logs);
}
- while(off < conf.file.len && !charislinebreak(conf.file.ptr[off])) off++;
- off++;
+ while(off < conf.file.len && !charislinebreak(conf.file.ptr[off++]));
};
return conf;
}
+str get_key(str file, str key){
+ int off = 0;
+ while(off < file.len){
+ while(off < file.len && charisspace(file.ptr[off])) off++;
+ if(file.ptr[off] == '#'){
+ while(off < file.len && !charislinebreak(file.ptr[off])) off++;
+ continue;
+ }
+ str candidate = sread_delim_f(file.ptr + off, charisspace, true);
+ off += candidate.len;
+ while(off < file.len && charisspace(file.ptr[off]) && !charislinebreak(file.ptr[off])) off++;
+ if(streq(key, candidate)){
+ return read_delim_f(file.ptr + off, charisspace, true);
+ }
+ while(off < file.len && !charislinebreak(file.ptr[off])) off++;
+ off++;
+ }
+ return (str){0};
+}
+
void free_master_config(config_m *conf){
conf->name = (str){0};
conf->port = (str){0};
@@ -220,6 +260,7 @@ void free_worker_config(config_w *conf){
conf->ipv4 = 0;
conf->ipv6 = 0;
free_mime_types();
+ free_url_rewrites();
for(int i = 0; i < list_size(conf->files); i++){
unmap_file(&conf->files[i]);
}
@@ -271,6 +312,7 @@ void print_worker_config(config_w conf){
conf.ipv6 ? "yes" : "no"
);
print_mime_types();
+ print_url_rewrites();
printf("\t- logs: {\n");
for(int i = 0; i < LOG_LEVEL_COUNT; i++){
switch(i){
diff --git a/src/config/config.h b/src/config/config.h
index 3f74fc3..70435ac 100644
--- a/src/config/config.h
+++ b/src/config/config.h
@@ -5,6 +5,7 @@
#include "log/log.h"
#include "list/list.h"
#include "mime/mime.h"
+#include "rewrites/rewrites.h"
#include <errno.h>
@@ -32,10 +33,12 @@ typedef struct config_w {
config_m master_config(char *filename);
config_w worker_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 print_master_config(config_m conf);
void print_worker_config(config_w conf);
-#endif
+#endif \ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 78312c5..98da9d0 100755
--- a/src/main.c
+++ b/src/main.c
@@ -14,9 +14,9 @@
config_m config;
struct {
str path;
- str sock_path;
- str sock_addr;
+ str socket_file;
str ipc_addr;
+ str config_file;
str workers;
} dir;
http_server *server;
@@ -27,10 +27,69 @@ struct worker {
} *workers;
+static void propagate_signal(int sig, siginfo_t *info, void *ucontext){
+ for(int i = 0; i < list_size(workers); i++){
+ kill(workers[i].pid, sig);
+ }
+}
+
+void deinit(void);
+
+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);
+ deinit();
+ exit(0);
+}
+
+static void cleanup_worker(pid_t pid, int cleandir){
+ waitpid(pid, NULL, 0);
+ list_remove_entry(workers, pid);
+ if(cleandir){
+ str spid = utostr(pid, 10);
+ str workerfile = dup_strs(dir.workers, spid);
+ if(remove(workerfile.ptr) != 0){
+ log_error("Error cleaning up worker's %d file '%.*s': %s", pid, workerfile.len, workerfile.ptr, strerror(errno));
+ }
+ free_str(&workerfile);
+ free_str(&spid);
+ }
+}
+
+// TODO: look more into waitpid()
+// TODO: make a wrapper for sigabbrev_np
void worker_undertaker(int sig, siginfo_t *info, void *ucontext){
if(sig == SIGCHLD && list_entry_exists(workers, info->si_pid)){
- list_remove_entry(workers, info->si_pid);
- log_warn("worker %d is dead. now workers size is %d", info->si_pid, list_size(workers));
+ switch(info->si_code){
+ case CLD_EXITED:
+ cleanup_worker(info->si_pid, 0);
+ log_info("Worker process %d exited normally with exit value %d",info->si_pid, info->si_status);
+ break;
+ case CLD_KILLED:
+ cleanup_worker(info->si_pid, 1);
+ log_info("Worker process %d was killed by signal SIG%s (%s)",
+ info->si_pid, sigabbrev_np(info->si_status), sigdescr_np(info->si_status));
+ break;
+ case CLD_DUMPED:
+ cleanup_worker(info->si_pid, 1);
+ log_info("Worker process %d was killed by signal SIG%s (%s) and produced a core dump",
+ info->si_pid, sigabbrev_np(info->si_status), sigdescr_np(info->si_status));
+ break;
+ case CLD_TRAPPED:
+ log_info("Worker process %d was trapped by signal %d", info->si_pid, info->si_status);
+ break;
+ case CLD_STOPPED:
+ log_info("Worker process %d was stopped by signal %d", info->si_pid, info->si_status);
+ break;
+ case CLD_CONTINUED:
+ log_info("Worker process %d was continued by signal %d", info->si_pid, info->si_status);
+ break;
+ default:
+ cleanup_worker(info->si_pid, 1);
+ log_info("Received SIGCHLD for process %d for some reason, with exit code/signal %d", info->si_pid, info->si_status);
+ break;
+ }
+ log_debug("Now workers size is %d", list_size(workers));
}
}
@@ -42,24 +101,8 @@ int create_server_dir(str name){
return 1;
}
}
- dir.sock_path = dup_strs(dir.path, sstr("socket/"));
- log_info("creating sock path in %.*s", dir.sock_path.len, dir.sock_path.ptr);
- if(!dir_exists(dir.sock_path.ptr)){
- // TODO: else? how to reattach to socket? how to leave socket reattachable?
- // TODO: look at ptrace(2)
- if(mkdir(dir.sock_path.ptr, 0777) != 0){
- log_error("Error creating socket directory in '%.*s': %s", dir.sock_path.len, dir.sock_path.ptr, strerror(errno));
- return 1;
- }
- }
- str sssocket = utostr(server->ssocket, 10);
- dir.sock_addr = dup_strs(dir.sock_path, sssocket);
- free_str(&sssocket);
- log_info("creating sock in %.*s", dir.sock_addr.len, dir.sock_addr.ptr);
- if(creat(dir.sock_addr.ptr, 0777) == -1){
- log_error("Error creating socket file for server in '%.*s': %s", dir.sock_addr.len, dir.sock_addr.ptr, strerror(errno));
- return 1;
- }
+ dir.socket_file = dup_strs(dir.path, sstr("socket"));
+ dir.config_file = dup_strs(dir.path, sstr("configfile"));
dir.ipc_addr = dup_strs(dir.path, sstr("ipcserver"));
if(path_exists(dir.ipc_addr.ptr)){
if(remove(dir.ipc_addr.ptr) != 0){
@@ -77,13 +120,58 @@ int create_server_dir(str name){
return 0;
}
+int copy_config_file(char *configfile, str dest){
+ str cff = map_file(configfile);
+ if(cff.ptr == NULL){
+ log_error("Error opening config file '%s'", configfile);
+ 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;
+ }
+ str_to_fp(cff, cfp);
+ fclose(cfp);
+ unmap_file(&cff);
+ return 0;
+}
+
+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);
+ 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;
+ }
+ 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;
+ }
+ return 0;
+}
+
int init(char *configfile){
- config = master_config(configfile);
- if(config.name.len == 0){ // TODO: maybe check for this someway else
+ str file = map_file(configfile);
+ str name = get_key(file, sstr("name"));
+ unmap_file(&file);
+ if(create_server_dir(name) != 0){
+ free_str(&name);
+ return 1;
+ }
+ free_str(&name);
+ if(copy_config_file(configfile, dir.config_file) != 0){
+ return 1;
+ }
+ config = master_config(dir.config_file.ptr);
+ if(config.file.ptr == NULL){
log_error("Unable to read config from '%s'", configfile);
return 1;
}
- print_master_config(config);
+ //print_master_config(config);
log_info("Succesfully read master config from '%s'", configfile);
// decouple so the whole net.c doesnt get linked?
server = setup_http_server(config.port, config.backlog);
@@ -91,32 +179,36 @@ int init(char *configfile){
log_error("Error setting up socket server");
return 1;
}
- if(create_server_dir(config.name) != 0){
+ if(write_server_socket(dir.socket_file, server->ssocket)){
return 1;
}
- // configurable name?
sender = setup_ipc_sender(dir.ipc_addr, IPC_BACKLOG);
if(sender == NULL){
log_error("Error setting up IPC sender");
return 1;
}
init_list(workers);
- struct sigaction chld = { .sa_sigaction = worker_undertaker, .sa_flags = SA_SIGINFO };
+ 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));
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));
+ return 1;
+ }
+ if(sigaction(SIGQUIT, &qit, NULL) == -1){
+ log_error("Error setting up SIGQUIT signal handler: %s", strerror(errno));
+ return 1;
+ }
+ if(sigaction(SIGINT, &qit, NULL) == -1){
+ log_error("Error setting up SIGINT signal handler: %s", strerror(errno));
+ }
return 0;
}
void remove_server_dir(void){
- if(remove(dir.sock_addr.ptr) != 0){
- log_error("Error removing socket file in '%.*s': %s", dir.sock_addr.len, dir.sock_addr.ptr, strerror(errno));
- }
- if(remove(dir.sock_path.ptr) != 0){
- log_error("Error removing socket path in '%.*s': %s", dir.sock_path.len, dir.sock_path.ptr, strerror(errno));
- }
- // remove workers entries first
if(remove(dir.workers.ptr) != 0){
log_error("Error removing workers directory in '%.*s': %s", dir.workers.len, dir.workers.ptr, strerror(errno));
}
@@ -125,6 +217,14 @@ void remove_server_dir(void){
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));
+ }
+ 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));
+ }
+ 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));
}
@@ -170,10 +270,6 @@ int main(int argc, char *argv[]){
return_value = 1;
goto DEINIT;
}
- log_debug("test");
- log_info("test");
- log_warn("test");
- log_error("test");
#ifdef SHOW_IP
system("curl -s http://ipinfo.io/ip && echo");
@@ -206,31 +302,24 @@ int main(int argc, char *argv[]){
case 'f': case 'F':
pid_t nw = fork();
if(nw == 0){
- char *args[] = {"./worker.exe", dir.ipc_addr.ptr, NULL};
+ char *args[] = {"./worker.exe", config.name.ptr, "&", NULL};
execv("./worker.exe", args);
log_error("Cannot exec worker: %s", strerror(errno));
return 1;
}
struct worker w = { .pid = nw, .wsocket = accept(sender->ssocket, NULL, NULL) };
list_push(workers, w);
- send_ipc_message(w.wsocket, CERT, sstr("ssl/cert.pem"));
- send_ipc_message(w.wsocket, KEY, sstr("ssl/key.pem"));
- str ss = utostr(server->ssocket, 10);
- send_ipc_message(w.wsocket, SOCKET, ss);
- free_str(&ss);
- send_ipc_message(w.wsocket, REWRITES, sstr("urirewrites"));
- //send_ipc_message(w.wsocket, HTTPS, sstr(""));
- break;
- case 's':
- for(int i = 0; i < list_size(workers); i++){
- send_ipc_message(workers[i].wsocket, HTTPS, sstr(""));
- }
- break;
- case 'S':
- for(int i = 0; i < list_size(workers); i++){
- send_ipc_message(workers[i].wsocket, HTTP, sstr(""));
- }
break;
+ // case 's':
+ // for(int i = 0; i < list_size(workers); i++){
+ // send_ipc_message(workers[i].wsocket, HTTPS, sstr(""));
+ // }
+ // break;
+ // case 'S':
+ // for(int i = 0; i < list_size(workers); i++){
+ // 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(""));
@@ -256,7 +345,7 @@ int main(int argc, char *argv[]){
case 'q': case 'Q':
while(list_size(workers) > 0){
shutdown(workers[0].wsocket, SHUT_RDWR);
- //kill(workers[0].pid, SIGQUIT); // redo this PLEASE
+ kill(workers[0].pid, SIGTERM); // redo this PLEASE
waitpid(workers[0].pid, NULL, 0);
}
while(wait(NULL) > 0);
diff --git a/src/net/net.c b/src/net/net.c
index 3e70cef..19792f1 100755
--- a/src/net/net.c
+++ b/src/net/net.c
@@ -12,8 +12,6 @@ str response_headers[] = {
sstr("Transfer-Encoding"),
};
-LIST(struct uri_mod) uri_rewrites = NULL;
-
static int pleasesslgivemetheerror(int ssl_get_error){
char *error;
switch(ssl_get_error){
@@ -145,11 +143,11 @@ int setup_https(http_worker *hw, str certfile, str keyfile){
return 1;
}*/
if(SSL_CTX_use_certificate_file(hw->ssl_ctx, certfile.ptr, SSL_FILETYPE_PEM) <= 0){
- log_error("Using certificate file");
+ 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 ){
- log_error("Using private key file");
+ log_error("Error while trying to set up key file");
return 1;
}
hw->ssl = SSL_new(hw->ssl_ctx);
@@ -193,7 +191,7 @@ int accept_connection(http_worker *hw, char ip[INET_ADDRSTRLEN]){
int casize = sizeof(caddr);
log_info("Waiting...");
if((hw->csocket = accept(hw->ssocket, (struct sockaddr *)&caddr, (socklen_t*)&casize)) == -1){
- log_error("accept_socket() -> accept(): %s", strerror(errno));
+ log_error("accept_connection() -> accept(): %s", strerror(errno));
return -1;
}
log_info("accepted");
@@ -221,46 +219,56 @@ static inline int worker_read(http_worker *hw, str *buf){
int receive_request(http_worker *hw, 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 } };
- while((hw->secure && SSL_has_pending(hw->ssl)) || poll(pfd, 1, 100)){
- int new = worker_read(hw, request);
- if(new < 0 || (hw->secure && new == 0)){
- int error = new;
- if(hw->secure) error = pleasesslgivemetheerror(SSL_get_error(hw->ssl, new));
- else log_error("http (no s) error: %s", strerror(errno));
- return error;
- }
- request->len += new;
- if(request->len == request->cap){
- log_info("gotta resize buffer");
- if(resize_str(request, request->cap*2) != 0){
- log_error("Not enough memory in reply str");
- return -1;
+ 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(rb == 0){
+ return pleasesslgivemetheerror(SSL_get_error(hw->ssl, rb));
+ }
+ }
+ }else{
+ rb = worker_read(hw, request);
+ if(rb == 0){
+ if(request->len == 0){
+ return -1;
+ }
+ return 0;
+ }
+ if(rb < 0){
+ return rb;
+ }
+ }
+ request->len += rb;
+ if(request->len == request->cap){
+ log_debug("gotta resize buffer");
+ if(resize_str(request, request->cap*2) != 0){
+ log_error("Not enough memory in reply str");
+ return -1;
+ }
}
+ }else{
+ log_error("Socket returned revents '%d'", pfd[0].revents);
}
}
return 0;
}
-str generate_resource(struct uri resource, str url){
- str file = {0};
+str generate_resource(url resource, str rurl){
/*
generate if all of these are true
1) no file specified (aka we need index.html)
2) theres an index.html.php
3) index.html isnt cached (future)
*/
- str phpfile = dnstr(resource.path.len + slen(".php"));
- copy_strs(phpfile, resource.path, sstr(".php"));
+ str phpfile = dup_strs(resource.path, sstr(".php"));
if(access(phpfile.ptr, F_OK) == 0){
// we need a str_copy or something
- str command = dnstr(
- slen("REQUEST_URI='") + resource.path.len + slen("' QUERY_STRING='") + resource.query.len +
- slen("' URL='") + url.len +
- slen("' php -c ./ ") + phpfile.len + slen(" > ") + resource.path.len
- );
- copy_strs(command,
+ str command = dup_strs(command,
sstr("REQUEST_URI='"), resource.path, sstr("' QUERY_STRING='"), resource.query,
- sstr("' URL='"), url,
+ sstr("' URL='"), rurl,
sstr("' php -c ./ "), phpfile, sstr(" > "), resource.path
);
log_warn("command: %s", command.ptr);
@@ -268,7 +276,7 @@ str generate_resource(struct uri resource, str url){
free_str(&command);
}
free_str(&phpfile);
- file = dup_str(resource.path);
+ str file = dup_str(resource.path);
/*
if(uri.query.len > 0){
if(access(uri.path.ptr, F_OK) != 0){
@@ -343,8 +351,8 @@ void build_http_message(char *request, int rlen, struct http_message *hm){
while(request < end && *request != ' ') hm->method.len++, request++;
if(++request >= end) return;
- hm->uri.ptr = request;
- while(request < end && *request != ' ') hm->uri.len++, request++;
+ hm->url.ptr = request;
+ while(request < end && *request != ' ') hm->url.len++, request++;
if(++request >= end) return;
hm->req_ver.ptr = request;
@@ -393,7 +401,7 @@ __attribute__ ((optimize(3))) http_method get_http_method(str method){
static uint64_t http_len(struct http_message *hm){
uint64_t len = 0;
- len += hm->method.len + hm->uri.len + hm->req_ver.len + 5 + 2;
+ len += hm->method.len + hm->url.len + hm->req_ver.len + 5 + 2;
for(int i = 0; i < hm->hlen; ++i){
len += hm->headers[i].name.len + hm->headers[i].value.len + 4;
}
@@ -420,7 +428,7 @@ static uint64_t http_len(struct http_message *hm){
static str http_header_to_str(struct http_message *hm){
str s = {0};
s.ptr = calloc(http_len(hm) + 1, sizeof(char));
- copy_strs(s, hm->method, sstr(" "), hm->uri, sstr(" "), hm->req_ver, sstr("\r\n"));
+ copy_strs(s, hm->method, sstr(" "), hm->url, sstr(" "), hm->req_ver, sstr("\r\n"));
for(int i = 0; i < hm->hlen; i++){
copy_strs(s, hm->headers[i].name, sstr(": "), hm->headers[i].value, sstr("\r\n"));
}
@@ -428,110 +436,28 @@ static str http_header_to_str(struct http_message *hm){
return s;
}
-/*
- Given two strings p and u, and a uri (a struct with two strings) o
- where p is a pattern, u is a url that is gonna checked for the pattern
- and o is the uri output blueprint that must be returned should u follow p
-
- There is a tokens array where tokens found in the url can be stored (up to 9 tokens)
-
- In p:
- <X> optionally matches a character X and stores it in the tokens array
- ^ optionally matches any character and stores it in the tokens array
- * optionally matches a string of character until another match is found
- or the url to match ends, and stores it in the tokens array
-
- In o:
- $1 through $9 reference the tokens in the token array (I could make it 10 tokens tbh)
- Both the strings in the uri can access these tokens
- Referencing a token writes it to the output uri
- If theres a token before a <X>, say $3<a> that means that the character
- between the less than and greater than signs will only be written
- to the output if the token number 3 in the array exists (has length > 0)
- All other characters get outputted normally
-*/
-static struct uri uri_rewrite(str p, str u, struct uri o){
- int i = 0, j = 0, in = 0, ti = 0;
- str tokens[9] = {0};
- for(; j < p.len; i += 1){
- if(i < u.len && p.ptr[j+in] == '<' && p.ptr[j+in+1] == u.ptr[i]){
- if(ti < 9) tokens[ti++] = (str){.ptr = u.ptr+i, .len = 1};
- j += 3+in, in = 0;
- }else if(i < u.len && (p.ptr[j+in] == '^' || p.ptr[j+in] == u.ptr[i])){
- if(p.ptr[j] == '^' && ti < 9) tokens[ti++] = (str){.ptr = u.ptr+i, .len = 1};
- j += 1+in, in = 0;
- }else if(i < u.len && p.ptr[j] == '*'){
- if(!in){
- if(ti < 9) tokens[ti++] = (str){.ptr = u.ptr+i, .len = 0};
- in = 1;
- }
- if(ti-in < 9) tokens[ti-in].len++;
- }else{
- if(i >= u.len && p.ptr[j] == '*') j++;
- else if(i >= u.len && p.ptr[j] == '<') j += 3;
- else return (struct uri){0};
- }
- }
- if(i < u.len) return (struct uri){0};
- struct uri r = {0};
- str *no = &o.path, *nr = &r.path;
- for(int k = 0, rlen = 0; k < 2; k++, no = &o.query, nr = &r.query){
- for(int i = 0; i < no->len; i++, rlen++){
- if(no->ptr[i] == '$') rlen += tokens[no->ptr[++i]-'1'].len-1;
- }
- nr->ptr = calloc(rlen+1, sizeof(char));
- if(nr->ptr == NULL){
- if(r.path.ptr != NULL) free(r.path.ptr);
- return (struct uri){0};
- }
-
- for(int i = 0; i < no->len; i++){
- if(no->ptr[i] == '$'){
- if(++i+1 < no->len && no->ptr[i+1] == '<'){
- if(tokens[no->ptr[i]-'1'].len > 0) i++;
- else while(no->ptr[++i] != '>');
- }else{
- copy_str((*nr), tokens[no->ptr[i]-'1']);
- }
- }else{
- if(no->ptr[i] != '>') nr->ptr[nr->len++] = no->ptr[i];
- }
- }
- }
-
- return r;
-}
-
-struct uri sanitize_uri(str uri){
- str suri = {.ptr = calloc(uri.len+1, sizeof(char)), .len = 0};
- if(suri.ptr == NULL) return (struct uri){0};
- int i = 0, o = 0;
- while(i+o < uri.len){
- suri.ptr[i] = lowerchar(uri.ptr[i+o]);
- if(i > 0 && (
- (uri.ptr[i+o] == '/' && uri.ptr[i+o-1] == '/') ||
- (uri.ptr[i+o] == '.' && uri.ptr[i+o-1] == '.') ||
- (uri.ptr[i+o] == '/' && i+o+1 == uri.len) ||
- uri.ptr[i+o] == '%')
+url sanitize_url(str rurl){
+ str srurl = dnstr(rurl.len);
+ if(srurl.ptr == NULL) return (url){0};
+ int o = 0;
+ while(srurl.len+o < rurl.len){
+ srurl.ptr[srurl.len] = lowerchar(rurl.ptr[srurl.len+o]);
+ if(srurl.len > 0 && (
+ (rurl.ptr[srurl.len+o] == '/' && rurl.ptr[srurl.len+o-1] == '/') ||
+ (rurl.ptr[srurl.len+o] == '.' && rurl.ptr[srurl.len+o-1] == '.') ||
+ (rurl.ptr[srurl.len+o] == '/' && srurl.len+o+1 == rurl.len) ||
+ rurl.ptr[srurl.len+o] == '%')
){
++o;
}else{
- ++i;
+ srurl.len++;
}
}
- suri.ptr[suri.len = i] = '\0';
-
- struct uri u = {0};
- for(int i = 0; i < list_size(uri_rewrites); i++){
- u = uri_rewrite(uri_rewrites[i].pattern, suri, uri_rewrites[i].output);
- if(u.path.len > 0) break;
- }
- free_str(&suri);
- if(u.path.len == 0){
- u.path = dstr("localc/404/index.html");
- free_str(&u.query);
- }
+ log_debug("before:\t'%.*s'", rurl.len, rurl.ptr);
+ log_debug("after:\t'%.*s'", srurl.len, srurl.ptr);
+ url u = url_check(srurl);
+ free_str(&srurl);
return u;
}
@@ -611,36 +537,3 @@ void send_file(http_worker *hw, str filename){
}
close(fd);
}
-
-// this shouldnt be here
-int read_uri_rewrites(char *map, uint64_t size){
- uint64_t i = 0;
- if(strncmp(map, "rewrites", slen("rewrites")) != 0) return 1;
- i += slen("rewrites");
- while(charisspace(map[i])) i++;
- if(map[i++] != '{') return 1;
- list_free(uri_rewrites);
- init_nlist(uri_rewrites);
- while(i < size && map[i] != '}'){
- struct uri_mod um = {0};
- i += ({sread_delim_f(map+i, charisspace, false);}).len;
- i += ({um.pattern = read_delim_f(map+i, charisspace, true);}).len;
- i += ({sread_delim_f(map+i, charisblank, false);}).len;
- i += ({um.output.path = read_delim_f(map+i, charisspace, true);}).len;
- i += ({sread_delim_f(map+i, charisblank, false);}).len;
- i += ({um.output.query = read_delim_f(map+i, charisspace, true);}).len;
- i += ({sread_delim(map+i, '\n');}).len + 1;
- list_push(uri_rewrites, um);
- }
- return 0;
-}
-
-void free_uri_rewrites(void){
- for(uint32_t i = 0; i < list_size(uri_rewrites); i++){
- free_str(&uri_rewrites[i].pattern);
- free_str(&uri_rewrites[i].output.path);
- free_str(&uri_rewrites[i].output.query);
- }
- list_free(uri_rewrites);
-}
-
diff --git a/src/net/net.h b/src/net/net.h
index dc7c147..297e417 100755
--- a/src/net/net.h
+++ b/src/net/net.h
@@ -20,6 +20,7 @@
#include "files/files.h"
#include "log/log.h"
#include "mime/mime.h"
+#include "rewrites/rewrites.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <poll.h>
@@ -35,16 +36,6 @@ typedef enum http_method {
} http_method;
-struct uri {
- str path;
- str query;
-};
-
-struct uri_mod {
- str pattern;
- struct uri output;
-};
-
struct header {
str name;
str value;
@@ -59,7 +50,7 @@ struct http_message {
str resp_ver;
};
union {
- str uri;
+ str url;
str status;
};
union {
@@ -106,7 +97,7 @@ int accept_connection(http_worker *hw, char ip[INET_ADDRSTRLEN]);
int receive_request(http_worker *hw, str *request);
-str generate_resource(struct uri resource, str url);
+str generate_resource(url resource, str rurl);
char *handlePOST(char *request);
@@ -114,12 +105,8 @@ void build_http_message(char *request, int len, struct http_message *hm);
enum http_method get_http_method(str method);
-struct uri sanitize_uri(str uri);
+url sanitize_url(str rurl);
void send_file(http_worker *hw, str filename);
-int read_uri_rewrites(char *map, uint64_t size);
-
-void free_uri_rewrites(void);
-
-#endif
+#endif \ No newline at end of file
diff --git a/src/rewrites/rewrites.c b/src/rewrites/rewrites.c
new file mode 100644
index 0000000..3a9a762
--- /dev/null
+++ b/src/rewrites/rewrites.c
@@ -0,0 +1,160 @@
+#include "rewrites.h"
+
+
+static rewrite *rewrites;
+
+void read_url_rewrites(str file){
+ if(rewrites == NULL){
+ init_nlist(rewrites);
+ }
+ int off = 0;
+ while(off < file.len){
+ while(off < file.len && charisspace(file.ptr[off])) off++;
+ if(file.ptr[off] == '#'){
+ while(off < file.len && !charislinebreak(file.ptr[off])) off++;
+ continue;
+ }
+ rewrite rwt = {0};
+ rwt.pattern = sread_delim_f(file.ptr + off, charisspace, true);
+ off += rwt.pattern.len;
+ while(off < file.len && charisblank(file.ptr[off])) off++;
+ rwt.output.path = sread_delim_f(file.ptr + off, charisspace, true);
+ off += rwt.output.path.len;
+ while(off < file.len && charisblank(file.ptr[off])) off++;
+ rwt.output.query = sread_delim_f(file.ptr + off, charisspace, true);
+ 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);
+ }
+ }
+}
+
+void free_url_rewrites(void){
+ list_free(rewrites);
+}
+
+int check_pattern(str text, str pattern, str tokens[9]){
+ if(tokens == NULL){
+ return 0;
+ }
+ int i = 0, j = 0, in = 0, ti = 0;
+ for(; j < pattern.len; i += 1){
+ if(i < text.len && pattern.ptr[j+in] == '<' && pattern.ptr[j+in+1] == text.ptr[i]){
+ if(ti < 9 && tokens) tokens[ti++] = (str){.ptr = text.ptr+i, .len = 1};
+ j += 3+in, in = 0;
+ }else if(i < text.len && (pattern.ptr[j+in] == '^' || pattern.ptr[j+in] == text.ptr[i])){
+ if(pattern.ptr[j] == '^' && ti < 9 && tokens) tokens[ti++] = (str){.ptr = text.ptr+i, .len = 1};
+ j += 1+in, in = 0;
+ }else if(i < text.len && pattern.ptr[j] == '*'){
+ if(!in){
+ if(ti < 9 && tokens) tokens[ti++] = (str){.ptr = text.ptr+i, .len = 0};
+ in = 1;
+ }
+ if(ti-in < 9 && tokens) tokens[ti-in].len++;
+ }else{
+ if(i >= text.len && pattern.ptr[j] == '*') j++;
+ else if(i >= text.len && pattern.ptr[j] == '<') j += 3;
+ else return 0;
+ }
+ }
+ return (i >= text.len);
+}
+
+str fill_blueprint(str bp, str tokens[9]){
+ str r = {0};
+ int rlen = 0;
+ for(int i = 0; i < bp.len; i++, rlen++){
+ if(bp.ptr[i] == '$') rlen += tokens[bp.ptr[++i]-'1'].len-1;
+ }
+ r.ptr = calloc(rlen+1, sizeof(char));
+ if(r.ptr == NULL){
+ return r;
+ }
+
+ for(int i = 0; i < bp.len; i++){
+ if(bp.ptr[i] == '$'){
+ if(++i+1 < bp.len && bp.ptr[i+1] == '<'){
+ if(tokens[bp.ptr[i]-'1'].len > 0) i++;
+ else while(bp.ptr[++i] != '>');
+ }else{
+ copy_str(r, tokens[bp.ptr[i]-'1']);
+ }
+ }else{
+ if(bp.ptr[i] != '>') r.ptr[r.len++] = bp.ptr[i];
+ }
+ }
+ return r;
+}
+
+/*
+ Given a rewrite, with a pattern (that is checked against the url) and an output
+ (that is used as an blueprintfor the output if the raw url follows the pattern)
+
+ There is a tokens array where tokens found in the url can be stored (up to 9 tokens)
+
+ In pattern:
+ <X> optionally matches a character X and stores it in the tokens array
+ ^ optionally matches any character and stores it in the tokens array
+ * optionally matches a string of character until another match is found
+ or the url to match ends, and stores it in the tokens array
+
+ In the ouput:
+ $1 through $9 reference the tokens in the token array (I could make it 10 tokens tbh)
+ Both the strings in the uri can access these tokens
+ Referencing a token writes it to the output uri
+ If theres a token before a <X>, say $3<a> that means that the character
+ between the less than and greater than signs will only be written
+ to the output if the token number 3 in the array exists (has length > 0)
+ All other characters get outputted normally
+*/
+url url_rewrite(str rurl, rewrite rwt){
+ str tokens[9] = {0};
+ if(!check_pattern(rurl, rwt.pattern, tokens)){
+ return (url){0};
+ }
+ url r = {
+ .path = fill_blueprint(rwt.output.path, tokens),
+ .query = fill_blueprint(rwt.output.query, tokens),
+ };
+ if(r.path.len == 0){
+ free_str(&r.path);
+ free_str(&r.query);
+ return (url){0};
+ }
+ return r;
+}
+
+url url_check(str rurl){
+ str tokens[9] = {0};
+ for(int i = 0; i < list_size(rewrites); i++){
+ if(check_pattern(rurl, rewrites[i].pattern, tokens)){
+ url r = {
+ .path = fill_blueprint(rewrites[i].output.path, tokens),
+ .query = fill_blueprint(rewrites[i].output.query, tokens),
+ };
+ if(r.path.len == 0){
+ free_str(&r.path);
+ free_str(&r.query);
+ }
+ return r;
+ }
+ }
+ return (url){0};
+}
+
+void print_url_rewrites(void){
+ int size = list_size(rewrites);
+ printf("\t- rewrites:{\n");
+ for(int i = 0; i < size; i++){
+ printf("\t\t%.*s\t%.*s\t%.*s\n",
+ rewrites[i].pattern.len, rewrites[i].pattern.ptr,
+ rewrites[i].output.path.len, rewrites[i].output.path.ptr,
+ rewrites[i].output.query.len, rewrites[i].output.query.ptr
+ );
+ }
+ printf("\t}\n");
+}
diff --git a/src/rewrites/rewrites.h b/src/rewrites/rewrites.h
new file mode 100644
index 0000000..14b77b2
--- /dev/null
+++ b/src/rewrites/rewrites.h
@@ -0,0 +1,29 @@
+#ifndef REWRITES_H
+#define REWRITES_H
+
+#include "str/str.h"
+#include "list/list.h"
+
+
+typedef struct url {
+ str path;
+ str query;
+} url;
+
+typedef struct rewrite {
+ str pattern;
+ url output;
+} rewrite;
+
+
+void read_url_rewrites(str file);
+void free_url_rewrites(void);
+
+int check_pattern(str text, str pattern, str tokens[9]);
+str fill_blueprint(str bp, str tokens[9]);
+url url_rewrite(str url, rewrite rwt);
+url url_check(str url);
+
+void print_url_rewrites(void);
+
+#endif \ No newline at end of file
diff --git a/src/worker.c b/src/worker.c
index f4b67c2..64403ac 100755
--- a/src/worker.c
+++ b/src/worker.c
@@ -10,66 +10,64 @@
config_w config;
struct {
str path;
+ str socket_path;
str ipc_addr;
+ str config_file;
str self;
} dir;
ipc_listener *listener;
http_worker *worker;
// remove these or something
-int secure;
+int secure = 0;
str rewritesfile;
-str rootdir;
-str bundlefile;
-str certfile;
-str keyfile;
-struct pollfd fds[2] = {0};
+// TODO: remove?
// make int for errors?
void handle_message(ipc_msg im){
log_debug("received message: [%d] (%d) %s", im.type, im.msg.len, im.msg.ptr);
switch(im.type){
case NONE: break;
case SOCKET:
- if(worker != NULL){
- destroy_http_worker(&worker);
- }
- int ssocket = strtou(im.msg);
- worker = setup_http_worker(ssocket, secure, certfile, keyfile);
- fds[1] = (struct pollfd){ .fd = worker->ssocket, .events = POLLIN };
+ // if(worker != NULL){
+ // destroy_http_worker(&worker);
+ // }
+ // int ssocket = strtou(im.msg);
+ // worker = setup_http_worker(ssocket, secure, certfile, keyfile);
+ // fds[1] = (struct pollfd){ .fd = worker->ssocket, .events = POLLIN };
break;
case REWRITES:
- int fsize = get_file_size(im.msg.ptr);
- int fd = open(im.msg.ptr, O_RDONLY | O_NONBLOCK);
- char *rewrites = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0);
- if(rewrites == (void*)-1){
- log_error("cant mmap rewrites: %s", strerror(errno));
- return;
- }
- if(read_uri_rewrites(rewrites, fsize) != 0){
- log_error("init: read_uri_rewrites: %s", strerror(errno));
- return;
- }
- munmap(rewritesfile.ptr, fsize);
- close(fd);
+ //int fsize = get_file_size(im.msg.ptr);
+ //int fd = open(im.msg.ptr, O_RDONLY | O_NONBLOCK);
+ //char *rewrites = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0);
+ //if(rewrites == (void*)-1){
+ // log_error("cant mmap rewrites: %s", strerror(errno));
+ // return;
+ //}
+ //if(read_uri_rewrites(rewrites, fsize) != 0){
+ // log_error("init: read_uri_rewrites: %s", strerror(errno));
+ // return;
+ //}
+ //munmap(rewritesfile.ptr, fsize);
+ //close(fd);
break;
//case ROOT:
// free_str(&rootdir);
// rootdir = dup_str(im.msg);
// break;
case BUNDLE: // look into reinitializing the worker when receiving this
- free_str(&bundlefile);
- bundlefile = dup_str(im.msg);
- break;
+ // free_str(&bundlefile);
+ // bundlefile = dup_str(im.msg);
+ // break;
case CERT: // look into reinitializing the worker when receiving this
- free_str(&certfile);
- certfile = dup_str(im.msg);
- break;
+ // free_str(&certfile);
+ // certfile = dup_str(im.msg);
+ // break;
case KEY: // look into reinitializing the worker when receiving this
- free_str(&keyfile);
- keyfile = dup_str(im.msg);
- break;
+ // free_str(&keyfile);
+ // keyfile = dup_str(im.msg);
+ // break;
case RESTART:
char *args[] = {"./worker.exe", listener->saddr.ptr, NULL};
execv("./worker.exe", args);
@@ -81,18 +79,20 @@ void handle_message(ipc_msg im){
// re-requests entire config;
break;
case HTTP:
- log_info("received http signal");
- if(secure != 0){
- secure = 0;
- terminate_https(worker);
- }
+ // TODO: revise this
+ // log_info("received http signal");
+ // if(secure != 0){
+ // secure = 0;
+ // terminate_https(worker);
+ // }
break;
case HTTPS:
- log_info("received https signal");
- if(secure == 0){
- secure = 1;
- setup_https(worker, certfile, keyfile);
- }
+ // TODO: revise this
+ // log_info("received https signal");
+ // if(secure == 0){
+ // secure = 1;
+ // setup_https(worker, certfile, keyfile);
+ // }
break;
case LOG:
break;
@@ -103,18 +103,39 @@ void handle_message(ipc_msg im){
}
}
-// possibly change name
+void deinit(void);
-int create_server_dir(str name){
+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);
+}
+
+// possibly change name
+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': %s", dir.path.len, 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.ipc_addr = dup_strs(dir.path, sstr("ipcserver"));
+ if(!file_exists(dir.ipc_addr.ptr)){
+ log_error("No IPC socket in '%.*s'", dir.ipc_addr.len, dir.ipc_addr.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);
+ return 1;
+ }
+ // TODO: revise this
str pid = utostr(getpid(), 10);
dir.self = dup_strs(dir.path, sstr("workers/"), pid);
- printf("WE'RE GONNA CREATE THE FILE %s\n", dir.self.ptr);
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);
@@ -127,15 +148,44 @@ int create_server_dir(str name){
return 0;
}
-int init(char *configfile){
- config = worker_config(configfile);
- if(config.name.len == 0){ // TODO: maybe check for this someway else
- log_error("Unable to read config from '%s'", configfile);
+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){
+ 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 ssocket;
+ int sfd = open(dir.socket_path.ptr, O_RDONLY);
+ 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");
+ return 1;
+ }
+ listener = setup_ipc_listener(dir.ipc_addr);
+ if(listener == NULL){
+ log_error("Can't set up ipc listener on self");
+ 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));
+ return 1;
+ }
+ if(sigaction(SIGQUIT, &qit, NULL) == -1){
+ log_error("Error setting up SIGQUIT signal handler: %s", strerror(errno));
return 1;
}
- print_worker_config(config);
- log_info("Succesfully read worker config from '%s'", configfile);
- if(create_server_dir(config.name) != 0){
+ if(sigaction(SIGINT, &qit, NULL) == -1){
+ log_error("Error setting up SIGINT signal handler: %s", strerror(errno));
return 1;
}
return 0;
@@ -146,126 +196,113 @@ 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));
}
- printf("%s IS NO MORE!", dir.self.ptr);
free_str(&dir.self);
free_str(&dir.ipc_addr);
free_str(&dir.path);
}
void deinit(void){
+ destroy_ipc_listener(&listener);
+ destroy_http_worker(&worker);
free_worker_config(&config);
remove_server_dir();
}
+void print_usage(void){
+ printf("worker [server name]\n");
+}
+
int main(int argc, char **argv){
- int return_value = 0;
+ if(argc < 2){
+ print_usage();
+ return 1;
+ }
- init("config.example");
+ int return_value = 0;
- listener = setup_ipc_listener((str){.cap = 0, .len = len(argv[1]), .ptr = argv[1]});
- if(listener == NULL){
- log_error("Can't set up ipc listener on worker %d", getpid());
+ if(init(dsstr(argv[1])) != 0){
return_value = 1;
goto DEINIT;
}
log_info("init'd");
//bool end = false;
- log_debug("erm");
str request = {.cap = 8192, .len = 0, .ptr = alloca(8192)};
- fds[0] = (struct pollfd){ .fd = listener->csocket, .events = POLLIN };
-
- int r;
- while((r = poll(fds, 2, 0)) != -1){
- if(r > 0){
- log_info("[%d] %d\t-\t%d", fds[1].fd, fds[1].events & POLLIN, fds[1].revents & POLLIN);
+ while(1){
+ char cip[INET_ADDRSTRLEN] = {0};
+ return_value = accept_connection(worker, cip);
+ switch(return_value){
+ case -1: // couldnt accept, do something ig
+ continue;
+ case SSL_ERROR_SSL:
+ reset_https(worker);
+ log_info("continuing\n");
+ continue;
+ }
+ log_info("socket %d accepted with ip %s", worker->csocket, cip);
+ return_value = receive_request(worker, &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);
+ log_info("continuing\n");
+ continue;
}
- if(fds[0].revents & POLLHUP){
- log_info("RECEIVED POLLHUP!!!!!!");
- // end? or something idk
- }else if(fds[0].revents & POLLIN){
- ipc_msg msg = receive_ipc_message(listener);
- handle_message(msg);
- free_ipc_message(&msg);
- continue;
- }else if(fds[1].revents & POLLIN){
- log_info("ermmm");
- char cip[INET_ADDRSTRLEN] = {0};
- return_value = accept_connection(worker, cip);
- switch(return_value){
- case -1: // couldnt accept, do something ig
- continue;
- case SSL_ERROR_SSL:
- reset_https(worker);
- log_info("continuing\n");
- continue;
- }
- log_info("socket %d accepted with ip %s", worker->csocket, cip);
- return_value = receive_request(worker, &request);
- switch(return_value){
- case -1: // couldnt accept, do something ig
- continue;
- case SSL_ERROR_SSL:
- reset_https(worker);
- log_info("continuing\n");
- continue;
- }
-
- printf("'%.*s'\n", request.len, request.ptr);
- struct http_message hm = {0};
- build_http_message(request.ptr, request.len, &hm);
- log_info("uri before: %.*s", hm.uri.len, hm.uri.ptr);
- struct uri suri = sanitize_uri(hm.uri);
- log_info("uri after: %.*s", suri.path.len, suri.path.ptr);
- enum http_method method = get_http_method(hm.method);
+ printf("%d: '%.*s'\n", request.len, request.len, request.ptr);
- switch(method){
- case GET:
- str resource = generate_resource(suri, hm.uri);
- send_file(worker, 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);
- break;
- case PUT:
- break;
- case DELETE:
- break;
- default:
- break;
- }
- free_str(&suri.path);
- free_str(&suri.query);
- log_debug("query freed");
- request.len = 0;
+ struct http_message hm = {0};
+ build_http_message(request.ptr, request.len, &hm);
+ log_info("url before: %.*s", hm.url.len, hm.url.ptr);
+ url surl = sanitize_url(hm.url);
+ log_info("uri after: '%.*s' ? '%.*s'", surl.path.len, surl.path.ptr, surl.query.len, surl.query.ptr);
+ enum http_method method = get_http_method(hm.method);
- if(worker->secure){
- SSL_clear(worker->ssl);
- }
- close(worker->csocket);
+ switch(method){
+ case GET:
+ str resource = generate_resource(surl, hm.url);
+ send_file(worker, 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);
+ break;
+ case PUT:
+ break;
+ case DELETE:
+ break;
+ default:
+ break;
+ }
- //SSL_shutdown(config.ssl); // look into SSL_clear()
+finish_request:
+ free_str(&surl.path);
+ free_str(&surl.query);
+ log_debug("query freed");
+ request.len = 0;
- log_debug("end of loop");
- }else if(fds[1].revents & POLLHUP){
- // like restart the worker
+ if(worker->secure){
+ SSL_clear(worker->ssl);
}
+ close(worker->csocket);
+
+ //SSL_shutdown(config.ssl); // look into SSL_clear()
+
+ log_debug("end of loop");
}
DEINIT:
deinit();
- log_info("dieing :(");
- destroy_ipc_listener(&listener);
- destroy_http_worker(&worker);
free_str(&rewritesfile);
- free_uri_rewrites();
+ log_info("dieing :(");
return return_value;
}