/* mtr -- a network diagnostic tool Copyright (C) 1997,1998 Matt Kimball This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NO_CURSES #include #include #if defined(HAVE_NCURSES_H) # include #elif defined(HAVE_NCURSES_CURSES_H) # include #elif defined(HAVE_CURSES_H) # include #elif defined(HAVE_CURSESX_H) # include #else # error No curses header file available #endif #if defined(HAVE_SYS_TYPES_H) #include #else /* If a system doesn't have sys/types.h, lets hope that time_t is an int */ #define time_t int #endif #ifndef HAVE_ATTRON #define attron(x) #define attroff(x) #endif #ifndef getmaxyx # define getmaxyx(win,y,x) ((y) = (win)->_maxy + 1, (x) = (win)->_maxx + 1) #endif #include "mtr-curses.h" #include "display.h" #include "net.h" #include "dns.h" #endif #include extern char LocalHostname[]; extern int PrintASN; extern int PrintOwner; void pwcenter(char *str) { int maxx, maxy; int cx; getmaxyx(stdscr, maxy, maxx); cx = (signed)(maxx - strlen(str)) / 2; while(cx-- > 0) printw(" "); printw(str); } int mtr_curses_keyaction() { char c = getch(); if(tolower(c) == 'q') return ActionQuit; if(c==3) return ActionQuit; if (c==12) return ActionClear; if ((c==19) || (tolower (c) == 'p')) return ActionPause; if ((c==17) || (c == ' ')) return ActionResume; if(tolower(c) == 'r') return ActionReset; if (tolower(c) == 'd') return ActionDisplay; if (tolower(c) == 'n') return ActionDNS; return 0; } void mtr_curses_hosts(int startstat) { int max; int at; int addr; int y, x; char *name; char asn[21]="[?]"; max = net_max(); for(at = 0; at < max; at++) { printw("%2d. ", at + 1); addr = net_addr(at); if(addr != 0) { name = dns_lookup(addr); if (! net_up(at)) attron(A_BOLD); if(name != NULL) { printw("%s", name); } else { printw("%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); } if(PrintASN) printw(" [%s]",get_origin(name,addr)); if (PrintOwner) { struct in_addr a; a.s_addr = htonl(addr); printw(" (%s)",lookup_owner(a,name,addr)); } attroff(A_BOLD); getyx(stdscr, y, x); 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); } else { printw("???"); } printw("\n"); } } static double factors[] = { 0.02, 0.05, 0.08, 0.15, 0.33, 0.50, 0.80, 1.00 }; static int scale[8]; static int low_ms, high_ms; void mtr_gen_scale(void) { int *saved, i, max, at; int range; low_ms = 1000000; high_ms = -1; for (i = 0; i < 8; i++) { scale[i] = 0; } max = net_max(); for (at = 0; at < max; at++) { saved = net_saved_pings(at); for (i = 0; i < SAVED_PINGS; i++) { if (saved[i] < 0) continue; if (saved[i] < low_ms) { low_ms = saved[i]; } if (saved[i] > high_ms) { high_ms = saved[i]; } } } range = high_ms - low_ms; for (i = 0; i < 8; i++) { scale[i] = low_ms + ((double)range * factors[i]); } } static const char* block_map = ".123abc>"; void mtr_print_scaled(int ms) { int i; for (i = 0; i < 8; i++) { if (ms <= scale[i]) { printw("%c", block_map[i]); return; } } printw(">"); } void mtr_fill_graph(int at, int cols) { int* saved; int i; int val; saved = net_saved_pings(at); for (i = SAVED_PINGS-cols; i < SAVED_PINGS; i++) { if (saved[i] == -2) { printw(" "); } else if (saved[i] == -1) { attron(A_BOLD); printw("?"); attroff(A_BOLD); } else { if (display_mode == 1) { if (saved[i] > scale[6]) { printw("%c", block_map[7]); } else { printw("."); } } else { mtr_print_scaled(saved[i]); } } } } void mtr_curses_graph(int startstat, int cols) { int max, at, addr, y, x; char* name; max = net_max(); for (at = 0; at < max; at++) { printw("%2d. ", at+1); addr = net_addr(at); if (!addr) { printw("???\n"); continue; } if (! net_up(at)) attron(A_BOLD); name = dns_lookup(addr); if (name) { printw("%s", name); } else { printw("%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) && 0xff, (addr >> 8) & 0xff, addr & 0xff); } attroff(A_BOLD); getyx(stdscr, y, x); move(y, startstat); printw(" "); mtr_fill_graph(at, cols); printw("\n"); } } void mtr_curses_redraw() { int maxx, maxy; int startstat; int rowstat; int i; time_t t; erase(); getmaxyx(stdscr, maxy, maxx); rowstat = 5; move(0, 0); attron(A_BOLD); pwcenter("Matt's traceroute [v" VERSION "]"); attroff(A_BOLD); mvprintw(1,0, LocalHostname); 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); 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"); attroff(A_BOLD); move(rowstat, 0); mtr_curses_hosts(startstat); } else { /* David Sward, Jan 1999 */ char msg[80]; int max_cols = maxx<=SAVED_PINGS+30 ? maxx-30 : SAVED_PINGS; startstat = 28; sprintf(msg, " Last %3d pings", max_cols); mvprintw(rowstat - 1, startstat, msg); attroff(A_BOLD); move(rowstat, 0); mtr_gen_scale(); mtr_curses_graph(startstat, max_cols); printw("\n"); attron(A_BOLD); printw("Scale:"); attroff(A_BOLD); for (i = 0; i < 7; i++) { printw(" %c:%d ms", block_map[i], scale[i]/1000); } } refresh(); } void mtr_curses_open() { initscr(); raw(); noecho(); mtr_curses_redraw(); } void mtr_curses_close() { printw("\n"); endwin(); } void mtr_curses_clear() { mtr_curses_close(); mtr_curses_open(); }