view seobeo/main.c @ 3:2758f5527d2b

[Seobeo] Working on simple TCP server and client logic.
author June Park <parkjune1995@gmail.com>
date Wed, 24 Sep 2025 18:49:09 -0700
parents adcfad6e86fb
children 0b3b4f5887bb
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(int client_fd)
{
  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/1.1 404 Not Found\r\n"
      "Content-Length: 0\r\n"
      "Connection: close\r\n"
      "\r\n";
    send(client_fd, not_found, strlen(not_found), 0);
    close(client_fd);
    return;
  }

  // 3) Prepare header with the correct content‐length
  size_t body_size = entry->capacity;
  const char *template =
    "HTTP/1.1 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);
  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);
  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;
  }

  // 6) Tear down
  close(client_fd);
}

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

  struct sigaction sa;

  sa.sa_handler = SigchildHandler; // reap all dead processes
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = SA_RESTART;
  if (sigaction(SIGCHLD, &sa, NULL) == -1) {
    perror("sigaction");
    exit(1);
  }
  
  int sock_fd = Seobeo_CreateSocket(1, "6969", 10);
  Seobeo_ListenClient(sock_fd, &HandleClientRequest);

  return 0;
}