Annotation of embedaddon/mtr/curses.c, revision 1.1.1.1
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 1997,1998 Matt Kimball
4:
5: This program is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License version 2 as
7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: #include <config.h>
20: #include <strings.h>
21: #include <unistd.h>
22:
23: #ifndef NO_CURSES
24: #include <ctype.h>
25: #include <stdlib.h>
26: #include <string.h>
27:
28: /* MacOSX may need this before scoket.h...*/
29: #if defined(HAVE_SYS_TYPES_H)
30: #include <sys/types.h>
31: #else
32: /* If a system doesn't have sys/types.h, lets hope that time_t is an int */
33: #define time_t int
34: #endif
35:
36: #include <sys/socket.h>
37: #include <netinet/in.h>
38: #include <arpa/inet.h>
39:
40: #if defined(HAVE_NCURSES_H)
41: # include <ncurses.h>
42: #elif defined(HAVE_NCURSES_CURSES_H)
43: # include <ncurses/curses.h>
44: #elif defined(HAVE_CURSES_H)
45: # include <curses.h>
46: #elif defined(HAVE_CURSESX_H)
47: # include <cursesX.h>
48: #else
49: # error No curses header file available
50: #endif
51:
52: #ifndef HAVE_ATTRON
53: #define attron(x)
54: #define attroff(x)
55: #endif
56:
57: #ifndef getmaxyx
58: # define getmaxyx(win,y,x) ((y) = (win)->_maxy + 1, (x) = (win)->_maxx + 1)
59: #endif
60:
61: #include "mtr.h"
62: #include "mtr-curses.h"
63: #include "display.h"
64: #include "net.h"
65: #include "dns.h"
66: #ifndef NO_IPINFO
67: #include "asn.h"
68: #endif
69: #include "version.h"
70: #endif
71:
72: #include <time.h>
73:
74: extern char LocalHostname[];
75: extern int fstTTL;
76: extern int maxTTL;
77: extern int cpacketsize;
78: extern int bitpattern;
79: extern int tos;
80: extern float WaitTime;
81: extern int af;
82: extern int mtrtype;
83:
84: static int __unused_int;
85:
86: void pwcenter(char *str)
87: {
88: int maxx;
89: int cx;
90:
91: getmaxyx(stdscr, __unused_int, maxx);
92: cx = (signed)(maxx - strlen(str)) / 2;
93: while(cx-- > 0)
94: printw(" ");
95: printw(str);
96: }
97:
98:
99: int mtr_curses_keyaction(void)
100: {
101: int c = getch();
102: int i=0;
103: float f = 0.0;
104: char buf[MAXFLD+1];
105:
106: if(c == 'q')
107: return ActionQuit;
108: if(c==3)
109: return ActionQuit;
110: if (c==12)
111: return ActionClear;
112: if ((c==19) || (tolower (c) == 'p'))
113: return ActionPause;
114: if ((c==17) || (c == ' '))
115: return ActionResume;
116: if(tolower(c) == 'r')
117: return ActionReset;
118: if (tolower(c) == 'd')
119: return ActionDisplay;
120: if (tolower(c) == 'e')
121: return ActionMPLS;
122: if (tolower(c) == 'n')
123: return ActionDNS;
124: #ifndef NO_IPINFO
125: if (tolower(c) == 'y')
126: return ActionII;
127: if (tolower(c) == 'z')
128: return ActionAS;
129: #endif
130: if (c == '+')
131: return ActionScrollDown;
132: if (c == '-')
133: return ActionScrollUp;
134:
135: if (tolower(c) == 's') {
136: mvprintw(2, 0, "Change Packet Size: %d\n", cpacketsize );
137: mvprintw(3, 0, "Size Range: %d-%d, < 0:random.\n", MINPACKET, MAXPACKET);
138: move(2,20);
139: refresh();
140: while ( (c=getch ()) != '\n' && i < MAXFLD ) {
141: attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh ();
142: buf[i++] = c; /* need more checking on 'c' */
143: }
144: buf[i] = '\0';
145: cpacketsize = atoi ( buf );
146: return ActionNone;
147: }
148: if (tolower(c) == 'b') {
149: mvprintw(2, 0, "Ping Bit Pattern: %d\n", bitpattern );
150: mvprintw(3, 0, "Pattern Range: 0(0x00)-255(0xff), <0 random.\n");
151: move(2,18);
152: refresh();
153: while ( (c=getch ()) != '\n' && i < MAXFLD ) {
154: attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh ();
155: buf[i++] = c; /* need more checking on 'c' */
156: }
157: buf[i] = '\0';
158: bitpattern = atoi ( buf );
159: if( bitpattern > 255 ) { bitpattern = -1; }
160: return ActionNone;
161: }
162: if ( c == 'Q') { /* can not be tolower(c) */
163: mvprintw(2, 0, "Type of Service(tos): %d\n", tos );
164: mvprintw(3, 0, "default 0x00, min cost 0x02, rel 0x04,, thr 0x08, low del 0x10...\n");
165: move(2,22);
166: refresh();
167: while ( (c=getch ()) != '\n' && i < MAXFLD ) {
168: attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
169: buf[i++] = c; /* need more checking on 'c' */
170: }
171: buf[i] = '\0';
172: tos = atoi ( buf );
173: if( tos > 255 || tos <0 ) {
174: tos = 0;
175: }
176: return ActionNone;
177: }
178: if (tolower(c) == 'i') {
179: mvprintw(2, 0, "Interval : %0.0f\n\n", WaitTime );
180: move(2,11);
181: refresh();
182: while ( (c=getch ()) != '\n' && i < MAXFLD ) {
183: attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
184: buf[i++] = c; /* need more checking on 'c' */
185: }
186: buf[i] = '\0';
187:
188: f = atof( buf );
189:
190: if (f <= 0.0) return ActionNone;
191: if (getuid() != 0 && f < 1.0)
192: return ActionNone;
193: WaitTime = f;
194:
195: return ActionNone;
196: }
197: if (tolower(c) == 'f') {
198: mvprintw(2, 0, "First TTL: %d\n\n", fstTTL );
199: move(2,11);
200: refresh();
201: while ( (c=getch ()) != '\n' && i < MAXFLD ) {
202: attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
203: buf[i++] = c; /* need more checking on 'c' */
204: }
205: buf[i] = '\0';
206: i = atoi( buf );
207:
208: if ( i < 1 || i> maxTTL ) return ActionNone;
209: fstTTL = i;
210:
211: return ActionNone;
212: }
213: if (tolower(c) == 'm') {
214: mvprintw(2, 0, "Max TTL: %d\n\n", maxTTL );
215: move(2,9);
216: refresh();
217: while ( (c=getch ()) != '\n' && i < MAXFLD ) {
218: attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
219: buf[i++] = c; /* need more checking on 'c' */
220: }
221: buf[i] = '\0';
222: i = atoi( buf );
223:
224: if ( i < fstTTL || i>(MaxHost-1) ) return ActionNone;
225: maxTTL = i;
226:
227: return ActionNone;
228: }
229: /* fields to display & their ordering */
230: if (tolower(c) == 'o') {
231: mvprintw(2, 0, "Fields: %s\n\n", fld_active );
232:
233: for( i=0; i<MAXFLD; i++ ){
234: if( data_fields[i].descr != NULL )
235: printw( " %s\n", data_fields[i].descr);
236: }
237: printw("\n");
238: move(2,8); /* length of "Fields: " */
239: refresh();
240:
241: i = 0;
242: while ( (c=getch ()) != '\n' && i < MAXFLD ) {
243: if( strchr(available_options, c) ) {
244: attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
245: buf[i++] = c; /* Only permit values in "available_options" be entered */
246: } else {
247: printf("\a"); /* Illegal character. Beep, ring the bell. */
248: }
249: }
250: buf[i] = '\0';
251: if ( strlen( buf ) > 0 ) strcpy( fld_active, buf );
252:
253: return ActionNone;
254: }
255: if (tolower(c) == 'j') {
256: if( index(fld_active, 'N') ) {
257: strcpy(fld_active, "DR AGJMXI"); /* GeoMean and jitter */
258: } else {
259: strcpy(fld_active, "LS NABWV"); /* default */
260: }
261: return ActionNone;
262: }
263: if (tolower(c) == 'u') {
264: switch ( mtrtype ) {
265: case IPPROTO_ICMP:
266: case IPPROTO_TCP:
267: mtrtype = IPPROTO_UDP;
268: break;
269: case IPPROTO_UDP:
270: mtrtype = IPPROTO_ICMP;
271: break;
272: }
273: return ActionNone;
274: }
275: if (tolower(c) == 't') {
276: switch ( mtrtype ) {
277: case IPPROTO_ICMP:
278: case IPPROTO_UDP:
279: mtrtype = IPPROTO_TCP;
280: break;
281: case IPPROTO_TCP:
282: mtrtype = IPPROTO_ICMP;
283: break;
284: }
285: return ActionNone;
286: }
287: /* reserve to display help message -Min */
288: if (tolower(c) == '?'|| tolower(c) == 'h') {
289: int pressanykey_row = 20;
290: mvprintw(2, 0, "Command:\n" );
291: printw(" ?|h help\n" );
292: printw(" p pause (SPACE to resume)\n" );
293: printw(" d switching display mode\n" );
294: printw(" e toggle MPLS information on/off\n" );
295: printw(" n toggle DNS on/off\n" );
296: printw(" r reset all counters\n" );
297: printw(" o str set the columns to display, default str='LRS N BAWV'\n" );
298: printw(" j toggle latency(LS NABWV)/jitter(DR AGJMXI) stats\n" );
299: printw(" c <n> report cycle n, default n=infinite\n" );
300: printw(" i <n> set the ping interval to n seconds, default n=1\n" );
301: printw(" f <n> set the initial time-to-live(ttl), default n=1\n" );
302: printw(" m <n> set the max time-to-live, default n= # of hops\n" );
303: printw(" s <n> set the packet size to n or random(n<0)\n" );
304: printw(" b <c> set ping bit pattern to c(0..255) or random(c<0)\n" );
305: printw(" Q <t> set ping packet's TOS to t\n" );
306: printw(" u switch between ICMP ECHO and UDP datagrams\n" );
307: #ifndef NO_IPINFO
308: printw(" y switching IP info\n");
309: printw(" z toggle ASN info on/off\n");
310: pressanykey_row += 2;
311: #endif
312: printw("\n");
313: mvprintw(pressanykey_row, 0, " press any key to go back..." );
314:
315: getch(); /* get any key */
316: return ActionNone;
317: }
318:
319: return ActionNone; /* ignore unknown input */
320: }
321:
322:
323: void mtr_curses_hosts(int startstat)
324: {
325: int max;
326: int at;
327: struct mplslen *mpls, *mplss;
328: ip_t *addr, *addrs;
329: int y;
330: char *name;
331:
332: int i, j, k;
333: int hd_len;
334: char buf[1024];
335:
336: max = net_max();
337:
338: for(at = net_min () + display_offset; at < max; at++) {
339: printw("%2d. ", at + 1);
340: addr = net_addr(at);
341: mpls = net_mpls(at);
342:
343: if( addrcmp( (void *) addr, (void *) &unspec_addr, af ) != 0 ) {
344: name = dns_lookup(addr);
345: if (! net_up(at))
346: attron(A_BOLD);
347: #ifndef NO_IPINFO
348: if (is_printii())
349: printw(fmt_ipinfo(addr));
350: #endif
351: if(name != NULL) {
352: if (show_ips) printw("%s (%s)", name, strlongip(addr));
353: else printw("%s", name);
354: } else {
355: printw("%s", strlongip( addr ) );
356: }
357: attroff(A_BOLD);
358:
359: getyx(stdscr, y, __unused_int);
360: move(y, startstat);
361:
362: /* net_xxx returns times in usecs. Just display millisecs */
363: hd_len = 0;
364: for( i=0; i<MAXFLD; i++ ) {
365: /* Ignore options that don't exist */
366: /* On the other hand, we now check the input side. Shouldn't happen,
367: can't be careful enough. */
368: j = fld_index[fld_active[i]];
369: if (j == -1) continue;
370:
371: /* temporay hack for stats usec to ms... */
372: if( index( data_fields[j].format, 'f' ) ) {
373: sprintf(buf + hd_len, data_fields[j].format,
374: data_fields[j].net_xxx(at) /1000.0 );
375: } else {
376: sprintf(buf + hd_len, data_fields[j].format,
377: data_fields[j].net_xxx(at) );
378: }
379: hd_len += data_fields[j].length;
380: }
381: buf[hd_len] = 0;
382: printw("%s", buf);
383:
384: for (k=0; k < mpls->labels && enablempls; k++) {
385: if((k+1 < mpls->labels) || (mpls->labels == 1)) {
386: /* if we have more labels */
387: printw("\n [MPLS: Lbl %lu Exp %u S %u TTL %u]", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]);
388: } else {
389: /* bottom label */
390: printw("\n [MPLS: Lbl %lu Exp %u S %u TTL %u]", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]);
391: }
392: }
393:
394: /* Multi path */
395: for (i=0; i < MAXPATH; i++ ) {
396: addrs = net_addrs(at, i);
397: mplss = net_mplss(at, i);
398: if ( addrcmp( (void *) addrs, (void *) addr, af ) == 0 ) continue;
399: if ( addrcmp( (void *) addrs, (void *) &unspec_addr, af ) == 0 ) break;
400:
401: name = dns_lookup(addrs);
402: if (! net_up(at)) attron(A_BOLD);
403: printw("\n ");
404: #ifndef NO_IPINFO
405: if (is_printii())
406: printw(fmt_ipinfo(addrs));
407: #endif
408: if (name != NULL) {
409: if (show_ips) printw("%s (%s)", name, strlongip(addrs));
410: else printw("%s", name);
411: } else {
412: printw("%s", strlongip( addrs ) );
413: }
414: for (k=0; k < mplss->labels && enablempls; k++) {
415: printw("\n [MPLS: Lbl %lu Exp %u S %u TTL %u]", mplss->label[k], mplss->exp[k], mplss->s[k], mplss->ttl[k]);
416: }
417: attroff(A_BOLD);
418: }
419:
420: } else {
421: printw("???");
422: }
423:
424: printw("\n");
425: }
426: move(2, 0);
427: }
428:
429: #define NUM_FACTORS 8
430: static double factors[NUM_FACTORS];
431: static int scale[NUM_FACTORS];
432: static int low_ms, high_ms;
433:
434: void mtr_gen_scale(void)
435: {
436: int *saved, i, max, at;
437: int range;
438:
439: low_ms = 1000000;
440: high_ms = -1;
441:
442: for (i = 0; i < NUM_FACTORS; i++) {
443: scale[i] = 0;
444: }
445: max = net_max();
446: for (at = display_offset; at < max; at++) {
447: saved = net_saved_pings(at);
448: for (i = 0; i < SAVED_PINGS; i++) {
449: if (saved[i] < 0) continue;
450: if (saved[i] < low_ms) {
451: low_ms = saved[i];
452: }
453: if (saved[i] > high_ms) {
454: high_ms = saved[i];
455: }
456: }
457: }
458: range = high_ms - low_ms;
459: for (i = 0; i < NUM_FACTORS; i++) {
460: scale[i] = low_ms + ((double)range * factors[i]);
461: }
462: }
463:
464:
465: static char block_map[NUM_FACTORS];
466:
467: void mtr_curses_init() {
468: int i;
469: int block_split;
470:
471: /* Initialize factors to a log scale. */
472: for (i = 0; i < NUM_FACTORS; i++) {
473: factors[i] = ((double)1 / NUM_FACTORS) * (i + 1);
474: factors[i] *= factors[i]; /* Squared. */
475: }
476:
477: /* Initialize block_map. */
478: block_split = (NUM_FACTORS - 2) / 2;
479: if (block_split > 9) {
480: block_split = 9;
481: }
482: for (i = 1; i <= block_split; i++) {
483: block_map[i] = '0' + i;
484: }
485: for (i = block_split+1; i < NUM_FACTORS-1; i++) {
486: block_map[i] = 'a' + i - block_split - 1;
487: }
488: block_map[0] = '.';
489: block_map[NUM_FACTORS-1] = '>';
490: }
491:
492:
493: void mtr_print_scaled(int ms)
494: {
495: int i;
496:
497: for (i = 0; i < NUM_FACTORS; i++) {
498: if (ms <= scale[i]) {
499: printw("%c", block_map[i]);
500: return;
501: }
502: }
503: printw(">");
504: }
505:
506:
507: void mtr_fill_graph(int at, int cols)
508: {
509: int* saved;
510: int i;
511:
512: saved = net_saved_pings(at);
513: for (i = SAVED_PINGS-cols; i < SAVED_PINGS; i++) {
514: if (saved[i] == -2) {
515: printw(" ");
516: } else if (saved[i] == -1) {
517: attron(A_BOLD);
518: printw("?");
519: attroff(A_BOLD);
520: } else {
521: if (display_mode == 1) {
522: if (saved[i] > scale[6]) {
523: printw("%c", block_map[NUM_FACTORS-1]);
524: } else {
525: printw(".");
526: }
527: } else {
528: mtr_print_scaled(saved[i]);
529: }
530: }
531: }
532: }
533:
534:
535: void mtr_curses_graph(int startstat, int cols)
536: {
537: int max, at, y;
538: ip_t * addr;
539: char* name;
540:
541: max = net_max();
542:
543: for (at = display_offset; at < max; at++) {
544: printw("%2d. ", at+1);
545:
546: addr = net_addr(at);
547: if (!addr) {
548: printw("???\n");
549: continue;
550: }
551:
552: if (! net_up(at))
553: attron(A_BOLD);
554: if (addrcmp((void *) addr, (void *) &unspec_addr, af)) {
555: #ifndef NO_IPINFO
556: if (is_printii())
557: printw(fmt_ipinfo(addr));
558: #endif
559: name = dns_lookup(addr);
560: printw("%s", name?name:strlongip(addr));
561: } else
562: printw("???");
563: attroff(A_BOLD);
564:
565: getyx(stdscr, y, __unused_int);
566: move(y, startstat);
567:
568: printw(" ");
569: mtr_fill_graph(at, cols);
570: printw("\n");
571: }
572: }
573:
574:
575: void mtr_curses_redraw(void)
576: {
577: int maxx;
578: int startstat;
579: int rowstat;
580: time_t t;
581:
582: int i, j;
583: int hd_len = 0;
584: char buf[1024];
585: char fmt[16];
586:
587:
588: erase();
589: getmaxyx(stdscr, __unused_int, maxx);
590:
591: rowstat = 5;
592:
593: move(0, 0);
594: attron(A_BOLD);
595: pwcenter("My traceroute [v" MTR_VERSION "]");
596: attroff(A_BOLD);
597:
598: mvprintw(1, 0, "%s (%s)", LocalHostname, net_localaddr());
599: /*
600: printw("(tos=0x%X ", tos);
601: printw("psize=%d ", packetsize );
602: printw("bitpattern=0x%02X)", (unsigned char)(abs(bitpattern)));
603: if( cpacketsize > 0 ){
604: printw("psize=%d ", cpacketsize);
605: } else {
606: printw("psize=rand(%d,%d) ",MINPACKET, -cpacketsize);
607: }
608: if( bitpattern>=0 ){
609: printw("bitpattern=0x%02X)", (unsigned char)(bitpattern));
610: } else {
611: printw("bitpattern=rand(0x00-FF))");
612: }
613: */
614: time(&t);
615: mvprintw(1, maxx-25, ctime(&t));
616:
617: printw("Keys: ");
618: attron(A_BOLD); printw("H"); attroff(A_BOLD); printw("elp ");
619: attron(A_BOLD); printw("D"); attroff(A_BOLD); printw("isplay mode ");
620: attron(A_BOLD); printw("R"); attroff(A_BOLD); printw("estart statistics ");
621: attron(A_BOLD); printw("O"); attroff(A_BOLD); printw("rder of fields ");
622: attron(A_BOLD); printw("q"); attroff(A_BOLD); printw("uit\n");
623:
624: if (display_mode == 0) {
625: for (i=0; i < MAXFLD; i++ ) {
626: j = fld_index[fld_active[i]];
627: if (j < 0) continue;
628:
629: sprintf( fmt, "%%%ds", data_fields[j].length );
630: sprintf( buf + hd_len, fmt, data_fields[j].title );
631: hd_len += data_fields[j].length;
632: }
633: attron(A_BOLD);
634: mvprintw(rowstat - 1, 0, " Host");
635: mvprintw(rowstat - 1, maxx-hd_len-1, "%s", buf);
636: mvprintw(rowstat - 2, maxx-hd_len-1, " Packets Pings");
637: attroff(A_BOLD);
638:
639: move(rowstat, 0);
640: mtr_curses_hosts(maxx-hd_len-1);
641:
642: } else {
643: char msg[80];
644: int padding = 30;
645: #ifndef NO_IPINFO
646: if (is_printii())
647: padding += get_iiwidth();
648: #endif
649: int max_cols = maxx<=SAVED_PINGS+padding ? maxx-padding : SAVED_PINGS;
650: startstat = padding - 2;
651:
652: sprintf(msg, " Last %3d pings", max_cols);
653: mvprintw(rowstat - 1, startstat, msg);
654:
655: attroff(A_BOLD);
656: move(rowstat, 0);
657:
658: mtr_gen_scale();
659: mtr_curses_graph(startstat, max_cols);
660:
661: printw("\n");
662: attron(A_BOLD);
663: printw("Scale:");
664: attroff(A_BOLD);
665:
666: for (i = 0; i < NUM_FACTORS-1; i++) {
667: printw(" %c:%d ms", block_map[i], scale[i]/1000);
668: }
669: }
670:
671: refresh();
672: }
673:
674:
675: void mtr_curses_open(void)
676: {
677: initscr();
678: raw();
679: noecho();
680:
681: mtr_curses_init();
682: mtr_curses_redraw();
683: }
684:
685:
686: void mtr_curses_close(void)
687: {
688: printw("\n");
689: endwin();
690: }
691:
692:
693: void mtr_curses_clear(void)
694: {
695: mtr_curses_close();
696: mtr_curses_open();
697: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>