//tcp client
// can work on unix or windows machines
// this program tests the time it takes to transfer a fixed file size by varying the packet size

#define WIN
//#define BSD



//i/o stuff
#include < stdio.h >		//printf
#include < iostream.h >	//cout
#include < fstream.h >

//misc
#include < time.h >			//clock_t, clock()


#ifdef WIN
	#include < windows.h >
	#include < malloc.h >
#else //BSD
	#include < sys/types.h >
	#include < sys/socket.h >
	#include < netinet/in.h >
	#include < arpa/inet.h >
	#include < netdb.h >
#endif


#define	MESS_SIZE	1000000	/* file size equal 1,000,000 bytes */
#define  PORTNUM      18000   /* the port # the server is listening to */
#define	REPEAT		 2
#define	MAX_PACKET_SIZE	65507   //65495 //ie. 2^16 - 1 - 20 - 20


//set time out for lost datagram
void setTimeout( int ) ;

void crunch( int socketid ) ;//crunch out numbers


/* Main ============================================================ */
void main(int argc, char *argv[] )
{
   int  port = PORTNUM;  /* the port number agrred upon server & writer */
   int server_len;       /* length for sockaddr for the server */

  int  socketid;        /* the socket ID */
   int  status;          /* error status holder */


   /* --- socket address in the Internet --- */
   struct sockaddr_in serverINETaddress;
   struct hostent *myhostent;


#ifdef WIN
	WORD		wVersionRequested = MAKEWORD( 1, 1 ) ;
	WSADATA	wsaData ;
	WSAStartup( wVersionRequested, &wsaData ) ;
#endif

cout << "clocks per sec = " << CLOCKS_PER_SEC << endl;


/* --- Get Internet address --- */
   myhostent = gethostbyname("131.247.2.16");
   server_len = sizeof(serverINETaddress);

#ifdef WIN
	memset( (char *)&serverINETaddress, 0, server_len ) ;
	memcpy( (char *)&serverINETaddress.sin_addr,
			  (char *)myhostent->h_addr,
			  myhostent->h_length ) ;
#else
	bzero((char *)&serverINETaddress, server_len);
	bcopy((char *)myhostent->h_addr,
			(char *)&serverINETaddress.sin_addr,
			myhostent->h_length);
#endif

   serverINETaddress.sin_family = AF_INET;
	serverINETaddress.sin_port = htons(port);
	/* end getting address */






/* --- Create a socket --- */
	socketid = socket( AF_INET, SOCK_STREAM, 0 ) ;
	if( socketid < 0 )
	{  
		printf("Error in creating a socket.\n") ;
		exit(-1) ;
	}



/* --- Connecting the socket --- */
	status = connect(socketid,
						  (struct sockaddr *)&serverINETaddress,
						  server_len);
	if( status < 0 )
	{
		printf("Error in connecting.\n");
		exit(-1);
	}


//set timed out to 5 seconds
	setTimeout( socketid ) ;

/* do it all */
	crunch( socketid ) ;//ie. crunch out numbers




//all done
#ifdef WIN
	closesocket( socketid ) ;
	WSACleanup() ;
#else
	close(socketid);     
#endif

}



void setTimeout( int my_s )
{
	struct timeval tv ;

	tv.tv_sec = 10000 ;//2 seconds
	tv.tv_usec = 0 ;

#ifdef WIN
	setsockopt( my_s,
					SOL_SOCKET,
					SO_RCVTIMEO,
					(char FAR *)&tv,
					sizeof( tv ) );
#else	//BSD
	setsockopt( my_s,
					SOL_SOCKET,
					SO_RCVTIMEO,
					(char *)&tv,
					sizeof( tv ) ) ;
#endif


}





void crunch( int socketid )
{
	int i, 				//loop variable
	     packet_size,	//another loop variable
		 changeable_packet,
		 buffer_left,
		 lost_packets = 0 ;//count of

	long int n ;

	long double clock_diff,
				   total_clock1,
					total_clock2 ;

	char   *sendline = new char[ MESS_SIZE ];   // Buffer for output data
	char   *recvline = new char[ MESS_SIZE + 1 ];   // Buffer for output data


	clock_t clock1, clock2;
	fstream outfile ;

cout << "size of long int = " << sizeof( long int ) << endl ;
cout << "just checking\n" << endl;
//open file
	outfile.open( "outfile_tcp.dat", ios::out ) ;  
//file header
	outfile << "packet_size" << "  " << "time( sec )\n\n" ;


//the loop
	for( packet_size=3600; packet_size<=MAX_PACKET_SIZE; packet_size+=10 )
	{	//actually, packetsize = 20 ip_header + 20 tcp_header + packet_size
	
		clock_diff	= 0 ;		//reset clocks
		for( i=0; i< REPEAT; i++ )//statistically do 5 times
		{
			
			total_clock1 = 0;//reset total to zero
			total_clock2 = 0;
			changeable_packet = packet_size ;

			buffer_left = MESS_SIZE ;//will decrease buffer size in do loop
			do
			{

				clock1 = clock() ;//start timer

				send( socketid,	//in sendto, 28, ie 20 + 8, more bytes will be added
						sendline,
						changeable_packet,
						0 ) ;
		

				n =  recv( socketid,	//receive acknowledgement
						recvline,
						changeable_packet + 1,
						0 ) ;
//cout << "n = " << n << endl ;
				clock2 = clock() ;//end timer

				if( n<0 )//timed out, resend packet
				{
					cout << "timeout" << endl;
					cout << "resending packet " << packet_size << endl;
				
					//for fun, count number of lost packets
					lost_packets++ ;

					//go back to beginning of do loop
					continue ;
				}



				total_clock1 += (double)clock1 ;
				total_clock2 += (double)clock2 ;
		
				buffer_left -= packet_size ;//decrease buffer size
				
				if( buffer_left < packet_size )//update packet
					changeable_packet = buffer_left ;

			}while( buffer_left > 0 ) ;

			
			//add up 5 times then divide by 5 to get average
			clock_diff = clock_diff +( total_clock2 - total_clock1 );
		}//end sampling five times
		

		//output to screen
		cout	<< endl 
				<< "packet_size = " << packet_size
				<< "  diff in clocks in secs = " << clock_diff / (REPEAT*CLOCKS_PER_SEC)
				<< "  packets returned = " << n 				
				<< endl ;
		
		//output to file
		outfile	<< packet_size << "  " 
					<< clock_diff/(REPEAT*CLOCKS_PER_SEC) << "\n" ;
		
	}//end for loop

	cout << "total lost packets... " << lost_packets << endl ;	

	outfile.close() ;
	delete [] sendline ;
	delete [] recvline ;
}