Annotation of embedaddon/iftop/ui_common.c, revision 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>