/*
 *      Module Name: TCPrecv.c
 *          Version: 1.0
 *    Original Date: 12/03/98
 *           Author: Paul Jacobson
 *         Language: Cygwin GNU C
 *  Compile Options:
 *  Compile Defines:
 *        Libraries: 
 *     Link Options: 
 *
 *     Entry Points: main()
 * 		             
 *
 *
 *  Description.
 *  =====================================================================
 *	This module contains the test code for TCP/IP evaluation.  This module will
 *  transmit n TCP datagrams of size m bytes at a TCP server.
 *
 *  Edit    Date/Ver    Edit Description
 *  ================    ====================================================
 *          
 *	Copyright (C) 1998 by Digital Products, Inc.
 *	All Rights Reserved.
 *
 */
#include <stdio.h>
#include <stdlib.h>

#ifdef WIN32
#include "signal.h"
#include "winsock2.h"
#else
#include <sys/signal.h>
#include <socket.h>
#include <if.h>
#include <in.h>
#include <sys/times.h>
#include <unistd.h>
#include <arpa/inet.h>  /* 06/10/03 */
#endif

#include <string.h>
#include <errno.h>
#include <time.h>

#define DATA_BUFFER_SIZE    20000

char rcvData[DATA_BUFFER_SIZE];

#define cntFname "cnt.dat"

unsigned int updateCnt(const char *fname);

void logTest(const char *fname, 
                     unsigned int cnt,
                     const char *host, 
                     int bytes, 
                     int msec, 
                     struct tm *lt);


/*------------------------------------------------------------------------
 * TCPrecv - send a bunch of data  
 *------------------------------------------------------------------------
 */

int TCPrecv(const char *host, int szSegment, int szData, char *log_fname)
{
	int	                sock;               /* socket descriptor    */
    unsigned long       addrServer;
	struct sockaddr_in  fsin;               /* Internet endpoint address	*/
    int                 szTransfer, result;
#ifdef WIN32
    unsigned long       start, stop;
    WSADATA             wsaData;
    int                 Ret;
#else
    clock_t              start, stop;    
    struct tms          notusedTms;
#endif
    char                command[64];
    unsigned int        test_cnt;
    struct fd_set       rfds;
    time_t t;
    struct tm *lt;
    
#ifdef WIN32

   // Initialize Winsock version 2.2

   if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
   {
      // NOTE: Since Winsock failed to load we cannot use WSAGetLastError 
      // to determine the error code as is normally done when a Winsock 
      // API fails. We have to report the return status of the function.

      printf("WSAStartup failed with error %d\n", Ret);
      exit(1);
   }
#endif

    /*  open the datagram socket    */
	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock < 0)
    {
        printf("socket failure: errno: %d\n", errno);
#ifdef WIN32
        WSACleanup();
#endif
        exit(1);
    }

    /*  Convert the host address    */
    addrServer  = inet_addr((const char *)host);

    /*  setup the sock address in */
    memset((void *)&fsin, 0, sizeof(fsin));
    fsin.sin_family        = AF_INET;
    fsin.sin_addr.s_addr   = addrServer;
    fsin.sin_port          = htons(7777);
    result = connect(sock, (struct sockaddr *)&fsin, sizeof(fsin));
    if (result < 0)
   	{
        printf("connect failure: errno: %d\n", errno);
#ifdef WIN32
        WSACleanup();
#endif
        exit(1);
    }

    /*  setup the poll  */
    FD_ZERO((struct fd_set *)&rfds);
    #ifdef WIN32
    FD_SET((SOCKET)sock, (struct fd_set *)&rfds);
    #else
    FD_SET(sock, (struct fd_set *)&rfds);
    #endif

    /*  generate the command string */
    sprintf (command, "T %d %d\r\n", szData, szSegment);
    result = send (sock, command, strlen(command), 0);
    if (result < 0)
    {
        printf("send(%d,,%d,0) failed: %d\n", sock, szData, errno );
#ifdef WIN32
        WSACleanup();
#endif
        exit(1);
    }

    select (sock+1, (struct fd_set *)&rfds, NULL, NULL, NULL);

    /*  Record the start time   */
#ifdef WIN32
    start       = GetCurrentTime();
#else
    start       = times(&notusedTms);
#endif
    szTransfer  = 0;

    /*  Send the data   */
    do
    {
        result = recv(sock, (char *)rcvData, DATA_BUFFER_SIZE, 0);
        if (result < 0)
        {
            printf("recv(%d,,%d,0) failed: %d\n", sock, DATA_BUFFER_SIZE, errno );
#ifdef WIN32
            WSACleanup();
#endif
            exit(1);
        }
        szTransfer += result;
    }
    while ((szTransfer < szData) && (result > 0));

    /*  record the stop time    */
#ifdef WIN32
    stop = GetCurrentTime();
    closesocket (sock);

    printf ("TCPrecv: %d bytes %d msec", szTransfer, (int)(((stop - start))));

    if ((int)(stop - start))
    {
        printf (" [%ld kbps]", szTransfer/(((stop - start))));
    }
#else
    stop = times(&notusedTms);
    close (sock);

    printf ("TCPrecv: %d bytes %d msec", szTransfer, (int)((1000* (stop - start))/sysconf(_SC_CLK_TCK)));

    if ((int)(stop - start))
    {
        printf (" [%ld kbps]", szTransfer/((1000* (stop - start))/sysconf(_SC_CLK_TCK)));
    }
#endif

    t  = time(&t);
    lt = localtime(&t);

    printf (", %2d:%02d.%02d %2d/%02d/%d.\n", lt->tm_hour, lt->tm_min, lt->tm_sec, lt->tm_mday, 
                    lt->tm_mon + 1, 1900 + lt->tm_year);

    if (log_fname)
    {
        test_cnt = updateCnt(cntFname);
        logTest(log_fname, test_cnt, host, szTransfer, stop - start, lt);
    }
    printf("\n");

	Sleep(1000);

#ifdef WIN32
    WSACleanup();
#endif

    return 0;
}


/*  main - TCP client    */
int main(int argc, char *argv[])
{
	char	*host = "199.92.186.198";	/* host to use if none supplied	*/
    char    *szData = "10000";
    int     iszData;
    char    *log_fname = NULL;

    if (argc > 4)
        argc = 4;

	switch (argc) 
    {
    case 4:
        log_fname = argv[3];
	case 3:
		host = argv[2];
    case 2:
		szData = argv[1];
        iszData = atoi(szData);

        /*  Use atleast 2 K bytes    */
        if (iszData < 2000)
        {
            printf("I'm going to request at least 2000 bytes.\n");
            iszData = 2000;
        }

        printf ("TCPrecv: Request %d bytes from %s.\n", iszData, host);

       	TCPrecv(host, 0, iszData, log_fname);
        break;

	case 1:
	default:
        fprintf(stderr, "usage: TCPrecv [<Bytes of data to receive> [<Server ip address> [<Log file name>]]]\n");
        getchar();
		exit(1);
	}
    
    return 0;
}

unsigned int updateCnt(const char *fname)
{
	unsigned int cnt = 0;

	FILE * f = fopen(fname, "rb");

	if (f)
	{
        fread (&cnt, sizeof cnt, 1, f); 
		fclose(f);
	}

	cnt++;
	printf("CNT = %u\n",cnt);

	f = fopen( fname, "wb");
	if (f)
	{
	    fwrite (&cnt, sizeof cnt, 1, f); 
	    fclose(f);
    }

    return cnt;
}

void logTest(const char *fname, 
                     unsigned int cnt,
                     const char *host, 
                     int bytes, 
                     int msec, 
                     struct tm *lt)
{

    FILE * f;

    f = fopen(fname, "a");
    if (f)
    {
        if (msec)
        {
            fprintf(f, "%4d  TCPrecv: Recv %d bytes from %s, %d msec, [%d kbps], %2d:%02d.%02d %2d/%02d/%d\n", 
                    cnt, bytes, host, msec, bytes/msec, lt->tm_hour, lt->tm_min, lt->tm_sec, lt->tm_mday, 
                    lt->tm_mon + 1, 1900 + lt->tm_year);
        }
        else
        {
            fprintf(f, "%4d  TCPrecv: Recv Send %d bytes from %s, %2d:%02d.%02d %2d/%02d/%d\n", 
                    cnt, bytes, host, lt->tm_hour, lt->tm_min, lt->tm_sec, lt->tm_mday, 
                    lt->tm_mon + 1, 1900 + lt->tm_year);
        }
 
        fclose(f);
    }
}
