C-based Traffic generator



  

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

#include <sys/uio.h> 
#include <netinet/in.h>
#include <errno.h>

#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <fcntl.h>
#include <math.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <string.h>
#include <pcap.h>
#include <assert.h>

#define TRAFFICSOURCE_VERSION "$Revision: 1.13 $ $Date: 2000/01/21 15:48:10 $"

extern const char trafficsource_version[];  /* version string */
extern  int optind, opterr;

#define OUTPUT_BUFFER_SIZE    2000              /* Big enough for largest payload+header*/
#define BURST_DEFAULT         0.352             /* secs */
#define IDLE_DEFAULT          0.620             /* secs */
#define PEAK_DEFAULT          32000  		/* bits/sec (32Kbits/sec) */
#define INVERSE_M ((double)   4.6566128200e-10)	/* (1.0/(double)M) */
#define DEBUG                 0
#define DEFAULT_PACKETSIZE    64               /* payload */
#define DEFAULT_SOURCES       10
#define DEFAULT_PORT          4000              /* discard port */
#define DEFAULT_HOST          "10.3.1.2"
#define DEFAULT_SNAPLEN       68
#define DEFAULT_INTERVAL      16                 /* ms */
#define DEFAULT_LENGTH        98                 /* packet length */
#define DEFAULT_TCPDUMP       "/tmp/tcpdump"
#define TEXT_TRACE            "/tmp/trace_file"
#define BIN_TRACE             "/tmp/bin_trace_file"


/*
 * From bitindex to int index.
 */
#define BITS2INT32(B) ((B)/(sizeof(u_int32_t)*8))
#define REMAIN(B) ((B)%(sizeof(u_int32_t)*8))
#define GETBIT(d, i) ((((d)[BITS2INT32(i)]) & (1 << REMAIN(i))) ? 1 : 0)


struct 
data_pattern {
  double burst_time;
  double idle_time;
  double peak_rate;
  double interval;
  int packet_size;
  int burstlen;
  int idlelen;
  char dst_hostname[64];
  short dst_port;
  int nsources;
  char tcpdump_filename[64];
  char text_trace[64];
  char bin_trace[64];
  unsigned int running_time;
  unsigned int nsteps;
  int stats;
  int tcpdump;
  int senddata;
  int bindata;
  int readwritetrace;
};


enum wise_hdr_type_t {
  WISE_HDR_NULL, /* Illegal */
  WISE_HDR_DATA, /* User defined payload */
  WISE_HDR_PING, /* No payload */
  WISE_HDR_ECHO  /* Echo on PINGs seq, timestamp */
};


static void 	 usage();
void        	 generate_packets(struct data_pattern *d);
int         	 calc_length(double burstlen);
void        	 send_packet(FILE *);
void        	 idle_cycle(FILE *);
void        	 zero_cycle(FILE *);
struct timeval   gettimestamp(void);
struct timeval   timevaladd(struct timeval t1, struct timeval t2);
struct timeval   timevalsub(struct timeval t1, struct timeval t2);
char *           timevalprint(struct timeval t1);
int         	 write_trace(int rtime, struct data_pattern *d, int *rem, char *trace_file, int nsources);
void        	 show_source_statistics(int *data, int nelements);
/*int             send_data(struct data_pattern *d, FILE *, int i, struct sockaddr_in *addr, int sockfd, int nsources, pcap_dumper_t *pcap_file);*/
void             delay(double);
int              initialise(struct data_pattern *d, struct sockaddr_in *addr);
void             get_arguments(int argc, char *argv[], struct data_pattern *d);
int              calc_interval(struct data_pattern *d, int source, int rtime, FILE *, int *rem, int sources);
void             dodots(int j);
void             calc_burstlength(struct data_pattern *d, int sources, int *rem);
int
write_tcpdump_file(pcap_dumper_t *pcap_file, int noelements, struct data_pattern *d, int nsources);
int
produce_trace(struct data_pattern *d, int rtime, int **data, char *text_trace, char *bin_trace, int nsources, int *rem);
int              make_bitmap(int **data, int l, int this);
int              read_tracefile(char *tracefile, int nsources, int *nelements, int **data);



/*
 * gprof
 * calc packet size, hold constant rate and interval
 */

#include "trafficsource.h"
#include "rtp.h"

#define  DBG 0

const char trafficsource_version[] = TRAFFICSOURCE_VERSION;

#if 0
static struct pcap *pd;
#endif

char   dst_str[128], *pstr;
int    snaplen = DEFAULT_SNAPLEN;
struct timeval T0; /* Start time */


void
calc_burstlength(struct data_pattern *d, int nsources, int rem[]) {
  int i, temp;

  d->interval = ((double)DEFAULT_INTERVAL)/1000.0;
  d->burstlen = (d->burst_time/d->interval);
  d->idlelen = (d->idle_time/d->interval);
  d->nsteps = (int)(d->running_time/d->interval);
  
  for (i = 0; i < nsources; i++){
    do {
      temp = calc_length(d->burstlen);
      if (i % 2) 
	rem[i] = -temp; /* just make 50% start with idle i.e. -ve values */
      else
	rem[i] = temp;  /* other 50% +ve, hence busrt */
    } while (rem[i] == 0);        /* We don't want a burstlen of 0 */
  }
}



int
calc_length(double burstlen) {
  double rand, logvalue;

  rand = INVERSE_M * random();
  logvalue = burstlen * -log(rand);
  
  return ((int)(logvalue + 0.5));
}



int
calc_interval(struct data_pattern *d, int source, int rtime, FILE *trace_file, int *rem, int nsources) {
  int temp;

  /*
   * burst time
   */
  if (rem[source] > 0) { 
      send_packet(trace_file);
      if (--rem[source] == 0) { 
	  do {
	      temp = calc_length(d->idlelen);
	  } while (temp == 0);
	  rem[source] = -temp;
      }
      return 1;
  }
  /*
   * Idle time
   */
  else if (rem[source] < 0) { 
      idle_cycle(trace_file);
      if(++rem[source] == 0) { 
	  do {
	      temp = calc_length(d->burstlen);
	  } while (temp == 0);
	  rem[source] = temp;
      }
      return -1;
  }
  /*
   * Shouldn't come here but bugs you know...
   */
  else {
    zero_cycle(trace_file);
  }
  return 0;
}


/*
 * Executes the loops making exponential sources.
 *
 */
int
write_trace(int rtime, struct data_pattern *d, int *rem, char *trace_file, int sources) {
  int i,j;

  FILE *f;
  /*
   * Open trace file.
   */
  if ((f = fopen(trace_file, "w")) == NULL){
    perror("fopen");
    return -1;
  }

  for (j = 0; j < rtime; j++) {
    /*      dodots(j);*/
      /*      fprintf(f, "\n%d\t", j);*/
      for(i = 0; i < sources; i++) {
	  calc_interval(d, i, j, f, rem, sources);
      }
  }

  fclose(f);
  return  0;
}

void
dodots(int j) {
    if (j % 100 == 0) {
	printf(".");
	fflush(stdout);
    }
}


void
send_packet(FILE *trace_file) {
  fprintf(trace_file, " %s ", "1");
  fflush(trace_file);
}



void
idle_cycle(FILE *trace_file) {
  fprintf(trace_file, " %s ", "0");
  fflush(trace_file);
}



void
zero_cycle(FILE *trace_file) {
  fprintf(trace_file, " %s ", "-1");
  fflush(trace_file);
}

void
new_line(FILE *trace_file) {
  fprintf(trace_file, "\n");
}



static void 
usage ()
{
  fprintf(stderr, "\nusage: ");
  fprintf(stderr, "trafficsource \n\n"
          "[-h]\t\t\t\t# Print this text\n"
          "[-v]\t\t\t\t# Print version\n"
	  "[-b burstsize]\t\t\t# Burstsize (def: 0.325)\n"
	  "[-i idletime]\t\t\t# Idletime (def: 0.625)\n"
	  "[-p peak rate]\t\t\t# Peak rate (def: 20480 bits/sec) \n"
	  "[-s packet size]\t\t# Packet Size (def:%d)\n"
	  "[-n number of sources]\t\t# Number of Sources (def:10)\n"
	  "[-t tcpdump filename]\t\t# Tcpdump filename (def/tmp/tcpdump)\n"
	  "[-f trace filename]\t\t# Trace filename text (def:/tmp/trace_file)\n"
	  "[-d destination host:port]\t# ipv4addr:port (def 10.3.1.2:4000)\n"
	  "[-l running time]\t\t# Duration of trace (seconds) (def:512)\n"
	  "[-c stats]\t\t\t# Statistics on trace generated (def:none)\n"
	  "[-r]\t\t\t\t# Write & read file /tmp/trace_file (def:on)\n\n"
	  "e.g. ./trafficsource -t /tmp/tcpfile -f /tmp/tracefile -d 193.10.66.193:9 -n 10\n\n",
	  DEFAULT_PACKETSIZE
          );
  exit(0);
}


int
initialise(struct data_pattern *d, struct sockaddr_in *addr) {

    /* 
     * initialise with default values 
     */

    d->burst_time = BURST_DEFAULT;
    d->idle_time = IDLE_DEFAULT;
    d->peak_rate = PEAK_DEFAULT;
    d->packet_size = DEFAULT_PACKETSIZE;
    d->nsources = DEFAULT_SOURCES;
    d->running_time = 100 * BURST_DEFAULT;
    d->packet_size = DEFAULT_PACKETSIZE;
    strcpy(d->tcpdump_filename, DEFAULT_TCPDUMP);
    strcpy(d->text_trace, TEXT_TRACE);
    strcpy(d->bin_trace, BIN_TRACE);
    d->stats = 0;
    d->tcpdump = 0;
    d->senddata = 1;
    d->readwritetrace = 1;

    if (!addr)
	return -1;
    addr->sin_family = AF_INET;
    addr->sin_port = htons(DEFAULT_PORT);
    addr->sin_addr.s_addr = inet_addr(DEFAULT_HOST);
    
    return 0;
}


void
get_arguments(int argc, char *argv[], struct data_pattern *d ) {
  char dst_str[128], *pstr;
  int ppos;

  argv++;argc--;
  for (;(argc>0)&& *argv; argc--, argv++){
    if (**argv != '-')
      break;
    (*argv)++;
    if (strlen(*argv)==0)
      usage();
    switch(**argv) {
    case 'h': /* help */
      usage(); /* usage exits */
      break;
    case 'v': /* version */
      printf("%s\n", trafficsource_version);
      exit(0);
      break;
    case 'b': /* burst rate */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%lf", &d->burst_time) != 1) 
	usage();     
      break;
    case 'i': /* idle time */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%lf", &d->idle_time) != 1)
	usage();
      break;
    case 'p': /* peak rate */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%lf", &d->peak_rate) != 1)
	usage();
      break;
    case 's': /* packet size (bytes) */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%d", &d->packet_size) != 1)
	usage();
      break;
    case 'd': /* destination */
      argc--;argv++;
      strcpy(dst_str, *argv);
      if ((pstr = (char*)strrchr(dst_str, ':')) != NULL){
	ppos = pstr-dst_str;
	d->dst_port = (short)atoi(pstr+1); 
	*pstr = '\0';
      }
      strcpy(d->dst_hostname, dst_str);
      break;
    case 'n': /* number of sources */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%d", &d->nsources) != 1)
	usage();
      break;
    case 't': /* tcpdump filename */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%s", d->tcpdump_filename) != 1)
	usage();
      break;
    case 'f': /* text filename */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%s", d->text_trace) != 1)
	usage();
      break;
    case 'l': /* running time (seconds) */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%d", &d->running_time) != 1)
	usage();
      break;
    case 'c': /* stats */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%d", &d->stats) != 1)
	usage();
      break;
    case 'u': /* tcpdump */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%d", &d->tcpdump) != 1)
	usage();
      break;
    case 'r': /* readfile */
      argc--;argv++;
      if (!*argv || sscanf(*argv, "%d", &d->readwritetrace) != 1)
	usage();
      break;
    default:
      fprintf(stderr, "-%s - unrecognized option\n", *argv);
      usage();
      break;
    }
  }
  if (argc != 0)
    usage();
}




int
write_tcpdump_file_bitmap(pcap_dumper_t *pcap_file, struct data_pattern *d, int nsources, int nelements, int *data) {
  struct        pcap_pkthdr h;
  static char   outbuf[0];  
  static struct timeval now;
  int           i = 0;

  for(i = 0; i < nelements; i++) {
    /*
     * Wait until the next slot
     */
    if (i && ((i % nsources) == 0)){
      delay(d->interval);
    }

    /*
     * For each source, see if there is a packet to send
     */
    if (GETBIT(data, i)) {
      now = gettimestamp();
      h.caplen = DEFAULT_SNAPLEN;
      h.len = DEFAULT_LENGTH;
      bcopy(&now, &h.ts, sizeof(struct timeval));
      pcap_dump((u_char *)pcap_file, &h, outbuf);
    }
  } /* for elements */
  return 0;

}


int
write_tcpdump_file(pcap_dumper_t *pcap_file, int noelements, struct data_pattern *d, int nsources) {
  struct        pcap_pkthdr h;
  static char   outbuf[0];  
  static struct timeval now;
  int           i = 0, j = 0;
  int           *ptr; 

  FILE *f;

  /*
   * Open trace file (again)
   */
  if ((f = fopen(d->text_trace, "r")) == NULL){
    perror("fopen");
    return -1;
  }

    ptr = malloc((nsources + 1) * sizeof(int) * d->nsteps);

    if (ptr == NULL) {
      fprintf(stderr, "Not enough memory to load table Megs\n");
      exit(0);
    }
  
  /*
   * Small section of code below reads the ascii trace file really it
   * should read the binary version, we have that and it's faster.  
   */
  while (fscanf(f, "%d", &ptr[i]) != EOF) {
    /*    printf("%d ", ptr[i]);*/
    i++;
    if (i % (nsources + 1) == 0)
      ;
      /*      printf(" \n");  */
  }
  fclose(f);
  noelements = i;
  

  
  for(i = 0; i < noelements; i++) {
    /*
     * Wait until the next slot
     */
    if ((i % (nsources + 1)) == 0)
      delay(d->interval);
    
    /*
     * For each source, see if there is a packet to send
     */
    if ( (ptr[i] == 1) && (i != 4)) {
      /*
       * Write the tcpdump file
       */
      now = gettimestamp();
      h.caplen = DEFAULT_SNAPLEN;
      h.len = DEFAULT_LENGTH;
      bcopy(&now, &h.ts, sizeof(struct timeval));
      pcap_dump((u_char *)pcap_file, &h, outbuf);
      j++;
    }
  }

  free(ptr);
  return j;
} 
    



	    	    	    	    


void 
delay(double waittime) {
    int ret = 0;
    static struct timeval wait_tv, now, start, future, diff;

    now = start = gettimestamp();

    wait_tv.tv_sec = (int)waittime;
    wait_tv.tv_usec = abs((waittime - wait_tv.tv_sec) * 1000000);
    
    
    future = timevaladd(wait_tv, start);
    diff = timevalsub(future, now);

    while ((diff.tv_usec > 0) && (diff.tv_sec >= 0)) {
	ret = gettimeofday(&now, NULL);
	diff = timevalsub(future, now);
    }

}


void
show_source_statistics(int *data, int nelements) {
  FILE *fd_stats;


  fd_stats = fopen("/tmp/trace_file", "w");

#if 0
  for (i=1; i < 200; i++) {
  }

  for (i=1; i < 200; i++) {
  }
#endif
  
  fflush(fd_stats);
  fclose(fd_stats);
}


struct timeval gettimestamp() {  
  struct timeval t;
  gettimeofday(&t, NULL);
  return t;
}

void timevalfix(struct timeval *t1)
{
    if (t1->tv_usec < 0) {
        t1->tv_sec--;
        t1->tv_usec += 1000000;
    }
    if (t1->tv_usec >= 1000000) {
        t1->tv_sec++;
        t1->tv_usec -= 1000000;
    }
}
 
struct timeval timevaladd(struct timeval t1, struct timeval t2)
{
  struct timeval t = t1;
  t.tv_sec += t2.tv_sec;
  t.tv_usec += t2.tv_usec;
  timevalfix(&t);
  return t; 
}
 
struct timeval timevalsub(struct timeval t1, struct timeval t2)
{
  struct timeval t = t1;
  t.tv_sec -= t2.tv_sec;
  t.tv_usec -= t2.tv_usec;
  timevalfix(&t);
  return t; 
}

char *timevalprint(struct timeval t1)
{
  static char s[64];
  if (t1.tv_sec < 0 && t1.tv_usec > 0){
    if (t1.tv_sec == -1)
      sprintf(s, "-%ld.%06ld", t1.tv_sec+1, 1000000-t1.tv_usec);
    else
      sprintf(s, "%ld.%06ld", t1.tv_sec+1, 1000000-t1.tv_usec);
  }
  else
    sprintf(s, "%ld.%06ld", t1.tv_sec, t1.tv_usec);
  return s;
}

char *timevalprintms(struct timeval t1)
{
  static char s[64];
  if (t1.tv_sec < 0 && t1.tv_usec > 0){
    if (t1.tv_sec == -1)
      sprintf(s, "-%ld.%06ld", t1.tv_sec+1, 1000000-t1.tv_usec);
    else
      sprintf(s, "%ld.%06ld", t1.tv_sec+1, 1000000-t1.tv_usec);
  }
  else
    sprintf(s, "%ld", t1.tv_sec*1000+t1.tv_usec/1000);
  return s;
}



void rtp_set_hdr(rtp_header *hdr, struct timeval *T0, u_int32_t ssrc)
{
  struct timeval T;
  /* Fill in RTP v2 information */
   hdr->flags = 0x0;
   rtp_set_v(hdr->flags, RTP_VERSION);
   rtp_set_pt(hdr->flags, RTP_PT_WISE); /* payload type */

   if (T0)
     T = *T0;

   else
     T = gettimestamp();
   TV2NTP(&T, &hdr->ts);
   hdr->ssrc = ssrc;
}

void NTP2TV(struct NTP_timestamp *NTP, struct timeval *TV)
{
  static struct timeval T;

  T = gettimestamp(); /* Need only be done every 18 hours :-> */
  TV->tv_sec = NTP->sec | (T.tv_sec & 0xffff0000);
  TV->tv_usec = ((NTP->frac*15625)>>10);
}

/* struct timeval to NTP 32-bit timestamp */
void TV2NTP(struct timeval *TV, struct NTP_timestamp *NTP)
{
/* u-seconds to 16 bit fraction 1024=2^10.  Coneversion is x*65536/1000000*/
  NTP->sec = TV->tv_sec & 0xffff;
  NTP->frac = (TV->tv_usec<<10)/15625;
}

/* struct timeval to NTP 32-bit timestamp */
void TV2NTP_64(struct timeval *TV, struct NTP_timestamp_64 *NTP)
{
  NTP->sec = TV->tv_sec;
  /* conversion factor is 4294967296/1000000 */
  NTP->frac = (u_int32_t)((double)TV->tv_usec*4294.967296);   
}

/* Translate NTP timestamp to floating point seconds */
double NTP2sec(struct NTP_timestamp *NTP)
{
  return (double)NTP->sec + ((double)NTP->frac)/65536.0;
}

/* Encode RTP header: generated from from Assar Ws ydr */
char *marshal_rtp_hdr(rtp_header *o, char *ptr)
{
     rtp_header *p = (rtp_header *)ptr;
     p->flags = htons(o->flags);
     p->seq = htons(o->seq);
     p->ts.sec = htons(o->ts.sec);
     p->ts.frac = htons(o->ts.frac);
     p->ssrc = htonl(o->ssrc);
     return ptr;
}




int
make_bitmap(int **data, int l, int this) {
  int k, a = 0;
  
  k = BITS2INT32(l);
  a = this << REMAIN(l);
  (*data)[k] |= a;

  return 0;
}


int
produce_trace(struct data_pattern *d, int rtime, int **data, char *text_trace, char *bin_trace, int source, int *rem) {

  int j, l, i = 0, temp, written = 0, tot, pkts = 0;
  double pkts_on, pkts_src, interval;
  FILE *f = NULL, *bf = NULL;
  int tot_elements;
  double myinterval;
  int *textfile; 


  myinterval = ((double)DEFAULT_INTERVAL)/1000.0;
  tot_elements = d->nsources * d->running_time / myinterval;


  /*
   * Open trace file for writing specified
   */
  if (d->readwritetrace) {
    if (text_trace != NULL) {
      if ((f = fopen(text_trace, "w")) == NULL){
	fprintf(stderr, "fopen text trace file");
	return -1;
      }
    }
  }
  /*
   * read pre written trace file
   */
  else {
    printf("\nReading trace files %s\n", (TEXT_TRACE));
    textfile = malloc((sizeof(int) * tot_elements));

    if ((f = fopen(text_trace, "r")) == NULL){
      fprintf(stderr, "fopen reading text trace file");
      return -1;
    }

    i = 0; 

    while ((fscanf(f, "%d", &textfile[i]) != EOF) || i > tot_elements) {
      if (i > tot_elements) {
	printf("over tot_elements %d\n", tot_elements);
      }
      if (textfile[i] == 1)
	pkts++;
      i++;
    }
    fclose(f);

    printf("Read %d elements (%d 1's) from %d sources time running_time %d\n", tot_elements, pkts, d->nsources, d->running_time);

    for(i = 0; i < tot_elements; i++) {
      make_bitmap(data, i, textfile[i]);
    }
    free(textfile);
    return 0;
  }



  if (bin_trace != NULL) { 
    if ((bf = fopen(bin_trace, "w")) == NULL){
      fprintf(stderr, "fopen binary trace file");
      return -1;
    }
  }

  /*
   * Print info for user
   *
   * rtime = running time
   * source = number of sources
   * pkts_on = approx number of packets
   *
   * BURST_DEFAULT = 0.352 probability source is on
   * DEFAULT_INTERVAL = space between packets in ms
   */

  interval = ((double)DEFAULT_INTERVAL)/1000.0;
  
  tot = rtime * d->nsources;

  pkts_on = tot * BURST_DEFAULT;
  
  pkts_src = pkts_on / d->nsources;

  printf("\nProducing trace files %s\n", (TEXT_TRACE));
  printf("\nrunning time %d, interval %f\n", d->running_time, d->interval);
  printf ("sources %d total 1's 0's %d\n", d->nsources, tot);
  printf ("packets on (approx)= %f pkts/source %f\n", pkts_on, pkts_src);

  /*
   * Number of elements
   */
  l = -1;

  for (j = 0; j < rtime; j++) {
    for(i = 0; i < source; i++) {
      l++;

      /*
       * burst time
       */
      if (rem[i] > 0) { 
	make_bitmap(data, l, 1);
	send_packet(f);
	if (--rem[i] == 0) { 
	  do {
	    temp = calc_length(d->idlelen);
	  } while (temp == 0);
	  rem[i] = -temp;
	}
	continue;
      }
      /*
       * Idle time
       */
      else if (rem[i] < 0) { 
	make_bitmap(data, l, 0);
	idle_cycle(f);
	if(++rem[i] == 0) { 
	  do {
	    temp = calc_length(d->burstlen);
	  } while (temp == 0);
	  rem[i] = temp;
	}
       continue;
      }
      /*
       * Shouldn't come here but bugs you know...
       */
      else {
	make_bitmap(data, l, -1);
	zero_cycle(f);
      }
    } /*  sources */
    new_line(f);
  } /* rtime */

  /*
   * Write binary file
   */
  written = fwrite(*data, sizeof(int), rtime * source, bf);


  if (text_trace != NULL) {
    fclose(f);
  }
  if (bf != NULL) {
    fclose(bf);
  }



  return 0;
}


/*
 * Just spin loop til gettimeofday is T.
 * return -1 if time had already passed.
 */
static int
delay_til(struct timeval T, struct timeval *max) 
{
  static struct timeval now;
  struct timeval diff;
  
  now = gettimestamp();
  if (timercmp(&now, &T, >)){
#if DBG
    /* printf(" miss "); */
#endif
    diff = timevalsub(now, T);
    if (timercmp(&diff, max, >))
	 *max = diff;
    return -1;
  }
  while (timercmp(&now, &T, <))
    now = gettimestamp();
  return 0;
}


static int
send_it(int source, struct sockaddr_in *addr, int sockfd, unsigned short *seqs, unsigned timestamp, int packet_size) 
{
  static char outbuf[OUTPUT_BUFFER_SIZE];   
  static rtp_header hdr;
  static int first = 1;
  int sent;
  int len = 0;
  char *p = outbuf;

  
  if(first) {
    first = 0;
    /*
     * set the source from which this packet came
     */
    hdr.flags = 0x0;
    rtp_set_v(hdr.flags, RTP_VERSION);
    rtp_set_pt(hdr.flags, RTP_PT_WISE); /* payload type */
  }
  hdr.ts.sec  = (timestamp&0xffff0000)>>16;
  hdr.ts.frac = timestamp&0xffff;
  hdr.seq = seqs[source];
  hdr.ssrc = source;
  /* 
   * Translate header into network byte order
   */
  marshal_rtp_hdr(&hdr, p);
  len += sizeof(rtp_header);
  p += sizeof(rtp_header);

  len += packet_size;
  p +=   packet_size;
  
  if ((sent = sendto(sockfd, outbuf, len, 0x0, 
		     (struct sockaddr*)addr, sizeof(*addr))) < 0)
    perror("sendto");
  fflush(NULL);
  return (sent);
}

/*
 * Send all data. 
 * Send it within a loop.
 * Packets are sent in rounds: src 0, src 1,..., src n-1.
 * Each round should take TP time (<1 sec).
 * Distance between packets within a round is dP (= TP/nsources).
 */
static int
send_data(struct sockaddr_in *addr, int nsources, int nelements, double interval_s, int packet_size, int *data) 
{
  unsigned int i=0, j;
  int sockfd, src;
  struct timeval TP; /* Periodic interval */
  struct timeval TP0; /* Start of Periodic interval */
  struct timeval dT; /* increment within interval */ 
  struct timeval T;
#if DBG  
  struct timeval diff;
#endif  
  struct timeval max_missed; /* max missed time */
  unsigned short *seqs; /* Vector of sequence #: one for each src. */
  u_int32_t timestep = 0;
  u_int32_t missed = 0; /* # of missed deadlines */
  u_int32_t sent_bytes = 0; /* # of succesfully sent bytes */
  u_int32_t sent_packets = 0; /* # of succesfully sent packets */
  u_int32_t notsent_packets = 0; /* # of succesfully sent packets */

  if ((seqs = (unsigned short*)calloc(nsources, sizeof(unsigned short))) == NULL){
    perror("malloc");
    return -1;
  }
  if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
      perror("socket");
      return -1;
  }
  /*
   * 
   */
  assert(interval_s < 1.0);
  TP.tv_sec = 0;
  TP.tv_usec = (u_int32_t)(interval_s*1000000);
  dT.tv_sec = 0;
  dT.tv_usec = TP.tv_usec/nsources;
  /*
   * Wait 1 sec til start.
   */
  T0 = gettimestamp();
  T0.tv_sec += 1;
  TP0 = T = T0;
#if DBG
  printf("T0: %s\n", timevalprint(T0));
  printf("TP: %s\n", timevalprint(TP));
  printf("dT: %s\n", timevalprint(dT));
#endif  

  for(i=0; i < nelements; i++) {
    src = i % nsources;
    /*
     * Wait until the next slot
     */
    /* 
     * Check if new sending round: timestep is plus one.
     */
    if (i && (src == 0)){
      timestep++; /* eq i/nsources */
      assert(timestep == i/nsources);
      T = TP0 = timevaladd(TP0, TP);
    }
    if (src != 0)
      T = timevaladd(T, dT);
    /*
     * For each source, see if there is a packet to send
     */
#if DBG
    printf("%d ", GETBIT(data, i));
    diff = timevalsub(T, T0);	
    printf("%s\n", timevalprint(diff));
    /*    printf("%s %d\n", timevalprint(diff), src);*/
#endif
    if (GETBIT(data, i)){
      if (delay_til(T, &max_missed) < 0)
	missed++;
      j = send_it(src, addr, sockfd, seqs, timestep, packet_size);
      if (j==0)
	notsent_packets++;
      else
	sent_packets++;
      sent_bytes += j;
      seqs[src]++;
    }
#if DBG
    if ((i+1)%nsources == 0)
      ;
#endif
  } /* for() */
  
#if 0
  printf("\n");
#endif
  printf("Successfully sent: \t%8d [packets]\n", sent_packets);
  printf("Successfully sent: \t%8d [bytes]\n", sent_bytes);
  printf("Missed deadlines: \t%8d", missed);
  if (missed)
       printf(" (max: %s)", timevalprint(max_missed));
  printf("\nFailed sendto:s: \t%8d\n", notsent_packets);
  free(seqs);
  return 0;
}


int
main(int argc, char *argv[]) {
  int                sent = 0, nelements = 0;
  struct             data_pattern *d;
  struct sockaddr_in addr;
  int    	     *rem, *data;
#if 0  
  char               ebuf[PCAP_ERRBUF_SIZE]; 
  char               *device = NULL;
  pcap_dumper_t      *pcap_file;
#endif
  double             interval;

  interval = ((double)DEFAULT_INTERVAL)/1000.0;

  d = malloc(sizeof(struct data_pattern));
  if (d == NULL)
    exit(0);

#if 0
  if (device == NULL) {
    device = pcap_lookupdev(ebuf);
    if (device == NULL)
      printf("%s", ebuf);
  }

  pd = pcap_open_live(device, snaplen, 0, 1000, ebuf);  /* 0 !promiscous mode */
#endif
  
  initialise(d, &addr);
  get_arguments(argc, argv, d);

#if 0
  pcap_file = pcap_dump_open(pd, d->tcpdump_filename);
#endif  

  rem = malloc(d->nsources * sizeof(int));
  if (rem == NULL) {
    perror("malloc");
    exit(0);
  }

  calc_burstlength(d, d->nsources, rem);
  nelements = d->nsources * d->nsteps;
  
  if ((data = (u_int32_t*)malloc(nelements/8)) == NULL){
    perror("malloc");
    exit(0);
  }

  produce_trace(d, d->nsteps, &data, d->text_trace, d->bin_trace, d->nsources, rem);
  

  if (d->stats) {
    printf("Producing statistics, well er\n");
    show_source_statistics(data, nelements);
  }

  if (d->tcpdump) {
    printf("writing tcpdump file\n");
#if 0    
    lines = write_tcpdump_file_bitmap(pcap_file, d, d->nsources, nelements, data);
#endif    
  }

  if (d->senddata) {
    printf("sending data\n");
    sent = send_data(&addr, d->nsources, nelements, interval, d->packet_size, data);
  }
  
  /*
   * Clean up, close files and exit
   */
#if 0
  pcap_dump_close(pcap_file);
  pcap_close(pd);
#endif
  free(data);
  free(rem);
  if (d->senddata) {
    /* printf("%d bytes sent\n", sent); */
  }
  free(d);
  return 0;
}