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

#define INCLUDE_0
#include "dt_common.c"

#ifndef xFree
void xFree(a) char *a; {}
#endif

void xAssertPrint(s, n) char *s; int n; {}

main (argc, argv)
  int  argc;
  char *argv[];
{
#define INCLUDE_1
#include "dt_common.c"
int next_sec=1000;
int ts, ol, hd;
int inSeqBase=-1, outSeqBase=-1;
int firstAck=1, rcvCnt=0;

  for (k=1; k<argc; k++) {
    if (!strcmp(argv[k], "-r")) 
      rcv_only_flag = 1;
    else if (!strcmp(argv[k], "-rs"))
      rcv_summary_flag = 1, rcv_only_flag = 1;
    else if (!strcmp(argv[k], "-s"))
      stat_flag = 1;
    else if (!strcmp(argv[k], "-d"))
      debug_flag = 1;
    else if (!strcmp(argv[k], "-t"))
      fix_time_flag = 0;
  }

  if (rcv_only_flag  &&  !rcv_summary_flag) {
    Pflags[1] = 1;
    Pflags[3] = 1;
    Pflags[7] = 1;
  }
  else if (!rcv_summary_flag) {
    Pflags[0] = 1;
    Pflags[1] = Pflags[3] = Pflags[5] = Pflags[7] = 1;
  }
  if (rcv_summary_flag) {
    Pflags[8] = 1;
  }

#define INCLUDE_2
#include "dt_common.c"

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

  for (k=0; k<nt; k++) {
    if (SidsUse[Traces[k].sid] == 0)
      continue;
    switch(Traces[k].event) {
      char str2[500];
      int  state, rcv_nxt, last_ack;
      
    case TCP_EVENT_IN:
      if (Traces[k].time > next_sec) {
	if (Traces[k].time >= (next_sec + 1000))
	  next_sec = (Traces[k].time/1000)*1000;
	printf(".......... %d sec\n", next_sec/1000);
	next_sec += 1000;
      }
      time = Traces[k].time;
      len = Traces[k].data;
      sprintf(str, " i  %6d     %4d   ",
	     Traces[k].time, Traces[k].data);
      k++;
      seq = Traces[k].time;
      if (inSeqBase < 0)
        inSeqBase = seq;
      seq -= inSeqBase;
      win = ((int)Traces[k].data)<<winScale;
      k++;
      flags = (int)Traces[k].data;
      cp = flags2str(flags, 0);
      ack = Traces[k].time;

      if (firstAck)
        firstAck = 0;
      else if (outSeqBase < 0)
        outSeqBase = ack;
      ack -= outSeqBase;
      if (Traces[k+1].event == TCP_EVENT_BADSUM) {
        printf("%s BAD CHECKSUM\n", str);
        break;
      }
      ol = -1;
      hd = 0;
      str2[0] = '\0';
      if (Traces[k+1].event == TCP_EVENT_ROPT)
        ol = Traces[++k].time;
      while (Traces[k+1].event == TCP_EVENT_OTHER9) {
        k++;
        if (Traces[k].data == 0)
          sprintf(str2+strlen(str2),
                  "           OPT- MAX_SEG:   %d\n", Traces[k].time);
        else if (Traces[k].data == 1)
          sprintf(str2+strlen(str2),
                  "           OPT- TIMESTAMP: %d\n", Traces[k].time);
        else if (Traces[k].data == 2)
          sprintf(str2+strlen(str2),
                  "           OPT- BIG WIN:   %d\n", Traces[k].time);
        else if (Traces[k].data == 3)
          sprintf(str2+strlen(str2),
                  "           OPT- SACKS:     %d\n", Traces[k].time);
        else if (Traces[k].data == 4)
          sprintf(str2+strlen(str2),
                  "           RXMT TO:        %d\n", Traces[k].time);
        else if (Traces[k].data == 5) {
          sprintf(str2+strlen(str2),
                  "           PREDICTION:     %d\n", Traces[k].time);
          hd = 1;
        }
      }
      if (Traces[k+1].event == TCP_EVENT_IN0) {
        k++;
        state = Traces[k].data;
        rcv_nxt = Traces[k].time-inSeqBase;
        rcvCnt++;
      }
      if (Traces[k+1].event == TCP_EVENT_IN1) {
        k++;
	if (IS_ACK(flags)) {
	  if (Traces[k].data == 0 && len == 0)
	    str[2] = 'D';
          printf("%s%7d  %5d  %6d   ", str, ack, (int)Traces[k].data,
                 rcv_nxt);
          if (ol > 0)
            printf("ol:%2d  %6d  ", ol, seq);
	  else 
	    printf("       %6d  ", seq);
	}
	else {
          printf("%s             %6d   ", str, rcv_nxt);
          if (ol > 0)
            printf("ol:%2d  %6d  ", ol, seq);
	  else
	    printf("       %6d  ", seq);
	}
      }
      else {
        if (IS_ACK(flags)) {
/*
	  if (RcvTraces[rcvCnt].flags & F_DUPRCV)
            str[2] = 'd';
          if (Traces[k+1].event != TCP_EVENT_OTHER9 || Traces[k+1].data != 5)
            str[2] = 'd';
*/
          if (rcv_nxt > seq  ||  (len == 0  &&  ack-last_ack == 0))
            str[2] = 'd';
          printf("%s%7d  %5d  %6d   ", str, ack, ack-last_ack,
                 rcv_nxt);
          if (ol > 0)
            printf("ol:%2d  %6d  ", ol, seq);
	  else
	    printf("       %6d  ", seq);
	}
	else {
	  printf("%s               %6d   ", str, rcv_nxt);
	  if (ol > 0)
	    printf("ol:%2d  %6d  ", ol, seq);
	  else
	    printf("       %6d  ", seq);
	}
      }
      if (rcv_nxt > seq)
        printf("<");
      else if (rcv_nxt < seq)
        printf(">");
      else
        printf(" ");
      printf(" %s\n", cp);
      if (str2[0] != '\0')
        printf(str2);
      last_ack = ack;
      break;
    case TCP_EVENT_BADSUM:
      printf("*          Bad sum\n");
      break;
    case TCP_EVENT_ROPT:
/*       printf("    Option  l: %-4d\n",  */
/* 	     Traces[k].time); */
      break;
    case TCP_EVENT_OTHER9:
      if (Traces[k].data == 0)
        printf("           OPT- MAX_SEG:   %d\n", Traces[k].time);
      else if (Traces[k].data == 1)
        printf("           OPT- TIMESTAMP: %d\n", Traces[k].time);
      else if (Traces[k].data == 2)
        printf("           OPT- BIG WIN:   %d\n", Traces[k].time);
      else if (Traces[k].data == 3)
        printf("           OPT- SACKS:     %d\n", Traces[k].time);
      else if (Traces[k].data == 4) {
        int rxtcur, rtt, srtt, rttvar, v=Traces[k].time;
        rxtcur = v&0xff;
        rtt = (v&0xff00)>>8;
        srtt = (v&0xff0000)>>16;
        rttvar = (v&0xff000000)>>24;
        printf("           RXMT TO:        %d, rtt=%d, srtt=%d, rttvar=%d\n",
       rxtcur, rtt, srtt, rttvar);
      }
      else if (Traces[k].data == 5)
        printf("           PREDICTION:     %d\n", Traces[k].time);
      else if (Traces[k].data == 6)
        winScale = Traces[k].time;
      break;
    case TCP_EVENT_IN0:
/*       printf(" i         rnxt: %-4d  state: %s\n",  */
/* 	     Traces[k].time, */
/* 	     state2str((int)Traces[k].data)); */
      break;
    case TCP_EVENT_IN1:
      printf(" i         a:%-7d la:%-4d\n", 
	     Traces[k].time, (int)Traces[k].data);
      break;
    case TCP_EVENT_DROPAA:
      printf("*         Dropping after ack  flags: %s\n", 
	     flags2str(Traces[k].time, 0));
      break;
    case TCP_EVENT_DROPWR:
      printf("*         Dropping with reset flags: %s\n",
	     flags2str(Traces[k].time, 0));
      break;
    case TCP_EVENT_DROP:
      printf("*         Dropping packet     flags: %s\n",
	     flags2str(Traces[k].time, 0));
      break;
    case TCP_EVENT_DUP:
      break;
    case TCP_EVENT_OUT:
      if (Traces[k].time > next_sec) {
	if (Traces[k].time >= (next_sec + 1000))
	  next_sec = (Traces[k].time/1000)*1000;
	printf(".......... %d sec\n", next_sec/1000);
	next_sec += 1000;
      }
      printf(" O  %6d ", Traces[k].time);
      cp = state2str((int)Traces[k].data);
      if (Traces[k+1].event == TCP_EVENT_OUT0) {
        seq = Traces[k+3].time;
        if (outSeqBase < 0)
          outSeqBase = seq;
        seq -= outSeqBase;
	printf(" (%6d) [%7d,%6d] {%5d | %5d | %5d}     ",
	       Traces[k+1].time, seq, Traces[k+2].time-Traces[k+3].time,
	       ((int)Traces[k+1].data)<<winScale,
	       ((int)Traces[k+2].data)<<winScale,
	       ((int)Traces[k+3].data)<<winScale);
	k += 3;
      }
      else 
	printf("                                                     ");
      printf("%s\n", cp); 
      break;
    case TCP_EVENT_OUT0:
      seq = Traces[k+2].time;
      if (outSeqBase < 0)
        outSeqBase = seq;
      seq -= outSeqBase;
      printf(" o          (%6d) [%7d,%6d]",
	     Traces[k].time, seq, Traces[k+1].time-Traces[k+2].time);
      printf(" {%5d | %5d | %5d}\n",
	     (int)Traces[k].data<<winScale, (int)Traces[k+1].data<<winScale,
             (int)Traces[k+2].data<<winScale);
      k += 2;
      break;      
    case TCP_EVENT_OUT1:
      if (Traces[k-1].event == TCP_EVENT_DUP) {
	printf(" sD");
	if (SndTraces[pn].flags & F_LOST)
	  printf("L");
	else
	  printf(" ");
      }
      else {
	printf(" s");
	if (SndTraces[pn].flags & F_LOST)
	  printf("L ");
	else
	  printf("  ");
      }
      printf("                  %7d   %4d",
	     Traces[k].time-outSeqBase, (int)Traces[k].data);
      if (SndTraces[pn].flags & F_LOST  ||  SndTraces[pn].flags & F_RESEND) {
	printf("                         ");
	if (SndTraces[pn].flags & F_LOST)
	  printf("*L ");
	else
	  printf("*  ");
	if (SndTraces[pn].flags & F_RESEND)
	  printf("R*\n");
	else
	  printf(" *\n");
      }
      else
	printf("\n");
      pn++;
      break;
    case TCP_EVENT_FAST_TO:
      printf("+   %6d  Fast Timeout\n",
	     Traces[k].time);
      break;
    case TCP_EVENT_SLOW_TO:
      printf("-   %6d  Slow Timeout\n",
	     Traces[k].time);
      break;
    case TCP_EVENT_TIMER:
      printf("T   %6d type: %s\n",
	     Traces[k].time, timer2str((int)Traces[k].data));
      break;
    case TCP_EVENT_OPEN:
      printf("O+  %6d rport: %d\n",
	     Traces[k].time, (int)Traces[k].data);
      break;
    case TCP_EVENT_OPEN0:
      printf("*         Connect failed     lport: %d\n",
	     (int)Traces[k].data);
      break;
    case TCP_EVENT_OPEN1:
      printf("O-         lport: %d\n",
	     (int)Traces[k].data);
      break;
    case TCP_EVENT_PUSH:
      printf(" P  %6d     %4d\n",
	     Traces[k].time, (int)Traces[k].data);
      break;
    case TCP_EVENT_PUSHW:
      printf("B              %4d space:%-4d\n",
	     Traces[k].time, (int)Traces[k].data);
      break;
    case TCP_EVENT_PUSHA:
      printf("U   %6d\n", 
	     Traces[k].time);
      break;
    case TCP_EVENT_PUSHEC:
      printf("*         Session already closed\n");
      break;
    case TCP_EVENT_PUSHEO:
      printf("*         Tcp_output failed with error code: %d\n", 
	     Traces[k].time);
      break;
    case TCP_EVENT_CTL_PUSH:
      printf(" c  %6d Ctrl op - push\n",
	     Traces[k].time);
      break;
    case TCP_EVENT_CTL_NDUP:
      printf(" c         Ctrl op - set rxmt threshold: %d\n", Traces[k].time);
      break;
    case TCP_EVENT_CTL_SSN:
      printf(" c         Ctrl op - set slow start packet no: %d\n", 
	     Traces[k].time);
      break;
    case TCP_EVENT_SET_TO:
      printf("           rtt: %4d  timeout: %4d\n", Traces[k].data,
	     Traces[k].time);
      break;
    case TCP_EVENT_WSND:
      printf(" W         len: %4d  worried: %d\n", Traces[k].time,
	     Traces[k].data);
      break;
    case TCP_EVENT_RCWND:
      if (Traces[k].data == TCP_NOTE_DUPACK)
	c = 'd';
      else
	c = 'w';
      P2("R%c        last_sent: %d\n", c, Traces[k].time);
      break;
    case TCP_EVENT_RTO:
      P2("RT        new to: %d, old to: %d\n", Traces[k].time, Traces[k].data);
      break;
    case TCP_EVENT_OTHERa:
      if (Traces[k].data == 1) {
        P1("<r>       doing rate send, o7: %d\n", Traces[k].time);
      }
      else if (Traces[k].data == 0) {
        P1("<r>       rate send cancelled, o7: %d\n", Traces[k].time);
      }
      else if (Traces[k].data >= 10) {
        P2("<R>       rate schedule at %6d, o7: %d\n", Traces[k].time,
           Traces[k].data - 10);
      }
      break;
    case TCP_EVENT_OTHER1:
    case TCP_EVENT_OTHER2:
    case TCP_EVENT_OTHER3:
    case TCP_EVENT_OTHER4:
    case TCP_EVENT_OTHER5:
    case TCP_EVENT_OTHER6:
    case TCP_EVENT_OTHER8:
/*    case TCP_EVENT_OTHER9: */
      P3("<o>       Other%d, arg1:%d, arg2:%d\n", 
	 Traces[k].event-TCP_EVENT_OTHER1+1, Traces[k].time, 
	 Traces[k].data);
      break;
    case TCP_EVENT_OTHER7:
      P3("<o>       Other%d, time:%d, VegasFlags:%d\n", 
	 Traces[k].event-TCP_EVENT_OTHER1+1, Traces[k].time, 
	 Traces[k].data);
      k++;
      P1("          exp_inc_nseg:%d\n", Traces[k].time);
      k++;
      P1("          cong_detect_top_nseg:%d\n", Traces[k].time);
      P1("          cong_detect_bot_nseg:%d\n", Traces[k].data);
      break;
    default:
      printf("*          (%d) UNKNOWN EVENT *********\n", Traces[k].event);
    }
  }
}

/* 
 * These stub routines are included to avoid linking in msg.c.
 */
void *msgWalkToughNext(cxt, len)
MsgWalk *cxt;
int     *len;
{ fprintf(stderr, "Remove this Stub for msgWalkToughNext !! \n"); exit(-1); }

void msgToughDestroy(n)
MsgNode n;
{ fprintf(stderr, "Remove this Stub for msgToughDestroy!!\n"); exit(-1); }
