changeset 4:0b3b4f5887bb

[Seobeo] Updated so that it create socket for both server and clients.
author June Park <parkjune1995@gmail.com>
date Fri, 26 Sep 2025 15:14:46 -0700
parents 2758f5527d2b
children 3e12bf044589
files seobeo/main.c seobeo/s_linux_network.c seobeo/seobeo.h
diffstat 3 files changed, 196 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/seobeo/main.c	Wed Sep 24 18:49:09 2025 -0700
+++ b/seobeo/main.c	Fri Sep 26 15:14:46 2025 -0700
@@ -18,10 +18,11 @@
   errno = saved_errno;
 }
 
-void HandleClientRequest(int client_fd)
+void HandleClientRequest(Seobeo_PHandle cli)
 {
   size_t idx = Dowa_HashMap_GetPosition(cache, "index.html");
-  Dowa_PHashEntry entry = cache->entries[idx];
+  Dowa_PHashEntry entry = cache->entries[idx]; 
+
   if (!entry) {
     // 404 response if missing
     const char *not_found =
@@ -29,8 +30,8 @@
       "Content-Length: 0\r\n"
       "Connection: close\r\n"
       "\r\n";
-    send(client_fd, not_found, strlen(not_found), 0);
-    close(client_fd);
+    send(cli->socket, not_found, strlen(not_found), 0);
+    Seobeo_Handle_Destroy(cli);
     return;
   }
 
@@ -48,40 +49,29 @@
   char *header = malloc(header_len + 1);
   if (!header) {
     perror("malloc");
-    close(client_fd);
     return;
   }
   snprintf(header, header_len + 1, template, body_size);
 
-  // 4) Send header
-  send(client_fd, header, header_len, 0);
+  Seobeo_Handle_QueueData(cli,
+              (const uint8*)header,
+              (uint32)(header_len + 1));
   free(header);
 
-  // 5) Stream the body in a loop until everything is sent
-  ssize_t total_sent = 0;
-  const char *body = entry->buffer;
-  while ((size_t)total_sent < body_size)
-  {
-    ssize_t sent = send(
-      client_fd,
-      body + total_sent,
-      body_size - total_sent,
-      0
-    );
-    if (sent <= 0)
-    {
-      // error or connection closed by client
-      break;
-    }
-    total_sent += sent;
-  }
+  Seobeo_Handle_QueueData(cli,
+              (const uint8*)entry->buffer,
+              (uint32)body_size);
 
-  // 6) Tear down
-  close(client_fd);
+
+  Seobeo_Handle_Flush(cli);
+
+  Seobeo_Handle_Destroy(cli);
 }
 
 int main(void)
 {
+  struct sigaction sa;
+
   cache = Dowa_HashMap_Create(1024);
   if (Dowa_Cache_Folder(cache, "seobeo/pages") != 0)
   {
@@ -89,7 +79,10 @@
     return -1;
   }
 
-  struct sigaction sa;
+  Seobeo_PHandle srv = Seobeo_Stream_Handle_Create(NULL, "8080");
+
+  if (srv->socket < 0) return 1;
+  printf("Listening on port 8080\n");
 
   sa.sa_handler = SigchildHandler; // reap all dead processes
   sigemptyset(&sa.sa_mask);
@@ -98,10 +91,23 @@
     perror("sigaction");
     exit(1);
   }
-  
-  int sock_fd = Seobeo_CreateSocket(1, "6969", 10);
-  Seobeo_ListenClient(sock_fd, &HandleClientRequest);
+
+  while (1) {
+    Seobeo_PHandle cli = Seobeo_Stream_Handle_Accept(srv);
+    if (cli == NULL)
+    {
+      continue; 
+    }
+    printf("connected to %s\n", cli->host);
 
+    if (!fork())
+    {
+      HandleClientRequest(cli);
+      exit(0);
+    }
+    Seobeo_Handle_Destroy(cli);
+  }
+
+  Seobeo_Handle_Destroy(srv);
   return 0;
 }
-
--- a/seobeo/s_linux_network.c	Wed Sep 24 18:49:09 2025 -0700
+++ b/seobeo/s_linux_network.c	Fri Sep 26 15:14:46 2025 -0700
@@ -1,29 +1,16 @@
 #include "seobeo/seobeo.h"
 
-int Seobeo_CreateSocket(int32 stream, char* port, int32 backlog)
+int Seobeo_CreateSocket(int32 stream, const char *host,  const char* port, int32 backlog)
 {
-  int32 sock_fd;
-  struct addrinfo hints, *server_infos, *free_server_info;
-  int32 yes = 1; // Need this for setsockopt 
+  struct addrinfo hints = {0}, *server_infos, *free_server_info;
+  int32 sock_fd, yes = 1;  // Need this for setsockopt 
 
-  memset(&hints, 0, sizeof(hints));
-  if (stream)
-  {
-    hints.ai_family = AF_INET;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = IPPROTO_TCP; 
-    hints.ai_flags = AI_PASSIVE;
-  }
-  else
-  {
-    hints.ai_family = AF_INET;
-    hints.ai_socktype = SOCK_DGRAM;
-    hints.ai_protocol = IPPROTO_UDP; 
-    hints.ai_flags = AI_PASSIVE;
-  }
+  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;
 
-
-  if (getaddrinfo(NULL, port, &hints, &server_infos) != 0)
+  if (getaddrinfo(host, port, &hints, &server_infos) != 0)
   {
     perror("getaddrinfo");
     return -1;
@@ -62,14 +49,14 @@
      }
 
      // UDP should be non blocking
-	   if(!stream)
+     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;
-	     }
+         perror("v_network: Couldn't make socket non-blocking\n");
+         return -1;
+       }
      }
 
      // binded to a open server infos;
@@ -86,11 +73,12 @@
   }
 
   // TCP listen
-	if(stream)
+  if(stream)
   {
     if (listen(sock_fd, backlog) != 0)
     {
       perror("listen");
+      close(sock_fd);
       return -1;
     }
   }
@@ -98,43 +86,133 @@
   return sock_fd;
 }
 
-
-void Seobeo_ListenClient(int sock_fd, void (*handle_client)(int))
+Seobeo_PHandle Seobeo_Stream_Handle_Create(const char *host,  const char* port)
 {
-  int32 client_fd;
-  struct sockaddr_storage client_addr; 
-  socklen_t sin_size;
+  Seobeo_PHandle p_handle;
+  p_handle = malloc(sizeof(*p_handle));
+
+  p_handle->socket = Seobeo_CreateSocket(1, host,  port, 10); // socke fd
+  p_handle->host = host != NULL ? strdup(host) : "localhost";
+  p_handle->port = strdup(port);
+
+  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;
+
+  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;
 
+  return p_handle;
+}
+
+Seobeo_PHandle Seobeo_Stream_Handle_Accept(Seobeo_PHandle server_h)
+{
+  struct sockaddr_storage addr;
+  socklen_t addrlen = sizeof addr;
   char client_inet_addr[INET6_ADDRSTRLEN];
+  int client_fd = accept(server_h->socket,
+                         (struct sockaddr*)&addr,
+                         &addrlen);
+  inet_ntop(
+      addr.ss_family,
+      Seobeo_GetIP4OrIP6((struct sockaddr *)&addr),
+      client_inet_addr, sizeof client_inet_addr);
+
+  if (client_fd == -1)
+  {
+    return NULL;
+  }
+
+  Seobeo_PHandle h = malloc(sizeof *h);
 
-  while (1) 
-  {
-    sin_size = sizeof(client_addr);
-    client_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
+  h->socket               = client_fd;
+  h->host                 = strdup(client_inet_addr);
+  h->port                 = NULL;
+
+  h->read_buffer_capacity = server_h->read_buffer_capacity;
+  h->read_buffer_len      = 0;
+  h->read_buffer          = malloc(h->read_buffer_capacity);
+
+  h->write_buffer_capacity = server_h->write_buffer_capacity;
+  h->write_buffer_len      = 0;
+  h->write_buffer          = malloc(h->write_buffer_capacity);
+
+  return h;
+}
 
-    if (client_fd == -1)
-    {
-      perror("accept");
-      break;
+void Seobeo_Handle_Destroy(Seobeo_PHandle h)
+{
+  close(h->socket);
+  free(h->host);
+  free(h->port);
+  free(h->read_buffer);
+  free(h->write_buffer);
+  free(h->file);
+  free(h->text_copy);
+  free(h->file_name);
+  free(h);
+}
+
+int Seobeo_Handle_Flush(Seobeo_PHandle h)
+{
+  uint32 total = h->write_buffer_len;
+  uint32 sent  = 0;
+
+  while (sent < total) {
+    ssize_t n = write(
+      h->socket,
+      h->write_buffer + sent,
+      total - sent
+    );
+    if (n < 0) {
+      if (errno == EINTR)  continue;
+      if (errno == EAGAIN) return 1;
+      return -1;
     }
+    sent += (uint32)n;
+  }
 
-    inet_ntop(
-        client_addr.ss_family,
-        Seobeo_GetIP4OrIP6((struct sockaddr *)&client_addr),
-        client_inet_addr, sizeof client_inet_addr);
+  h->write_buffer_len = 0;
+  return 0;
+}
+
 
-    printf("server: got connection from %s\n", client_inet_addr);
+int Seobeo_Handle_QueueData(Seobeo_PHandle h, const uint8_t *data, uint32_t data_size)
+{
+  if (h->write_buffer_len + data_size > h->write_buffer_capacity) {
+    int rc = Seobeo_Handle_Flush(h);
+    if (rc < 0) return -1;
+    if (rc > 0) return 1;
+  }
 
-    // Create a child process
-    if (!fork())
+  if (data_size > h->write_buffer_capacity)
+  {
+    uint32_t offset = 0;
+    while (offset < data_size)
     {
-      close(sock_fd);
-      handle_client(client_fd);
-      exit(0);
+      ssize_t n = write(h->socket,
+                data + offset,
+                data_size - offset);
+      if (n < 0) {
+        if (errno == EINTR)  continue;
+        if (errno == EAGAIN) return 1;
+        return -1;
+      }
+      offset += (uint32_t)n;
     }
+    return 0;
+  }
 
-    close(client_fd);
-  }
+  memcpy(h->write_buffer + h->write_buffer_len,
+         data,
+         data_size);
+  h->write_buffer_len += data_size;
+  return 0;
 }
 
 void *Seobeo_GetIP4OrIP6(struct sockaddr *sa)
--- a/seobeo/seobeo.h	Wed Sep 24 18:49:09 2025 -0700
+++ b/seobeo/seobeo.h	Fri Sep 26 15:14:46 2025 -0700
@@ -21,14 +21,38 @@
 
 #include "dowa/dowa.h"
 
+#define INITIAL_BUFFER_CAPACITY 4096
+
+typedef struct {
+  int     socket; 
+  char    *host;
+  char    *port;
+
+  uint8   *read_buffer;
+  uint32  read_buffer_capacity;
+  uint32  read_buffer_len; // current size
+  uint32  read_buffer_pos; // TODO: Implement this for client 
+
+  uint8   *write_buffer;
+  uint32  write_buffer_capacity;
+  uint32  write_buffer_len; // current size
+
+  void    *file;
+  void    *text_copy;
+  char    *file_name;
+} Sebeo_Handle, *Seobeo_PHandle;
+
 
 // --- Internal? --- //
-extern int  Seobeo_CreateSocket(int32 stream, char* port, int32 backlog);
-extern void Seobeo_ListenClient(int sock_fd, void (*handle_client)(int));
-extern void *Seobeo_GetIP4OrIP6(struct sockaddr *sa);
+extern int            Seobeo_CreateSocket(int32 stream, const char *host,  const char* port, int32 backlog);
+extern void           *Seobeo_GetIP4OrIP6(struct sockaddr *sa);
 
 // --- TCP --- //
-// extern int Seobeo_TCP_SocketCreate(char* port, int32 backlog)
+extern Seobeo_PHandle Seobeo_Stream_Handle_Create(const char *host,  const char* port);
+extern Seobeo_PHandle Seobeo_Stream_Handle_Accept(Seobeo_PHandle server_h);
+extern void           Seobeo_Handle_Destroy(Seobeo_PHandle h);
+extern int            Seobeo_Handle_Flush(Seobeo_PHandle h);
+extern int            Seobeo_Handle_QueueData(Seobeo_PHandle h, const uint8_t *data, uint32_t data_size);
 
 
 #endif