commit f778a27c607ba779cae44fd074cf8eec3fbda50c
parent 6798449c8145f9d1be8e4d32c362b9bbfa77ca4f
Author: quantumish <freifeld.david@gmail.com>
Date: Mon, 15 May 2023 01:07:35 -0700
Simple logic for switch to process-based design
Diffstat:
| M | http.c | | | 314 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | utils/sync.c | | | 35 | +++++++++++++++++------------------ |
2 files changed, 177 insertions(+), 172 deletions(-)
diff --git a/http.c b/http.c
@@ -1,6 +1,5 @@
#define _GNU_SOURCE
-#include <bits/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
@@ -9,7 +8,7 @@
#include <string.h>
#include <assert.h>
#include <dirent.h>
-
+#include <time.h>
#include <signal.h>
#include <errno.h>
@@ -23,9 +22,6 @@
#include <arpa/inet.h>
#include <pthread.h>
-#include <time.h>
-
-#include <zlib.h>
#include <libunwind.h>
#include <libunwind-ptrace.h>
@@ -44,13 +40,13 @@ response_t serve_error(enum StatusCode c) {
response_t r = resp_new(c);
resp_add_hdr(&r, "Content-Type", "text/html");
- char errt[256];
- sprintf(errt, "Error %d", c);
+ char errt[256];
+ sprintf(errt, "Error %d", c);
- html_t html = html_new();
- html_body_add(&html.body, html_h1_new(errt));
- html_body_add(&html.body, html_p_new("Hey! Don't do that."));
- char* msg = html_render(&html);
+ html_t html = html_new();
+ html_body_add(&html.body, html_h1_new(errt));
+ html_body_add(&html.body, html_p_new("Hey! Don't do that."));
+ char* msg = html_render(&html);
resp_add_content(&r, msg, strlen(msg));
return r;
@@ -71,65 +67,65 @@ response_t serve_file(request_t* req) {
strcat(path, req->path);
int fd = open(path, O_RDONLY); // TODO handle
response_t r = resp_new(OK);
-
+
struct stat st;
fstat(fd, &st);
char* fbuf = malloc(st.st_size); // TODO what if file larger than memory?
for (size_t i = 0; read(fd, fbuf+(i*4096), 4096) > 0; i++);
-
+
char* ext = get_file_ext(req->path);
- resp_set_ctype(&r, ext);
+ resp_set_ctype(&r, ext);
- bool ok = true;
+ bool ok = true;
char* mtype = (char*)ext_to_mtype(ext);
- char* hdr;
- if ((hdr = hashmap_get(&req->headers, "Accept"))) {
- ok = false;
- shitvec_t mtypes = hdr_parse_accept(hdr);
- for (int j = 0; j < mtypes.vec_sz; j++) {
- struct req_mimetype* a_mtype = shitvec_get(&mtypes, j);
- // TODO doesn't handle stuff like image/* (is that even allowed?)
- if (strcmp(a_mtype->item, mtype) == 0 || strcmp(a_mtype->item, "*/*") == 0) {
- ok = true;
- break;
- }
- }
+ char* hdr;
+ if ((hdr = hashmap_get(&req->headers, "Accept"))) {
+ ok = false;
+ shitvec_t mtypes = hdr_parse_accept(hdr);
+ for (int j = 0; j < mtypes.vec_sz; j++) {
+ struct req_mimetype* a_mtype = shitvec_get(&mtypes, j);
+ // TODO doesn't handle stuff like image/* (is that even allowed?)
+ if (strcmp(a_mtype->item, mtype) == 0 || strcmp(a_mtype->item, "*/*") == 0) {
+ ok = true;
+ break;
+ }
+ }
}
-
+
char* buf = fbuf; // buffer to be written
size_t bufsize = st.st_size;
-
+
if (ok && (hdr = hashmap_get(&req->headers, "Accept-Encoding"))) {
- ok = false;
- shitvec_t mtypes = hdr_parse_accept(hdr); // abuse of this func
- for (int j = 0; j < mtypes.vec_sz; j++) {
- struct req_mimetype* a_mtype = shitvec_get(&mtypes, j);
+ ok = false;
+ shitvec_t mtypes = hdr_parse_accept(hdr); // abuse of this func
+ for (int j = 0; j < mtypes.vec_sz; j++) {
+ struct req_mimetype* a_mtype = shitvec_get(&mtypes, j);
if (strcmp(a_mtype->item, "gzip") == 0) {
resp_add_hdr(&r, "Content-Encoding", "gzip");
buf = gzip_compress(buf, &bufsize);
ok = true;
- break;
- } else if (strcmp(a_mtype->item, "deflate") == 0) {
+ break;
+ } else if (strcmp(a_mtype->item, "deflate") == 0) {
resp_add_hdr(&r, "Content-Encoding", "deflate");
buf = zlib_compress(buf, &bufsize);
ok = true;
break;
} else if (strcmp(a_mtype->item, "identity") == 0) {
- ok = true;
- break;
- }
- }
+ ok = true;
+ break;
+ }
+ }
}
/* if (!ok) return serve_error(NotAcceptable); */
- #ifndef __APPLE__
+#ifndef __APPLE__
char datebuf[64];
time_to_str(st.st_mtim.tv_sec, datebuf);
- resp_add_hdr(&r, "Last-Modified", datebuf);
- #endif
-
+ resp_add_hdr(&r, "Last-Modified", datebuf);
+#endif
+
resp_add_content(&r, buf, bufsize);
free(buf);
return r;
@@ -141,45 +137,45 @@ response_t serve_file(request_t* req) {
response_t make_response (request_t* req, int pfd) {
if (req_parse(req) < 0) {
log_error("Failed to parse incoming request.");
- return serve_error(BadRequest);
+ return serve_error(BadRequest);
+ }
+
+ if (hashmap_get(&req->headers, "Profile") != 0x0) {
+ log_debug("Got header");
+ int profile = true;
+ if (ptrace(PTRACE_TRACEME, NULL) < 0) {
+ log_error("PTRACE_TRACME failed with err %d", errno);
+ }
+ if (write(pfd, "profile", 8) != 8) {
+ log_error("write err");
+ }
+ usleep(100);
}
- if (hashmap_get(&req->headers, "Profile") != 0x0) {
- log_debug("Got header");
- int profile = true;
- if (ptrace(PTRACE_TRACEME, NULL) < 0) {
- log_error("PTRACE_TRACME failed with err %d", errno);
- }
- if (write(pfd, "profile", 8) != 8) {
- log_error("write err");
- }
- usleep(100);
- }
-
log_info("Got request %s %s", method_name(req->method), req->path);
- char* mapped_path = hashmap_get(&path_redirs, req->path);
- if (mapped_path != NULL) {
- strcpy(req->path, mapped_path);
- }
-
+ char* mapped_path = hashmap_get(&path_redirs, req->path);
+ if (mapped_path != NULL) {
+ strcpy(req->path, mapped_path);
+ }
+
if (!shitvec_check(&paths, req->path, (sv_cmp_t)strcmp)) {
return serve_error(NotFound);
}
- log_debug("method = %d", req->method);
+ log_debug("method = %d", req->method);
switch (req->method) {
- case GET: return serve_file(req);
+ case GET: return serve_file(req);
default: return serve_error(MethodNotAllowed);
- }
+ }
}
double diff_timespec(const struct timespec *time1, const struct timespec *time0) {
- return (time1->tv_sec - time0->tv_sec)
- + (time1->tv_nsec - time0->tv_nsec) / 1000000000.0;
+ return (time1->tv_sec - time0->tv_sec)
+ + (time1->tv_nsec - time0->tv_nsec) / 1000000000.0;
}
-void* handle_conn(int ns, int pfd) {
+void* handle_conn(int ns, int pfd) {
char msgbuf[1024] = {0};
while(true) {
struct timespec before, after, tdiff;
@@ -190,19 +186,19 @@ void* handle_conn(int ns, int pfd) {
clock_gettime(CLOCK_MONOTONIC, &before);
if (msgbuf[0] != 0) {
request_t req = req_new(msgbuf, 1024);
-
- response_t r = make_response(&req, pfd);
+
+ response_t r = make_response(&req, pfd);
send(ns, r.content, r.sz, 0);
free(r.content);
- write(pfd, "stop", 5);
- clock_gettime(CLOCK_MONOTONIC, &after);
+ write(pfd, "stop", 5);
+ clock_gettime(CLOCK_MONOTONIC, &after);
log_info("Handled request in %f sec", diff_timespec(&after, &before));
req_free(&req);
}
}
}
-int list_files_sv(shitvec_t* sv, char* base) {
+int list_files_sv(shitvec_t* sv, char* base) {
char path[MAX_PATH_LEN] = "/";
struct dirent* dp;
DIR* dir = opendir(base);
@@ -217,124 +213,134 @@ int list_files_sv(shitvec_t* sv, char* base) {
list_files_sv(sv, path+1);
}
}
-
- closedir(dir);
+
+ closedir(dir);
return 0;
}
channel_t listen_chan;
-/* void* listen_for_conns(void* ctxt) { */
-/* int s = *(int*)ctxt; */
-/* int namelen; */
-/* struct sockaddr_in client; */
-/* while (true) { */
-/* listen(s, 1); */
-/* int ns = accept(s, (struct sockaddr*)&client, (socklen_t*)&namelen); */
-/* log_info("Handling connection from %s", inet_ntoa(client.sin_addr)); */
-/* channel_push(&listen_chan, &ns); */
-/* } */
-/* } */
-
-#define MAX_SYMLEN 128
-
-int profile(pid_t tid) {
- errno = 0;
- log_debug("Tracing %d", tid);
- if (ptrace(PTRACE_ATTACH, tid) < 0) {
- log_error("ptrace() fail, errno %d", errno);
- }
- kill(tid, SIGSTOP);
- waitpid(tid, NULL, 0);
- void* ui = _UPT_create(tid);
- if (!ui) return -1;
- unw_cursor_t c;
- unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0);
- unw_init_remote(&c, as, ui);
- do {
- unw_word_t offset;
- char fname[MAX_SYMLEN] = {0};
- int resp = unw_get_proc_name(&c, fname, sizeof(fname), &offset);
- log_trace("%s (code %d, errno %d)", fname, resp, errno);
- } while(unw_step(&c) > 0);
- _UPT_resume(as, &c, ui);
- _UPT_destroy(ui);
+void* listen_for_conns(void* ctxt) {
+ int s = *(int*)ctxt;
+ int namelen;
+ struct sockaddr_in client;
+ while (true) {
+ listen(s, 1);
+ int ns = accept(s, (struct sockaddr*)&client, (socklen_t*)&namelen);
+ log_info("Handling connection from %s", inet_ntoa(client.sin_addr));
+ channel_push(&listen_chan, &ns);
+ }
+}
+
+#define MAX_SYMLEN 32
+
+shitvec_t profile(pid_t tid) {
+ shitvec_t stack = shitvec_new(MAX_SYMLEN);
+ errno = 0;
+ log_debug("Tracing %d", tid);
+ if (ptrace(PTRACE_ATTACH, tid) < 0) {
+ log_error("ptrace() fail, errno %d", errno);
+ }
+ kill(tid, SIGSTOP);
+ waitpid(tid, NULL, 0);
+ void* ui = _UPT_create(tid);
+ if (!ui) return -1;
+ unw_cursor_t c;
+ unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0);
+ unw_init_remote(&c, as, ui);
+ do {
+ unw_word_t offset;
+ char fname[MAX_SYMLEN] = {0};
+ int resp = unw_get_proc_name(&c, fname, sizeof(fname), &offset);
+ log_trace("%s (code %d, errno %d)", fname, resp, errno);
+ shitvec_push(&stack, fname);
+ } while(unw_step(&c) > 0);
+ _UPT_resume(as, &c, ui);
+ _UPT_destroy(ui);
kill(tid, SIGSTOP);
- printf("waiting\n");
- waitpid(tid, NULL, 0);
- ptrace(PTRACE_DETACH, tid, NULL, NULL);
- return 0;
+ waitpid(tid, NULL, 0);
+ ptrace(PTRACE_DETACH, tid, NULL, NULL);
+ return stack;
}
-struct thread_comm {
- channel_t chan;
- pid_t tid;
+struct tree_node {
+ struct tree_node* left;
+ struct tree_node* right;
+ char name[MAX_SYMLEN];
+};
+
+struct conn_ctxt {
+ pid_t pid;
+ int fd;
};
// TODO some sort of DDOS protection idk
int main() {
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) die("socket");
-
- int portnum = 8080;
+
+ int portnum = 8080;
struct sockaddr_in name;
name.sin_family = AF_INET;
name.sin_port = htons(portnum);
name.sin_addr.s_addr = htonl(INADDR_ANY);
- while(bind(s, (struct sockaddr*)&name, sizeof(name)) < 0) {
- portnum += 1;
- name.sin_port = htons(portnum);
- }
-
+ while(bind(s, (struct sockaddr*)&name, sizeof(name)) < 0) {
+ portnum += 1;
+ name.sin_port = htons(portnum);
+ }
+
paths = shitvec_new(MAX_PATH_LEN);
path_redirs = hashmap_new(MAX_PATH_LEN, MAX_PATH_LEN);
path_redirs.vark = true;
hashmap_set(&path_redirs, "/", "/index.html");
-
+
list_files_sv(&paths, "public");
int nlen;
getsockname(s, (struct sockaddr*)&name, (socklen_t*)&nlen);
log_debug("Open on port %d.", htons(name.sin_port));
-
- listen_chan = channel_new(sizeof(int));
- /* pthread_t lthread; */
- /* pthread_create(&lthread, NULL, listen_for_conns, &s); */
+ listen_chan = channel_new(sizeof(int));
- int namelen;
+ pthread_t lthread;
+ pthread_create(&lthread, NULL, listen_for_conns, &s);
+
+ int namelen;
struct sockaddr_in client;
-
- int* ns;
- pid_t pid;
+ shitvec_t conns = shitvec_new(sizeof(struct conn_ctxt));
while (true) {
- listen(s, 1);
- int ns = accept(s, (struct sockaddr*)&client, (socklen_t*)&namelen);
- log_info("Got connection");
-
- int pfds[2];
- pipe(pfds);
-
- pid = fork();
- if (pid == 0) {
- handle_conn(ns, pfds[1]);
- exit(0);
- } else {
- /* char msg[8] = {0}; */
- /* read(pfds[0], &msg, 8); */
- /* int retval = fcntl(pfds[0], F_SETFL, fcntl(pfds[0], F_GETFL) | O_NONBLOCK); */
-
- /* while(true) { */
- /* profile(pid); */
- /* usleep(10); */
- /* if (read(pfds[0], &msg, 5) == 5 && strcmp(msg, "stop") == 0) break; */
- /* } */
- }
+ int* ptr = channel_try_recv(&listen_chan);
+ if (ptr != NULL) {
+ int pfds[2];
+ pipe(pfds);
+ int retval = fcntl(pfds[0], F_SETFL, fcntl(pfds[0], F_GETFL) | O_NONBLOCK);
+ pid_t pid = fork();
+ if (pid == 0) {
+ handle_conn(*ptr, pfds[1]);
+ close(pfds[0]);
+ close(pfds[1]);
+ exit(0);
+ }
+ struct conn_ctxt ctxt = {.fd = pfds[0], .pid = pid };
+ shitvec_push(&conns, &ctxt);
+ }
+ for (int i = 0; i < conns.vec_sz; i++) {
+ struct conn_ctxt* ctxt = shitvec_get(&conns, i);
+ char msg[8] = {0};
+ if (read(ctxt->fd, &msg, 8) != 8 || strcmp(msg, "profile") != 0) continue;
+ shitvec_t nodes = shitvec_new(sizeof(struct tree_node));
+ while(true) {
+ profile(ctxt->pid);
+ usleep(10);
+ if (read(ctxt->fd, &msg, 5) == 5 && strcmp(msg, "stop") == 0) break;
+ }
+ }
}
}
+
// meta todos:
// - TODO true dependencyless (no zlib, no pthread)
// - TODO HTML parsing maybe but that makes me want to cry
diff --git a/utils/sync.c b/utils/sync.c
@@ -8,35 +8,34 @@ channel_t channel_new(size_t msg_sz) {
pthread_mutex_init(&out.mutex, NULL);
out.queue = shitvec_new(msg_sz);
out.sz = 0;
- return out;
+ return out;
}
void channel_push(channel_t* chan, void* msg) {
pthread_mutex_lock(&chan->mutex);
- shitvec_push(&chan->queue, msg);
- pthread_mutex_unlock(&chan->mutex);
- __atomic_fetch_add(&chan->sz, 1, __ATOMIC_RELAXED);
+ shitvec_push(&chan->queue, msg);
+ pthread_mutex_unlock(&chan->mutex);
+ __atomic_fetch_add(&chan->sz, 1, __ATOMIC_RELAXED);
}
void* channel_pop(channel_t* chan) {
- void* out;
- pthread_mutex_lock(&chan->mutex);
- out = shitvec_get(&chan->queue, chan->queue.vec_sz-1);
- chan->queue.vec_sz -= 1;
- pthread_mutex_unlock(&chan->mutex);
- __atomic_fetch_sub(&chan->sz, 1, __ATOMIC_RELAXED);
- return out;
+ void* out;
+ pthread_mutex_lock(&chan->mutex);
+ out = shitvec_get(&chan->queue, chan->queue.vec_sz-1);
+ chan->queue.vec_sz -= 1;
+ pthread_mutex_unlock(&chan->mutex);
+ __atomic_fetch_sub(&chan->sz, 1, __ATOMIC_RELAXED);
+ return out;
}
void* channel_recv(channel_t* chan) {
- while(__atomic_load_n(&chan->sz, __ATOMIC_RELAXED) == 0);
- return channel_pop(chan);
+ while(__atomic_load_n(&chan->sz, __ATOMIC_RELAXED) == 0);
+ return channel_pop(chan);
}
void* channel_try_recv(channel_t* chan) {
- if (__atomic_load_n(&chan->sz, __ATOMIC_RELAXED) > 0) {
- return channel_pop(chan);
- }
- return 0x0;
+ if (__atomic_load_n(&chan->sz, __ATOMIC_RELAXED) > 0) {
+ return channel_pop(chan);
+ }
+ return 0x0;
}
-