/* 
   This file is part of Practical Distributed Processing
   Copyright (C) 2006-2007 Phillip J. Brooke and Richard F. Paige
*/

#include "compat.h"
#include "constants.h"
#include "netstr.h"
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

/* 
   Accept a stream connection, and print whatever is sent to us.
*/

int main ()
{
  char *             buffer        = malloc(BUFFER_SIZE);
  int                exit_flag;
  int                i;
  int                on            = 1;
  int                recv_value;
  int                s1;
  int                s2;
  socklen_t          sockaddr_in_len;
  struct sockaddr_in a;

  printf("Server starting...\n");

  /* Create a socket to listen on. */
  if ((s1 = socket(PF_INET, SOCK_STREAM, 0)) >= 0)
    printf("The socket has been created\n");
  else
    {
      perror("Could not create socket");
      exit(EXIT_FAILURE);
    }

  /* Reuse local addresses when binding the socket.  See socket(7). */
  if (setsockopt(s1, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
    {
      perror("Problem setting socket option");
      exit(EXIT_FAILURE);
    }

  /* Describe the addresses we'll accept connections from. */
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = INADDR_ANY;
  a.sin_port = htons(EXAMPLE_PORT);

  /* Bind the socket to the address. */
  if (bind(s1, (struct sockaddr *) &a, sizeof(a)) == 0)
    printf("Bound socket\n");
  else
    {
      perror("Could not bind socket");
      exit(EXIT_FAILURE);
    }

  /* Listen on the socket. */
  printf("Setting socket to listen...");
  if (listen(s1, 5) != 0)
    {
      perror("Problem listening on s1");
      exit(EXIT_FAILURE);
    }
  printf(" listening on socket\n");

  /* Now loop forever. */
  while (1) {
    printf("Waiting for inbound connection...\n");
    /* Accept the next connection. */
    sockaddr_in_len = sizeof(struct sockaddr_in);
    s2 = accept(s1, (struct sockaddr *) &a, &sockaddr_in_len);
    if (s2 == -1)
      {
	perror("Problem accepting connection");
	exit(EXIT_FAILURE);
      }
    else
      printf("Accepted connection from client on %s\n",
	     inet_ntoa(a.sin_addr));

    /* Loop until the connection closes, printing whatever the client
       sends. */
    exit_flag = 1;
    while (exit_flag) {
      recv_value = NSrecv(s2, buffer, BUFFER_SIZE, 0);
      if (recv_value == 0) {
	printf("Closing connection...\n");
	exit_flag = 0;
      } else if (recv_value < 0) {
	perror("Problem with recv");
	exit(EXIT_FAILURE);
      } else {
	printf("Received: %s\n", buffer);
	/* Send an anagram back. */
	{
	  int send_val;
	  char *bufferfry;
	  char *bufferfry2;
	  char *newln_position;
	  
	  /* We don't want any newlines in the anagram, so replace the
	     first (if any) with end-of-string. */
	  newln_position = strchr(buffer, '\n');
	  if (newln_position != NULL) {
	    *newln_position = '\0';
	  }
	  /* Get our anagram and send it.  Do this a random number of times*/
	  for (i = 0; i<(random()%10); i++) {
	    bufferfry = (char *)strfry(buffer);
	    /* We'll append a newline (+1).  We also have to include
	       the \0 (+1 again).*/
	    bufferfry2 = (char *)strndup(bufferfry, strlen(bufferfry)+2);
	    printf("(%d) Sending response %d...%s\n", 
		   i, getpid(), bufferfry2);
	    send_val = send(s2, bufferfry2, strlen(bufferfry2), 0);
	    free(bufferfry2);
	    if (send_val < 0) 
	      {
		perror("Send failed!");
		exit(EXIT_FAILURE);
	      }
	    printf("(%d) Sent response\n", getpid());
	  }
	}
      }
    } 

    /* Close the inbound socket. */
    if (close(s2) != 0)
      perror("Warning: problem closing s2");
  }

  /* We never exit the while loop.  If we did, we should close
     s1 and exit. */
}
