/* 1100, Fri 17 Apr 98

   PKT_TRACE: Collect packet trace

   Copyright (C) 1997-2002 by Nevil Brownlee,
   ITSS Technology Development, The University of Auckland */

#include <dos.h>
#include <conio.h>
#include <alloc.h>
#include <ctype.h>
#include <errno.h>

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>

#include "..\snmplib\ausnmp.h"
#include "..\wattcp\wattcp.h"
#include "..\wattcp\pktdrv.h"

char tfname[50] = "ptrace.dat";

int target_pps = 500;  /* Default reqd packet rate */
int trace_sz = 5001;   /* Default trace size */

struct p_t {
   double s;  /* Arrival time, seconds */
   Bit16 sz;  /* Packet size, bytes */
   };

struct p_t *p_table;
int n_p = 0;  /* Nbr of packets in buffer */
int nxp = 0;  /* Index to next packet position */

int time_to_stop = 0;


void accept_pkt(unsigned int len, unsigned char far *buff, 
   unsigned int i_face, unsigned int lah_len);
void receive(void);

double s_uptime(void);  /* In trac_upt.cpp */

Bit8 *pkt_rcv_call1(Bit16 len, Bit16 lah_len, Bit8 *buff, Bit16 if_nbr)
{
   if (!time_to_stop) {
      p_table[nxp].s = s_uptime();
      p_table[nxp].sz = len;
      if (n_p != trace_sz) ++n_p;
      if (++nxp == trace_sz) nxp = 0;
      }
   return (unsigned char far *)NULL;  /* Don't bother with call2 */
   }

void pkt_rcv_call2(Bit16 len, Bit8 *buff, Bit16 if_nbr)
{
   }

void pps(void)
{
   double inter, from,to, rate;

   if (n_p != trace_sz) {
      from = p_table[0].s;
      to = p_table[n_p-1].s;
      }
   else {
      from = p_table[nxp].s;
      to = p_table[nxp == 0 ? trace_sz-1 : nxp-1].s;
      }
   inter = to-from;
   rate = (double)(n_p-1) / inter;
   printf("%d packets, %.1f s elapsed, %.0f pps\n", 
      n_p-1, inter, rate);
   if ((int)rate >= target_pps && n_p == trace_sz)
      time_to_stop = 1;
   }

char *strmov(char *d, char *s)
{
   while (*s != '\0') *d++ = *s++;
   return d;
   }

int main(int argc, char *argv[])
{
   int arg, a, c;
   char cbuf[20], *ap;
   int n_interfaces;

   if (argc == 1) {
      printf("ptrace [-p kilopackets] [-r rate] [-f tracefilename]\n");
      printf("   defaults are -p5 -r500 -fptrace.dat\n");
      exit(0);
      }

   n_interfaces = 0;
   for (arg = 1; arg < argc; ++arg) {
      if (argv[arg][0] == '-') {
         ap = argv[arg]+2;
         switch (a = argv[arg][1]) {
	 case 'f':  /* name of trace file */
	    if (*ap == '\0') ap = argv[++arg];
            ap = strmov(tfname, ap);
            *ap = '\0';
	    break;
	 case 'I':  /* IP only - no metering */
	 case 'i':  /* Just plain metering */
	 case 'h':  /* Metering with high-performance driver */
	    if (*ap == NULL) ap = argv[++arg];
            if (arg == argc) c = 0;  /* No more args */
            else c = isdigit(*ap) ? atoi(ap) : 0;  /* -h means -h0 */
	    en_table[n_interfaces].int_nbr = c;
	    if (a != 'I') en_table[n_interfaces].type =
	       a == 'h' ? EN_MT|EN_HP : EN_MT;
	    ++n_interfaces;
	    break;
	 case 'p':  /* kilopackets to collect */
	    if (*ap == '\0') ap = argv[++arg];
            trace_sz = atoi(ap)*1000 + 1;
	    break;
	 case 'r':  /* target packet rate (pps) */
	    if (*ap == '\0') ap = argv[++arg];
            target_pps = atoi(ap);
	    break;
	 default:
	    printf("Invalid option: -%c\n", argv[arg][1]);
	    exit(0);
	    }
	 }
      }
   if (n_interfaces == 0) {
      en_table[0].type= EN_MT;  n_interfaces =  1;
      }

   printf("collecting %d packets from %d interfaces\n      rate %d pps writing to %s\n",
      trace_sz-1,n_interfaces, target_pps,tfname);
   printf("   press ESC  to terminate early\n\n");
   p_table = (struct p_t *)farmalloc(trace_sz*sizeof(struct p_t));
   if (p_table == NULL) {
      printf("Couldn't allocate packet table\n");
      exit(3);
      }

   if (pkt_init())  /* Initialise just the packet driver(s) */
      exit(1);  /* Problems in starting one of the packet driver(s) */

   receive();
   return 1;  /* Keep compiler happy */
   }

double start_time;
int rec_nbr = 0;

void write_pkt_info(FILE *f, struct p_t *ptp)
{
   fprintf(f, "%.6f %u\n",  ptp->s-start_time, ptp->sz);
   if (++rec_nbr % 1000 == 0) printf(".");
   }

void write_data(void)
{
   FILE *f;
   int j;
   f = fopen(tfname, "w");
   if (f == NULL) {
      printf("couldn't open %s for write\n", tfname);
      return;
      }
   printf("file %s opened for write\n", tfname);
   if (n_p == trace_sz) {  /* Buffer full */
      start_time = p_table[nxp].s;  /* 'next' position, not written out */
      for (j = nxp+1; j != trace_sz; ++j)
         write_pkt_info(f, &p_table[j]);
      for (j = 0; j != nxp; ++j)
         write_pkt_info(f, &p_table[j]);
      }
   else {  /* Buffer not full */
      start_time = p_table[0].s;
      for (j = 1; j != n_p; ++j) {
         write_pkt_info(f, &p_table[j]);
         }
      }
   fclose(f);
   }

void receive()
{
   unsigned short k, n;
   unsigned long tot;
   int osc = 10;

   tot = set_timeout(1);
   for (;;) {
      if (chk_timeout(tot)) {
         tot = set_timeout(1);  /* 1 second */

         if (--osc == 0) {  /* Check rate every 10s */
            pps();
            osc = 10;
            }

         if (time_to_stop) {
            printf("Time to stop !!!\n");
            pkt_release();
            write_data();
            exit(0);
            }
         if (kbhit()) {
            if (getch() == 27) {  /* ESC */
               pkt_release();
               write_data();
               printf("\nShutting down\n");
               // shut down access to packet driver
               //
               exit(0);
               }
            }
         }
      }

   }

void au_send_mon(int length, unsigned char far *buffer)
{  return;  }  /* Default version, never used */
