123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- /*
- tcpreplay.c
- Matt Undy <mundy@anzen.com>
-
- Copyright (c) 1999 Anzen Computing. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- This product includes software developed by Anzen Computing, Inc.
- 4. Neither the name of Anzen Computing, Inc. nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- Notes:
- The performance of paced modes could be increased somewhat by
- estimating sleep time and only checking against the RTC ocasionally,
- although this would also result in a less precise data rate,
- especially on machines with an imprecise usleep().
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif /* HAVE_CONFIG_H */
- #include <stdio.h>
- #include <stdlib.h>
- #if TIME_WITH_SYS_TIME
- # include <sys/time.h>
- # include <time.h>
- #else
- # if HAVE_SYS_TIME_H
- # include <sys/time.h>
- # else
- # include <time.h>
- # endif
- #endif
- #include <pcap.h>
- #include <libnet.h>
- #define TCPREPLAY_VERSION "1.0.1"
- #define PACE 1 /*0b01*/
- #define RATE 2 /*0b10*/
- #define TIME_GT(x,y) (x tv_sec>y tv_sec||(x tv_sec==y tv_sec&&x tv_usec>y tv_usec))
- #define TIME_LT(x,y) (x tv_sec<y tv_sec||(x tv_sec==y tv_sec&&x tv_usec<y tv_usec))
- #define TIME_ASSIGN(x,y) x tv_sec=y tv_sec; x tv_usec=y tv_usec;
- #define PRINT_TIMEVAL(x) fprintf(stderr, " tv_sec=%li tv_usec=%li\n",x tv_sec, x tv_usec);
- typedef struct timeval time_struct;
- extern int errno;
- int failed_writes, first_pkt,older_pkts;
- int pkts_sent;
- long long bytes_sent;
- int iterrations;
- int mode;
- int rate;
- int debug;
- float multiplier;
- struct timeval lasttime, lastpkt, behind_time, starttime_struc,
- startpkt_struct, last_dpkt, starttime, pkttime_struct;
- int caplen;
- int iterations;
- char * interface;
- void usage(){
- fprintf(stderr, "Version: " TCPREPLAY_VERSION "\nUsage: tcpreplay "
- "[-i interface] [-l loops] [-m multiplier] [-r rate] <file>\n");
- exit (1);
- }
- /* we aren't checking for overflow here. if it happens we have run
- into the 2038 problem and the whole time handling is broken (or a bug). */
- void addtime(time_struct * op1,time_struct * op2,time_struct * result)
- {
- result->tv_usec = op1->tv_usec+op2->tv_usec;
- if (result->tv_usec > 999999) {
- result->tv_usec -= 1000000;
- op1->tv_sec++;
- }
- result->tv_sec = op1->tv_sec+op2->tv_sec;
- }
- /*
- if op1>op2, return op1-op2 and 0
- if op1<op2, return |op1-op2| and 1
- (return a negative # with the sign bit in the return int)
- if op2>op1, subtract op2 from op1 and set return int
- */
- int subtime(time_struct * op1, time_struct * op2, time_struct * result)
- {
- int borrow=0;
- int sign=0;
- time_struct * temp_time;
-
- if (TIME_LT(op1->, op2->)) {
- sign = 1;
- temp_time = op1;
- op1 = op2;
- op2 = temp_time;
- }
- if (op1->tv_usec >= op2->tv_usec) {
- result->tv_usec = op1->tv_usec-op2->tv_usec;
- }
- else {
- result->tv_usec = (op1->tv_usec+1000000)-op2->tv_usec;
- borrow = 1;
- }
- result->tv_sec = (op1->tv_sec-op2->tv_sec)-borrow;
-
- return sign;
- }
- void divtime(time_struct * num, float denom) {
- num->tv_sec = num->tv_sec/denom;
- num->tv_usec = num->tv_usec/denom;
- }
- void write_packet(u_char * user,struct pcap_pkthdr* pcap_hdr, u_char * data)
- {
- int write_status = -1;
- float sec;
- struct timeval now, dtime, dpkt, sleeptime;
-
- if (mode) {
- #if HAVE_GETTIMEOFDAY
- gettimeofday(&now,NULL);
- #endif
- iterations++;
- #ifdef DEBUG
- if ((!(iterations %99))&&debug>0) {
- fprintf(stderr, "\nELAPSED TIME %lu sec %li usec\n\n",
- now.tv_sec-starttime_struc.tv_sec,
- now.tv_usec - starttime_struc.tv_usec);
- fprintf(stderr, "\nELAPSED PACKET TIME %lu sec %li usec\n\n",
- pcap_hdr->ts.tv_sec - startpkt_struct.tv_sec,
- pcap_hdr->ts.tv_usec - startpkt_struct.tv_usec);
- }
- #endif
- if (first_pkt) {
- first_pkt = 0;
- TIME_ASSIGN(starttime_struc., now.);
- TIME_ASSIGN(lastpkt., pcap_hdr->ts.);
- TIME_ASSIGN(startpkt_struct., pcap_hdr->ts.);
- }
- if (subtime(&now, &starttime_struc, &dtime)) {
- fprintf(stderr, "The RTC has decreased since last read (or someone multithreaded this wrong)\n");
- /*if it is earlier than the last time we executed this loop,
- something is very wrong*/
- abort();
- }
- if (mode & PACE) {
- if (subtime(&pcap_hdr->ts, &lastpkt, &dpkt)) {
- /*Uncomment this if you want to stop on out of order packets
- in the dump file*/
- /*fprintf(stderr, "packets in pcap file not in increasing time of arrival\n");
- abort();*/
- older_pkts++;
- }
- else {
- divtime(&dpkt, multiplier);
- addtime(&dpkt, &pkttime_struct, &pkttime_struct);
- }
- #ifdef DEBUG
- if (debug > 2) {
- fprintf(stderr, "dtime: ");
- PRINT_TIMEVAL(dtime.);
- fprintf(stderr, "pkttime_struct: ");
- PRINT_TIMEVAL(pkttime_struct.);
- }
- #endif
- }
- if (mode & RATE) {
- /*calculate time packet should take, add to total packet time. */
- sec = (float)pcap_hdr->caplen / (float)rate;
- dpkt.tv_sec = sec;
- dpkt.tv_usec = (sec - dpkt.tv_sec) * 1000000;
- #ifdef DEBUG
- if (debug > 2) {
- fprintf(stderr, "dpkt:");
- PRINT_TIMEVAL(dpkt.);
- }
- #endif
- addtime(&dpkt, &pkttime_struct, &pkttime_struct);
- #ifdef DEBUG
- if (debug > 2) {
- fprintf(stderr, "pkttime_struct: ");
- PRINT_TIMEVAL(pkttime_struct.);
- }
- #endif
- }
- if (subtime(&dtime, &pkttime_struct, &sleeptime)) {
- /*we are ahead by pkttime if true*/
- #ifdef DEBUG
- if (debug > 2) {
- fprintf(stderr, "sleeptime: ");
- PRINT_TIMEVAL(sleeptime.);
- }
- #endif
- sleep(sleeptime.tv_sec);
- usleep(sleeptime.tv_usec);
- }
- TIME_ASSIGN(lastpkt., pcap_hdr->ts.);
- }
- while (write_status < 0) {
- write_status = write_link_layer((struct link_int *)user, interface,
- data,pcap_hdr->caplen);
- #ifdef DEBUG
- if (debug > 1) {
- fprintf(stderr, "write_status = %i\n", write_status);
- }
- #endif
- if (write_status < 0) {
- /*if errno = = 55(ENOBUFS) loop, otherwise break*/
- if (errno != ENOBUFS) {
- fprintf(stderr, "errno = %i\n", errno);
- perror("pcap_inject");
- exit(1);
- }
- else {
- failed_writes++;
- }
- }
- }
- bytes_sent += write_status;
- pkts_sent++;
- }
- int main(int argc, char * argv[])
- {
- pcap_t * in_file;
- struct link_int * write_if;
- float Mrate = 0;
- double starttime_local, startusec;
- char ebuf[256];
- struct timeval tp;
- extern char *optarg;
- extern int optind;
- int ch, iterrated,files = 0;
- char * name = NULL;
- int stdinput = 0;
- debug = 0;
- iterrations = 1;
- mode = 0;
- interface = NULL;
- while ((ch = getopt(argc, argv, "i:l:r:m:h")) != -1)
- switch(ch) {
- case 'd':
- debug++;
- break;
- case 'm':
- multiplier = atof(optarg);
- mode = mode | PACE;
- break;
- case 'r':
- mode = mode | RATE;
- Mrate = atof(optarg);
- rate = (Mrate * (1024 * 1024)) / 8;
- break;
- case 'l':
- iterrations = atoi(optarg);
- break;
- case 'i':
- interface = optarg;
- break;
- case 'h':
- usage();
- break;
- default:
- usage();
- }
-
- if ((mode & PACE) && (mode & RATE)) {
- usage();
- }
- if ((mode & PACE) && multiplier == 0) {
- fprintf(stderr, "invalid pace multiplier - use a nonzero multiplier\n");
- usage();
- }
- if ((mode & RATE) && (Mrate == 0)) {
- fprintf(stderr, "invalid sending rate - use a nonzero rate\n");
- usage();
- }
- if (interface == NULL) {
- if (!(interface = pcap_lookupdev(ebuf))) {
- fprintf(stderr, "can't determine default interface: %s\n", ebuf);
- exit(1);
- }
- }
-
- iterations = 0;
- older_pkts = 0;
- #if HAVE_GETTIMEOFDAY
- gettimeofday(&tp,NULL);
- #endif
- /*if you don't have gettimeofday, you will have to add the appropriate
- syscall for your system*/
- starttime_local = tp.tv_sec;
- startusec = tp.tv_usec;
- failed_writes = 0;
- pkts_sent = 0;
- bytes_sent = 0;
- write_if = open_link_interface(interface,ebuf);
- if (write_if <= 0) {
- fprintf(stderr, "output i/f: %s\n",ebuf);
- exit(1);
- }
- /*need to account for no args*/
- if (argc == optind) {
- stdinput = 1;
- }
- for (files=0;files < argc-optind || stdinput;files++) {
- if (stdinput) {
- name = malloc(4);
- strcpy(name,"-");
- }
- else {
- name = argv[files+optind];
- }
- for (iterrated = 0; iterrated < iterrations; iterrated++){
- first_pkt = 1;
- #if HAVE_GETTIMEOFDAY
- gettimeofday(&tp,NULL);
- #endif
- pkttime_struct.tv_sec = 0;
- pkttime_struct.tv_usec = 0;
- lasttime.tv_sec = tp.tv_sec;
- lasttime.tv_usec = tp.tv_usec;
- in_file = pcap_open_offline(name, ebuf);
- if (!in_file) {
- fprintf(stderr, "Error opening %s for reading\n",argv[1]);
- fprintf(stderr, "in_file: %s\n",ebuf);
- exit (1);
- }
- if (pcap_dispatch(in_file, 0,(void *)&write_packet,
- (u_char *) write_if) == -1) {
- pcap_perror(in_file, argv[1]);
- }
- pcap_close(in_file);
- }
- stdinput = 0;
- }
- if (failed_writes) {
- fprintf(stderr, "%i write attempts failed from full buffers and were repeated\n", failed_writes);
- }
- if (older_pkts) {
- fprintf(stderr, "%i packet delays removed because they were out of order\n", older_pkts);
- }
- fprintf(stderr, "%i packets sucessfully sent", pkts_sent);
- #if HAVE_GETTIMEOFDAY
- gettimeofday(&tp, NULL);
- #endif
- fprintf(stderr, " in %f seconds(%f packets per second)\n",
- (tp.tv_sec - starttime_local + ((tp.tv_usec - startusec) / 1000000)),
- (pkts_sent / ((tp.tv_sec - starttime_local) * 1000000 +
- ((tp.tv_usec - startusec)))) * 1000000);
- fprintf(stderr, "%lld bytes sucessfully sent", bytes_sent);
-
- fprintf(stderr, "(%f bytes per second\n",
- (bytes_sent / ((tp.tv_sec - starttime_local) * 1000000 +
- ((tp.tv_usec - startusec)))) * 1000000);
- fprintf(stderr, "%f megabits per second)\n",
- (((bytes_sent / ((tp.tv_sec - starttime_local) * 1000000 +
- ((tp.tv_usec-startusec)))) * 1000000) * 8) /
- (1024 * 1024));
- exit(0);
- }
|