/*
 * megtest.c
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1996,1991  Arizona Board of Regents
 *
 * $Revision: 1.7 $
 * $Date: 1997/06/26 06:56:39 $
 */

#define PROT_STRING "meg"

#include "xkernel.h"
#include "tcp.h"
#include "ip.h"
/* #include "site.h" */
#include "tcp_internal.h"
#include "xsim.h"

#include "xkernel.h"
#ifndef XKMACHKERNEL
#include "x_stdio.h"
#else
#include "assert.h"
#endif ! XKMACHKERNEL

#define MAX_INSTANCES 2000
#define TIMES 1
#define LENGTH 1000*1024
#define BUFFER_SIZE 50 * 1024
#define DROP_INTERVAL 0 
#define DIS_INTERVAL 0 

static  IPhost ServerAddr = {0,0,0,0};
static  IPhost ClientAddr = {0,0,0,0};

typedef struct tcpVars {
    IPhost    myHost;
    Protl     myProtl;
    Sessn     clientDownSes;
    XTime     starttime0, starttime;
    XTime     total0, total, condelay;
    int       serverParam;
    int       clientParam;
    char      *serverString; 
    IPhost    serverAddr;
    IPhost    clientAddr;
    Semaphore s;
    int       dbId;
    int       space;
    int       length;
    int       maxPacket;
    int       usePacketArg;
    int       thresh;
    int       mytrace;
    int       delay;
    long       runTime; /* VENKAT */
    int       doneFlag;
    int       endRunFlag;
    int       showTime; 
    int       tripDelay;
    long      serverPort;
    long      clientPort;
    long      reset;
    int       foundMyAddr;
    char      *hostStr;
    char      *dbName;
    char      *llpName;
    int       serverRcvDup;
    int       serverSaveTrace;
    int       killTraffic;
    float     bw, bw0;
    char      *dbStr[10];
    int       dbStrCnt;
    int       trips;
    int       tcpVals[15];
    int       rlen, plen, rtime;
    char      timeArray[30];
    Msg       m, savedMsg;
} tcpVars;

tcpVars *VarsArray[MAX_INSTANCES];
int     VarsArrayN = 0;
int     tracemegtestp;
char    *TcpProtls[] = {"void", "ttcp", "rtcp", "vtcp", "btcp", "void"};

#ifdef __STDC__

static void     client(Event, void *);
static void     server(Event, void *);
static void     endTest( Event, void * );
static void     reset( Event, void * );
static void     saveStats( tcpVars * );
static void     subtime( XTime *, XTime *, XTime *);
static void     processOptions(tcpVars *);
static int      isServer(tcpVars *);
static int      isClient(tcpVars *);
static void     clientSetPart(tcpVars *, Part *);
static void     serverSetPart(tcpVars *, Part *);
static XkReturn closeDone(Sessn);
static XkReturn saveServerSessn(Protl, Protl, Sessn, Protl);
static int      runTest(tcpVars *);
static XkReturn serverDemux(Protl,Sessn,Msg *);
static XkReturn clientDemux(Protl,Sessn,Msg *);
int megtest_init(Protl);

#else

static void     client();
static void     server();
static void     endTest();
static  void    reset();
static void     saveStats();
static void     subtime();
static void     processOptions();
static int      isServer();
static int      isClient();
static void     clientSetPart();
static void     serverSetPart();
static XkReturn closeDone();
static XkReturn saveServerSessn();
static int      runTest();
static XkReturn serverDemux();
static XkReturn clientDemux();
int megtest_init();

#endif __STDC__

#ifdef XNETSIM
extern int xsimBegTest();
extern int xsimEndTest();
#endif

extern  int Yield(void);

#ifdef XKMACHKERNEL
static int
sscanf1(str, format, a1)
char *str, format;
int *a1;
{
    int n;

    *a1 = 0;
    while (*str >= '0' && *str <= '9')
        *a1 = 10*(*a1) + (*str++ - '0');
    return 1;
}
#else
#define sscanf1 sscanf
#endif XKMACHKERNEL

#ifdef __STDC__
#define DOUBLEQUOTEWRAP(x) #x
#define STRINGIFY(z) DOUBLEQUOTEWRAP(z)
#endif

#ifdef XNETSIM
extern int  xsimArgc;
extern char **xsimArgv;
extern void endTraffic( Event, VOID *);
extern void *ClientTrafficPS[20];
extern int  ClientTrafficPSCnt;
#endif

static
unsigned long getTime(char *cp, int defs)
{
    unsigned long d = 0, dc = 1, t, s = defs;

    sscanf(cp, "%ld", &t);
    while(isdigit(*cp))
        cp++;
    if (*cp == '.')
        while (isdigit(*cp))
            d = d*10 + (*cp++ - '0'), dc *= 10;
    if (*cp == 'm' && *(cp+1) != 'i')
        s = 1000;
    else if (*cp == 'u')
        s = 1;
    else if (*cp == 's')
        s = 1000000;
    else if (*cp == 'm'  &&  *(cp+1) == 'i')
        s = 60000000;
    t = t*s + d*s/dc;
    return t;
}

static void
showTime(ev, foo)
Event ev;
VOID  *foo;
{
    XTime   now;
    int     sec, msec;
    tcpVars *v = (tcpVars *)foo;

    xGetTime(&now);
    sec = now.sec + now.usec/1000000;
    msec = now.usec/1000;
    printf("[megtest] time: %d.%03d\n", sec , msec);
    evDetach( evSchedule(showTime, (void *)v, v->showTime*1000) );
}

static void
processOptions(v)
tcpVars *v;
{
    int    i, k = -1, foundMyAddr = 0, foundAllAddr = 0;
    char   *arg, *hostStr, str[100];
/*  IPhost host; */
    
#define argPrefix(str) (! strncmp(arg, str, strlen(str)))
#define argEq(str) (! strcmp(arg, str) )

    sprintf(str, "%s/%s", v->myProtl->name, v->myProtl->instName);

#ifndef XNETSIM
    foundMyAddr = 1;
#else
    v->hostStr = hostStr = v->myProtl->instName;
    for (i = 0; i < xsimArgc; i++) {
        arg = xsimArgv[i];
    
        if (argEq("-s"))
            v->serverParam = 1;
        else if (argPrefix("-c")) {
            v->clientParam = 1;
            v->serverString = arg + 2;
        }
        else if (argEq("-killTraffic"))
            v->killTraffic = 1;
        else if (argEq("-serverSaveTrace")) 
	    v->serverSaveTrace = 1;
	else if (argPrefix("-serverPort=")) 
	    sscanf(arg+12, "%ld", &v->serverPort);
	else if (argPrefix("-tcpTime=")) 
	    v->runTime = getTime(arg+9, 1000000);
	else if (argPrefix("-megTime=")) 
	    v->runTime = getTime(arg+9, 1000000);
	else if (argPrefix("-len=")) {
            sscanf(arg+5, "%d", &k);
            if (k > 0)
                v->length = k*1024;
        }
        else if (argPrefix("-trips="))
            sscanf1(arg + strlen("-trips="), "%d", &v->trips);
        else if (argPrefix("-buf=")) {
            sscanf(arg+5, "%d", &k);
            if (k > 0)
	        v->space = k*1024;
        }
	else if (argPrefix("-dbId=")) 
	    sscanf(arg+6, "%d", &v->dbId);
	else if (argPrefix("-megReset=")) 
	    v->reset = getTime(arg+10, 1000000);
	else if (argPrefix("-delay=")) 
	    v->delay = getTime(arg+7, 1000);
	else if (argPrefix("-tripDelay=") ) 
	    v->tripDelay = getTime(arg+11, 1000);
	else if (argPrefix("-thresh=")) {
            sscanf(arg+strlen("-thresh="), "%d", &v->thresh);
            v->thresh *= 1024;
        }
	else if (argPrefix("-usePacket="))
	    sscanf(arg+strlen("-usePacket="), "%d", &v->usePacketArg);
	else if (argPrefix("-tcpPacket=") && v->usePacketArg == 0)
	    sscanf(arg+strlen("-tcpPacket="), "%d", &v->usePacketArg);
        else if (argPrefix("-dbStr="))
            v->dbStr[v->dbStrCnt++] = arg + 7;  
        else if (argPrefix("-dbStr2="))
            v->dbStr[v->dbStrCnt++] = arg + 8;
        else if (argPrefix("-dbStr3="))
            v->dbStr[v->dbStrCnt++] = arg + 8;
        else if (argPrefix("-db="))
            v->dbName = arg + 4;
        else if (argPrefix("-showTime="))
            sscanf(arg+strlen("-showTime="), "%d", &v->showTime);
    }
  
#endif XNETSIM

    for (i = 1; i < globalArgc; i++) {
        arg = globalArgv[i];
    
        if (argEq("-all")) {
            foundAllAddr = 1;
            continue;
        }
        else if (argEq("-N")) {
            foundAllAddr = 0;
            if (foundMyAddr)
	        break; 
            arg = globalArgv[++i];
            if (strcmp(str, arg)) {
	        i++;
	        continue;
            }     
/*          arg = globalArgv[++i]; */
/*          str2ipHost(&host, arg); */
/*          v->myHost = host; */
            foundMyAddr = 1;
/*          v->hostStr = hostStr = arg; */
/*          xsimDbg(TMG_FLAG, */
/* 	    printf("[%s] %s found my address\n", hostStr, str)); */
            continue; 
        }
        else if (!foundMyAddr && !foundAllAddr)
            continue;
        else if (argEq("-s"))
            v->serverParam = 1;
        else if (argEq("-killTraffic"))
            v->killTraffic = 1;
        else if (argPrefix("-c")) {
            v->clientParam = 1;
            v->serverString = arg + 2;
        }
        else if (argPrefix("-len=")) {
            sscanf(arg+5, "%d", &k);
            if (k > 0)
	        v->length = k*1024;
        }
        else if (argPrefix("-trips="))
            sscanf1(arg + strlen("-trips="), "%d", &v->trips);
        else if (argPrefix("-buf=")) {
            sscanf(arg+5, "%d", &k);
            if (k > 0)
	        v->space = k*1024;
        }
        else if (argPrefix("-delay=")) {
            sscanf(arg+7, "%d", &k);
            if (k > 0)
	        v->delay = k;
        }
        else if (argPrefix("-thresh=")) {
            sscanf(arg+strlen("-thresh="), "%d", &v->thresh);
            v->thresh *= 1024;
        }
        else if (argPrefix("-dbStr="))
            v->dbStr[v->dbStrCnt++] = arg + 7;
        else if (argPrefix("-dbStr2="))
            v->dbStr[v->dbStrCnt++] = arg + 8;
        else if (argPrefix("-dbStr3="))
            v->dbStr[v->dbStrCnt++] = arg + 8;
        else if (argPrefix("-db="))
            v->dbName = arg + 4;
    }
  
#undef argPrefix
#undef argEq
}

int
megtest_init( self )
Protl self;
{
    Protl   llp;
    int     k;
    tcpVars *v;

    v = (tcpVars *)xMallocZero(sizeof(tcpVars));
    if (VarsArrayN >= MAX_INSTANCES)
        Kabort("Too many instances of megtest protocol!");
    VarsArray[VarsArrayN++] = v;
#ifndef XNETSIM    
    {
	time_t begTime;

        time(&begTime);
        strcpy(v->timeArray, ctime(&begTime));
    }
#endif
    v->serverParam = 0;
    v->clientParam = 0;
    v->serverAddr = ServerAddr;
    v->clientAddr = ClientAddr;
    v->space = BUFFER_SIZE;
    v->dbId = 0;
    v->length = LENGTH;
    v->mytrace = 0;
    v->delay = 0;
    v->reset = 0;
    for (k = 0; k < 15; k++)
        v->tcpVals[k] = 0;
    v->serverPort = 2001;
    v->clientPort = ANY_PORT;
    v->foundMyAddr = 0;
    v->serverSaveTrace = 1;
    v->hostStr = "?????";
    v->killTraffic = 0; 
    v->thresh = 0;
    v->runTime = 0;
    v->doneFlag = 0;
    v->endRunFlag = 0;
    v->usePacketArg = 0;
    v->showTime = 0;
    v->dbName = NULL;
    v->dbStrCnt = 0;
    v->trips = 1;
    v->tripDelay = 0;
    v->myProtl = self;
    v->rlen = v->plen = v->rtime = 0;

    processOptions(v);

    if (v->thresh == 0)
        v->thresh =  v->space/2 ;

    llp = xGetProtlDown(self, 0);
    if (!xIsProtl(llp))
	Kabort("Test protocol has no lower protocol");
    v->llpName = llp->name;
/*  xControlProtl(xGetProtlDown(self, 0), GETMYHOST, (char *)&v->myHost, */
/*		  sizeof(IPhost)); */
    if (xControlProtl(xGetProtlDown(self, 0), GETMYHOST, (char *)&v->myHost,
                      sizeof(IPhost)) < 0)
        Kabort("GETMYHOST fails! in megtest\n");
    xsimDbg(TMG_FLAG, printf("[%s] %s found my address\n", v->hostStr,
			     self->name, self->instName));

    printf("[%s] %s timing test\n", v->hostStr, PROT_STRING);
    /* 
     * Call the per-test initialization function which gives the test
     * the opportunity to override the default functions
     */
    if (v->showTime > 0)
        evDetach( evSchedule(showTime, (void *)v, v->showTime*1000) );
    if (isServer(v)) {
#ifdef XNETSIM
        xsimBegTest();
#endif
        evDetach( evSchedule(server, (void *)v, 0) );
    }
    else if (isClient(v)) {
#ifdef XNETSIM
        xsimBegTest();
#endif
        evDetach( evSchedule(client, (void *)v, v->delay) );
        if (v->runTime > 0)
            evDetach(evSchedule(endTest, (void *)v, v->runTime));
	if (v->reset > 0)
	    evDetach( evSchedule(reset, (void *)v, v->reset) );
    }
    else
        printf("[%s] %stest: I am neither server nor client\n", 
	       v->hostStr, PROT_STRING);
    return 0;
}

static int
isServer(v)
tcpVars *v;
{
    if (v->serverParam)
	return TRUE;
    return !bcmp((char *)&v->myHost, (char *)&v->serverAddr, sizeof(IPhost));
}

static int
isClient(v)
tcpVars *v;
{
    if (v->clientParam) {
	str2ipHost(&v->serverAddr, v->serverString);
	v->clientAddr = v->myHost;
	return TRUE;
    }
    return !bcmp((char *)&v->myHost, (char *)&v->clientAddr, sizeof(IPhost));
}

static void
clientSetPart(v, p)
tcpVars *v;
Part    *p;
{
    partInit(p, 1);
    partPush(p[0], &v->serverAddr, sizeof(IPhost));
    partPush(p[0], &v->serverPort, sizeof(long));
    printf("[%s] Client sending to: %s\n",
	   v->hostStr, ipHostStr(&v->serverAddr));
}

static void
serverSetPart(v, p)
tcpVars *v;
Part    *p;
{
    partInit(p, 1);
    partPush(*p, ANY_HOST, 0);
    partPush(*p, &v->serverPort, sizeof(long));
    printf("[%s] Server responding to: %s\n", v->hostStr, "ANY_HOST");
}

tcpVars *getMyVars(self)
Protl self;
{
    char str[100];
    int  k;

    for (k = 0; k < VarsArrayN; k++) {
        if (self == VarsArray[k]->myProtl)
            return VarsArray[k];
    } 
    sprintf(str, "getMyVars fails for Protl: %x\n", self);
    Kabort(str);
    return NULL;  
}           

static XkReturn
closeDone(lls)
Sessn lls;
{
    xTrace2(prottest, TR_MAJOR_EVENTS, "%s test -- closedone (%x) called",
	    "meg", lls);
    return XK_SUCCESS;
}

#ifdef __STDC__
static XkReturn saveServerSessn(Protl, Protl, Sessn, Protl);
#endif

static XkReturn
saveServerSessn( self, llp, s, hlpType )
Protl self, llp, hlpType;
Sessn s;
{
    tcpVars *v;

    v = getMyVars(self);
    xTrace1(prottest, TR_MAJOR_EVENTS,
	    "%stest program duplicates lower server session",
	    PROT_STRING);

    xDuplicate(s);

    if (xControlSessn(s, TCP_SETRCVBUFSIZE, (char*)&v->space,
		      sizeof(v->space)) < 0) {
        xError("saveServerSessn: TCP_SETRCVBUFSIZE failed");
    }

    if (xControlSessn(s, TCP_SETSNDBUFSIZE, (char*)&v->space,
		      sizeof(v->space)) < 0) {
        xError("saveServerSessn: TCP_SETSNDBUFSIZE failed");
    }

    if (xControlSessn(s, TCP_SETRCVBUFSPACE, (char*)&v->space,
		      sizeof(v->space)) < 0) {
        xError("saveServerSessn: TCP_SETRCVBUFSPACE failed");
    }

    return XK_SUCCESS;
}

static void
server(ev, foo)
Event ev;
VOID  *foo;
{
    Part    p;
    tcpVars *v = (tcpVars *)foo;
  
    printf("\n*** I am the server\n");/* Don't change (LSB) */
    printf("[%s] buffer size: %d\n", v->hostStr, v->space);
    v->myProtl->demux = serverDemux;
    v->myProtl->opendone = saveServerSessn;
    v->myProtl->closedone = closeDone;
    serverSetPart(v, &p);

     if (xControlProtl(xGetProtlDown(v->myProtl, 0), TCP_SETRCVBUFSIZE,
		      (char*)&v->space, sizeof(v->space)) < 0) {
        xError("server : TCP_SETRCVBUFSIZE failed");
    }

    if (xOpenEnable(v->myProtl, v->myProtl, xGetProtlDown(v->myProtl, 0), &p)
        == XK_FAILURE) {
        printf("[%s] %stest server can't openenable lower protocol\n",
	       v->hostStr, PROT_STRING);
    }
    else
        printf("[%s] %stest server done with xopenenable\n", 
	       v->hostStr, PROT_STRING);
}

void
wakeSem(ev, foo)
Event ev;
VOID  *foo;
{
    tcpVars *v = (tcpVars *)foo;
    semSignal(&v->s);
}

static void
reset(Event ev, VOID *foo)
{
    tcpVars *v=(tcpVars *)foo;

    if (v->clientDownSes == NULL)
        Kabort("clientDownSes == NULL in reset");
    if (xControlSessn(v->clientDownSes, TCP_GETINFO,
                      (char *)v->tcpVals,sizeof(int)*15) < 0)
        Kabort("TCP_GETINFO fails in client!\n");
}

void
endTest(ev, foo)
Event ev;
VOID  *foo;
{  
    char    str[100]; 
    int     k, vals[15], totalBytes;
    XTime   now;
    tcpVars *v = (tcpVars *)foo;

    if (v->doneFlag)
        return;
    v->endRunFlag = 1;
    if (v->clientDownSes == NULL) {  /* Connection never got established! */
#ifndef XNETSIM
        Kabort(str); 
#else      
        printf("%s\n", str);
        if (v->killTraffic) {
            for (k = 0; k < ClientTrafficPSCnt; k++)
                evDetach( evSchedule(endTraffic, ClientTrafficPS[k], 0) );
        }
        xsimEndTest();
	/* xsimEndTest();  /* For server side! */
#endif
        return;
    }
    subtime(&v->starttime0, &v->starttime, &v->condelay);
    xGetTime(&now); 
    sprintf(str, "%s-%s", v->myProtl->name, v->myProtl->instName);
    if (v->reset &&  v->reset < (now.sec*1000000 + now.usec)) {
        v->starttime.sec = v->starttime0.sec = v->reset/1000000;
        v->starttime.usec = v->starttime0.usec = v->reset%1000000;
    }
    subtime(&v->starttime, &now, &v->total);
    subtime(&v->starttime0, &now, &v->total0);
    if (xControlSessn(v->clientDownSes, TCP_GETINFO, (char *)vals,
		      sizeof(int)*11) < 0)
        Kabort("TCP_GETINFO fails in client!\n");
  
    for (k = 1; k < 15; k++) {
        if (k == 9)
            continue;
        vals[k] -= v->tcpVals[k];
    }
    totalBytes = vals[8];
    v->bw = totalBytes/1024/(v->total.sec+v->total.usec/1000000.0);
    v->bw0 = totalBytes/1024/(v->total0.sec+v->total0.usec/1000000.0);
    printf("Total time %ld\n",v->total0.sec+v->total0.usec/1000000.0);
    printf("[%s] len=%4dKB, 1 trip @ %ld.%02ld (%ld.%02ld) %dKB, bw %.1fKB/s %.3f (%.1f, %.3f)\n",
           v->hostStr, totalBytes/1024, v->total0.sec, v->total0.usec/10000,
           v->total.sec, v->total.usec/10000, totalBytes/1024,
           v->bw0, v->bw0*1024*8/1e6,v->bw, v->bw*1024*8/1e6);

    saveStats(v);
    xsimEndTest(); /* for server side!, client side done in saveStats */
}   
    
static void
saveStats(v)
tcpVars *v;
{ 
    char  str[100], buf[4000], *cp;
    int   vals[15], id = 0, k;
    FILE  *fout, *fin;

    vals[9] = vals[10] = vals[11] = 0;
    if (xControlSessn(v->clientDownSes, TCP_GETINFO, (char *)vals,
		      sizeof(int)*11) < 0)
        Kabort("TCP_GETINFO fails in client!\n");
    for (k = 1; k < 15; k++) {
        if (k == 9)
            continue;
        vals[k] -= v->tcpVals[k];
    }
    printf("[%s] condelay:         %ld.%03ld\n", v->hostStr, v->condelay.sec,
           v->condelay.usec/1000);
    printf("[%s] Protocol:%s, version:%d\n", v->hostStr, TcpProtls[vals[0]>>8],
           vals[0]&0xff); 
    printf("[%s] REXMT timeouts:%d\n", v->hostStr, vals[1]);
    printf("[%s]       largest timeout:%d\n", v->hostStr, vals[9]);
    printf("[%s] KB sent:       %d\n", v->hostStr, vals[8]/1024);
    printf("[%s] KB rexmtd:     %d\n", v->hostStr, vals[3]/1024);
    printf("[%s] KB rcvd dup:   %d\n", v->hostStr, vals[4]/1024);
    printf("[%s] KB rcvd dup os:%d\n", v->hostStr, v->serverRcvDup/1024);
    printf("[%s] Fine grained TOs (dup, worry): %d, %d\n", v->hostStr,
           vals[10], vals[11]);
    sprintf(buf, "[%s %s] Runtime: %ld.%03ld, condelay: %ld.%03ld, bw: %.1fKB/s\n",
            v->hostStr, v->llpName, v->total0.sec, v->total0.usec/1000,
            v->condelay.sec, v->condelay.usec/1000, v->bw0);
    sprintf(buf + strlen(buf), "REXMT timeouts:%4d\n", vals[1]);
/*  for (k = 0; k < v->dbStrCnt; k++)
        sprintf(buf + strlen(buf), "%s  ", v->dbStr[k]);
    if (k > 0)
        sprintf(buf + strlen(buf), "\n");
*/
    sprintf(buf + strlen(buf), "KB rexmtd:     %4d\n", vals[3]/1024);
    sprintf(buf + strlen(buf), "KB rcvd dup:   %4d\n", vals[4]/1024);

    if (v->dbName) {
	if (v->dbId != 0)
	    id = v->dbId;
	else if ((fin = fopen("idFile", "r")) != NULL) {
            fscanf(fin, "%d", &id); 
            fclose(fin);
        }
        if ((fout = fopen(v->dbName, "a")) == NULL)
            printf("Could not open db file: %s\n", v->dbName);
        else {
            fprintf(fout, "%%\n+++++\n%%\nProtocol: %s\nType: %d\n",
                    TcpProtls[vals[0]>>8], vals[0]&0xff);
            fprintf(fout, "id: %d\n", id);
  
#ifdef XNETSIM
            fprintf(fout, "Host: %s\n", v->myProtl->instName);
            fprintf(fout, "Path: xsim\n");
#else
            cp = v->timeArray;
            fprintf(fout, "Date: %c%c%c %c%c %c%c\n", cp[4], cp[5], cp[6],
                    cp[8], cp[9], cp[22], cp[23]);
            fprintf(fout, "Dow: %c%c%c\n", cp[0], cp[1], cp[2]);
            fprintf(fout, "Time: %c%c%c%c%c\n", cp[11], cp[12], cp[13], cp[14],
                    cp[15]);
#endif
            fprintf(fout, "buf size: %d\n", v->space/1024);
            fprintf(fout, "KB sent: %d\n", vals[8]/1024);
            fprintf(fout, "KB resent: %d\n", vals[3]/1024);
            fprintf(fout, "KB dup os: %d\n", v->serverRcvDup/1024);
    
            for (k = 0; k < v->dbStrCnt; k++)
                fprintf(fout, "%s\n", v->dbStr[k]);
            fprintf(fout, "timeouts: %d\n", vals[1]);
	    fprintf(fout, "largeto: %d\n", vals[9]);
            fprintf(fout, "dup to: %d\n", vals[10]);
            fprintf(fout, "worry to: %d\n", vals[11]);
            fprintf(fout, "T KB/S: %.1f\n", v->bw0);
            fprintf(fout, "runtime: %ld.%03ld\n", v->total0.sec,
		    v->total0.usec/1000);
	    fprintf(fout, "condelay: %ld.%03ld\n", v->condelay.sec,
	            v->condelay.usec/1000);
	    fprintf(fout, "rundelay: %d\n", v->delay/1000);
            fclose(fout); 
        }
    }   
    if (xControlSessn(v->clientDownSes, TCP_DUMPTRACE, buf, strlen(buf)+1) < 0)
        Kabort("TCP_DUMPTRACE fails in client!\n");
    if (!v->doneFlag) 
        xClose(v->clientDownSes);
    v->clientDownSes = NULL;
    v->doneFlag = 1;
    sprintf(str, "[%s] ***** End of test (client)  *****", v->hostStr);
#ifndef XNETSIM
    Kabort(str);
#else 
    printf("%s\n", str);
    if (v->killTraffic) { 
        for (k = 0; k < ClientTrafficPSCnt; k++)
            evDetach( evSchedule(endTraffic, ClientTrafficPS[k], 0) );
    }
    xsimEndTest();
#endif
}     
      
static void
client(ev, foo)
Event ev;
VOID  *foo;
{
    char    str[100];
    Part    p[2];
    tcpVars *v = (tcpVars *)foo;
  
    printf("\n*** I am the client\n");
    printf("[%s] *** buffer size: %d\n", v->hostStr, v->space);
  
    if (!strcmp(v->hostStr, "h1n37_1"))
        printf("I'm there!\n");
    v->myProtl->demux = clientDemux;
    semInit(&v->s,0);
    
    clientSetPart(v, p);
    xGetTime(&v->starttime0);
    if (v->clientDownSes == 0) {
/*      if (xControlProtl(v->myProtl, TCP_SETRCVBUFSIZE, (char*)&v->space,
                          sizeof(v->space)) < 0) {
            sprintf(str, "[%s] client: TCP_SETRCVBUFSIZE for prot failed",
		    v->hostStr);
            xError(str);
        } 
*/
        v->clientDownSes = xOpen(v->myProtl, v->myProtl, 
			         xGetProtlDown(v->myProtl, 0), p);
        if (v->clientDownSes == ERR_SESSN) {
            printf("[%s] %stest: open failed!\n", v->hostStr, PROT_STRING);
            Kabort("End of test");
            return;
        }
    }
  
    if (xControlSessn(v->clientDownSes, TCP_SETTHRESH, (char*)&v->thresh,
                      sizeof(v->thresh)) < 0) {
        sprintf(str, "[%s] client: TCP_SETTHRESH failed", v->hostStr);
        xError(str);
    }

    if (xControlSessn(v->clientDownSes, TCP_SETRCVBUFSIZE, (char*)&v->space, 
	              sizeof(v->space)) < 0) {
        sprintf(str, "[%s] client: TCP_SETRCVBUFSIZE failed", v->hostStr);
        xError(str);
    }

    if (xControlSessn(v->clientDownSes, TCP_SETSNDBUFSIZE, (char*)&v->space, 
	              sizeof(v->space)) < 0) {
        sprintf(str, "[%s] client: TCP_SETSNDBUFSIZE failed", v->hostStr);
        xError(str);
    }
  
    if (xControlSessn(v->clientDownSes, TCP_SETRCVBUFSPACE, (char*)&v->space, 
		      sizeof(v->space)) < 0){
        sprintf(str, "[%s] client: TCP_SETRCVBUFSIZE failed", v->hostStr);
        xError(str);
    }

    runTest(v);
    if (!v->doneFlag && !v->endRunFlag)
        saveStats(v);
}

static int
runTest(v)
tcpVars *v;
{
    XTime now;
    Msg   savedMsg, m;
    int   test, len = v->length, times = v->trips;
    char  *buf, str[100];
    int   i, totalBytes;
    
    printf("[%s] runTest: entered len = %dKB times = %d \n", v->hostStr,
	   len/1024, times);
    totalBytes = 0;
    xGetTime(&v->starttime);
/*  xControlSessn(v->clientDownSes, GETOPTPACKET, (char *)&v->maxPacket, */
/*		  sizeof(int)); */
    if (v->usePacketArg <= 0) {
        if (xControlSessn(v->clientDownSes, GETOPTPACKET, (char *)&v->maxPacket,
                          sizeof(int)) < 0)
            Kabort("GETOPTPACKET fails in runTest!\n");
    }
    else
	v->maxPacket = v->usePacketArg;
    buf = msgConstructAllocate(&savedMsg, v->maxPacket);
    msgConstructEmpty(&m);
    for (test = 0; test < times; test++) {
        xsimDbg(TMG_FLAG,
		printf("[%s] runTest: test %d started, maxPacket=%d \n",
		       v->hostStr, test, v->maxPacket));
        for (i = 0; i < len; i += v->maxPacket) {
            xsimDbg(TMG_FLAG, printf("[%s] runTest: sending pkt:%d, byte:%dK\n",
		    v->hostStr, i/v->maxPacket, i/1024));
            msgAssign(&m, &savedMsg);
	    
            if (i + v->maxPacket  > len)
	        msgTruncate(&m, len-i);
            totalBytes += msgLength(&m);  
/*          printf("runTest: i = %d msgLength = %d totalBytes  = %d\n", */
/* 	           i, msgLength(&m), totalBytes); */
            if (v->doneFlag || v->endRunFlag) {
                msgDestroy(&savedMsg); 
                msgDestroy(&m);
                return 0;
            }
	    if (i/v->maxPacket == 67000)
	      Yield();
            if (xPush(v->clientDownSes, &m) == XMSG_ERR_HANDLE) {
                if (v->doneFlag  ||  v->endRunFlag) {
                    msgDestroy(&savedMsg);
                    msgDestroy(&m);
                    return 0;
                }
	        printf("[%s] runTest: xpush failed! ********\n", v->hostStr);
	    }
/*	    printf("Bytes sent is %d\n",totalBytes);*/
            Yield();
        }

        xControlSessn(v->clientDownSes, TCP_PUSH, 0, 0);
        xControlSessn(v->clientDownSes, TCP_PUSH, 0, 0);
        xControlSessn(v->clientDownSes, TCP_PUSH, 0, 0);
        xsimDbg(TMG_FLAG, printf("[%s] runTest: test %d total bytes sent = %d\n",
		v->hostStr, test, totalBytes));
	printf("[%s] runTest: test %d total bytes sent = %d\n",v->hostStr,
	       test, totalBytes);
        semWait(&v->s);
        if (v->tripDelay > 0) {
            evDetach(evSchedule(wakeSem, (void *)v, v->tripDelay));
            semWait(&v->s);
        }
    }
    xGetTime(&now);
    if (v->reset > 0  &&  v->reset < (now.sec*1000000 + now.usec)) {
        v->starttime.sec = v->starttime0.sec = v->reset/1000000;
        v->starttime.usec = v->starttime0.usec = v->reset%1000000;
    }
    sprintf(str, "%s-%s", v->myProtl->name, v->myProtl->instName);

/*  xControlSessn(v->clientDownSes, TCP_DUMPTRACE, 0, 0); */
    subtime(&v->starttime, &now, &v->total);
    subtime(&v->starttime0, &now, &v->total0);
    subtime(&v->starttime0, &v->starttime, &v->condelay);
    v->bw = totalBytes/1024/(v->total.sec+v->total.usec/1000000.0);
    v->bw0 = totalBytes/1024/(v->total0.sec+v->total0.usec/1000000.0);
    printf("Total time is :%ld, %ld\n",v->total.sec,v->total0.usec/1000000.0);
    printf("[%s] len=%4dKB, %d trips @ %ld.%02ld (%ld.%02ld) %dKB, bw %.1fKB/s, %.3f Mb/s (%.1f, %.3f Mb/s)\n",
	   v->hostStr, len/1024, times, v->total0.sec, v->total0.usec/10000, 
	   v->total.sec, v->total.usec/10000, totalBytes/1024,
	   v->bw0,v->bw0*1024*8/1e+6,v->bw,v->bw*1024*8/1e+6);
  
    msgDestroy(&savedMsg); 
    msgDestroy(&m); 

    return 0;
}

static XkReturn
serverDemux(self, lls, dg)
Protl self;
Sessn lls;
Msg   *dg;
{
    char    *buf;
    int     vals[5];
    tcpVars *v;

    v = getMyVars(self);
    v->plen += msgLength(dg);
    v->rlen += msgLength(dg);
    xsimDbg(TMG_FLAG,  
          printf("[%s] serverDemux: Called TotalReceived = %dK msgLength = %d \n",  
 		   v->hostStr, v->plen/1024, msgLength(dg))); 
    if (v->rlen >= v->length) {
        xsimDbg(TMG_FLAG,
	        printf("[%s] serverDemux: test complete rlen = %d, LENGTH = %d\n",
		       v->hostStr, v->rlen, v->length));
        buf = msgConstructAllocate(&v->savedMsg, 4);
        msgConstructEmpty(&v->m);
/*      xControlSessn(lls, TCP_GETINFO, (char *)vals, sizeof(int)*5); */
        if (xControlSessn(lls, TCP_GETINFO, (char *)vals, sizeof(int)*5) < 0)
            Kabort("TCP_GETINFO fails in serverDemux!\n");
        *((int *)buf) = vals[4];
        msgAssign(&v->m, &v->savedMsg);
        if (v->rlen != v->length) 
            printf("[%s] serverDeumx: Bad Length!\n", v->hostStr);
        if (xPush(lls, &v->m) == XMSG_ERR_HANDLE) {
            printf("[%s] serverDemux: xpush failed!\n", v->hostStr);
            xControlSessn(lls, TCP_PUSH, 0,0);
	}
        xControlSessn(lls, TCP_PUSH, 0,0);
        xControlSessn(lls, TCP_PUSH, 0,0);
        v->rlen = 0;
        v->rtime++;
        msgDestroy(&v->savedMsg);
        msgDestroy(&v->m);
        if (v->rtime == v->trips) { 
/*          xControlProtl(xGetProtlDown(v->myProtl, 0), TCP_DUMPSTATEINFO, 0, */
/*			  0); */
/*          printf("For [%s] -----\n", v->hostStr); */
/*          printf("NTPL 0\n"); */
/*          printf("UKB  %4d\n", v->length/1024); */
/*          printf("TRKB %4d\n", v->length/1024); */

            printf("[%s] Protocol:%s, version:%d\n", v->hostStr, 
	           TcpProtls[vals[0]>>8], vals[0]&0xff);
            printf("[%s] REXMT timeouts:%d\n", v->hostStr, vals[1]); 
            printf("[%s] KB sent:       %d\n", v->hostStr, vals[2]/1024);
            printf("[%s] KB rexmtd:     %d\n", v->hostStr, vals[3]/1024);
            printf("[%s] KB rcvd dup:   %d\n", v->hostStr, vals[4]/1024);

#ifndef XNETSIM      
            xClose(lls);
            Kabort("***** End of test (server)  *****");
#else
            printf("[%s] ***** End of test (server)  *****\n", v->hostStr);
/*          xControlSessn(lls, TCP_DUMPTRACE, NULL, 0); */
            if (v->serverSaveTrace)
                if (xControlSessn(lls, TCP_DUMPTRACE, NULL, 0) < 0)
                    Kabort("TCP_DUMTRACE fails in serverDemux!\n");
            xClose(lls);
            xsimEndTest();
#endif
        }
    }

    if (xControlSessn(lls, TCP_SETRCVBUFSPACE, (char*)&v->space, 
	              sizeof(v->space)) < 0) {
        fprintf(stderr,
		"[%s] TCP custom test_demux: TCP_SETRCVBUFSPACE failed\n",
	        v->hostStr);
    }

    return XK_SUCCESS;
}

static long
msgLoad(void *ptr, char *netData, long len, void *arg)
{
    xAssert(len == sizeof(int));
    bcopy(netData, (char *)ptr, sizeof(int));
    return sizeof(int); 
}           

static XkReturn
clientDemux(self, lls, dg)
Protl self;
Sessn lls;
Msg   *dg;
{
    tcpVars *v;
    void    *buf;

    v = getMyVars(self);
/*  printf("clientDeumx: Called  \n"); */

    buf = msgPop(dg, sizeof(int));
    if (! buf)
        printf("[%s] clientDemux: Could not pop serverRcvDup\n", v->hostStr);
    else
        msgLoad((void *)&v->serverRcvDup, buf, sizeof(int), 0);

    semSignal(&v->s);
  
    if (xControlSessn(lls, TCP_SETRCVBUFSPACE, (char*)&v->space,
		      sizeof(v->space)) < 0) {
        fprintf(stderr, 
	        "[%s] TCP custom test_demux: TCP_SETRCVBUFSPACE failed\n",
	        v->hostStr);
    }

    return XK_SUCCESS;
}

static void
subtime(t1, t2, t3)
XTime *t1, *t2, *t3;
{
    t3->sec = t2->sec - t1->sec;
    t3->usec = t2->usec - t1->usec;
    if (t3->usec < 0) {
	t3->usec += 1000000;
	t3->sec -= 1;
    }
}
