Annotation of embedaddon/iftop/ui.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * ui.c:
                      3:  *
                      4:  */
                      5: 
                      6: #include <sys/types.h>
                      7: 
                      8: #include <ctype.h>
                      9: #include <curses.h>
                     10: #include <errno.h>
                     11: #include <string.h>
                     12: #include <math.h>
                     13: #include <pthread.h>
                     14: #include <signal.h>
                     15: #include <stdlib.h>
                     16: #include <unistd.h>
                     17: #include <netdb.h>
                     18: 
                     19: #include <sys/wait.h>
                     20: 
                     21: #include "addr_hash.h"
                     22: #include "serv_hash.h"
                     23: #include "iftop.h"
                     24: #include "resolver.h"
                     25: #include "sorted_list.h"
                     26: #include "options.h"
                     27: #include "screenfilter.h"
                     28: 
                     29: #define HOSTNAME_LENGTH 256
                     30: 
                     31: #define HISTORY_DIVISIONS   3
                     32: 
                     33: #define HELP_TIME 2
                     34: 
                     35: #define HELP_MESSAGE \
                     36: "Host display:                          General:\n"\
                     37: " n - toggle DNS host resolution         P - pause display\n"\
                     38: " s - toggle show source host            h - toggle this help display\n"\
                     39: " d - toggle show destination host       b - toggle bar graph display\n"\
                     40: " t - cycle line display mode            B - cycle bar graph average\n"\
                     41: "                                        T - toggle cummulative line totals\n"\
                     42: "Port display:                           j/k - scroll display\n"\
                     43: " N - toggle service resolution          f - edit filter code\n"\
                     44: " S - toggle show source port            l - set screen filter\n"\
                     45: " D - toggle show destination port       L - lin/log scales\n"\
                     46: " p - toggle port display                ! - shell command\n"\
                     47: "                                        q - quit\n"\
                     48: "Sorting:\n"\
                     49: " 1/2/3 - sort by 1st/2nd/3rd column\n"\
                     50: " < - sort by source name\n"\
                     51: " > - sort by dest name\n"\
                     52: " o - freeze current order\n"\
                     53: "\n"\
                     54: "iftop, version " IFTOP_VERSION 
                     55: 
                     56: 
                     57: /* 2, 10 and 40 seconds */
                     58: int history_divs[HISTORY_DIVISIONS] = {1, 5, 20};
                     59: 
                     60: #define UNIT_DIVISIONS 4
                     61: char* unit_bits[UNIT_DIVISIONS] =  { "b", "Kb", "Mb", "Gb"};
                     62: char* unit_bytes[UNIT_DIVISIONS] =  { "B", "KB", "MB", "GB"};
                     63: 
                     64: typedef struct host_pair_line_tag {
                     65:     addr_pair ap;
                     66:     double long total_recv;
                     67:     double long total_sent;
                     68:     double long recv[HISTORY_DIVISIONS];
                     69:     double long sent[HISTORY_DIVISIONS];
                     70: } host_pair_line;
                     71: 
                     72: 
                     73: extern hash_type* history;
                     74: extern int history_pos;
                     75: extern int history_len;
                     76: 
                     77: extern options_t options ;
                     78: 
                     79: void ui_finish();
                     80: 
                     81: hash_type* screen_hash;
                     82: hash_type* service_hash;
                     83: sorted_list_type screen_list;
                     84: host_pair_line totals;
                     85: int peaksent, peakrecv, peaktotal;
                     86: 
                     87: #define HELP_MSG_SIZE 80
                     88: int showhelphint = 0;
                     89: int persistenthelp = 0;
                     90: time_t helptimer = 0;
                     91: char helpmsg[HELP_MSG_SIZE];
                     92: int dontshowdisplay = 0;
                     93: 
                     94: /*
                     95:  * Compare two screen lines based on bandwidth.  Start comparing from the 
                     96:  * specified column
                     97:  */
                     98: int screen_line_bandwidth_compare(host_pair_line* aa, host_pair_line* bb, int start_div) {
                     99:     int i;
                    100:     for(i = start_div; i < HISTORY_DIVISIONS; i++) {
                    101:         if(aa->recv[i] + aa->sent[i] != bb->recv[i] + bb->sent[i]) {
                    102:             return(aa->recv[i] + aa->sent[i] < bb->recv[i] + bb->sent[i]);
                    103:         }
                    104:     }
                    105:     return 1;
                    106: }
                    107: 
                    108: /*
                    109:  * Compare two screen lines based on hostname / IP.  Fall over to compare by
                    110:  * bandwidth.
                    111:  */
                    112: int screen_line_host_compare(struct in_addr* a, struct in_addr* b, host_pair_line* aa, host_pair_line* bb) {
                    113:     char hosta[HOSTNAME_LENGTH], hostb[HOSTNAME_LENGTH];
                    114:     int r;
                    115: 
                    116:     /* This isn't overly efficient because we resolve again before 
                    117:        display. */
                    118:     if (options.dnsresolution) {
                    119:         resolve(a, hosta, HOSTNAME_LENGTH);
                    120:         resolve(b, hostb, HOSTNAME_LENGTH);
                    121:     }
                    122:     else {
                    123:         strcpy(hosta, inet_ntoa(*a));
                    124:         strcpy(hostb, inet_ntoa(*b));
                    125:     }
                    126: 
                    127:     r = strcmp(hosta, hostb);
                    128: 
                    129:     if(r == 0) {
                    130:         return screen_line_bandwidth_compare(aa, bb, 2);
                    131:     }
                    132:     else {
                    133:         return (r > 0);
                    134:     }
                    135: 
                    136: 
                    137: }
                    138: 
                    139: int screen_line_compare(void* a, void* b) {
                    140:     host_pair_line* aa = (host_pair_line*)a;
                    141:     host_pair_line* bb = (host_pair_line*)b;
                    142:     if(options.sort == OPTION_SORT_DIV1) {
                    143:       return screen_line_bandwidth_compare(aa, bb, 0);
                    144:     }
                    145:     else if(options.sort == OPTION_SORT_DIV2) {
                    146:       return screen_line_bandwidth_compare(aa, bb, 1);
                    147:     }
                    148:     else if(options.sort == OPTION_SORT_DIV3) {
                    149:       return screen_line_bandwidth_compare(aa, bb, 2);
                    150:     }
                    151:     else if(options.sort == OPTION_SORT_SRC) {
                    152:       return screen_line_host_compare(&(aa->ap.src), &(bb->ap.src), aa, bb);
                    153:     }
                    154:     else if(options.sort == OPTION_SORT_DEST) {
                    155:       return screen_line_host_compare(&(aa->ap.dst), &(bb->ap.dst), aa, bb);
                    156:     }
                    157: 
                    158:     return 1;
                    159: }
                    160: 
                    161: void readable_size(float n, char* buf, int bsize, int ksize, int bytes) {
                    162: 
                    163:     int i = 0;
                    164:     float size = 1;
                    165: 
                    166:     /* Convert to bits? */
                    167:     if(bytes == 0) { 
                    168:       n *= 8;
                    169:     }
                    170: 
                    171:     while(1) {
                    172:       if(n < size * 1000 || i >= UNIT_DIVISIONS - 1) {
                    173:         snprintf(buf, bsize, " %4.0f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); 
                    174:         break;
                    175:       }
                    176:       i++;
                    177:       size *= ksize;
                    178:       if(n < size * 10) {
                    179:         snprintf(buf, bsize, " %4.2f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); 
                    180:         break;
                    181:       }
                    182:       else if(n < size * 100) {
                    183:         snprintf(buf, bsize, " %4.1f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); 
                    184:         break;
                    185:       }
                    186:   }
                    187: }
                    188: 
                    189: 
                    190: /* Barchart scales. */
                    191: static struct {
                    192:     int max, interval;
                    193: } scale[] = {
                    194:         {      64000,     10 },     /* 64 kbit/s */
                    195:         {     128000,     10 },
                    196:         {     256000,     10 },
                    197:         {    1000000,     10 },     /* 1 Mbit/s */
                    198:         {   10000000,     10 },     
                    199:         {  100000000,    100 },
                    200:         { 1000000000,    100 }      /* 1 Gbit/s */
                    201:     };
                    202: static int rateidx = 0, wantbiggerrate;
                    203: 
                    204: static int get_bar_interval(float bandwidth) {
                    205:     int i = 10;
                    206:     if(bandwidth > 100000000) {
                    207:         i = 100;
                    208:     }
                    209:     return i;
                    210: }
                    211: 
                    212: static float get_max_bandwidth() {
                    213:     float max;
                    214:     if(options.max_bandwidth > 0) {
                    215:         max = options.max_bandwidth;
                    216:     }
                    217:     else {
                    218:         max = scale[rateidx].max;
                    219:     }
                    220:     return max;
                    221: }
                    222: 
                    223: /* rate in bits */
                    224: static int get_bar_length(const int rate) {
                    225:     float l;
                    226:     if (rate <= 0)
                    227:         return 0;
                    228:     if (rate > scale[rateidx].max)
                    229:         wantbiggerrate = 1;
                    230:     if(options.log_scale) {
                    231:         l = log(rate) / log(get_max_bandwidth());
                    232:     }
                    233:     else {
                    234:         l = rate / get_max_bandwidth();
                    235:     }
                    236:     return (l * COLS);
                    237: }
                    238: 
                    239: static void draw_bar_scale(int* y) {
                    240:     float i;
                    241:     float max,interval;
                    242:     max = get_max_bandwidth();
                    243:     interval = get_bar_interval(max);
                    244:     if(options.showbars) {
                    245:         float stop;
                    246:         /* Draw bar graph scale on top of the window. */
                    247:         move(*y, 0);
                    248:         clrtoeol();
                    249:         mvhline(*y + 1, 0, 0, COLS);
                    250:         /* i in bytes */
                    251: 
                    252:         if(options.log_scale) {
                    253:             i = 1.25;
                    254:             stop = max / 8;
                    255:         }
                    256:         else {
                    257:             i = max / (5 * 8);
                    258:             stop = max / 8;
                    259:         }
                    260: 
                    261:         /* for (i = 1.25; i * 8 <= max; i *= interval) { */
                    262:         while(i <= stop) {
                    263:             char s[40], *p;
                    264:             int x;
                    265:             /* This 1024 vs 1000 stuff is just plain evil */
                    266:             readable_size(i, s, sizeof s, options.log_scale ? 1000 : 1024, 0);
                    267:             p = s + strspn(s, " ");
                    268:             x = get_bar_length(i * 8);
                    269:             mvaddch(*y + 1, x, ACS_BTEE);
                    270:             if (x + strlen(p) >= COLS)
                    271:                 x = COLS - strlen(p);
                    272:             mvaddstr(*y, x, p);
                    273: 
                    274:             if(options.log_scale) {
                    275:                 i *= interval;
                    276:             }
                    277:             else {
                    278:                 i += max / (5 * 8);
                    279:             }
                    280:         }
                    281:         mvaddch(*y + 1, 0, ACS_LLCORNER);
                    282:         *y += 2;
                    283:     }
                    284:     else {
                    285:         mvhline(*y, 0, 0, COLS);
                    286:         *y += 1;
                    287:     }
                    288: }
                    289: 
                    290: int history_length(const int d) {
                    291:     if (history_len < history_divs[d])
                    292:         return history_len * RESOLUTION;
                    293:     else
                    294:         return history_divs[d] * RESOLUTION;
                    295: }
                    296: 
                    297: void draw_line_total(float sent, float recv, int y, int x, option_linedisplay_t linedisplay, int bytes) {
                    298:     char buf[10];
                    299:     float n;
                    300:     switch(linedisplay) {
                    301:         case OPTION_LINEDISPLAY_TWO_LINE:
                    302:           draw_line_total(sent, recv, y, x, OPTION_LINEDISPLAY_ONE_LINE_SENT, bytes);
                    303:           draw_line_total(sent, recv, y+1, x, OPTION_LINEDISPLAY_ONE_LINE_RECV, bytes);
                    304:           break;
                    305:         case OPTION_LINEDISPLAY_ONE_LINE_SENT:
                    306:           n = sent;
                    307:           break;
                    308:         case OPTION_LINEDISPLAY_ONE_LINE_RECV:
                    309:           n = recv;
                    310:           break;
                    311:         case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
                    312:           n = recv + sent;
                    313:           break;
                    314:     }
                    315:     if(linedisplay != OPTION_LINEDISPLAY_TWO_LINE) {
                    316:         readable_size(n, buf, 10, 1024, bytes);
                    317:         mvaddstr(y, x, buf);
                    318:     }
                    319: }
                    320: 
                    321: void draw_bar(float n, int y) {
                    322:     int L;
                    323:     mvchgat(y, 0, -1, A_NORMAL, 0, NULL);
                    324:     L = get_bar_length(8 * n);
                    325:     if (L > 0)
                    326:         mvchgat(y, 0, L + 1, A_REVERSE, 0, NULL);
                    327: }
                    328: 
                    329: void draw_line_totals(int y, host_pair_line* line, option_linedisplay_t linedisplay) {
                    330:     int j;
                    331:     int x = (COLS - 8 * HISTORY_DIVISIONS);
                    332: 
                    333:     for(j = 0; j < HISTORY_DIVISIONS; j++) {
                    334:         draw_line_total(line->sent[j], line->recv[j], y, x, linedisplay, options.bandwidth_in_bytes);
                    335:         x += 8;
                    336:     }
                    337:     
                    338:     if(options.showbars) {
                    339:       switch(linedisplay) {
                    340:         case OPTION_LINEDISPLAY_TWO_LINE:
                    341:           draw_bar(line->sent[options.bar_interval],y);
                    342:           draw_bar(line->recv[options.bar_interval],y+1);
                    343:           break;
                    344:         case OPTION_LINEDISPLAY_ONE_LINE_SENT:
                    345:           draw_bar(line->sent[options.bar_interval],y);
                    346:           break;
                    347:         case OPTION_LINEDISPLAY_ONE_LINE_RECV:
                    348:           draw_bar(line->recv[options.bar_interval],y);
                    349:           break;
                    350:         case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
                    351:           draw_bar(line->recv[options.bar_interval] + line->sent[options.bar_interval],y);
                    352:           break;
                    353:       }
                    354:     }
                    355: }
                    356: 
                    357: void draw_totals(host_pair_line* totals) {
                    358:     /* Draw rule */
                    359:     int y = LINES - 4;
                    360:     int j;
                    361:     char buf[10];
                    362:     int x = (COLS - 8 * HISTORY_DIVISIONS);
                    363:     y++;
                    364:     draw_line_totals(y, totals, OPTION_LINEDISPLAY_TWO_LINE);
                    365:     y += 2;
                    366:     for(j = 0; j < HISTORY_DIVISIONS; j++) {
                    367:         readable_size((totals->sent[j] + totals->recv[j]) , buf, 10, 1024, options.bandwidth_in_bytes);
                    368:         mvaddstr(y, x, buf);
                    369:         x += 8;
                    370:     }
                    371: }
                    372: 
                    373: extern history_type history_totals;
                    374: 
                    375: void screen_list_init() {
                    376:     screen_list.compare = &screen_line_compare;
                    377:     sorted_list_initialise(&screen_list);
                    378: }
                    379: 
                    380: void screen_list_clear() {
                    381:     sorted_list_node* nn = NULL;
                    382:     peaksent = peakrecv = peaktotal = 0;
                    383:     while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) {
                    384:         free(nn->data);
                    385:     }
                    386:     sorted_list_destroy(&screen_list);
                    387: }
                    388: 
                    389: void calculate_totals() {
                    390:     int i;
                    391: 
                    392:     /**
                    393:      * Calculate peaks and totals
                    394:      */
                    395:     for(i = 0; i < HISTORY_LENGTH; i++) {
                    396:         int j;
                    397:         int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
                    398: 
                    399:         for(j = 0; j < HISTORY_DIVISIONS; j++) {
                    400:             if(i < history_divs[j]) {
                    401:                 totals.recv[j] += history_totals.recv[ii];
                    402:                 totals.sent[j] += history_totals.sent[ii];
                    403:             }
                    404:         }
                    405: 
                    406:         if(history_totals.recv[i] > peakrecv) {
                    407:             peakrecv = history_totals.recv[i];
                    408:         }
                    409:         if(history_totals.sent[i] > peaksent) {
                    410:             peaksent = history_totals.sent[i];
                    411:         }
                    412:         if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) {
                    413:             peaktotal = history_totals.recv[i] + history_totals.sent[i];       
                    414:         }
                    415:     }
                    416:     for(i = 0; i < HISTORY_DIVISIONS; i++) {
                    417:       int t = history_length(i);
                    418:       totals.recv[i] /= t;
                    419:       totals.sent[i] /= t;
                    420:     }
                    421: }
                    422: 
                    423: void make_screen_list() {
                    424:     hash_node_type* n = NULL;
                    425:     while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
                    426:         host_pair_line* line = (host_pair_line*)n->rec;
                    427:         int i;
                    428:         for(i = 0; i < HISTORY_DIVISIONS; i++) {
                    429:           line->recv[i] /= history_length(i);
                    430:           line->sent[i] /= history_length(i);
                    431:         }
                    432: 
                    433:         /* Don't make a new, sorted screen list if order is frozen
                    434:          */
                    435:         if(!options.freezeorder) {
                    436:             sorted_list_insert(&screen_list, line);
                    437:         } 
                    438:         
                    439:     }
                    440: }
                    441: 
                    442: /*
                    443:  * Zeros all data in the screen hash, but does not remove items.
                    444:  */
                    445: void screen_hash_clear() {
                    446:     hash_node_type* n = NULL;
                    447:     while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
                    448:         host_pair_line* hpl = (host_pair_line*)n->rec;
                    449:         memset(hpl->recv, 0, sizeof(hpl->recv));
                    450:         memset(hpl->sent, 0, sizeof(hpl->sent));
                    451:     }
                    452: }
                    453: 
                    454: void analyse_data() {
                    455:     hash_node_type* n = NULL;
                    456: 
                    457:     if(options.paused == 1) {
                    458:       return;
                    459:     }
                    460: 
                    461:     // Zero totals
                    462:     memset(&totals, 0, sizeof totals);
                    463: 
                    464:     if(options.freezeorder) {
                    465:       screen_hash_clear();
                    466:     }
                    467:     else {
                    468:       screen_list_clear();
                    469:       hash_delete_all(screen_hash);
                    470:     }
                    471: 
                    472:     while(hash_next_item(history, &n) == HASH_STATUS_OK) {
                    473:         history_type* d = (history_type*)n->rec;
                    474:         host_pair_line* screen_line;
                    475:        union {
                    476:            host_pair_line **h_p_l_pp;
                    477:            void **void_pp;
                    478:        } u_screen_line = { &screen_line };
                    479:         addr_pair ap;
                    480:         int i;
                    481:         int tsent, trecv;
                    482:         tsent = trecv = 0;
                    483: 
                    484: 
                    485:         ap = *(addr_pair*)n->key;
                    486: 
                    487:         /* Aggregate hosts, if required */
                    488:         if(options.aggregate_src) {
                    489:             ap.src.s_addr = 0;
                    490:         }
                    491:         if(options.aggregate_dest) {
                    492:             ap.dst.s_addr = 0;
                    493:         }
                    494: 
                    495:         /* Aggregate ports, if required */
                    496:         if(options.showports == OPTION_PORTS_DEST || options.showports == OPTION_PORTS_OFF) {
                    497:             ap.src_port = 0;
                    498:         }
                    499:         if(options.showports == OPTION_PORTS_SRC || options.showports == OPTION_PORTS_OFF) {
                    500:             ap.dst_port = 0;
                    501:         }
                    502:         if(options.showports == OPTION_PORTS_OFF) {
                    503:             ap.protocol = 0;
                    504:         }
                    505: 
                    506:        
                    507:         if(hash_find(screen_hash, &ap, u_screen_line.void_pp) == HASH_STATUS_KEY_NOT_FOUND) {
                    508:             screen_line = xcalloc(1, sizeof *screen_line);
                    509:             hash_insert(screen_hash, &ap, screen_line);
                    510:             screen_line->ap = ap;
                    511:         }
                    512:         
                    513:        screen_line->total_sent += d->total_sent;
                    514:        screen_line->total_recv += d->total_recv;
                    515: 
                    516:         for(i = 0; i < HISTORY_LENGTH; i++) {
                    517:             int j;
                    518:             int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
                    519: 
                    520:             for(j = 0; j < HISTORY_DIVISIONS; j++) {
                    521:                 if(i < history_divs[j]) {
                    522:                     screen_line->recv[j] += d->recv[ii];
                    523:                     screen_line->sent[j] += d->sent[ii];
                    524:                 }
                    525:             }
                    526:         }
                    527: 
                    528:     }
                    529: 
                    530:     make_screen_list();
                    531: 
                    532:     
                    533:     calculate_totals();
                    534: 
                    535: }
                    536: 
                    537: void sprint_host(char * line, struct in_addr* addr, unsigned int port, unsigned int protocol, int L) {
                    538:     char hostname[HOSTNAME_LENGTH];
                    539:     char service[HOSTNAME_LENGTH];
                    540:     char* s_name;
                    541:     union {
                    542:         char **ch_pp;
                    543:         void **void_pp;
                    544:     } u_s_name = { &s_name };
                    545: 
                    546:     ip_service skey;
                    547:     int left;
                    548:     if(addr->s_addr == 0) {
                    549:         sprintf(hostname, " * ");
                    550:     }
                    551:     else {
                    552:         if (options.dnsresolution)
                    553:             resolve(addr, hostname, L);
                    554:         else
                    555:             strcpy(hostname, inet_ntoa(*addr));
                    556:     }
                    557:     left = strlen(hostname);
                    558: 
                    559:     if(port != 0) {
                    560:       skey.port = port;
                    561:       skey.protocol = protocol;
                    562:       if(options.portresolution && hash_find(service_hash, &skey, u_s_name.void_pp) == HASH_STATUS_OK) {
                    563:         snprintf(service, HOSTNAME_LENGTH, ":%s", s_name);
                    564:       }
                    565:       else {
                    566:         snprintf(service, HOSTNAME_LENGTH, ":%d", port);
                    567:       }
                    568:     }
                    569:     else {
                    570:       service[0] = '\0';
                    571:     }
                    572: 
                    573: 
                    574:     sprintf(line, "%-*s", L, hostname);
                    575:     if(left > (L - strlen(service))) {
                    576:         left = L - strlen(service);
                    577:         if(left < 0) {
                    578:            left = 0;
                    579:         }
                    580:     }
                    581:     sprintf(line + left, "%-*s", L-left, service);
                    582: }
                    583: 
                    584: 
                    585: 
                    586: void ui_print() {
                    587:     sorted_list_node* nn = NULL;
                    588:     char host1[HOSTNAME_LENGTH], host2[HOSTNAME_LENGTH];
                    589:     static char *line;
                    590:     static int lcols;
                    591:     int y = 0;
                    592: 
                    593:     if (dontshowdisplay)
                    594:         return;
                    595: 
                    596:     if (!line || lcols != COLS) {
                    597:         xfree(line);
                    598:         line = calloc(COLS + 1, 1);
                    599:     }
                    600: 
                    601:     /* 
                    602:      * erase() is faster than clear().  Dunno why we switched to 
                    603:      * clear() -pdw 24/10/02
                    604:      */
                    605:     erase();
                    606: 
                    607:     draw_bar_scale(&y);
                    608: 
                    609:     if(options.showhelp) {
                    610:       mvaddstr(y,0,HELP_MESSAGE);
                    611:     }
                    612:     else {
                    613:       int i = 0;
                    614: 
                    615:       while(i < options.screen_offset && ((nn = sorted_list_next_item(&screen_list, nn)) != NULL)) {
                    616:         i++;
                    617:       }
                    618: 
                    619:       /* Screen layout: we have 2 * HISTORY_DIVISIONS 6-character wide history
                    620:        * items, and so can use COLS - 12 * HISTORY_DIVISIONS to print the two
                    621:        * host names. */
                    622: 
                    623:       if(i == 0 || nn != NULL) {
                    624:         while((y < LINES - 5) && ((nn = sorted_list_next_item(&screen_list, nn)) != NULL)) {
                    625:             int x = 0, L;
                    626: 
                    627: 
                    628:             host_pair_line* screen_line = (host_pair_line*)nn->data;
                    629: 
                    630:             if(y < LINES - 5) {
                    631:                 L = (COLS - 8 * HISTORY_DIVISIONS - 4) / 2;
                    632:                 if(options.show_totals) {
                    633:                     L -= 4;    
                    634:                 }
                    635:                 if(L > HOSTNAME_LENGTH) {
                    636:                     L = HOSTNAME_LENGTH;
                    637:                 }
                    638: 
                    639:                 sprint_host(host1, &(screen_line->ap.src), screen_line->ap.src_port, screen_line->ap.protocol, L);
                    640:                 sprint_host(host2, &(screen_line->ap.dst), screen_line->ap.dst_port, screen_line->ap.protocol, L);
                    641:                 if(!screen_filter_match(host1) && !screen_filter_match(host2)) {
                    642:                   continue;
                    643:                 }
                    644: 
                    645:                 mvaddstr(y, x, host1);
                    646:                 x += L;
                    647: 
                    648:                 switch(options.linedisplay) {
                    649:                   case OPTION_LINEDISPLAY_TWO_LINE:
                    650:                     mvaddstr(y, x, " => ");
                    651:                     mvaddstr(y+1, x, " <= ");
                    652:                     break;
                    653:                   case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
                    654:                     mvaddstr(y, x, "<=> ");
                    655:                     break;
                    656:                   case OPTION_LINEDISPLAY_ONE_LINE_SENT:
                    657:                     mvaddstr(y, x, " => ");
                    658:                     break;
                    659:                   case OPTION_LINEDISPLAY_ONE_LINE_RECV:
                    660:                     mvaddstr(y, x, " <= ");
                    661:                     break;
                    662:                 }
                    663: 
                    664:                 x += 4;
                    665: 
                    666: 
                    667:                 mvaddstr(y, x, host2);
                    668:                 
                    669:                 if(options.show_totals) {
                    670:                     draw_line_total(screen_line->total_sent, screen_line->total_recv, y, COLS - 8 * (HISTORY_DIVISIONS + 1), options.linedisplay, 1);
                    671:                 }
                    672: 
                    673:                 draw_line_totals(y, screen_line, options.linedisplay);
                    674: 
                    675:             }
                    676:             if(options.linedisplay == OPTION_LINEDISPLAY_TWO_LINE) {
                    677:               y += 2;
                    678:             }
                    679:             else {
                    680:               y += 1;
                    681:             }
                    682:         }
                    683:       }
                    684:     }
                    685: 
                    686: 
                    687:     y = LINES - 3;
                    688:     
                    689:     mvhline(y-1, 0, 0, COLS);
                    690: 
                    691:     mvaddstr(y, 0, "TX: ");
                    692:     mvaddstr(y+1, 0, "RX: ");
                    693:     mvaddstr(y+2, 0, "TOTAL: ");
                    694: 
                    695:     /* Cummulative totals */
                    696:     mvaddstr(y, 16, "cumm: ");
                    697: 
                    698:     readable_size(history_totals.total_sent, line, 10, 1024, 1);
                    699:     mvaddstr(y, 22, line);
                    700: 
                    701:     readable_size(history_totals.total_recv, line, 10, 1024, 1);
                    702:     mvaddstr(y+1, 22, line);
                    703: 
                    704:     readable_size(history_totals.total_recv + history_totals.total_sent, line, 10, 1024, 1);
                    705:     mvaddstr(y+2, 22, line);
                    706: 
                    707:     /* peak traffic */
                    708:     mvaddstr(y, 32, "peak: ");
                    709: 
                    710:     readable_size(peaksent / RESOLUTION, line, 10, 1024, options.bandwidth_in_bytes);
                    711:     mvaddstr(y, 39, line);
                    712: 
                    713:     readable_size(peakrecv / RESOLUTION, line, 10, 1024, options.bandwidth_in_bytes);
                    714:     mvaddstr(y+1, 39, line);
                    715: 
                    716:     readable_size(peaktotal / RESOLUTION, line, 10, 1024, options.bandwidth_in_bytes);
                    717:     mvaddstr(y+2, 39, line);
                    718: 
                    719:     mvaddstr(y, COLS - 8 * HISTORY_DIVISIONS - 8, "rates:");
                    720: 
                    721:     draw_totals(&totals);
                    722: 
                    723: 
                    724:     if(showhelphint) {
                    725:       mvaddstr(0, 0, " ");
                    726:       mvaddstr(0, 1, helpmsg);
                    727:       mvaddstr(0, 1 + strlen(helpmsg), " ");
                    728:       mvchgat(0, 0, strlen(helpmsg) + 2, A_REVERSE, 0, NULL);
                    729:     }
                    730:     move(LINES - 1, COLS - 1);
                    731:     
                    732:     refresh();
                    733: 
                    734:     /* Bar chart auto scale */
                    735:     if (wantbiggerrate && options.max_bandwidth == 0) {
                    736:         ++rateidx;
                    737:         wantbiggerrate = 0;
                    738:     }
                    739: }
                    740: 
                    741: void ui_tick(int print) {
                    742:   if(print) {
                    743:     ui_print();
                    744:   }
                    745:   else if(showhelphint && (time(NULL) - helptimer > HELP_TIME) && !persistenthelp) {
                    746:     showhelphint = 0;
                    747:     ui_print();
                    748:   }
                    749: }
                    750: 
                    751: void ui_curses_init() {
                    752:     (void) initscr();      /* initialize the curses library */
                    753:     keypad(stdscr, TRUE);  /* enable keyboard mapping */
                    754:     (void) nonl();         /* tell curses not to do NL->CR/NL on output */
                    755:     (void) cbreak();       /* take input chars one at a time, no wait for \n */
                    756:     (void) noecho();       /* don't echo input */
                    757:     halfdelay(2);
                    758: }
                    759: 
                    760: void showhelp(const char * s) {
                    761:   strncpy(helpmsg, s, HELP_MSG_SIZE);
                    762:   showhelphint = 1;
                    763:   helptimer = time(NULL);
                    764:   persistenthelp = 0;
                    765:   tick(1);
                    766: }
                    767: 
                    768: void ui_init() {
                    769:     char msg[20];
                    770:     ui_curses_init();
                    771:     
                    772:     erase();
                    773: 
                    774:     screen_list_init();
                    775:     screen_hash = addr_hash_create();
                    776: 
                    777:     service_hash = serv_hash_create();
                    778:     serv_hash_initialise(service_hash);
                    779: 
                    780:     snprintf(msg,20,"Listening on %s",options.interface);
                    781:     showhelp(msg);
                    782: 
                    783: 
                    784: }
                    785: 
                    786: 
                    787: void showportstatus() {
                    788:   if(options.showports == OPTION_PORTS_ON) {
                    789:     showhelp("Port display ON");
                    790:   }
                    791:   else if(options.showports == OPTION_PORTS_OFF) {
                    792:     showhelp("Port display OFF");
                    793:   }
                    794:   else if(options.showports == OPTION_PORTS_DEST) {
                    795:     showhelp("Port display DEST");
                    796:   }
                    797:   else if(options.showports == OPTION_PORTS_SRC) {
                    798:     showhelp("Port display SOURCE");
                    799:   }
                    800: }
                    801: 
                    802: 
                    803: void ui_loop() {
                    804:     /* in edline.c */
                    805:     char *edline(int linenum, const char *prompt, const char *initial);
                    806:     /* in iftop.c */
                    807:     char *set_filter_code(const char *filter);
                    808: 
                    809:     extern sig_atomic_t foad;
                    810: 
                    811:     while(foad == 0) {
                    812:         int i;
                    813:         i = getch();
                    814:         switch (i) {
                    815:             case 'q':
                    816:                 foad = 1;
                    817:                 break;
                    818: 
                    819:             case 'n':
                    820:                 if(options.dnsresolution) {
                    821:                     options.dnsresolution = 0;
                    822:                     showhelp("DNS resolution off");
                    823:                 }
                    824:                 else {
                    825:                     options.dnsresolution = 1;
                    826:                     showhelp("DNS resolution on");
                    827:                 }
                    828:                 tick(1);
                    829:                 break;
                    830: 
                    831:             case 'N':
                    832:                 if(options.portresolution) {
                    833:                     options.portresolution = 0;
                    834:                     showhelp("Port resolution off");
                    835:                 }
                    836:                 else {
                    837:                     options.portresolution = 1;
                    838:                     showhelp("Port resolution on");
                    839:                 }
                    840:                 tick(1);
                    841:                 break;
                    842: 
                    843:             case 'h':
                    844:             case '?':
                    845:                 options.showhelp = !options.showhelp;
                    846:                 tick(1);
                    847:                 break;
                    848: 
                    849:             case 'b':
                    850:                 if(options.showbars) {
                    851:                     options.showbars = 0;
                    852:                     showhelp("Bars off");
                    853:                 }
                    854:                 else {
                    855:                     options.showbars = 1;
                    856:                     showhelp("Bars on");
                    857:                 }
                    858:                 tick(1);
                    859:                 break;
                    860: 
                    861:             case 'B':
                    862:                 options.bar_interval = (options.bar_interval + 1) % 3;
                    863:                 if(options.bar_interval == 0) {
                    864:                     showhelp("Bars show 2s average");
                    865:                 }
                    866:                 else if(options.bar_interval == 1) { 
                    867:                     showhelp("Bars show 10s average");
                    868:                 }
                    869:                 else {
                    870:                     showhelp("Bars show 40s average");
                    871:                 }
                    872:                 ui_print();
                    873:                 break;
                    874:             case 's':
                    875:                 if(options.aggregate_src) {
                    876:                     options.aggregate_src = 0;
                    877:                     showhelp("Show source host");
                    878:                 }
                    879:                 else {
                    880:                     options.aggregate_src = 1;
                    881:                     showhelp("Hide source host");
                    882:                 }
                    883:                 break;
                    884:             case 'd':
                    885:                 if(options.aggregate_dest) {
                    886:                     options.aggregate_dest = 0;
                    887:                     showhelp("Show dest host");
                    888:                 }
                    889:                 else {
                    890:                     options.aggregate_dest = 1;
                    891:                     showhelp("Hide dest host");
                    892:                 }
                    893:                 break;
                    894:             case 'S':
                    895:                 /* Show source ports */
                    896:                 if(options.showports == OPTION_PORTS_OFF) {
                    897:                   options.showports = OPTION_PORTS_SRC;
                    898:                 }
                    899:                 else if(options.showports == OPTION_PORTS_DEST) {
                    900:                   options.showports = OPTION_PORTS_ON;
                    901:                 }
                    902:                 else if(options.showports == OPTION_PORTS_ON) {
                    903:                   options.showports = OPTION_PORTS_DEST;
                    904:                 }
                    905:                 else {
                    906:                   options.showports = OPTION_PORTS_OFF;
                    907:                 }
                    908:                 showportstatus();
                    909:                 break;
                    910:             case 'D':
                    911:                 /* Show dest ports */
                    912:                 if(options.showports == OPTION_PORTS_OFF) {
                    913:                   options.showports = OPTION_PORTS_DEST;
                    914:                 }
                    915:                 else if(options.showports == OPTION_PORTS_SRC) {
                    916:                   options.showports = OPTION_PORTS_ON;
                    917:                 }
                    918:                 else if(options.showports == OPTION_PORTS_ON) {
                    919:                   options.showports = OPTION_PORTS_SRC;
                    920:                 }
                    921:                 else {
                    922:                   options.showports = OPTION_PORTS_OFF;
                    923:                 }
                    924:                 showportstatus();
                    925:                 break;
                    926:             case 'p':
                    927:                 options.showports = 
                    928:                   (options.showports == OPTION_PORTS_OFF)
                    929:                   ? OPTION_PORTS_ON
                    930:                   : OPTION_PORTS_OFF;
                    931:                 showportstatus();
                    932:                 // Don't tick here, otherwise we get a bogus display
                    933:                 break;
                    934:             case 'P':
                    935:                 if(options.paused) {
                    936:                     options.paused = 0;
                    937:                     showhelp("Display unpaused");
                    938:                 }
                    939:                 else {
                    940:                     options.paused = 1;
                    941:                     showhelp("Display paused");
                    942:                     persistenthelp = 1;
                    943:                 }
                    944:                 break;
                    945:             case 'o':
                    946:                 if(options.freezeorder) {
                    947:                     options.freezeorder = 0;
                    948:                     showhelp("Order unfrozen");
                    949:                 }
                    950:                 else {
                    951:                     options.freezeorder = 1;
                    952:                     showhelp("Order frozen");
                    953:                     persistenthelp = 1;
                    954:                 }
                    955:                 break;
                    956:             case '1':
                    957:                 options.sort = OPTION_SORT_DIV1;
                    958:                 showhelp("Sort by col 1");
                    959:                 break;
                    960:             case '2':
                    961:                 options.sort = OPTION_SORT_DIV2;
                    962:                 showhelp("Sort by col 2");
                    963:                 break;
                    964:             case '3':
                    965:                 options.sort = OPTION_SORT_DIV3;
                    966:                 showhelp("Sort by col 3");
                    967:                 break;
                    968:             case '<':
                    969:                 options.sort = OPTION_SORT_SRC;
                    970:                 showhelp("Sort by source");
                    971:                 break;
                    972:             case '>':
                    973:                 options.sort = OPTION_SORT_DEST;
                    974:                 showhelp("Sort by dest");
                    975:                 break;
                    976:             case 'j':
                    977:                 options.screen_offset++;
                    978:                 ui_print();
                    979:                 break;
                    980:             case 'k':
                    981:                 if(options.screen_offset > 0) {
                    982:                   options.screen_offset--;
                    983:                   ui_print();
                    984:                 }
                    985:                 break;
                    986:             case 't':
                    987:                 options.linedisplay = (options.linedisplay + 1) % 4;
                    988:                 switch(options.linedisplay) {
                    989:                   case OPTION_LINEDISPLAY_TWO_LINE:
                    990:                     showhelp("Two lines per host");
                    991:                     break;
                    992:                   case OPTION_LINEDISPLAY_ONE_LINE_SENT:
                    993:                     showhelp("Sent traffic only");
                    994:                     break;
                    995:                   case OPTION_LINEDISPLAY_ONE_LINE_RECV:
                    996:                     showhelp("Received traffic only");
                    997:                     break;
                    998:                   case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
                    999:                     showhelp("One line per host");
                   1000:                     break;
                   1001:                 }
                   1002:                 ui_print();
                   1003:                 break;
                   1004:             case 'f': {
                   1005:                 char *s;
                   1006:                 dontshowdisplay = 1;
                   1007:                 if ((s = edline(0, "Net filter", options.filtercode))) {
                   1008:                     char *m;
                   1009:                     if (s[strspn(s, " \t")] == 0) {
                   1010:                         /* Empty filter; set to NULL. */
                   1011:                         xfree(s);
                   1012:                         s = NULL;
                   1013:                     }
                   1014:                     if (!(m = set_filter_code(s))) {
                   1015:                         xfree(options.filtercode);
                   1016:                         options.filtercode = s;
                   1017:                         /* -lpcap will write junk to stderr; we do our best to
                   1018:                          * erase it.... */
                   1019:                         move(COLS - 1, LINES - 1);
                   1020:                         wrefresh(curscr);
                   1021:                         showhelp("Installed new filter");
                   1022:                     } else {
                   1023:                         showhelp(m);
                   1024:                         xfree(s);
                   1025:                     }
                   1026:                 }
                   1027:                 dontshowdisplay = 0;
                   1028:                 ui_print();
                   1029:                 break;
                   1030:             }
                   1031:             case 'l': {
                   1032: #ifdef HAVE_REGCOMP
                   1033:                 char *s;
                   1034:                 dontshowdisplay = 1;
                   1035:                 if ((s = edline(0, "Screen filter", options.screenfilter))) {
                   1036:                     if(!screen_filter_set(s)) {
                   1037:                         showhelp("Invalid regexp");
                   1038:                     }
                   1039:                 }
                   1040:                 dontshowdisplay = 0;
                   1041:                 ui_print();
                   1042: #else
                   1043:                 showhelp("Sorry, screen filters not supported on this platform")
                   1044: #endif
                   1045:                 break;
                   1046:             }
                   1047:             case '!': {
                   1048: #ifndef NO_SYSTEM
                   1049:                 char *s;
                   1050:                 dontshowdisplay = 1;
                   1051:                 if ((s = edline(0, "Command", "")) && s[strspn(s, " \t")]) {
                   1052:                     int i, dowait = 0;
                   1053:                     erase();
                   1054:                     refresh();
                   1055:                     endwin();
                   1056:                     errno = 0;
                   1057:                     i = system(s);
                   1058:                     if (i == -1 || (i == 127 && errno != 0)) {
                   1059:                         fprintf(stderr, "system: %s: %s\n", s, strerror(errno));
                   1060:                         dowait = 1;
                   1061:                     } else if (i != 0) {
                   1062:                         if (WIFEXITED(i))
                   1063:                             fprintf(stderr, "%s: exited with code %d\n", s, WEXITSTATUS(i));
                   1064:                         else if (WIFSIGNALED(i))
                   1065:                             fprintf(stderr, "%s: killed by signal %d\n", s, WTERMSIG(i));
                   1066:                         dowait = 1;
                   1067:                     }
                   1068:                     ui_curses_init();
                   1069:                     if (dowait) {
                   1070:                         fprintf(stderr, "Press any key....");
                   1071:                         while (getch() == ERR);
                   1072:                     }
                   1073:                     erase();
                   1074:                     xfree(s);
                   1075:                 }
                   1076:                 dontshowdisplay = 0;
                   1077: #else
                   1078:                 showhelp("Sorry, subshells have been disabled.");
                   1079: #endif
                   1080:                 break;
                   1081:             }
                   1082:             case 'T':
                   1083:                 options.show_totals = !options.show_totals;
                   1084:                 if(options.show_totals) {
                   1085:                     showhelp("Show cummulative totals");
                   1086:                 }
                   1087:                 else {
                   1088:                     showhelp("Hide cummulative totals");
                   1089:                 }
                   1090:                 ui_print();
                   1091:                 break;
                   1092:             case 'L':
                   1093:                 options.log_scale = !options.log_scale;
                   1094:                 showhelp(options.log_scale ? "Logarithmic scale" : "Linear scale");
                   1095:                 ui_print();
                   1096:                 break;
                   1097:             case KEY_CLEAR:
                   1098:             case 12:    /* ^L */
                   1099:                 wrefresh(curscr);
                   1100:                 break;
                   1101:             case ERR:
                   1102:                 break;
                   1103:             default:
                   1104:                 showhelp("Press H or ? for help");
                   1105:                 break;
                   1106:         }
                   1107:         tick(0);
                   1108:     }
                   1109: }
                   1110: 
                   1111: void ui_finish() {
                   1112:     endwin();
                   1113: }

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