/*
 * traffic.c
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1996,1993  Arizona Board of Regents
 *
 * $Revision: 1.7 $
 * $Date: 1996/06/22 00:26:44 $
 */

#define PROT_STRING "traffic"

#include "xkernel.h"
#include "tcp.h"
#include "ip.h"
/* #include "site.h" */
#include "tcp_internal.h"
#include "xsim.h"
#include "simul.h"
#include <math.h>

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

#include "../include/tcpapps.h"
#include "../include/brkdn_dist.h"

static int xx_wZy, xx_wzY;
#define MAXIMUM(x,y) ((xx_wZy=x) < (xx_wzY=y) ? xx_wzY : xx_wZy)

/* #define MAX(x,y) (x < y ? y : x) */

#define TYPE_FTP         0
#define TYPE_TELNET      1
#define TYPE_SMTP        2
#define TYPE_NNTP        3

#define STATE_CONNECTING 0
#define STATE_CONNECTED  1
#define STATE_CONTROL    2
#define STATE_DATA       3
#define STATE_DONE       4

#define OP_CONNECT       0x1
#define OP_CONNECTED     0x2
#define OP_DONE          0x4
#define OP_LAST          0x8
#define OP_BEGIN         0x10

#define MAX_HOSTS        50
#define SERVER_PORT      3007
#define MAX_CONV         1024
#define DEF_MAXTIME      1000000

typedef struct trafficHdr {
    short src;
    short dst;
    char  type;
    char  op;
    int   id;
    int   len;
} TrafficHdr;

typedef struct serverStruct {
    struct serverStruct *next;
    int        lenLeft;
    int        last;
    Binding    bind;
    TrafficHdr hdr;
} TSS;

typedef struct trafficConvState {
    Sessn      downSessn;
    int        type;
    int        id;
    int        state;
    int        isServer;
    int        duration;
    int        endTime;
    int        nitems;
    int        sendLen;
    int        rcvLen;
    int        sendPkt;
    int        sentTime[32];
    int        cnt;
    char       *buf;
    u_short    randState[3];
    int        llsBufferSize;
    TrafficHdr hdr;
    Msg        msg;
    Msg        savedMsg;
    int        maxPacket;
    struct trafficProtState *ps;
} TCS;

typedef struct trafficProtState {
    IPhost      myHost;
    char        *hostStr;
    Protl       myProtl;
    int         isClient;
    int         isServer;
    long        serverPort[4];
    long        clientPort;
    int         nConv;
    int         showFlag;
    u_long      sendLen[4];
    u_long      rcvLen[4];
    u_long      sendPkt[4];
    u_long      convBegun[4];
    u_long      convEnded[4];
    u_long      totalConv;
    int         maxTime;
    int         done;
    int         trafficHoldFlags[4];
    u_long      telnetDelaySum;
    u_long      telnetDelayCnt;
    u_long      telnetDelayMax;
    u_long      telnetDelayGt[20];
    int         info[12];
    int         ftpBufSize;
    int         otherBufSize;
    u_short     citRandState[3];
    u_short     hostRandState[3];
    u_short     serverRandState[3];
    int         seed;
    char        *dbName;
    char        *dbStr[10];
    int         dbStrCnt;
    int         hostNum;
    IPhost      *hostArray;
    int         *ftpHostDist;
    int         *telnetHostDist;
    int         *smtpHostDist;
    int         *nntpHostDist;
    TCS         *convs[MAX_CONV];
    int         freeConv[MAX_CONV];
    int         nextConv;
    int         cit;		/* Conversation mean interarrival times in ms*/
    int         begcit;
    int         begdur;
    int         begint;
    struct brkdn_dist *brkdn_dist;
    char        infoBuf[1000];
    int         infoArray[100][8];
    int         nextInfoUpdate;
    Map         serverMap;
    int         traceSize;
    int         traceFileSize;
    TraceStruct ts;
} TPS;


int           tracetrafficp;
u_long        TrafficConvCnt = 0;
static int    KeepStacks = 0;
static char   Ctypes[] = {'f', 't', 's', 'n', '?'};
static char   *HdrTypes[] = {"ftp", "telnet", "smtp", "nntp", "????"};
static u_long IdCnt = 1;
static TSS    *SsFreeList = NULL;
static u_long TrafficConvBegun[4] = {0,0,0,0}, TrafficConvEnded[4] = {0,0,0,0};
static u_long TrafficTCPInfo[12], TrafficInfo[4][3], TrafficTelnetInfo[40];
static u_long TrafficReset[20], TrafficResetCnt=0;
static IPhost *IpHostArray = NULL;
static int    IpHostArrayN = 0;
static int    randomHosts = 0;

extern int  ThreadFreeStacks(int);

#ifdef XMEMTRACK

static int TrackId = 0;

extern char *xMallocTrack(unsigned, int);
extern char *xMallocZeroTrack(unsigned, int);
extern void xFreeTrack(char *, unsigned, int);
extern int  TrackGetId(char *);

#define xMalloc(s)     xMallocTrack(s, TrackId)
#define xMallocZero(s) xMallocZeroTrack(s, TrackId)

#endif

static char *opStr(int type)
{
    char *cp;
    static char str[100];

    cp = str;
    *cp = '\0';
    if (type & OP_CONNECT)
        strcat(str, "CONNECT ");
    if (type & OP_CONNECTED)
        strcat(str, "CONNECTED ");
    if (type & OP_DONE)
        strcat(str, "DONE ");
    if (type & OP_LAST)
        strcat(str, "LAST ");
    if (type & OP_BEGIN)
        strcat(str, "BEGIN ");
    return str;
}

#ifdef __STDC__

static void   trafficHdrStore(VOID *, char *, long, VOID *);
static long   trafficHdrLoad(VOID *, char *, long, VOID *);
static void   processOptions(TPS *);
int           traffic_init(Protl);
static void   clientSetPart(TPS *, Part *, IPhost *, int);
static void   serverSetPart(TPS *, Part *, int);
static void   trafficStart(Event, VOID *);
static IPhost *getServer(u_short *, int *, IPhost *);
static void   closeConv(Event, VOID *);
static void   nextTelnet(Event, VOID *);
static void   freeConv(TPS *, int);
static void   startConv(Event, VOID *);
static void   sendIt(Event, VOID *);
void          endTraffic(Event, VOID *);
void          resetInfo(Event, VOID *);

static XkReturn closeDone(Sessn);
static XkReturn saveSessn(Protl, Protl, Sessn, Protl);
static XkReturn demux(Protl, Sessn, Msg *);

extern double erand48(u_short *);
extern long   nrand48(u_short *);

#else

static void   trafficHdrStore();
static long   trafficHdrLoad();
static void   processOptions();
int           traffic_init();
static void   clientSetPart();
static void   serverSetPart();
static void   trafficStart();
static IPhost *getServer();
static void   closeConv();
static void   nextTelnet();
static void   freeConv();
static void   startConv();
static void   ftpSend();
static void   sendIt();
void          endTraffic();
void          resetInfo();

static XkReturn closeDone();
static XkReturn saveSessn();
static XkReturn demux();

extern double erand48();
extern long   nrand48();

#endif __STDC__

#define MAX_TRAFFIC_CLIENTS 400
void        *ClientTrafficPS[MAX_TRAFFIC_CLIENTS];
int         ClientTrafficPSCnt = 0;
extern long lrand48();
extern int  Yield();

#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 XNETSIM
extern int  xsimArgc;
extern char **xsimArgv;
int         xsimBegTest();
int         xsimEndTest();
#endif

static void
trafficHdrStore (VOID *hdr, char *dst, long len, VOID *arg)
{
    TrafficHdr tmp;

    tmp.src = htons(((TrafficHdr *)hdr)->src);
    tmp.dst = htons(((TrafficHdr *)hdr)->dst);
    tmp.id = htonl(((TrafficHdr *)hdr)->id);
    tmp.len = htonl(((TrafficHdr *)hdr)->len);
    tmp.op = ((TrafficHdr *)hdr)->op;
    tmp.type = ((TrafficHdr *)hdr)->type;
    bcopy((char *)&tmp, dst, sizeof(TrafficHdr));
}

static long
trafficHdrLoad (VOID *hdr, char *src, long len, VOID *arg)
{
    bcopy(src, (char *)hdr, sizeof(TrafficHdr));
    ((TrafficHdr *)hdr)->src = ntohs(((TrafficHdr *)hdr)->src);
    ((TrafficHdr *)hdr)->dst = ntohs(((TrafficHdr *)hdr)->dst);
    ((TrafficHdr *)hdr)->id = ntohl(((TrafficHdr *)hdr)->id);
    ((TrafficHdr *)hdr)->len = ntohl(((TrafficHdr *)hdr)->len);
    return sizeof(TrafficHdr);
}

static int
expDist(u_short *state, int mean)
{
    double val=-1.0;
    /* --- mean is in msec, returned value in usecs */

    while (val < 0.0  ||  val > 2000000.0)
        val = (-log(erand48(state))*((double)mean));
    return (int)(val * 1000.0);
}

static void
getDistr (char **argv, int *array, char *name, int num)
{
    char str[100];
    int  k, n = 0;

    for (k = 0; k < num; k++) {
        sscanf(argv[k], "%d", array+k);
        n += array[k];
    }
    if (n != 100) {
        sprintf(str, "Input error, sum of %s's is not 100");
        Kabort(str);
    }
}

#define HOST_DIST(k, hd, HostDist)    \
  if (k > 0)                          \
    HostDist[k] = hd + HostDist[k-1]; \
  else                                \
    HostDist[k] = hd;

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
processOptions(TPS *ps)
{
    char   *arg, *hostStr, str[100], *cp;
    int    i, j = 0, k, n, foundMyAddr = 0, hostCnt = 0, foundAllAddr = 0;
    int    fhd[MAX_HOSTS], thd[MAX_HOSTS], shd[MAX_HOSTS], nhd[MAX_HOSTS];
    IPhost hosts[MAX_HOSTS];

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

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

#ifndef XNETSIM
    foundMyAddr = 1;
#else
    ps->hostStr = hostStr = ps->myProtl->instName;
    for (i = 0; i < xsimArgc; i++) {
        arg = xsimArgv[i];

        if (argEq("-hosts")) {
            sscanf(xsimArgv[++i], "%d", &hostCnt);
            if (hostCnt > 0) {
	        j = 100/hostCnt;
	        ps->isClient = 1;
            }
            n = 0;
            for (k = 0; k < hostCnt; k++) {
	        str2ipHost(&hosts[k], xsimArgv[++i]);
	        fhd[k] = thd[k] = shd[k] = nhd[k] = j;
	        n += j;
            }
            k--;
            fhd[k] = thd[k] = shd[k] = nhd[k] = 100 + j - n;
        }
	else if (argEq("-rhosts")) {
	    sscanf(xsimArgv[++i], "%d", &hostCnt);
	    if (hostCnt > 0) {
	        ps->isClient = 1;
	        randomHosts = 1;
	    }
	}
        else if (argEq("-c0"))
            ps->isClient = 0;
        else if (argEq("-c1"))
            ps->isClient = 1;
	else if (argEq("-c"))
	    ps->isClient = 1;
        else if (argEq("-s0"))
            ps->isServer = 0;
        else if (argEq("-s1"))
            ps->isServer = 1;
	else if (argEq("-s"))
	    ps->isServer = 1;
        else if (argEq("-showTraffic"))
            ps->showFlag = 1;
        else if (argPrefix("-seed="))
            sscanf(xsimArgv[i]+6, "%d", &ps->seed);
        else if (argEq("-trafficConv="))
            sscanf(xsimArgv[i]+13, "%d", &ps->totalConv);
        else if (argPrefix("-trafficTime="))
	    ps->maxTime = getTime(xsimArgv[i]+13, 1000000)/1000;
        else if (argPrefix("-cit="))
	    ps->cit = getTime(xsimArgv[i]+5, 1000)/1000;
        else if (argPrefix("-begcit="))
	    ps->begcit = getTime(xsimArgv[i]+8, 1000)/1000;
        else if (argPrefix("-begdur="))
	    ps->begdur = getTime(xsimArgv[i]+8, 1000)/1000;
        else if (argPrefix("-begint="))
	    ps->begint = getTime(xsimArgv[i]+8, 1000)/1000;
        else if (argPrefix("-begkeep="))
            sscanf(xsimArgv[i]+9, "%d", &KeepStacks);
        else if (argPrefix("-reset="))
	    TrafficReset[TrafficResetCnt++] = getTime(xsimArgv[i]+7,
	                                              1000000)/1000;
        else if (argPrefix("-hold=")) {
            cp = xsimArgv[i] + 6;
            while (*cp != '\0') {
                for (k = 0; k < 4; k++) {
                    if (*cp == Ctypes[k]) {
 	                ps->trafficHoldFlags[k] = 1;
	                break;
                    }
		}
                cp++;
            }
        }
        else if (argPrefix("-trafficTrace=")) {
            sscanf(xsimArgv[i]+14, "%d", &ps->traceSize);
	    cp = xsimArgv[i] + 14;
	    while (*cp != ':'  &&  *cp != '\0')
	        cp++;
	    if (*cp == ':')
	        sscanf(cp+1, "%d", &ps->traceFileSize);
	    else
	        ps->traceFileSize = 1;
	}
        else if (argPrefix("-ftpBufSize="))
            sscanf(xsimArgv[i]+12, "%hu", &ps->ftpBufSize);
        else if (argPrefix("-otherBufSize="))
            sscanf(xsimArgv[i]+14, "%hu", &ps->otherBufSize);
        else if (argEq("-fhd")) {
            getDistr(xsimArgv+(++i), fhd, "fhd", hostCnt);
            i += hostCnt - 1;
        }
        else if (argEq("-thd")) {
            getDistr(xsimArgv+(++i), thd, "thd", hostCnt);
            i += hostCnt - 1;
        }
        else if (argEq("-shd")) {
            getDistr(xsimArgv+(++i), shd, "fsd", hostCnt);
            i += hostCnt - 1;
        }
        else if (argEq("-nhd")) {
            getDistr(xsimArgv+(++i), nhd, "nhd", hostCnt);
            i += hostCnt - 1;
        }
        else if (argPrefix("-db="))
            ps->dbName = arg + 4;
	else if (argPrefix("-dbStr="))
            ps->dbStr[ps->dbStrCnt++] = arg + 7;
	else if (argPrefix("-dbStr2=")) 	/* backward compatible */
            ps->dbStr[ps->dbStrCnt++] = arg + 8;
	else if (argPrefix("-dbStr3=")) 	/* backward compatible */
            ps->dbStr[ps->dbStrCnt++] = arg + 8;
    }

#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;
            }
            foundMyAddr = 1;
            continue;
        }
	else if (!foundMyAddr  &&  !foundAllAddr)
            continue;
	else if (argEq("-trafficConv"))
            sscanf(globalArgv[++i], "%d", &ps->totalConv);
	else if (argEq("-hosts")) {
            sscanf(globalArgv[++i], "%d", &hostCnt);
            if (hostCnt > 0)
	        j = 100/hostCnt;
            n = 0;
            for (k = 0; k < hostCnt; k++) {
	        str2ipHost(&hosts[k], globalArgv[++i]);
	        fhd[k] = thd[k] = shd[k] = nhd[k] = j;
	        n += j;
            }
            k--;
            fhd[k] = thd[k] = shd[k] = nhd[k] = n;
        }
	else if (argEq("-rhosts")) {
	    sscanf(globalArgv[++i], "%d", &hostCnt);
	    if(hostCnt > 0) {
	        ps->isClient = 1;
	        randomHosts = 1;
	    }
	}
        else if (argEq("-c0"))
            ps->isClient = 0;
        else if (argEq("-c1"))
            ps->isClient = 1;
	else if (argEq("-c"))
	    ps->isClient = 1;
        else if (argEq("-s0"))
            ps->isServer = 0;
        else if (argEq("-s1"))
            ps->isServer = 1;
	else if (argEq("-s"))
	    ps->isServer = 1;
        else if (argEq("-showTraffic"))
            ps->showFlag = 1;
        else if (argPrefix("-seed="))
            sscanf(globalArgv[i]+6, "%d", &ps->seed);
        else if (argPrefix("-cit="))
            sscanf(globalArgv[i]+5, "%d", &ps->cit);
        else if (argPrefix("-begcit="))
            sscanf(globalArgv[i]+8, "%d", &ps->begcit);
        else if (argPrefix("-begdur="))
            sscanf(globalArgv[i]+8, "%d", &ps->begdur);
        else if (argPrefix("-begint="))
            sscanf(globalArgv[i]+8, "%d", &ps->begint);
        else if (argPrefix("-begkeep="))
            sscanf(globalArgv[i]+9, "%d", &KeepStacks);
        else if (argPrefix("-reset="))
            sscanf(globalArgv[i]+7, "%d", &TrafficReset[TrafficResetCnt++]);
        else if (argPrefix("-hold=")) {
            cp = globalArgv[i] + 6;
            while (*cp != '\0') {
                for (k = 0; k < 4; k++) {
                    if (*cp == Ctypes[k]) {
                        ps->trafficHoldFlags[k] = 1;
                        break;
                    }
		}
                cp++;
            }
        }
        else if (argPrefix("-ftpBufSize="))
            sscanf(globalArgv[i]+12, "%hu", &ps->ftpBufSize);
        else if (argPrefix("-otherBufSize="))
            sscanf(globalArgv[i]+14, "%hu", &ps->otherBufSize);
        else if (argEq("-fhd")) {
            getDistr(globalArgv+(++i), fhd, "fhd", hostCnt);
            i += hostCnt - 1;
        }
        else if (argEq("-thd")) {
            getDistr(globalArgv+(++i), thd, "thd", hostCnt);
            i += hostCnt - 1;
        }
        else if (argEq("-shd")) {
            getDistr(globalArgv+(++i), shd, "fsd", hostCnt);
            i += hostCnt - 1;
        }
        else if (argEq("-nhd")) {
            getDistr(globalArgv+(++i), nhd, "nhd", hostCnt);
            i += hostCnt - 1;
        }
        else if (argPrefix("-db="))
            ps->dbName = arg + 4;
        else if (argPrefix("-dbStr="))
            ps->dbStr[ps->dbStrCnt++] = arg + 7;
        else if (argPrefix("-dbStr2="))
            ps->dbStr[ps->dbStrCnt++] = arg + 8;
        else if (argPrefix("-dbStr3="))
            ps->dbStr[ps->dbStrCnt++] = arg + 8;
    }

    ps->hostNum = hostCnt;
    if (hostCnt > 0) {
        ps->hostArray = (IPhost *) xMalloc(sizeof(IPhost)*hostCnt);
        ps->ftpHostDist = (int *) xMalloc(sizeof(int)*hostCnt);
        ps->telnetHostDist = (int *) xMalloc(sizeof(int)*hostCnt);
        ps->smtpHostDist = (int *) xMalloc(sizeof(int)*hostCnt);
        ps->nntpHostDist = (int *) xMalloc(sizeof(int)*hostCnt);
        for (k = 0; k < hostCnt; k++) {
            ps->hostArray[k] = hosts[k];
	    HOST_DIST(k, fhd[k], ps->ftpHostDist);
	    HOST_DIST(k, thd[k], ps->telnetHostDist);
	    HOST_DIST(k, shd[k], ps->smtpHostDist);
	    HOST_DIST(k, nhd[k], ps->nntpHostDist);
        }
    }
    xsimDbg(TTR_FLAG, printf("[%s] Traffic, ", ps->hostStr));
    if (ps->isClient)
        xsimDbg(TTR_FLAG, printf("isClient "));
    if (ps->isServer) {
        xsimDbg(TTR_FLAG, printf("isServer\n"));
    }
    else {
        xsimDbg(TTR_FLAG, printf("\n"));
    }
    xsimDbg(TTR_FLAG, printf("[%s]   cit: %d\n", ps->hostStr, ps->cit));
    xsimDbg(TTR_FLAG, printf("[%s]   Hosts: ", ps->hostStr));
    for (k = 0; k < hostCnt; k++) {
        xsimDbg(TTR_FLAG, printf("%s ", ipHostStr(&ps->hostArray[k])));
    }
    xsimDbg(TTR_FLAG, printf("\n[%s]   fhd: ", ps->hostStr));
    for (k = 0; k < hostCnt; k++) {
        xsimDbg(TTR_FLAG, printf("%d ", ps->ftpHostDist[k]));
    }
    xsimDbg(TTR_FLAG, printf("\n[%s]   thd: ", ps->hostStr));
    for (k = 0; k < hostCnt; k++) {
        xsimDbg(TTR_FLAG, printf("%d ", ps->telnetHostDist[k]));
    }
    xsimDbg(TTR_FLAG, printf("\n[%s]   shd: ", ps->hostStr));
    for (k = 0; k < hostCnt; k++) {
        xsimDbg(TTR_FLAG, printf("%d ", ps->smtpHostDist[k]));
    }
    xsimDbg(TTR_FLAG, printf("\n[%s]   nhd: ", ps->hostStr));
    for (k = 0; k < hostCnt; k++) {
        xsimDbg(TTR_FLAG, printf("%d ", ps->nntpHostDist[k]));
    }
    xsimDbg(TTR_FLAG, printf("\n"));
    xsimDbg(TTR_FLAG, printf("Limit of conversations: %d\n", ps->totalConv));
    xsimDbg(TTR_FLAG, printf("Max time: %dsecs\n", ps->maxTime));

#undef argPrefix
#undef argEq
}

static int BegTimeSec = -1;

extern int  getHostCnt(void);
extern void getHostArray(int, char *, IPhost *);

int
traffic_init(Protl self)
{
    int    i, k, s = 0, j, n;
    ushort randState[3];
    Protl  llp;
    TPS    *ps;
    XTime  xtime;

#ifdef XNETSIM
    if (BegTimeSec < 0)
        BegTimeSec = time(NULL);
    IpHostArrayN = k = getHostCnt();
    IpHostArray = (IPhost *) xMallocZero(sizeof(IPhost)*(k+2));
    getHostArray(IpHostArrayN, "traffic", IpHostArray);
#endif

#ifdef XMEMTRACK
    if (TrackId == 0)
        TrackId = TrackGetId("Traffic");
#endif
    ps = (TPS *)xMallocZero(sizeof(TPS));
    k = sizeof(TPS);
    ps->myProtl = self;
    ps->isClient = 0;
    ps->isServer = 1;
    ps->totalConv = 100000000;
    ps->maxTime = DEF_MAXTIME;
    ps->done = 0;
    ps->nConv = 0;
    ps->hostNum = 0;
    ps->sendLen[0] = ps->sendLen[1] = ps->sendLen[2] = ps->sendLen[3] = 0;
    ps->rcvLen[0] =  ps->rcvLen[1] =  ps->rcvLen[2] =  ps->rcvLen[3] = 0;
    ps->sendPkt[0] = ps->sendPkt[1] = ps->sendPkt[2] = ps->sendPkt[3] = 0;
    ps->cit = 100;
    ps->begcit = 0;
    ps->begdur = 0;
    ps->begint = 0;
    ps->seed = 0;
    ps->showFlag = 0;
    ps->telnetDelaySum = 0;
    ps->telnetDelayCnt = 0;
    ps->ftpBufSize = 20000;
    ps->otherBufSize = 10000;
    for (k = 0; k < 4; k++)
        ps->serverPort[k] = SERVER_PORT + k;
    self->state = (char *)ps;
    for (k = 0; k < MAX_CONV; k++) {
        ps->freeConv[k] = k;
        ps->convs[k] = NULL;
/*      ps->convs[k].ps = ps; */
    }
    ps->dbName = NULL;
    ps->dbStrCnt = 0;
    ps->nextConv = 1;
    ps->myProtl->demux = demux;
    ps->myProtl->opendone = saveSessn;
    ps->myProtl->closedone = closeDone;
    ps->serverMap = mapCreate(MAX_CONV, sizeof(Sessn));
    ps->nextInfoUpdate = 5;

    processOptions(ps);

    if (ps->begdur > 0  &&  ps->begcit == 0)
        ps->begcit = 2*ps->cit;

    /* --- If random number generator seed was not specified, get one */
    if (!ps->seed) {
        if (xControlProtl(xGetProtlDown(ps->myProtl, 0), SIM_GETSEED,
                          (char *)&ps->seed, sizeof(int)) != sizeof(int)) {
            printf("[%s] SIM_GETSEED failed!\n", ps->hostStr);
            time((time_t *)&ps->seed);
        }
        for (j = k = 0; *(self->instName+k) != '\0'; k++)
            j ^= *(self->instName+k) << 6*k;
        s ^= j;
        randState[0] = 0x531a;
        randState[1] = s & 0xffff;
        randState[2] = (s >> 16) & 0xffff;
        nrand48(randState), nrand48(randState), nrand48(randState);
        ps->seed = nrand48(randState)%200000;
        printf("[%s-%s] Making own seed: %d\n", self->name, self->instName,
               ps->seed);
    }
    printf("[%s] Traffic, seed=%d\n", ps->hostStr, ps->seed);
    ps->serverRandState[0] = ps->citRandState[0] = 0x330e;
    ps->serverRandState[1] = ps->citRandState[1] = (ps->seed) & 0xffff;
    ps->serverRandState[2] = ps->citRandState[2] = (ps->seed) >> 16;
    ps->hostRandState[0] = ps->citRandState[0];
    ps->hostRandState[1] = ps->citRandState[1];
    ps->hostRandState[2] = ps->citRandState[2];

    if (randomHosts) {
        n = 0;
        j = 100/ps->hostNum;
        for (k = 0; k < ps->hostNum; k++) {
            i = nrand48(ps->hostRandState)%IpHostArrayN;
            ps->hostArray[k] = IpHostArray[i];
            HOST_DIST(k, j, ps->ftpHostDist);
            HOST_DIST(k, j, ps->telnetHostDist);
            HOST_DIST(k, j, ps->smtpHostDist);
            HOST_DIST(k, j, ps->nntpHostDist);
       }
       k--;
       ps->ftpHostDist[k] = ps->telnetHostDist[k] = ps->smtpHostDist[k] =
           ps->nntpHostDist[k] = 100;
    }
    if (ps->isClient)
        ps->brkdn_dist = brkdn_dist(ps->citRandState);

    llp = xGetProtlDown(self, 0);
    if (!xIsProtl(llp))
        Kabort("Test protocol has no lower protocol");
    xControlProtl(xGetProtlDown(self, 0),GETMYHOST, (char *)&ps->myHost,
		  sizeof(IPhost));
    xsimDbg(TTR_FLAG, printf("[%s] Traffic, found my address %s\n", ps->hostStr,
		             ipHostStr(&ps->myHost)));

    if (ps->traceSize > 0) {
        TRACE_MALLOC(ps->ts, ps->traceSize, TRACE_PROTL_TRAFFIC, self->name,
		     self->instName, ps->traceFileSize);
        traceRegisterAddBuf(ps->ts.traceObj, ps->infoBuf, 1000);
    }
    /*
     * Call the per-test initialization function which gives the test
     * the opportunity to override the default functions
     */
    if (!(ps->isServer || ps->isClient))
        printf("[%s] %s: I am neither server nor client\n",
	       ps->hostStr, PROT_STRING);
    else
        evDetach(evSchedule(trafficStart, (void *)ps, 0));

    if (ps->maxTime != DEF_MAXTIME && ps->isClient)
        evDetach(evSchedule(endTraffic, (void *)ps, ps->maxTime*1000));
    for (k = 0; k < TrafficResetCnt; k++)
        evDetach(evSchedule(resetInfo, (void *)NULL, TrafficReset[k]*1000));
    return 0;
}

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

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

static XkReturn
closeDone(lls)
Sessn lls;
{
    xsimDbg(TTR_FLAG, printf("       *      (%x) Traffic closeDone called\n",
			     lls));
    return XK_SUCCESS;
}

static XkReturn
saveSessn(self, llp, s, hlpType)
Protl self, llp, hlpType;
Sessn s;
{
    xsimDbg(TTR_FLAG, printf("[????] *       (%x) Traffic, saving session\n",
			     s));
    xDuplicate(s);
    return XK_SUCCESS;
}

static void
trafficStart(ev, foo)
Event ev;
VOID  *foo;
{
    int  n, k;
    Part p;
    TPS  *ps = (TPS *)foo;

    if (ps->isServer) {
        printf("\n[%s] Traffic, *** I am a server\n", ps->hostStr);
	for (k = 0; k < 4; k++) {
	    serverSetPart(ps, &p, k);
            if (xOpenEnable(ps->myProtl, ps->myProtl,
			    xGetProtlDown(ps->myProtl, 0), &p) == XK_FAILURE) {
                printf("[%s] %s server can't openenable lower protocol\n",
	               ps->hostStr, PROT_STRING);
            }
	}
        printf("[%s] Traffic server done with xopenenable\n", ps->hostStr);
    }
    if (ps->isClient) {
#ifdef XNETSIM
        xsimBegTest();
        ClientTrafficPS[ClientTrafficPSCnt++] = (void *)ps;
	if (ClientTrafficPSCnt >= MAX_TRAFFIC_CLIENTS)
	   Kabort("Exceeding maximum number of traffic clients!\n");
#endif
        printf("[%s] Traffic, *** I am a client\n", ps->hostStr);
        n = 0;
        xsimDbg(TTR_FLAG, printf("[%s] First Conversation in %dusecs\n",
			         ps->hostStr, n));
        evDetach(evSchedule(startConv, (void *)ps, n));
    }
}

static IPhost *
getServer (u_short *state, int *dist, IPhost *hosts)
{
    int i, k, n;

    i = nrand48(state)%100;
    for (n = k = 0; n <= i; k++)
        if ((n += dist[k]) >= i)
            return &hosts[k];
    return NULL;
}

static void
closeConv (Event ev, VOID *foo)
{
    TCS *cs = (TCS *)foo;

    cs->ps->convEnded[cs->type]++;
    xClose(cs->downSessn);
    cs->downSessn = NULL;
    freeConv(cs->ps, cs->hdr.src);
}

static void
nextTelnet (Event ev, VOID *foo)
{
    int   closeFlag = 0;
    TCS   *cs = (TCS *)foo;
    XTime xtime;
    void  *buf;

    xGetTime(&xtime);
    if ((xtime.sec*1000 + xtime.usec/1000) > cs->endTime) {
        closeFlag = 1;
        cs->hdr.op = OP_DONE | OP_CONNECTED;
    }
    else
        cs->hdr.op = OP_CONNECTED;
    cs->sendLen++, cs->ps->sendLen[cs->type]++;
    cs->ps->sendPkt[cs->type]++;
    cs->sentTime[cs->cnt%32] = xtime.sec*1000 + xtime.usec/1000;
    cs->buf = msgConstructAllocate(&cs->msg, cs->hdr.len);
    *cs->buf = (char) ((cs->cnt++)%32);
/*  msgAssign(&cs->msg, &cs->savedMsg); */

    buf = msgPush(&cs->msg, sizeof(TrafficHdr));
    xAssert(buf);
    trafficHdrStore(&cs->hdr, buf, sizeof(TrafficHdr), 0);

    xPush(cs->downSessn, &cs->msg);
    xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
    msgDestroy(&cs->msg);
    if (!closeFlag) {
        evDetach(evSchedule(nextTelnet, (void *)cs,
			     ((int)telnet_interarrival(cs->randState))*1000));
    }
}

static void
freeConv (TPS *ps, int conv)
{
    if ((--ps->nextConv) < 0)
        Kabort("ERROR in freeConv, nextConv < 0!");
    ps->freeConv[ps->nextConv] = conv;
    TrafficConvCnt--;
}

void
resetInfo (Event ev, VOID *foo)
{
    int vals[11], i, k;
    TPS *ps;

    for (i = 0; i < ClientTrafficPSCnt; i++) {
        ps = (TPS *)ClientTrafficPS[i];

        for (k = 0; k < 11; k++)
            vals[k] = 0;
        if (xControlProtl(xGetProtlDown(ps->myProtl, 0), TCP_GETINFO,
			  (char *)vals, sizeof(int)*11) < 8) {
            printf("[%s] TCP_GETINFO failed!\n", ps->hostStr);
        }
        else {
            for (k = 1; k <= 10; k++)
                ps->info[k] = vals[k];
        }
        for (k = 0; k < 4; k++)
            ps->sendLen[k] = ps->rcvLen[k] = ps->sendPkt[k] = 0;
        ps->telnetDelayMax = ps->telnetDelayCnt = ps->telnetDelaySum = 0;
        for (k = 0; k < 20; k++)
            ps->telnetDelayGt[k] = 0;
    }
}

static char *TcpProtls[] = {"void", "ttcp", "rtcp", "vtcp", "btcp", "void"};

void
endTraffic (Event ev, VOID *foo)
{
    char        *cp;
    int         vals[11], id = 0, seed, noinfo = 1, i, j, k, i1, i2;
    TPS         *ps = (TPS *)foo;
    XTime       xtime;
    FILE        *fin, *fout;
    static int  cnt = 0;
    static FILE *foutdbg = NULL;

    cnt++;
    printf("\n[%s] Time Limit Reached for traffic\n", ps->hostStr);
    vals[9] = vals[10] = 0;
    if (xControlProtl(xGetProtlDown(ps->myProtl, 0), TCP_GETINFO, (char *)vals,
	              sizeof(int)*11) < 8) {
        printf("[%s] TCP_GETINFO failed!\n", ps->hostStr);
        ps->infoBuf[0] = '\0';
    }
    else {
        noinfo = 0;
	if (foutdbg == NULL)
	    foutdbg = fopen("traffic-dbg.out", "a");
	if (foutdbg != NULL) {
	    if (cnt == 1) {
	        fprintf(foutdbg, "RXMT sndbyte sndrxtbyte rcvdupbyte sndpkt sndrxtpkt sndruppkt rcvackbyte\n");
	        fprintf(foutdbg, "- saved values to do reset\n");
	        fprintf(foutdbg, "traffic sendLen, rcvLen, sendPkt for ftp,telnet,smtp ,nntp\n\n");
	    }
            for (k = 1; k <= 10; k++)
                fprintf(foutdbg, "%d ", vals[k]);
            fprintf(foutdbg, "\n");
            for (k = 1; k <= 10; k++)
                fprintf(foutdbg, "%d ", ps->info[k]);
            fprintf(foutdbg, "\n");
            for (k = 0; k < 4; k++)
                fprintf(foutdbg, "%d %d %d\n", ps->sendLen[k], ps->rcvLen[k],
                        ps->sendPkt[k]);
        }
        for (k = 1; k <= 10; k++)
            vals[k] -= ps->info[k];
        if (ClientTrafficPSCnt < 10  ||  ps->showFlag) {
            printf("[%s] Protocol:%s, version:%d\n", ps->hostStr,
  	           TcpProtls[vals[0]>>8], vals[0]&0xff);
            printf("[%s] REXMT timeouts:  %6d\n", ps->hostStr, vals[1]);
            printf("[%s] KB sent:         %6d\n", ps->hostStr, vals[2]/1024);
            printf("[%s] KB rexmtd:       %6d\n", ps->hostStr, vals[3]/1024);
            printf("[%s] KB rcvd dup:     %6d\n", ps->hostStr, vals[4]/1024);
            printf("[%s] pkt sent:        %6d\n", ps->hostStr, vals[5]);
            printf("[%s] pkt rexmtd:      %6d\n", ps->hostStr, vals[6]);
            printf("[%s] pkt rcvd dup:    %6d\n", ps->hostStr, vals[7]);
            printf("[%s] Fine grained TOs (dup, worry): %d, %d\n", ps->hostStr,
  	           vals[9], vals[10]);
        }
        for (k = 1; k <= 10; k++)
            TrafficTCPInfo[k] += vals[k];

        if (foutdbg != NULL) {
            for (k = 1; k <= 10; k++)
                fprintf(foutdbg, "%d ", TrafficTCPInfo[k]);
            fprintf(foutdbg, "\n\n");
        }
        cp = ps->infoBuf;
        sprintf(cp, "[%s] Protocol:%s, version:%d", ps->hostStr,
	        TcpProtls[vals[0]>>8], vals[0]&0xff);
        cp += strlen(cp) + 1;
        sprintf(cp, "[%s] REXMT timeouts:%d", ps->hostStr, vals[1]);
        cp += strlen(cp) + 1;
        sprintf(cp, "[%s] KB sent:       %d", ps->hostStr, vals[2]/1024);
        cp += strlen(cp) + 1;
        sprintf(cp, "[%s] KB rexmtd:     %d", ps->hostStr, vals[3]/1024);
        cp += strlen(cp) + 1;
        sprintf(cp, "[%s] KB rcvd dup:   %d", ps->hostStr, vals[4]/1024);
        cp += strlen(cp) + 1;
        sprintf(cp, "[%s] pkt sent:      %d", ps->hostStr, vals[5]);
        cp += strlen(cp) + 1;
        sprintf(cp, "[%s] pkt rexmtd:    %d", ps->hostStr, vals[6]);
        cp += strlen(cp) + 1;
        sprintf(cp, "[%s] pkt rcvd dup:  %d", ps->hostStr, vals[7]);
        cp += strlen(cp) + 1;
        *cp = '\0';
    }
    i = ps->sendPkt[0] + ps->sendPkt[1] + ps->sendPkt[2] + ps->sendPkt[3];
    for (k = 0; k < 4; k++) {
        if (ClientTrafficPSCnt < 10 || ps->showFlag) {
            printf("KB %6s sent, rcvd: %6ld, %6ld, Pkt sent: %8ld (%2ld%%)\n",
	           HdrTypes[k], ps->sendLen[k]/1024, ps->rcvLen[k]/1024,
		   ps->sendPkt[k], ps->sendPkt[k]*100/i);
        }
        TrafficInfo[k][0] += ps->sendLen[k];
        TrafficInfo[k][1] += ps->rcvLen[k];
        TrafficInfo[k][2] += ps->sendPkt[k];
    }
    for (i = j = k = 0; k < 4; k++) {
        i += ps->convBegun[k], j += ps->convEnded[k];
        TrafficConvBegun[k] += ps->convBegun[k];
        TrafficConvEnded[k] += ps->convEnded[k];
    }
    if (ClientTrafficPSCnt < 10  ||  ps->showFlag) {
        for (k = 0; k < 4; k++) {
            printf("%6s conv %2ld%%, began: %4ld, ended: %4ld, still going: %4ld\n",
                   HdrTypes[k], 100*ps->convBegun[k]/i, ps->convBegun[k],
                   ps->convEnded[k], ps->convBegun[k]-ps->convEnded[k]);
        }
    }

    if (ClientTrafficPSCnt < 10  ||  ps->showFlag)
        printf("[%s] max telnet delay:%ldms\n",
	       ps->hostStr, ps->telnetDelayMax);
    if (ps->telnetDelayMax > TrafficTelnetInfo[0])
        TrafficTelnetInfo[0] = ps->telnetDelayMax;
    if (ps->telnetDelayCnt > 0) {
        if (ClientTrafficPSCnt < 10  ||  ps->showFlag)
            printf("[%s] avg telnet delay:%.1fms\n", ps->hostStr,
  	           ((double)ps->telnetDelaySum)/ps->telnetDelayCnt);
        TrafficTelnetInfo[1] += ps->telnetDelaySum;
        TrafficTelnetInfo[2] += ps->telnetDelayCnt;
        TrafficTelnetInfo[3]++;
        for (j = k = 0, i = 4; k < 20; k++) {
            j += ps->telnetDelayGt[k];
/*          if ((k >= 1 && k <= 5) || k == 9 || k == 19) { */
                TrafficTelnetInfo[i++] += j;
                if (ClientTrafficPSCnt < 10  ||  ps->showFlag) {
	            int jjj;
                    if (k == 0)
	                jjj = 50;
	            else if (k < 11)
	                jjj = 50 + k*10;
                    else if (k < 18)
	                jjj = 200 + (k-11)*50;
                    else
                        jjj = 1000 + (k-18)*500;
  	            printf("[%s] %% telnet delay < %dms: %.2f\n", ps->hostStr,
			   jjj, j*100.0/ps->telnetDelayCnt);
                }
/*          } */
        }
    }
    ps->done = 1;

    if (ps->dbName != NULL  &&  !noinfo) {
        if ((fin = fopen("idFile", "r")) != NULL) {
            fscanf(fin, "%d", &id);
            fclose(fin);
        }
        if ((fout = fopen(ps->dbName, "a")) == NULL)
            printf("Could not open db file: `%s'\n", ps->dbName);
        else {
            fprintf(fout, "%%\n+++++\n%%\nProtocol: traffic\n");
            fprintf(fout, "cit: %d\n", ps->cit);
            fprintf(fout, "id: %d\n", id);
/*          if (xControlProtl(xGetProtlDown(ps->myProtl, 0), SIM_GETSEED, */
/*                            (char *)&seed,  sizeof(int)) != sizeof(int)) { */
/* 	        printf("[%s] SIM_GETSEED failed!\n", ps->hostStr); */
/*          } */
            seed = ps->seed;
            fprintf(fout, "seed: %d\n", seed);
            xGetTime(&xtime);
            fprintf(fout, "run time: %d\n", xtime.sec);
            fprintf(fout, "lower protocol: %s\nlower type: %d\n",
	            TcpProtls[vals[0]>>8], vals[0]&0xff);
            fprintf(fout, "timeouts: %d\n", vals[1]);
            fprintf(fout, "dup to: %d\n", vals[9]);
            fprintf(fout, "worry to: %d\n", vals[10]);
            fprintf(fout, "KB sent: %d\n", vals[2]/1024);
            fprintf(fout, "KB resent: %d\n", vals[3]/1024);
            fprintf(fout, "pkt sent: %d\n", vals[5]);
            fprintf(fout, "pkt resent: %d\n", vals[6]);
            for (k = 0; k < 4; k++)
                fprintf(fout, "KB %s sent: %ld\n", HdrTypes[k],
			ps->sendLen[k]/1024);
            for (k = 0; k < 4; k++)
                fprintf(fout, "KB %s rcvd: %ld\n", HdrTypes[k],
			ps->rcvLen[k]/1024);

            fprintf(fout, "max telnet delay: %ld\n", ps->telnetDelayMax);
            if (ps->telnetDelayCnt > 0) {
	        fprintf(fout, "telnet delay: %ld\n",
		        ps->telnetDelaySum/ps->telnetDelayCnt);
/*              fprintf(fout, "KB dup: %d\n", vals[4]/1024); */
	        for (j = k = 0; k < 20; k++) {
	            j += ps->telnetDelayGt[k];
	            if ((k >= 1 && k <= 5) || k == 9 || k == 19)
	                fprintf(fout, "telnet delay < %d: %.1f\n",
		                (k+1)*50, j*100.0/ps->telnetDelayCnt);
	        }
            }
            for (k = 0; k < ps->dbStrCnt; k++)
	        fprintf(fout, "%s\n", ps->dbStr[k]);
            k = ((ps->nextInfoUpdate - 5)/5) % 100;
            if (k <= 24)
	        i1 = 1, i2 = k;
            else
	        i1 = k - 12, i2 = k;
            for (j = 0, i = i1; i <= i2; j++,i++) {
	        fprintf(fout, "rto%d: %d\n", j, ps->infoArray[i][1]);
	        fprintf(fout, "sb%d: %d\n", j, ps->infoArray[i][2]/1024);
	        fprintf(fout, "rb%d: %d\n", j, ps->infoArray[i][3]/1024);
	        fprintf(fout, "sp%d: %d\n", j, ps->infoArray[i][5]);
	        fprintf(fout, "rp%d: %d\n", j, ps->infoArray[i][6]);
            }
	
            fclose(fout);
        }
    }

    if (cnt == ClientTrafficPSCnt) {
	fclose(foutdbg);
        printf("\n++++++  Totals for simulation\n\n");
        printf("REXMT timeouts:  %6ld\n", TrafficTCPInfo[1]);
        printf("KB sent:         %6ld\n", TrafficTCPInfo[2]/1024);
        printf("KB rexmtd:       %6ld\n", TrafficTCPInfo[3]/1024);
        printf("KB rcvd dup:     %6ld\n", TrafficTCPInfo[4]/1024);
        printf("pkt sent:        %6ld\n", TrafficTCPInfo[5]);
        printf("pkt rexmtd:      %6ld\n", TrafficTCPInfo[6]);
        printf("pkt rcvd dup:    %6ld\n", TrafficTCPInfo[7]);
        printf("Fine grained TOs (dup, worry): %ld, %ld\n", ps->hostStr,
               TrafficTCPInfo[9], TrafficTCPInfo[10]);

        i = TrafficInfo[0][2] + TrafficInfo[1][2] + TrafficInfo[2][2] +
	    TrafficInfo[3][2];
        for (k = 0; k < 4; k++)
            printf("KB %6s sent, rcvd: %5ld, %5ld, Pkt sent: %8ldK (%2ld%%)\n",
	           HdrTypes[k],TrafficInfo[k][0]/1024,
                   TrafficInfo[k][1]/1024, TrafficInfo[k][2]/1000,
	           TrafficInfo[k][2]*100/i);

        for (i = k = 0; k < 4; k++)
            i += TrafficConvBegun[k];
        i++;
        for (k = 0; k < 4; k++)
            printf("%6s conv %2ld%%, began: %4ld, ended: %4ld, still going: %4ld\n",
                   HdrTypes[k], 100*TrafficConvBegun[k]/i,
		   TrafficConvBegun[k], TrafficConvEnded[k],
		   TrafficConvBegun[k]-TrafficConvEnded[k]);

        printf("max telnet delay:%ldms\n", TrafficTelnetInfo[0]);
        if (TrafficTelnetInfo[2] > 0) {
            printf("avg telnet delay:%.1fms\n",
                   ((double)TrafficTelnetInfo[1])/TrafficTelnetInfo[2]);
            for (k = 4; k < 24; k++) {
                int jjj;
                if (k-4 == 0)
                    jjj = 50;
                else if (k-4 < 11)
                    jjj = 50 + (k-4)*10;
                else if (k-4 < 18)
                    jjj = 200 + (k-15)*50;
                else
                    jjj = 1000 + (k-22)*500;
                printf("%% telnet delay < %dms: %.1f\n", jjj,
                       TrafficTelnetInfo[k]*100.0/TrafficTelnetInfo[2]);
            }
        }
    }

#ifdef XNETSIM
/*  malloc(3333); */
    xsimEndTest();
#endif
}

static void
startConv (Event ev, VOID *foo)
{
    char   *cp, *buf;
    int    i, n, j, k, conv, *dist, ts;
    TPS    *ps = (TPS *)foo;
    TCS    *cs;
    Part   p[2];
    IPhost *server;
    Msg    m;
    XTime  xtime;
    void   *buffer;
    float  t;
    static lastSec = -1, ftime = 1, lastRealSec = 0;

    if (ps->done)
        return;

    if (IdCnt > ps->totalConv  &&  ps->nConv == 0) {
        xControlProtl(ps->myProtl, TCP_DUMPTRACE, NULL, 0);
#ifdef XNETSIM
        xsimEndTest();
#endif
        return;
    }
    xGetTime(&xtime);
    if (xtime.sec < ps->begdur) {
        if (xtime.sec < ps->begint)
            n = expDist(ps->citRandState, ps->begcit);
        else {
            t = xtime.sec + xtime.usec/1000000.0 - ps->begint;
            n = ps->begcit - (t/(ps->begdur-ps->begint))*(ps->begcit - ps->cit);
            n = expDist(ps->citRandState, n);
        }
    }
    else
        n = expDist(ps->citRandState, ps->cit);

    if (xtime.sec > lastSec /* || ftime */) {
        if (KeepStacks > 0  &&  ps->begdur > 0  &&  ps->begdur < xtime.sec) {
            ThreadFreeStacks(KeepStacks);
            KeepStacks = 0;
        }
        /* ftime = 0; */
        lastSec = xtime.sec;
#ifdef XNETSIM
        if (xtime.sec > 0)
            i = (time(NULL) - BegTimeSec)/xtime.sec;
        else
            i = 1;
#endif
        if (lastSec%5 == 0) {
#ifdef XNETSIM
            fprintf(stderr, "[%s] ++++++++++++++++ %d sec elapsed (sim speed: %2d:%02d/sec)\n",
                    ps->hostStr, xtime.sec, i/60, i%60);
#else
            fprintf(stderr, "[%s] ++++++++++++++++ %d sec elapsed\n",
                    ps->hostStr, xtime.sec);
#endif
#ifdef XMEMTRACK
            TrackPrint();
            tdbgPrint();
#endif
        }
        else
            fprintf(stderr, "[%s] ................ %d sec elapsed\n",
	            ps->hostStr, xtime.sec);
    }
    else if ((ts=time(NULL)) - lastRealSec > 300) {
        fprintf(stderr, "...............  %d real mins elapsed (%d.%03d sim)\n",
                (ts - BegTimeSec)/60, xtime.sec, xtime.usec/1000);
        lastRealSec = ts;
    }
    if (ps->nextInfoUpdate <= xtime.sec) {
        j = (ps->nextInfoUpdate/5) % 100;
        i = (ps->nextInfoUpdate/5 - 1) % 100;
        ps->nextInfoUpdate += 5;
        if (xControlProtl(xGetProtlDown(ps->myProtl, 0), TCP_GETINFO,
		         (char *)ps->infoArray[j], sizeof(int)*8) ==
	    sizeof(int)*8) {
            for (k = 0; k < 8; k++)
	        ps->infoArray[j][k] -= ps->infoArray[i][k];
        }
    }
    xsimDbg(TTR_FLAG, printf("[%s] N       %d.%03d Next conv in %d %d\n",
			     ps->hostStr, xtime.sec, xtime.usec/1000,
			     n/1000000, n%1000000));
    evDetach(evSchedule(startConv, (void *)ps, n));
    if (IdCnt > ps->totalConv)
        return;
    if ((i = ps->nextConv++) >= (MAX_CONV-2)) {
        ps->nextConv--;
        printf("** Could not start conversation, too many (%d) already!\n",
	       MAX_CONV);
        return;
    }
    TrafficConvCnt++;
    conv = ps->freeConv[i];
    if (ps->convs[conv] == NULL) {
        ps->convs[conv] = (TCS *)xMallocZero(sizeof(TCS));
        ps->convs[conv]->ps = ps;
    }
    cs = ps->convs[conv];
    cs->id = IdCnt++;
    cs->sendLen = 0;
    cs->rcvLen = 0;
    cs->sendPkt = 0;
    cs->randState[0] = nrand48(ps->citRandState);
    cs->randState[1] = nrand48(ps->citRandState);
    cs->randState[2] = nrand48(ps->citRandState);
    cp = next_app(cs->randState, ps->brkdn_dist);
    if ((*cp == 'f'  &&  ps->trafficHoldFlags[0])  ||
        (*cp == 't'  &&  ps->trafficHoldFlags[1])  ||
        (*cp == 's'  &&  ps->trafficHoldFlags[2])  ||
        (*cp == 'n'  &&  ps->trafficHoldFlags[3])) {
        ps->nextConv--;
        TrafficConvCnt--;
        return;
    }
    xsimDbg(TTR_FLAG,
	    printf("[%s] B%c %4d Traffic, starting conversation %s\n",
		   ps->hostStr, *cp, cs->id, cp));
    if (!strcmp(cp, "ftp")) {
        cs->type = TYPE_FTP;
        dist = ps->ftpHostDist;
        cs->nitems = ftp_nitems(cs->randState);
    }
    else if (!strcmp(cp, "telnet")) {
        cs->type = TYPE_TELNET;
        dist = ps->telnetHostDist;
        cs->duration = telnet_duration(cs->randState);
        xGetTime(&xtime);
        cs->endTime = xtime.sec*1000 + xtime.usec/1000 + cs->duration;
        cs->cnt = 0;
    }
    else if (!strcmp(cp, "smtp")) {
        cs->type = TYPE_SMTP;
        dist = ps->smtpHostDist;
    }
    else if (!strcmp(cp, "nntp")) {
        cs->type = TYPE_NNTP;
        dist = ps->nntpHostDist;
        cs->nitems = nntp_nitems(cs->randState);
    }
    else {
        printf("** Application type `%s' unknown in startConv\n", cp);
        ps->nextConv--;
        TrafficConvCnt--;
        return;
    }
    cs->ps->convBegun[cs->type]++;
    cs->state = STATE_CONNECTING;
    cs->isServer = 0;
    cs->hdr.src = conv;
    cs->hdr.dst = 0;
    cs->hdr.id = cs->id;
    cs->hdr.type = cs->type;
    cs->hdr.op = OP_CONNECT;

    server = getServer(ps->hostRandState, dist, ps->hostArray);
    xsimDbg(TTR_FLAG, printf("[%s]         using server: %s\n", ps->hostStr,
			     ipHostStr(server)));
    xsimDbg(TTR_FLAG,
 	    printf("[%s]         HDR: src:%hd, dst:%hd, type:%s, op:%s\n",
		   ps->hostStr, cs->hdr.src, cs->hdr.dst,
		   HdrTypes[(int)cs->hdr.type], opStr(cs->hdr.op)));
    clientSetPart(ps, p, server, cs->type);
    if (cs->downSessn == NULL) {
        cs->downSessn = xOpen(ps->myProtl, ps->myProtl,
			       xGetProtlDown(ps->myProtl, 0), p);
        if (cs->downSessn == ERR_SESSN) {
            printf("[%s] ******* open failed for conversation!\n", ps->hostStr);
            Kabort("End of test");
            return;
        }
    }
    xControlSessn(cs->downSessn, GETOPTPACKET, (char *)&cs->maxPacket,
		  sizeof(int));
    cs->maxPacket -= sizeof(TrafficHdr);
    xControlSessn(cs->downSessn, TCP_GETSNDBUFSPACE, (char *)&cs->llsBufferSize,
	          sizeof(cs->llsBufferSize));
    ps->nConv++;
    xsimDbg(TTR_FLAG, printf("[%s]         lls: %x\n", ps->hostStr,
			     cs->downSessn));
    DO_TRACE_WT(ps->ts, TRACE_EVENT_OPEN, cs->id, cs->type);
    DO_TRACE_L(ps->ts, TRACE_EVENT_DATA, 0, (server-ps->hostArray), 0);

    if (cs->type == TYPE_SMTP) {
        cs->hdr.len = MAXIMUM(1, smtp_itemsize(cs->randState));
        cs->sendLen += cs->hdr.len;
        cs->ps->sendLen[cs->type] += cs->hdr.len;
        DO_TRACE_L(ps->ts, TRACE_EVENT_DATA, 1, cs->hdr.len, cs->hdr.src);
        cs->hdr.op = OP_CONNECT | OP_LAST;
        xsimDbg(TTR_FLAG, printf("[%s] Ss %4d smtp sending %d bytes\n",
			         ps->hostStr, cs->id, cs->hdr.len));
        if (cs->hdr.len+sizeof(TrafficHdr) >= cs->llsBufferSize) {
            if (xControlSessn(cs->downSessn, TCP_SETSNDBUFSIZE,
			      (char*)&ps->otherBufSize,
			      sizeof(ps->otherBufSize)) < 0)
	        printf("******  TCP_SETSNDBUFSIZE failed\n");
            sendIt(NULL, (void *)cs);
        }
        else {
            buf = msgConstructAllocate(&m, cs->hdr.len);
            buffer = msgPush(&m, sizeof(TrafficHdr));
            xAssert(buffer);
            trafficHdrStore(&cs->hdr, buffer, sizeof(TrafficHdr), 0);

            cs->ps->sendPkt[cs->type]++;
            xPush(cs->downSessn, &m);
            xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
            msgDestroy(&m);
        }
    }
    else if (cs->type == TYPE_NNTP) {
        cs->hdr.len = MAXIMUM(1, nntp_itemsize(cs->randState));
        cs->sendLen += cs->hdr.len;
        cs->ps->sendLen[cs->type] += cs->hdr.len;
        DO_TRACE_L(ps->ts, TRACE_EVENT_DATA, cs->nitems, cs->hdr.len,
		   cs->hdr.src);
        if (cs->nitems == 1)
            cs->hdr.op |= OP_LAST;
        xsimDbg(TTR_FLAG,
	        printf("[%s] Sn %4d nntp %d items, sending %d bytes\n",
		       ps->hostStr, cs->id, cs->nitems, cs->hdr.len));
        if (xControlSessn(cs->downSessn, TCP_SETSNDBUFSIZE,
			(char*)&ps->otherBufSize, sizeof(ps->otherBufSize)) < 0)
            printf("******  TCP_SETSNDBUFSIZE failed\n");
        if (cs->hdr.len+sizeof(TrafficHdr) >= cs->llsBufferSize)
            sendIt(NULL, (void *)cs);
        else {
            buf = msgConstructAllocate(&m, cs->hdr.len);
            buffer = msgPush(&m, sizeof(TrafficHdr));
            xAssert(buffer);
            trafficHdrStore(&cs->hdr, buffer, sizeof(TrafficHdr), 0);

            cs->ps->sendPkt[cs->type]++;
            xPush(cs->downSessn, &m);
            xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
            msgDestroy(&m);
        }
        cs->nitems--;
    }
    else if (cs->type == TYPE_TELNET) {
        cs->hdr.len = 1;
        cs->sendLen += cs->hdr.len;
        cs->ps->sendLen[cs->type] += cs->hdr.len;
        DO_TRACE_L(ps->ts, TRACE_EVENT_DATA, 0, cs->duration, cs->hdr.src);
        xsimDbg(TTR_FLAG,
	        printf("[%s] St %4d telnet duration: %dms, sending %d byte\n",
		       ps->hostStr, cs->id, cs->duration, cs->hdr.len));
        cs->buf = msgConstructAllocate(&cs->msg, cs->hdr.len);
        *cs->buf = (char) (cs->cnt)%32;
/*      msgConstructEmpty(&cs->msg);
        msgAssign(&cs->msg, &cs->savedMsg);
*/
        buffer = msgPush(&cs->msg, sizeof(TrafficHdr));
        xAssert(buffer);
        trafficHdrStore(&cs->hdr, buffer, sizeof(TrafficHdr), 0);

        xGetTime(&xtime);
        cs->sentTime[(cs->cnt++)%32] = xtime.sec*1000 + xtime.usec/1000;
        cs->ps->sendPkt[cs->type]++;
        xPush(cs->downSessn, &cs->msg);
        xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
        msgDestroy(&cs->msg);
        evDetach(evSchedule(nextTelnet, (void *)cs,
			    ((int)telnet_interarrival(cs->randState))*1000));
    }
    else if (cs->type == TYPE_FTP) {
        if (xControlSessn(cs->downSessn, TCP_SETSNDBUFSIZE,
			  (char*)&ps->ftpBufSize, sizeof(ps->ftpBufSize)) < 0)
            printf("******  TCP_SETSNDBUFSIZE failed\n");
        cs->hdr.len = MAXIMUM(1, ftp_ctlsize(cs->randState));
        cs->sendLen += cs->hdr.len;
        cs->ps->sendLen[cs->type] += cs->hdr.len;
        DO_TRACE_L(ps->ts, TRACE_EVENT_DATA, cs->nitems, cs->hdr.len,
		   cs->hdr.src);
        cs->hdr.op |= OP_BEGIN;
        xsimDbg(TTR_FLAG,
	        printf("[%s] Sf %4d ftp %d items, sending %d bytes (control)\n",
		       ps->hostStr, cs->id, cs->nitems, cs->hdr.len));
        if (xControlSessn(cs->downSessn, TCP_SETSNDBUFSIZE,
			  (char*)&ps->ftpBufSize, sizeof(ps->ftpBufSize)) < 0)
            printf("******  TCP_SETSNDBUFSIZE failed\n");
        buf = msgConstructAllocate(&m, cs->hdr.len);
        buffer = msgPush(&m, sizeof(TrafficHdr));
        xAssert(buffer);
        trafficHdrStore(&cs->hdr, buffer, sizeof(TrafficHdr), 0);

        cs->ps->sendPkt[cs->type]++;
        xPush(cs->downSessn, &m);
        xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
        msgDestroy(&m);
    }
}

static void
sendIt (Event ev, VOID *foo)
{
    char   *buffer;
    void   *buf;
    int    len;
    TCS    *cs = (TCS *)foo;
    TPS    *ps = cs->ps;
    static int count = 0;

    len = cs->hdr.len;
    xsimDbg(TTR_FLAG, printf("[%s] b%c %4d BEGIN sendIt (%d) itemsize:%d\n",
			     ps->hostStr, Ctypes[(int)cs->hdr.type],
			     cs->id, ++count, len));

    if (len+sizeof(TrafficHdr) < cs->maxPacket) {
        buffer = msgConstructAllocate(&cs->msg, len+sizeof(TrafficHdr));
        len -= len;
    }
    else {
        buffer = msgConstructAllocate(&cs->msg,
				      cs->maxPacket-sizeof(TrafficHdr));
        len -= (cs->maxPacket - sizeof(TrafficHdr));
    }
    buf = msgPush(&cs->msg, sizeof(TrafficHdr));
    xAssert(buf);
    trafficHdrStore(&cs->hdr, buf, sizeof(TrafficHdr), 0);

    ps->sendPkt[cs->type]++;
    if (xPush(cs->downSessn, &cs->msg) == XMSG_ERR_HANDLE) {
        printf("[%s] ******* traffic %s sendIt (%d-%d) xPush failed! ***\n",
	       ps->hostStr, HdrTypes[(int)cs->hdr.type], cs->id, count);
    }
    msgDestroy(&cs->msg);

    for (; len > 0; len -= cs->maxPacket) {
        if (len >= cs->maxPacket)
            buffer = msgConstructAllocate(&cs->msg, cs->maxPacket);
        else
            buffer = msgConstructAllocate(&cs->msg, len);
        ps->sendPkt[cs->type]++;
        if (xPush(cs->downSessn, &cs->msg) == XMSG_ERR_HANDLE) {
            printf("[%s] ******* traffic %s sendIt (%d-%d) xPush failed! ***\n",
	           ps->hostStr, HdrTypes[(int)cs->hdr.type], cs->id, count);
        }
        msgDestroy(&cs->msg);
        if (ps->done) {
            xClose(cs->downSessn);
            return;
        }
/*      Yield(); */
    }
    xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
    xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
    xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
    xsimDbg(TTR_FLAG, printf("[%s] e%c %4d DONE sendIt (%d)\n", ps->hostStr,
			     Ctypes[(int)cs->hdr.type], cs->id, count));
}

static long
copyPop(void *dst, char *src, long count, void *type)
{
    bcopy(src, (char *)dst, count);
    return count;
}

static XkReturn
demux(self, lls, dg)
Protl self;
Sessn lls;
Msg   *dg;
{
    char       *buf, ca[4];
    void       *buffer;
    int        closeFlag = 0, len, j;
    int        space = 10000;
    TPS        *ps;
    TCS        *cs;
    TSS        *ss;
    TrafficHdr hdr;
    Msg        msg;

    if (xControlSessn(lls, TCP_SETRCVBUFSPACE, (char *)&space, sizeof(space)) < 0)
        printf("ERROR: SETRCVBUFSPACE in traffic demux\n");
    ps = self->state;
    len = msgLength(dg);
/*  ps->rcvLen += len; */
    if (mapResolve(ps->serverMap, (void *)&lls, (void **)&ss) != XK_FAILURE) {
        ss->lenLeft -= len;
        xsimDbg(TTR_FLAG, printf("[%s] .%c %4d (%x) len:%d, left:%d\n",
			         ps->hostStr, Ctypes[(int)ss->hdr.type],
			         ss->hdr.id, lls, len, ss->lenLeft));
        if (ss->lenLeft <= 0) {
            hdr = ss->hdr;
            hdr.dst = ss->hdr.src;
            hdr.src = 0;
            hdr.len = 1;
            hdr.op = OP_CONNECTED | OP_DONE;
            xsimDbg(TTR_FLAG,
		    printf("[%s]         %s done w/long msg (replying)\n",
			   ps->hostStr, HdrTypes[(int)ss->hdr.type]));
            buf = msgConstructAllocate(&msg, hdr.len);
            buffer = msgPush(&msg, sizeof(TrafficHdr));
            xAssert(buffer);
            trafficHdrStore(&hdr, buffer, sizeof(TrafficHdr), 0);

            ps->sendPkt[ss->hdr.type]++;
            xPush(lls, &msg);
            xControlSessn(lls, TCP_PUSH, 0, 0);
            msgDestroy(&msg);
            if (mapRemoveBinding(ps->serverMap, ss->bind) == ERR_BIND)
	        printf("ERROR: mapRemoveBinding fails in traffic!\n");
            xsimDbg(TTR_FLAG, printf("[%s]         removing from map: %x\n",
			             ps->hostStr, lls));
            ss->next = SsFreeList;
            SsFreeList = ss;
/*          xFree((char *)ss); */
            if (ss->last) {
	        xClose(lls);
            }
        }
        return XK_SUCCESS;
    }

    buffer = msgPop(dg, sizeof(TrafficHdr));
    if (!buffer)
        printf("[%s] demux: Could not pop in server\n", ps->hostStr);
    else
        trafficHdrLoad((void *)&hdr, buffer, sizeof(TrafficHdr), 0);

    if (hdr.id == 0) {
        printf("****** hdr.id == 0!  lls: %x\n", lls);
        return XK_SUCCESS;
    }
    DO_TRACE_WT(ps->ts, TRACE_EVENT_DEMUX, hdr.id, hdr.type);
    len -= sizeof(TrafficHdr);

    /* --- Server side */
    if (hdr.dst == 0) {
        DO_TRACE_L(ps->ts, TRACE_EVENT_DATA, hdr.op, len, 0);
        xsimDbg(TTR_FLAG,
	        printf("[%s]sd%c %4d (%x), src:%hd, dst:%hd, op:%s, len:%d\n",
		       ps->hostStr, Ctypes[(int)hdr.type], hdr.id, lls, hdr.src,
		       hdr.dst, opStr(hdr.op), hdr.len));

        if (hdr.type == TYPE_SMTP) {
            if (hdr.len > len) {
                if (SsFreeList == NULL)
	            ss = (TSS *) xMalloc(sizeof(TSS));
                else {
	            ss = SsFreeList;
                    SsFreeList = ss->next;
                }
	        ss->hdr = hdr;
	        ss->lenLeft = hdr.len - len;
	        if (hdr.op & OP_LAST)
	            ss->last = 1;
	        else
	            ss->last = 0;
	        ss->bind = mapBind(ps->serverMap, (void *)&lls, (void *)ss);
	        if (ss->bind == ERR_BIND)
	            printf("ERROR: Bind error in SMTP, id:%d\n", hdr.id);
	        xsimDbg(TTR_FLAG, printf("[%s]         adding to map: %x\n",
				         ps->hostStr, lls));
	        if (xControlSessn(lls, TCP_SETRCVBUFSIZE,
		                  (char*)&ps->otherBufSize,
				  sizeof(ps->otherBufSize)) < 0)
	            printf("******  TCP_SETRCVBUFSIZE failed\n");
            }
            else {
	        hdr.dst = hdr.src;
	        hdr.src = 0;
	        hdr.len = 1;
	        hdr.op = OP_CONNECTED | OP_DONE;
	        xsimDbg(TTR_FLAG,
			printf("[%s]         %s done w/msg (replying)\n",
			       ps->hostStr, HdrTypes[(int)hdr.type]));
	        buf = msgConstructAllocate(&msg, hdr.len);
                buffer = msgPush(&msg, sizeof(TrafficHdr));
                xAssert(buffer);
                trafficHdrStore(&hdr, buffer, sizeof(TrafficHdr), 0);

	        ps->sendPkt[hdr.type]++;
	        xPush(lls, &msg);
	        xControlSessn(lls, TCP_PUSH, 0, 0);
	        msgDestroy(&msg);
	        xClose(lls);
            }
            return XK_SUCCESS;
        }
        else if (hdr.type == TYPE_NNTP) {
            if (xControlSessn(lls, TCP_SETRCVBUFSIZE,
		              (char*)&ps->otherBufSize,
			      sizeof(ps->otherBufSize)) < 0)
	        printf("******  TCP_SETRCVBUFSIZE failed\n");
            if (hdr.len > len) {
                if (SsFreeList == NULL)
                    ss = (TSS *) xMalloc(sizeof(TSS));
                else {
                    ss = SsFreeList;
                    SsFreeList = ss->next;
                }
	        ss->hdr = hdr;
	        ss->lenLeft = hdr.len - len;
	        if (hdr.op & OP_LAST)
	            ss->last = 1;
	        else
	            ss->last = 0;
	        ss->bind = mapBind(ps->serverMap, (void *)&lls, (void *)ss);
	        if (ss->bind == ERR_BIND)
	            printf("ERROR: Bind error in NNTP, id:%d\n", hdr.id);

	        xsimDbg(TTR_FLAG, printf("[%s]         adding to map: %x\n",
				         ps->hostStr, lls));
            }
            else {
	        if (hdr.op & OP_LAST)
	            closeFlag = 1;
	        hdr.dst = hdr.src;
	        hdr.src = 0;
	        hdr.len = 1;
	        hdr.op = OP_CONNECTED | OP_DONE;
	        xsimDbg(TTR_FLAG,
			printf("[%s]         %s done w/msg (replying)\n",
			       ps->hostStr, HdrTypes[(int)hdr.type]));
	        buf = msgConstructAllocate(&msg, hdr.len);
                buffer = msgPush(&msg, sizeof(TrafficHdr));
                xAssert(buffer);
                trafficHdrStore(&hdr, buffer, sizeof(TrafficHdr), 0);

	        ps->sendPkt[hdr.type]++;
	        xPush(lls, &msg);
	        xControlSessn(lls, TCP_PUSH, 0, 0);
	        msgDestroy(&msg);
	        if (closeFlag)
	            xClose(lls);
            }
            return XK_SUCCESS;
        }
        else if (hdr.type == TYPE_TELNET) {

            buffer = msgPop(dg, 1);
            if (! buffer)
                printf("[%s] Telnet: Could not pop ca in server\n",
		       ps->hostStr);
            else
                copyPop((void *)ca, buffer, 1, 0);

/*          msgPop(dg, copyPop, ca, 1, NULL); */
            if (hdr.op & OP_DONE) {
	        closeFlag = 1;
	        hdr.op = OP_CONNECTED | OP_DONE;
            }
            else
	        hdr.op = OP_CONNECTED;
            hdr.dst = hdr.src;
            hdr.src = 0;
            hdr.len = MAXIMUM(1, telnet_pktsize(ps->serverRandState));
            xsimDbg(TTR_FLAG,
		    printf("[%s]         telnet replying with %d bytes\n",
			   ps->hostStr, hdr.len));
            buf = msgConstructAllocate(&msg, hdr.len);
            *buf = ca[0];

            buffer = msgPush(&msg, sizeof(TrafficHdr));
            xAssert(buffer);
            trafficHdrStore(&hdr, buffer, sizeof(TrafficHdr), 0);

            ps->sendPkt[hdr.type]++;
            xPush(lls, &msg);
            xControlSessn(lls, TCP_PUSH, 0, 0);
            msgDestroy(&msg);
            if (closeFlag)
  	        xClose(lls);
            return XK_SUCCESS;
        }
        else if (hdr.type == TYPE_FTP) {
            if (hdr.op & OP_DONE) {
	        xsimDbg(TTR_FLAG,
			printf("[%s]  f      ftp DONE\n", ps->hostStr));
 	        xClose(lls);
	        return XK_SUCCESS;
            }
            else if (hdr.op & OP_LAST) {
	        hdr.dst = hdr.src;
	        hdr.src = 0;
	        hdr.len = 1;
	        hdr.op = OP_CONNECTED | OP_DONE;
	        xsimDbg(TTR_FLAG,
		  printf("[%s]  f      ftp (****LAST) replying with %d bytes\n",
		         ps->hostStr, hdr.len));
	        buf = msgConstructAllocate(&msg, hdr.len);
                buffer = msgPush(&msg, sizeof(TrafficHdr));
                xAssert(buffer);
                trafficHdrStore(&hdr, buffer, sizeof(TrafficHdr), 0);

 	        ps->sendPkt[hdr.type]++;
	        xPush(lls, &msg);
	        xControlSessn(lls, TCP_PUSH, 0, 0);
	        msgDestroy(&msg);
	        return XK_SUCCESS;
            }
            else if (hdr.op & OP_BEGIN) {
	        if (xControlSessn(lls, TCP_SETRCVBUFSIZE,
		                  (char*)&ps->ftpBufSize,
				  sizeof(ps->ftpBufSize)) < 0)
	            printf("******  TCP_SETRCVBUFSIZE failed\n");
	        hdr.dst = hdr.src;
	        hdr.src = 0;
	        hdr.op = OP_CONNECTED | OP_BEGIN;
	        hdr.len = MAXIMUM(1, ftp_ctlsize(ps->serverRandState));
	        xsimDbg(TTR_FLAG,
			printf("[%s]        ftp replying with %d bytes\n",
			       ps->hostStr, hdr.len));
	        buf = msgConstructAllocate(&msg, hdr.len);
                buffer = msgPush(&msg, sizeof(TrafficHdr));
                xAssert(buffer);
                trafficHdrStore(&hdr, buffer, sizeof(TrafficHdr), 0);

	        ps->sendPkt[hdr.type]++;
	        xPush(lls, &msg);
	        xControlSessn(lls, TCP_PUSH, 0, 0);
	        msgDestroy(&msg);
	        return XK_SUCCESS;
            }
            else {
	        if (hdr.len > len) {
                    if (SsFreeList == NULL)
                        ss = (TSS *) xMalloc(sizeof(TSS));
                    else {
                        ss = SsFreeList;
                        SsFreeList = ss->next;
                    }
	            ss->hdr = hdr;
	            ss->lenLeft = hdr.len - len;
	            if (hdr.op & OP_LAST)
	                ss->last = 1;
	            else
	                ss->last = 0;
	            ss->bind = mapBind(ps->serverMap, (void *)&lls, (void *)ss);
	            if (ss->bind == ERR_BIND)
	                printf("ERROR: Bind error in FTP, id:%d\n", hdr.id);

	            xsimDbg(TTR_FLAG, printf("[%s]         adding to map: %x\n",
				             ps->hostStr, lls));
	        }
	        else {
	            hdr.dst = hdr.src;
	            hdr.src = 0;
	            hdr.len = 1;
	            hdr.op = OP_CONNECTED | OP_DONE;
	            xsimDbg(TTR_FLAG,
		      printf("[%s]  f      ftp (LAST) replying with %d bytes\n",
			     ps->hostStr, hdr.len));
	            buf = msgConstructAllocate(&msg, hdr.len);
                    buffer = msgPush(&msg, sizeof(TrafficHdr));
                    xAssert(buffer);
                    trafficHdrStore(&hdr, buffer, sizeof(TrafficHdr), 0);

	            ps->sendPkt[hdr.type]++;
	            xPush(lls, &msg);
	            xControlSessn(lls, TCP_PUSH, 0, 0);
	            msgDestroy(&msg);
	        }
	        return XK_SUCCESS;
            }
        }
        else {
            printf ("******  Unknown type:%d\n", hdr.type);
            return XK_SUCCESS;
        }
        return XK_SUCCESS;
    }

    /* --- This is only executed by the client (originator) */
    cs = ps->convs[hdr.dst];
    if (cs == NULL)
        Kabort("cs is NULL (wrong hdr.dst)!\n");
    cs->rcvLen += len;
    cs->ps->rcvLen[cs->type] += len;
    DO_TRACE_L(ps->ts, TRACE_EVENT_DATA, hdr.op, len, 1);
    xsimDbg(TTR_FLAG,
	    printf("[%s]cd%c %4d (%x), src:%hd, dst:%hd, op:%s, len:%d\n",
		   ps->hostStr, Ctypes[(int)hdr.type], hdr.id, lls, hdr.src,
		   hdr.dst, opStr(hdr.op), hdr.len));

    if (cs->type == TYPE_SMTP) {
        if (hdr.op & OP_DONE) {
            xsimDbg(TTR_FLAG, printf("[%s] Ds %4d smtp DONE!\n", ps->hostStr,
			             cs->id));
            evDetach(evSchedule(closeConv, (void *)cs, 0));
            ps->nConv--;
            DO_TRACE_L(ps->ts, TRACE_EVENT_CLOSE, cs->id, cs->sendLen,
		       cs->type);
        }
        else
            printf("******  SMTP not OP_DONE\n");
        return XK_SUCCESS;
    }
    else if (cs->type == TYPE_NNTP) {
        if (!(hdr.op & OP_DONE))
            printf("******  in nntp, not OP_DONE\n");
        if (cs->nitems > 0) {
            if (cs->nitems == 1)
	        cs->hdr.op = OP_CONNECTED | OP_LAST;
            else
	        cs->hdr.op = OP_CONNECTED;
            cs->hdr.len = MAXIMUM(1, nntp_itemsize(cs->randState));
            cs->sendLen += cs->hdr.len;
            cs->ps->sendLen[cs->type] += cs->hdr.len;
            DO_TRACE_L(ps->ts, TRACE_EVENT_SEND, cs->id, cs->hdr.len, cs->type);
            xsimDbg(TTR_FLAG,
	           printf("[%s]  n      nntp %d items left, sending %d bytes\n",
		          ps->hostStr, cs->nitems, cs->hdr.len));
            if (cs->hdr.len+sizeof(TrafficHdr) >= cs->llsBufferSize)
	        evDetach(evSchedule(sendIt, (void *)cs, 0));
            else {
	        buf = msgConstructAllocate(&msg, cs->hdr.len);
                buffer = msgPush(&msg, sizeof(TrafficHdr));
                xAssert(buffer);
                trafficHdrStore(&cs->hdr, buffer, sizeof(TrafficHdr), 0);

                ps->sendPkt[cs->type]++;
	        xPush(cs->downSessn, &msg);
	        xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
	        msgDestroy(&msg);
            }
            cs->nitems--;
        }
        else {
            xsimDbg(TTR_FLAG,
		    printf("[%s] Dn      nntp (%d) DONE!\n", ps->hostStr,
			   cs->id));
            evDetach(evSchedule(closeConv, (void *)cs, 0));
            ps->nConv--;
            DO_TRACE_L(ps->ts, TRACE_EVENT_CLOSE, cs->id, cs->sendLen,
		       cs->type);
        }
        return XK_SUCCESS;
    }
    else if (cs->type == TYPE_TELNET) {
        XTime xtime;

        xGetTime(&xtime);

        buffer = msgPop(dg, 1);
        if (! buffer)
            printf("[%s] Telnet: Could not pop ca in client\n", ps->hostStr);
        else
            copyPop((void *)ca, buffer, 1, 0);

/*      msgPop(dg, copyPop, ca, 1, NULL); */
        j = (xtime.sec*1000 + xtime.usec/1000) - cs->sentTime[(int)ca[0]];
        ps->telnetDelaySum += j;
        ps->telnetDelayCnt++;
        if (j > ps->telnetDelayMax)
            ps->telnetDelayMax = j;
        if (j < 50)
            ps->telnetDelayGt[0]++;
        else if (j >= 50  &&  j <150)
            ps->telnetDelayGt[(j-40)/10]++;
        else if (j < 500)
            ps->telnetDelayGt[11+(j-150)/50]++;
        else if (j < 2000)
            ps->telnetDelayGt[18+(j-500)/500]++;
        if (hdr.op & OP_DONE) {
            xsimDbg(TTR_FLAG, printf("[%s] Dt %4d telnet DONE!\n", ps->hostStr,
			             cs->id));
/*          msgDestroy(&cs->savedMsg); */
/*          msgDestroy(&cs->msg); */
            evDetach(evSchedule(closeConv, (void *)cs, 0));
            ps->nConv--;
            DO_TRACE_L(ps->ts, TRACE_EVENT_CLOSE, cs->id, cs->sendLen,
		       cs->type);
        }
        return XK_SUCCESS;
    }
    else if (cs->type == TYPE_FTP) {
        if (hdr.op & OP_DONE) {
            cs->nitems--;
            if (cs->nitems > 0) {
	        cs->hdr.len = MAXIMUM(1, ftp_ctlsize(cs->randState));
	        cs->sendLen += cs->hdr.len;
                cs->ps->sendLen[cs->type] += cs->hdr.len;
	        cs->hdr.op = OP_CONNECTED | OP_BEGIN;
	        xsimDbg(TTR_FLAG,
		    printf("[%s]  f      ftp %d items left, sending %d bytes\n",
		           ps->hostStr, cs->nitems, hdr.len));
	        buf = msgConstructAllocate(&msg, cs->hdr.len);
                buffer = msgPush(&msg, sizeof(TrafficHdr));
                xAssert(buffer);
                trafficHdrStore(&cs->hdr, buffer, sizeof(TrafficHdr), 0);

	        ps->sendPkt[cs->type]++;
	        xPush(cs->downSessn, &msg);
	        xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
	        msgDestroy(&msg);
            }
            else {
	        cs->hdr.len = 1;
	        cs->hdr.op = OP_CONNECTED | OP_DONE;
	        xsimDbg(TTR_FLAG, printf("[%s] Df      ftp DONE!\n",
					 ps->hostStr));
	        buf = msgConstructAllocate(&msg, cs->hdr.len);
                buffer = msgPush(&msg, sizeof(TrafficHdr));
                xAssert(buffer);
                trafficHdrStore(&cs->hdr, buffer, sizeof(TrafficHdr), 0);

	        ps->sendPkt[cs->type];
	        xPush(cs->downSessn, &msg);
	        xControlSessn(cs->downSessn, TCP_PUSH, 0, 0);
	        msgDestroy(&msg);
	        evDetach(evSchedule(closeConv, (void *)cs, 0));
	        ps->nConv--;
	        DO_TRACE_L(ps->ts, TRACE_EVENT_CLOSE, cs->id, cs->sendLen,
			   cs->type);
            }
            return XK_SUCCESS;
        }
        else if (hdr.op & OP_BEGIN) {
            cs->hdr.len = ftp_itemsize(cs->randState);
            cs->sendLen += cs->hdr.len;
            cs->ps->sendLen[cs->type] += cs->hdr.len;
            DO_TRACE_L(ps->ts, TRACE_EVENT_SEND, cs->id, cs->hdr.len, cs->type);
            cs->hdr.op = OP_CONNECTED;
            evDetach(evSchedule(sendIt, (void *)cs, 0));
        }
        else
            printf("******  ftp hdr not OP_DONE or OP_BEGIN\n");
    }
    return XK_SUCCESS;
}

int error ()
{
    printf("Someone called function error!\n");
    return 1;
}
