summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpdw <>2014-01-01 14:37:31 +0000
committerpdw <>2014-01-01 14:37:31 +0000
commita9663192567697bfb217704cd67c34fd32a68389 (patch)
tree519a7c9cbc7d65b17d3c0a017f0de404be448326
parent59cf360690c99ad5149305ce3600151fa0f1483b (diff)
downloadiftop-a9663192567697bfb217704cd67c34fd32a68389.zip
Patch for text output mode by originally by Patrik Bless, updated by Roman Hoog
Antink <rha@open.ch>
-rw-r--r--Makefile.am4
-rw-r--r--cfgfile.c3
-rw-r--r--hash.c10
-rw-r--r--iftop.c50
-rw-r--r--options.c38
-rw-r--r--options.h3
-rw-r--r--ui.c368
-rw-r--r--ui_common.c375
-rw-r--r--ui_common.h48
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
diff --git a/cfgfile.c b/cfgfile.c
index 6b4a06e..ad1edc8 100644
--- a/cfgfile.c
+++ b/cfgfile.c
@@ -39,6 +39,9 @@ char * config_directives[] = {
"net-filter6",
"link-local",
"port-display",
+ "timed-output",
+ "no-curses",
+ "num-lines",
NULL
};
diff --git a/hash.c b/hash.c
index 540af8e..1c500f1 100644
--- a/hash.c
+++ b/hash.c
@@ -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) {
diff --git a/iftop.c b/iftop.c
index f0e692f..3c7e58a 100644
--- a/iftop.c
+++ b/iftop.c
@@ -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);
diff --git a/options.c b/options.c
index ced4125..d067cbc 100644
--- a/options.c
+++ b/options.c
@@ -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();
};
diff --git a/options.h b/options.h
index 0123285..86620d9 100644
--- a/options.h
+++ b/options.h
@@ -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;
diff --git a/ui.c b/ui.c
index 86c3e51..849006e 100644
--- a/ui.c
+++ b/ui.c
@@ -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_ */