123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- /*
- * ui_common.c
- *
- *
- */
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.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);
- }
|