]> git.ipfire.org Git - thirdparty/mtr.git/commitdiff
mtr v0.55 v0.55
authorRoger Wolff <r.e.wolff@bitwizard.nl>
Thu, 1 Apr 2004 00:00:00 +0000 (00:00 +0000)
committerTravis Cross <tc@traviscross.com>
Sun, 3 Feb 2013 20:45:37 +0000 (20:45 +0000)
 - 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

15 files changed:
AUTHORS
NEWS
configure.in
curses.c
display.c
display.h
gtk.c
mtr.8
mtr.c
net.c
net.h
report.c
report.h
select.c
split.c

diff --git a/AUTHORS b/AUTHORS
index ff20499e629810a2d46c055b7d64a7857eb65dff..a7f9644eac8f5e51d6d712efdde6b7ced2d88a59 100644 (file)
--- 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 66ac13e3ae331db26f6c39660870e2cf02dc8d17..4e06bf204ab11fd64fc09221852c058870a14013 100644 (file)
--- 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......
  
index 08f5499d634d2f2139c808351001cfd7f4b9539c..707403ad77c65da58a924bcc1e7c61d1dcf29b85 100644 (file)
@@ -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)
index d9bd20d71d1c24dbe1e38a00035f066de822fdfc..f7f63b215ecd57bab21d5924831019f9cd261b43 100644 (file)
--- a/curses.c
+++ b/curses.c
 #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) {
@@ -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<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);
 
@@ -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<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("???");
@@ -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<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];
index a00ff10c93945126c68e575dadc92c68151c350a..b9502ce1687965cd20751f883bae026cda20801c 100644 (file)
--- 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;
index 0c4bdd6ce9493abc16532d26deded379aede766a..648e5b194d813a862cc927271a3e57b1a6719563 100644 (file)
--- a/display.h
+++ b/display.h
     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 64b13b074c2375f01787a1f608a381525bf25090..c5f9cedc3327df553335f9939348f06218ccb2a8 100644 (file)
--- 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 c56c1a4b696798d11ae80f86f7846083ab97eb7d..89ac76c32661855c7526b9a8ca145a4833a96745 100644 (file)
--- 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 ef84187692b553bde3f96a143a555680b98daa7d..1036eb3c8f4920045f67b58173bca56ed770e707 100644 (file)
--- 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 2ac9ce0075e8271a15e41f946c4720f055f28629..f3d0ea9298b72044716f390d6e7515ccfdc3ce62 100644 (file)
--- a/net.c
+++ b/net.c
@@ -33,6 +33,7 @@
 #include <memory.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <math.h>
 #include <errno.h>
 
@@ -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<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;
@@ -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<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;
   }
 
@@ -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; i++) {
       host[at].saved[i] = -2;  /* unsent */
     }
@@ -484,18 +623,21 @@ void net_reset() {
   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() 
@@ -508,17 +650,19 @@ 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;
 }
diff --git a/net.h b/net.h
index 285e220511ca16c033d70866aec66f74fb587ccb..4e35062345e5f51cdead6e8e4ebf5368ec51f9c4 100644 (file)
--- 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 */
+  { "<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
+};
index 96c1f3158c193f70650a3390915c76f3ea78eb79..b254648de91a9d52923731de212e4a2dd2283a6f 100644 (file)
--- a/report.c
+++ b/report.c
 #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 {
@@ -62,22 +89,199 @@ void report_close() {
       }
     }
 
-    /* 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");
+  }
+}
index 8a8a9b647b30ab4bd60bcf266459db80803c0192..b402f9bd7d60bab73fac1af81b7f4601c2e60b35 100644 (file)
--- 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();
index 1ce0d86d7bbd4adefd1da5ccbf9826ff8d405a63..c95b13a498e1c9dce390b1e3983f0f6b34d476ce 100644 (file)
--- 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 388f5810a337afdef15b184bd54e73197714c06a..7e0112450723f23e871ddc4cb3792168c7b4db82 100644 (file)
--- 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);