view seobeo/s_linux_network.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

#include "seobeo/seobeo.h"

int Seobeo_CreateSocket(int32 stream, char* port, int32 backlog)
{
  int32 sock_fd;
  struct addrinfo hints, *server_infos, *free_server_info;
  int32 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;
  }


  if (getaddrinfo(NULL, port, &hints, &server_infos) != 0)
  {
    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;
     }

     // 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
  freeaddrinfo(server_infos);

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

  // TCP listen
	if(stream)
  {
    if (listen(sock_fd, backlog) != 0)
    {
      perror("listen");
      return -1;
    }
  }

  return sock_fd;
}


void Seobeo_ListenClient(int sock_fd, void (*handle_client)(int))
{
  int32 client_fd;
  struct sockaddr_storage client_addr; 
  socklen_t sin_size;

  char client_inet_addr[INET6_ADDRSTRLEN];

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

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

    inet_ntop(
        client_addr.ss_family,
        Seobeo_GetIP4OrIP6((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);
      handle_client(client_fd);
      exit(0);
    }

    close(client_fd);
  }
}

void *Seobeo_GetIP4OrIP6(struct sockaddr *sa)
{
  if (sa->sa_family == AF_INET) 
  {
    return &(((struct sockaddr_in*)sa)->sin_addr);
  }

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