/*
 * Parse an event log from reno/traceroute
 * NB: this must be run on the same archetecture as reno/traceroute
 * (Byte order and word size are not corrected)
 */
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>

#include <netinet/in.h>

#define NOERROR(val,msg) {if (((int)(val)) < 0) {perror(msg);exit(1);}}
#define NOTNULL(val,msg) {if (!(val)) {fprintf(stderr,msg);exit(1);}}
#define USEC(st,fi) (((fi)->tv_sec-(st)->tv_sec)*1000000+ \
                ((fi)->tv_usec-(st)->tv_usec))

char usage[] = "Usage: showev [<switch> [<val>]]*\n\
    -v [<level>] Verbose\n";
#define EVSHIFT 24
#define EVMASK  0xFFFFFF
#define EVRING  1024

long eventbuff[EVRING];
long *evp = eventbuff, *lastev = eventbuff;
int infd, eof=0;
long getev(){
  static int len = sizeof(eventbuff);

  while (evp == lastev) {
    if (len != sizeof(eventbuff)) {
      eof = 1;
      return(0);	/* cheat */
    }
    len = read(infd, eventbuff, sizeof(eventbuff));
    NOERROR(len, "Read eventbuff");
    evp = &eventbuff[0];
    lastev = &eventbuff[len/sizeof(long)];
  }
  return (ntohl(*evp++));
}

main(argc, argv)
     char *argv[];
{
  char *sv, **av = argv;
  int verbose=0;
  int newmtu = 0;

  FILE *xgf;
  long priortime, elapsedtime = -1;
  
  /* general switch cracker */
  argc--, av++;
  while (argc > 0 && *av[0] == '-') {
    sv = *av++; argc--;
    while (*++sv) switch (*sv) {
    case 'v':
      if ((argc > 0) && isdigit(*av[0])) {
	verbose = atoi(*av++);
	argc--;
      } else
	verbose++;
      break;
punt:
      printf(usage);
      printf("Invalid argument to -%c\n", *sv);
      exit(1);
    default:
      printf(usage);
      printf("Unknown switch: -%c\n", *sv);
      exit(2);
    }
  }

  if (argc == 0) {
    printf("Using file event.log\n");
    infd=open("event.log", O_RDONLY, 0);
  } else if (argc == 1) {
    infd=open(*av++, O_RDONLY, 0);
  } else {
    printf(usage);
    printf("You may supply only one file name\n");
    exit(2);
  }
  NOERROR(infd, "showev");

  /* XXX */
  NOTNULL(xgf = fopen("plot.dat", "w"), "open plot.dat\n");

  /* loop through all events */
  while (!eof) {
    struct timeval start, stamp;
    char event;
    long value;

    value = getev();
    event = (value >> EVSHIFT) & 0xFF;
    value &= EVMASK;
    switch (event) {

    case 'T':	/* Time stamp */
    case 'L':	/* Log stamp */
      priortime = elapsedtime;
      if (start.tv_sec) {
	stamp.tv_sec = value;
	stamp.tv_usec = getev();
	elapsedtime = USEC(&start, &stamp);
      } else {
	start.tv_sec = value;
	start.tv_usec = getev();
	elapsedtime = 0;
      }
      if (event == 'L') {
	if (verbose >= 5) printf("L took %d uS\n", elapsedtime-priortime);
      }
      break;

    /* Window adjustments w/ reason */
    case '?':
    case 't':
    case 'R':
    case 'r':
    case 'd':
    case 'e':
    case 'a':
      if (verbose >= 2) putchar(event);
      if (verbose >= 6) printf(" %d\n", value);
      if (newmtu) {
	fprintf(xgf, "%f %d\n", elapsedtime/1000000.0 - 1.0, 0);
	fprintf(xgf, "%f %d\n", elapsedtime/1000000.0 - 1.0, newmtu * 1000);
	fprintf(xgf, "%f %d\n", elapsedtime/1000000.0, 0);
	newmtu = 0;
      }
      fprintf(xgf, "%f %d\n", elapsedtime/1000000.0, value);
      break;

    case 'O':
    case 'I':
      if (verbose >= 4) putchar(event);
      if (verbose >= 8) printf(" %d\n", value);
      break;

    case 'A':	/* Address */
      {
	long a = getev();
	u_char *pa = (u_char *) &a;
	if (verbose >= 1) printf("hop %d (%d.%d.%d.%d)\n",
				 value, pa[0], pa[1], pa[2], pa[3]);
      }
      break;

    case 'H':	/* hop (mtu) */
      fprintf(xgf, "%f %d\n", elapsedtime/1000000.0, 0);
      newmtu = value;
/*      fprintf(xgf, "\n%c hop %d\n", '"', value); */
      break;

    case 'V':	/* Version */
    case 0:	/* padd */
      break;

    default:
      printf("Unknown event: %c %d (%f)\n", event, value, elapsedtime/1000000.0);
    }

  }
}
