/*
 * $RCSfile: dt_common.c,v $
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1996,1994  Arizona Board of Regents
 */

#ifdef INCLUDE_0  /***********************************  BEGIN INCLUDE_0 */
#undef INCLUDE_0

#include <stdio.h>
#include <math.h>
#include "xkernel.h"

#define P0(str)			(p_flag ? printf(str) : 0)
#define P1(str,a1)		(p_flag ? printf(str,a1) : 0)
#define P2(str,a1,a2)		(p_flag ? printf(str,a1,a2) : 0)
#define P3(str,a1,a2,a3)	(p_flag ? printf(str,a1,a2,a3) : 0)
#define P4(str,a1,a2,a3,a4)	(p_flag ? printf(str,a1,a2,a3,a4) : 0)
#define P5(str,a1,a2,a3,a4,a5)	(p_flag ? printf(str,a1,a2,a3,a4,a5) : 0)

#define NO_INCLUDE_UPI_H

#define TCP_TRACE


/* --- Dummy stuff for include file */
struct tcphdr   {int i;};
struct tcpiphdr {int i;};
struct inpcb    {int i;};
typedef u_int tcp_seq;

#define TCPT_NTIMERS 4
#include "tcp_var.h"

#include "tcp_trace.h"

#define MAX_NUM_PACKETS 100000
#define MAX_NUM_EVENTS  300000
#define INIT_COMP(min,max,avg)  min=1000000,max=0,avg=0
#define DO_COMP(t2,t1,min,max,avg)	\
  d = t2 - t1;				\
  if (d < min) min = d;			\
  if (d > max) max = d;			\
  avg += d;

typedef struct {
  int		seq;
  int		len;
  int		ack;
  int		time;
  short		flags;
  short		sid;
} RcvTraceType;

typedef struct {
  int		time;
  int		seq;
  int		time_rcvd_ack;
  int		len;
  short		flags;
  short		sid;
} SndTraceType;

#define F_LOST 		0x1
#define F_RESEND	0x2
#define F_DUPRCV	0x100

TcpTrace       	*Traces;
RcvTraceType  	RcvTraces[MAX_NUM_PACKETS];
SndTraceType    SndTraces[MAX_NUM_PACKETS];
struct tcpstat  TcpStat;
int		NumPacketsSent=0, NumPacketsRcvd=0;
int		NumPacketsRcvdDup=0, NumPacketsRcvdOutOrder=0;
int		LastPacketRcvd=-1;
char *events[4] = {"push", "ack ", "to  ", "ss  "};
int		total_bytes_sent, total_bytes_rcvd, test_time;
char		buf[5000];
char 		*fname="trace.data";
int		beg_time=0;
int		len, seq, ack, flg, opt_len, win;
int		RexmtN=0, PersistN=0, KeepN=0, MslN=0, BadsumN=0, DropN=0;
int             Pflags[20];
int             Sids[256], SidCnt=0, SidsUse[256];
int             SidUse=-1;
int             winScale=0;
int             rHisto[500], sdCnt=0;
float           sdSumXX=0.0, sdSumX=0.0, sd;
char 		*States[]={"CLOSED", "LISTEN", "SYN_SENT", "SYN_RECEIVED",
			   "ESTABLISHED", "CLOSE_WAIT", "FINT_WAIT_1",
			   "CLOSING", "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT"};
char		*Timer[]={"REXMT", "PERSIST", "KEEP", "2MSL"};

#define IS_ACK(x) 	(x & 0x10)
#define IS_PUSH(x)	(x & 0x08)
#define IS_URG(x)	(x & 0x20)
#define IS_RST(x)	(x & 0x04)
#define IS_SYN(x)	(x & 0x02)
#define IS_FIN(x)	(x & 0x01)


/*-------------------------  timer2str  -------------------------
*/
char *timer2str (t)

int t;
{
  if (t < 0  ||  t > 3)
    return "ERROR";
  else
    return Timer[t];

} /* End of timer2str  .............................................*/


/*-------------------------  state2str  -------------------------
*/
char *state2str (st)

int st;
{
  if (st < 0  ||  st > 10)
    return "UNKNOWN";
  else
    return States[st];

} /* End of state2str  .............................................*/


/*-------------------------  flags2str  -------------------------
*/
char *flags2str (flag, off)

int flag, off;
{
  static char str[50];

  str[0] = '\0';
  if (IS_ACK(flag))	strcat(str, "ACK ");
  else if (off)		strcat(str, "    ");
  if (IS_PUSH(flag))	strcat(str, "PUSH ");
  else if (off) 	strcat(str, "     ");
  if (IS_URG(flag))	strcat(str, "URG ");
  if (IS_RST(flag))	strcat(str, "RST ");
  if (IS_SYN(flag))	strcat(str, "SYN ");
  if (IS_FIN(flag))	strcat(str, "FIN");
  return str;

} /* End of flags2str  .............................................*/


#endif		   /***********************************  END INCLUDE_0 */


#ifdef INCLUDE_1  /***********************************  BEGIN INCLUDE_1 */
#undef INCLUDE_1

  char c, *cp, cc, str[100];
  int  i, j, k, kk, n, nt, max_diff, lost_cnt=0, lost_bytes=0;
  int  last_time, flags;
  int  dup_cnt=0, dup_rcvd_bytes=0, dups_cnt=0, dups_bytes=0;
  int  smin, smax, savg, rmin, rmax, ravg, rminCnt=0, d;
  int  npit=0, run_time, read_np_lost, otLen, bytes_rcvd=0;
  int  rcv_only_flag=0, rcv_summary_flag=0, stat_flag=1, stat_size=0;
  int  db_flag=0, p_flag=1, head_flag=1, fix_time_flag=1;
  int  debug_flag=0, max_beg_seq_sent=-1, max_beg_seq_rcvd=-1, pn=0;
  int  loss_mode=0, time=0, largestSeq=0, timeLastSend;
  int  rttCnt=0, rttMaxTime=0, rttLast=0, rttSum=0, rttMin=10000000, rttMax=0;
  int  rttCur;
  FILE *fin, *fout;
  dthdr fileHdr;
  dttracemapentry *trace_map;
  long post_off;
  int post_len;

#endif		/***********************************  END INCLUDE_1 */


#ifdef INCLUDE_2  /***********************************  BEGIN INCLUDE_2 */
#undef INCLUDE_2

  if (argc > 1  &&  *argv[argc-1] != '-')
   fname = argv[argc-1];
/*  if (argc > 1  &&  *argv[argc-1] == '-')
    fin = stdin;
    else */
  if ((fin = fopen(fname, "r")) == NULL) {
    fprintf(stderr, "ERROR: Could not open trace.data\n");
    exit(1);
  }
  for (k=1; k<argc; k++)
    if (!strncmp(argv[k], "-sid=", 5)) {
      sscanf(argv[k]+5, "%d", &SidUse);
      SidsUse[SidUse] = 1;
    }
  if (SidUse == -1)
    for (k=0; k<255; k++)
      SidsUse[k] = 1;

  fread((char *)&fileHdr, sizeof(dthdr), 1, fin);
  post_off = dtPostAmbleLocation(&fileHdr);

  /* go to the postamble location */
  fseek(fin, post_off, 0);

  fread((char *)&post_len, sizeof(int), 1, fin);
  fread(&test_time, sizeof(long), 1, fin); /* VENKAT */
  if (debug_flag) 
    printf("test_time: %ld\n", test_time), fflush(stdout);
  fread(&total_bytes_sent, sizeof(int), 1, fin);
  if (debug_flag) 
    printf("total_bytes_sent: %d\n", total_bytes_sent), fflush(stdout);
  fread(&total_bytes_rcvd, sizeof(int), 1, fin);
  if (debug_flag)
    printf("total_bytes_rcvd: %d\n", total_bytes_rcvd), fflush(stdout);
  fread(&run_time, sizeof(long), 1, fin); /* VENKAT */
  if (debug_flag)
    printf("run_time: %ld\n", run_time), fflush(stdout);
  fread(&read_np_lost, sizeof(int), 1, fin);
  if (debug_flag)
    printf("read_np_lost: %d\n", read_np_lost), fflush(stdout);
  fread(&otLen, sizeof(int), 1, fin);
  if (debug_flag)
    printf("otLen: %d\n", otLen), fflush(stdout);
  if (otLen > 0) {
    fread(buf, otLen, 1, fin);
/*     bcopy(buf, &ot, sizeof(TcpOtherTrace)); */
  }

  fread(&stat_size, sizeof(int), 1, fin);
  if (debug_flag)
    printf("size of stats: %d\n", stat_size), fflush(stdout);
  if (stat_size > 0) {
    fread(buf, stat_size, 1, fin);
    bcopy(buf, (char *)&TcpStat, sizeof(struct tcpstat)); 
  }
  fread(&i, sizeof(int), 1, fin);
  if (i > 0) {
    fread(buf, 1, i, fin);
    printf("\nOther file info:\n\n%s\n", buf);
  }

  trace_map = dtGetTraceMap(&fileHdr);  
  if (! trace_map) {
    printf("Error getting the map of the trace file\n");
    exit(-1);
  }

  for (i=j=0; j<fileHdr.numberBuffers; j++)
    i += trace_map[j].size + 1024;
  Traces = (TcpTrace *) malloc(i + 1024);

  nt = 0;
  for (j=0; j<fileHdr.numberBuffers; j++) {
    fseek(fin, trace_map[j].seek, 0);

    /* read the trace data */
    fread(&Traces[nt], 1, trace_map[j].size, fin);
    nt += trace_map[j].size/sizeof(TcpTrace);
  }
  fclose(fin);
  if (debug_flag)
    printf("number of traces: %d\n", nt), fflush(stdout);
  printf("Test Date: %s\n", ctime((time_t *)&test_time));
  if (Pflags[0]) {
    P1("Number of Kbytes sent:   %d\n", total_bytes_sent/1024); 
    P1("Number of Kbytes rcvd:   %d\n", total_bytes_rcvd); 
    P2("Run time:                %ds %dms\n",run_time/1000, run_time%1000);
    P1("Number of packets lost:  %d\n", read_np_lost); 
    P1("Throughput:              %5.1f KB/s\n",  
 	   (total_bytes_sent/1024.)/((run_time+1)/1000.)); 
  }

  /* --- Get beginning time */
  if (fix_time_flag)
    for (k=0; k<nt; k++)
      if (Traces[k].event == TCP_EVENT_OPEN  &&  SidsUse[Traces[k].sid]) {
        beg_time = Traces[k].time - 2;
        break;
      }
  /* --- Fix for the receiver side */
  if (k > 40)
    beg_time = 0;

  /* --- Fix the times */
  for (k=0; k<nt; k++) {
    if (Traces[k].event == TCP_EVENT_OTHER9) {
      if (Traces[k].data == 6)
        winScale = Traces[k].time;
    }
    else if ((i=Traces[k].event) == TCP_EVENT_IN  ||  i == TCP_EVENT_OUT  ||
	i == TCP_EVENT_FAST_TO  ||  i == TCP_EVENT_SLOW_TO  ||
	i == TCP_EVENT_TIMER  ||  i == TCP_EVENT_OPEN  ||  
	i == TCP_EVENT_PUSH  ||  i == TCP_EVENT_PUSHA ||  
	i == TCP_EVENT_CTL_PUSH) {

      if (Sids[Traces[k].sid] == 0)
        Sids[Traces[k].sid] = 1, SidCnt++;
      Traces[k].time -= beg_time;
    }
  }

  printf("\nNumber of sid: %d\n", SidCnt);
  for (k=i=0; k<255; k++)
    if (Sids[k] != 0) {
      printf("%3d ", k);
      if (++i >= 19)
      printf("\n"), i=0;
    }

  for (k=0; k<nt; k++) {
    if (SidsUse[Traces[k].sid] == 0)
      continue;
    switch (Traces[k].event) {

    case TCP_EVENT_OUT:
      last_time = Traces[k].time;
      break;
    case TCP_EVENT_DUP:
      break;
    case TCP_EVENT_OUT1:
      SndTraces[NumPacketsSent].time = last_time;
      SndTraces[NumPacketsSent].sid = Traces[k].sid;
      len = SndTraces[NumPacketsSent].len = Traces[k].data;
      seq = SndTraces[NumPacketsSent].seq = Traces[k].time;
      SndTraces[NumPacketsSent++].flags = 0;
      if (NumPacketsSent > MAX_NUM_PACKETS) {
	printf("ERROR: MAX_NUM_PACKETS < NumPacketsSent\n");
	exit(1);
      }
      if (Traces[k-1].event == TCP_EVENT_DUP) {
	int flg=0;
	SndTraces[NumPacketsSent-1].flags |= F_RESEND;
	dups_cnt++;
	dups_bytes += len;
	for (j=NumPacketsSent-2; j>=0; j--) {
	  if (SndTraces[j].len == 0)
	    continue;
          if (seq >= SndTraces[j].seq &&
	      seq < SndTraces[j].seq+SndTraces[j].len-24 && len >= 32) {
/*        if (seq < SndTraces[j].seq+SndTraces[j].len &&
              seq+len >= SndTraces[j].seq+SndTraces[j].len) { */
	    SndTraces[j].flags |= F_LOST;
	    lost_cnt++;
	    lost_bytes += SndTraces[j].len;
	    flg = 1;
	  }
	  else if (flg && (seq > SndTraces[j].seq))
	    break;
	}
      }
      break;
    case TCP_EVENT_IN:
      last_time = Traces[k].time;
      break;
    case TCP_EVENT_IN1:
      ack = Traces[k].time;
      for (j=NumPacketsSent-1; j>=0; j--) {
	if (ack >= (SndTraces[j].seq + SndTraces[j].len)) {
	  if (SndTraces[j].time_rcvd_ack == 0  &&  
	      !(SndTraces[j].flags & F_LOST)) {
	    SndTraces[j].time_rcvd_ack = last_time;
	    break;
	  }
	  else if (SndTraces[j].time_rcvd_ack != 0 &&
		   !(SndTraces[j].flags & F_RESEND))
	    break;
	}
      }
      break;
    case TCP_EVENT_BADSUM:
      BadsumN++;
      break;
    case TCP_EVENT_DROP:
      DropN++;
      break;
    case TCP_EVENT_TIMER:
      if (Traces[k].data == 0) RexmtN++;
      if (Traces[k].data == 1) PersistN++;
      if (Traces[k].data == 2) KeepN++;
      if (Traces[k].data == 3) MslN++;
      break;
    case TCP_EVENT_SET_TO:
      rttCnt++;
      rttSum += Traces[k].data;
      if (last_time-rttLast > rttMaxTime) 
	rttMaxTime = last_time - rttLast;
      rttLast = last_time;
      if (Traces[k].data > rttMax)
	rttMax = Traces[k].data;
      if (Traces[k].data < rttMin)
	rttMin = Traces[k].data;
      break;
    default:
      ;
    }
  }

  for (k=0; k<nt; k++) {
    if (SidsUse[Traces[k].sid] == 0)
      continue;
    switch (Traces[k].event) {

    case TCP_EVENT_IN:
      last_time = Traces[k].time;
      len = Traces[k].data;
      seq = Traces[++k].time;
      opt_len = 0;
      if (IS_ACK(Traces[++k].data))
	ack = Traces[k].time;
      else
	ack = -1;
      flags = (int)Traces[k].data;
      RcvTraces[NumPacketsRcvd].time = last_time;
      if (len > 0  &&  seq <= max_beg_seq_rcvd) {
	for (j=NumPacketsRcvd-1; j>=0; j--) {
	  if (RcvTraces[j].flags & F_DUPRCV)
	    break;
	  if (seq <= RcvTraces[j].seq  &&  seq+len >= RcvTraces[j].seq) {
	    RcvTraces[j].flags |= F_DUPRCV;
	    dup_cnt++;
	    dup_rcvd_bytes += RcvTraces[j].len;
	  }
	  else if (seq > RcvTraces[j].seq)
	    break;
	}
      }
      else
	max_beg_seq_rcvd = seq;
      break;
    case TCP_EVENT_ROPT:
      opt_len = Traces[k].time;
      break;
    case TCP_EVENT_IN0:
      RcvTraces[NumPacketsRcvd].sid = Traces[k].sid;
      RcvTraces[NumPacketsRcvd].time = last_time;
      RcvTraces[NumPacketsRcvd].seq = seq;
      RcvTraces[NumPacketsRcvd].len = len-opt_len;
      RcvTraces[NumPacketsRcvd].flags = flags;
      RcvTraces[NumPacketsRcvd++].ack = ack;
      bytes_rcvd += len-opt_len;
      break;
    default:
      ;
    }
  }

if (debug_flag) {
     printf("Num Packets Sent %d\n",NumPacketsSent);
     printf("Num Packets Rcvd %d\n",NumPacketsRcvd);
}

  if (Pflags[1]) {
    P0("\n"); 
    P1("... %4d packets rcvd\n", NumPacketsRcvd); 
    P1("... %4d duplicate packets rcvd\n", dup_cnt); 
    P1("... %4d KB received in non dup packets\n", bytes_rcvd/1024); 
    P1("... %4d KB received in dup packets\n", dup_rcvd_bytes/1024); 
    P1("... %4d packets received with bad checksum\n", BadsumN); 
    P1("... %4d packets dropped\n", DropN); 
    P1("... %4d REXMT   timeouts\n", RexmtN); 
    P1("... %4d PERSIST timeouts\n", PersistN); 
    P1("... %4d KEEP    timeouts\n", KeepN); 
    P1("... %4d 2MSL    timeouts\n", MslN); 
  }

  if (Pflags[3]  &&  stat_flag  &&  stat_size == sizeof(struct tcpstat)) {
    P0("TCP STATISTICS\n"); 
    P1("  Badsum:  %4d\n", TcpStat.tcps_rcvbadsum); 
    P1("  Badoff:  %4d\n", TcpStat.tcps_rcvbadoff); 
    P1("  Short:   %4d\n", TcpStat.tcps_rcvshort); 
    P1("  Unack:   %4d\n", TcpStat.tcps_unack); 
    P1("  Rtt seg: %4d\n", TcpStat.tcps_segstimed); 
    P1("     succ: %4d\n", TcpStat.tcps_rttupdated); 
    P1("  RXMT to: %4d\n", TcpStat.tcps_rexmttimeo); 
    P1("  PERS to: %4d\n", TcpStat.tcps_persisttimeo); 
    P1("  KEEP to: %4d\n", TcpStat.tcps_keeptimeo); 
    P1("  KEEP probes:           %4d\n", TcpStat.tcps_keepprobe); 
    P1("  Packets retransmitted: %4d\n", TcpStat.tcps_sndrexmitpack); 
    P1("  KB retransmited:       %4d\n", TcpStat.tcps_sndrexmitbyte/1024); 
    P1("  Dup packets rcvd:      %4d\n", TcpStat.tcps_rcvduppack); 
    P1("  Dup KB rcvd:           %4d\n", TcpStat.tcps_rcvdupbyte/1024); 
    P1("  Out of order packets:  %4d\n", TcpStat.tcps_rcvoopack); 
  }

  if (Pflags[4]) {
    if (NumPacketsSent > 1) {
      P3("\nLost   %d packets out of %d (%.1f KB)\n", lost_cnt,  
 	     NumPacketsSent, lost_bytes/1024.0); 
      P3("Resent %d packets out of %d (%.1f KB)\n", dups_cnt,  
 	     NumPacketsSent, dups_bytes/1024.0); 
    }
    if (NumPacketsRcvd > 1) {
      P3("\nReceived %d duplicate pks out of %d (%.1f KB)\n", 
 	     dup_cnt, NumPacketsRcvd, dup_rcvd_bytes/1024.0); 
    }
  }

  if (1) {
    if (Pflags[5]) 
      printf("\n*****  Sender Info:\n"); 
    if (Pflags[6])
      printf("\n pk time (ms)\n--- -----\n");

    INIT_COMP(smin,smax,savg);
    INIT_COMP(rmin,rmax,ravg);
    for (k=1; k<NumPacketsSent; k++) {
      if (SidsUse[Traces[k].sid] == 0)
        continue;
      if (SndTraces[k].time_rcvd_ack > 0) {
	DO_COMP(SndTraces[k].time_rcvd_ack, SndTraces[k].time,
		rmin, rmax, ravg);
        rttCur = SndTraces[k].time_rcvd_ack - SndTraces[k].time;
        if (rttCur/50 < 498)
          rHisto[(rttCur + 25)/50]++;
        rminCnt++;
        sdSumXX += rttCur*rttCur;
        sdSumX += rttCur;
        sdCnt++;
      }
      DO_COMP(SndTraces[k].time, SndTraces[k-1].time, smin, smax, savg);
      if (Pflags[5])
	if (SndTraces[k].time_rcvd_ack <= 0) 
	  printf("  "); 
	else if (SndTraces[k].time_rcvd_ack < SndTraces[k-1].time_rcvd_ack) 
	  printf(". "); 
	else 
	  printf("  "); 
      if (Pflags[6])
	printf("%3d %5d\n", k, SndTraces[k].time); 
      if (Pflags[5]) {
	printf("pk: %3d, seq: %7d, len: %4d, t: %5d, rack: %5d, rtt: ", 
	       k, SndTraces[k].seq, SndTraces[k].len, SndTraces[k].time,  
	       SndTraces[k].time_rcvd_ack);
	if (SndTraces[k].time_rcvd_ack > 0) 
	  printf("%5d", SndTraces[k].time_rcvd_ack - SndTraces[k].time); 
	else
	  printf("     ");
	if (SndTraces[k].flags & F_LOST) 
	  printf(" L"); 
	else 
	  printf("  "); 
	if (SndTraces[k].flags & F_RESEND) 
	  printf(" R"); 
	else 
	  printf("  ");
	printf("  %3d\n", SndTraces[k].sid);
      }
    }
    P3("\nFor transmiting delta times, Min: %4d, Max: %4d, Ave: %4d\n\n",
	   smin, smax, savg/(NumPacketsSent-1));
    if (rttCnt > 0) {
      P3("For round trip times,        Min: %4d, Max: %4d, Ave: %4d\n",
	 rttMin, rttMax, rttSum/rttCnt);
      P2("Number of times rtt was calculated: %d (out of %d sends)\n",
	 rttCnt, NumPacketsSent);
      P1("Largest elapsed time between rtt calcuations: %d\n\n", rttMaxTime);
    }
    else if (rminCnt > 0) {
      sd = sqrt((sdCnt*sdSumXX - sdSumX*sdSumX))/sdCnt;
      P4("For round trip times,        Min:%4d, Max:%4d, Ave:%4d, SD:%.1f\n\n",
         rmin, rmax, ravg/rminCnt, sd);
      if (p_flag) {
        int i1, i0;
        for (i1=499; i1>0; i1--)
          if (rHisto[i1] > 0)
            break;
        for (i0=0; i0<500; i0++)
          if (rHisto[i0] > 0)
            break;
        for (i=i0; i<=i1; i++)
          printf("rtt %4d - %4d   cnt %4d\n", i*50, (i+1)*50, rHisto[i]);
      }
    }
  }

  if (Pflags[6])
    exit(0);

  if (Pflags[7]) {
    P0("\n\n*****  Receiver Info:\n");
    INIT_COMP(smin,smax, savg);
    if (NumPacketsRcvd > 0) {
      P4("  pk: %3d, s:%7d, l: %4d, t:%6d\n",
	     0, RcvTraces[0].seq, RcvTraces[0].len, RcvTraces[0].time);
    }
    for (k=1; k<NumPacketsRcvd; k++) {
      if (SidsUse[Traces[k].sid] == 0)
        continue;
      DO_COMP(RcvTraces[k].time, RcvTraces[k-1].time, smin, smax, savg);
      P4("  pk: %3d, s:%7d, l: %4d, t:%6d",
	 k, RcvTraces[k].seq, RcvTraces[k].len, RcvTraces[k].time);
      if (RcvTraces[k].ack > 0)
	P2(", a:%7d al:%5d ", RcvTraces[k].ack, 
	   RcvTraces[k].ack-RcvTraces[k-1].ack);
      else 
	P0("                      ");
      if (RcvTraces[k].flags & F_DUPRCV)
	P0(" D");
      else
	P0("  ");
      P1(" %s", flags2str(RcvTraces[k].flags, 1));
      P1("   %3d\n", RcvTraces[k].sid);
    }
    P3("\nFor receiving delta times,   Min: %4d, Max: %4d, Ave: %4d\n",
	   smin, smax, savg/(NumPacketsRcvd-1));
  }
  
  if (Pflags[8]) {
    printf("DISP %4d\n", TcpStat.tcps_rcvtotal-TcpStat.tcps_rcvduppack);
    printf("DUPP %4d\n", TcpStat.tcps_rcvduppack);
    exit(0); 
  }

#endif		/***********************************  END INCLUDE_2 */


#ifdef INCLUDE_3  /***********************************  BEGIN INCLUDE_3 */
#undef INCLUDE_3

  P0("\n\n*****  Event Info:\n"); 
  P1("       Number of events: %d\n", nt);

  for (k=0; k<nt; k++) {
    /* if (SidUse != 0  &&  Traces[k].sid != 0  &&  Traces[k].sid != SidUse) */
    if (SidsUse[Traces[k].sid] == 0)
      continue;
    switch(Traces[k].event) {
      
    case TCP_EVENT_IN:
      time = Traces[k].time;
/*       printf(" i  %6d ", time); */
      k++;
      seq = Traces[k].time;
      win = (int)Traces[k].data;
      k++;
      flags = (int)Traces[k].data;
      cp = flags2str(flags, 0);
      ack = Traces[k].time;
      cc = ' ';

      if (Traces[k+1].event == TCP_EVENT_ROPT) {
	if (Traces[k+3].event == TCP_EVENT_IN1) {
	  if (IS_ACK(flags)  &&  loss_mode > 0) {
	    if ((j = Traces[k+3].data) == 0)
	      cc = 'D';
 	    P4(" i%c  %6d %7d   %6d", cc, time, ack, j); 
	  }
	  else
	   ;
	  k += 3;
	}
	else {
	  if (IS_ACK(flags)  &&  loss_mode > 0)
 	    P2(" iD  %6d %7d         ", time, ack); 
	  else
	    ;
	  k++;
	}
      }
      else {
	if (Traces[k+2].event == TCP_EVENT_IN1) {
	  if (IS_ACK(flags)  &&  loss_mode > 0)
 	    P3(" i   %6d %7d   %6d", time, ack, (int)Traces[k+2].data);
	  else
	    ;
	  k += 2;
	}
	else {
	  if (IS_ACK(flags) &&  loss_mode > 0)
 	    P2(" iD  %6d %7d         ", time, ack); 
	  else
	    ;
	}
      }
      if (IS_ACK(flags)  &&  loss_mode > 0) {
	if (Traces[k+1].event == TCP_EVENT_SET_TO) {
	  P2("  (%d, %d)\n", Traces[k+1].data, Traces[k+1].time);
	}
	else
	  P0("\n");
      }
      break;
    case TCP_EVENT_BADSUM:
      break;
    case TCP_EVENT_ROPT:
      break;
    case TCP_EVENT_IN0:
      break;
    case TCP_EVENT_IN1:
      break;
    case TCP_EVENT_DROPAA:
      break;
    case TCP_EVENT_DROPWR:
      break;
    case TCP_EVENT_DROP:
      break;
    case TCP_EVENT_DUP:
      break;
    case TCP_EVENT_OUT:
      time = Traces[k].time;
      break;
    case TCP_EVENT_OUT0:
      k += 2;
      break;      
    case TCP_EVENT_OUT1:
      timeLastSend = time;
      if (Traces[k].time > largestSeq)
	largestSeq = Traces[k].time;
      if (SndTraces[pn].flags & F_LOST) {
	Lit[LitN].pn = pn;
	Lit[LitN].seq = Traces[k].time;
	Lit[LitN].time_sent = time;
	Lit[LitN].flags |= F_LOST;
	if (loss_mode == 0)
	  Lit[LitN].flags |= F_BEG_GROUP;
      }
      if (Traces[k-1].event == TCP_EVENT_DUP) {
	if (SndTraces[pn].flags & F_LOST) {
 	  P0(" sDL"); 
	  Lit[LitN].flags |= F_DUP;
	  for (kk=LitN-1; kk>=0; kk--)
	    if (Lit[kk].seq == Traces[k].time) {
	      Lit[kk].time_resent = time;
	      break;
	    }
	}
	else {
 	  P0(" sD "); 
	  for (kk=LitN-1; kk>=0; kk--)
	    if (Lit[kk].seq == Traces[k].time) {
	      Lit[kk].time_resent = time;
	      break;
	    }
	  if (loss_mode > 0) {
	    loss_mode--;
	    if (loss_mode <= 0) {
	      Lit[LitN].flags |= F_END_GROUP;
	      Lit[LitN].pn = pn;
	      Lit[LitN].seq = largestSeq;
	      Lit[LitN++].time_sent = time;
 	      P3(" %6d %7d   %6d\n..........\n", time, Traces[k].time, 
 		     (int)Traces[k].data); 
	    }
	  }
	}
      }
      else if (SndTraces[pn].flags & F_LOST) {
 	P0(" sL "); 
	loss_mode++;
      }
      else if (loss_mode > 0)
 	P0(" s  "); 
      if (loss_mode > 0)
 	P3(" %6d %7d   %6d\n", time, Traces[k].time, (int)Traces[k].data); 
      if (SndTraces[pn].flags & F_LOST) 
	LitN++;
      pn++;
      break;
    case TCP_EVENT_FAST_TO:
      if (loss_mode > 0)
 	P1("+    %6d  Fast Timeout\n", Traces[k].time); 
      break;
    case TCP_EVENT_SLOW_TO:
      if (loss_mode > 0)
 	P1("-    %6d  Slow Timeout\n", Traces[k].time); 
      break;
    case TCP_EVENT_TIMER:
      P2("T    %6d type: %s\n", 
 	     Traces[k].time, timer2str((int)Traces[k].data)); 
      if (Traces[k].data == 0) {
	Lit[LitN].flags |= F_RXMT_RESEND;
	Lit[LitN].pn = pn;
	Lit[LitN].time_sent = Traces[k].time;
	Lit[LitN++].time_resent = Traces[k].time - timeLastSend;
      }
      break;
    case TCP_EVENT_OPEN:
      break;
    case TCP_EVENT_OPEN0:
      break;
    case TCP_EVENT_OPEN1:
      break;
    case TCP_EVENT_PUSH:
      if (0  &&  loss_mode > 0) 
	printf(" P  %6d     %4d\n",
	       Traces[k].time, (int)Traces[k].data);
      break;
    case TCP_EVENT_PUSHW:
    case TCP_EVENT_PUSHA:
    case TCP_EVENT_PUSHEC:
    case TCP_EVENT_PUSHEO:
    case TCP_EVENT_CTL_PUSH:
    case TCP_EVENT_CTL_NDUP:
    case TCP_EVENT_CTL_SSN:
    case TCP_EVENT_SET_TO:
      break;
    case TCP_EVENT_WSND:
      P2("W    %s val: %d\n", "      ", Traces[k].data);
      break;
    default:
      printf("*          (%d) UNKNOWN EVENT *********\n", Traces[k].event);
    }
  }

#endif 	/***********************************  END INCLUDE_3 */


