From: Roger Wolff Date: Thu, 1 Apr 2004 00:00:00 +0000 (+0000) Subject: mtr v0.55 X-Git-Tag: v0.55^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=548d4b6082d886f8841def5f4b6f22c849445347;p=thirdparty%2Fmtr.git mtr v0.55 - Cleanup patch. I'm going to do some maintenance on MTR, but I want to be able to say: Can you see which version fixed/broke things for you, so you're going to see a bunch of new releases soon. source: ftp://ftp.bitwizard.nl/mtr/mtr-0.55.tar.gz --- diff --git a/AUTHORS b/AUTHORS index ff20499..a7f9644 100644 --- a/AUTHORS +++ b/AUTHORS @@ -39,6 +39,7 @@ Brett Johnson (brett@jdacareers.com) Roland Illig (roland.illig@gmx.de) Damian Gryski (dgryski@uwaterloo.ca) + Rob Foehl (rwf@loonybin.net) Mircea Damian Cougar (cougar@random.ee) Brian Casey diff --git a/NEWS b/NEWS index 66ac13e..4e06bf2 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,9 @@ WHAT'S NEW? + v0.55 Cleanup patch. I'm going to do some maintenance on MTR, + but I want to be able to say: Can you see which version + fixed/broke things for you, so you're going to see a + bunch of new releases soon. + v0.54 Added "scrolling" patch from Roland Illig, to allow scrolling in text mode. I've always wanted this...... diff --git a/configure.in b/configure.in index 08f5499..707403a 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ AC_INIT(mtr.c) -AM_INIT_AUTOMAKE(mtr, 0.54) +AM_INIT_AUTOMAKE(mtr, 0.55) AC_SUBST(GTK_OBJ) AC_SUBST(CURSES_OBJ) diff --git a/curses.c b/curses.c index d9bd20d..f7f63b2 100644 --- a/curses.c +++ b/curses.c @@ -59,7 +59,17 @@ #endif #include + extern char LocalHostname[]; +extern char fld_active[]; +extern int fstTTL; +extern int maxTTL; +extern int packetsize; +extern int bitpattern; +extern int tos; +extern float WaitTime; + + void pwcenter(char *str) { @@ -75,8 +85,10 @@ void pwcenter(char *str) { int mtr_curses_keyaction() { int c = getch(); + int i=0; + char buf[MAXFLD]; - if(tolower(c) == 'q') + if(c == 'q') return ActionQuit; if(c==3) return ActionQuit; @@ -97,19 +109,176 @@ int mtr_curses_keyaction() { if (c == '-') return ActionScrollUp; - return 0; + /* more stuffs added by Min */ + if (tolower(c) == 's') { + mvprintw(2, 0, "Change Packet Size: %d\n", packetsize ); + mvprintw(3, 0, "Size Range: %d-%d, <0 random.\n", MINPACKET, MAXPACKET); + move(2,20); + refresh(); + while ( (c=getch ()) != '\n' && i=0 ) { + if ( packetsize < MINPACKET ) packetsize = MINPACKET; + if ( packetsize > MAXPACKET ) packetsize = MAXPACKET; + } else { + packetsize = + - (int)(MINPACKET + (MAXPACKET-MINPACKET)*(rand()/(RAND_MAX+0.1))); + } + + return ActionNone; + } + if (tolower(c) == 'b') { + mvprintw(2, 0, "Ping Bit Pattern: %d\n", bitpattern ); + mvprintw(3, 0, "Pattern Range: 0(0x00)-255(0xff), <0 random.\n"); + move(2,18); + refresh(); + while ( (c=getch ()) != '\n' && i 255 ) { bitpattern = -1; } + return ActionNone; + } + if ( c == 'Q') { /* can not be tolower(c) */ + mvprintw(2, 0, "Type of Service(tos): %d\n", tos ); + mvprintw(3, 0, "default 0x00, min cost 0x02, rel 0x04,, thr 0x08, low del 0x10...\n"); + move(2,22); + refresh(); + while ( (c=getch ()) != '\n' && i 255 || tos <0 ) { + tos = 0; + } + return ActionNone; + } + if (tolower(c) == 'i') { + mvprintw(2, 0, "Interval : %0.0f\n\n", WaitTime ); + move(2,11); + refresh(); + while ( (c=getch ()) != '\n' && i maxTTL ) return ActionNone; + fstTTL = i; + + return ActionNone; + } + if (tolower(c) == 'm') { + mvprintw(2, 0, "Max TTL: %d\n\n", maxTTL ); + move(2,9); + refresh(); + while ( (c=getch ()) != '\n' && i(MaxHost-1) ) return ActionNone; + maxTTL = i; + + return ActionNone; + } + /* fields to display & their ordering -Min */ + if (tolower(c) == 'o') { + mvprintw(2, 0, "Fields: %s\n\n", fld_active ); + + for( i=0; i= 'A' && c<= 'Z' || c==' ') { + buf[i++] = c; /* only accept [ A-Z], can be extend to [a-z0-9] */ + } + } + buf[i] = '\0'; + if ( strlen( buf ) > 0 ) strcpy( fld_active, buf ); + + return ActionNone; + } + if (tolower(c) == 'j') { + if( index(fld_active, 'N') ) { + strcpy(fld_active, "DR AGJMXI"); /* GeoMean and jitter */ + } else { + strcpy(fld_active, "LS NABWV"); /* default */ + } + return ActionNone; + } + /* reserve to display help message -Min */ + if (tolower(c) == '?'|| tolower(c) == 'h') { + mvprintw(2, 0, "Command:\n" ); + printw(" ?|h help\n" ); + printw(" d switching display mode\n" ); + printw(" n toggle DNS on/off\n" ); + printw(" o str set the columns to display, default str='LRS N BAWV'\n" ); + printw(" j toggle latency(LS NABWV)/jitter(DR AGJMXI) stats\n" ); + printw(" c report cycle n, default n=infinite\n" ); + printw(" i set the ping interval to n seconds, default n=1\n" ); + printw(" f set the initial time-to-live(ttl), default n=1\n" ); + printw(" m set the max time-to-live, default n= # of hops\n" ); + printw(" s set the packet size to n or random(n<0)\n" ); + printw(" b set ping bit pattern to c(0..255) or random(c<0)\n" ); + printw(" Q set ping packet's TOS to t\n\n\n" ); + mvprintw(16, 0, " press any key to go back..." ); + + getch(); /* get any key */ + return ActionNone; + } + + return ActionNone; /* ignore unknown input */ } void mtr_curses_hosts(int startstat) { int max; int at; - int addr; + int addr, addrs; int y, x; char *name; + int i, j; + int hd_len; + char buf[1024]; + max = net_max(); - for(at = display_offset; at < max; at++) { + for(at = net_min () + display_offset; at < max; at++) { printw("%2d. ", at + 1); addr = net_addr(at); @@ -129,12 +298,53 @@ void mtr_curses_hosts(int startstat) { move(y, startstat); /* net_xxx returns times in usecs. Just display millisecs */ - printw(" %3d%% %4d %4d %4d %4d %4d %6d", - net_percent(at), - net_returned(at), net_xmit(at), - net_last(at)/1000, net_best(at)/1000, - net_avg(at)/1000, net_worst(at)/1000); + /* changedByMin */ + hd_len = 0; + for( i=0; i= 'a' && fld_active[i]<= 'z') { + j = fld_active[i] - 'a' + 11 + 26; + } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') { + j = fld_active[i] - 'A' + 11; + } else if( fld_active[i]>= '0' && fld_active[i]<= '9') { + j = fld_active[i] - '0' +1; + } else if( fld_active[i] == ' ' ) { + j = 0; + } else { + continue; /* ignore stuff don't understand */ + } + /* temporay hack for stats usec to ms... */ + if( index( data_fields[ fld_index[j] ].format, 'f' ) ) { + sprintf(buf + hd_len, data_fields[ fld_index[j] ].format, + data_fields[ fld_index[j] ].net_xxx(at) /1000.0 ); + } else { + sprintf(buf + hd_len, data_fields[ fld_index[j] ].format, + data_fields[ fld_index[j] ].net_xxx(at) ); + } + hd_len += data_fields[ fld_index[j] ].length; + } + buf[hd_len] = 0; + printw("%s", buf); + + /* Multi path by Min */ + for( i=0; i> 24) & 0xff, (addrs >> 16) & 0xff, + (addrs >> 8) & 0xff, addrs & 0xff); + } + attroff(A_BOLD); + } } else { printw("???"); @@ -142,6 +352,7 @@ void mtr_curses_hosts(int startstat) { printw("\n"); } + move(2, 0); } static double factors[] = { 0.02, 0.05, 0.08, 0.15, 0.33, 0.50, 0.80, 1.00 }; @@ -255,9 +466,13 @@ void mtr_curses_redraw() { int maxx, maxy; int startstat; int rowstat; - int i; time_t t; + int i, j; + int hd_len = 0; + char buf[1024]; + char fmt[16]; + erase(); getmaxyx(stdscr, maxy, maxx); @@ -265,35 +480,65 @@ void mtr_curses_redraw() { move(0, 0); attron(A_BOLD); - pwcenter("Matt's traceroute [v" VERSION "]"); + pwcenter("My traceroute [v" VERSION "]"); attroff(A_BOLD); - mvprintw(1,0, LocalHostname); + mvprintw(1,0, "%s", LocalHostname); + printw("(tos=0x%X ", tos); + printw("psize=%d ", abs(packetsize) ); + printw("bitpattern=0x%02X)", (unsigned char)(abs(bitpattern))); + /* + if( packetsize>0 ){ + printw("psize=%d ", packetsize); + } else { + printw("psize=rand(%d,%d) ",MINPACKET, MAXPACKET); + } + if( bitpattern>=0 ){ + printw("bitpattern=0x%02X)", (unsigned char)(bitpattern)); + } else { + printw("bitpattern=rand(0x00-FF))"); + } + */ time(&t); mvprintw(1, maxx-25, ctime(&t)); printw("Keys: "); - attron(A_BOLD); printw("D"); attroff(A_BOLD); - printw(" - Display mode "); - attron(A_BOLD); printw("R"); attroff(A_BOLD); - printw(" - Restart statistics "); - attron(A_BOLD); printw("Q"); attroff(A_BOLD); - printw(" - Quit\n"); + attron(A_BOLD); printw("H"); attroff(A_BOLD); printw("elp "); + attron(A_BOLD); printw("D"); attroff(A_BOLD); printw("isplay mode "); + attron(A_BOLD); printw("R"); attroff(A_BOLD); printw("estart statistics "); + attron(A_BOLD); printw("O"); attroff(A_BOLD); printw("rder of fields "); + attron(A_BOLD); printw("q"); attroff(A_BOLD); printw("uit\n"); - attron(A_BOLD); - mvprintw(rowstat - 1, 0, "Hostname"); - if (display_mode == 0) { - startstat = maxx - 41; - - /* Modified by Brian Casey December 1997 bcasey@imagiware.com */ - mvprintw(rowstat - 2, startstat, " Packets Pings"); - mvprintw(rowstat - 1, startstat, " %%Loss Rcv Snt Last Best Avg Worst"); + /* changedByMin */ + for( i=0; i= 'a' && fld_active[i]<= 'z') { + j = fld_active[i] - 'a' + 11 + 26; + } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') { + j = fld_active[i] - 'A' + 11; + } else if( fld_active[i]>= '0' && fld_active[i]<= '9') { + j = fld_active[i] - '0' +1; + } else if( fld_active[i] == ' ' ) { + j = 0; + } else { + continue; /* ignore unknown */ + } + sprintf( fmt, "%%%ds", data_fields[fld_index[j]].length ); + sprintf( buf + hd_len, fmt, data_fields[fld_index[j]].title ); + hd_len += data_fields[fld_index[j]].length; + } + attron(A_BOLD); + mvprintw(rowstat - 1, 0, " Host"); + mvprintw(rowstat - 1, maxx-hd_len-1, "%s", buf); + mvprintw(rowstat - 2, maxx-hd_len-1, " Packets Pings"); attroff(A_BOLD); + move(rowstat, 0); + mtr_curses_hosts(maxx-hd_len-1); - mtr_curses_hosts(startstat); } else { /* David Sward, Jan 1999 */ char msg[80]; diff --git a/display.c b/display.c index a00ff10..b9502ce 100644 --- a/display.c +++ b/display.c @@ -73,18 +73,25 @@ void display_detect(int *argc, char ***argv) { void display_open() { switch(DisplayMode) { + case DisplayReport: report_open(); break; - + case DisplayTXT: + txt_open(); + break; + case DisplayXML: + xml_open(); + break; + case DisplayCSV: + csv_open(); + break; case DisplayCurses: mtr_curses_open(); break; - case DisplaySplit: /* BL */ split_open(); break; - case DisplayGTK: gtk_open(); break; @@ -96,15 +103,21 @@ void display_close() { case DisplayReport: report_close(); break; - + case DisplayTXT: + txt_close(); + break; + case DisplayXML: + xml_close(); + break; + case DisplayCSV: + csv_close(); + break; case DisplayCurses: mtr_curses_close(); break; - case DisplaySplit: /* BL */ split_close(); break; - case DisplayGTK: gtk_close(); break; @@ -146,6 +159,9 @@ int display_keyaction() { void display_rawping(int host, int msec) { switch(DisplayMode) { case DisplayReport: + case DisplayTXT: + case DisplayXML: + case DisplayCSV: case DisplaySplit: /* BL */ case DisplayCurses: case DisplayGTK: @@ -160,6 +176,9 @@ void display_rawping(int host, int msec) { void display_rawhost(int host, int ip_addr) { switch(DisplayMode) { case DisplayReport: + case DisplayTXT: + case DisplayXML: + case DisplayCSV: case DisplaySplit: /* BL */ case DisplayCurses: case DisplayGTK: @@ -173,13 +192,15 @@ void display_rawhost(int host, int ip_addr) { void display_loop() { switch(DisplayMode) { - case DisplayCurses: case DisplayReport: + case DisplayTXT: + case DisplayXML: + case DisplayCSV: case DisplaySplit: /* BL */ + case DisplayCurses: case DisplayRaw: select_loop(); break; - case DisplayGTK: gtk_loop(); break; @@ -193,6 +214,9 @@ void display_clear() { mtr_curses_clear(); break; case DisplayReport: + case DisplayTXT: + case DisplayXML: + case DisplayCSV: case DisplaySplit: /* BL */ case DisplayRaw: break; diff --git a/display.h b/display.h index 0c4bdd6..648e5b1 100644 --- a/display.h +++ b/display.h @@ -17,9 +17,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -enum { ActionNone, ActionQuit, ActionReset, ActionDisplay, ActionClear, - ActionPause, ActionResume, ActionDNS, ActionScrollDown, ActionScrollUp }; -enum { DisplayReport, DisplayCurses, DisplayGTK, DisplaySplit, DisplayRaw }; +enum { ActionNone, ActionQuit, ActionReset, ActionDisplay, + ActionClear, ActionPause, ActionResume, ActionDNS, + ActionScrollDown, ActionScrollUp, }; +enum { DisplayReport, DisplayCurses, DisplayGTK, DisplaySplit, + DisplayRaw, DisplayXML, DisplayCSV, DisplayTXT}; /* Prototypes for display.c */ void display_detect(int *argc, char ***argv); diff --git a/gtk.c b/gtk.c index 64b13b0..c5f9ced 100644 --- a/gtk.c +++ b/gtk.c @@ -193,8 +193,8 @@ void Toolbar_fill(GtkWidget *Toolbar) { gtk_widget_show(Entry); } -char *Report_Text[] = { "Hostname", "Loss", "Rcv", "Snt", "Last", "Best", "Avg", "Worst", NULL }; -int Report_Positions[] = { 10, 240, 280, 320, 360, 400, 440, 480, 0 }; +char *Report_Text[] = { "Hostname", "Loss", "Rcv", "Snt", "Last", "Best", "Avg", "Worst", "StDev", NULL }; +int Report_Positions[] = { 10, 200, 240, 280, 320, 360, 400, 440, 480, 0 }; GtkWidget *Report; GtkWidget *ReportBody; @@ -273,7 +273,9 @@ void gtk_set_field(GtkCList *List, int row, int ix, char *str) { gtk_clist_set_text(List, row, ix, str); } -void gtk_set_field_num(GtkCList *List, int row, int ix, char *format, int num) { +//void gtk_set_field_num(GtkCList *List, int row, int ix, char *format, int num) { +// changed int to dobule byMin +void gtk_set_field_num(GtkCList *List, int row, int ix, char *format, double num) { char str[32]; sprintf(str, format, num); @@ -308,26 +310,29 @@ void gtk_update_row(GtkCList *List, int row) { gdk_color_alloc (cmap, &color); gtk_clist_set_foreground(List, row, &color); - gtk_set_field(List, row, 0, name); + /* changed the format type and added stdev and first/max TTL byMin */ + /* the row - net_min() is kind of not clean, need some more work */ + gtk_set_field(List, row - net_min(), 0, name); - gtk_set_field_num(List, row, 1, "%d%%", net_percent(row)); - gtk_set_field_num(List, row, 2, "%d", net_returned(row)); - gtk_set_field_num(List, row, 3, "%d", net_xmit(row)); + gtk_set_field_num(List, row - net_min(), 1, "%.0f%%", net_loss(row)/1000.0); + gtk_set_field_num(List, row - net_min(), 2, "%.0f", net_returned(row)); + gtk_set_field_num(List, row - net_min(), 3, "%.0f", net_xmit(row)); - gtk_set_field_num(List, row, 4, "%d", net_last(row)/1000); - gtk_set_field_num(List, row, 5, "%d", net_best(row)/1000); - gtk_set_field_num(List, row, 6, "%d", net_avg(row)/1000); - gtk_set_field_num(List, row, 7, "%d", net_worst(row)/1000); + gtk_set_field_num(List, row - net_min(), 4, "%.0f", net_last(row)/1000.0); + gtk_set_field_num(List, row - net_min(), 5, "%.0f", net_best(row)/1000.0); + gtk_set_field_num(List, row - net_min(), 6, "%.0f", net_avg(row)/1000.0); + gtk_set_field_num(List, row - net_min(), 7, "%.0f", net_worst(row)/1000.0); + gtk_set_field_num(List, row - net_min(), 8, "%.2f", net_stdev(row)/1000.0); } void gtk_redraw() { - int at; + int at = net_min(); // changed from 0 to net_min for TTL stuff byMin int max = net_max(); gtk_clist_freeze(GTK_CLIST(ReportBody)); - while(GTK_CLIST(ReportBody)->rows < max) { + while(GTK_CLIST(ReportBody)->rows < max -at) { // byMin gtk_clist_append(GTK_CLIST(ReportBody), Report_Text); } @@ -335,7 +340,8 @@ void gtk_redraw() { gtk_clist_remove(GTK_CLIST(ReportBody), GTK_CLIST(ReportBody)->rows - 1); } - for(at = 0; at < max; at++) { + // for(at=0; at < max; at++) { // replaced byMin + for(; at < max; at++) { gtk_update_row(GTK_CLIST(ReportBody), at); } @@ -349,7 +355,7 @@ void Window_fill(GtkWidget *Window) { gtk_window_set_title(GTK_WINDOW(Window), "My traceroute [v" VERSION "]"); gtk_window_set_wmclass(GTK_WINDOW(Window), "mtr", "Mtr"); - gtk_widget_set_usize(Window, 580, 400); + gtk_widget_set_usize(Window, 600, 400); gtk_container_border_width(GTK_CONTAINER(Window), 10); VBox = gtk_vbox_new(FALSE, 10); diff --git a/mtr.8 b/mtr.8 index c56c1a4..89ac76c 100644 --- a/mtr.8 +++ b/mtr.8 @@ -121,10 +121,7 @@ network performance. .B \-\-report\-cycles\ COUNT Use this option to set the number of pings sent to determine both the machines on the network and the reliability of -those machines. Each cycle lasts one second. This option -is only useful with the -.B -r -option. +those machines. Each cycle lasts one second. .TP .B \-p\ BYTES diff --git a/mtr.c b/mtr.c index ef84187..1036eb3 100644 --- a/mtr.c +++ b/mtr.c @@ -45,35 +45,75 @@ int display_mode; int Interactive = 1; int PrintVersion = 0; int PrintHelp = 0; -int MaxPing = 16; +int MaxPing = 10; +int ForceMaxPing = 0; float WaitTime = 1.0; char *Hostname = NULL; char *InterfaceAddress = NULL; char LocalHostname[128]; int dns = 1; -int packetsize = MINPACKET; +int packetsize = 64; /* default packet size */ +int bitpattern = 0; +int tos = 0; +/* begin ttl windows addByMin */ +int fstTTL = 1; /* default start at first hop */ +//int maxTTL = MaxHost-1; /* max you can go is 255 hops */ +int maxTTL = 30; /* inline with traceroute */ +/* end ttl */ + +#ifdef ENABLE_IPV6 +#define DEFAULT_AF AF_UNSPEC +#else +#define DEFAULT_AF AF_INET +#endif + + +#ifdef NO_HERROR +#define herror(str) printf(str ": error looking up \"%s\"\n", Hostname); +#endif + +int af = DEFAULT_AF; + +/* default display field(defined by key in net.h) and order */ +char fld_active[2*MAXFLD] = "LS NABWV"; + + -void parse_arg(int argc, char **argv) { +void parse_arg(int argc, char **argv) +{ int opt; static struct option long_options[] = { { "version", 0, 0, 'v' }, { "help", 0, 0, 'h' }, + { "report", 0, 0, 'r' }, - { "report-cycles", 1, 0, 'c' }, + { "xml", 0, 0, 'x' }, { "curses", 0, 0, 't' }, { "gtk", 0, 0, 'g' }, + { "raw", 0, 0, 'l' }, + { "split", 0, 0, 'p' }, /* BL */ + /* maybe above should change to -d 'x' */ + + { "order", 1, 0, 'o' }, /* fileds to display & their order */ + { "interval", 1, 0, 'i' }, - { "psize", 1, 0, 'p' }, + { "report-cycles", 1, 0, 'c' }, + { "psize", 1, 0, 's' }, /* changed 'p' to 's' to match ping option + overload psize<0, ->rand(min,max) */ + { "bitpattern", 1, 0, 'b' },/* overload b>255, ->rand(0,255) */ + { "tos", 1, 0, 'Q' }, /* typeof service (0,255) */ { "no-dns", 0, 0, 'n' }, - { "split", 0, 0, 's' }, /* BL */ { "address", 1, 0, 'a' }, - { "raw", 0, 0, 'l' }, + { "first-ttl", 1, 0, 'f' }, /* -f & -m are borrowed from traceroute */ + { "max-ttl", 1, 0, 'm' }, { 0, 0, 0, 0 } }; opt = 0; while(1) { - opt = getopt_long(argc, argv, "a:hvrc:tgklnsi:p:", long_options, NULL); + /* added f:m:o: byMin */ + opt = getopt_long(argc, argv, + "vhrxtglpo:i:c:s:b:Q:na:f:m:", long_options, NULL); if(opt == -1) break; @@ -84,30 +124,40 @@ void parse_arg(int argc, char **argv) { case 'h': PrintHelp = 1; break; + case 'r': DisplayMode = DisplayReport; break; - case 'c': - MaxPing = atoi (optarg); - break; - case 'p': - packetsize = atoi (optarg); - break; case 't': DisplayMode = DisplayCurses; break; - case 'a': - InterfaceAddress = optarg; - break; case 'g': DisplayMode = DisplayGTK; break; - case 's': /* BL */ + case 'p': /* BL */ DisplayMode = DisplaySplit; break; case 'l': DisplayMode = DisplayRaw; break; + case 'x': + DisplayMode = DisplayXML; + break; + + case 'c': + MaxPing = atoi (optarg); + ForceMaxPing = 1; + break; + case 's': + packetsize = atoi (optarg); + if( packetsize >=0 ) { + if ( packetsize < MINPACKET ) packetsize = MINPACKET; + if ( packetsize > MAXPACKET ) packetsize = MAXPACKET; + } + break; + case 'a': + InterfaceAddress = optarg; + break; case 'n': dns = 0; break; @@ -118,12 +168,54 @@ void parse_arg(int argc, char **argv) { exit (1); } if (getuid() != 0 && WaitTime < 1.0) - WaitTime = 1.0; + WaitTime = 1.0; + break; + case 'f': + fstTTL = atoi (optarg); + if( fstTTL > maxTTL ) { + fstTTL = maxTTL; + } + if( fstTTL < 1) { /* prevent 0 hop */ + fstTTL = 1; + } + break; + case 'm': + maxTTL = atoi (optarg); + if( maxTTL > (MaxHost - 1) ) { + maxTTL = MaxHost-1; + } + if( maxTTL < 1) { /* prevent 0 hop */ + maxTTL = 1; + } + if( fstTTL > maxTTL ) { /* don't know the pos of -m or -f */ + fstTTL = maxTTL; + } + break; + case 'o': + /* XXX no error checking on the input string, lazy */ + strncpy (fld_active, optarg, MAXFLD-1 ); + break; + case 'b': + bitpattern = atoi (optarg); + if( bitpattern > 255 ) + bitpattern = -1; + break; + case 'Q': + tos = atoi (optarg); + if( tos > 255 || tos <0 ) { + /* error message, should do more checking for valid values, + * details in rfc2474 */ + tos = 0; + } break; } } - - if ((DisplayMode == DisplayReport) || (DisplayMode == DisplayRaw)) + + if(DisplayMode == DisplayReport || + DisplayMode == DisplayTXT || + DisplayMode == DisplayXML || + DisplayMode == DisplayRaw || + DisplayMode == DisplayCSV ) Interactive = 0; if(optind > argc - 1) @@ -131,9 +223,13 @@ void parse_arg(int argc, char **argv) { Hostname = argv[optind++]; - if (argc > optind) + if (argc > optind) { packetsize = atoi(argv[optind]); - + if( packetsize >=0 ) { + if ( packetsize < MINPACKET ) packetsize = MINPACKET; + if ( packetsize > MAXPACKET ) packetsize = MAXPACKET; + } + } } @@ -161,9 +257,9 @@ void parse_mtr_options (char *string) int main(int argc, char **argv) { - int traddr; - struct hostent *host; - int net_preopen_result; + int traddr; + struct hostent * host = NULL; + int net_preopen_result; /* Get the raw sockets first thing, so we can drop to user euid immediately */ @@ -180,6 +276,9 @@ int main(int argc, char **argv) { printf("mtr: Unable to drop permissions.\n"); exit(1); } + + /* reset the random seed */ + srand(getpid()); display_detect(&argc, &argv); @@ -212,7 +311,7 @@ int main(int argc, char **argv) { } - if(InterfaceAddress) { /* Mostly borrowed from ping(1) code */ + if (InterfaceAddress) { /* Mostly borrowed from ping(1) code */ int i1, i2, i3, i4; char dummy; extern int sendsock; /* from net.c:118 */ @@ -226,7 +325,7 @@ int main(int argc, char **argv) { printf("mtr: bad interface address: %s\n", InterfaceAddress); exit(1); } else { - unsigned char*ptr; + unsigned char *ptr; ptr = (unsigned char*)&sourceaddress.sin_addr; ptr[0] = i1; ptr[1] = i2; @@ -239,14 +338,21 @@ int main(int argc, char **argv) { exit(1); } } + +#ifdef ENABLE_IPV6 + if (af == AF_UNSPEC) { + af = AF_INET6; + host = gethostbyname2(Hostname, af); + if (host == NULL) af = AF_INET; + } +#endif + + if (host == NULL) { + host = gethostbyname2(Hostname, af); + } - host = gethostbyname(Hostname); if(host == NULL) { -#ifndef NO_HERROR herror("mtr"); -#else - printf("mtr: error looking up \"%s\"\n", Hostname); -#endif exit(1); } @@ -257,6 +363,25 @@ int main(int argc, char **argv) { exit(1); } + switch (af) { + case AF_INET: + traddr = *(int *)host->h_addr; + + if(net_open(traddr) != 0) { + printf("mtr: Unable to get raw socket. (Executable not suid?)\n"); + exit(1); + } + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + if(net6_open((struct in6_addr *)host->h_addr) != 0) { + printf("mtr: Unable to get raw socket. (Executable not suid?)\n"); + exit(1); + } + break; +#endif + } + display_open(); dns_open(); diff --git a/net.c b/net.c index 2ac9ce0..f3d0ea9 100644 --- a/net.c +++ b/net.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -83,14 +84,22 @@ struct IPHeader { struct nethost { uint32 addr; + uint32 addrs[MAXPATH]; /* for multi paths byMin */ int xmit; int returned; int sent; int up; - long long total; + long long var;/* variance, could be overflowed */ int last; int best; int worst; + int avg; /* average: addByMin */ + int gmean; /* geometirc mean: addByMin */ + int jitter; /* current jitter, defined as t1-t0 addByMin */ +//int jbest; /* min jitter, of cause it is 0, not needed */ + int javg; /* avg jitter */ + int jworst; /* max jitter */ + int jinta; /* estimated variance,? rfc1889's "Interarrival Jitter" */ int transit; int saved[SAVED_PINGS]; int saved_seq_offset; @@ -119,11 +128,15 @@ int sendsock; int recvsock; struct sockaddr_in sourceaddress; struct sockaddr_in remoteaddress; -static int batch_at = 0; - -extern int packetsize; +static int batch_at = 0; static int numhosts = 10; +extern int fstTTL; /* initial hub(ttl) to ping byMin */ +extern int maxTTL; /* last hub to ping byMin*/ +extern int packetsize; /* packet size used by ping */ +extern int bitpattern; /* packet bit pattern used by ping */ +extern int tos; /* type of service set in ping packet*/ + /* return the number of microseconds to wait before sending the next ping */ @@ -178,7 +191,8 @@ int new_sequence(int index) { } /* Attempt to find the host at a particular number of hops away */ -void net_send_query(int index) { +void net_send_query(int index) +{ /*ok char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/ char packet[MAXPACKET]; struct IPHeader *ip; @@ -190,35 +204,40 @@ void net_send_query(int index) { if ( packetsize < MINPACKET ) packetsize = MINPACKET; if ( packetsize > MAXPACKET ) packetsize = MAXPACKET; - memset(packet, 0, packetsize); + + memset(packet, (unsigned char) abs(bitpattern), abs(packetsize)); ip = (struct IPHeader *)packet; icmp = (struct ICMPHeader *)(packet + sizeof(struct IPHeader)); ip->version = 0x45; - ip->tos = 0; - ip->len = BSDfix ? packetsize: htons (packetsize); + ip->tos = tos; + ip->len = BSDfix ? abs(packetsize): htons (abs(packetsize)); ip->id = 0; - ip->frag = 0; + ip->frag = 0; /* 1, if want to find mtu size? Min */ ip->ttl = index + 1; ip->protocol = IPPROTO_ICMP; + ip->check = 0; + /* BSD needs the source address here, Linux & others do not... */ ip->saddr = saddr_correction(sourceaddress.sin_addr.s_addr); ip->daddr = remoteaddress.sin_addr.s_addr; - icmp->type = ICMP_ECHO; - icmp->id = getpid(); + icmp->type = ICMP_ECHO; + icmp->code = 0; + icmp->checksum = 0; + icmp->id = getpid(); icmp->sequence = new_sequence(index); - icmp->checksum = checksum(icmp, packetsize - sizeof(struct IPHeader)); - ip->check = checksum(ip, packetsize); + icmp->checksum = checksum(icmp, abs(packetsize) - sizeof(struct IPHeader)); + ip->check = checksum(ip, abs(packetsize)); gettimeofday(&sequence[icmp->sequence].time, NULL); - rv = sendto(sendsock, packet, packetsize, 0, - (struct sockaddr *)&remoteaddress, sizeof(remoteaddress)); + rv = sendto(sendsock, packet, abs(packetsize), 0, + (struct sockaddr *)&remoteaddress, sizeof(remoteaddress)); if (first && (rv < 0) && (errno == EINVAL)) { - ip->len = packetsize; - rv = sendto(sendsock, packet, packetsize, 0, + ip->len = abs (packetsize); + rv = sendto(sendsock, packet, abs(packetsize), 0, (struct sockaddr *)&remoteaddress, sizeof(remoteaddress)); if (rv >= 0) { fprintf (stderr, "You've got a broken (FreeBSD?) system\n"); @@ -233,6 +252,9 @@ void net_send_query(int index) { void net_process_ping(int seq, uint32 addr, struct timeval now) { int index; int totusec; + int oldavg; /* usedByMin */ + int oldjavg; /* usedByMin */ + int i; /* usedByMin */ if(seq < 0 || seq >= MaxSequence) return; @@ -245,22 +267,69 @@ void net_process_ping(int seq, uint32 addr, struct timeval now) { totusec = (now.tv_sec - sequence[seq].time.tv_sec ) * 1000000 + (now.tv_usec - sequence[seq].time.tv_usec); + /* impossible? if( totusec < 0 ) totusec = 0 */; if(host[index].addr == 0) { - host[index].addr = addr; + host[index].addr = addr; // should be out of if as addr can change display_rawhost(index, host[index].addr); + + /* multi paths by Min */ + host[index].addrs[0] = addr; + } else { + for( i=0; i host[index].worst) - host[index].worst = totusec; - host[index].total += totusec; + if(host[index].returned < 1) { + host[index].best = host[index].worst = host[index].gmean = totusec; + host[index].avg = host[index].var = 0; + + host[index].jitter = host[index].jworst = host[index].jinta= 0; + } + + /* some time best can be too good to be true, experienced + * at least in linux 2.4.x. + * safe guard 1) best[index]>=best[index-1] if index>0 + * 2) best >= average-20,000 usec (good number?) + * Min + if( index > 0 ) { + if(totusec < host[index].best && + totusec>= host[index-1].best ) host[index].best = totusec; + } else { + if(totusec < host[index].best ) host[index].best = totusec; + } + */ + if(totusec < host[index].best ) host[index].best = totusec; + if(totusec > host[index].worst) host[index].worst = totusec; + + if(host[index].jitter > host[index].jworst) + host[index].jworst = host[index].jitter; + host[index].returned++; + /* begin addByMin do more stats */ + oldavg = host[index].avg; + host[index].avg += (totusec - oldavg +.0) / host[index].returned; + host[index].var += (totusec - oldavg +.0) * (totusec - host[index].avg); + + oldjavg = host[index].javg; + host[index].javg += (host[index].jitter - oldjavg) / host[index].returned; + /* below algorithm is from rfc1889, A.8 */ + host[index].jinta += host[index].jitter - ((host[index].jinta + 8) >> 4); + + if ( host[index].returned > 1 ) + host[index].gmean = pow( (double) host[index].gmean, (host[index].returned-1.0)/host[index].returned ) + * pow( (double) totusec, 1.0/host[index].returned ); + /* end addByMin*/ host[index].sent = 0; host[index].up = 1; host[index].transit = 0; @@ -273,7 +342,7 @@ void net_process_ping(int seq, uint32 addr, struct timeval now) { now we just need to read it, see if it is for us, and if it is a reply to something we sent, then call net_process_ping() */ void net_process_return() { - char packet[2048]; + char packet[MAXPACKET]; struct sockaddr_in fromaddr; int fromaddrsize; int num; @@ -283,7 +352,7 @@ void net_process_return() { gettimeofday(&now, NULL); fromaddrsize = sizeof(fromaddr); - num = recvfrom(recvsock, packet, 2048, 0, + num = recvfrom(recvsock, packet, MAXPACKET, 0, (struct sockaddr *)&fromaddr, &fromaddrsize); if(num < sizeof(struct IPHeader) + sizeof(struct ICMPHeader)) @@ -312,39 +381,72 @@ void net_process_return() { int net_addr(int at) { return ntohl(host[at].addr); } +int net_addrs(int at, int i) { + return ntohl(host[at].addrs[i]); +} + -int net_percent(int at) { - if((host[at].xmit - host[at].transit) == 0) - return 0; - return 100 - (100 * host[at].returned / (host[at].xmit - host[at].transit)); +int net_loss(int at) +{ + if((host[at].xmit - host[at].transit) == 0) return 0; + /* times extra 1000 */ + return 1000*(100 - (100.0 * host[at].returned / (host[at].xmit - host[at].transit)) ); } -int net_last(int at) { - return host[at].last; +int net_drop(int at) +{ + return (host[at].xmit - host[at].transit) - host[at].returned; } -int net_best(int at) { - return host[at].best; +int net_last(int at) +{ + return (host[at].last); } -int net_worst(int at) { - return host[at].worst; +int net_best(int at) +{ + return (host[at].best); } -int net_avg(int at) { - if(host[at].returned == 0) - return 0; +int net_worst(int at) +{ + return (host[at].worst); +} - return host[at].total / host[at].returned; +int net_avg(int at) +{ + return (host[at].avg); +} +int net_gmean(int at) +{ + return (host[at].gmean); } +int net_stdev(int at) +{ + if( host[at].returned > 1 ) { + return ( sqrt( host[at].var/(host[at].returned -1.0) ) ); + } else { + return( 0 ); + } +} +/* jitter stuff */ +int net_jitter(int at) { return (host[at].jitter); } +int net_jworst(int at) { return (host[at].jworst); } +int net_javg(int at) { return (host[at].javg); } +int net_jinta(int at) { return (host[at].jinta); } +/* end jitter */ + -int net_max() { +int net_max() +{ int at; int max; max = 0; - for(at = 0; at < MaxHost-2; at++) { + // replacedByMin + // for(at = 0; at < MaxHost-2; at++) { + for(at = 0; at < maxTTL-1; at++) { if(host[at].addr == remoteaddress.sin_addr.s_addr) { return at + 1; } else if(host[at].addr != 0) { @@ -355,25 +457,37 @@ int net_max() { return max; } +/* add by Min (wonder its named net_min;-)) because of ttl stuff */ +int net_min () +{ + return ( fstTTL - 1 ); +} + /* Added by Brian Casey December 1997 bcasey@imagiware.com*/ -int net_returned(int at) { - return host[at].returned; +int net_returned(int at) +{ + return host[at].returned; } -int net_xmit(int at) { - return host[at].xmit; +int net_xmit(int at) +{ + return host[at].xmit; } -int net_transit(int at) { - return host[at].transit; + +int net_transit(int at) +{ + return host[at].transit; } -int net_up(int at) { +int net_up(int at) +{ return host[at].up; } -void net_end_transit() { +void net_end_transit() +{ int at; - + for(at = 0; at < MaxHost; at++) { host[at].transit = 0; } @@ -381,25 +495,39 @@ void net_end_transit() { -int net_send_batch() { - int n_unknown, i; - +int net_send_batch() +{ + int n_unknown=0, i; + + /* randomized packet size and/or bit pattern if packetsize<0 and/or + bitpattern<0. abs(packetsize) and/or abs(bitpattern) will be used + */ + if( batch_at < fstTTL ) { + if( packetsize < 0 ) { + packetsize = + - (int)(MINPACKET + (MAXPACKET-MINPACKET)*(rand()/(RAND_MAX+0.1))); + } + if( bitpattern < 0 ) { + bitpattern = - (int)(256 + 255*(rand()/(RAND_MAX+0.1))); + } + } net_send_query(batch_at); - n_unknown = 0; - - for (i=0;i MAX_UNKNOWN_HOSTS) || - (batch_at >= MaxHost-2)) { + // or reach limit + (batch_at >= maxTTL-1)) { numhosts = batch_at+1; - batch_at = 0; + batch_at = fstTTL - 1; return 1; } @@ -408,7 +536,8 @@ int net_send_batch() { } -int net_preopen() { +int net_preopen() +{ int trueopt = 1; sendsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); @@ -432,7 +561,8 @@ int net_preopen() { return 0; } -int net_open(int addr) { +int net_open(int addr) +{ net_reset(); remoteaddress.sin_family = AF_INET; @@ -441,7 +571,8 @@ int net_open(int addr) { return 0; } -void net_reopen(int addr) { +void net_reopen(int addr) +{ int at; for(at = 0; at < MaxHost; at++) { @@ -455,11 +586,12 @@ void net_reopen(int addr) { net_send_batch(); } -void net_reset() { +void net_reset() +{ int at; int i; - batch_at = 0; + batch_at = fstTTL - 1; /* above replacedByMin */ numhosts = 10; for(at = 0; at < MaxHost; at++) { @@ -468,9 +600,16 @@ void net_reset() { host[at].returned = 0; host[at].sent = 0; host[at].up = 0; - host[at].total = 0; + host[at].last = 0; + host[at].avg = 0; host[at].best = 0; host[at].worst = 0; + host[at].gmean = 0; + host[at].var = 0; + host[at].jitter = 0; + host[at].javg = 0; + host[at].jworst = 0; + host[at].jinta = 0; for (i=0; i SAVED_PINGS) { - return; - } - host[at].saved[idx] = ms; +void net_save_return(int at, int seq, int ms) +{ + int idx; + idx = seq - host[at].saved_seq_offset; + if (idx < 0 || idx > SAVED_PINGS) { + return; + } + host[at].saved[idx] = ms; } diff --git a/net.h b/net.h index 285e220..4e35062 100644 --- a/net.h +++ b/net.h @@ -26,13 +26,24 @@ void net_reset(); void net_close(); int net_waitfd(); void net_process_return(); -int net_max(); + +int net_max(void); +int net_min(void); +int net_last(int at); int net_addr(int at); -int net_percent(int at); +int net_loss(int at); +int net_drop(int at); +int net_last(int at); int net_best(int at); int net_worst(int at); -int net_last(int at); int net_avg(int at); +int net_gmean(int at); +int net_stdev(int at); +int net_jitter(int at); +int net_jworst(int at); +int net_javg(int at); +int net_jinta(int at); + int net_send_batch(); void net_end_transit(); @@ -52,8 +63,58 @@ void net_save_xmit(int at); void net_save_return(int at, int seq, int ms); int net_duplicate(int at, int seq); +#define MAXPATH 8 #define MaxHost 256 #define MaxSequence 65536 -#define MAXPACKET 4096 -#define MINPACKET 64 +#define MAXPACKET 4470 /* largest test ICMP packet size */ +#define MINPACKET 28 /* 20 bytes IP header and 8 bytes ICMP */ + +/* stuff used by display such as report, curses... --Min */ +#define MAXFLD 20 /* max stats fields to display */ + +#if defined (__STDC__) && __STDC__ +#define CONST const +#else +#define CONST /* */ +#endif + + +/* dynamic field drawing */ +struct fields { + CONST char *descr; + CONST char *title; + CONST char *format; + int length; + int (*net_xxx)(); +}; + +static struct fields data_fields[MAXFLD] = { + /* Remark, Header, Format, Width, CallBackFunc */ + { ": Space between fields", " ", " ", 1, &net_drop }, /* 0 */ + { "L: Loss Ratio", "Loss%", " %4.1f%%", 6, &net_loss }, /* 1 */ + { "D: Dropped Packets", "Drop", " %4d", 5, &net_drop }, /* 2 */ + { "R: Received Packets", "Rcv", " %5d", 6, &net_returned}, /* 3 */ + { "S: Sent Packets", "Snt", " %5d", 6, &net_xmit }, /* 4 */ + { "N: Newest RTT(ms)", "Last", " %5.1f", 6, &net_last }, /* 5 */ + { "B: Min/Best RTT(ms)", "Best", " %5.1f", 6, &net_best }, /* 6 */ + { "A: Average RTT(ms)", "Avg", " %5.1f", 6, &net_avg }, /* 7 */ + { "W: Max/Worst RTT(ms)", "Wrst", " %5.1f", 6, &net_worst }, /* 8 */ + { "V: Standard Deviation", "StDev", " %5.1f", 6, &net_stdev }, /* 9 */ + { "G: Geometric Mean", "Gmean", " %5.1f", 6, &net_gmean }, /* 10 */ + { "J: Current Jitter", "Jttr", " %4.1f", 5, &net_jitter}, /* 11 */ + { "M: Jitter Mean/Avg.", "Javg", " %4.1f", 5, &net_javg }, /* 12 */ + { "X: Worst Jitter", "Jmax", " %4.1f", 5, &net_jworst}, /* 13 */ + { "I: Interarrival Jitter", "Jint", " %4.1f", 5, &net_jinta }, /* 14 */ + { 0, 0, 0, 0, 0 } +}; + +/* keys: the value in the array is the index number in data_fields[] */ +static int fld_index[] = { + 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* ' ', 0,1..9 */ + 7, 6, -1, 2, -1, -1, 10, -1, 14, 11, -1, 1, 12, /* A..M */ + 5, -1, -1, -1, 3, 4, -1, -1, 9, 8, 13, -1, -1, /* N..Z */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a..m */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* n..z */ + -1 +}; diff --git a/report.c b/report.c index 96c1f31..b254648 100644 --- a/report.c +++ b/report.c @@ -29,24 +29,51 @@ #include "net.h" extern int dns; +extern char LocalHostname[]; +extern char *Hostname; +extern char fld_active[]; +extern int fstTTL; +extern int maxTTL; +extern int packetsize; +extern int bitpattern; +extern int tos; +extern int MaxPing; -void report_open() { - printf("%-38s LOSS RCVD SENT BEST AVG WORST\n", "HOST"); - fflush(stdout); -} +void report_open() {} void report_close() { - int at, max, addr; + int i, j, at, max, addr; int haddr; char name[81]; + char buf[1024]; + char fmt[16]; + int len=0; struct hostent *host; - max = net_max(); + sprintf(buf, "HOST: %-33s", LocalHostname); + for( i=0; i= 'a' && fld_active[i]<= 'z') { + j = fld_active[i] - 'a' + 11 + 26; + } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') { + j = fld_active[i] - 'A' + 11; + } else if( fld_active[i]>= '0' && fld_active[i]<= '9') { + j = fld_active[i] - '0' +1; + } else if( fld_active[i] == ' ' ) { + j = 0; + } else { + continue; /* ignore unknown */ + } + sprintf( fmt, "%%%ds", data_fields[fld_index[j]].length ); + sprintf( buf +33+ len, fmt, data_fields[fld_index[j]].title ); + len += data_fields[fld_index[j]].length; + } + printf("%s\n",buf); - for(at = 0; at < max; at++) { + max = net_max(); + at = net_min(); + for(; at < max; at++) { addr = net_addr(at); - strcpy(name, ""); if(addr == 0) { sprintf(name, "???"); } else { @@ -62,22 +89,199 @@ void report_close() { } } - /* Coding tip: + len=0; + sprintf( buf, " %2d. %-33s", at+1, name); + for( i=0; i= 'a' && fld_active[i]<= 'z') { + j = fld_active[i] - 'a' + 11 + 26; + } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') { + j = fld_active[i] - 'A' + 11; + } else if( fld_active[i]>= '0' && fld_active[i]<= '9') { + j = fld_active[i] - '0' +1; + } else if( fld_active[i] == ' ' ) { + j = 0; + } else { + continue; /* ignore stuff don't understand */ + } - NEVER EVER use a format like "%6d%6d%6d". This will nicely - format your three numbers in 18 spaces just like " %5d %5d %5d" - and save you three bytes of static string space. However, when - the numbers suddenly become a bit larger than you expected - you'll end up with unexpected results: just one huge number - instead of three separate numbers. This especially matters if - the reader of the info is a program and not human. */ + /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ + if( index( data_fields[ fld_index[j] ].format, 'f' ) ) { + sprintf( buf +33+ len, data_fields[ fld_index[j] ].format, + data_fields[ fld_index[j] ].net_xxx(at) /1000.0 ); + } else { + sprintf( buf +33+ len, data_fields[ fld_index[j] ].format, + data_fields[ fld_index[j] ].net_xxx(at) ); + } + len += data_fields[fld_index[j]].length; + } + printf("%s\n",buf); + } +} +void txt_open() {} +void txt_close() { report_close(); } + + + +void xml_open() {} +void xml_close() { + int i, j, at, max, addr; + int haddr; + char name[81]; + struct hostent *host; - printf("%-38s %4d%% %5d %4d %7.2f %7.2f %7.2f\n", name, - net_percent(at), - net_returned(at), net_xmit(at), - net_best(at)/1000.0, net_avg(at)/1000.0, net_worst(at)/1000.0); + printf("=0 ){ + printf(" PSIZE=%d", packetsize); + } else { + printf(" PSIZE=rand(%d-%d)",MINPACKET, MAXPACKET); } + if( bitpattern>=0 ) { + printf(" BITPATTERN=0x%02X", (unsigned char)(bitpattern)); + } else { + printf(" BITPATTERN=rand(0x00-FF)"); + } + printf(" TESTS=%d>\n", MaxPing); + + max = net_max(); + at = net_min(); + for(; at < max; at++) { + addr = net_addr(at); + + if(addr == 0) { + sprintf(name, "???"); + } else { + haddr = htonl(addr); + host = dns?gethostbyaddr((char *)&haddr, sizeof(int), AF_INET):NULL; + + if (host != NULL) { + strncpy(name, host->h_name, 80); + name[80] = 0; + } else { + sprintf(name, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff); + } + } + + printf(" \n", at+1, name); + for( i=0; i= 'a' && fld_active[i]<= 'z') { + j = fld_active[i] - 'a' + 11 + 26; + } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') { + j = fld_active[i] - 'A' + 11; + } else if( fld_active[i]>= '0' && fld_active[i]<= '9') { + j = fld_active[i] - '0' +1; + } else if( fld_active[i] == ' ' ) { + continue; /* ignore space */ + j = 0; + } else { + continue; /* ignore stuff don't understand */ + } + + strcpy(name, " <%s>"); + strcat(name, data_fields[ fld_index[j] ].format); + strcat(name, "\n"); + /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ + if( index( data_fields[ fld_index[j] ].format, 'f' ) ) { + printf( name, + data_fields[fld_index[j]].title, + data_fields[ fld_index[j] ].net_xxx(at) /1000.0, + data_fields[fld_index[j]].title ); + } else { + printf( name, + data_fields[fld_index[j]].title, + data_fields[ fld_index[j] ].net_xxx(at), + data_fields[fld_index[j]].title ); + } + } + printf(" \n"); + } + printf("\n"); } +void csv_open() {} +void csv_close() { + int i, j, at, max, addr; + int haddr; + char name[81]; + struct hostent *host; + + /* Caption */ + printf("=0 ){ + printf(" PSIZE=%d", packetsize); + } else { + printf(" PSIZE=rand(%d-%d)",MINPACKET, MAXPACKET); + } + if( bitpattern>=0 ) { + printf(" BITPATTERN=0x%02X", (unsigned char)(bitpattern)); + } else { + printf(" BITPATTERN=rand(0x00-FF)"); + } + printf(" TESTS=%d>\n", MaxPing); + + /* Header */ + printf("HUPCOUNT, HOST"); + for( i=0; i= 'a' && fld_active[i]<= 'z') { + j = fld_active[i] - 'a' + 11 + 26; + } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') { + j = fld_active[i] - 'A' + 11; + } else if( fld_active[i]>= '0' && fld_active[i]<= '9') { + j = fld_active[i] - '0' +1; + } else if( fld_active[i] == ' ' ) { + continue; /* ignore space */ + j = 0; + } else { + continue; /* ignore stuff don't understand */ + } + printf( ", %s", data_fields[fld_index[j]].title ); + } + printf("\n"); + + max = net_max(); + at = net_min(); + for(; at < max; at++) { + addr = net_addr(at); + + if(addr == 0) { + sprintf(name, "???"); + } else { + haddr = htonl(addr); + host = dns?gethostbyaddr((char *)&haddr, sizeof(int), AF_INET):NULL; + + if (host != NULL) { + strncpy(name, host->h_name, 80); + name[80] = 0; + } else { + sprintf(name, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff); + } + } + printf("%d, %s", at+1, name); + for( i=0; i= 'a' && fld_active[i]<= 'z') { + j = fld_active[i] - 'a' + 11 + 26; + } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') { + j = fld_active[i] - 'A' + 11; + } else if( fld_active[i]>= '0' && fld_active[i]<= '9') { + j = fld_active[i] - '0' +1; + } else if( fld_active[i] == ' ' ) { + continue; /* ignore space */ + j = 0; + } else { + continue; /* ignore stuff don't understand */ + } + /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ + if( index( data_fields[ fld_index[j] ].format, 'f' ) ) { + printf( ", %.2f", data_fields[ fld_index[j] ].net_xxx(at) /1000.0); + } else { + printf( ", %d", data_fields[ fld_index[j] ].net_xxx(at) ); + } + } + printf("\n"); + } +} diff --git a/report.h b/report.h index 8a8a9b6..b402f9b 100644 --- a/report.h +++ b/report.h @@ -21,3 +21,9 @@ void report_open(); void report_close(); +void txt_open(); +void txt_close(); +void xml_open(); +void xml_close(); +void csv_open(); +void csv_close(); diff --git a/select.c b/select.c index 1ce0d86..c95b13a 100644 --- a/select.c +++ b/select.c @@ -35,6 +35,7 @@ extern int Interactive; extern int MaxPing; +extern int ForceMaxPing; extern float WaitTime; double dnsinterval; @@ -44,19 +45,17 @@ int display_offset = 0; void select_loop() { fd_set readfd; - int anyset; - int action, maxfd; + int action; + int anyset = 0; + int maxfd = 0; int dnsfd, netfd; - int NumPing; - int paused; + int NumPing = 0; + int paused = 0; struct timeval lasttime, thistime, selecttime; int dt; int rv; - NumPing = 0; - anyset = 0; gettimeofday(&lasttime, NULL); - paused=0; while(1) { dt = calc_deltatime (WaitTime); @@ -74,13 +73,11 @@ void select_loop() { dnsfd = dns_waitfd(); FD_SET(dnsfd, &readfd); - if(dnsfd >= maxfd) - maxfd = dnsfd + 1; + if(dnsfd >= maxfd) maxfd = dnsfd + 1; netfd = net_waitfd(); FD_SET(netfd, &readfd); - if(netfd >= maxfd) - maxfd = netfd + 1; + if(netfd >= maxfd) maxfd = netfd + 1; do { if(anyset || paused) { @@ -88,9 +85,9 @@ void select_loop() { selecttime.tv_usec = 0; rv = select(maxfd, (void *)&readfd, NULL, NULL, &selecttime); + } else { - if(Interactive) - display_redraw(); + if(Interactive) display_redraw(); gettimeofday(&thistime, NULL); @@ -98,7 +95,7 @@ void select_loop() { (thistime.tv_sec == lasttime.tv_sec + intervaltime.tv_sec && thistime.tv_usec >= lasttime.tv_usec + intervaltime.tv_usec)) { lasttime = thistime; - if(NumPing >= MaxPing && !Interactive) + if(NumPing >= MaxPing && (!Interactive || ForceMaxPing)) return; if (net_send_batch()) NumPing++; @@ -134,60 +131,63 @@ void select_loop() { } anyset = 0; + /* Have we got new packets back? */ + if(FD_ISSET(netfd, &readfd)) { + net_process_return(); + anyset = 1; + } + /* Handle any pending resolver events */ dnsinterval = WaitTime; dns_events(&dnsinterval); + /* Have we finished a nameservice lookup? */ + if(FD_ISSET(dnsfd, &readfd)) { + dns_ack(); + anyset = 1; + } + /* Has a key been pressed? */ if(FD_ISSET(0, &readfd)) { - action = display_keyaction(); - - if(action == ActionQuit) + switch (display_keyaction()) { + case ActionQuit: + return; break; - - if(action == ActionReset) + case ActionReset: net_reset(); - - if (action == ActionDisplay) + break; + case ActionDisplay: display_mode = (display_mode+1) % 3; - - if (action == ActionClear) + break; + case ActionClear: display_clear(); - - if (action == ActionPause) + break; + case ActionPause: paused=1; - - if (action == ActionResume) + break; + case ActionResume: paused=0; + break; + case ActionDNS: + if (dns) { + use_dns = !use_dns; + display_clear(); + } + break; - if (action == ActionDNS && dns) { - use_dns = !use_dns; - display_clear(); - } - - if (action == ActionScrollDown) { + case ActionScrollDown: display_offset += 5; - } else if (action == ActionScrollUp) { + break; + case ActionScrollUp: display_offset -= 5; if (display_offset < 0) { display_offset = 0; } + break; } - - anyset = 1; - } - - /* Have we finished a nameservice lookup? */ - if(FD_ISSET(dnsfd, &readfd)) { - dns_ack(); - anyset = 1; - } - - /* Have we got new packets back? */ - if(FD_ISSET(netfd, &readfd)) { - net_process_return(); anyset = 1; } } + return; } diff --git a/split.c b/split.c index 388f581..7e01124 100644 --- a/split.c +++ b/split.c @@ -102,7 +102,7 @@ split_redraw() { if(name != NULL) { /* May be we should test name's length */ sprintf(newLine, "%s %d %d %d %d %d %d", name, - net_percent(at), + net_loss(at), net_returned(at), net_xmit(at), net_best(at) /1000, net_avg(at)/1000, net_worst(at)/1000); @@ -110,7 +110,7 @@ split_redraw() { sprintf(newLine, "%d.%d.%d.%d %d %d %d %d %d %d", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff, - net_percent(at), + net_loss(at), net_returned(at), net_xmit(at), net_best(at) /1000, net_avg(at)/1000, net_worst(at)/1000);