Annotation of embedaddon/iftop/ui.c, revision 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>