/* 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>

/* It opens a connection to the host name rhost that is listening
   on the specified port. It returns the socket descriptor, or -1
   in case of failure.
 */
int clientsocket(const char *rhost, unsigned short port)
{
  struct hostent *ptrh;  /* pointer to a host table entry     */
  struct sockaddr_in sad;/* structure to hold server's address*/
  int    fd;             /* socket descriptor                 */

  memset((char *)&sad, 0, sizeof(sad)); /* clear sockaddr structure */
  sad.sin_family = AF_INET;  /* set family to Internet */
  sad.sin_port = htons((u_short)port); 
  /* Convert host name to equivalent IP address and copy sad */
  ptrh = gethostbyname(rhost);
  if (((char *)ptrh) == NULL) {
    fprintf(stderr, "invalid host: %s\n", rhost);
    return (-1);
  }
  memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
  
  /* Create a socket */
  fd = socket(PF_INET, SOCK_STREAM, 0);
  if (fd < 0) {
    fprintf(stderr, "socket creation failed\n");
    return (-1);;
  }
  
  /* Connect the socket to the specified server */
  if (connect(fd, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
    fprintf(stderr, "connect failed\n");
    return (-1);
  }

  return fd;
}


#define PROTOPORT 5194 /* default protocol port number */

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

int main(int argc, char *argv[])
{
  int    cs;     /* client socket */
  int    port;   /* protocol port number */
  char   *host;  /* pointer to host name */
  int    n = 0;  /* number of characters read in line */
  char   c;

  /* 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 */
    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;
  }

  /* Initialize the client socket structure by connecting to server */
  if ( ( cs = clientsocket(host, port) ) < 0 ) {
    fprintf(stderr, "Cannot connect to server\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 */
    printf("Enter a line: ");
    n = 0;
    for (;;) {
      c = getchar();
      write(cs, &c, 1); /* why using write one character at a time is ok
			   in this case? */
      if (c == '\n') break;
      n++;
    }
    /* Read a line from the socket */
    n = 0;
    for (;;) {
      read(cs, &c, 1);
      putchar(c);
      if (c == '\n') break;
      n++;
    }
    if (n == 0) break; /* The line entered by user was null */
  } 
  /* Close socket */
  close(cs);
  
  /* Terminate client program gracefully */
  exit(0); 
}
