Annotation of embedaddon/iftop/ui_common.c, revision 1.1.1.1
1.1 misho 1: /*
2: * ui_common.c
3: *
4: *
5: */
6:
7: #include <string.h>
8: #include <stdio.h>
9: #include <stdlib.h>
10:
11: #include "addr_hash.h"
12: #include "serv_hash.h"
13: #include "iftop.h"
14: #include "resolver.h"
15: #include "sorted_list.h"
16: #include "options.h"
17:
18: #include "ui_common.h"
19:
20: /* 2, 10 and 40 seconds */
21: int history_divs[HISTORY_DIVISIONS] = {1, 5, 20};
22:
23: #define UNIT_DIVISIONS 4
24: char* unit_bits[UNIT_DIVISIONS] = { "b", "Kb", "Mb", "Gb"};
25: char* unit_bytes[UNIT_DIVISIONS] = { "B", "KB", "MB", "GB"};
26:
27: extern hash_type* history;
28: extern int history_pos;
29: extern int history_len;
30:
31: /*
32: * Compare two screen lines based on bandwidth. Start comparing from the
33: * specified column
34: */
35: int screen_line_bandwidth_compare(host_pair_line* aa, host_pair_line* bb, int start_div) {
36: int i;
37: switch(options.linedisplay) {
38: case OPTION_LINEDISPLAY_ONE_LINE_SENT:
39: for(i = start_div; i < HISTORY_DIVISIONS; i++) {
40: if(aa->sent[i] != bb->sent[i]) {
41: return(aa->sent[i] < bb->sent[i]);
42: }
43: }
44: break;
45: case OPTION_LINEDISPLAY_ONE_LINE_RECV:
46: for(i = start_div; i < HISTORY_DIVISIONS; i++) {
47: if(aa->recv[i] != bb->recv[i]) {
48: return(aa->recv[i] < bb->recv[i]);
49: }
50: }
51: break;
52: case OPTION_LINEDISPLAY_TWO_LINE:
53: case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
54: /* fallback to the combined sent+recv that also act as fallback for sent/recv */
55: break;
56: }
57: for(i = start_div; i < HISTORY_DIVISIONS; i++) {
58: if(aa->recv[i] + aa->sent[i] != bb->recv[i] + bb->sent[i]) {
59: return(aa->recv[i] + aa->sent[i] < bb->recv[i] + bb->sent[i]);
60: }
61: }
62: return 1;
63: }
64:
65: /*
66: * Compare two screen lines based on hostname / IP. Fall over to compare by
67: * bandwidth.
68: */
69: int screen_line_host_compare(void* a, void* b, host_pair_line* aa, host_pair_line* bb) {
70: char hosta[HOSTNAME_LENGTH], hostb[HOSTNAME_LENGTH];
71: int r;
72:
73: /* This isn't overly efficient because we resolve again before
74: display. */
75: if (options.dnsresolution) {
76: resolve(aa->ap.af, a, hosta, HOSTNAME_LENGTH);
77: resolve(bb->ap.af, b, hostb, HOSTNAME_LENGTH);
78: }
79: else {
80: inet_ntop(aa->ap.af, a, hosta, sizeof(hosta));
81: inet_ntop(bb->ap.af, b, hostb, sizeof(hostb));
82: }
83:
84: r = strcmp(hosta, hostb);
85:
86: if(r == 0) {
87: return screen_line_bandwidth_compare(aa, bb, 2);
88: }
89: else {
90: return (r > 0);
91: }
92:
93:
94: }
95:
96: /*
97: * Compare two screen lines based on the sorting options selected.
98: */
99: int screen_line_compare(void* a, void* b) {
100: host_pair_line* aa = (host_pair_line*)a;
101: host_pair_line* bb = (host_pair_line*)b;
102: if(options.sort == OPTION_SORT_DIV1) {
103: return screen_line_bandwidth_compare(aa, bb, 0);
104: }
105: else if(options.sort == OPTION_SORT_DIV2) {
106: return screen_line_bandwidth_compare(aa, bb, 1);
107: }
108: else if(options.sort == OPTION_SORT_DIV3) {
109: return screen_line_bandwidth_compare(aa, bb, 2);
110: }
111: else if(options.sort == OPTION_SORT_SRC) {
112: return screen_line_host_compare(&(aa->ap.src6), &(bb->ap.src6), aa, bb);
113: }
114: else if(options.sort == OPTION_SORT_DEST) {
115: return screen_line_host_compare(&(aa->ap.dst6), &(bb->ap.dst6), aa, bb);
116: }
117:
118: return 1;
119: }
120:
121: /*
122: * Format a data size in human-readable format
123: */
124: void readable_size(float n, char* buf, int bsize, int ksize, int bytes) {
125:
126: int i = 0;
127: float size = 1;
128:
129: /* Convert to bits? */
130: if(bytes == 0) {
131: n *= 8;
132: }
133:
134: while(1) {
135: if(n < size * 1000 || i >= UNIT_DIVISIONS - 1) {
136: snprintf(buf, bsize, " %4.0f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]);
137: break;
138: }
139: i++;
140: size *= ksize;
141: if(n < size * 10) {
142: snprintf(buf, bsize, " %4.2f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]);
143: break;
144: }
145: else if(n < size * 100) {
146: snprintf(buf, bsize, " %4.1f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]);
147: break;
148: }
149: }
150: }
151:
152: int history_length(const int d) {
153: if (history_len < history_divs[d])
154: return history_len * RESOLUTION;
155: else
156: return history_divs[d] * RESOLUTION;
157: }
158:
159: void screen_list_init() {
160: screen_list.compare = &screen_line_compare;
161: sorted_list_initialise(&screen_list);
162: }
163:
164: void screen_list_clear() {
165: sorted_list_node* nn = NULL;
166: peaksent = peakrecv = peaktotal = 0;
167: while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) {
168: free(nn->data);
169: }
170: sorted_list_destroy(&screen_list);
171: }
172:
173: /*
174: * Calculate peaks and totals
175: */
176: void calculate_totals() {
177: int i;
178:
179: for(i = 0; i < HISTORY_LENGTH; i++) {
180: int j;
181: int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
182:
183: for(j = 0; j < HISTORY_DIVISIONS; j++) {
184: if(i < history_divs[j]) {
185: totals.recv[j] += history_totals.recv[ii];
186: totals.sent[j] += history_totals.sent[ii];
187: }
188: }
189:
190: if(history_totals.recv[i] > peakrecv) {
191: peakrecv = history_totals.recv[i];
192: }
193: if(history_totals.sent[i] > peaksent) {
194: peaksent = history_totals.sent[i];
195: }
196: if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) {
197: peaktotal = history_totals.recv[i] + history_totals.sent[i];
198: }
199: }
200: for(i = 0; i < HISTORY_DIVISIONS; i++) {
201: int t = history_length(i);
202: totals.recv[i] /= t;
203: totals.sent[i] /= t;
204: }
205: }
206:
207: void make_screen_list() {
208: hash_node_type* n = NULL;
209: while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
210: host_pair_line* line = (host_pair_line*)n->rec;
211: int i;
212: for(i = 0; i < HISTORY_DIVISIONS; i++) {
213: line->recv[i] /= history_length(i);
214: line->sent[i] /= history_length(i);
215: }
216:
217: /* Don't make a new, sorted screen list if order is frozen
218: */
219: if(!options.freezeorder) {
220: sorted_list_insert(&screen_list, line);
221: }
222:
223: }
224: }
225:
226: /*
227: * Zeros all data in the screen hash, but does not remove items.
228: */
229: void screen_hash_clear() {
230: hash_node_type* n = NULL;
231: while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
232: host_pair_line* hpl = (host_pair_line*)n->rec;
233: hpl->total_recv = hpl->total_sent = 0;
234: memset(hpl->recv, 0, sizeof(hpl->recv));
235: memset(hpl->sent, 0, sizeof(hpl->sent));
236: }
237: }
238:
239: void analyse_data() {
240: hash_node_type* n = NULL;
241:
242: if(options.paused == 1) {
243: return;
244: }
245:
246: // Zero totals
247: memset(&totals, 0, sizeof totals);
248:
249: if(options.freezeorder) {
250: screen_hash_clear();
251: }
252: else {
253: screen_list_clear();
254: hash_delete_all(screen_hash);
255: }
256:
257: while(hash_next_item(history, &n) == HASH_STATUS_OK) {
258: history_type* d = (history_type*)n->rec;
259: host_pair_line* screen_line;
260: union {
261: host_pair_line **h_p_l_pp;
262: void **void_pp;
263: } u_screen_line = { &screen_line };
264: addr_pair ap;
265: int i;
266: int tsent, trecv;
267: tsent = trecv = 0;
268:
269:
270: ap = *(addr_pair*)n->key;
271:
272: /* Aggregate hosts, if required */
273: if(options.aggregate_src) {
274: memset(&ap.src6, '\0', sizeof(ap.src6));
275: }
276: if(options.aggregate_dest) {
277: memset(&ap.dst6, '\0', sizeof(ap.dst6));
278: }
279:
280: /* Aggregate ports, if required */
281: if(options.showports == OPTION_PORTS_DEST || options.showports == OPTION_PORTS_OFF) {
282: ap.src_port = 0;
283: }
284: if(options.showports == OPTION_PORTS_SRC || options.showports == OPTION_PORTS_OFF) {
285: ap.dst_port = 0;
286: }
287: if(options.showports == OPTION_PORTS_OFF) {
288: ap.protocol = 0;
289: }
290:
291:
292: if(hash_find(screen_hash, &ap, u_screen_line.void_pp) == HASH_STATUS_KEY_NOT_FOUND) {
293: screen_line = xcalloc(1, sizeof *screen_line);
294: hash_insert(screen_hash, &ap, screen_line);
295: screen_line->ap = ap;
296: }
297:
298: screen_line->total_sent += d->total_sent;
299: screen_line->total_recv += d->total_recv;
300:
301: for(i = 0; i < HISTORY_LENGTH; i++) {
302: int j;
303: int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
304:
305: for(j = 0; j < HISTORY_DIVISIONS; j++) {
306: if(i < history_divs[j]) {
307: screen_line->recv[j] += d->recv[ii];
308: screen_line->sent[j] += d->sent[ii];
309: }
310: }
311: }
312:
313: }
314:
315: make_screen_list();
316:
317:
318: calculate_totals();
319:
320: }
321:
322: void sprint_host(char * line, int af, struct in6_addr* addr, unsigned int port, unsigned int protocol, int L, int unspecified_as_star) {
323: char hostname[HOSTNAME_LENGTH];
324: char service[HOSTNAME_LENGTH];
325: char* s_name;
326: union {
327: char **ch_pp;
328: void **void_pp;
329: } u_s_name = { &s_name };
330:
331: ip_service skey;
332: int left;
333:
334: if(IN6_IS_ADDR_UNSPECIFIED(addr) && unspecified_as_star) {
335: sprintf(hostname, " * ");
336: }
337: else {
338: if (options.dnsresolution)
339: resolve(af, addr, hostname, L);
340: else
341: inet_ntop(af, addr, hostname, sizeof(hostname));
342: }
343: left = strlen(hostname);
344:
345: if(port != 0) {
346: skey.port = port;
347: skey.protocol = protocol;
348: if(options.portresolution && hash_find(service_hash, &skey, u_s_name.void_pp) == HASH_STATUS_OK) {
349: snprintf(service, HOSTNAME_LENGTH, ":%s", s_name);
350: }
351: else {
352: snprintf(service, HOSTNAME_LENGTH, ":%d", port);
353: }
354: }
355: else {
356: service[0] = '\0';
357: }
358:
359: /* If we're showing IPv6 addresses with a port number, put them in square
360: * brackets. */
361: if(port == 0 || af == AF_INET || L < 2) {
362: sprintf(line, "%-*s", L, hostname);
363: }
364: else {
365: sprintf(line, "[%-.*s]", L-2, hostname);
366: left += 2;
367: }
368: if(left > (L - strlen(service))) {
369: left = L - strlen(service);
370: if(left < 0) {
371: left = 0;
372: }
373: }
374: sprintf(line + left, "%-*s", L-left, service);
375: }
376:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>