Blame ui/curses.c

Packit b802ec
/*
Packit b802ec
    mtr  --  a network diagnostic tool
Packit b802ec
    Copyright (C) 1997,1998  Matt Kimball
Packit b802ec
Packit b802ec
    This program is free software; you can redistribute it and/or modify
Packit b802ec
    it under the terms of the GNU General Public License version 2 as 
Packit b802ec
    published by the Free Software Foundation.
Packit b802ec
Packit b802ec
    This program is distributed in the hope that it will be useful,
Packit b802ec
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b802ec
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b802ec
    GNU General Public License for more details.
Packit b802ec
Packit b802ec
    You should have received a copy of the GNU General Public License
Packit b802ec
    along with this program; if not, write to the Free Software
Packit b802ec
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Packit b802ec
*/
Packit b802ec
Packit b802ec
#include "config.h"
Packit b802ec
Packit b802ec
#include "mtr.h"
Packit b802ec
Packit b802ec
#include <strings.h>
Packit b802ec
#include <unistd.h>
Packit b802ec
Packit b802ec
#include <ctype.h>
Packit b802ec
#include <stdlib.h>
Packit b802ec
#include <string.h>
Packit b802ec
#include <time.h>
Packit b802ec
Packit b802ec
/* MacOSX may need this before socket.h...*/
Packit b802ec
#if defined(HAVE_SYS_TYPES_H)
Packit b802ec
#include <sys/types.h>
Packit b802ec
#endif
Packit b802ec
Packit b802ec
#include <sys/socket.h>
Packit b802ec
#include <netinet/in.h>
Packit b802ec
#include <arpa/inet.h>
Packit b802ec
Packit b802ec
#if defined(HAVE_NCURSES_H)
Packit b802ec
#include <ncurses.h>
Packit b802ec
#elif defined(HAVE_NCURSES_CURSES_H)
Packit b802ec
#include <ncurses/curses.h>
Packit b802ec
#elif defined(HAVE_CURSES_H)
Packit b802ec
#include <curses.h>
Packit b802ec
#elif defined(HAVE_CURSESX_H)
Packit b802ec
#include <cursesX.h>
Packit b802ec
#else
Packit b802ec
#error No curses header file available
Packit b802ec
#endif
Packit b802ec
Packit b802ec
/* This go-around is needed only when compiling with antique version of curses.
Packit b802ec
   getmaxyx is part of Technical Standard X/Open Curses Issue 4, Version 2 (1996).
Packit b802ec
   http://pubs.opengroup.org/onlinepubs/9693989999/toc.pdf see page 106 */
Packit b802ec
#ifndef getmaxyx
Packit b802ec
#define getmaxyx(win,y,x)	((y) = (win)->_maxy + 1, (x) = (win)->_maxx + 1)
Packit b802ec
#endif
Packit b802ec
Packit b802ec
#include "mtr.h"
Packit b802ec
#include "mtr-curses.h"
Packit b802ec
#include "net.h"
Packit b802ec
#include "dns.h"
Packit b802ec
#include "asn.h"
Packit b802ec
#include "display.h"
Packit b802ec
#include "utils.h"
Packit b802ec
Packit b802ec
Packit b802ec
enum { NUM_FACTORS = 8 };
Packit b802ec
static double factors[NUM_FACTORS];
Packit b802ec
static int scale[NUM_FACTORS];
Packit b802ec
static char block_map[NUM_FACTORS];
Packit b802ec
Packit b802ec
enum { black = 1, red, green, yellow, blue, magenta, cyan, white };
Packit b802ec
static const int block_col[NUM_FACTORS + 1] = {
Packit b802ec
    COLOR_PAIR(red) | A_BOLD,
Packit b802ec
    A_NORMAL,
Packit b802ec
    COLOR_PAIR(green),
Packit b802ec
    COLOR_PAIR(green) | A_BOLD,
Packit b802ec
    COLOR_PAIR(yellow) | A_BOLD,
Packit b802ec
    COLOR_PAIR(magenta) | A_BOLD,
Packit b802ec
    COLOR_PAIR(magenta),
Packit b802ec
    COLOR_PAIR(red),
Packit b802ec
    COLOR_PAIR(red) | A_BOLD
Packit b802ec
};
Packit b802ec
Packit b802ec
static void pwcenter(
Packit b802ec
    char *str)
Packit b802ec
{
Packit b802ec
    int maxx;
Packit b802ec
    size_t cx;
Packit b802ec
    int __unused_int ATTRIBUTE_UNUSED;
Packit b802ec
Packit b802ec
    getmaxyx(stdscr, __unused_int, maxx);
Packit b802ec
    cx = (size_t) (maxx - strlen(str)) / 2;
Packit b802ec
    printw("%*s%s", (int) cx, "", str);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static char *format_number(
Packit b802ec
    int n,
Packit b802ec
    int w,
Packit b802ec
    char *buf)
Packit b802ec
{
Packit b802ec
    if (w != 5)
Packit b802ec
        /* XXX todo: implement w != 5.. */
Packit b802ec
        snprintf(buf, w + 1, "%s", "unimpl");
Packit b802ec
    else if (n < 100000)
Packit b802ec
        /* buf is good as-is */ ;
Packit b802ec
    else if (n < 1000000)
Packit b802ec
        snprintf(buf, w + 1, "%3dk%1d", n / 1000, (n % 1000) / 100);
Packit b802ec
    else if (n < 10000000)
Packit b802ec
        snprintf(buf, w + 1, "%1dM%03d", n / 1000000,
Packit b802ec
                 (n % 1000000) / 1000);
Packit b802ec
    else if (n < 100000000)
Packit b802ec
        snprintf(buf, w + 1, "%2dM%02d", n / 1000000,
Packit b802ec
                 (n % 1000000) / 10000);
Packit b802ec
    else if (n < 1000000000)
Packit b802ec
        snprintf(buf, w + 1, "%3dM%01d", n / 1000000,
Packit b802ec
                 (n % 1000000) / 100000);
Packit b802ec
    else                        /* if (n < 10000000000) */
Packit b802ec
        snprintf(buf, w + 1, "%1dG%03d", n / 1000000000,
Packit b802ec
                 (n % 1000000000) / 1000000);
Packit b802ec
Packit b802ec
    return buf;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int mtr_curses_keyaction(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    int c = getch();
Packit b802ec
    int i = 0;
Packit b802ec
    float f = 0.0;
Packit b802ec
    char buf[MAXFLD + 1];
Packit b802ec
Packit b802ec
    if (c == 'Q') {             /* must be checked before c = tolower(c) */
Packit b802ec
        mvprintw(2, 0, "Type of Service(tos): %d\n", ctl->tos);
Packit b802ec
        mvprintw(3, 0,
Packit b802ec
                 "default 0x00, min cost 0x02, rel 0x04,, thr 0x08, low del 0x10...\n");
Packit b802ec
        move(2, 22);
Packit b802ec
        refresh();
Packit b802ec
        while ((c = getch()) != '\n' && i < MAXFLD) {
Packit b802ec
            attron(A_BOLD);
Packit b802ec
            printw("%c", c);
Packit b802ec
            attroff(A_BOLD);
Packit b802ec
            refresh();
Packit b802ec
            buf[i++] = c;       /* need more checking on 'c' */
Packit b802ec
        }
Packit b802ec
        buf[i] = '\0';
Packit b802ec
        ctl->tos = atoi(buf);
Packit b802ec
        if (ctl->tos > 255 || ctl->tos < 0)
Packit b802ec
            ctl->tos = 0;
Packit b802ec
        return ActionNone;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    c = tolower(c);
Packit b802ec
Packit b802ec
    switch (c) {
Packit b802ec
    case 'q':
Packit b802ec
    case 3:
Packit b802ec
        return ActionQuit;
Packit b802ec
    case 12:
Packit b802ec
        return ActionClear;
Packit b802ec
    case 19:
Packit b802ec
    case 'p':
Packit b802ec
        return ActionPause;
Packit b802ec
    case 17:
Packit b802ec
    case ' ':
Packit b802ec
        return ActionResume;
Packit b802ec
    case 'r':
Packit b802ec
        return ActionReset;
Packit b802ec
    case 'd':
Packit b802ec
        return ActionDisplay;
Packit b802ec
    case 'e':
Packit b802ec
        return ActionMPLS;
Packit b802ec
    case 'n':
Packit b802ec
        return ActionDNS;
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
    case 'y':
Packit b802ec
        return ActionII;
Packit b802ec
    case 'z':
Packit b802ec
        return ActionAS;
Packit b802ec
#endif
Packit b802ec
    case '+':
Packit b802ec
        return ActionScrollDown;
Packit b802ec
    case '-':
Packit b802ec
        return ActionScrollUp;
Packit b802ec
    case 's':
Packit b802ec
        mvprintw(2, 0, "Change Packet Size: %d\n", ctl->cpacketsize);
Packit b802ec
        mvprintw(3, 0, "Size Range: %d-%d, < 0:random.\n", MINPACKET,
Packit b802ec
                 MAXPACKET);
Packit b802ec
        move(2, 20);
Packit b802ec
        refresh();
Packit b802ec
        while ((c = getch()) != '\n' && i < MAXFLD) {
Packit b802ec
            attron(A_BOLD);
Packit b802ec
            printw("%c", c);
Packit b802ec
            attroff(A_BOLD);
Packit b802ec
            refresh();
Packit b802ec
            buf[i++] = c;       /* need more checking on 'c' */
Packit b802ec
        }
Packit b802ec
        buf[i] = '\0';
Packit b802ec
        ctl->cpacketsize = atoi(buf);
Packit b802ec
        return ActionNone;
Packit b802ec
    case 'b':
Packit b802ec
        mvprintw(2, 0, "Ping Bit Pattern: %d\n", ctl->bitpattern);
Packit b802ec
        mvprintw(3, 0, "Pattern Range: 0(0x00)-255(0xff), <0 random.\n");
Packit b802ec
        move(2, 18);
Packit b802ec
        refresh();
Packit b802ec
        while ((c = getch()) != '\n' && i < MAXFLD) {
Packit b802ec
            attron(A_BOLD);
Packit b802ec
            printw("%c", c);
Packit b802ec
            attroff(A_BOLD);
Packit b802ec
            refresh();
Packit b802ec
            buf[i++] = c;       /* need more checking on 'c' */
Packit b802ec
        }
Packit b802ec
        buf[i] = '\0';
Packit b802ec
        ctl->bitpattern = atoi(buf);
Packit b802ec
        if (ctl->bitpattern > 255)
Packit b802ec
            ctl->bitpattern = -1;
Packit b802ec
        return ActionNone;
Packit b802ec
    case 'i':
Packit b802ec
        mvprintw(2, 0, "Interval : %0.0f\n\n", ctl->WaitTime);
Packit b802ec
        move(2, 11);
Packit b802ec
        refresh();
Packit b802ec
        while ((c = getch()) != '\n' && i < MAXFLD) {
Packit b802ec
            attron(A_BOLD);
Packit b802ec
            printw("%c", c);
Packit b802ec
            attroff(A_BOLD);
Packit b802ec
            refresh();
Packit b802ec
            buf[i++] = c;       /* need more checking on 'c' */
Packit b802ec
        }
Packit b802ec
        buf[i] = '\0';
Packit b802ec
Packit b802ec
        f = atof(buf);
Packit b802ec
Packit b802ec
        if (f <= 0.0)
Packit b802ec
            return ActionNone;
Packit b802ec
        if (getuid() != 0 && f < 1.0)
Packit b802ec
            return ActionNone;
Packit b802ec
        ctl->WaitTime = f;
Packit b802ec
Packit b802ec
        return ActionNone;
Packit b802ec
    case 'f':
Packit b802ec
        mvprintw(2, 0, "First TTL: %d\n\n", ctl->fstTTL);
Packit b802ec
        move(2, 11);
Packit b802ec
        refresh();
Packit b802ec
        while ((c = getch()) != '\n' && i < MAXFLD) {
Packit b802ec
            attron(A_BOLD);
Packit b802ec
            printw("%c", c);
Packit b802ec
            attroff(A_BOLD);
Packit b802ec
            refresh();
Packit b802ec
            buf[i++] = c;       /* need more checking on 'c' */
Packit b802ec
        }
Packit b802ec
        buf[i] = '\0';
Packit b802ec
        i = atoi(buf);
Packit b802ec
Packit b802ec
        if (i < 1 || i > ctl->maxTTL)
Packit b802ec
            return ActionNone;
Packit b802ec
        ctl->fstTTL = i;
Packit b802ec
Packit b802ec
        return ActionNone;
Packit b802ec
    case 'm':
Packit b802ec
        mvprintw(2, 0, "Max TTL: %d\n\n", ctl->maxTTL);
Packit b802ec
        move(2, 9);
Packit b802ec
        refresh();
Packit b802ec
        while ((c = getch()) != '\n' && i < MAXFLD) {
Packit b802ec
            attron(A_BOLD);
Packit b802ec
            printw("%c", c);
Packit b802ec
            attroff(A_BOLD);
Packit b802ec
            refresh();
Packit b802ec
            buf[i++] = c;       /* need more checking on 'c' */
Packit b802ec
        }
Packit b802ec
        buf[i] = '\0';
Packit b802ec
        i = atoi(buf);
Packit b802ec
Packit b802ec
        if (i < ctl->fstTTL || i > (MaxHost - 1))
Packit b802ec
            return ActionNone;
Packit b802ec
        ctl->maxTTL = i;
Packit b802ec
Packit b802ec
        return ActionNone;
Packit b802ec
        /* fields to display & their ordering */
Packit b802ec
    case 'o':
Packit b802ec
        mvprintw(2, 0, "Fields: %s\n\n", ctl->fld_active);
Packit b802ec
Packit b802ec
        for (i = 0; i < MAXFLD; i++) {
Packit b802ec
            if (data_fields[i].descr != NULL)
Packit b802ec
                printw("  %s\n", data_fields[i].descr);
Packit b802ec
        }
Packit b802ec
        printw("\n");
Packit b802ec
        move(2, 8);             /* length of "Fields: " */
Packit b802ec
        refresh();
Packit b802ec
Packit b802ec
        i = 0;
Packit b802ec
        while ((c = getch()) != '\n' && i < MAXFLD) {
Packit b802ec
            if (strchr(ctl->available_options, c)) {
Packit b802ec
                attron(A_BOLD);
Packit b802ec
                printw("%c", c);
Packit b802ec
                attroff(A_BOLD);
Packit b802ec
                refresh();
Packit b802ec
                buf[i++] = c;   /* Only permit values in "available_options" be entered */
Packit b802ec
            } else {
Packit b802ec
                printf("\a");   /* Illegal character. Beep, ring the bell. */
Packit b802ec
            }
Packit b802ec
        }
Packit b802ec
        buf[i] = '\0';
Packit b802ec
        if (strlen(buf) > 0)
Packit b802ec
            xstrncpy(ctl->fld_active, buf, 2 * MAXFLD);
Packit b802ec
Packit b802ec
        return ActionNone;
Packit b802ec
    case 'j':
Packit b802ec
        if (strchr(ctl->fld_active, 'N'))
Packit b802ec
            /* GeoMean and jitter */
Packit b802ec
            xstrncpy(ctl->fld_active, "DR AGJMXI", 2 * MAXFLD);
Packit b802ec
        else
Packit b802ec
            /* default */
Packit b802ec
            xstrncpy(ctl->fld_active, "LS NABWV", 2 * MAXFLD);
Packit b802ec
        return ActionNone;
Packit b802ec
    case 'u':
Packit b802ec
        switch (ctl->mtrtype) {
Packit b802ec
        case IPPROTO_ICMP:
Packit b802ec
        case IPPROTO_TCP:
Packit b802ec
            ctl->mtrtype = IPPROTO_UDP;
Packit b802ec
            break;
Packit b802ec
        case IPPROTO_UDP:
Packit b802ec
            ctl->mtrtype = IPPROTO_ICMP;
Packit b802ec
            break;
Packit b802ec
        }
Packit b802ec
        return ActionNone;
Packit b802ec
    case 't':
Packit b802ec
        switch (ctl->mtrtype) {
Packit b802ec
        case IPPROTO_ICMP:
Packit b802ec
        case IPPROTO_UDP:
Packit b802ec
            ctl->mtrtype = IPPROTO_TCP;
Packit b802ec
            break;
Packit b802ec
        case IPPROTO_TCP:
Packit b802ec
            ctl->mtrtype = IPPROTO_ICMP;
Packit b802ec
            break;
Packit b802ec
        }
Packit b802ec
        return ActionNone;
Packit b802ec
        /* reserve to display help message -Min */
Packit b802ec
    case '?':
Packit b802ec
    case 'h':
Packit b802ec
        mvprintw(2, 0, "Command:\n");
Packit b802ec
        printw("  ?|h     help\n");
Packit b802ec
        printw("  p       pause (SPACE to resume)\n");
Packit b802ec
        printw("  d       switching display mode\n");
Packit b802ec
        printw("  e       toggle MPLS information on/off\n");
Packit b802ec
        printw("  n       toggle DNS on/off\n");
Packit b802ec
        printw("  r       reset all counters\n");
Packit b802ec
        printw
Packit b802ec
            ("  o str   set the columns to display, default str='LRS N BAWV'\n");
Packit b802ec
        printw
Packit b802ec
            ("  j       toggle latency(LS NABWV)/jitter(DR AGJMXI) stats\n");
Packit b802ec
        printw("  c <n>   report cycle n, default n=infinite\n");
Packit b802ec
        printw
Packit b802ec
            ("  i <n>   set the ping interval to n seconds, default n=1\n");
Packit b802ec
        printw
Packit b802ec
            ("  f <n>   set the initial time-to-live(ttl), default n=1\n");
Packit b802ec
        printw
Packit b802ec
            ("  m <n>   set the max time-to-live, default n= # of hops\n");
Packit b802ec
        printw("  s <n>   set the packet size to n or random(n<0)\n");
Packit b802ec
        printw
Packit b802ec
            ("  b <c>   set ping bit pattern to c(0..255) or random(c<0)\n");
Packit b802ec
        printw("  Q <t>   set ping packet's TOS to t\n");
Packit b802ec
        printw("  u       switch between ICMP ECHO and UDP datagrams\n");
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
        printw("  y       switching IP info\n");
Packit b802ec
        printw("  z       toggle ASN info on/off\n");
Packit b802ec
#endif
Packit b802ec
        printw("\n");
Packit b802ec
        printw(" press any key to go back...");
Packit b802ec
        getch();                /* read and ignore 'any key' */
Packit b802ec
        return ActionNone;
Packit b802ec
    default:                   /* ignore unknown input */
Packit b802ec
        return ActionNone;
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static void format_field(
Packit b802ec
    char *dst,
Packit b802ec
    int dst_length,
Packit b802ec
    const char *format,
Packit b802ec
    int n)
Packit b802ec
{
Packit b802ec
    if (index(format, 'N')) {
Packit b802ec
        *dst++ = ' ';
Packit b802ec
        format_number(n, 5, dst);
Packit b802ec
    } else if (strchr(format, 'f')) {
Packit b802ec
        /* this is for fields where we measure integer microseconds but
Packit b802ec
           display floating point miliseconds. Convert to float here. */
Packit b802ec
        snprintf(dst, dst_length, format, n / 1000.0);
Packit b802ec
        /* this was marked as a temporary hack over 10 years ago. -- REW */
Packit b802ec
    } else {
Packit b802ec
        snprintf(dst, dst_length, format, n);
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
static void mtr_curses_hosts(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    int startstat)
Packit b802ec
{
Packit b802ec
    int max;
Packit b802ec
    int at;
Packit b802ec
    struct mplslen *mpls, *mplss;
Packit b802ec
    ip_t *addr, *addrs;
Packit b802ec
    int y;
Packit b802ec
    char *name;
Packit b802ec
Packit b802ec
    int i, j, k;
Packit b802ec
    int hd_len;
Packit b802ec
    char buf[1024];
Packit b802ec
    int __unused_int ATTRIBUTE_UNUSED;
Packit b802ec
Packit b802ec
    max = net_max(ctl);
Packit b802ec
Packit b802ec
    for (at = net_min(ctl) + ctl->display_offset; at < max; at++) {
Packit b802ec
        printw("%2d. ", at + 1);
Packit b802ec
        addr = net_addr(at);
Packit b802ec
        mpls = net_mpls(at);
Packit b802ec
Packit b802ec
        if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af) !=
Packit b802ec
            0) {
Packit b802ec
            name = dns_lookup(ctl, addr);
Packit b802ec
            if (!net_up(at))
Packit b802ec
                attron(A_BOLD);
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
            if (is_printii(ctl))
Packit b802ec
                printw(fmt_ipinfo(ctl, addr));
Packit b802ec
#endif
Packit b802ec
            if (name != NULL) {
Packit b802ec
                if (ctl->show_ips)
Packit b802ec
                    printw("%s (%s)", name, strlongip(ctl, addr));
Packit b802ec
                else
Packit b802ec
                    printw("%s", name);
Packit b802ec
            } else {
Packit b802ec
                printw("%s", strlongip(ctl, addr));
Packit b802ec
            }
Packit b802ec
            attroff(A_BOLD);
Packit b802ec
Packit b802ec
            getyx(stdscr, y, __unused_int);
Packit b802ec
            move(y, startstat);
Packit b802ec
Packit b802ec
            /* net_xxx returns times in usecs. Just display millisecs */
Packit b802ec
            hd_len = 0;
Packit b802ec
            for (i = 0; i < MAXFLD; i++) {
Packit b802ec
                /* Ignore options that don't exist */
Packit b802ec
                /* On the other hand, we now check the input side. Shouldn't happen, 
Packit b802ec
                   can't be careful enough. */
Packit b802ec
                j = ctl->fld_index[ctl->fld_active[i]];
Packit b802ec
                if (j == -1)
Packit b802ec
                    continue;
Packit b802ec
                format_field(buf + hd_len, sizeof(buf) - hd_len,
Packit b802ec
                             data_fields[j].format,
Packit b802ec
                             data_fields[j].net_xxx(at));
Packit b802ec
                hd_len += data_fields[j].length;
Packit b802ec
            }
Packit b802ec
            buf[hd_len] = 0;
Packit b802ec
            printw("%s", buf);
Packit b802ec
Packit b802ec
            for (k = 0; k < mpls->labels && ctl->enablempls; k++) {
Packit b802ec
                printw("\n    [MPLS: Lbl %lu Exp %u S %u TTL %u]",
Packit b802ec
                       mpls->label[k], mpls->exp[k], mpls->s[k],
Packit b802ec
                       mpls->ttl[k]);
Packit b802ec
            }
Packit b802ec
Packit b802ec
            /* Multi path */
Packit b802ec
            for (i = 0; i < MAXPATH; i++) {
Packit b802ec
                addrs = net_addrs(at, i);
Packit b802ec
                mplss = net_mplss(at, i);
Packit b802ec
                if (addrcmp((void *) addrs, (void *) addr, ctl->af) == 0)
Packit b802ec
                    continue;
Packit b802ec
                if (addrcmp
Packit b802ec
                    ((void *) addrs, (void *) &ctl->unspec_addr,
Packit b802ec
                     ctl->af) == 0)
Packit b802ec
                    break;
Packit b802ec
Packit b802ec
                name = dns_lookup(ctl, addrs);
Packit b802ec
                if (!net_up(at))
Packit b802ec
                    attron(A_BOLD);
Packit b802ec
                printw("\n    ");
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
                if (is_printii(ctl))
Packit b802ec
                    printw(fmt_ipinfo(ctl, addrs));
Packit b802ec
#endif
Packit b802ec
                if (name != NULL) {
Packit b802ec
                    if (ctl->show_ips)
Packit b802ec
                        printw("%s (%s)", name, strlongip(ctl, addrs));
Packit b802ec
                    else
Packit b802ec
                        printw("%s", name);
Packit b802ec
                } else {
Packit b802ec
                    printw("%s", strlongip(ctl, addrs));
Packit b802ec
                }
Packit b802ec
                for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
Packit b802ec
                    printw("\n    [MPLS: Lbl %lu Exp %u S %u TTL %u]",
Packit b802ec
                           mplss->label[k], mplss->exp[k], mplss->s[k],
Packit b802ec
                           mplss->ttl[k]);
Packit b802ec
                }
Packit b802ec
                attroff(A_BOLD);
Packit b802ec
            }
Packit b802ec
Packit b802ec
        } else {
Packit b802ec
            printw("???");
Packit b802ec
        }
Packit b802ec
Packit b802ec
        printw("\n");
Packit b802ec
    }
Packit b802ec
    move(2, 0);
Packit b802ec
}
Packit b802ec
Packit b802ec
static void mtr_gen_scale(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    int *saved, i, max, at;
Packit b802ec
    int range;
Packit b802ec
    static int low_ms, high_ms;
Packit b802ec
Packit b802ec
    low_ms = 1000000;
Packit b802ec
    high_ms = -1;
Packit b802ec
Packit b802ec
    for (i = 0; i < NUM_FACTORS; i++) {
Packit b802ec
        scale[i] = 0;
Packit b802ec
    }
Packit b802ec
    max = net_max(ctl);
Packit b802ec
    for (at = ctl->display_offset; at < max; at++) {
Packit b802ec
        saved = net_saved_pings(at);
Packit b802ec
        for (i = 0; i < SAVED_PINGS; i++) {
Packit b802ec
            if (saved[i] < 0)
Packit b802ec
                continue;
Packit b802ec
            if (saved[i] < low_ms) {
Packit b802ec
                low_ms = saved[i];
Packit b802ec
            }
Packit b802ec
            if (saved[i] > high_ms) {
Packit b802ec
                high_ms = saved[i];
Packit b802ec
            }
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
    range = high_ms - low_ms;
Packit b802ec
    for (i = 0; i < NUM_FACTORS; i++) {
Packit b802ec
        scale[i] = low_ms + ((double) range * factors[i]);
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
static void mtr_curses_init(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    int i;
Packit b802ec
    int block_split;
Packit b802ec
Packit b802ec
    /* Initialize factors to a log scale. */
Packit b802ec
    for (i = 0; i < NUM_FACTORS; i++) {
Packit b802ec
        factors[i] = ((double) 1 / NUM_FACTORS) * (i + 1);
Packit b802ec
        factors[i] *= factors[i];       /* Squared. */
Packit b802ec
    }
Packit b802ec
Packit b802ec
    /* Initialize block_map.  The block_split is always smaller than 9 */
Packit b802ec
    block_split = (NUM_FACTORS - 2) / 2;
Packit b802ec
    for (i = 1; i <= block_split; i++) {
Packit b802ec
        block_map[i] = '0' + i;
Packit b802ec
    }
Packit b802ec
    for (i = block_split + 1; i < NUM_FACTORS - 1; i++) {
Packit b802ec
        block_map[i] = 'a' + i - block_split - 1;
Packit b802ec
    }
Packit b802ec
    block_map[0] = '.';
Packit b802ec
    block_map[NUM_FACTORS - 1] = '>';
Packit b802ec
}
Packit b802ec
Packit b802ec
static void mtr_print_scaled(
Packit b802ec
    int ms)
Packit b802ec
{
Packit b802ec
    int i;
Packit b802ec
Packit b802ec
    for (i = 0; i < NUM_FACTORS; i++) {
Packit b802ec
        if (ms <= scale[i]) {
Packit b802ec
            attrset(block_col[i + 1]);
Packit b802ec
            printw("%c", block_map[i]);
Packit b802ec
            attrset(A_NORMAL);
Packit b802ec
            return;
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
    printw(">");
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static void mtr_fill_graph(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    int at,
Packit b802ec
    int cols)
Packit b802ec
{
Packit b802ec
    int *saved;
Packit b802ec
    int i;
Packit b802ec
Packit b802ec
    saved = net_saved_pings(at);
Packit b802ec
    for (i = SAVED_PINGS - cols; i < SAVED_PINGS; i++) {
Packit b802ec
        if (saved[i] == -2) {
Packit b802ec
            printw(" ");
Packit b802ec
        } else if (saved[i] == -1) {
Packit b802ec
            attrset(block_col[0]);
Packit b802ec
            printw("%c", '?');
Packit b802ec
            attrset(A_NORMAL);
Packit b802ec
        } else {
Packit b802ec
            if (ctl->display_mode == DisplayModeBlockmap) {
Packit b802ec
                if (saved[i] > scale[6]) {
Packit b802ec
                    printw("%c", block_map[NUM_FACTORS - 1]);
Packit b802ec
                } else {
Packit b802ec
                    printw(".");
Packit b802ec
                }
Packit b802ec
            } else {
Packit b802ec
                mtr_print_scaled(saved[i]);
Packit b802ec
            }
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static void mtr_curses_graph(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    int startstat,
Packit b802ec
    int cols)
Packit b802ec
{
Packit b802ec
    int max, at, y;
Packit b802ec
    ip_t *addr;
Packit b802ec
    char *name;
Packit b802ec
    int __unused_int ATTRIBUTE_UNUSED;
Packit b802ec
Packit b802ec
    max = net_max(ctl);
Packit b802ec
Packit b802ec
    for (at = ctl->display_offset; at < max; at++) {
Packit b802ec
        printw("%2d. ", at + 1);
Packit b802ec
Packit b802ec
        addr = net_addr(at);
Packit b802ec
        if (!addr) {
Packit b802ec
            printw("???\n");
Packit b802ec
            continue;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        if (!net_up(at))
Packit b802ec
            attron(A_BOLD);
Packit b802ec
        if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
            if (is_printii(ctl))
Packit b802ec
                printw(fmt_ipinfo(ctl, addr));
Packit b802ec
#endif
Packit b802ec
            name = dns_lookup(ctl, addr);
Packit b802ec
            printw("%s", name ? name : strlongip(ctl, addr));
Packit b802ec
        } else
Packit b802ec
            printw("???");
Packit b802ec
        attroff(A_BOLD);
Packit b802ec
Packit b802ec
        getyx(stdscr, y, __unused_int);
Packit b802ec
        move(y, startstat);
Packit b802ec
Packit b802ec
        printw(" ");
Packit b802ec
        mtr_fill_graph(ctl, at, cols);
Packit b802ec
        printw("\n");
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void mtr_curses_redraw(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    int maxx;
Packit b802ec
    int startstat;
Packit b802ec
    int rowstat;
Packit b802ec
    time_t t;
Packit b802ec
    int __unused_int ATTRIBUTE_UNUSED;
Packit b802ec
Packit b802ec
    int i, j;
Packit b802ec
    int hd_len = 0;
Packit b802ec
    char buf[1024];
Packit b802ec
    char fmt[16];
Packit b802ec
Packit b802ec
Packit b802ec
    erase();
Packit b802ec
    getmaxyx(stdscr, __unused_int, maxx);
Packit b802ec
Packit b802ec
    rowstat = 5;
Packit b802ec
Packit b802ec
    move(0, 0);
Packit b802ec
    attron(A_BOLD);
Packit b802ec
    snprintf(buf, sizeof(buf), "%s%s%s", "My traceroute  [v",
Packit b802ec
             PACKAGE_VERSION, "]");
Packit b802ec
    pwcenter(buf);
Packit b802ec
    attroff(A_BOLD);
Packit b802ec
Packit b802ec
    mvprintw(1, 0, "%s (%s)", ctl->LocalHostname, net_localaddr());
Packit b802ec
    t = time(NULL);
Packit b802ec
    mvprintw(1, maxx - 25, iso_time(&t);;
Packit b802ec
    printw("\n");
Packit b802ec
Packit b802ec
    printw("Keys:  ");
Packit b802ec
    attron(A_BOLD);
Packit b802ec
    printw("H");
Packit b802ec
    attroff(A_BOLD);
Packit b802ec
    printw("elp   ");
Packit b802ec
    attron(A_BOLD);
Packit b802ec
    printw("D");
Packit b802ec
    attroff(A_BOLD);
Packit b802ec
    printw("isplay mode   ");
Packit b802ec
    attron(A_BOLD);
Packit b802ec
    printw("R");
Packit b802ec
    attroff(A_BOLD);
Packit b802ec
    printw("estart statistics   ");
Packit b802ec
    attron(A_BOLD);
Packit b802ec
    printw("O");
Packit b802ec
    attroff(A_BOLD);
Packit b802ec
    printw("rder of fields   ");
Packit b802ec
    attron(A_BOLD);
Packit b802ec
    printw("q");
Packit b802ec
    attroff(A_BOLD);
Packit b802ec
    printw("uit\n");
Packit b802ec
Packit b802ec
    if (ctl->display_mode == DisplayModeDefault) {
Packit b802ec
        for (i = 0; i < MAXFLD; i++) {
Packit b802ec
            j = ctl->fld_index[ctl->fld_active[i]];
Packit b802ec
            if (j < 0)
Packit b802ec
                continue;
Packit b802ec
Packit b802ec
            snprintf(fmt, sizeof(fmt), "%%%ds", data_fields[j].length);
Packit b802ec
            snprintf(buf + hd_len, sizeof(buf) - hd_len, fmt,
Packit b802ec
                     data_fields[j].title);
Packit b802ec
            hd_len += data_fields[j].length;
Packit b802ec
        }
Packit b802ec
        attron(A_BOLD);
Packit b802ec
        mvprintw(rowstat - 1, 0, " Host");
Packit b802ec
        mvprintw(rowstat - 1, maxx - hd_len - 1, "%s", buf);
Packit b802ec
        mvprintw(rowstat - 2, maxx - hd_len - 1,
Packit b802ec
                 "   Packets               Pings");
Packit b802ec
        attroff(A_BOLD);
Packit b802ec
Packit b802ec
        move(rowstat, 0);
Packit b802ec
        mtr_curses_hosts(ctl, maxx - hd_len - 1);
Packit b802ec
Packit b802ec
    } else {
Packit b802ec
        char msg[80];
Packit b802ec
        int padding = 30;
Packit b802ec
        int max_cols;
Packit b802ec
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
        if (is_printii(ctl))
Packit b802ec
            padding += get_iiwidth(ctl->ipinfo_no);
Packit b802ec
#endif
Packit b802ec
        max_cols =
Packit b802ec
            maxx <= SAVED_PINGS + padding ? maxx - padding : SAVED_PINGS;
Packit b802ec
        startstat = padding - 2;
Packit b802ec
Packit b802ec
        snprintf(msg, sizeof(msg), " Last %3d pings", max_cols);
Packit b802ec
        mvprintw(rowstat - 1, startstat, msg);
Packit b802ec
Packit b802ec
        attroff(A_BOLD);
Packit b802ec
        move(rowstat, 0);
Packit b802ec
Packit b802ec
        mtr_gen_scale(ctl);
Packit b802ec
        mtr_curses_graph(ctl, startstat, max_cols);
Packit b802ec
Packit b802ec
        printw("\n");
Packit b802ec
        attron(A_BOLD);
Packit b802ec
        printw("Scale:");
Packit b802ec
        attroff(A_BOLD);
Packit b802ec
Packit b802ec
        for (i = 0; i < NUM_FACTORS - 1; i++) {
Packit b802ec
            printw("  ");
Packit b802ec
            attrset(block_col[i + 1]);
Packit b802ec
            printw("%c", block_map[i]);
Packit b802ec
            attrset(A_NORMAL);
Packit b802ec
            printw(":%d ms", scale[i] / 1000);
Packit b802ec
        }
Packit b802ec
        printw("  ");
Packit b802ec
        attrset(block_col[NUM_FACTORS]);
Packit b802ec
        printw("%c", block_map[NUM_FACTORS - 1]);
Packit b802ec
        attrset(A_NORMAL);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    refresh();
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void mtr_curses_open(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    int bg_col = 0;
Packit b802ec
    int i;
Packit b802ec
Packit b802ec
    initscr();
Packit b802ec
    raw();
Packit b802ec
    noecho();
Packit b802ec
    start_color();
Packit b802ec
    if (use_default_colors() == OK)
Packit b802ec
        bg_col = -1;
Packit b802ec
    for (i = 0; i < NUM_FACTORS; i++)
Packit b802ec
        init_pair(i + 1, i, bg_col);
Packit b802ec
Packit b802ec
    mtr_curses_init();
Packit b802ec
    mtr_curses_redraw(ctl);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void mtr_curses_close(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    printw("\n");
Packit b802ec
    endwin();
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void mtr_curses_clear(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    mtr_curses_close();
Packit b802ec
    mtr_curses_open(ctl);
Packit b802ec
}