File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iftop / ui_common.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 18 14:04:50 2016 UTC (7 years, 8 months ago) by misho
Branches: iftop, MAIN
CVS tags: v1_0rc4, HEAD
iftop 1.0pre4

    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>