diff seobeo/s_linux_network.c @ 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
line wrap: on
line diff
--- 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)