Mercurial
changeset 18:fa2b8af609d9
[Seobeo] Fixed a bug with pathing. Support SSL.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Mon, 06 Oct 2025 08:21:34 -0700 |
| parents | d97ec3ded2ae |
| children | 875bb6e10db7 |
| files | .hgignore MODULE.bazel MODULE.bazel.lock cutelient/main.c dowa/d_memory.c dowa/dowa.h playground/BUILD playground/main.c seobeo/BUILD seobeo/os/s_linux_edge.c seobeo/os/s_macos_edge.c seobeo/s_linux_network.c seobeo/s_web.c seobeo/seobeo.h |
| diffstat | 14 files changed, 435 insertions(+), 244 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Sat Oct 04 07:53:12 2025 -0700 +++ b/.hgignore Mon Oct 06 08:21:34 2025 -0700 @@ -9,3 +9,6 @@ .bazelcache/ projects/* + +.git/* +.gitignore
--- a/MODULE.bazel Sat Oct 04 07:53:12 2025 -0700 +++ b/MODULE.bazel Mon Oct 06 08:21:34 2025 -0700 @@ -1,18 +1,18 @@ bazel_dep(name = "rules_cc", version = "0.1.1") bazel_dep(name = "platforms", version = "0.0.11") bazel_dep(name = "bazel_skylib", version = "1.8.2") +bazel_dep(name = "openssl", version = "3.3.1.bcr.7") http_file = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") + +# Bun http_file( name = "bun_darwin_arm64_zip", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.2.23/bun-darwin-aarch64.zip", sha256 = "22f5fa3fff72b0d3b8e7e0f8051ecadf2e41920d474ac62db5279144809c9005", ) - - http_file( name = "bun_linux_aarch64_zip", url = "https://github.com/oven-sh/bun/releases/download/bun-v1.2.23/bun-linux-aarch64.zip", sha256 = "6a7a98c546d084a845deda62eb2a5b94a6a14a63ea81cf9186d46bf55bf910a9", ) -
--- a/MODULE.bazel.lock Sat Oct 04 07:53:12 2025 -0700 +++ b/MODULE.bazel.lock Mon Oct 06 08:21:34 2025 -0700 @@ -16,6 +16,7 @@ "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc", "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", @@ -43,14 +44,17 @@ "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/openssl/3.3.1.bcr.7/MODULE.bazel": "dcb8181b28242d40ef854248f2929f3118dec18e68080e8ae3c0b7444316745b", + "https://bcr.bazel.build/modules/openssl/3.3.1.bcr.7/source.json": "339b52ba88f2d4bd7a55822bf1c790b7c00a09e0f8d323208b9e67086f22bdb6", "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", - "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29", "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580", + "https://bcr.bazel.build/modules/platforms/1.0.0/source.json": "f4ff1fd412e0246fd38c82328eb209130ead81d62dcd5a9e40910f867f733d96", "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", @@ -70,12 +74,14 @@ "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", - "https://bcr.bazel.build/modules/rules_cc/0.1.1/source.json": "d61627377bd7dd1da4652063e368d9366fc9a73920bfa396798ad92172cf645c", + "https://bcr.bazel.build/modules/rules_cc/0.2.4/MODULE.bazel": "1ff1223dfd24f3ecf8f028446d4a27608aa43c3f41e346d22838a4223980b8cc", + "https://bcr.bazel.build/modules/rules_cc/0.2.4/source.json": "2bd87ef9b41d4753eadf65175745737135cba0e70b479bdc204ef0c67404d0c4", "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", @@ -105,6 +111,8 @@ "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_perl/0.4.1/MODULE.bazel": "4d09ad3a3cf71e606faab258a753ba9f0516b5d3c6aff9b813d06ea65c04702f", + "https://bcr.bazel.build/modules/rules_perl/0.4.1/source.json": "70e943e2deea44c1b2ddfafe178a294b82f8b8a24ee25d547eaaa202142f1b4d", "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", @@ -122,7 +130,8 @@ "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", "https://bcr.bazel.build/modules/rules_python/0.40.0/source.json": "939d4bd2e3110f27bfb360292986bb79fd8dcefb874358ccd6cdaa7bda029320", "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", - "https://bcr.bazel.build/modules/rules_shell/0.2.0/source.json": "7f27af3c28037d9701487c4744b5448d26537cc66cdef0d8df7ae85411f8de95", + "https://bcr.bazel.build/modules/rules_shell/0.4.0/MODULE.bazel": "0f8f11bb3cd11755f0b48c1de0bbcf62b4b34421023aa41a2fc74ef68d9584f0", + "https://bcr.bazel.build/modules/rules_shell/0.4.0/source.json": "1d7fa7f941cd41dc2704ba5b4edc2e2230eea1cc600d80bd2b65838204c50b95", "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef",
--- a/cutelient/main.c Sat Oct 04 07:53:12 2025 -0700 +++ b/cutelient/main.c Mon Oct 06 08:21:34 2025 -0700 @@ -1,7 +1,13 @@ +#include <err.h> #include "seobeo/seobeo.h" -int main() +int main(int argc, char **argv) { - Seobeo_Web_ClientGet("127.0.0.1", "6969", "/react"); + if (argc < 3) + { + err(EXIT_FAILURE, "Usage: %s URL, PORT, PATH\n", argv[0]); + } + Seobeo_Web_ClientGet(argv[1], argv[2], argv[3]); + return 0; }
--- a/dowa/d_memory.c Sat Oct 04 07:53:12 2025 -0700 +++ b/dowa/d_memory.c Mon Oct 06 08:21:34 2025 -0700 @@ -94,7 +94,7 @@ { int idx_foo = Dowa_HashMap_GetPosition(p_hash_map, key); void *value = p_hash_map->entries[idx_foo]; - if (strcmp(((Dowa_PHashEntry) value)->key, key) != 0) + if (value == NULL || strcmp(((Dowa_PHashEntry) value)->key, key) != 0) { return NULL; }
--- a/dowa/dowa.h Sat Oct 04 07:53:12 2025 -0700 +++ b/dowa/dowa.h Mon Oct 06 08:21:34 2025 -0700 @@ -14,6 +14,9 @@ #define HASH_KEY_NUMBER 5381 // DJD hash number #define ONE_MEGA_BYTE 1048576 +#define TRUE 1 +#define FALSE 0 + typedef unsigned int uint32; typedef int int32; typedef unsigned short uint16;
--- a/playground/BUILD Sat Oct 04 07:53:12 2025 -0700 +++ b/playground/BUILD Mon Oct 06 08:21:34 2025 -0700 @@ -11,6 +11,9 @@ cc_binary( name = "playground_osx", srcs = ["main.c"], + deps = [ + "@openssl//:ssl", + ] ) filegroup(
--- a/playground/main.c Sat Oct 04 07:53:12 2025 -0700 +++ b/playground/main.c Mon Oct 06 08:21:34 2025 -0700 @@ -1,83 +1,94 @@ -// #include <pthread.h> -// #include <stdio.h> -// #include <stdlib.h> -// #define NUM_THREADS 5 -// -// void *PrintHello(void *threadid) -// { -// long tid; -// tid = (long)threadid; -// printf("Hello World! It's me, thread #%ld!\n", tid); -// pthread_exit(NULL); -// } -// -// int main (int argc, char *argv[]) -// { -// pthread_t threads[NUM_THREADS]; -// int rc; -// long t; -// for(t = 0; t < NUM_THREADS; t++) -// { -// printf("In main: creating thread %ld\n", t); -// rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t); -// if (rc) -// { -// printf("ERROR; return code from pthread_create() is %d\n", rc); -// exit(-1); -// } -// } -// -// /* Last thing that main() should do */ -// pthread_exit(NULL); -// } +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <openssl/ssl.h> +#include <openssl/err.h> -#include <sys/event.h> -#include <err.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#define INITIAL_BUFFER_CAPACITY 8192 -int main(int argc, char **argv) +void init_openssl() +{ + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); +} + +int main(void) { - struct kevent event; /* Event we want to monitor */ - struct kevent tevent; /* Event triggered */ - int kq, fd, ret; + const char *host = "www.google.com"; + const char *port = "443"; - if (argc != 2) - err(EXIT_FAILURE, "Usage: %s path\n", argv[0]); + struct addrinfo hints = {0}, *res; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(host, port, &hints, &res) != 0) + { + perror("getaddrinfo"); + return 1; + } - fd = open(argv[1], O_RDONLY); - if (fd == -1) - err(EXIT_FAILURE, "Failed to open '%s'", argv[1]); + int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sockfd < 0) + { + perror("socket"); + return 1; + } - /* Create kqueue. */ - kq = kqueue(); - if (kq == -1) - err(EXIT_FAILURE, "kqueue() failed"); + if (connect(sockfd, res->ai_addr, res->ai_addrlen) != 0) + { + perror("connect"); + return 1; + } - /* Initialize kevent structure. */ - EV_SET(&event, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, - NOTE_WRITE | NOTE_ATTRIB, - 0, NULL); + freeaddrinfo(res); + + init_openssl(); + SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); + SSL_CTX_set_default_verify_paths(ctx); + + SSL *ssl = SSL_new(ctx); + SSL_set_fd(ssl, sockfd); - /* Attach event to the kqueue. */ - ret = kevent(kq, &event, 1, NULL, 0, NULL); - if (ret == -1) - err(EXIT_FAILURE, "kevent register"); + // ✅ use real hostname for SNI + SSL_set_tlsext_host_name(ssl, host); + + // ✅ perform blocking handshake for simplicity + fcntl(sockfd, F_SETFL, 0); + + if (SSL_connect(ssl) != 1) + { + fprintf(stderr, "SSL_connect failed\n"); + ERR_print_errors_fp(stderr); + return 1; + } + + printf("✅ SSL handshake successful!\n"); - for (;;) - { - /* Sleep until something happens. */ - ret = kevent(kq, NULL, 0, &tevent, 1, NULL); - if (ret == -1) { - err(EXIT_FAILURE, "kevent wait"); - } else if (ret > 0) { - if (tevent.flags & EV_ERROR) - errx(EXIT_FAILURE, "Event error: %s", strerror(event.data)); - else - printf("Something was written in '%s'\n", argv[1]); - } - } + // send a basic HTTP request + const char *req = + "GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: close\r\n\r\n"; + SSL_write(ssl, req, strlen(req)); + + char buf[INITIAL_BUFFER_CAPACITY]; + int bytes; + while ((bytes = SSL_read(ssl, buf, sizeof(buf) - 1)) > 0) + { + buf[bytes] = '\0'; + printf("%s", buf); + } + + SSL_shutdown(ssl); + SSL_free(ssl); + SSL_CTX_free(ctx); + close(sockfd); + EVP_cleanup(); + return 0; }
--- a/seobeo/BUILD Sat Oct 04 07:53:12 2025 -0700 +++ b/seobeo/BUILD Mon Oct 06 08:21:34 2025 -0700 @@ -1,6 +1,7 @@ load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_cc//cc:cc_library.bzl", "cc_library") + filegroup( name = "seobeo_hdrs", srcs = [ @@ -28,7 +29,10 @@ "os/s_macos_edge.c", ], hdrs = [":seobeo_hdrs"], - deps = ["//dowa:dowa"], + deps = [ + "//dowa:dowa", + "@openssl//:ssl", + ], target_compatible_with = [ "@platforms//os:osx", ], @@ -43,7 +47,10 @@ "os/s_linux_edge.c", ], hdrs = [":seobeo_headers"], - deps = ["//dowa:dowa"], + deps = [ + "//dowa:dowa", + "@openssl//:ssl", + ], target_compatible_with = [ "@platforms//os:linux", ],
--- a/seobeo/os/s_linux_edge.c Sat Oct 04 07:53:12 2025 -0700 +++ b/seobeo/os/s_linux_edge.c Mon Oct 06 08:21:34 2025 -0700 @@ -52,9 +52,10 @@ pthread_t threads[thread_count]; for (int i = 0; i < thread_count; i++) { - WorkerArgs args = { p_server_handle, p_html_cache, epfd }; - pthread_create(&threads[i], NULL, - Seobeo_Web_Edge_Worker, &args); + WorkerArgs *args = malloc(sizeof(WorkerArgs)); + *args = (WorkerArgs){ p_server_handle, p_html_cache, epfd }; + + pthread_create(&threads[i], NULL, Seobeo_Web_Edge_Worker, args); } for (int i = 0; i < thread_count; i++) {
--- a/seobeo/os/s_macos_edge.c Sat Oct 04 07:53:12 2025 -0700 +++ b/seobeo/os/s_macos_edge.c Mon Oct 06 08:21:34 2025 -0700 @@ -60,9 +60,10 @@ pthread_t threads[thread_count]; for (int i = 0; i < thread_count; i++) { - WorkerArgs args = { p_server_handle, p_html_cache, kq }; - pthread_create(&threads[i], NULL, - Seobeo_Web_Edge_Worker, &args); + WorkerArgs *args = malloc(sizeof(WorkerArgs)); + *args = (WorkerArgs){ p_server_handle, p_html_cache, kq }; + + pthread_create(&threads[i], NULL, Seobeo_Web_Edge_Worker, args); } for (int i = 0; i < thread_count; i++) {
--- a/seobeo/s_linux_network.c Sat Oct 04 07:53:12 2025 -0700 +++ b/seobeo/s_linux_network.c Mon Oct 06 08:21:34 2025 -0700 @@ -1,20 +1,20 @@ #include "seobeo/seobeo.h" -int Seobeo_CreateSocket(int32 stream, const char *host, const char* port) -{ - struct addrinfo hints = {0}, *server_infos, *free_server_info; - int32 sock_fd, yes = 1; // Need this for setsockopt - hints.ai_family = AF_INET; - hints.ai_socktype = stream ? SOCK_STREAM : SOCK_DGRAM; - hints.ai_protocol = stream ? IPPROTO_TCP : IPPROTO_UDP; - hints.ai_flags = stream ? AI_PASSIVE : 0; +Seobeo_PHandle Seobeo_Stream_Handle_Server_Create(const char *host, const char* port) +{ + Seobeo_PHandle p_handle; + struct addrinfo hints, *server_infos, *free_server_info; + int32 socket_fd, yes = 1; // Need this for setsockopt + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE; if (getaddrinfo(host, port, &hints, &server_infos) != 0) - { - perror("getaddrinfo"); - return -1; - } + { perror("getaddrinfo"); return NULL; } for ( @@ -23,88 +23,107 @@ free_server_info = free_server_info->ai_next ) { - if - ( - (sock_fd = socket( - free_server_info->ai_family, free_server_info->ai_socktype, - free_server_info->ai_protocol - )) == -1 - ) - { - perror("socket"); - continue; - } - - if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) - { - perror("setsockopt"); - continue; - } + if((socket_fd = socket(free_server_info->ai_family, + free_server_info->ai_socktype, free_server_info->ai_protocol)) == -1) + { perror("socket"); continue; } - if (host != NULL) - { - if (connect(sock_fd, free_server_info->ai_addr, free_server_info->ai_addrlen) == -1) - { - perror("connect"); - continue; - } + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) + { perror("setsockopt"); continue; } - } - else - { - if (bind(sock_fd, free_server_info->ai_addr, free_server_info->ai_addrlen) == -1) - { - perror("v_network: Couldn't make socket non-blocking\n"); - continue; - } + if (bind(socket_fd, free_server_info->ai_addr, free_server_info->ai_addrlen) == -1) + { perror("v_network: Couldn't make socket non-blocking\n"); continue; } - // UDP should be non blocking - if(!stream) - { - if (fcntl(sock_fd, F_SETFL, O_NONBLOCK) != 0) - { - close(sock_fd); - perror("v_network: Couldn't make socket non-blocking\n"); - return -1; - } - } - } - // binded to a open server infos; break; } - // No longer need these values + if (listen(socket_fd, 16) != 0) + { perror("listen"); close(socket_fd); return NULL; } + + if(fcntl(socket_fd, F_SETFL, O_NONBLOCK) != 0) { perror("fcntl"); return NULL; } freeaddrinfo(server_infos); - if (free_server_info == NULL) - { - perror("No free server"); - return -1; - } + p_handle = malloc(sizeof(*p_handle)); + p_handle->socket = socket_fd; + p_handle->type = SEOBEO_STREAM_TYPE_SERVER; + p_handle->connected = FALSE; + + p_handle->host = host != NULL ? strdup(host) : "localhost"; + p_handle->port = strdup(port); + + p_handle->ssl_ctx = NULL; + p_handle->ssl = NULL; + - if (host == NULL) - { - if (listen(sock_fd, 16) != 0) - { - perror("listen"); - close(sock_fd); - return -1; - } - } + p_handle->read_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY); + p_handle->read_buffer_capacity = INITIAL_BUFFER_CAPACITY; + p_handle->read_buffer_len = 0; - return sock_fd; + p_handle->write_buffer = malloc(sizeof(*p_handle->read_buffer) * INITIAL_BUFFER_CAPACITY); + p_handle->write_buffer_capacity = INITIAL_BUFFER_CAPACITY; + p_handle->write_buffer_len = 0; + + p_handle->file = NULL; + p_handle->text_copy = NULL; + p_handle->file_name = NULL; + p_handle->destroyed = false; + + return p_handle; } -Seobeo_PHandle Seobeo_Stream_Handle_Create(const char *host, const char* port) + +Seobeo_PHandle Seobeo_Stream_Handle_Client_Create(const char *host, const char* port, boolean use_tls) { Seobeo_PHandle p_handle; p_handle = malloc(sizeof(*p_handle)); - p_handle->socket = Seobeo_CreateSocket(1, host, port); // socke fd - if (!p_handle->socket) + struct addrinfo hints, *server_infos, *free_server_info; + int32 socket_fd, yes = 1; // Need this for setsockopt + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(host, port, &hints, &server_infos) != 0) + { perror("getaddrinfo"); return NULL; } + + + if((socket_fd = socket(server_infos->ai_family, + server_infos->ai_socktype, server_infos->ai_protocol)) == -1) + { perror("socket"); return NULL; } + + if (connect(socket_fd, server_infos->ai_addr, server_infos->ai_addrlen) != 0) + { perror("connect"); return NULL; } + freeaddrinfo(server_infos); + + p_handle->socket = socket_fd; + p_handle->type = SEOBEO_STREAM_TYPE_CLIENT; + if (use_tls) { - perror("Seobeo_CreateSocket"); + printf("USE SSL\n\n"); + init_openssl(); + p_handle->ssl_ctx = SSL_CTX_new(TLS_client_method()); + SSL_CTX_set_default_verify_paths(p_handle->ssl_ctx); + + p_handle->ssl = SSL_new(p_handle->ssl_ctx); + SSL_set_fd(p_handle->ssl, p_handle->socket); + + SSL_set_tlsext_host_name(p_handle->ssl, host); + // Blocking for TSL handshake + fcntl(socket_fd, F_SETFL, 0); + + if (SSL_connect(p_handle->ssl) != 1) + { + fprintf(stderr, "SSL_connect failed\n"); + ERR_print_errors_fp(stderr); + return NULL; + } + }else + { + p_handle->ssl_ctx = NULL; + p_handle->ssl = NULL; } + p_handle->connected = true; + p_handle->host = host != NULL ? strdup(host) : "localhost"; p_handle->port = strdup(port); @@ -142,9 +161,16 @@ return NULL; } - Seobeo_PHandle p_client_handle = malloc(sizeof *p_client_handle); + Seobeo_PHandle p_client_handle = malloc(sizeof *p_client_handle); p_client_handle->socket = client_fd; + p_client_handle->type = SEOBEO_STREAM_TYPE_CLIENT; + p_client_handle->connected = true; + + // TODO: support SSL in the future. + p_client_handle->ssl_ctx = NULL; + p_client_handle->ssl = NULL; + p_client_handle->host = strdup(client_inet_addr); p_client_handle->port = NULL; @@ -156,6 +182,8 @@ p_client_handle->write_buffer_len = 0; p_client_handle->write_buffer = malloc(p_client_handle->write_buffer_capacity); + p_client_handle->destroyed = false; + return p_client_handle; } @@ -181,35 +209,56 @@ free(p_handle); } -int Seobeo_Handle_Flush(Seobeo_PHandle p_handle) + +int32 Seobeo_Handle_Flush(Seobeo_PHandle p_handle) { uint32 total = p_handle->write_buffer_len; uint32 sent = 0; + printf("Total: %d\n\n", p_handle->write_buffer_len); + while (sent < total) { - ssize_t n = write( - p_handle->socket, - p_handle->write_buffer + sent, - total - sent - ); - if (n < 0) { - if (errno == EINTR) continue; - if (errno == EAGAIN) return 1; - return -1; + if (p_handle->ssl) + { + int n = SSL_write(p_handle->ssl, p_handle->write_buffer + sent, total - sent); + if (n < 0) + { + int err = SSL_get_error(p_handle->ssl, n); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) + { + // caller must wait for socket readiness and retry + return 0; + } + ERR_print_errors_fp(stderr); + return -1; + } + sent += (uint32)n; + }else + { + ssize_t n = write( + p_handle->socket, + p_handle->write_buffer + sent, + total - sent + ); + if (n < 0) { + if (errno == EINTR) continue; + if (errno == EAGAIN) return 1; + return -1; + } + sent += (uint32)n; } - sent += (uint32)n; } p_handle->write_buffer_len = 0; return 0; } -int Seobeo_Handle_Queue(Seobeo_PHandle p_handle, const uint8 *data, uint32 data_size) +int32 Seobeo_Handle_Queue(Seobeo_PHandle p_handle, const uint8 *data, uint32 data_size) { if (p_handle->write_buffer_len + data_size > p_handle->write_buffer_capacity) { - int rc = Seobeo_Handle_Flush(p_handle); + int32 rc = Seobeo_Handle_Flush(p_handle); if (rc < 0) return -1; if (rc > 0) return 1; } @@ -222,14 +271,29 @@ ssize_t n = write(p_handle->socket, data + offset, data_size - offset); + if (n==0) + { + // DEBUG + printf("NONE %d\n", offset); + break; + } if (n < 0) { - if (errno == EINTR) continue; + if (errno == EINTR || errno == EAGAIN) + { + // DEBUG + printf("Partial write, returning early (offset=%d)\n", offset); + continue; + } if (errno == EAGAIN) return 1; return -1; } offset += (uint32)n; + // DEBUG + printf("\n\noffset: %d data_size: %d\n\n", offset, data_size); } + // DEBUG + printf("\n\nTotal: %d\n", offset); return 0; } @@ -237,32 +301,54 @@ data, data_size); p_handle->write_buffer_len += data_size; + // DEBUG + printf("\nheader data_size: %d\n\n", data_size); return 0; } -int Seobeo_Handle_Read(Seobeo_PHandle p_handle) +int32 Seobeo_Handle_Read(Seobeo_PHandle p_handle) { + int32 read_size; + if (!p_handle) return -1; + // How many bytes we can still read into the buffer uint32 free_space = p_handle->read_buffer_capacity - p_handle->read_buffer_len; if (free_space == 0) return -1; - ssize_t n = read( - p_handle->socket, - p_handle->read_buffer + p_handle->read_buffer_len, - free_space - ); - if (n < 0) { - if (errno == EINTR) return Seobeo_Handle_Read(p_handle); - if (errno == EAGAIN) return 0; // no data available right now - return -1; // fatal error - } - if (n == 0) { - return -2; // peer closed the connection + if (p_handle->ssl) + { + read_size = (int32)SSL_read(p_handle->ssl, p_handle->read_buffer, + free_space); + if (read_size <= 0) + { + int err = SSL_get_error(p_handle->ssl, read_size); + switch (err) + { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + return 0; + case SSL_ERROR_ZERO_RETURN: + default: + // TODO: Handle these errors + return -2; + } + } + }else + { + read_size = (int32)read(p_handle->socket, + p_handle->read_buffer + p_handle->read_buffer_len, + free_space); + if (read_size == 0) return -2; + if (read_size < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) return 0; + return -1; + } } - p_handle->read_buffer_len += (uint32)n; - return (int)n; // number of bytes read + p_handle->read_buffer_len += (uint32)read_size; + return read_size; } void Seobeo_Handle_Consume(Seobeo_PHandle p_handle, uint32 consumed)
--- a/seobeo/s_web.c Sat Oct 04 07:53:12 2025 -0700 +++ b/seobeo/s_web.c Mon Oct 06 08:21:34 2025 -0700 @@ -8,6 +8,19 @@ "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Connection: close\r\n" + "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\n" + "accept-language: en-GB,en;q=0.9,en-US;q=0.8,ko;q=0.7\r\n" + "if-modified-since: Sat, 02 Aug 2025 22:51:58 GMT\r\n" + "if-none-match: W/\"688e968e-5700\"\r\n" + "priority: u=0, i\r\n" + "sec-ch-ua: \"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Google Chrome\";v=\"140\"\r\n" + "sec-ch-ua-mobile: 0\r\n" + "sec-ch-ua-platform: \"macOS\"\r\n" + "sec-fetch-dest: document\r\n" + "sec-fetch-mode: navigate\r\n" + "sec-fetch-site: none\r\n" + "sec-fetch-user: 1\r\n" + "upgrade-insecure-requests: 1\r\n" "\r\n", path, host ); @@ -33,7 +46,7 @@ sprintf( buffer, - "HTTP/2.2 %d %s\r\n" + "HTTP/1.1 %d %s\r\n" "Content-Type: %s\r\n" "Content-Length: %d\r\n" "Connection: close\r\n" @@ -71,17 +84,16 @@ goto clean_up; } - Dowa_HashMap_Print(p_req_map); + // DEBUG + // Dowa_HashMap_Print(p_req_map); const char *path = (const char*)Dowa_HashMap_Get(p_req_map, "Path"); - char *file_path = Dowa_Arena_Allocate(p_response_arena, (size_t)512); if (!path || strcmp(path, "/") == 0) { strcpy(file_path, "index.html"); - } - else + }else { size_t L = strlen(path); // strip leading '/' @@ -91,25 +103,38 @@ snprintf(file_path, 512, "%.*s/index.html", (int)(L-1), path+1); else snprintf(file_path, 512, "%.*s", (int)(L-1), path+1); - } - else + }else { // Probably never get here? strcpy(file_path, path); } } + // DEBUG // printf("\n\nfile_path: %s\n", file_path); // Recursively go though the path until it gets to a file while ((slash = strchr(file_path, '/'))) { *slash = '\0'; // e.g. file_path="foo", slash+1="index.html" - char *dir = file_path; // "foo" + char *dir = file_path; // "foo" file_path = slash + 1; // "index.html" + printf("\n\nDirectory: %s\n\n", dir); + p_current = Dowa_HashMap_Get(p_current, dir); - if (!p_current) { perror("No value"); goto clean_up; } + if (!p_current) + { + fprintf(stderr, "No value in hashmap key: %s\n\n", dir); + Seobeo_Web_GenerateResponseHeader(p_response_header, + HTTP_NOT_FOUND, + "text/html", 0); + Seobeo_Handle_Queue(p_cli_handle, + (const uint8*)p_response_header, + (uint32)strlen(p_response_header)); + Seobeo_Handle_Flush(p_cli_handle); + goto clean_up; + } } size_t pos = Dowa_HashMap_GetPosition(p_current, file_path); @@ -141,13 +166,19 @@ else if (strstr(file_path, ".json")) mime = "application/json"; size_t body_size = entry->capacity; + printf("key: %s\n\n", entry->key); + printf("Body Size: %zu\n\n", body_size); Seobeo_Web_GenerateResponseHeader(p_response_header, HTTP_OK, mime, body_size); + + printf("response header: %s, data: %d\n\n", p_response_header, (uint32)strlen(p_response_header)); Seobeo_Handle_Queue(p_cli_handle, (const uint8*)p_response_header, (uint32)strlen(p_response_header)); + + printf("response body data: %d\n\n", (uint32)body_size); Seobeo_Handle_Queue(p_cli_handle, (const uint8*)entry->buffer, (uint32)body_size); @@ -286,13 +317,15 @@ } Seobeo_PHandle p_server_handle = - Seobeo_Stream_Handle_Create(NULL, port); + Seobeo_Stream_Handle_Server_Create(NULL, port); if (p_server_handle->socket < 0) return 1; + printf("Listening on port %s\n", port); // Fork‐based fallback if (mode == SEOBEO_MODE_FORK) { + printf("FORK MODE\n"); struct sigaction sa; sa.sa_handler = SigchildHandler; sigemptyset(&sa.sa_mask); @@ -316,6 +349,7 @@ if (mode == SEOBEO_MODE_EDGE) { + printf("EDGE MODE\n"); Seobeo_Web_Edge(p_server_handle, thread_count, p_html_cache); } @@ -327,30 +361,24 @@ const char *port, const char *path) { - Seobeo_PHandle h = Seobeo_Stream_Handle_Create(host, port); + Seobeo_PHandle h = Seobeo_Stream_Handle_Client_Create(host, port, TRUE); if (!h || h->socket < 0) { - if (h) Seobeo_Handle_Destroy(h); + if (h) + Seobeo_Handle_Destroy(h); return -1; } Dowa_PArena p_request_arena = Dowa_Arena_Create(1 * 1024 * 1024); - if (!p_request_arena) - { - perror("Dowa_Arena_Create"); - return -1; - } + if (!p_request_arena) { perror("Dowa_Arena_Create"); return -1; } + void *p_request_header = Dowa_Arena_Allocate(p_request_arena, 4096); - if (!p_request_header) - { - perror("Dowa_Arena_Allocate"); - return -1; - } + if (!p_request_header) { perror("Dowa_Arena_Allocate"); return -1; } int request_len = Seobeo_Web_GenerateRequestHeader(p_request_header, host, path); - printf("request: %s\n", (char *)p_request_header); + // DEBUG + // printf("request: %s\n", (char *)p_request_header); Seobeo_Handle_Queue(h, (uint8 *)p_request_header, (uint32)request_len); - if (Seobeo_Handle_Flush(h) < 0) { perror("Seobeo_Handle_Flush"); @@ -358,30 +386,32 @@ return -1; } + // Response size_t cap = 1024*8, used = 0; char *p_request_body = Dowa_Arena_Allocate(p_request_arena, cap); if (!p_request_body) { Seobeo_Handle_Destroy(h); return -1; } - while (1) { + while (1) + { int n = Seobeo_Handle_Read(h); + printf("Size: %d\n", n); if (n > 0) { + // TODO: Maybe directly use arena inside of the struct? idk if that is useful or not... memcpy(p_request_body + used, h->read_buffer, h->read_buffer_len); used += h->read_buffer_len; Seobeo_Handle_Consume(h, (uint32)h->read_buffer_len); - } - else if (n == 0) + }else if (n == 0) { - // non-blocking mode and no data right now → keep looping or break? - // For a simple blocking client, you could block instead: + // Wait continue; - } - else if (n == -2) + }else if (n == -2) { + // Debug // peer closed; we’ve got everything + printf("\n\nCLOSED\n\n"); break; - } - else + }else { Dowa_Arena_Free(p_request_arena); Seobeo_Handle_Destroy(h); @@ -389,7 +419,7 @@ } } - printf("%s\n\n", p_request_body); + printf("%s", p_request_body); Dowa_Arena_Free(p_request_arena); Seobeo_Handle_Destroy(h); return 0;
--- a/seobeo/seobeo.h Sat Oct 04 07:53:12 2025 -0700 +++ b/seobeo/seobeo.h Mon Oct 06 08:21:34 2025 -0700 @@ -22,6 +22,10 @@ #include <stdatomic.h> #include <stdbool.h> +// SSL +#include <openssl/ssl.h> +#include <openssl/err.h> + #include "dowa/dowa.h" #define INITIAL_BUFFER_CAPACITY 4096 @@ -37,23 +41,39 @@ #define HTTP_NOT_FOUND 404 #define HTTP_INTERNAL_ERROR 500 +typedef enum { + SEOBEO_STREAM_TYPE_SERVER, + SEOBEO_STREAM_TYPE_CLIENT, +} Seobeo_SocketType; + typedef struct { - int socket; - char *host; - char *port; + uint32 ip; + uint16 port; +} Seobeo_Address, Seobeo_PAddress; + +typedef struct { + int32 socket; + Seobeo_SocketType type; + boolean connected; - uint8 *read_buffer; - uint32 read_buffer_capacity; - uint32 read_buffer_len; // current size - uint32 read_buffer_used; // TODO: Implement this for client + char *host; + char *port; + + SSL_CTX *ssl_ctx; + SSL *ssl; - uint8 *write_buffer; - uint32 write_buffer_capacity; - uint32 write_buffer_len; // current size + uint8 *read_buffer; + uint32 read_buffer_capacity; + uint32 read_buffer_len; // current size + uint32 read_buffer_used; // TODO: Implement this for client - void *file; - void *text_copy; - char *file_name; + uint8 *write_buffer; + uint32 write_buffer_capacity; + uint32 write_buffer_len; // current size + + void *file; + void *text_copy; + char *file_name; atomic_bool destroyed; } Sebeo_Handle, *Seobeo_PHandle; @@ -70,11 +90,12 @@ } Seobeo_ServerMode; // --- Socket, IP related --- // -extern int Seobeo_CreateSocket(int32 stream, const char *host, const char* port); +extern boolean Seobeo_DNS_LookUp(Seobeo_Address *address, char *dns_name); extern void *Seobeo_GetIP4OrIP6(struct sockaddr *sa); // --- TCP --- // -extern Seobeo_PHandle Seobeo_Stream_Handle_Create(const char *host, const char* port); +extern Seobeo_PHandle Seobeo_Stream_Handle_Server_Create(const char *host, const char* port); +extern Seobeo_PHandle Seobeo_Stream_Handle_Client_Create(const char *host, const char* port, boolean use_tls); extern Seobeo_PHandle Seobeo_Stream_Handle_Accept(Seobeo_PHandle p_server_handle); extern int Seobeo_Stream_Handle_Read(Seobeo_PHandle p_handle); @@ -95,5 +116,15 @@ extern int Seobeo_Handle_Read(Seobeo_PHandle p_handle); extern void Seobeo_Handle_Consume(Seobeo_PHandle p_handle, uint32 consumed); +static void init_openssl(void) +{ + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); +} + +static void cleanup_openssl(void) +{ + EVP_cleanup(); +} #endif