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
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......
AC_INIT(mtr.c)
-AM_INIT_AUTOMAKE(mtr, 0.54)
+AM_INIT_AUTOMAKE(mtr, 0.55)
AC_SUBST(GTK_OBJ)
AC_SUBST(CURSES_OBJ)
#endif
#include <time.h>
+
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) {
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;
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<MAXFLD ) {
+ attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh;
+ buf[i++] = c; /* need more checking on 'c' */
+ }
+ buf[i] = '\0';
+ packetsize = atoi ( buf );
+ if( packetsize >=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<MAXFLD ) {
+ attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh;
+ buf[i++] = c; /* need more checking on 'c' */
+ }
+ buf[i] = '\0';
+ bitpattern = atoi ( buf );
+ if( bitpattern > 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<MAXFLD ) {
+ attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh;
+ buf[i++] = c; /* need more checking on 'c' */
+ }
+ buf[i] = '\0';
+ tos = atoi ( buf );
+ if( tos > 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<MAXFLD ) {
+ attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh;
+ buf[i++] = c; /* need more checking on 'c' */
+ }
+ buf[i] = '\0';
+ i = atoi( buf );
+
+ if ( i < 1 ) return ActionNone;
+ WaitTime = (float) i;
+
+ return ActionNone;
+ }
+ if (tolower(c) == 'f') {
+ mvprintw(2, 0, "First TTL: %d\n\n", fstTTL );
+ move(2,11);
+ refresh();
+ while ( (c=getch ()) != '\n' && i<MAXFLD ) {
+ attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh;
+ buf[i++] = c; /* need more checking on 'c' */
+ }
+ buf[i] = '\0';
+ i = atoi( buf );
+
+ if ( i < 1 || 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<MAXFLD ) {
+ attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh;
+ buf[i++] = c; /* need more checking on 'c' */
+ }
+ buf[i] = '\0';
+ i = atoi( buf );
+
+ if ( i < fstTTL || 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<MAXFLD; i++ ){
+ if( data_fields[i].descr != NULL )
+ printw( " %s\n", data_fields[i].descr);
+ }
+ printw("\n");
+ move(2,8); /* length of "Fields: " */
+ refresh();
+
+ i = 0;
+ while ( (c=getch ()) != '\n' && i<MAXFLD ) {
+ attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh;
+ if( c>= '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 <n> report cycle n, default n=infinite\n" );
+ printw(" i <n> set the ping interval to n seconds, default n=1\n" );
+ printw(" f <n> set the initial time-to-live(ttl), default n=1\n" );
+ printw(" m <n> set the max time-to-live, default n= # of hops\n" );
+ printw(" s <n> set the packet size to n or random(n<0)\n" );
+ printw(" b <c> set ping bit pattern to c(0..255) or random(c<0)\n" );
+ printw(" Q <t> 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);
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<MAXFLD; i++ ) {
+ // assume only a-zA-Z are valid options, and error checking
+ // is done in the input side?
+ if( fld_active[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<MAXPATH; i++ ) {
+ addrs = net_addrs(at, i);
+ if( addrs == addr ) continue;
+ if( addrs == 0 ) break;
+
+ name = dns_lookup(addrs);
+ if (! net_up(at)) attron(A_BOLD);
+ if(name != NULL) {
+ printw("\n %s", name);
+ } else {
+ printw("\n %d.%d.%d.%d",
+ (addrs >> 24) & 0xff, (addrs >> 16) & 0xff,
+ (addrs >> 8) & 0xff, addrs & 0xff);
+ }
+ attroff(A_BOLD);
+ }
} else {
printw("???");
printw("\n");
}
+ move(2, 0);
}
static double factors[] = { 0.02, 0.05, 0.08, 0.15, 0.33, 0.50, 0.80, 1.00 };
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);
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<MAXFLD; i++ ) {
+ // assume only 0-9A-Za-z are valid options, and error checking
+ // is down on the input side
+ if( fld_active[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];
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;
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;
void display_rawping(int host, int msec) {
switch(DisplayMode) {
case DisplayReport:
+ case DisplayTXT:
+ case DisplayXML:
+ case DisplayCSV:
case DisplaySplit: /* BL */
case DisplayCurses:
case DisplayGTK:
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:
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;
mtr_curses_clear();
break;
case DisplayReport:
+ case DisplayTXT:
+ case DisplayXML:
+ case DisplayCSV:
case DisplaySplit: /* BL */
case DisplayRaw:
break;
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);
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;
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);
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);
}
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);
}
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);
.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
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;
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;
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)
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;
+ }
+ }
}
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 */
printf("mtr: Unable to drop permissions.\n");
exit(1);
}
+
+ /* reset the random seed */
+ srand(getpid());
display_detect(&argc, &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 */
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;
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);
}
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();
#include <memory.h>
#include <unistd.h>
#include <stdio.h>
+#include <stdlib.h>
#include <math.h>
#include <errno.h>
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;
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 */
}
/* 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;
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");
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;
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<MAXPATH; ) {
+ if( host[index].addrs[i] == addr || host[index].addrs[i] == 0 ) break;
+ i++;
+ }
+ if( host[index].addrs[i] != addr && i<MAXPATH ) {
+ host[index].addrs[i] = addr;
+ }
+ /* end multi paths */
}
- if(host[index].returned <= 0) {
- host[index].best = host[index].worst = totusec;
- }
+
+ host[index].jitter = totusec - host[index].last;
+ if( host[index].jitter < 0 ) host[index].jitter = - host[index].jitter;
host[index].last = totusec;
- if(totusec < host[index].best)
- host[index].best = totusec;
- if(totusec > 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;
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;
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))
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) {
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;
}
-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<batch_at;i++) {
+ for (i=fstTTL-1;i<batch_at;i++) {
if (host[i].addr == 0)
n_unknown++;
if (host[i].addr == remoteaddress.sin_addr.s_addr)
- n_unknown = 100; /* Make sure we drop into "we should restart" */
+ n_unknown = MaxHost; /* Make sure we drop into "we should restart" */
}
- if ((host[batch_at].addr == remoteaddress.sin_addr.s_addr) ||
+ if ( // success in reaching target
+ (host[batch_at].addr == remoteaddress.sin_addr.s_addr) ||
+ // fail in consecuitive MAX_UNKNOWN_HOSTS (firewall?)
(n_unknown > 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;
}
}
-int net_preopen() {
+int net_preopen()
+{
int trueopt = 1;
sendsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
return 0;
}
-int net_open(int addr) {
+int net_open(int addr)
+{
net_reset();
remoteaddress.sin_family = AF_INET;
return 0;
}
-void net_reopen(int addr) {
+void net_reopen(int addr)
+{
int at;
for(at = 0; at < MaxHost; at++) {
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++) {
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; i++) {
host[at].saved[i] = -2; /* unsent */
}
gettimeofday(&reset, NULL);
}
-void net_close() {
+void net_close()
+{
close(sendsock);
close(recvsock);
}
-int net_waitfd() {
+int net_waitfd()
+{
return recvsock;
}
-int* net_saved_pings(int at) {
- return host[at].saved;
+int* net_saved_pings(int at)
+{
+ return host[at].saved;
}
void net_save_increment()
}
}
-void net_save_xmit(int at) {
+void net_save_xmit(int at)
+{
if (host[at].saved[SAVED_PINGS-1] != -2)
net_save_increment();
host[at].saved[SAVED_PINGS-1] = -1;
}
-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;
+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;
}
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();
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 */
+ { "<sp>: 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
+};
#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<MAXFLD; i++ ) {
+ if( fld_active[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 {
}
}
- /* Coding tip:
+ len=0;
+ sprintf( buf, " %2d. %-33s", at+1, name);
+ for( i=0; i<MAXFLD; i++ ) {
+ if( fld_active[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("<MTR SRC=%s DST=%s", LocalHostname, Hostname);
+ printf(" TOS=0x%X", tos);
+ if( packetsize>=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(" <HUB COUNT=%d HOST=%s>\n", at+1, name);
+ for( i=0; i<MAXFLD; i++ ) {
+ if( fld_active[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, "</%s>\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(" </HUB>\n");
+ }
+ printf("</MTR>\n");
}
+void csv_open() {}
+void csv_close() {
+ int i, j, at, max, addr;
+ int haddr;
+ char name[81];
+ struct hostent *host;
+
+ /* Caption */
+ printf("<SRC=%s DST=%s", LocalHostname, Hostname);
+ printf(" TOS=0x%X", tos);
+ if( packetsize>=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<MAXFLD; i++ ) {
+ if( fld_active[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<MAXFLD; i++ ) {
+ if( fld_active[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");
+ }
+}
void report_open();
void report_close();
+void txt_open();
+void txt_close();
+void xml_open();
+void xml_close();
+void csv_open();
+void csv_close();
extern int Interactive;
extern int MaxPing;
+extern int ForceMaxPing;
extern float WaitTime;
double dnsinterval;
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);
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) {
selecttime.tv_usec = 0;
rv = select(maxfd, (void *)&readfd, NULL, NULL, &selecttime);
+
} else {
- if(Interactive)
- display_redraw();
+ if(Interactive) display_redraw();
gettimeofday(&thistime, NULL);
(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++;
}
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;
}
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);
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);