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

#include "constants.h"
#include "netstr.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>

/* 
   Readloop simply loops, reading input from a user and sending it out
   on the socket.  End of file causes it to stop.
*/

void readloop (int s)
{
  char *fgets_val;
  char *line_read          = malloc(LINE_READ_MAX_SIZE);
  char *newln_position;
  int   exit_flag;
  int   send_val;

  exit_flag = 1;
  while (exit_flag) {
    printf("Send what? ");
    fgets_val = fgets(line_read, LINE_READ_MAX_SIZE, stdin);
    if (fgets_val == NULL) {
      /* End of file. */
      exit_flag = 0;
    } else {
      /* fgets can include newlines, but we don't want them so we'll
	 mark it as end of string */
      newln_position = strchr(line_read, '\n');
      if (newln_position != NULL) {
	*newln_position = '\0';
      }
      /* Send it out on the socket. */
      send_val = send(s, line_read, strlen(line_read), 0);
      if (send_val < 0) 
	{
	  perror("Send failed!");
	  exit(EXIT_FAILURE);
	}
    }
  }
}

/* 
   A variation of readloop for unconnected DGRAM sockets.
*/

void readloop2 (int                    s,
		const struct sockaddr *a, 
		socklen_t              alen)
{
  char *fgets_val;
  char *line_read          = malloc(LINE_READ_MAX_SIZE);
  char *newln_position;
  int   exit_flag;
  int   send_val;

  exit_flag = 1;
  while (exit_flag) {
    printf("Send what? ");
    fgets_val = fgets(line_read, LINE_READ_MAX_SIZE, stdin);
    if (fgets_val == NULL) {
      /* End of file. */
      exit_flag = 0;
    } else {
      /* fgets can include newlines, so we'll mark it as end of string */
      newln_position = strchr(line_read, '\n');
      if (newln_position != NULL)
	*newln_position = '\0';
      /* Send it out on the socket. */
      send_val = sendto(s, line_read, strlen(line_read), 0, a, alen);
      if (send_val < 0) 
	{
	  perror("Send failed!");
	  exit(EXIT_FAILURE);
	}
    }
  }
}

/* 
   A variation of readloop that sends a string on s, receives a string
   on s, and loops.
*/

void readloop3 (int s)
{
  char *buffer             = malloc(BUFFER_SIZE);
  char *fgets_val;
  char *line_read          = malloc(LINE_READ_MAX_SIZE);
  char *newln_position;
  int   exit_flag;
  int   send_val;
  int   recv_value;

  exit_flag = 1;
  while (exit_flag) {
    printf("Send what? ");
    fgets_val = fgets(line_read, LINE_READ_MAX_SIZE, stdin);
    if (fgets_val == NULL) {
      /* End of file. */
      exit_flag = 0;
    } else {
      /* fgets can include newlines, but we don't want them so we'll
	 mark it as end of string */
      newln_position = strchr(line_read, '\n');
      if (newln_position != NULL) {
	*newln_position = '\0';
      }
      /* Send it out on the socket. */
      send_val = send(s, line_read, strlen(line_read), 0);
      if (send_val < 0) 
	{
	  perror("Send failed!");
	  exit(EXIT_FAILURE);
	}
      /* Receive a reply on the socket. */
      recv_value = NSrecv(s, 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);
      }
    }
  }
}

/* 
   A variation of readloop that sends and receives on s, using select.
*/

void readloop4 (int s)
{
  char   *buffer             = malloc(BUFFER_SIZE);
  char   *fgets_val;
  char   *line_read          = malloc(LINE_READ_MAX_SIZE);
  char   *newln_position;
  fd_set  rd;
  int     exit_flag;
  int     select_val;
  int     send_val;
  int     recv_value;


  exit_flag = 1;
  while (exit_flag) {
    printf("Send what? (waiting for stdin or network)\n");

    /* We know monitor both stdin and socket s for ready data. */
    FD_ZERO(&rd);
    /* Monitor stdin (descriptor 0) for read. */
    FD_SET(0, &rd);
    /* Monitor socket s for read. */
    FD_SET(s, &rd);
    /* We'll wait forever, so we'll set the timeout to NULL.
       Simlarly, the write and exception sets are NULL because we are
       monitoring none.  
       n in select() is set to s+1, because s will be the highest
       descriptor in the sets. */
    select_val = select(s+1, &rd, NULL, NULL, NULL);
    if (select_val == -1) 
      {
	perror("Select failed!");
	exit(EXIT_FAILURE);
      }
    /* If we're here, then select returned with (hopefully) stdin or s
       having changes. */
    /* Check stdin: */
    if (FD_ISSET(0, &rd)) {
      fgets_val = fgets(line_read, LINE_READ_MAX_SIZE, stdin);
      if (fgets_val == NULL) {
	/* End of file. */
	exit_flag = 0;
      } else {
	/* fgets can include newlines, but we don't want them so we'll
	   mark it as end of string */
	newln_position = strchr(line_read, '\n');
	if (newln_position != NULL) {
	  *newln_position = '\0';
	}
	/* Send it out on the socket. */
	send_val = send(s, line_read, strlen(line_read), 0);
	if (send_val < 0) 
	  {
	    perror("Send failed!");
	    exit(EXIT_FAILURE);
	  }
      }
    }
    /* Check the socket s for a reply. */
    if (FD_ISSET(s, &rd)) {
      /* Receive a reply on the socket. */
      recv_value = NSrecv(s, 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);
      }
    }
  }
}

