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>