23 #include "addr_hash.h"
24 #include "serv_hash.h"
27 #include "sorted_list.h"
29 #include "screenfilter.h"
31 #include "ui_common.h"
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 cumulative 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"\
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"\
54 "iftop, version " PACKAGE_VERSION
57 extern hash_type* history;
58 extern int history_pos;
59 extern int history_len;
61 extern options_t options ;
65 #define HELP_MSG_SIZE 80
67 int persistenthelp = 0;
69 char helpmsg[HELP_MSG_SIZE];
70 int dontshowdisplay = 0;
72 /* Barchart scales. */
76 { 64000, 10 }, /* 64 kbit/s */
79 { 1000000, 10 }, /* 1 Mbit/s */
82 { 1000000000, 100 } /* 1 Gbit/s */
84 static int rateidx = 0, wantbiggerrate;
86 static int rateidx_init = 0;
88 static int get_bar_interval(float bandwidth) {
90 if(bandwidth > 100000000) {
96 static float get_max_bandwidth() {
98 if(options.max_bandwidth > 0) {
99 max = options.max_bandwidth;
102 max = scale[rateidx].max;
108 static int get_bar_length(const int rate) {
112 if (rate > scale[rateidx].max) {
115 while(rate > scale[rateidx_init++].max) {
117 rateidx = rateidx_init;
120 if(options.log_scale) {
121 l = log(rate) / log(get_max_bandwidth());
124 l = rate / get_max_bandwidth();
129 static void draw_bar_scale(int* y) {
132 max = get_max_bandwidth();
133 interval = get_bar_interval(max);
134 if(options.showbars) {
136 /* Draw bar graph scale on top of the window. */
139 mvhline(*y + 1, 0, 0, COLS);
142 if(options.log_scale) {
151 /* for (i = 1.25; i * 8 <= max; i *= interval) { */
155 /* This 1024 vs 1000 stuff is just plain evil */
156 readable_size(i, s, sizeof s, options.log_scale ? 1000 : 1024, options.bandwidth_unit);
157 p = s + strspn(s, " ");
158 x = get_bar_length(i * 8);
159 mvaddch(*y + 1, x, ACS_BTEE);
160 if (x + strlen(p) >= COLS)
161 x = COLS - strlen(p);
164 if(options.log_scale) {
171 mvaddch(*y + 1, 0, ACS_LLCORNER);
175 mvhline(*y, 0, 0, COLS);
180 void draw_line_total(float sent, float recv, int y, int x, option_linedisplay_t linedisplay, option_bw_unit_t unit) {
183 switch(linedisplay) {
184 case OPTION_LINEDISPLAY_TWO_LINE:
185 draw_line_total(sent, recv, y, x, OPTION_LINEDISPLAY_ONE_LINE_SENT, unit);
186 draw_line_total(sent, recv, y+1, x, OPTION_LINEDISPLAY_ONE_LINE_RECV, unit);
188 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
191 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
194 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
198 if(linedisplay != OPTION_LINEDISPLAY_TWO_LINE) {
199 readable_size(n, buf, 10, 1024, unit);
204 void draw_bar(float n, int y) {
206 mvchgat(y, 0, -1, A_NORMAL, 0, NULL);
207 L = get_bar_length(8 * n);
209 mvchgat(y, 0, L + 1, A_REVERSE, 0, NULL);
212 void draw_line_totals(int y, host_pair_line* line, option_linedisplay_t linedisplay) {
214 int x = (COLS - 8 * HISTORY_DIVISIONS);
216 for(j = 0; j < HISTORY_DIVISIONS; j++) {
217 draw_line_total(line->sent[j], line->recv[j], y, x, linedisplay, options.bandwidth_unit);
221 if(options.showbars) {
222 switch(linedisplay) {
223 case OPTION_LINEDISPLAY_TWO_LINE:
224 draw_bar(line->sent[options.bar_interval],y);
225 draw_bar(line->recv[options.bar_interval],y+1);
227 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
228 draw_bar(line->sent[options.bar_interval],y);
230 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
231 draw_bar(line->recv[options.bar_interval],y);
233 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
234 draw_bar(line->recv[options.bar_interval] + line->sent[options.bar_interval],y);
240 void draw_totals(host_pair_line* totals) {
245 int x = (COLS - 8 * HISTORY_DIVISIONS);
247 draw_line_totals(y, totals, OPTION_LINEDISPLAY_TWO_LINE);
249 for(j = 0; j < HISTORY_DIVISIONS; j++) {
250 readable_size((totals->sent[j] + totals->recv[j]) , buf, 10, 1024, options.bandwidth_unit);
256 extern history_type history_totals;
260 sorted_list_node* nn = NULL;
261 char host1[HOSTNAME_LENGTH], host2[HOSTNAME_LENGTH];
265 option_bw_unit_t cumunit;
270 if (!line || lcols != COLS) {
272 line = calloc(COLS + 1, 1);
276 * erase() is faster than clear(). Dunno why we switched to
277 * clear() -pdw 24/10/02
283 if(options.showhelp) {
284 mvaddstr(y,0,HELP_MESSAGE);
289 while(i < options.screen_offset && ((nn = sorted_list_next_item(&screen_list, nn)) != NULL)) {
293 /* Screen layout: we have 2 * HISTORY_DIVISIONS 6-character wide history
294 * items, and so can use COLS - 12 * HISTORY_DIVISIONS to print the two
297 if(i == 0 || nn != NULL) {
298 while((y < LINES - 5) && ((nn = sorted_list_next_item(&screen_list, nn)) != NULL)) {
302 host_pair_line* screen_line = (host_pair_line*)nn->data;
305 L = (COLS - 8 * HISTORY_DIVISIONS - 4) / 2;
306 if(options.show_totals) {
309 if(L > HOSTNAME_LENGTH) {
313 sprint_host(host1, screen_line->ap.af,
314 &(screen_line->ap.src6),
315 screen_line->ap.src_port,
316 screen_line->ap.protocol, L, options.aggregate_src);
317 sprint_host(host2, screen_line->ap.af,
318 &(screen_line->ap.dst6),
319 screen_line->ap.dst_port,
320 screen_line->ap.protocol, L, options.aggregate_dest);
322 if(!screen_filter_match(host1) && !screen_filter_match(host2)) {
326 mvaddstr(y, x, host1);
329 switch(options.linedisplay) {
330 case OPTION_LINEDISPLAY_TWO_LINE:
331 mvaddstr(y, x, " => ");
332 mvaddstr(y+1, x, " <= ");
334 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
335 mvaddstr(y, x, "<=> ");
337 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
338 mvaddstr(y, x, " => ");
340 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
341 mvaddstr(y, x, " <= ");
348 mvaddstr(y, x, host2);
350 if(options.show_totals) {
351 draw_line_total(screen_line->total_sent, screen_line->total_recv, y, COLS - 8 * (HISTORY_DIVISIONS + 1), options.linedisplay, 1);
354 draw_line_totals(y, screen_line, options.linedisplay);
357 if(options.linedisplay == OPTION_LINEDISPLAY_TWO_LINE) {
370 mvhline(y-1, 0, 0, COLS);
372 mvaddstr(y, 0, "TX: ");
373 mvaddstr(y+1, 0, "RX: ");
374 mvaddstr(y+2, 0, "TOTAL: ");
376 /* Cummulative totals */
377 mvaddstr(y, 16, "cum: ");
379 /* Previous versions of iftop always displayed totals in bytes, even when
380 use-bytes = false. Stay compatible when the default unit hasn't been
382 cumunit = options.bandwidth_unit;
383 if (cumunit == OPTION_BW_BITS)
384 cumunit = OPTION_BW_BYTES;
385 readable_size(history_totals.total_sent, line, 10, 1024, cumunit);
386 mvaddstr(y, 22, line);
388 readable_size(history_totals.total_recv, line, 10, 1024, cumunit);
389 mvaddstr(y+1, 22, line);
391 readable_size(history_totals.total_recv + history_totals.total_sent, line, 10, 1024, cumunit);
392 mvaddstr(y+2, 22, line);
395 mvaddstr(y, 32, "peak: ");
397 readable_size(peaksent / RESOLUTION, line, 10, 1024, options.bandwidth_unit);
398 mvaddstr(y, 39, line);
400 readable_size(peakrecv / RESOLUTION, line, 10, 1024, options.bandwidth_unit);
401 mvaddstr(y+1, 39, line);
404 mvaddstr(y+2, 32, "lost: ");
405 readable_size(history_totals.lost_packets, line, 10, 1000, OPTION_BW_PKTS);
406 mvaddstr(y+2, 39, line);
408 mvaddstr(y, COLS - 8 * HISTORY_DIVISIONS - 8, "rates:");
410 draw_totals(&totals);
415 mvaddstr(0, 1, helpmsg);
416 mvaddstr(0, 1 + strlen(helpmsg), " ");
417 mvchgat(0, 0, strlen(helpmsg) + 2, A_REVERSE, 0, NULL);
419 move(LINES - 1, COLS - 1);
423 /* Bar chart auto scale */
424 if (wantbiggerrate && options.max_bandwidth == 0) {
430 void ui_tick(int print) {
434 else if(showhelphint && (time(NULL) - helptimer > HELP_TIME) && !persistenthelp) {
440 void ui_curses_init() {
441 (void) initscr(); /* initialize the curses library */
442 keypad(stdscr, TRUE); /* enable keyboard mapping */
443 (void) nonl(); /* tell curses not to do NL->CR/NL on output */
444 (void) cbreak(); /* take input chars one at a time, no wait for \n */
445 (void) noecho(); /* don't echo input */
446 (void) curs_set(0); /* hide blinking cursor in ui */
450 void showhelp(const char * s) {
451 strncpy(helpmsg, s, HELP_MSG_SIZE);
453 helptimer = time(NULL);
465 screen_hash = addr_hash_create();
467 service_hash = serv_hash_create();
468 serv_hash_initialise(service_hash);
470 snprintf(msg,20,"Listening on %s",options.interface);
477 void showportstatus() {
478 if(options.showports == OPTION_PORTS_ON) {
479 showhelp("Port display ON");
481 else if(options.showports == OPTION_PORTS_OFF) {
482 showhelp("Port display OFF");
484 else if(options.showports == OPTION_PORTS_DEST) {
485 showhelp("Port display DEST");
487 else if(options.showports == OPTION_PORTS_SRC) {
488 showhelp("Port display SOURCE");
495 char *edline(int linenum, const char *prompt, const char *initial);
497 char *set_filter_code(const char *filter);
499 extern sig_atomic_t foad;
510 if(options.dnsresolution) {
511 options.dnsresolution = 0;
512 showhelp("DNS resolution off");
515 options.dnsresolution = 1;
516 showhelp("DNS resolution on");
522 if(options.portresolution) {
523 options.portresolution = 0;
524 showhelp("Port resolution off");
527 options.portresolution = 1;
528 showhelp("Port resolution on");
535 options.showhelp = !options.showhelp;
540 if(options.showbars) {
541 options.showbars = 0;
542 showhelp("Bars off");
545 options.showbars = 1;
552 options.bar_interval = (options.bar_interval + 1) % 3;
553 if(options.bar_interval == 0) {
554 showhelp("Bars show 2s average");
556 else if(options.bar_interval == 1) {
557 showhelp("Bars show 10s average");
560 showhelp("Bars show 40s average");
565 if(options.aggregate_src) {
566 options.aggregate_src = 0;
567 showhelp("Show source host");
570 options.aggregate_src = 1;
571 showhelp("Hide source host");
575 if(options.aggregate_dest) {
576 options.aggregate_dest = 0;
577 showhelp("Show dest host");
580 options.aggregate_dest = 1;
581 showhelp("Hide dest host");
585 /* Show source ports */
586 if(options.showports == OPTION_PORTS_OFF) {
587 options.showports = OPTION_PORTS_SRC;
589 else if(options.showports == OPTION_PORTS_DEST) {
590 options.showports = OPTION_PORTS_ON;
592 else if(options.showports == OPTION_PORTS_ON) {
593 options.showports = OPTION_PORTS_DEST;
596 options.showports = OPTION_PORTS_OFF;
601 /* Show dest ports */
602 if(options.showports == OPTION_PORTS_OFF) {
603 options.showports = OPTION_PORTS_DEST;
605 else if(options.showports == OPTION_PORTS_SRC) {
606 options.showports = OPTION_PORTS_ON;
608 else if(options.showports == OPTION_PORTS_ON) {
609 options.showports = OPTION_PORTS_SRC;
612 options.showports = OPTION_PORTS_OFF;
618 (options.showports == OPTION_PORTS_OFF)
622 // Don't tick here, otherwise we get a bogus display
627 showhelp("Display unpaused");
631 showhelp("Display paused");
636 if(options.freezeorder) {
637 options.freezeorder = 0;
638 showhelp("Order unfrozen");
641 options.freezeorder = 1;
642 showhelp("Order frozen");
647 options.sort = OPTION_SORT_DIV1;
648 showhelp("Sort by col 1");
651 options.sort = OPTION_SORT_DIV2;
652 showhelp("Sort by col 2");
655 options.sort = OPTION_SORT_DIV3;
656 showhelp("Sort by col 3");
659 options.sort = OPTION_SORT_SRC;
660 showhelp("Sort by source");
663 options.sort = OPTION_SORT_DEST;
664 showhelp("Sort by dest");
667 options.screen_offset++;
671 if(options.screen_offset > 0) {
672 options.screen_offset--;
677 options.linedisplay = (options.linedisplay + 1) % 4;
678 switch(options.linedisplay) {
679 case OPTION_LINEDISPLAY_TWO_LINE:
680 showhelp("Two lines per host");
682 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
683 showhelp("Sent traffic only");
685 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
686 showhelp("Received traffic only");
688 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
689 showhelp("One line per host");
697 if ((s = edline(0, "Net filter", options.filtercode))) {
699 if (s[strspn(s, " \t")] == 0) {
700 /* Empty filter; set to NULL. */
704 if (!(m = set_filter_code(s))) {
705 xfree(options.filtercode);
706 options.filtercode = s;
707 /* -lpcap will write junk to stderr; we do our best to
709 move(COLS - 1, LINES - 1);
711 showhelp("Installed new filter");
725 if ((s = edline(0, "Screen filter", options.screenfilter))) {
726 if(!screen_filter_set(s)) {
727 showhelp("Invalid regexp");
733 showhelp("Sorry, screen filters not supported on this platform")
738 #ifdef ALLOW_SUBSHELL
741 if ((s = edline(0, "Command", "")) && s[strspn(s, " \t")]) {
748 if (i == -1 || (i == 127 && errno != 0)) {
749 fprintf(stderr, "system: %s: %s\n", s, strerror(errno));
753 fprintf(stderr, "%s: exited with code %d\n", s, WEXITSTATUS(i));
754 else if (WIFSIGNALED(i))
755 fprintf(stderr, "%s: killed by signal %d\n", s, WTERMSIG(i));
760 fprintf(stderr, "Press any key....");
761 while (getch() == ERR);
768 showhelp("Sorry, subshells have been disabled.");
773 options.show_totals = !options.show_totals;
774 if(options.show_totals) {
775 showhelp("Show cumulative totals");
778 showhelp("Hide cumulative totals");
783 options.log_scale = !options.log_scale;
784 showhelp(options.log_scale ? "Logarithmic scale" : "Linear scale");
794 showhelp("Press H or ? for help");