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");
struct command_t reply;
ip_t fromaddress;
int seq_num;
+ int err;
int round_trip_time;
char *reply_name;
struct mplslen mpls;
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;
}
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);
}
}
*probe_reply_func_t) (
struct mtr_ctl * ctl,
int sequence,
+ int err,
struct mplslen * mpls,
ip_t * addr,
int round_trip_time);
int at;
struct mplslen *mpls, *mplss;
ip_t *addr, *addrs;
+ int addrcmp_result;
+ int err;
int y;
char *name;
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);
}
attroff(A_BOLD);
}
-
} else {
- printw("???");
+ attron(A_BOLD);
+ printw("(%s)", host_error_to_string(err));
+ attroff(A_BOLD);
}
printw("\n");
int startstat,
int cols)
{
- int max, at, y;
+ int max, at, y, err;
ip_t *addr;
char *name;
int __unused_int ATTRIBUTE_UNUSED;
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);
#include "config.h"
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <time.h>
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);
+}
struct mtr_ctl *ctl);
extern void display_clear(
struct mtr_ctl *ctl);
+extern char *host_error_to_string(
+ int err);
struct nethost {
ip_t addr;
ip_t addrs[MAXPATH]; /* for multi paths byMin */
+ int err;
int xmit;
int returned;
int sent;
}
-/* 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)
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) {
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)
{
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;
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(