/*
** UDP client program
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <proto/socket.h>

#define DEFAULT_PORT 54321
#define MAX_RETRIES 10
#define TIMEOUT_SECS 1
#define TERMINATOR "quit\n"

main ( argc, argv )
     int argc;
     char *argv[];
{
int s, retcode, done, retry, match, timeout;
long fromlen;
char recvbuffer[256], sendbuffer[256];
struct sockaddr_in addr, from;
struct servent * sp;
struct hostent * hp;
struct timeval timer;
fd_set rfds;

if ( argc != 2 ) {
    fprintf ( stderr, "Usage:\t %s host \n", argv[0]);
    exit (1);
}

/*
** Users may specify hosts in 2 different formats:
** hostnames or IP addresses (aka dotted quads).
** First try looking up the host as a hostname, and
** if that fails try as an IP address.
*/

memset(&addr, 0, sizeof(struct sockaddr_in) );
hp = gethostbyname( argv[1] );
if ( hp != NULL ) {
    addr.sin_family = hp->h_addrtype ;
    addr.sin_addr.s_addr = *((int *) hp ->h_addr);
} else {
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr( argv[1] );
    if (addr.sin_addr.s_addr == -1) {
	fprintf(stderr,"Can't lookup host %s\n",argv[1]);
	exit(1);
    }
}

/*
** Applications should get the service number from the services file.
** Try the services file first, and upon failure, use a default port
** number.  This allows the example to run without modifying the
** system environment.
*/
sp = getservbyname( "example", "udp" );
if( sp != NULL ) {
    addr.sin_port = sp->s_port;
} else {
    addr.sin_port = DEFAULT_PORT;
}

/*
** Create a socket.
*/
s = socket ( AF_INET, SOCK_DGRAM, 0 );
if ( s == -1 ) {
    perror("socket");
    exit(1);
}

/*
** Client main loop - read data from stdin, send to server.
** Server echos back data, client reads data and prints on stdout.
** User may type quit or EOF to terminate program.
** Since data may get lost, the program must be prepared to
** deal with a lost message.  This simple client uses select
** to wait for the incoming packet or a timeout.  After a
** timeout it will retransmit the packet up to MAX_RETRIES
** times before giving up.  If the program receives a packet
** that doesn't contain the expected data it is dropped.
*/

printf("Type a message, then type EOF character or quit to quit\n");
done = 0;
while (!done) {                                         /* Main Client Loop */

    if( fgets(sendbuffer, sizeof(sendbuffer), stdin) == NULL ){
	if (feof(stdin)) {
	    strcpy(sendbuffer, "quit\n");
	    fprintf(stderr,"EOF - terminating server\n");
	}
	else {
	    perror("fgets");
	    exit(1);
	}
    }
    if (!strncmp(sendbuffer, TERMINATOR, strlen(TERMINATOR))) {
	done = 1;
    }

    retry = MAX_RETRIES+1;
    match = 0;
    while(!match && retry) {                            /* Transmit Loop */
	retcode = sendto(s, sendbuffer, strlen(sendbuffer),
			    0, (struct sockaddr *)&addr, sizeof(addr));
	if(retcode < 0 ) {
	    perror("sendto");
	    exit(1);
	}

	timeout = 0;
	while(!match && !timeout) {                     /* Timeout Loop */
	    FD_ZERO(&rfds);
	    FD_SET(s, &rfds);
	    timer.tv_sec = TIMEOUT_SECS;
	    timer.tv_usec = 0;
	    retcode = select(s+1, &rfds, NULL, NULL, &timer);
	    if (retcode < 0) {
		perror("select");
		exit(1);
	    }
	    else if ( retcode == 0 ) {                  /* Timeout */
		if (--retry) {
		    fprintf(stderr,"Client Timeout, retransmitting data\n");
		    timeout = 1;
		}
		else {
		    fprintf(stderr,"Client Timeout - giving up\n");
		    exit(1);
		}
	    }
	    else {					/* Get Packet */
		fromlen = sizeof(from);
		retcode = recvfrom(s, recvbuffer, sizeof(recvbuffer),
				    0, (struct sockaddr*)&from, &fromlen);
		if ( retcode < 0 ){
		    perror("recvfrom");
		    exit(1);
		}
		recvbuffer[retcode] = 0;
		fprintf(stdout,
		   "Response from %s, port %d, length %3d, data %s",
		   inet_ntoa(from.sin_addr),from.sin_port, retcode, recvbuffer);

		if (!strcmp( sendbuffer, recvbuffer )) {/* Check Packet */
		    fputs(recvbuffer, stdout);
		    match=1;
		}
	    }
	}
    }
}
exit(0);
}
