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>