]> git.ipfire.org Git - thirdparty/mtr.git/commitdiff
ui: display "no route to host" error as host entry rather than abort 209/head
authorMatt Kimball <matt.kimball@gmail.com>
Tue, 11 Jul 2017 21:55:40 +0000 (14:55 -0700)
committerMatt Kimball <matt.kimball@gmail.com>
Tue, 11 Jul 2017 21:55:40 +0000 (14:55 -0700)
When a host is reported as unreachable in response to a particular
network probe, the Windows version of the mtr UI had the unfortuante
behavior of exiting and and printing a terse message.  This is
surprising to a user, who would expect mtr probes and reporting to
continue.

With this change, probing continues and a status reading
"no route to host" is displayed in the probe report.

This change will also improve the reporting of the Unix version of
mtr, now specifying "no route to host" instead of misleadingly
indicating that no reply has been received.

This fixes issue #179.

ui/cmdpipe.c
ui/cmdpipe.h
ui/curses.c
ui/display.c
ui/display.h
ui/net.c
ui/net.h

index a90fa4fc74836c7f70e384cc55e73913f36cd12b..a3e57836942aa9197e91fa9c7db85cada8237925 100644 (file)
@@ -621,16 +621,6 @@ void handle_reply_errors(
 
     reply_name = reply->command_name;
 
-    if (!strcmp(reply_name, "no-route")) {
-        display_close(ctl);
-        error(EXIT_FAILURE, 0, "No route to host");
-    }
-
-    if (!strcmp(reply_name, "network-down")) {
-        display_close(ctl);
-        error(EXIT_FAILURE, 0, "Network down");
-    }
-
     if (!strcmp(reply_name, "probes-exhausted")) {
         display_close(ctl);
         error(EXIT_FAILURE, 0, "Probes exhausted");
@@ -677,6 +667,7 @@ void handle_command_reply(
     struct command_t reply;
     ip_t fromaddress;
     int seq_num;
+    int err;
     int round_trip_time;
     char *reply_name;
     struct mplslen mpls;
@@ -698,8 +689,16 @@ void handle_command_reply(
     seq_num = reply.token;
     reply_name = reply.command_name;
 
-    /*  If the reply type is unknown, ignore it for future compatibility  */
-    if (strcmp(reply_name, "reply") && strcmp(reply_name, "ttl-expired")) {
+    /*  Check for known reply types.  */
+    if (!strcmp(reply_name, "reply")
+            || !strcmp(reply_name, "ttl-expired")) {
+        err = 0;
+    } else if (!strcmp(reply_name, "no-route")) {
+        err = ENETUNREACH;
+    } else if (!strcmp(reply_name, "network-down")) {
+        err = ENETDOWN;
+    } else {
+        /*  If the reply type is unknown, ignore it  */
         return;
     }
 
@@ -710,7 +709,7 @@ void handle_command_reply(
     if (parse_reply_arguments
         (ctl, &reply, &fromaddress, &round_trip_time, &mpls)) {
 
-        reply_func(ctl, seq_num, &mpls, (void *) &fromaddress,
+        reply_func(ctl, seq_num, err, &mpls, (void *) &fromaddress,
                    round_trip_time);
     }
 }
index 7a5b68719386669c71861105437402aa75cd2fc8..93d4439dc594f1052b785e5af756305ee478c397 100644 (file)
@@ -47,6 +47,7 @@ void (
     *probe_reply_func_t) (
     struct mtr_ctl * ctl,
     int sequence,
+    int err,
     struct mplslen * mpls,
     ip_t * addr,
     int round_trip_time);
index a7588ca3f9b4e744603e46ca27c8c64339656241..7566ad7f8444c782e17a195e61dd8fc73b8672f0 100644 (file)
@@ -404,6 +404,8 @@ static void mtr_curses_hosts(
     int at;
     struct mplslen *mpls, *mplss;
     ip_t *addr, *addrs;
+    int addrcmp_result;
+    int err;
     int y;
     char *name;
 
@@ -416,11 +418,14 @@ static void mtr_curses_hosts(
 
     for (at = net_min(ctl) + ctl->display_offset; at < max; at++) {
         printw("%2d. ", at + 1);
+        err = net_err(at);
         addr = net_addr(at);
         mpls = net_mpls(at);
 
-        if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af) !=
-            0) {
+        addrcmp_result = addrcmp(
+            (void *) addr, (void *) &ctl->unspec_addr, ctl->af);
+
+        if (err == 0 && addrcmp_result != 0) {
             name = dns_lookup(ctl, addr);
             if (!net_up(at))
                 attron(A_BOLD);
@@ -498,9 +503,10 @@ static void mtr_curses_hosts(
                 }
                 attroff(A_BOLD);
             }
-
         } else {
-            printw("???");
+            attron(A_BOLD);
+            printw("(%s)", host_error_to_string(err));
+            attroff(A_BOLD);
         }
 
         printw("\n");
@@ -618,7 +624,7 @@ static void mtr_curses_graph(
     int startstat,
     int cols)
 {
-    int max, at, y;
+    int max, at, y, err;
     ip_t *addr;
     char *name;
     int __unused_int ATTRIBUTE_UNUSED;
@@ -629,22 +635,31 @@ static void mtr_curses_graph(
         printw("%2d. ", at + 1);
 
         addr = net_addr(at);
+        err = net_err(at);
+
         if (!addr) {
-            printw("???\n");
+            printw("(%s)", host_error_to_string(err));
             continue;
         }
 
-        if (!net_up(at))
-            attron(A_BOLD);
-        if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
+        if (err == 0
+            && addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
+
+            if (!net_up(at)) {
+                attron(A_BOLD);
+            }
+
 #ifdef HAVE_IPINFO
             if (is_printii(ctl))
                 printw(fmt_ipinfo(ctl, addr));
 #endif
             name = dns_lookup(ctl, addr);
             printw("%s", name ? name : strlongip(ctl, addr));
-        } else
-            printw("???");
+        } else {
+            attron(A_BOLD);
+            printw("(%s)", host_error_to_string(err));
+        }
+
         attroff(A_BOLD);
 
         getyx(stdscr, y, __unused_int);
index 4c088896c781fbd7fcc2ecf3728ed63d7ea13b3a..95db14065b475b5df4197f1cfcbd49b3be02316c 100644 (file)
 
 #include "config.h"
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/types.h>
 #include <time.h>
 
@@ -250,3 +252,26 @@ void display_clear(
         mtr_curses_clear(ctl);
 #endif
 }
+
+
+/*
+    Given an errno error code corresponding to a host entry, return a
+    user readable error string.
+*/
+char *host_error_to_string(
+    int err)
+{
+    if (err == ENETUNREACH) {
+        return "no route to host";
+    }
+
+    if (err == ENETDOWN) {
+        return "network down";
+    }
+
+    if (err == 0) {
+        return "waiting for reply";
+    }
+
+    return strerror(err);
+}
index d82752886458eb1ae53440aca0e2186b78520ae4..e3561afea99f66e346da5f486f4bc7f68600f1e2 100644 (file)
@@ -81,3 +81,5 @@ extern void display_loop(
     struct mtr_ctl *ctl);
 extern void display_clear(
     struct mtr_ctl *ctl);
+extern char *host_error_to_string(
+    int err);
index 3a7abc8614e1df679eb3e5acf1f32089968efb99..6396ab6d34574323aa39daf15e32554f871f5504 100644 (file)
--- a/ui/net.c
+++ b/ui/net.c
@@ -51,6 +51,7 @@ static void sockaddrtop(
 struct nethost {
     ip_t addr;
     ip_t addrs[MAXPATH];        /* for multi paths byMin */
+    int err;
     int xmit;
     int returned;
     int sent;
@@ -185,11 +186,37 @@ static void net_send_query(
 }
 
 
-/* We got a return on something we sent out.  Record the address and
-   time.  */
+/*
+    Mark a sequence entry as completed and return the host index
+    being probed.
+
+    Returns -1 in the case of an invalid sequence number.
+*/
+static int mark_sequence_complete(
+    int seq)
+{
+    if ((seq < 0) || (seq >= MaxSequence)) {
+        return -1;
+    }
+
+    if (!sequence[seq].transit) {
+        return -1;
+    }
+    sequence[seq].transit = 0;
+
+    return sequence[seq].index;
+}
+
+
+/*
+    A probe has successfully completed.
+
+    Record the round trip time and address of the responding host.
+*/
 static void net_process_ping(
     struct mtr_ctl *ctl,
     int seq,
+    int err,
     struct mplslen *mpls,
     ip_t * addr,
     int totusec)
@@ -206,16 +233,12 @@ static void net_process_ping(
 
     addrcpy((void *) &addrcopy, (char *) addr, ctl->af);
 
-    if ((seq < 0) || (seq >= MaxSequence)) {
-        return;
-    }
-
-    if (!sequence[seq].transit) {
+    index = mark_sequence_complete(seq);
+    if (index < 0) {
         return;
     }
-    sequence[seq].transit = 0;
 
-    index = sequence[seq].index;
+    host[index].err = err;
 
     if (addrcmp((void *) &(host[index].addr),
                 (void *) &ctl->unspec_addr, ctl->af) == 0) {
@@ -325,6 +348,15 @@ ip_t *net_addrs(
     return (ip_t *) & (host[at].addrs[i]);
 }
 
+/*
+    Get the error code corresponding to a host entry.
+*/
+int net_err(
+    int at)
+{
+    return host[at].err;
+}
+
 void *net_mpls(
     int at)
 {
@@ -444,6 +476,13 @@ int net_max(
         if (addrcmp((void *) &(host[at].addr),
                     (void *) remoteaddress, ctl->af) == 0) {
             return at + 1;
+        } else if (host[at].err != 0) {
+            /*
+                If a hop has returned an ICMP error
+                (such as "no route to host") then we'll consider that the
+                final hop.
+            */
+            return at + 1;
         } else if (addrcmp((void *) &(host[at].addr),
                            (void *) &ctl->unspec_addr, ctl->af) != 0) {
             max = at + 2;
index 6b95a00a2be8dc25b71f5dbc6b57438d2e8d9bc3..c713914b46f1f2266d81899209e4393e341a52f7 100644 (file)
--- a/ui/net.h
+++ b/ui/net.h
@@ -56,6 +56,8 @@ extern int net_last(
     int at);
 extern ip_t *net_addr(
     int at);
+extern int net_err(
+    int at);
 extern void *net_mpls(
     int at);
 extern void *net_mplss(