view seobeo/main.c @ 0:5695ef413be0

Initialized mono repo with bazels with few examples.
author June Park <parkjune1995@gmail.com>
date Tue, 23 Sep 2025 10:05:25 -0700
parents
children adcfad6e86fb
line wrap: on
line source

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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>

#define PORT "6969" 

#define BACKLOG 10   // how many pending connections queue will hold

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 *GetInternetaddr(struct sockaddr *sa)
{
  if (sa->sa_family == AF_INET) 
  {
    return &(((struct sockaddr_in*)sa)->sin_addr);
  }

  return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(void)
{
  int sock_fd, client_fd;
  struct addrinfo hints, *server_infos, *free_server_info;
  int yes = 1; // boolean

  struct sockaddr_storage client_addr; 
  socklen_t sin_size;

  char client_inet_addr[INET6_ADDRSTRLEN];

  struct sigaction sa;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  if (getaddrinfo(NULL, PORT, &hints, &server_infos) == 1)
  {
    perror("getaddrinfo");
    return 1;
  }

  for (free_server_info = server_infos; free_server_info != NULL; 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 (bind(sock_fd, free_server_info->ai_addr, free_server_info->ai_addrlen) == -1)
     {
       close(sock_fd);
       perror("setsockopt");
       continue;
     }

     // binded to a open server infos;
     break;
  }

  freeaddrinfo(server_infos);

  if (free_server_info == NULL)
  {
    perror("No free server");
    return 1;
  }

  if (listen(sock_fd, BACKLOG) != 0)
  {
    perror("listen");
    return 1;
  }

  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);
  }
  
  printf("server: waiting for connections...\n");

  char *response = 
    "HTTP/1.1 OK %s\r\n"
    "Content-Type: text/txt\r\n"
    "Content-Length: 13\r\n"
    "Connection: close\r\n"
    "\r\n"
    "Hello, world!";

  while (1) 
  {
    sin_size = sizeof(client_addr);
    client_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);

    if (client_fd == -1)
    {
      perror("accept");
      continue;
    }

    inet_ntop(
        client_addr.ss_family,
        GetInternetaddr((struct sockaddr *)&client_addr),
        client_inet_addr, sizeof client_inet_addr);

    printf("server: got connection from %s\n", client_inet_addr);

    // Create a child process
    if (!fork())
    {
      close(sock_fd);
      if (send(client_fd, response, strlen(response), 0) == -1)
      {
        perror("send");
        continue; 
      }
      close(client_fd);
      exit(0);
    }

    close(client_fd);
  }

  return 0;
}