/*****************************************************************************/
/* The program opens infinite number of connection with the TCP server       */
/*     in order to measure time                                              */
/*                                                                           */
/*****************************************************************************/

    #include <stdio.h> 
    #include <stdlib.h> 
    #include <errno.h> 
    #include <string.h> 
    #include <netdb.h> 
    #include <sys/types.h> 
    #include <netinet/in.h> 
    #include <sys/socket.h> 
    #include <unistd.h>
    #include <sys/time.h>
    #include <netinet/tcp.h>         /* for TCP_xxx defines */

 

    #define PORT 9999           /* the port client will be connecting to */
    #define MAXDATASIZE 100     /* max number of bytes we can get at once */


    int main(int argc, char *argv[])
    {

        int                     sockfd, numbytes;       /*Socket file descriptor & bystes sent  */
	int			on=1;
	int			len;
	int			sockopt;
        char                    buf[MAXDATASIZE];       /*The string to be passed               */
        struct  hostent         *he;                    /*Is needed for address resolution      */
        struct  sockaddr_in     their_addr;             /* connector's address information      */
		union val {
		int                           i_val;
		long                          l_val;
		char                          c_val[10];
		struct linger         linger_val;
		struct timeval        timeval_val;
	} val;
	
	static char     *sock_str_flag(union val *, int);
	static char     *sock_str_int(union val *, int);
	static char     *sock_str_linger(union val *, int);
	static char     *sock_str_timeval(union val *, int);
 
	static char     strres[128];

	static char     *
	sock_str_flag(union val *ptr, int len)
	{
	        if (len != sizeof(int))
        	        snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
	        else
                	snprintf(strres, sizeof(strres),
                                 "%s", (ptr->i_val == 0) ? "off" : "on");
	        return(strres);
	}

	static char     *
	sock_str_int(union val *ptr, int len)
	{
	        if (len != sizeof(int))
	                snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
	        else
	                snprintf(strres, sizeof(strres), "%d", ptr->i_val);
	        return(strres);
	}

	static char     *
	sock_str_linger(union val *ptr, int len)
	{
	        struct linger   *lptr = &ptr->linger_val;

	        if (len != sizeof(struct linger))
	                snprintf(strres, sizeof(strres),
	                                 "size (%d) not sizeof(struct linger)", len);
	        else
	                snprintf(strres, sizeof(strres), "l_onoff = %d, l_linger = %d",
	                                 lptr->l_onoff, lptr->l_linger);
	        return(strres);
	}

	static char     *
	sock_str_timeval(union val *ptr, int len)
	{
	        struct timeval  *tvptr = &ptr->timeval_val;

	        if (len != sizeof(struct timeval))
	                snprintf(strres, sizeof(strres),
	                                 "size (%d) not sizeof(struct timeval)", len);
	        else
	                snprintf(strres, sizeof(strres), "%d sec, %d usec",
	                                 tvptr->tv_sec, tvptr->tv_usec);
	        return(strres);
	}
 

	struct sock_opts {
	  char     *opt_str;
	  int           opt_level;
	  int           opt_name;
	  char   *(*opt_val_str)(union val *, int);
	} sock_opts[] = {
	        "SO_BROADCAST",     SOL_SOCKET,     SO_BROADCAST,   sock_str_flag,
	        "SO_DEBUG",         SOL_SOCKET,     SO_DEBUG,       sock_str_flag,
	        "SO_DONTROUTE",     SOL_SOCKET,     SO_DONTROUTE,   sock_str_flag,
	        "SO_ERROR",         SOL_SOCKET,     SO_ERROR,       sock_str_int,
	        "SO_KEEPALIVE",     SOL_SOCKET,     SO_KEEPALIVE,   sock_str_flag,
	        "SO_LINGER",        SOL_SOCKET,     SO_LINGER,      sock_str_linger,
	        "SO_OOBINLINE",     SOL_SOCKET,     SO_OOBINLINE,   sock_str_flag,
	        "SO_RCVBUF",        SOL_SOCKET,     SO_RCVBUF,      sock_str_int,
	        "SO_SNDBUF",        SOL_SOCKET,     SO_SNDBUF,      sock_str_int,
	        "SO_RCVLOWAT",      SOL_SOCKET,     SO_RCVLOWAT,    sock_str_int,
	        "SO_SNDLOWAT",      SOL_SOCKET,     SO_SNDLOWAT,    sock_str_int,
	        "SO_RCVTIMEO",      SOL_SOCKET,     SO_RCVTIMEO,    sock_str_timeval,
	        "SO_SNDTIMEO",      SOL_SOCKET,     SO_SNDTIMEO,    sock_str_timeval,
	        "SO_REUSEADDR",     SOL_SOCKET,     SO_REUSEADDR,   sock_str_flag,
	        "SO_TYPE",          SOL_SOCKET,     SO_TYPE,        sock_str_int,
	        "IP_TOS",           IPPROTO_IP,     IP_TOS,         sock_str_int,
	        "IP_TTL",           IPPROTO_IP,     IP_TTL,         sock_str_int,
	        "TCP_MAXSEG",       IPPROTO_TCP,TCP_MAXSEG,         sock_str_int,
	        "TCP_NODELAY",      IPPROTO_TCP,TCP_NODELAY,        sock_str_flag,
	        NULL,               0,              0,              NULL
	}; 
	struct	sock_opts	*ptr;


        if (argc != 2) {                                /*If not enaugh parameters were passed */
            fprintf(stderr,"usage: client hostname\n");
            exit(1);
        }

        if ((he=gethostbyname(argv[1])) == NULL) {      /* Host name resolution                 */
            herror("gethostbyname");
            exit(1);
        }


        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { /*Define the Internet socket,TCP*/
            perror("socket");
            exit(1);
        }

        if ((sockopt=setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) == -1) { /*Enable reuse of a socket*/
            perror("setsockopt"); 
            exit(1); 
        }



/*        if (getsockopt(sockfd, ptr->opt_level, ptr->opt_name,		*/
/*		&val, &len) == -1) {					*/
/*            perror("getsockopt error");				*/
/*	    exit(1);							*/
/*	}								*/
 
	
        their_addr.sin_family = AF_INET;                        /*Host byte order               */
        their_addr.sin_port = htons(PORT);                      /*Short, network byte order     */
        their_addr.sin_addr = *((struct in_addr *)he->h_addr);  /*Assign address of the server  */
        bzero(&(their_addr.sin_zero), 8);                       /*Zero the rest of the struct   */

        /*Connecting the server         */
	        if (connect(sockfd, (struct sockaddr *)&their_addr, \
                                              sizeof(struct sockaddr)) == -1){
			perror("connect");
       	     		exit(1);
       		 }


	while (1) {

		printf("Before \n");
		if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1) {/*Recieve infor from the server*/
			perror("recv");
			exit(1);
		}

		buf[numbytes] = '\0'; /*The info from the server has no \0 at the end of string         */
		printf("Received: %s\n",buf);
	}
                if ( shutdown(sockfd,2) == -1) {/*Recieve infor from the server*/
                        perror("Shutdown");
                        exit(1);
		printf("after \n");
                }
	
	close(sockfd);

        return 0;
    }
