/* Author: Pete Broadwell, Grinnell College
   Minor Adjustments for Linux made 11/29/00 by Henry M. Walker

   This program facilitates a simple client/server data transfer through the
   use of UNIX domain sockets. Simulating a simple scenario of the readers-
   writers problem, the writer (server) process writes 10 integers to the
   socket, which the reader (client) process then reads. */

#include <sys/types.h>
#include <unistd.h>          
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>     /* socket command libraries needed by some compilers */
#include <sys/socket.h>
#include <sys/un.h>

#define SOCKET_NAME "Com1" /* name of the socket file */
#define SIM_LENGTH 5 /* number of integers to be written and read */

/* procedure to remove socket file and exit */
void clean_up(int cond, int *sock)
{ printf("Exiting now.\n");
  close(*sock); /* close the socket file */
  unlink(SOCKET_NAME); /* remove the socket file */
  exit(cond);
} /* end of clean_up */

int main(void)
{ pid_t pid;
  pid = fork();     /* spawn new child process */
  if (-1 == pid)
    { perror("Error in fork");
      exit(1);
    }

  if (0 == pid)
    { /* processing for client */
      int sock; /* socket file descriptor */
      struct sockaddr_un cli_name; /* socket address structure */
      int count;
      int value; /* variable for number read from socket */

      sleep(1); /* give server process time to create the socket */
      printf("Client is alive and establishing socket connection.\n");

      /* set the socket descriptor */ 
      sock = socket(AF_UNIX, SOCK_STREAM, 0);
      if (sock < 0)
        { perror("Error opening channel");
          clean_up(1, &sock);
        }
      
      /* set the phyiscal address (cli_name) of the socket descriptor */
      bzero(&cli_name, sizeof(cli_name)); /* initializes cli_name structure */
      cli_name.sun_family = AF_UNIX; /* socket family will be AF_UNIX (UNIX) */
      strcpy(cli_name.sun_path, SOCKET_NAME); /* set the address of the
                                                 socket within the file system:
                                                 in this case, "Com1" */      
      /* connect to the socket */
      if (connect(sock, (struct sockaddr *)&cli_name, sizeof(cli_name)) < 0)
        { perror("Error establishing communications");
          clean_up(1, &sock);
        }

      /* read data from the socket */
      for (count = 1; count <= SIM_LENGTH; count++)
        { read(sock, &value, 4);
          printf("Client has received %d from socket.\n", value);
        }
      close(sock); /* close connection to the socket */
      exit(0);

    } /* end of processing for client */

  else
    { /* processing for server */
      int sock; /* variable for listening socket descriptor */
      int connect_sock; /* variable for connected socket descriptor */
      struct sockaddr_un serv_name;
      int count;
      size_t len; /* variable to store the size of the serv_name structure */

      /* set socket descriptor */ 
      sock = socket(AF_UNIX, SOCK_STREAM, 0);
      if (sock < 0)
        { perror("Error opening channel");
          clean_up(1, &sock);
        }

      /* set the physical address (serv_name) of the socket descriptor */
      bzero(&serv_name, sizeof(serv_name));
      serv_name.sun_family = AF_UNIX;
      strcpy(serv_name.sun_path, SOCKET_NAME);
  
      /* bind the socket address to the socket descriptor */
      if (bind(sock, (struct sockaddr *)&serv_name, sizeof(serv_name)) < 0)
        { perror("Error naming channel");
          clean_up(1, &sock);
        }
      
      listen(sock, 1); /* listen for connections on the socket */
      printf("Server is alive and waiting for socket connection from client.\n");
      
      /* accept connection request from client */
      len = sizeof(serv_name);
      connect_sock = accept(sock, (struct sockaddr *)&serv_name, &len);


      /* write data to the client's connected socket */
      for (count = 1; count <= SIM_LENGTH; count++)
        { write(connect_sock, &count, 4);
          printf("Server has written %d to socket.\n", count);
        }

      waitpid(pid, NULL, 0); /* Wait for client process to terminate */
      clean_up(0, &sock); /* Exit with no errors */
    } /* end of processing for server */

} /* end of main */
