/*

  File name : client1.c
  Related files: server1.c
  Author : Chee Yap
  Date : Nov 2001 (Web Visualization Class)

  Description : 
		VARIATIONS ON:

		This is the client side program
                of a simple TCP client-server test program.
                It simply reads a number (unsigned, integer
		or float) from the user input, sends it to the
		server (see server.c file), and then
                display everything returned from the server.
                This is repeated until the user types "quit",
		at which point both sides will close the connection.

  Usage: Simply type "client" to access the server at 
		jinai.cs.nyu.edu, at default port 1234.
	The general format is
		 % client [<server_site>] [ -p <port number> ]

  How to compile :

  On Solaris 2 :

	% gcc -o client client.c -lsocket -lnsl

  On SGI machines or Linux machines:

	% gcc -o client client.c


*/

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

int             con_sock;
int             srv_port = 1234;
char		host[128];

/*
  Received a signal. Close the connection and quit.
*/
void signal_handler()
{
	close(con_sock);

	exit(0);
}

/*
  establish_connection() will do what its name
  suggests: makes a connection to the server.
  It will use the global variables host and srv_port
  as input.  Then it will update the value of con_sock,
  which is the file descriptor of the socket
  used for communicating with the server.
*/
establish_connection()
{
	struct sockaddr_in name;
	struct hostent *hptr;
	int flag;

/*  step (a) create a socket  */
	con_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
		// it is misconception to use "AF_INET" instead of "PF_INET"

	if (con_sock <= 0) {
		perror("Open socket failed");
		exit(1);
	}

	name.sin_family = PF_INET; 
	name.sin_port = htons(srv_port);

/* getting the host IP information */
	if ((hptr = gethostbyname(host)) == NULL) {
	  perror("gethostbyname");
	  exit(1);
	}

	bcopy(hptr->h_addr, (char *)&name.sin_addr.s_addr, hptr->h_length);

	printf("Trying to contact %s...\n", host);

/* making connection */
	flag = connect(con_sock, (struct sockaddr *) &name, sizeof(name));

	if (flag < 0)
	{
	  perror("No connection");
	  close(con_sock);
	  exit(1);
	}
	printf("Connected\n");
}

extern int errno;

/*
  make_trans() will get user input, put them to the
server, and then display the return message from
the server.
*/
make_trans()
{
  char buff[1024], out[1024];
  int lg, flag;

  flag = 1;

  do {
/* getting one line from standard input */
    gets(buff);

    sprintf(out, "%s\r\n", buff);
/* write everything to the network. */
    lg = write(con_sock, out, strlen(out));

/* If having any trouble with the socket, it means that
   the connection is closed somehow, quit the program. */
    if (lg == -1 && errno == EBADF)
      goto error;

/* If the user input is "quit", then end the loop. */
    if (strncmp(buff, "quit", 4) == 0)
    {
      flag = 0;
      break;
    }
    do {
/* get response from the server. If there is error
   and it is EBADF, it means the connection might
   be closed, otherwise, try to read it again until
   we read it successfully.   */
    lg = read(con_sock, buff, 1024);
    if (lg == -1 && errno == EBADF)
      goto error;
    } while (lg <= 0);
    if (buff[lg - 1] != '\n' || buff[lg - 2] != '\r') {
       fprintf(stderr, "Error: Wrong format\r\n");
    }

/* Display the response to standard output */
    buff[lg - 1] = '\0';
    buff[lg - 2] = '\n';
    printf("%s", buff);
  } while (flag);

/* close the connection if */
  error:
  close(con_sock);
}


usage()
{
	fprintf(stderr, "usage: client [-p port]\n");
	exit(1);
}

main(argc, argv)
int argc;
char **argv;
{
	int             lg;


/* shift the parameters */
	argc--;
	argv++;

/* set initial value of the server. */
	strcpy(host, "jinai.cs.nyu.edu");
	while (argc > 0) {
		if (argv[0][0] != '-')
		{
/* setting new server name */
		  strcpy(host, argv[0]);
		  argv ++;
		  argc --;
		  continue;
		}
		switch (argv[0][1]) {
/* setting port number */
		case 'p':
			srv_port = atoi(argv[1]);
			argv += 2;
			argc -= 2;
			break;
		default:
			usage();
		}
	}

/* Intercept some signals so we can quit the program
   more gracefully when interrupted by such signals. */
	signal(SIGTERM, signal_handler);
	signal(SIGQUIT, signal_handler);
	signal(SIGINT, signal_handler);

	establish_connection();
	make_trans();
}
