/* You get to set several parmeters

TIMES the number of tests to run
LENGTH the size of the test
BUFFER_SIZE the size of the send and recieve buffers
DROP_INTERVAL drop every ith packet (if configured on top of the 
vdrop protocol) 
DROP_INTERVAL of 0 drops no packets
if you do not wish to use vdrop set the vdrop flag to 0

Note if you configure vdrop into your graph and sset the vdrop_flag to 
0 vdrop will choose a radom drop interval.

*/

/*
 * common_test.c
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1991,1996  Arizona Board of Regents
 *
 * $Revision: 1.2 $
 * $Date: 1996/02/01 15:34:36 $
 */


#include "xkernel.h"
#include "tcp.h"
#include "ip.h"
#include "site.h"
#include "vdrop.h"

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

#define TIMES 1
#define LENGTH 985*1024
#define BUFFER_SIZE 50 * 1024
#define DROP_INTERVAL 0

#ifdef __STDC__

static	void 	client( Event, void * );
static 	void 	server( Event, void * );
static 	void	subtime( XTime *, XTime *, XTime *);
static  void 	processOptions();
static  int	isServer();
static  int	isClient();
static  void	clientSetPart(Part *);
static  void	serverSetPart(Part *);
static	XkReturn closeDone(Sessn);
static	XkReturn saveServerSessn(Protl, Protl, Sessn, Protl);
static  int 	runTest(int,int);
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	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__

/**********************  TRACE */
#ifdef LTP_TRACE
  LtpTrace Traces[LTP_TRACE_MAX_ENTRIES];
  int      TraceNum = 0;
#endif
/**********************  TRACE */


static	IPhost	myHost;
static	Protl 	myProtl;
static	Sessn	clientDownSes;
static	XTime 	starttime;
static int serverParam = 0;
static int clientParam = 0;
static char *serverString; 
static IPhost ServerAddr = {192,12,69,48};
static IPhost ClientAddr = {192,12,69,49};
static Semaphore s;
static  u_short space=BUFFER_SIZE;
static int maxPacket;
static int vdrop_flag=0;
static int mytrace=0;



long    serverPort = 2001;
long    clientPort = ANY_PORT;


#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


static void
processOptions()
{
    int		i;
    char 	*arg;

#define argPrefix(str) (! strncmp(arg, str, strlen(str)))
#define argEq(str) (! strcmp(arg, str) )

    for (i=1; i < globalArgc; i++) {
	arg = globalArgv[i];
	if ( argEq("-s") ) {
	    serverParam = 1;
	} else if ( argPrefix("-c") ) {
	    clientParam = 1;
	    serverString = arg + 2;
	}
    }
 
#undef argPrefix
#undef argEq
}


int
megtest_init( self )
    Protl self;
{
    Protl	llp;

    processOptions();

    myProtl = self;
    llp = xGetProtlDown(self, 0);
    if (!xIsProtl(llp)) {
	Kabort("Test protocol has no lower protocol");
    }
    xControlProtl(xGetProtlDown(self, 0), GETMYHOST, (char *)&myHost, sizeof(IPhost));

    /* 
     * Call the per-test initialization function which gives the test
     * the opportunity to override the default functions
     */
    if (isServer()) {
	evDetach( evSchedule(server, 0, 0) );
    } else if (isClient()) {
        evDetach( evSchedule(client, 0, 0) );
    } else {
	printf("%stest: I am neither server nor client\n", "tcp");
    }
    return 0;
}


static int
isServer()
{
    if ( serverParam ) {
	return TRUE;
    }
    return ! bcmp((char *)&myHost, (char *)&ServerAddr, sizeof(IPhost));
}


static int
isClient()
{
    
    if ( clientParam ) {
	str2ipHost(&ServerAddr, serverString);
	ClientAddr = myHost;
	return TRUE;
    }
    return ! bcmp((char *)&myHost, (char *)&ClientAddr, sizeof(IPhost));
}



static void
clientSetPart( p )
    Part *p;
{
    partInit(p, 1);
    partPush(p[0], &ServerAddr, sizeof(IPhost));
    partPush(p[0], &serverPort, sizeof(long));

}

static void
serverSetPart( p )
    Part *p;
{
    partInit(p, 1);
    partPush(*p, ANY_HOST, 0);
    partPush(*p, &serverPort, sizeof(long));
}


static XkReturn
closeDone( lls )
    Sessn	lls;
{
    xTrace2(prottest, TR_MAJOR_EVENTS, "%s test -- closedone (%x) called",
	    "tcp", 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;
{
    int interval= DROP_INTERVAL;

    xTrace1(prottest, TR_MAJOR_EVENTS,
            "%s test program duplicates lower server session",
            "tcp");

    
    xDuplicate(s);

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

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

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

    if (vdrop_flag) 
    if  (xControlSessn(s, VDROP_SETINTERVAL, (char*)&interval, sizeof(interval)) < 0){
        printf("saveServerSessn: VDROP_SETINTERVAL failed\n");
    } 

    return XK_SUCCESS;
}


static void
server( ev, foo )
    Event	ev;
    VOID 	*foo;
{
    Part p;
    
    printf("I am the  server\n");
    myProtl->demux = serverDemux;
    myProtl->opendone = saveServerSessn;
    myProtl->closedone = closeDone;
    serverSetPart(&p);
    if ( xOpenEnable(myProtl, myProtl, xGetProtlDown(myProtl, 0), &p)
		== XK_FAILURE ) {
	printf("%s test server can't openenable lower protocol\n",
	       "tcp");
    } else {
	printf("%s test server done with xopenenable\n", "tcp");
    }
    return;
}

#include <signal.h>

/*-------------------------  cntrl_c  -------------------------
*/
void cntrl_c ()
{

  printf("***** User Termination (Ctrl-C)\n");
  tcpSaveTrace((char *)NULL, 0);
  Kabort("***** Cntrl-C termination (client) *****");

} /* End of cntrl_c  .............................................*/


static void
client( ev, foo )
    Event	ev;
    VOID 	*foo;
{
    Part	p[2];
    int interval= DROP_INTERVAL;
    

    printf("I am the client\n");

    myProtl->demux = clientDemux;
    semInit(&s,0);

    clientSetPart(p);
    if ( clientDownSes == 0 ) {
    	clientDownSes = xOpen(myProtl, myProtl, xGetProtlDown(myProtl, 0), p);
	if ( clientDownSes == ERR_SESSN ) {
	    printf("%s test: open failed!\n", "tcp");
	    Kabort("End of test");
	    return;
	}
    }

    if (xControlSessn(clientDownSes, TCP_SETRCVBUFSIZE, (char*)&space, 
		 sizeof(space)) < 0) {
      xError("client: TCP_SETRCVBUFSIZE failed");
    }   
    if (xControlSessn(clientDownSes, TCP_SETSNDBUFSIZE, (char*)&space, 
		 sizeof(space)) < 0) {
      xError("client: TCP_SETSNDBUFSIZE failed");
    } 
    if (xControlSessn(clientDownSes, TCP_SETRCVBUFSPACE, (char*)&space, 
		 sizeof(space)) < 0){
      xError("client: TCP_SETRCVBUFSPACE failed");
    } 

    if (vdrop_flag) 
    if  (xControlSessn(clientDownSes, VDROP_SETINTERVAL, (char*)&interval, 
		  sizeof(interval)) < 0){
      printf("client: VDROP_SETINTERVAL failed\n");
    } 

  /* --- Install signal handler */
  if (((int) signal(SIGINT, cntrl_c) == -1)) 
     Kabort("Could not install signal handler for cntrl-c\n");
  if (((int) signal(SIGQUIT, cntrl_c) == -1))
    Kabort("Could not install signal handler for quit\n");
  
    runTest(LENGTH,TIMES);

    xControlProtl(xGetProtlDown(myProtl, 0), TCP_DUMPSTATEINFO,0,0);

    printf("End of test\n");
    xClose(clientDownSes);
    Kabort("***** End of test (client)  *****");
    
}

static int
runTest( len , times)
    int len, times;
{
    XTime 	now, total;
    Msg		savedMsg,m;
    int 	test;
    char	*buf;
    int 	i,totalBytes;
    

    printf("runTest: entered len = %d times = %d \n\n",len, times);
    totalBytes = 0;
    xGetTime(&starttime);
    xControlSessn(clientDownSes, GETOPTPACKET, (char *)&maxPacket, sizeof(int));
    printf("************************************\n");
    printf("Max packet size: %d\n", maxPacket);
    buf = msgConstructAllocate(&savedMsg, maxPacket);
    msgConstructEmpty(&m);
    for (test = 0; test < times; test++) {
        if (mytrace) printf("runTest: test %d started  maxPacket = %d \n",test, maxPacket);
	for (i = 0; i< len; i += maxPacket) {
		msgAssign(&m,&savedMsg);
        	if (mytrace) printf("runTest: bytes sent = %d \n",i);
        	if (xPush(clientDownSes, &m) == XMSG_ERR_HANDLE) {
			printf("runTest: xpush failed!\n");
		} 
		totalBytes += maxPacket;  
		Yield();
	}
	if (mytrace) 
	  printf("runTest: test %d total bytes sent = %d\n",test,i);
	semWait(&s);
    }
    xGetTime(&now);
    tcpSaveTrace((char *)NULL, 0);
    subtime(&starttime, &now, &total);
    printf("len:   %4dKB\ntrips: %2d\ntime:  %2ds %3dms\n", (len+512)/1024, 
	   TIMES, total.sec, total.usec/1000);
    printf("totalKBytes: %5d\nbandwidth %5.1f KB/s\n", (totalBytes+512)/1024, 
	   (totalBytes/1024.)/(total.sec + total.usec/1000000.0));
    printf("************************************\n");

    msgDestroy(&savedMsg); 
    msgDestroy(&m); 


    return 0;
}


static int rlen=0;
static int rtimes=0;

static XkReturn
serverDemux( self, lls, dg )
    Protl self;
    Sessn lls;
    Msg *dg;
{
 

    if (mytrace) 
      printf("serverDeumx: Called rlen = %d msgLength = %d \n", rlen, msgLength(dg));

    rlen += msgLength(dg);
    if (rlen >= LENGTH) {
      printf("serverDemux: *** test complete ***\n");
      printf("Received %dKB\n", (rlen+512)/1024);
      if (xPush(lls,dg) == XMSG_ERR_HANDLE) {
	printf("serverDemux: xpush failed!\n");
      }
      rlen = 0;
      rtimes++;
      if (rtimes == TIMES) {
	Delay(5000);
	tcpSaveTrace((char *)NULL, 0);
	Kabort("***** End of test (server) *****");
      }
    }

    if (xControlSessn(lls, TCP_SETRCVBUFSPACE, (char*)&space, sizeof(space)) < 0) {
        fprintf(stderr, "TCP custom test_demux: TCP_SETRCVBUFSPACE failed\n");
    }

    return XK_SUCCESS;
}




static XkReturn
clientDemux( self, lls, dg )
    Protl self;
    Sessn lls;
    Msg *dg;
{

    if (mytrace) printf("clientDeumx: Called  \n");

    semSignal(&s);

    if (xControlSessn(lls, TCP_SETRCVBUFSPACE, (char*)&space, sizeof(space)) < 0) {
        fprintf(stderr, "TCP custom test_demux: TCP_SETRCVBUFSPACE failed\n");
    }

    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;
    }
}


