Annotation of embedaddon/mtr/ui/curses.c, revision 1.1.1.3

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
1.1.1.3 ! misho       6:     it under the terms of the GNU General Public License version 2 as
1.1       misho       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: 
1.1.1.2   misho      14:     You should have received a copy of the GNU General Public License along
                     15:     with this program; if not, write to the Free Software Foundation, Inc.,
                     16:     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1       misho      17: */
                     18: 
                     19: #include "config.h"
                     20: 
                     21: #include "mtr.h"
                     22: 
                     23: #include <strings.h>
                     24: #include <unistd.h>
                     25: 
                     26: #include <ctype.h>
                     27: #include <stdlib.h>
                     28: #include <string.h>
                     29: #include <time.h>
                     30: 
                     31: /* MacOSX may need this before socket.h...*/
                     32: #if defined(HAVE_SYS_TYPES_H)
                     33: #include <sys/types.h>
                     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: /* This go-around is needed only when compiling with antique version of curses.
                     53:    getmaxyx is part of Technical Standard X/Open Curses Issue 4, Version 2 (1996).
                     54:    http://pubs.opengroup.org/onlinepubs/9693989999/toc.pdf see page 106 */
                     55: #ifndef getmaxyx
                     56: #define getmaxyx(win,y,x)      ((y) = (win)->_maxy + 1, (x) = (win)->_maxx + 1)
                     57: #endif
                     58: 
                     59: #include "mtr.h"
                     60: #include "mtr-curses.h"
                     61: #include "net.h"
                     62: #include "dns.h"
                     63: #include "asn.h"
                     64: #include "display.h"
                     65: #include "utils.h"
                     66: 
                     67: 
                     68: enum { NUM_FACTORS = 8 };
                     69: static double factors[NUM_FACTORS];
                     70: static int scale[NUM_FACTORS];
                     71: static char block_map[NUM_FACTORS];
                     72: 
                     73: enum { black = 1, red, green, yellow, blue, magenta, cyan, white };
                     74: static const int block_col[NUM_FACTORS + 1] = {
                     75:     COLOR_PAIR(red) | A_BOLD,
                     76:     A_NORMAL,
                     77:     COLOR_PAIR(green),
                     78:     COLOR_PAIR(green) | A_BOLD,
                     79:     COLOR_PAIR(yellow) | A_BOLD,
                     80:     COLOR_PAIR(magenta) | A_BOLD,
                     81:     COLOR_PAIR(magenta),
                     82:     COLOR_PAIR(red),
                     83:     COLOR_PAIR(red) | A_BOLD
                     84: };
                     85: 
                     86: static void pwcenter(
                     87:     char *str)
                     88: {
                     89:     int maxx;
                     90:     size_t cx;
                     91:     int __unused_int ATTRIBUTE_UNUSED;
                     92: 
                     93:     getmaxyx(stdscr, __unused_int, maxx);
                     94:     cx = (size_t) (maxx - strlen(str)) / 2;
                     95:     printw("%*s%s", (int) cx, "", str);
                     96: }
                     97: 
                     98: 
                     99: static char *format_number(
                    100:     int n,
                    101:     int w,
                    102:     char *buf)
                    103: {
                    104:     if (w != 5)
                    105:         /* XXX todo: implement w != 5.. */
                    106:         snprintf(buf, w + 1, "%s", "unimpl");
                    107:     else if (n < 100000)
                    108:         /* buf is good as-is */ ;
                    109:     else if (n < 1000000)
                    110:         snprintf(buf, w + 1, "%3dk%1d", n / 1000, (n % 1000) / 100);
                    111:     else if (n < 10000000)
                    112:         snprintf(buf, w + 1, "%1dM%03d", n / 1000000,
                    113:                  (n % 1000000) / 1000);
                    114:     else if (n < 100000000)
                    115:         snprintf(buf, w + 1, "%2dM%02d", n / 1000000,
                    116:                  (n % 1000000) / 10000);
                    117:     else if (n < 1000000000)
                    118:         snprintf(buf, w + 1, "%3dM%01d", n / 1000000,
                    119:                  (n % 1000000) / 100000);
                    120:     else                        /* if (n < 10000000000) */
                    121:         snprintf(buf, w + 1, "%1dG%03d", n / 1000000000,
                    122:                  (n % 1000000000) / 1000000);
                    123: 
                    124:     return buf;
                    125: }
                    126: 
                    127: 
                    128: int mtr_curses_keyaction(
                    129:     struct mtr_ctl *ctl)
                    130: {
                    131:     int c = getch();
                    132:     int i = 0;
                    133:     float f = 0.0;
                    134:     char buf[MAXFLD + 1];
                    135: 
                    136:     if (c == 'Q') {             /* must be checked before c = tolower(c) */
                    137:         mvprintw(2, 0, "Type of Service(tos): %d\n", ctl->tos);
                    138:         mvprintw(3, 0,
                    139:                  "default 0x00, min cost 0x02, rel 0x04,, thr 0x08, low del 0x10...\n");
                    140:         move(2, 22);
                    141:         refresh();
                    142:         while ((c = getch()) != '\n' && i < MAXFLD) {
                    143:             attron(A_BOLD);
                    144:             printw("%c", c);
                    145:             attroff(A_BOLD);
                    146:             refresh();
                    147:             buf[i++] = c;       /* need more checking on 'c' */
                    148:         }
                    149:         buf[i] = '\0';
                    150:         ctl->tos = atoi(buf);
                    151:         if (ctl->tos > 255 || ctl->tos < 0)
                    152:             ctl->tos = 0;
                    153:         return ActionNone;
                    154:     }
                    155: 
                    156:     c = tolower(c);
                    157: 
                    158:     switch (c) {
                    159:     case 'q':
1.1.1.2   misho     160:     case -1:
1.1       misho     161:     case 3:
                    162:         return ActionQuit;
                    163:     case 12:
                    164:         return ActionClear;
                    165:     case 19:
                    166:     case 'p':
                    167:         return ActionPause;
                    168:     case 17:
                    169:     case ' ':
                    170:         return ActionResume;
                    171:     case 'r':
                    172:         return ActionReset;
                    173:     case 'd':
                    174:         return ActionDisplay;
                    175:     case 'e':
                    176:         return ActionMPLS;
                    177:     case 'n':
                    178:         return ActionDNS;
                    179: #ifdef HAVE_IPINFO
                    180:     case 'y':
                    181:         return ActionII;
                    182:     case 'z':
                    183:         return ActionAS;
                    184: #endif
                    185:     case '+':
                    186:         return ActionScrollDown;
                    187:     case '-':
                    188:         return ActionScrollUp;
                    189:     case 's':
                    190:         mvprintw(2, 0, "Change Packet Size: %d\n", ctl->cpacketsize);
                    191:         mvprintw(3, 0, "Size Range: %d-%d, < 0:random.\n", MINPACKET,
                    192:                  MAXPACKET);
                    193:         move(2, 20);
                    194:         refresh();
                    195:         while ((c = getch()) != '\n' && i < MAXFLD) {
                    196:             attron(A_BOLD);
                    197:             printw("%c", c);
                    198:             attroff(A_BOLD);
                    199:             refresh();
                    200:             buf[i++] = c;       /* need more checking on 'c' */
                    201:         }
                    202:         buf[i] = '\0';
                    203:         ctl->cpacketsize = atoi(buf);
                    204:         return ActionNone;
                    205:     case 'b':
                    206:         mvprintw(2, 0, "Ping Bit Pattern: %d\n", ctl->bitpattern);
                    207:         mvprintw(3, 0, "Pattern Range: 0(0x00)-255(0xff), <0 random.\n");
                    208:         move(2, 18);
                    209:         refresh();
                    210:         while ((c = getch()) != '\n' && i < MAXFLD) {
                    211:             attron(A_BOLD);
                    212:             printw("%c", c);
                    213:             attroff(A_BOLD);
                    214:             refresh();
                    215:             buf[i++] = c;       /* need more checking on 'c' */
                    216:         }
                    217:         buf[i] = '\0';
                    218:         ctl->bitpattern = atoi(buf);
                    219:         if (ctl->bitpattern > 255)
                    220:             ctl->bitpattern = -1;
                    221:         return ActionNone;
                    222:     case 'i':
                    223:         mvprintw(2, 0, "Interval : %0.0f\n\n", ctl->WaitTime);
                    224:         move(2, 11);
                    225:         refresh();
                    226:         while ((c = getch()) != '\n' && i < MAXFLD) {
                    227:             attron(A_BOLD);
                    228:             printw("%c", c);
                    229:             attroff(A_BOLD);
                    230:             refresh();
                    231:             buf[i++] = c;       /* need more checking on 'c' */
                    232:         }
                    233:         buf[i] = '\0';
                    234: 
                    235:         f = atof(buf);
                    236: 
                    237:         if (f <= 0.0)
                    238:             return ActionNone;
1.1.1.2   misho     239:         if (!running_as_root() && (f < 1.0))
1.1       misho     240:             return ActionNone;
                    241:         ctl->WaitTime = f;
                    242: 
                    243:         return ActionNone;
                    244:     case 'f':
                    245:         mvprintw(2, 0, "First TTL: %d\n\n", ctl->fstTTL);
                    246:         move(2, 11);
                    247:         refresh();
                    248:         while ((c = getch()) != '\n' && i < MAXFLD) {
                    249:             attron(A_BOLD);
                    250:             printw("%c", c);
                    251:             attroff(A_BOLD);
                    252:             refresh();
                    253:             buf[i++] = c;       /* need more checking on 'c' */
                    254:         }
                    255:         buf[i] = '\0';
                    256:         i = atoi(buf);
                    257: 
                    258:         if (i < 1 || i > ctl->maxTTL)
                    259:             return ActionNone;
                    260:         ctl->fstTTL = i;
                    261: 
                    262:         return ActionNone;
                    263:     case 'm':
                    264:         mvprintw(2, 0, "Max TTL: %d\n\n", ctl->maxTTL);
                    265:         move(2, 9);
                    266:         refresh();
                    267:         while ((c = getch()) != '\n' && i < MAXFLD) {
                    268:             attron(A_BOLD);
                    269:             printw("%c", c);
                    270:             attroff(A_BOLD);
                    271:             refresh();
                    272:             buf[i++] = c;       /* need more checking on 'c' */
                    273:         }
                    274:         buf[i] = '\0';
                    275:         i = atoi(buf);
                    276: 
                    277:         if (i < ctl->fstTTL || i > (MaxHost - 1))
                    278:             return ActionNone;
                    279:         ctl->maxTTL = i;
                    280: 
                    281:         return ActionNone;
                    282:         /* fields to display & their ordering */
                    283:     case 'o':
                    284:         mvprintw(2, 0, "Fields: %s\n\n", ctl->fld_active);
                    285: 
                    286:         for (i = 0; i < MAXFLD; i++) {
                    287:             if (data_fields[i].descr != NULL)
                    288:                 printw("  %s\n", data_fields[i].descr);
                    289:         }
                    290:         printw("\n");
                    291:         move(2, 8);             /* length of "Fields: " */
                    292:         refresh();
                    293: 
                    294:         i = 0;
                    295:         while ((c = getch()) != '\n' && i < MAXFLD) {
                    296:             if (strchr(ctl->available_options, c)) {
                    297:                 attron(A_BOLD);
                    298:                 printw("%c", c);
                    299:                 attroff(A_BOLD);
                    300:                 refresh();
                    301:                 buf[i++] = c;   /* Only permit values in "available_options" be entered */
                    302:             } else {
                    303:                 printf("\a");   /* Illegal character. Beep, ring the bell. */
                    304:             }
                    305:         }
                    306:         buf[i] = '\0';
                    307:         if (strlen(buf) > 0)
                    308:             xstrncpy(ctl->fld_active, buf, 2 * MAXFLD);
                    309: 
                    310:         return ActionNone;
                    311:     case 'j':
                    312:         if (strchr(ctl->fld_active, 'N'))
                    313:             /* GeoMean and jitter */
                    314:             xstrncpy(ctl->fld_active, "DR AGJMXI", 2 * MAXFLD);
                    315:         else
                    316:             /* default */
                    317:             xstrncpy(ctl->fld_active, "LS NABWV", 2 * MAXFLD);
                    318:         return ActionNone;
                    319:     case 'u':
                    320:         switch (ctl->mtrtype) {
                    321:         case IPPROTO_ICMP:
                    322:         case IPPROTO_TCP:
                    323:             ctl->mtrtype = IPPROTO_UDP;
                    324:             break;
                    325:         case IPPROTO_UDP:
                    326:             ctl->mtrtype = IPPROTO_ICMP;
                    327:             break;
                    328:         }
                    329:         return ActionNone;
                    330:     case 't':
                    331:         switch (ctl->mtrtype) {
                    332:         case IPPROTO_ICMP:
                    333:         case IPPROTO_UDP:
                    334:             ctl->mtrtype = IPPROTO_TCP;
                    335:             break;
                    336:         case IPPROTO_TCP:
                    337:             ctl->mtrtype = IPPROTO_ICMP;
                    338:             break;
                    339:         }
                    340:         return ActionNone;
                    341:         /* reserve to display help message -Min */
                    342:     case '?':
                    343:     case 'h':
                    344:         mvprintw(2, 0, "Command:\n");
                    345:         printw("  ?|h     help\n");
                    346:         printw("  p       pause (SPACE to resume)\n");
                    347:         printw("  d       switching display mode\n");
                    348:         printw("  e       toggle MPLS information on/off\n");
                    349:         printw("  n       toggle DNS on/off\n");
                    350:         printw("  r       reset all counters\n");
                    351:         printw
                    352:             ("  o str   set the columns to display, default str='LRS N BAWV'\n");
                    353:         printw
                    354:             ("  j       toggle latency(LS NABWV)/jitter(DR AGJMXI) stats\n");
                    355:         printw("  c <n>   report cycle n, default n=infinite\n");
                    356:         printw
                    357:             ("  i <n>   set the ping interval to n seconds, default n=1\n");
                    358:         printw
                    359:             ("  f <n>   set the initial time-to-live(ttl), default n=1\n");
                    360:         printw
                    361:             ("  m <n>   set the max time-to-live, default n= # of hops\n");
                    362:         printw("  s <n>   set the packet size to n or random(n<0)\n");
                    363:         printw
                    364:             ("  b <c>   set ping bit pattern to c(0..255) or random(c<0)\n");
                    365:         printw("  Q <t>   set ping packet's TOS to t\n");
                    366:         printw("  u       switch between ICMP ECHO and UDP datagrams\n");
1.1.1.2   misho     367:         printw("  t       switch between ICMP ECHO and TCP\n");
1.1       misho     368: #ifdef HAVE_IPINFO
                    369:         printw("  y       switching IP info\n");
                    370:         printw("  z       toggle ASN info on/off\n");
                    371: #endif
                    372:         printw("\n");
                    373:         printw(" press any key to go back...");
                    374:         getch();                /* read and ignore 'any key' */
                    375:         return ActionNone;
                    376:     default:                   /* ignore unknown input */
                    377:         return ActionNone;
                    378:     }
                    379: }
                    380: 
                    381: 
                    382: static void format_field(
                    383:     char *dst,
                    384:     int dst_length,
                    385:     const char *format,
                    386:     int n)
                    387: {
                    388:     if (index(format, 'N')) {
                    389:         *dst++ = ' ';
                    390:         format_number(n, 5, dst);
                    391:     } else if (strchr(format, 'f')) {
                    392:         /* this is for fields where we measure integer microseconds but
1.1.1.3 ! misho     393:            display floating point milliseconds. Convert to float here. */
1.1       misho     394:         snprintf(dst, dst_length, format, n / 1000.0);
                    395:         /* this was marked as a temporary hack over 10 years ago. -- REW */
                    396:     } else {
                    397:         snprintf(dst, dst_length, format, n);
                    398:     }
                    399: }
                    400: 
                    401: static void mtr_curses_hosts(
                    402:     struct mtr_ctl *ctl,
                    403:     int startstat)
                    404: {
                    405:     int max;
                    406:     int at;
                    407:     struct mplslen *mpls, *mplss;
                    408:     ip_t *addr, *addrs;
1.1.1.2   misho     409:     int addrcmp_result;
                    410:     int err;
1.1       misho     411:     int y;
                    412:     char *name;
                    413: 
                    414:     int i, j, k;
                    415:     int hd_len;
                    416:     char buf[1024];
                    417:     int __unused_int ATTRIBUTE_UNUSED;
                    418: 
                    419:     max = net_max(ctl);
                    420: 
                    421:     for (at = net_min(ctl) + ctl->display_offset; at < max; at++) {
                    422:         printw("%2d. ", at + 1);
1.1.1.2   misho     423:         err = net_err(at);
1.1       misho     424:         addr = net_addr(at);
                    425:         mpls = net_mpls(at);
                    426: 
1.1.1.2   misho     427:         addrcmp_result = addrcmp(addr, &ctl->unspec_addr, ctl->af);
                    428: 
                    429:         if (err == 0 && addrcmp_result != 0) {
1.1       misho     430:             name = dns_lookup(ctl, addr);
                    431:             if (!net_up(at))
                    432:                 attron(A_BOLD);
                    433: #ifdef HAVE_IPINFO
                    434:             if (is_printii(ctl))
1.1.1.3 ! misho     435:                 printw("%s", fmt_ipinfo(ctl, addr));
1.1       misho     436: #endif
                    437:             if (name != NULL) {
                    438:                 if (ctl->show_ips)
1.1.1.3 ! misho     439:                     printw("%s (%s)", name, strlongip(ctl->af, addr));
1.1       misho     440:                 else
                    441:                     printw("%s", name);
                    442:             } else {
1.1.1.3 ! misho     443:                 printw("%s", strlongip(ctl->af, addr));
1.1       misho     444:             }
                    445:             attroff(A_BOLD);
                    446: 
                    447:             getyx(stdscr, y, __unused_int);
                    448:             move(y, startstat);
                    449: 
                    450:             /* net_xxx returns times in usecs. Just display millisecs */
                    451:             hd_len = 0;
                    452:             for (i = 0; i < MAXFLD; i++) {
                    453:                 /* Ignore options that don't exist */
1.1.1.3 ! misho     454:                 /* On the other hand, we now check the input side. Shouldn't happen,
1.1       misho     455:                    can't be careful enough. */
                    456:                 j = ctl->fld_index[ctl->fld_active[i]];
                    457:                 if (j == -1)
                    458:                     continue;
                    459:                 format_field(buf + hd_len, sizeof(buf) - hd_len,
                    460:                              data_fields[j].format,
                    461:                              data_fields[j].net_xxx(at));
                    462:                 hd_len += data_fields[j].length;
                    463:             }
                    464:             buf[hd_len] = 0;
                    465:             printw("%s", buf);
                    466: 
                    467:             for (k = 0; k < mpls->labels && ctl->enablempls; k++) {
1.1.1.2   misho     468:                 printw("\n    [MPLS: Lbl %lu TC %u S %u TTL %u]",
                    469:                        mpls->label[k], mpls->tc[k], mpls->s[k],
1.1       misho     470:                        mpls->ttl[k]);
                    471:             }
                    472: 
                    473:             /* Multi path */
1.1.1.2   misho     474:             for (i = 0; i < MAX_PATH; i++) {
1.1       misho     475:                 addrs = net_addrs(at, i);
                    476:                 mplss = net_mplss(at, i);
1.1.1.2   misho     477:                 if (addrcmp(addrs, addr, ctl->af) == 0)
1.1       misho     478:                     continue;
1.1.1.2   misho     479:                 if (addrcmp(addrs, &ctl->unspec_addr,ctl->af) == 0)
1.1       misho     480:                     break;
                    481: 
                    482:                 name = dns_lookup(ctl, addrs);
                    483:                 if (!net_up(at))
                    484:                     attron(A_BOLD);
                    485:                 printw("\n    ");
                    486: #ifdef HAVE_IPINFO
                    487:                 if (is_printii(ctl))
1.1.1.3 ! misho     488:                     printw("%s", fmt_ipinfo(ctl, addrs));
1.1       misho     489: #endif
                    490:                 if (name != NULL) {
                    491:                     if (ctl->show_ips)
1.1.1.3 ! misho     492:                         printw("%s (%s)", name, strlongip(ctl->af, addrs));
1.1       misho     493:                     else
                    494:                         printw("%s", name);
                    495:                 } else {
1.1.1.3 ! misho     496:                     printw("%s", strlongip(ctl->af, addrs));
1.1       misho     497:                 }
                    498:                 for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
1.1.1.2   misho     499:                     printw("\n    [MPLS: Lbl %lu TC %u S %u TTL %u]",
                    500:                            mplss->label[k], mplss->tc[k], mplss->s[k],
1.1       misho     501:                            mplss->ttl[k]);
                    502:                 }
                    503:                 attroff(A_BOLD);
                    504:             }
                    505:         } else {
1.1.1.2   misho     506:             attron(A_BOLD);
                    507:             printw("(%s)", host_error_to_string(err));
                    508:             attroff(A_BOLD);
1.1       misho     509:         }
                    510: 
                    511:         printw("\n");
                    512:     }
                    513:     move(2, 0);
                    514: }
                    515: 
                    516: static void mtr_gen_scale(
                    517:     struct mtr_ctl *ctl)
                    518: {
                    519:     int *saved, i, max, at;
                    520:     int range;
                    521:     static int low_ms, high_ms;
                    522: 
                    523:     low_ms = 1000000;
                    524:     high_ms = -1;
                    525: 
                    526:     for (i = 0; i < NUM_FACTORS; i++) {
                    527:         scale[i] = 0;
                    528:     }
                    529:     max = net_max(ctl);
                    530:     for (at = ctl->display_offset; at < max; at++) {
                    531:         saved = net_saved_pings(at);
                    532:         for (i = 0; i < SAVED_PINGS; i++) {
                    533:             if (saved[i] < 0)
                    534:                 continue;
                    535:             if (saved[i] < low_ms) {
                    536:                 low_ms = saved[i];
                    537:             }
                    538:             if (saved[i] > high_ms) {
                    539:                 high_ms = saved[i];
                    540:             }
                    541:         }
                    542:     }
                    543:     range = high_ms - low_ms;
                    544:     for (i = 0; i < NUM_FACTORS; i++) {
                    545:         scale[i] = low_ms + ((double) range * factors[i]);
                    546:     }
                    547: }
                    548: 
                    549: static void mtr_curses_init(
                    550:     void)
                    551: {
                    552:     int i;
                    553:     int block_split;
                    554: 
                    555:     /* Initialize factors to a log scale. */
                    556:     for (i = 0; i < NUM_FACTORS; i++) {
                    557:         factors[i] = ((double) 1 / NUM_FACTORS) * (i + 1);
                    558:         factors[i] *= factors[i];       /* Squared. */
                    559:     }
                    560: 
                    561:     /* Initialize block_map.  The block_split is always smaller than 9 */
                    562:     block_split = (NUM_FACTORS - 2) / 2;
                    563:     for (i = 1; i <= block_split; i++) {
                    564:         block_map[i] = '0' + i;
                    565:     }
                    566:     for (i = block_split + 1; i < NUM_FACTORS - 1; i++) {
                    567:         block_map[i] = 'a' + i - block_split - 1;
                    568:     }
                    569:     block_map[0] = '.';
                    570:     block_map[NUM_FACTORS - 1] = '>';
                    571: }
                    572: 
                    573: static void mtr_print_scaled(
                    574:     int ms)
                    575: {
                    576:     int i;
                    577: 
                    578:     for (i = 0; i < NUM_FACTORS; i++) {
                    579:         if (ms <= scale[i]) {
                    580:             attrset(block_col[i + 1]);
                    581:             printw("%c", block_map[i]);
                    582:             attrset(A_NORMAL);
                    583:             return;
                    584:         }
                    585:     }
                    586:     printw(">");
                    587: }
                    588: 
                    589: 
                    590: static void mtr_fill_graph(
                    591:     struct mtr_ctl *ctl,
                    592:     int at,
                    593:     int cols)
                    594: {
                    595:     int *saved;
                    596:     int i;
                    597: 
                    598:     saved = net_saved_pings(at);
                    599:     for (i = SAVED_PINGS - cols; i < SAVED_PINGS; i++) {
                    600:         if (saved[i] == -2) {
                    601:             printw(" ");
                    602:         } else if (saved[i] == -1) {
                    603:             attrset(block_col[0]);
                    604:             printw("%c", '?');
                    605:             attrset(A_NORMAL);
                    606:         } else {
                    607:             if (ctl->display_mode == DisplayModeBlockmap) {
                    608:                 if (saved[i] > scale[6]) {
                    609:                     printw("%c", block_map[NUM_FACTORS - 1]);
                    610:                 } else {
                    611:                     printw(".");
                    612:                 }
                    613:             } else {
                    614:                 mtr_print_scaled(saved[i]);
                    615:             }
                    616:         }
                    617:     }
                    618: }
                    619: 
                    620: 
                    621: static void mtr_curses_graph(
                    622:     struct mtr_ctl *ctl,
                    623:     int startstat,
                    624:     int cols)
                    625: {
1.1.1.2   misho     626:     int max, at, y, err;
1.1       misho     627:     ip_t *addr;
                    628:     char *name;
                    629:     int __unused_int ATTRIBUTE_UNUSED;
                    630: 
                    631:     max = net_max(ctl);
                    632: 
                    633:     for (at = ctl->display_offset; at < max; at++) {
                    634:         printw("%2d. ", at + 1);
                    635: 
                    636:         addr = net_addr(at);
1.1.1.2   misho     637:         err = net_err(at);
                    638: 
1.1       misho     639:         if (!addr) {
1.1.1.2   misho     640:             printw("(%s)", host_error_to_string(err));
1.1       misho     641:             continue;
                    642:         }
                    643: 
1.1.1.2   misho     644:         if (err == 0
                    645:             && addrcmp(addr, &ctl->unspec_addr, ctl->af)) {
                    646: 
                    647:             if (!net_up(at)) {
                    648:                 attron(A_BOLD);
                    649:             }
                    650: 
1.1       misho     651: #ifdef HAVE_IPINFO
                    652:             if (is_printii(ctl))
1.1.1.3 ! misho     653:                 printw("%s", fmt_ipinfo(ctl, addr));
1.1       misho     654: #endif
                    655:             name = dns_lookup(ctl, addr);
1.1.1.3 ! misho     656:             printw("%s", name ? name : strlongip(ctl->af, addr));
1.1.1.2   misho     657:         } else {
                    658:             attron(A_BOLD);
                    659:             printw("(%s)", host_error_to_string(err));
                    660:         }
                    661: 
1.1       misho     662:         attroff(A_BOLD);
                    663: 
                    664:         getyx(stdscr, y, __unused_int);
                    665:         move(y, startstat);
                    666: 
                    667:         printw(" ");
                    668:         mtr_fill_graph(ctl, at, cols);
                    669:         printw("\n");
                    670:     }
                    671: }
                    672: 
                    673: 
                    674: void mtr_curses_redraw(
                    675:     struct mtr_ctl *ctl)
                    676: {
                    677:     int maxx;
                    678:     int startstat;
                    679:     int rowstat;
                    680:     time_t t;
                    681:     int __unused_int ATTRIBUTE_UNUSED;
                    682: 
                    683:     int i, j;
                    684:     int hd_len = 0;
                    685:     char buf[1024];
                    686:     char fmt[16];
                    687: 
                    688: 
                    689:     erase();
                    690:     getmaxyx(stdscr, __unused_int, maxx);
                    691: 
                    692:     rowstat = 5;
                    693: 
                    694:     move(0, 0);
                    695:     attron(A_BOLD);
                    696:     snprintf(buf, sizeof(buf), "%s%s%s", "My traceroute  [v",
                    697:              PACKAGE_VERSION, "]");
                    698:     pwcenter(buf);
                    699:     attroff(A_BOLD);
                    700: 
1.1.1.3 ! misho     701:     mvprintw(1, 0, "%s (%s) -> %s (%s)",
        !           702:        ctl->LocalHostname, net_localaddr(),
        !           703:        ctl->Hostname, net_remoteaddr());
1.1       misho     704:     t = time(NULL);
1.1.1.3 ! misho     705:     mvprintw(1, maxx - 25, "%s", iso_time(&t));
1.1       misho     706:     printw("\n");
                    707: 
                    708:     printw("Keys:  ");
                    709:     attron(A_BOLD);
                    710:     printw("H");
                    711:     attroff(A_BOLD);
                    712:     printw("elp   ");
                    713:     attron(A_BOLD);
                    714:     printw("D");
                    715:     attroff(A_BOLD);
                    716:     printw("isplay mode   ");
                    717:     attron(A_BOLD);
                    718:     printw("R");
                    719:     attroff(A_BOLD);
                    720:     printw("estart statistics   ");
                    721:     attron(A_BOLD);
                    722:     printw("O");
                    723:     attroff(A_BOLD);
                    724:     printw("rder of fields   ");
                    725:     attron(A_BOLD);
                    726:     printw("q");
                    727:     attroff(A_BOLD);
                    728:     printw("uit\n");
                    729: 
                    730:     if (ctl->display_mode == DisplayModeDefault) {
                    731:         for (i = 0; i < MAXFLD; i++) {
                    732:             j = ctl->fld_index[ctl->fld_active[i]];
                    733:             if (j < 0)
                    734:                 continue;
                    735: 
                    736:             snprintf(fmt, sizeof(fmt), "%%%ds", data_fields[j].length);
                    737:             snprintf(buf + hd_len, sizeof(buf) - hd_len, fmt,
                    738:                      data_fields[j].title);
                    739:             hd_len += data_fields[j].length;
                    740:         }
                    741:         attron(A_BOLD);
                    742:         mvprintw(rowstat - 1, 0, " Host");
                    743:         mvprintw(rowstat - 1, maxx - hd_len - 1, "%s", buf);
                    744:         mvprintw(rowstat - 2, maxx - hd_len - 1,
                    745:                  "   Packets               Pings");
                    746:         attroff(A_BOLD);
                    747: 
                    748:         move(rowstat, 0);
                    749:         mtr_curses_hosts(ctl, maxx - hd_len - 1);
                    750: 
                    751:     } else {
                    752:         char msg[80];
                    753:         int padding = 30;
                    754:         int max_cols;
                    755: 
                    756: #ifdef HAVE_IPINFO
                    757:         if (is_printii(ctl))
                    758:             padding += get_iiwidth(ctl->ipinfo_no);
                    759: #endif
                    760:         max_cols =
                    761:             maxx <= SAVED_PINGS + padding ? maxx - padding : SAVED_PINGS;
                    762:         startstat = padding - 2;
                    763: 
                    764:         snprintf(msg, sizeof(msg), " Last %3d pings", max_cols);
1.1.1.3 ! misho     765:         mvprintw(rowstat - 1, startstat, "%s", msg);
1.1       misho     766: 
                    767:         attroff(A_BOLD);
                    768:         move(rowstat, 0);
                    769: 
                    770:         mtr_gen_scale(ctl);
                    771:         mtr_curses_graph(ctl, startstat, max_cols);
                    772: 
                    773:         printw("\n");
                    774:         attron(A_BOLD);
                    775:         printw("Scale:");
                    776:         attroff(A_BOLD);
                    777: 
                    778:         for (i = 0; i < NUM_FACTORS - 1; i++) {
                    779:             printw("  ");
                    780:             attrset(block_col[i + 1]);
                    781:             printw("%c", block_map[i]);
                    782:             attrset(A_NORMAL);
                    783:             printw(":%d ms", scale[i] / 1000);
                    784:         }
                    785:         printw("  ");
                    786:         attrset(block_col[NUM_FACTORS]);
                    787:         printw("%c", block_map[NUM_FACTORS - 1]);
                    788:         attrset(A_NORMAL);
                    789:     }
                    790: 
                    791:     refresh();
                    792: }
                    793: 
                    794: 
                    795: void mtr_curses_open(
                    796:     struct mtr_ctl *ctl)
                    797: {
                    798:     int bg_col = 0;
                    799:     int i;
                    800: 
                    801:     initscr();
                    802:     raw();
                    803:     noecho();
                    804:     start_color();
                    805:     if (use_default_colors() == OK)
                    806:         bg_col = -1;
                    807:     for (i = 0; i < NUM_FACTORS; i++)
                    808:         init_pair(i + 1, i, bg_col);
                    809: 
                    810:     mtr_curses_init();
                    811:     mtr_curses_redraw(ctl);
                    812: }
                    813: 
                    814: 
                    815: void mtr_curses_close(
                    816:     void)
                    817: {
                    818:     printw("\n");
                    819:     endwin();
                    820: }
                    821: 
                    822: 
                    823: void mtr_curses_clear(
                    824:     struct mtr_ctl *ctl)
                    825: {
                    826:     mtr_curses_close();
                    827:     mtr_curses_open(ctl);
                    828: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>