11 #include "addr_hash.h"
12 #include "serv_hash.h"
15 #include "sorted_list.h"
18 #include "ui_common.h"
20 /* 2, 10 and 40 seconds */
21 int history_divs[HISTORY_DIVISIONS] = {1, 5, 20};
23 #define UNIT_DIVISIONS 4
24 char* unit_disp[][UNIT_DIVISIONS] = {
25 [OPTION_BW_BITS] = { "b", "Kb", "Mb", "Gb"},
26 [OPTION_BW_BYTES] = { "B", "KB", "MB", "GB"},
27 [OPTION_BW_PKTS] = { "p", "Kp", "Mp", "GB"},
30 extern hash_type* history;
31 extern int history_pos;
32 extern int history_len;
35 * Compare two screen lines based on bandwidth. Start comparing from the
38 int screen_line_bandwidth_compare(host_pair_line* aa, host_pair_line* bb, int start_div) {
40 switch(options.linedisplay) {
41 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
42 for(i = start_div; i < HISTORY_DIVISIONS; i++) {
43 if(aa->sent[i] != bb->sent[i]) {
44 return(aa->sent[i] < bb->sent[i]);
48 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
49 for(i = start_div; i < HISTORY_DIVISIONS; i++) {
50 if(aa->recv[i] != bb->recv[i]) {
51 return(aa->recv[i] < bb->recv[i]);
55 case OPTION_LINEDISPLAY_TWO_LINE:
56 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
57 /* fallback to the combined sent+recv that also act as fallback for sent/recv */
60 for(i = start_div; i < HISTORY_DIVISIONS; i++) {
61 if(aa->recv[i] + aa->sent[i] != bb->recv[i] + bb->sent[i]) {
62 return(aa->recv[i] + aa->sent[i] < bb->recv[i] + bb->sent[i]);
69 * Compare two screen lines based on hostname / IP. Fall over to compare by
72 int screen_line_host_compare(void* a, void* b, host_pair_line* aa, host_pair_line* bb) {
73 char hosta[HOSTNAME_LENGTH], hostb[HOSTNAME_LENGTH];
76 /* This isn't overly efficient because we resolve again before
78 if (options.dnsresolution) {
79 resolve(aa->ap.af, a, hosta, HOSTNAME_LENGTH);
80 resolve(bb->ap.af, b, hostb, HOSTNAME_LENGTH);
83 inet_ntop(aa->ap.af, a, hosta, sizeof(hosta));
84 inet_ntop(bb->ap.af, b, hostb, sizeof(hostb));
87 r = strcmp(hosta, hostb);
90 return screen_line_bandwidth_compare(aa, bb, 2);
100 * Compare two screen lines based on the sorting options selected.
102 int screen_line_compare(void* a, void* b) {
103 host_pair_line* aa = (host_pair_line*)a;
104 host_pair_line* bb = (host_pair_line*)b;
105 if(options.sort == OPTION_SORT_DIV1) {
106 return screen_line_bandwidth_compare(aa, bb, 0);
108 else if(options.sort == OPTION_SORT_DIV2) {
109 return screen_line_bandwidth_compare(aa, bb, 1);
111 else if(options.sort == OPTION_SORT_DIV3) {
112 return screen_line_bandwidth_compare(aa, bb, 2);
114 else if(options.sort == OPTION_SORT_SRC) {
115 return screen_line_host_compare(&(aa->ap.src6), &(bb->ap.src6), aa, bb);
117 else if(options.sort == OPTION_SORT_DEST) {
118 return screen_line_host_compare(&(aa->ap.dst6), &(bb->ap.dst6), aa, bb);
125 * Format a data size in human-readable format
127 void readable_size(float n, char* buf, int bsize, int ksize,
128 option_bw_unit_t unit) {
133 /* Convert to bits? */
134 if (unit == OPTION_BW_BITS) {
138 /* Force power of ten for pps */
139 if (unit == OPTION_BW_PKTS)
143 if(n < size * 1000 || i >= UNIT_DIVISIONS - 1) {
144 snprintf(buf, bsize, " %4.0f%s", n / size, unit_disp[unit][i]);
150 snprintf(buf, bsize, " %4.2f%s", n / size, unit_disp[unit][i]);
153 else if(n < size * 100) {
154 snprintf(buf, bsize, " %4.1f%s", n / size, unit_disp[unit][i]);
160 int history_length(const int d) {
161 if (history_len < history_divs[d])
162 return history_len * RESOLUTION;
164 return history_divs[d] * RESOLUTION;
167 void screen_list_init() {
168 screen_list.compare = &screen_line_compare;
169 sorted_list_initialise(&screen_list);
172 void screen_list_clear() {
173 sorted_list_node* nn = NULL;
174 peaksent = peakrecv = peaktotal = 0;
175 while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) {
178 sorted_list_destroy(&screen_list);
182 * Calculate peaks and totals
184 void calculate_totals() {
187 for(i = 0; i < HISTORY_LENGTH; i++) {
189 int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
191 for(j = 0; j < HISTORY_DIVISIONS; j++) {
192 if(i < history_divs[j]) {
193 totals.recv[j] += history_totals.recv[ii];
194 totals.sent[j] += history_totals.sent[ii];
198 if(history_totals.recv[i] > peakrecv) {
199 peakrecv = history_totals.recv[i];
201 if(history_totals.sent[i] > peaksent) {
202 peaksent = history_totals.sent[i];
204 if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) {
205 peaktotal = history_totals.recv[i] + history_totals.sent[i];
208 for(i = 0; i < HISTORY_DIVISIONS; i++) {
209 int t = history_length(i);
215 void make_screen_list() {
216 hash_node_type* n = NULL;
217 while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
218 host_pair_line* line = (host_pair_line*)n->rec;
220 for(i = 0; i < HISTORY_DIVISIONS; i++) {
221 line->recv[i] /= history_length(i);
222 line->sent[i] /= history_length(i);
225 /* Don't make a new, sorted screen list if order is frozen
227 if(!options.freezeorder) {
228 sorted_list_insert(&screen_list, line);
235 * Zeros all data in the screen hash, but does not remove items.
237 void screen_hash_clear() {
238 hash_node_type* n = NULL;
239 while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
240 host_pair_line* hpl = (host_pair_line*)n->rec;
241 hpl->total_recv = hpl->total_sent = 0;
242 memset(hpl->recv, 0, sizeof(hpl->recv));
243 memset(hpl->sent, 0, sizeof(hpl->sent));
247 void analyse_data() {
248 hash_node_type* n = NULL;
250 if(options.paused == 1) {
255 memset(&totals, 0, sizeof totals);
257 if(options.freezeorder) {
262 hash_delete_all(screen_hash);
265 while(hash_next_item(history, &n) == HASH_STATUS_OK) {
266 history_type* d = (history_type*)n->rec;
267 host_pair_line* screen_line;
269 host_pair_line **h_p_l_pp;
271 } u_screen_line = { &screen_line };
275 ap = *(addr_pair*)n->key;
277 /* Aggregate hosts, if required */
278 if(options.aggregate_src) {
279 memset(&ap.src6, '\0', sizeof(ap.src6));
281 if(options.aggregate_dest) {
282 memset(&ap.dst6, '\0', sizeof(ap.dst6));
285 /* Aggregate ports, if required */
286 if(options.showports == OPTION_PORTS_DEST || options.showports == OPTION_PORTS_OFF) {
289 if(options.showports == OPTION_PORTS_SRC || options.showports == OPTION_PORTS_OFF) {
292 if(options.showports == OPTION_PORTS_OFF) {
297 if(hash_find(screen_hash, &ap, u_screen_line.void_pp) == HASH_STATUS_KEY_NOT_FOUND) {
298 screen_line = xcalloc(1, sizeof *screen_line);
299 hash_insert(screen_hash, &ap, screen_line);
300 screen_line->ap = ap;
303 screen_line->total_sent += d->total_sent;
304 screen_line->total_recv += d->total_recv;
306 for(i = 0; i < HISTORY_LENGTH; i++) {
308 int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
310 for(j = 0; j < HISTORY_DIVISIONS; j++) {
311 if(i < history_divs[j]) {
312 screen_line->recv[j] += d->recv[ii];
313 screen_line->sent[j] += d->sent[ii];
327 void sprint_host(char * line, int af, struct in6_addr* addr, unsigned int port, unsigned int protocol, int L, int unspecified_as_star) {
328 char hostname[HOSTNAME_LENGTH];
329 char service[HOSTNAME_LENGTH];
334 } u_s_name = { &s_name };
339 if(IN6_IS_ADDR_UNSPECIFIED(addr) && unspecified_as_star) {
340 sprintf(hostname, " * ");
343 if (options.dnsresolution)
344 resolve(af, addr, hostname, L);
346 inet_ntop(af, addr, hostname, sizeof(hostname));
348 left = strlen(hostname);
352 skey.protocol = protocol;
353 if(options.portresolution && hash_find(service_hash, &skey, u_s_name.void_pp) == HASH_STATUS_OK) {
354 snprintf(service, HOSTNAME_LENGTH, ":%s", s_name);
357 snprintf(service, HOSTNAME_LENGTH, ":%d", port);
364 /* If we're showing IPv6 addresses with a port number, put them in square
366 if(port == 0 || af == AF_INET || L < 2) {
367 sprintf(line, "%-*s", L, hostname);
370 sprintf(line, "[%-.*s]", L-2, hostname);
373 if(left > (L - strlen(service))) {
374 left = L - strlen(service);
379 sprintf(line + left, "%-*s", L-left, service);