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>