/* echoclient.c - Whatever the user types is sent to the server,
 *                and whatever the server sends back is displayed
 *                to the user. If the user types a null line, the 
 *                connection will be closed.
 * Syntax: client [host [port]]
 *                 host: name of computer on which server is executing
 *                 port:protocol port number server is using
 * Note: Both arguments are optional. If no host name is specified
 *       the client uses "localhost"; if no protocol port is
 *       specified, the client uses the default given by PROTOPORT.
 */

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

#define PROTOPORT 5194 // default protocol port number

char localhost[] = "localhost"; // default host name 

int main(int argc, char *argv[])
{
  struct hostent *ptrh;  // pointer to a host table entry 
  struct protoent *ptrp; // pointer to a protocol table entry
  struct sockaddr_in sad;// structure to hold server's address
  int    sd;             // socket descriptor
  int    port;           // protocol port number
  char   *host;          // pointer to host name
  int    n = 0;          // number of characters read in line
  int    option_value;   // needed for setsockopt
  char   c;

  memset((char *)&sad, 0, sizeof(sad)); // clear sockaddr structure
  sad.sin_family = AF_INET;  // set family to Internet
  
  /* Check command-line argument for protocol port and extract
   * port number if one is specified. Otherwise, use the default
   * port value given by constant PROTOPORT
   */
  if (argc > 2) {         // If protocol port is specified 
    port = atoi(argv[2]); // Convert to binary
  } else {
    port = PROTOPORT;    // use default port number
  }

  if (port > 0)           // Test for legal value 
    sad.sin_port = htons((u_short)port);
  else {                  // Print error message and exit
    fprintf(stderr,"bad port number %s\n", argv[2]);
    exit(1);
  }
  
  // Check host argument and assign host name
  if (argc > 1) {
    host = argv[1];     // If host argument is specified
  } else {
    host = localhost;
  }
  
  // Convert host name to equivalent IP address and copy sad
  ptrh = gethostbyname(host);
  if (((char *)ptrh) == NULL) {
    fprintf(stderr, "invalid host: %s\n", host);
    exit(1);
  }
  memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
  
  // Map TCP transport protocol name to protocol number
  if (((int *)(ptrp = getprotobyname("tcp"))) == 0) {
    fprintf(stderr, "cannot map \"tcp\" to protocol number");
    exit(1);
  }
  
  // Create a socket
  sd = socket(PF_INET, SOCK_STREAM, ptrp->p_proto);
  if (sd < 0) {
    fprintf(stderr, "socket creation failed\n");
    exit(1);
  }
  
  // Make sure that port used will be immediately reusable
  option_value = 1;
  if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, 
		 (char *)&option_value, sizeof(option_value)) < 0)
    {
      perror("setsockopt");
      exit(1);
    }
  
  // Connect the socket to the specified server
  if (connect(sd, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
    fprintf(stderr, "connect failed\n");
    exit(1);
  }
  
  // Repeatedly read data from user, send to socket, and display response.
  for (;;) {
    // Read a line from user and write it to socket
    n = 0;
    printf("Enter a line: ");
    for (;;) {
      c = getchar();
      write(sd, &c, 1);
      if (c == '\n') break;
      n++;
    }
    // Read a line from the socket
    for (;;) {
      read(sd, &c, 1);
      putchar(c);
      if (c == '\n') break;
    }
    if (n == 0) break; // The line entered by user was null
  } 
  // Close socket
  close(sd);
  
  // Terminate client program gracefully 
  exit(0); 
}





