view seobeo/main.c @ 5:3e12bf044589

Fixed Dowa hashmap to recursively add files into memory.
author June Park <parkjune1995@gmail.com>
date Sat, 27 Sep 2025 16:23:04 -0700
parents 0b3b4f5887bb
children 1e61008b9980
line wrap: on
line source

/*
** server.c -- a stream socket server demo
*/

#include "seobeo/seobeo.h"

Dowa_PHashMap cache;

void SigchildHandler(int s)
{
  (void)s; // quiet unused variable warning

  // waitpid() might overwrite errno, so we save and restore it:
  int saved_errno = errno;

  while(waitpid(-1, NULL, WNOHANG) > 0);

  errno = saved_errno;
}

void HandleClientRequest(Seobeo_PHandle cli)
{
  Dowa_PArena response_arena = Dowa_Arena_Create(8192);
  if (!response_arena)
  {
    perror("Dowa_Arena_Initialize");
    goto clean_up;
  }

  size_t idx = Dowa_HashMap_GetPosition(cache, "index.html");
  Dowa_PHashEntry entry = cache->entries[idx]; 
  if (!entry)
  {
    // 404 response if missing
    const char *not_found =
      "HTTP/2.0 404 Not Found\r\n"
      "Content-Length: 0\r\n"
      "Connection: close\r\n"
      "\r\n";
    send(cli->socket, not_found, strlen(not_found), 0);
    goto clean_up;
  }

  // 3) Prepare header with the correct content‐length
  size_t body_size = entry->capacity;
  const char *template =
    "HTTP/2.0 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Content-Length: %zu\r\n"
    "Connection: close\r\n"
    "\r\n";

  // Compute how large the header is and allocate just enough space
  int header_len = snprintf(NULL, 0, template, body_size);
  void *header = Dowa_Arena_Allocate(response_arena, (size_t)(header_len+1));
  if (header == NULL)
  {
    perror("Dowa_Arena_Allocate");
    goto clean_up;
  }

  snprintf((char *)header, header_len + 1, template, body_size);
  Seobeo_Handle_QueueData(cli,
              (const uint8*)header,
              (uint32)(header_len + 1));
  Seobeo_Handle_QueueData(cli,
              (const uint8*)entry->buffer,
              (uint32)body_size);
  Seobeo_Handle_Flush(cli);
  goto clean_up;

clean_up:
  Seobeo_Handle_Destroy(cli);
  Dowa_Arena_Free(response_arena);
  return ;
}

int main(void)
{
  struct sigaction sa;

  cache = Dowa_HashMap_Create(1024);
  if (Dowa_Cache_Folder(cache, "seobeo/pages") != 0)
  {
    perror("Dowa_Cache_Folder");
    return -1;
  }

  Seobeo_PHandle srv = Seobeo_Stream_Handle_Create(NULL, "8080");

  if (srv->socket < 0) return 1;
  printf("Listening on port 8080\n");

  // TODO: Use epoll or something else.
  // Code from Beej's book
  // Handling child processes
  sa.sa_handler = SigchildHandler;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = SA_RESTART;
  if (sigaction(SIGCHLD, &sa, NULL) == -1)
  {
    perror("sigaction");
    exit(1);
  }

  while (1)
  {
    Seobeo_PHandle cli = Seobeo_Stream_Handle_Accept(srv);
    if (cli == NULL)
    {
      continue; 
    }
    printf("client connected from %s\n", cli->host);

    if (!fork())
    {
      HandleClientRequest(cli);
      exit(0);
    }
    Seobeo_Handle_Destroy(cli);
  }

  Seobeo_Handle_Destroy(srv);
  return 0;
}