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