diff options
author | pdw <> | 2014-01-01 14:37:31 +0000 |
---|---|---|
committer | pdw <> | 2014-01-01 14:37:31 +0000 |
commit | a9663192567697bfb217704cd67c34fd32a68389 (patch) | |
tree | 519a7c9cbc7d65b17d3c0a017f0de404be448326 | |
parent | 59cf360690c99ad5149305ce3600151fa0f1483b (diff) | |
download | iftop-a9663192567697bfb217704cd67c34fd32a68389.zip |
Patch for text output mode by originally by Patrik Bless, updated by Roman Hoog
Antink <rha@open.ch>
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | cfgfile.c | 3 | ||||
-rw-r--r-- | hash.c | 10 | ||||
-rw-r--r-- | iftop.c | 50 | ||||
-rw-r--r-- | options.c | 38 | ||||
-rw-r--r-- | options.h | 3 | ||||
-rw-r--r-- | ui.c | 368 | ||||
-rw-r--r-- | ui_common.c | 375 | ||||
-rw-r--r-- | ui_common.h | 48 |
9 files changed, 522 insertions, 377 deletions
diff --git a/Makefile.am b/Makefile.am index 238e358..f28cf32 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,7 @@ sbin_PROGRAMS = iftop iftop_SOURCES = addr_hash.c edline.c hash.c iftop.c ns_hash.c \ options.c resolver.c screenfilter.c serv_hash.c \ - sorted_list.c threadprof.c ui.c util.c \ + sorted_list.c threadprof.c ui_common.c ui.c tui.c util.c \ addrs_ioctl.c addrs_dlpi.c dlcommon.c \ stringmap.c cfgfile.c vector.c @@ -30,7 +30,7 @@ iftop_SOURCES = addr_hash.c edline.c hash.c iftop.c ns_hash.c \ noinst_HEADERS = addr_hash.h ether.h ethertype.h extract.h hash.h iftop.h \ integers.h ip.h llc.h ns_hash.h options.h resolver.h \ screenfilter.h serv_hash.h sll.h sorted_list.h tcp.h \ - threadprof.h token.h ui.h dlcommon.h stringmap.h \ + threadprof.h token.h ui_common.h ui.h tui.h dlcommon.h stringmap.h \ vector.h cfgfile.h ppp.h man_MANS = iftop.8 @@ -39,6 +39,9 @@ char * config_directives[] = { "net-filter6", "link-local", "port-display", + "timed-output", + "no-curses", + "num-lines", NULL }; @@ -76,6 +76,11 @@ hash_status_enum hash_find(hash_type* hash_table, void* key, void **rec) { hash_status_enum hash_next_item(hash_type* hash_table, hash_node_type** ppnode) { int i; + + if (hash_table == 0) { + return HASH_STATUS_KEY_NOT_FOUND; + } + if(*ppnode != NULL) { if((*ppnode)->next != NULL) { *ppnode = (*ppnode)->next; @@ -101,6 +106,11 @@ hash_status_enum hash_next_item(hash_type* hash_table, hash_node_type** ppnode) void hash_delete_all(hash_type* hash_table) { int i; hash_node_type *n, *nn; + + if(hash_table == 0) { + return; + } + for(i = 0; i < hash_table->size; i++) { n = hash_table->table[i]; while(n != NULL) { @@ -32,7 +32,9 @@ #include "iftop.h" #include "addr_hash.h" #include "resolver.h" +#include "ui_common.h" #include "ui.h" +#include "tui.h" #include "options.h" #ifdef DLT_LINUX_SLL #include "sll.h" @@ -65,6 +67,7 @@ extern options_t options; hash_type* history; history_type history_totals; time_t last_timestamp; +time_t first_timestamp; int history_pos = 0; int history_len = 1; pthread_mutex_t tick_mutex; @@ -141,12 +144,27 @@ void tick(int print) { t = time(NULL); if(t - last_timestamp >= RESOLUTION) { analyse_data(); - ui_print(); + if (options.no_curses) { + if (!options.timed_output || options.timed_output && t - first_timestamp >= options.timed_output) { + tui_print(); + if (options.timed_output) { + finish(SIGINT); + } + } + } + else { + ui_print(); + } history_rotate(); last_timestamp = t; } else { - ui_tick(print); + if (options.no_curses) { + tui_tick(print); + } + else { + ui_tick(print); + } } pthread_mutex_unlock(&tick_mutex); @@ -247,6 +265,8 @@ static void handle_ip_packet(struct ip* iptr, int hw_dir) memset(&ap, '\0', sizeof(ap)); + tick(0); + if( (IP_V(iptr) ==4 && options.netfilter == 0) || (IP_V(iptr) == 6 && options.netfilter6 == 0) ) { /* @@ -570,8 +590,6 @@ static void handle_eth_packet(unsigned char* args, const struct pcap_pkthdr* pkt ether_type = ntohs(eptr->ether_type); payload = packet + sizeof(struct ether_header); - tick(0); - if(ether_type == ETHERTYPE_8021Q) { struct vlan_8021q_header* vptr; vptr = (struct vlan_8021q_header*)payload; @@ -784,11 +802,31 @@ int main(int argc, char **argv) { init_history(); - ui_init(); + if (options.no_curses) { + tui_init(); + } + else { + ui_init(); + } pthread_create(&thread, NULL, (void*)&packet_loop, NULL); - ui_loop(); + /* Keep the starting time (used for timed termination) */ + first_timestamp = time(NULL); + + if (options.no_curses) { + if (options.timed_output) { + while(!foad) { + sleep(1); + } + } + else { + tui_loop(); + } + } + else { + ui_loop(); + } pthread_cancel(thread); @@ -30,7 +30,7 @@ options_t options; -char optstr[] = "+i:f:nNF:G:lhpbBPm:c:"; +char optstr[] = "+i:f:nNF:G:lhpbBPm:c:s:tL:o:"; /* Global options. */ @@ -55,7 +55,7 @@ config_enumeration_type sort_enumeration[] = { { "10s", OPTION_SORT_DIV2 }, { "40s", OPTION_SORT_DIV3 }, { "source", OPTION_SORT_SRC }, - { "destination", OPTION_SORT_SRC }, + { "destination", OPTION_SORT_DEST }, { NULL, -1 } }; @@ -155,6 +155,9 @@ void options_set_defaults() { options.max_bandwidth = 0; /* auto */ options.log_scale = 0; options.bar_interval = 1; + options.timed_output = 0; + options.no_curses = 0; + options.num_lines = 10; /* Figure out the name for the config file */ s = getenv("HOME"); @@ -268,6 +271,18 @@ static void usage(FILE *fp) { " -P show ports as well as hosts\n" " -m limit sets the upper limit for the bandwidth scale\n" " -c config file specifies an alternative configuration file\n" +" -t use text interface without ncurses\n" +"\n" +" Sorting orders:\n" +" -o 2s Sort by first column (2s traffic average)\n" +" -o 10s Sort by second column (10s traffic average) [default]\n" +" -o 40s Sort by third column (40s traffic average)\n" +" -o source Sort by source address\n" +" -o destination Sort by destination address\n" +"\n" +" The following options are only available in combination with -t\n" +" -s num print one single text output afer num seconds, then quit\n" +" -L num number of lines to print\n" "\n" "iftop, version " IFTOP_VERSION "\n" "copyright (c) 2002 Paul Warren <pdw@ex-parrot.com> and contributors\n" @@ -332,6 +347,22 @@ void options_read_args(int argc, char **argv) { config_set_string("use-bytes", "true"); break; + case 's': + config_set_string("timed-output", optarg); + break; + + case 't': + config_set_string("no-curses", "true"); + break; + + case 'L': + config_set_string("num-lines", optarg); + break; + + case 'o': + config_set_string("sort", optarg); + break; + case 'c': xfree(options.config_file); options.config_file = xstrdup(optarg); @@ -595,6 +626,9 @@ void options_make() { options_config_get_enum("port-display", showports_enumeration, (int*)&options.showports); options_config_get_string("screen-filter", &options.screenfilter); options_config_get_bool("link-local", &options.link_local); + options_config_get_int("timed-output", &options.timed_output); + options_config_get_bool("no-curses", &options.no_curses); + options_config_get_int("num-lines", &options.num_lines); options_config_get_net_filter(); options_config_get_net_filter6(); }; @@ -56,6 +56,9 @@ typedef struct { int aggregate_dest; int paused; int showhelp; + int timed_output; + int no_curses; + int num_lines; int bandwidth_in_bytes; option_sort_t sort; @@ -26,9 +26,7 @@ #include "options.h" #include "screenfilter.h" -#define HOSTNAME_LENGTH 256 - -#define HISTORY_DIVISIONS 3 +#include "ui_common.h" #define HELP_TIME 2 @@ -54,22 +52,6 @@ "iftop, version " IFTOP_VERSION -/* 2, 10 and 40 seconds */ -int history_divs[HISTORY_DIVISIONS] = {1, 5, 20}; - -#define UNIT_DIVISIONS 4 -char* unit_bits[UNIT_DIVISIONS] = { "b", "kb", "Mb", "Gb"}; -char* unit_bytes[UNIT_DIVISIONS] = { "B", "kB", "MB", "GB"}; - -typedef struct host_pair_line_tag { - addr_pair ap; - double long total_recv; - double long total_sent; - double long recv[HISTORY_DIVISIONS]; - double long sent[HISTORY_DIVISIONS]; -} host_pair_line; - - extern hash_type* history; extern int history_pos; extern int history_len; @@ -78,12 +60,6 @@ extern options_t options ; void ui_finish(); -hash_type* screen_hash; -hash_type* service_hash; -sorted_list_type screen_list; -host_pair_line totals; -int peaksent, peakrecv, peaktotal; - #define HELP_MSG_SIZE 80 int showhelphint = 0; int persistenthelp = 0; @@ -91,122 +67,6 @@ time_t helptimer = 0; char helpmsg[HELP_MSG_SIZE]; int dontshowdisplay = 0; -/* - * Compare two screen lines based on bandwidth. Start comparing from the - * specified column - */ -int screen_line_bandwidth_compare(host_pair_line* aa, host_pair_line* bb, int start_div) { - int i; - switch(options.linedisplay) { - case OPTION_LINEDISPLAY_ONE_LINE_SENT: - for(i = start_div; i < HISTORY_DIVISIONS; i++) { - if(aa->sent[i] != bb->sent[i]) { - return(aa->sent[i] < bb->sent[i]); - } - } - break; - case OPTION_LINEDISPLAY_ONE_LINE_RECV: - for(i = start_div; i < HISTORY_DIVISIONS; i++) { - if(aa->recv[i] != bb->recv[i]) { - return(aa->recv[i] < bb->recv[i]); - } - } - break; - case OPTION_LINEDISPLAY_TWO_LINE: - case OPTION_LINEDISPLAY_ONE_LINE_BOTH: - /* fallback to the combined sent+recv that also act as fallback for sent/recv */ - break; - } - for(i = start_div; i < HISTORY_DIVISIONS; i++) { - if(aa->recv[i] + aa->sent[i] != bb->recv[i] + bb->sent[i]) { - return(aa->recv[i] + aa->sent[i] < bb->recv[i] + bb->sent[i]); - } - } - return 1; -} - -/* - * Compare two screen lines based on hostname / IP. Fall over to compare by - * bandwidth. - */ -int screen_line_host_compare(void* a, void* b, host_pair_line* aa, host_pair_line* bb) { - char hosta[HOSTNAME_LENGTH], hostb[HOSTNAME_LENGTH]; - int r; - - /* This isn't overly efficient because we resolve again before - display. */ - if (options.dnsresolution) { - resolve(aa->ap.af, a, hosta, HOSTNAME_LENGTH); - resolve(bb->ap.af, b, hostb, HOSTNAME_LENGTH); - } - else { - inet_ntop(aa->ap.af, a, hosta, sizeof(hosta)); - inet_ntop(bb->ap.af, b, hostb, sizeof(hostb)); - } - - r = strcmp(hosta, hostb); - - if(r == 0) { - return screen_line_bandwidth_compare(aa, bb, 2); - } - else { - return (r > 0); - } - - -} - -int screen_line_compare(void* a, void* b) { - host_pair_line* aa = (host_pair_line*)a; - host_pair_line* bb = (host_pair_line*)b; - if(options.sort == OPTION_SORT_DIV1) { - return screen_line_bandwidth_compare(aa, bb, 0); - } - else if(options.sort == OPTION_SORT_DIV2) { - return screen_line_bandwidth_compare(aa, bb, 1); - } - else if(options.sort == OPTION_SORT_DIV3) { - return screen_line_bandwidth_compare(aa, bb, 2); - } - else if(options.sort == OPTION_SORT_SRC) { - return screen_line_host_compare(&(aa->ap.src6), &(bb->ap.src6), aa, bb); - } - else if(options.sort == OPTION_SORT_DEST) { - return screen_line_host_compare(&(aa->ap.dst6), &(bb->ap.dst6), aa, bb); - } - - return 1; -} - -void readable_size(float n, char* buf, int bsize, int ksize, int bytes) { - - int i = 0; - float size = 1; - - /* Convert to bits? */ - if(bytes == 0) { - n *= 8; - } - - while(1) { - if(n < size * 1000 || i >= UNIT_DIVISIONS - 1) { - snprintf(buf, bsize, " %4.0f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); - break; - } - i++; - size *= ksize; - if(n < size * 10) { - snprintf(buf, bsize, " %4.2f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); - break; - } - else if(n < size * 100) { - snprintf(buf, bsize, " %4.1f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); - break; - } - } -} - - /* Barchart scales. */ static struct { int max, interval; @@ -315,13 +175,6 @@ static void draw_bar_scale(int* y) { } } -int history_length(const int d) { - if (history_len < history_divs[d]) - return history_len * RESOLUTION; - else - return history_divs[d] * RESOLUTION; -} - void draw_line_total(float sent, float recv, int y, int x, option_linedisplay_t linedisplay, int bytes) { char buf[10]; float n; @@ -400,225 +253,6 @@ void draw_totals(host_pair_line* totals) { extern history_type history_totals; -void screen_list_init() { - screen_list.compare = &screen_line_compare; - sorted_list_initialise(&screen_list); -} - -void screen_list_clear() { - sorted_list_node* nn = NULL; - peaksent = peakrecv = peaktotal = 0; - while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) { - free(nn->data); - } - sorted_list_destroy(&screen_list); -} - -void calculate_totals() { - int i; - - /** - * Calculate peaks and totals - */ - for(i = 0; i < HISTORY_LENGTH; i++) { - int j; - int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH; - - for(j = 0; j < HISTORY_DIVISIONS; j++) { - if(i < history_divs[j]) { - totals.recv[j] += history_totals.recv[ii]; - totals.sent[j] += history_totals.sent[ii]; - } - } - - if(history_totals.recv[i] > peakrecv) { - peakrecv = history_totals.recv[i]; - } - if(history_totals.sent[i] > peaksent) { - peaksent = history_totals.sent[i]; - } - if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) { - peaktotal = history_totals.recv[i] + history_totals.sent[i]; - } - } - for(i = 0; i < HISTORY_DIVISIONS; i++) { - int t = history_length(i); - totals.recv[i] /= t; - totals.sent[i] /= t; - } -} - -void make_screen_list() { - hash_node_type* n = NULL; - while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) { - host_pair_line* line = (host_pair_line*)n->rec; - int i; - for(i = 0; i < HISTORY_DIVISIONS; i++) { - line->recv[i] /= history_length(i); - line->sent[i] /= history_length(i); - } - - /* Don't make a new, sorted screen list if order is frozen - */ - if(!options.freezeorder) { - sorted_list_insert(&screen_list, line); - } - - } -} - -/* - * Zeros all data in the screen hash, but does not remove items. - */ -void screen_hash_clear() { - hash_node_type* n = NULL; - while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) { - host_pair_line* hpl = (host_pair_line*)n->rec; - hpl->total_recv = hpl->total_sent = 0; - memset(hpl->recv, 0, sizeof(hpl->recv)); - memset(hpl->sent, 0, sizeof(hpl->sent)); - } -} - -void analyse_data() { - hash_node_type* n = NULL; - - if(options.paused == 1) { - return; - } - - // Zero totals - memset(&totals, 0, sizeof totals); - - if(options.freezeorder) { - screen_hash_clear(); - } - else { - screen_list_clear(); - hash_delete_all(screen_hash); - } - - while(hash_next_item(history, &n) == HASH_STATUS_OK) { - history_type* d = (history_type*)n->rec; - host_pair_line* screen_line; - union { - host_pair_line **h_p_l_pp; - void **void_pp; - } u_screen_line = { &screen_line }; - addr_pair ap; - int i; - int tsent, trecv; - tsent = trecv = 0; - - - ap = *(addr_pair*)n->key; - - /* Aggregate hosts, if required */ - if(options.aggregate_src) { - memset(&ap.src6, '\0', sizeof(ap.src6)); - } - if(options.aggregate_dest) { - memset(&ap.dst6, '\0', sizeof(ap.dst6)); - } - - /* Aggregate ports, if required */ - if(options.showports == OPTION_PORTS_DEST || options.showports == OPTION_PORTS_OFF) { - ap.src_port = 0; - } - if(options.showports == OPTION_PORTS_SRC || options.showports == OPTION_PORTS_OFF) { - ap.dst_port = 0; - } - if(options.showports == OPTION_PORTS_OFF) { - ap.protocol = 0; - } - - - if(hash_find(screen_hash, &ap, u_screen_line.void_pp) == HASH_STATUS_KEY_NOT_FOUND) { - screen_line = xcalloc(1, sizeof *screen_line); - hash_insert(screen_hash, &ap, screen_line); - screen_line->ap = ap; - } - - screen_line->total_sent += d->total_sent; - screen_line->total_recv += d->total_recv; - - for(i = 0; i < HISTORY_LENGTH; i++) { - int j; - int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH; - - for(j = 0; j < HISTORY_DIVISIONS; j++) { - if(i < history_divs[j]) { - screen_line->recv[j] += d->recv[ii]; - screen_line->sent[j] += d->sent[ii]; - } - } - } - - } - - make_screen_list(); - - - calculate_totals(); - -} - -void sprint_host(char * line, int af, struct in6_addr* addr, unsigned int port, unsigned int protocol, int L, int unspecified_as_star) { - char hostname[HOSTNAME_LENGTH]; - char service[HOSTNAME_LENGTH]; - char* s_name; - union { - char **ch_pp; - void **void_pp; - } u_s_name = { &s_name }; - - ip_service skey; - int left; - - if(IN6_IS_ADDR_UNSPECIFIED(addr) && unspecified_as_star) { - sprintf(hostname, " * "); - } - else { - if (options.dnsresolution) - resolve(af, addr, hostname, L); - else - inet_ntop(af, addr, hostname, sizeof(hostname)); - } - left = strlen(hostname); - - if(port != 0) { - skey.port = port; - skey.protocol = protocol; - if(options.portresolution && hash_find(service_hash, &skey, u_s_name.void_pp) == HASH_STATUS_OK) { - snprintf(service, HOSTNAME_LENGTH, ":%s", s_name); - } - else { - snprintf(service, HOSTNAME_LENGTH, ":%d", port); - } - } - else { - service[0] = '\0'; - } - - /* If we're showing IPv6 addresses with a port number, put them in square - * brackets. */ - if(port == 0 || af == AF_INET || L < 2) { - sprintf(line, "%-*s", L, hostname); - } - else { - sprintf(line, "[%-.*s]", L-2, hostname); - left += 2; - } - if(left > (L - strlen(service))) { - left = L - strlen(service); - if(left < 0) { - left = 0; - } - } - sprintf(line + left, "%-*s", L-left, service); -} - - void ui_print() { sorted_list_node* nn = NULL; diff --git a/ui_common.c b/ui_common.c new file mode 100644 index 0000000..803448e --- /dev/null +++ b/ui_common.c @@ -0,0 +1,375 @@ +/* + * ui_common.c + * + * + */ + +#include <string.h> +#include <stdio.h> + +#include "addr_hash.h" +#include "serv_hash.h" +#include "iftop.h" +#include "resolver.h" +#include "sorted_list.h" +#include "options.h" + +#include "ui_common.h" + +/* 2, 10 and 40 seconds */ +int history_divs[HISTORY_DIVISIONS] = {1, 5, 20}; + +#define UNIT_DIVISIONS 4 +char* unit_bits[UNIT_DIVISIONS] = { "b", "Kb", "Mb", "Gb"}; +char* unit_bytes[UNIT_DIVISIONS] = { "B", "KB", "MB", "GB"}; + +extern hash_type* history; +extern int history_pos; +extern int history_len; + +/* + * Compare two screen lines based on bandwidth. Start comparing from the + * specified column + */ +int screen_line_bandwidth_compare(host_pair_line* aa, host_pair_line* bb, int start_div) { + int i; + switch(options.linedisplay) { + case OPTION_LINEDISPLAY_ONE_LINE_SENT: + for(i = start_div; i < HISTORY_DIVISIONS; i++) { + if(aa->sent[i] != bb->sent[i]) { + return(aa->sent[i] < bb->sent[i]); + } + } + break; + case OPTION_LINEDISPLAY_ONE_LINE_RECV: + for(i = start_div; i < HISTORY_DIVISIONS; i++) { + if(aa->recv[i] != bb->recv[i]) { + return(aa->recv[i] < bb->recv[i]); + } + } + break; + case OPTION_LINEDISPLAY_TWO_LINE: + case OPTION_LINEDISPLAY_ONE_LINE_BOTH: + /* fallback to the combined sent+recv that also act as fallback for sent/recv */ + break; + } + for(i = start_div; i < HISTORY_DIVISIONS; i++) { + if(aa->recv[i] + aa->sent[i] != bb->recv[i] + bb->sent[i]) { + return(aa->recv[i] + aa->sent[i] < bb->recv[i] + bb->sent[i]); + } + } + return 1; +} + +/* + * Compare two screen lines based on hostname / IP. Fall over to compare by + * bandwidth. + */ +int screen_line_host_compare(void* a, void* b, host_pair_line* aa, host_pair_line* bb) { + char hosta[HOSTNAME_LENGTH], hostb[HOSTNAME_LENGTH]; + int r; + + /* This isn't overly efficient because we resolve again before + display. */ + if (options.dnsresolution) { + resolve(aa->ap.af, a, hosta, HOSTNAME_LENGTH); + resolve(bb->ap.af, b, hostb, HOSTNAME_LENGTH); + } + else { + inet_ntop(aa->ap.af, a, hosta, sizeof(hosta)); + inet_ntop(bb->ap.af, b, hostb, sizeof(hostb)); + } + + r = strcmp(hosta, hostb); + + if(r == 0) { + return screen_line_bandwidth_compare(aa, bb, 2); + } + else { + return (r > 0); + } + + +} + +/* + * Compare two screen lines based on the sorting options selected. + */ +int screen_line_compare(void* a, void* b) { + host_pair_line* aa = (host_pair_line*)a; + host_pair_line* bb = (host_pair_line*)b; + if(options.sort == OPTION_SORT_DIV1) { + return screen_line_bandwidth_compare(aa, bb, 0); + } + else if(options.sort == OPTION_SORT_DIV2) { + return screen_line_bandwidth_compare(aa, bb, 1); + } + else if(options.sort == OPTION_SORT_DIV3) { + return screen_line_bandwidth_compare(aa, bb, 2); + } + else if(options.sort == OPTION_SORT_SRC) { + return screen_line_host_compare(&(aa->ap.src6), &(bb->ap.src6), aa, bb); + } + else if(options.sort == OPTION_SORT_DEST) { + return screen_line_host_compare(&(aa->ap.dst6), &(bb->ap.dst6), aa, bb); + } + + return 1; +} + +/* + * Format a data size in human-readable format + */ +void readable_size(float n, char* buf, int bsize, int ksize, int bytes) { + + int i = 0; + float size = 1; + + /* Convert to bits? */ + if(bytes == 0) { + n *= 8; + } + + while(1) { + if(n < size * 1000 || i >= UNIT_DIVISIONS - 1) { + snprintf(buf, bsize, " %4.0f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); + break; + } + i++; + size *= ksize; + if(n < size * 10) { + snprintf(buf, bsize, " %4.2f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); + break; + } + else if(n < size * 100) { + snprintf(buf, bsize, " %4.1f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]); + break; + } + } +} + +int history_length(const int d) { + if (history_len < history_divs[d]) + return history_len * RESOLUTION; + else + return history_divs[d] * RESOLUTION; +} + +void screen_list_init() { + screen_list.compare = &screen_line_compare; + sorted_list_initialise(&screen_list); +} + +void screen_list_clear() { + sorted_list_node* nn = NULL; + peaksent = peakrecv = peaktotal = 0; + while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) { + free(nn->data); + } + sorted_list_destroy(&screen_list); +} + +/* + * Calculate peaks and totals + */ +void calculate_totals() { + int i; + + for(i = 0; i < HISTORY_LENGTH; i++) { + int j; + int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH; + + for(j = 0; j < HISTORY_DIVISIONS; j++) { + if(i < history_divs[j]) { + totals.recv[j] += history_totals.recv[ii]; + totals.sent[j] += history_totals.sent[ii]; + } + } + + if(history_totals.recv[i] > peakrecv) { + peakrecv = history_totals.recv[i]; + } + if(history_totals.sent[i] > peaksent) { + peaksent = history_totals.sent[i]; + } + if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) { + peaktotal = history_totals.recv[i] + history_totals.sent[i]; + } + } + for(i = 0; i < HISTORY_DIVISIONS; i++) { + int t = history_length(i); + totals.recv[i] /= t; + totals.sent[i] /= t; + } +} + +void make_screen_list() { + hash_node_type* n = NULL; + while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) { + host_pair_line* line = (host_pair_line*)n->rec; + int i; + for(i = 0; i < HISTORY_DIVISIONS; i++) { + line->recv[i] /= history_length(i); + line->sent[i] /= history_length(i); + } + + /* Don't make a new, sorted screen list if order is frozen + */ + if(!options.freezeorder) { + sorted_list_insert(&screen_list, line); + } + + } +} + +/* + * Zeros all data in the screen hash, but does not remove items. + */ +void screen_hash_clear() { + hash_node_type* n = NULL; + while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) { + host_pair_line* hpl = (host_pair_line*)n->rec; + hpl->total_recv = hpl->total_sent = 0; + memset(hpl->recv, 0, sizeof(hpl->recv)); + memset(hpl->sent, 0, sizeof(hpl->sent)); + } +} + +void analyse_data() { + hash_node_type* n = NULL; + + if(options.paused == 1) { + return; + } + + // Zero totals + memset(&totals, 0, sizeof totals); + + if(options.freezeorder) { + screen_hash_clear(); + } + else { + screen_list_clear(); + hash_delete_all(screen_hash); + } + + while(hash_next_item(history, &n) == HASH_STATUS_OK) { + history_type* d = (history_type*)n->rec; + host_pair_line* screen_line; + union { + host_pair_line **h_p_l_pp; + void **void_pp; + } u_screen_line = { &screen_line }; + addr_pair ap; + int i; + int tsent, trecv; + tsent = trecv = 0; + + + ap = *(addr_pair*)n->key; + + /* Aggregate hosts, if required */ + if(options.aggregate_src) { + memset(&ap.src6, '\0', sizeof(ap.src6)); + } + if(options.aggregate_dest) { + memset(&ap.dst6, '\0', sizeof(ap.dst6)); + } + + /* Aggregate ports, if required */ + if(options.showports == OPTION_PORTS_DEST || options.showports == OPTION_PORTS_OFF) { + ap.src_port = 0; + } + if(options.showports == OPTION_PORTS_SRC || options.showports == OPTION_PORTS_OFF) { + ap.dst_port = 0; + } + if(options.showports == OPTION_PORTS_OFF) { + ap.protocol = 0; + } + + + if(hash_find(screen_hash, &ap, u_screen_line.void_pp) == HASH_STATUS_KEY_NOT_FOUND) { + screen_line = xcalloc(1, sizeof *screen_line); + hash_insert(screen_hash, &ap, screen_line); + screen_line->ap = ap; + } + + screen_line->total_sent += d->total_sent; + screen_line->total_recv += d->total_recv; + + for(i = 0; i < HISTORY_LENGTH; i++) { + int j; + int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH; + + for(j = 0; j < HISTORY_DIVISIONS; j++) { + if(i < history_divs[j]) { + screen_line->recv[j] += d->recv[ii]; + screen_line->sent[j] += d->sent[ii]; + } + } + } + + } + + make_screen_list(); + + + calculate_totals(); + +} + +void sprint_host(char * line, int af, struct in6_addr* addr, unsigned int port, unsigned int protocol, int L, int unspecified_as_star) { + char hostname[HOSTNAME_LENGTH]; + char service[HOSTNAME_LENGTH]; + char* s_name; + union { + char **ch_pp; + void **void_pp; + } u_s_name = { &s_name }; + + ip_service skey; + int left; + + if(IN6_IS_ADDR_UNSPECIFIED(addr) && unspecified_as_star) { + sprintf(hostname, " * "); + } + else { + if (options.dnsresolution) + resolve(af, addr, hostname, L); + else + inet_ntop(af, addr, hostname, sizeof(hostname)); + } + left = strlen(hostname); + + if(port != 0) { + skey.port = port; + skey.protocol = protocol; + if(options.portresolution && hash_find(service_hash, &skey, u_s_name.void_pp) == HASH_STATUS_OK) { + snprintf(service, HOSTNAME_LENGTH, ":%s", s_name); + } + else { + snprintf(service, HOSTNAME_LENGTH, ":%d", port); + } + } + else { + service[0] = '\0'; + } + + /* If we're showing IPv6 addresses with a port number, put them in square + * brackets. */ + if(port == 0 || af == AF_INET || L < 2) { + sprintf(line, "%-*s", L, hostname); + } + else { + sprintf(line, "[%-.*s]", L-2, hostname); + left += 2; + } + if(left > (L - strlen(service))) { + left = L - strlen(service); + if(left < 0) { + left = 0; + } + } + sprintf(line + left, "%-*s", L-left, service); +} + diff --git a/ui_common.h b/ui_common.h new file mode 100644 index 0000000..e4fcc2e --- /dev/null +++ b/ui_common.h @@ -0,0 +1,48 @@ +/* + * ui_common.h + * + * + */ + +#ifndef __UI_COMMON_H_ /* include guard */ +#define __UI_COMMON_H_ + +#include <string.h> +#include <stdio.h> + +#include "addr_hash.h" +#include "serv_hash.h" +#include "iftop.h" +#include "resolver.h" +#include "sorted_list.h" +#include "options.h" + +#define HISTORY_DIVISIONS 3 + +#define UNIT_DIVISIONS 4 + +#define HOSTNAME_LENGTH 256 + +typedef struct host_pair_line_tag { + addr_pair ap; + double long total_recv; + double long total_sent; + double long recv[HISTORY_DIVISIONS]; + double long sent[HISTORY_DIVISIONS]; +} host_pair_line; + +extern options_t options; + +sorted_list_type screen_list; +host_pair_line totals; +int peaksent, peakrecv, peaktotal; +extern history_type history_totals; +hash_type* screen_hash; +hash_type* service_hash; + +void analyse_data(void); +void screen_list_init(void); +void sprint_host(char * line, int af, struct in6_addr* addr, unsigned int port, unsigned int protocol, int L, int unspecified_as_star); +void readable_size(float, char*, int, int, int); + +#endif /* __UI_COMMON_H_ */ |