tcpdump2arrival

The idea behind this program is to divide a long dump interval into subintervals and then count the number of packets which arrived in each subinterval. The program prints to stdout out the number of packets arriving in each subinterval starting at the beginning of the trace and terminating at the end. Each value is followed by an eol character.

This sequence of data values (know as an arrival process) may provide input for graphing or statistical analysis utilities, for example Dr. Burt Dempsey's suite of utilities for analyzing self-similarity (ultra_sp, rs, and norm_variance).

usage: arrivalrate [options] <inputfile>
-s <interval>  -> time interval expressed in sec
-m <interval>  -> time interval expressed in msec
-u <interval>  -> time interval expressed in usec
-o <offset>    -> offset--don't include the first n intervals
-d             -> run in debug mode (show everything)
-h             -> help--show usage
Default value for time interval is 10 msec

Since the code is quite short, it's simply listed below.

David Ott 11/27/98


/*****************************************************************************
 * ott 11/18/98 revised 11/20/98
 * 
 * input: tcpdump binary file
 * output: set of data points indicating the number of packets seen per
 *         time interval--printed to stdout
 * 
 *****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <pcap.h>
#include <net/bpf.h>
#include <net/ethernet.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

#define ERR_VAL -1
#define OK_VAL   0

void CloseFile(int fd, const char* filename);


/*****************************************************************************
 *
 * usage()
 *
 *****************************************************************************/
static void usage(void)
{
  fprintf(stderr, "usage: arrivalrate [options] <inputfile>\n");
  fprintf(stderr, "-s <interval>  -> time interval expressed in sec\n");
  fprintf(stderr, "-m <interval>  -> time interval expressed in msec\n");
  fprintf(stderr, "-u <interval>  -> time interval expressed in usec\n");
  fprintf(stderr, "-o <offset>    -> offset--don't include the first n intervals\n");
  fprintf(stderr, "-d             -> run in debug mode (show everything)\n");
  fprintf(stderr, "-h             -> show usage\n");
  fprintf(stderr, "Default value for time interval is 10 msec\n");
  exit(1);
}

/*****************************************************************************
 *
 * main
 *
 *****************************************************************************/
main(int argc, char** argv) {

  struct pcap_file_header pfh;
  struct pcap_pkthdr pph;
  char *infile;
  char ch,buf[300];
  int fd;
  int n, count;
  long interval = 10000; /* units are usec -- default 10000 usec (10 ms) */
  long start_sec, start_usec, dif_usec;
  int debug = 0;
  int offset = 0; /* no of initial data points to skip */
  int num = 0;    /* counts the number of data points */

  while ((ch = getopt(argc, argv, "s:m:u:o:dh")) != EOF) {
    switch (ch) {
    case 's':
      interval = atoi(optarg);
      interval = interval*1000000;
      break;
    case 'm':
      interval = atoi(optarg);
      interval = interval*1000;
      break;
    case 'u':
      interval = atoi(optarg);
      break;
    case 'o':
      offset = atoi(optarg);
      break;
    case 'd':
      debug = 1;
      break;
    case 'h':
    case '?':
      usage();
    }
  }
  
  if (optind < argc)
    infile = argv[optind];
  else
    usage();

  if (debug)
    printf("interval: %lu\n offset: %i\n",interval,offset);

  /* open file */
  if ( (fd = open(infile, O_RDONLY, NULL)) == -1) {
    fprintf(stderr,"Error: unable to open %s\n",infile);
    exit(ERR_VAL);
  }

  /* get pcap_file_header */
  if ( (n = read(fd, &pfh, sizeof(pfh))) == -1 ) {
    fprintf(stderr,"Error: unable to read pfh\n");
    CloseFile(fd,infile);
    exit(ERR_VAL);
  }

  if (debug) 
    printf("pfh: %x %hu %hu %i %u %u %x\n",    
	   pfh.magic,
	   pfh.version_major,
	   pfh.version_minor,
	   pfh.thiszone,
	   pfh.sigfigs,
	   pfh.snaplen,
	   pfh.linktype
	   );
  
  /* get first packet's tcpdump header */
  if ( (n = read(fd, &pph, sizeof(pph))) == -1 ) {
    fprintf(stderr,"Error: unable to read pph\n");
    CloseFile(fd,infile);
    exit(ERR_VAL);
  }
  else if (n == 0) {
    fprintf(stderr,"Error: zero bytes read into pph\n");
    CloseFile(fd,infile);
    exit(ERR_VAL);
  }

  if (debug)
    printf("pph: %lu %lu %u %u\n",
	   pph.ts.tv_sec,
	   pph.ts.tv_usec,
	   pph.caplen,
	   pph.len
           );
  
  /* throw remaining portion of packet away */
  if ( (n = read(fd, buf, pph.caplen)) == -1 ) {
    fprintf(stderr,"Error: unable to read buf\n");
    CloseFile(fd,infile);
    exit(ERR_VAL);
  }
  else if (n == 0) {
    fprintf(stderr,"Error: zero bytes read into buf\n");
    CloseFile(fd,infile);
    exit(ERR_VAL);
  }
  
  /* start set to first packet timestamp */
  start_sec  = pph.ts.tv_sec;
  start_usec = pph.ts.tv_usec;
  count = 1;  /* 1 since we are including this packet */

  if (debug)
    printf("start: %lu %lu\n", start_sec, start_usec);

  if (debug)
    printf("count: %i %lu %lu\n",
	   count,
	   start_sec,
	   start_usec);

  while (1) {

    /* get tcpdump header for next packet */
    if ( (n = read(fd, &pph, sizeof(pph))) == -1 ) {
      fprintf(stderr,"Error: unable to read pph\n");
      CloseFile(fd,infile);
      exit(ERR_VAL);
    }
    else if (n == 0) {
      fprintf(stderr,"Error: zero bytes read into pph\n");
      CloseFile(fd,infile);
      exit(ERR_VAL);
    }

    /* throw remaining portion of packet away */
    if ( (n = read(fd, buf, pph.caplen)) == -1 ) {
      fprintf(stderr,"Error: ppp unable to read buf\n");
      CloseFile(fd,infile);
      exit(ERR_VAL);
    }
    else if (n == 0) {
      fprintf(stderr,"Error: zero bytes read into buf\n");
      CloseFile(fd,infile);
      exit(ERR_VAL);
    }
    
    if (pph.ts.tv_usec < start_usec) { /* do a borrow */
      pph.ts.tv_sec--;
      pph.ts.tv_usec += 1000000;
    }
    dif_usec = (pph.ts.tv_usec - start_usec) +
               ((pph.ts.tv_sec - start_sec)*1000000);

    if (dif_usec < interval) {  /* case: packet witin interval */

      count++;

      if (debug)
	printf("count: %i %lu %lu\n",
	       count,
	       pph.ts.tv_sec,
	       pph.ts.tv_usec);
      
    } else {                   /* case: packet in some later interval */

      num++;
      if ( (num > offset) || (debug) )
	printf("%i\n",count);

      start_usec += interval;
      while (start_usec > 999999) {
	start_sec += 1;
	start_usec -= 1000000;
      }

      if (debug)
	printf("start: %lu %lu\n", start_sec, start_usec);

      count = 0;
      dif_usec = (pph.ts.tv_usec - start_usec) +
	         ((pph.ts.tv_sec - start_sec)*1000000);

      /* arbitrary number of intervals before next packet timestamp */
      while(dif_usec > interval) {

	num++;
	if ( (num > offset) || (debug) )
	  printf("%i\n",count);
	
	start_usec += interval;
	while (start_usec > 999999) {
	  start_sec += 1;
	  start_usec -= 1000000;
	}
	
	if (debug)
	  printf("start: %lu %lu\n", start_sec, start_usec);

	if (pph.ts.tv_usec < start_usec) { /* do a borrow */
	  pph.ts.tv_sec--;
	  pph.ts.tv_usec += 1000000;
	}
	dif_usec = (pph.ts.tv_usec - start_usec) +
	           ((pph.ts.tv_sec - start_sec)*1000000);
      }  

      count = 1; /* including this packet */

      if (debug)
	printf("count: %i %lu %lu\n",
	       count,
	       pph.ts.tv_sec,
	       pph.ts.tv_usec);

    }

  }

  CloseFile(fd,infile);
  exit(OK_VAL);

}

/*****************************************************************************
 *
 * CloseFile
 *
 *****************************************************************************/ 
void CloseFile(int fd, const char* filename) {

  if ( close(fd) == -1)
    fprintf(stderr,"Error: unable to close %s\n",filename);

}