From 3004ea063cbb186a63af99a2e13d7cb09f23360d Mon Sep 17 00:00:00 2001 From: pdw <> Date: Sun, 24 Mar 2002 16:22:26 +0000 Subject: [PATCH] iftop --- .iftop.h.swp | Bin 0 -> 12288 bytes .ui.c.swp | Bin 0 -> 16384 bytes Makefile | 46 ++++++++++++++ addr_hash.c | 69 ++++++++++++++++++++ addr_hash.h | 23 +++++++ hash.c | 112 ++++++++++++++++++++++++++++++++ hash.h | 39 ++++++++++++ iftop.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++ iftop.h | 21 ++++++ ns_hash.c | 64 +++++++++++++++++++ ns_hash.h | 18 ++++++ resolver.c | 143 +++++++++++++++++++++++++++++++++++++++++ resolver.h | 15 +++++ sorted_list.c | 59 +++++++++++++++++ sorted_list.h | 25 ++++++++ ui.c | 153 ++++++++++++++++++++++++++++++++++++++++++++ ui.h | 14 ++++ 17 files changed, 973 insertions(+) create mode 100644 .iftop.h.swp create mode 100644 .ui.c.swp create mode 100644 Makefile create mode 100644 addr_hash.c create mode 100644 addr_hash.h create mode 100644 hash.c create mode 100644 hash.h create mode 100644 iftop.c create mode 100644 iftop.h create mode 100644 ns_hash.c create mode 100644 ns_hash.h create mode 100644 resolver.c create mode 100644 resolver.h create mode 100644 sorted_list.c create mode 100644 sorted_list.h create mode 100644 ui.c create mode 100644 ui.h diff --git a/.iftop.h.swp b/.iftop.h.swp new file mode 100644 index 0000000000000000000000000000000000000000..641503eb6d7449c35114f8e7f23709947694f40c GIT binary patch literal 12288 zcmeI&&n^Q|6bA4^BsPK&E1N?%bkP|aB-o-&N`;b$$fRbb=F&`?ncGSu#Dnk(yn`p; z9W1br*pNtsGvi;xq8kh3yXiO0+&lNooZoWVO>;Fn&ts_xlF?1n^LRXMUUtw$8&TES zjb@t;*Y=d}6q{amAO#J(9vZ5oE7jLy%4@m}7eD|4KO~SI9WfJw1KiuQ@v+1WyV(aKnyG>GaI<*-)v&d~4_ z(LQ@B)RmxN=|Sy)oaVTT r_ZpwgQ9_mc=tiGYQTNKX%QeU4ty(c~;;qqvlk(yC@AoNhQf@#m;HQ51 literal 0 HcmV?d00001 diff --git a/.ui.c.swp b/.ui.c.swp new file mode 100644 index 0000000000000000000000000000000000000000..e7fc6858782d06c07b2c1f22064083b748359669 GIT binary patch literal 16384 zcmeI2eQX>@6~LE5+LRUo6bVI0XyPdCoqhJ5oir&;Y>^TNTXAAFcG7}lu6wt8y-n_R zue)m}P82FZ5g(;hivWqHC6Opa0-+$N1eEY0gd+YxAZUStM8!w{K#+ilP#Yk8{NC*D z-Jat*K}v-x?aDvj?R>m>^JeDF%(E+{z2iI8%>$bZo;MiACoVj;rSJLcji0>6Fk03@ zNxkG_SL=>znU^g0J_Hu4^Fh(6gfI7>gzz$y4RJPh~2 z2Ve}|0_R?97{7;K!NX96_do$w!;h~uj7Ojao8aFokqOViGw?J#3ZH^c!tF2uMfmeI z=m1}U_k#uFFa|5&*{coXDL4+FfhN2e&aFT${1kow--HwJ2;2`Jg({eE7feDgTmx6b z3OLRGb36dI!8w9E--YkMx8Xs!3vP#va06T*AoNdo5d<<$`>rVB+yrFiI64@hD8E>E#oYx#~F)^b5;*}h-s z37w|x&4s$;KDQ@TwiVWW+qBA6&$Y@@%sOZ~VeUqeS(dLlr=U^^&AHG%Bq@k7bc6f~ z2g3QX8`xDftV$hKbaIp`!gIU!OibiepBn5G2||CaDylW@phf*K$~stg8g_0_dMs^p z>4`CxP*KZ{Dkr72s^!JS;||2-qdw%s(s|{2{3DKsF{MqOVz071_oh%uvU1!OM(iyb zk`>peR_*a3Ahm4{Ml*F^uwJ9ig%O(0$|xGB{R*b6PwlF<*UenCy|-ZLutp_=WQm4>Y- zQ1MLPQcbhfa@@NY=^zH9W?Ky^N|IwXoWr&X>vp0|!>RbDzaZ5kGbVUDYJJId57P*|~*+Vp%LvB8XR` zWEFbUx|%ChGu7);i1+3?$<*d?-}{Ooa>U5p82kQC@edn-Aq|n4C}i2 zyjnA?A`i-NKkef{+Y?Xfw_o%G*R{JPT>Q3lilnB5wWqYKA}fA#oY_vt zr9$#_RZM1mR8hYzS<$KG9F{;G$Kd%3Wy_flSS-oTk%+$R1(Q^ePZ=Y}k?~9xSTtMN z!jk4%UZDDwlUM87i!dtF-NQwrE!v3O(q<*PcS|QNTDyrVM)IZ0K4wc4!~6Jp9`@#$ zVtDpWyQ$Jra`BX`nvI56%?%a;+`3m=l%G#In|Ax!9-RgjNlcG>s!%*G;X;dLVrfm% zNuoA`8&!y=eccS|<<3lxP0g9Z&8y*IHMVtXtUNWnb$ZWKd2&bF$=SXc*y8rJy4^EA z+P%n5&-%EBZ8HVoK-FuuOy5SyPC?h^5Tuir5G}px^gD=8FJh+!gbYQ!l4F408D?%N z&2Hv^rnZmYxpP$Osq@5;;z(x_uNV(_;KqALWv*6G6&Wb}np(GEV6e6W2kfe%8Y~TM zV0+iX>_))Rqn2~k$Z(VqpP$;EU^$69V~IHtsd^&;iRiS{Qb~-i52tc^lru$Hbj#Hm z9tRz_prlv5N^32)(3l{d%emmDCsmE(|y4e+rF!vMB)uNBy2X8NXJXG z)Aj6*RzqBkd1V~cyJ=@fi4<>moX&K|6Bp6m;bRx7OK9i#QYAVbLYb}2hO}(iH96AA z!Mocu<bb4{F3|m<8TWrim~`=hLLPzIYrll2`d$UL*(QZgJ5C zCK14GBWYYpUh;M?=l1ySB_b~SvTq~}>H!$q(CO9kWB&h%i4CPf>zA)z770sF# +#include +#include "addr_hash.h" +#include "hash.h" + +#define hash_table_size 256 + +int compare(void* a, void* b) { + addr_pair* aa = (addr_pair*)a; + addr_pair* bb = (addr_pair*)b; + return (aa->src.s_addr == bb->src.s_addr + && aa->dst.s_addr == bb->dst.s_addr); +} + +int hash(void* key) { + int hash; + long addr; + addr_pair* ap = (addr_pair*)key; + + addr = (long)ap->src.s_addr; + + hash = ((addr & 0x000000FF) + + (addr & 0x0000FF00 >> 8) + + (addr & 0x00FF0000 >> 16) + + (addr & 0xFF000000 >> 24)) % 0xFF; + + addr = (long)ap->dst.s_addr; + hash += ((addr & 0x000000FF) + + (addr & 0x0000FF00 >> 8) + + (addr & 0x00FF0000 >> 16) + + (addr & 0xFF000000 >> 24)) % 0xFF; + + return hash; +} + +void* copy_key(void* orig) { + addr_pair* copy = malloc(sizeof(addr_pair)); + if(copy == NULL) { + printf("Out of memory\n"); + exit(1); + } + *copy = *(addr_pair*)orig; + return copy; +} + +void delete_key(void* key) { + free(key); +} + +/* + * Allocate and return a hash + */ +hash_type* addr_hash_create() { + hash_type* hash_table; + if ((hash_table = calloc(hash_table_size, sizeof(hash_type*))) == 0) { + fprintf (stderr, "out of memory (hashTable)\n"); + exit(1); + } + hash_table->size = hash_table_size; + hash_table->compare = &compare; + hash_table->hash = &hash; + hash_table->delete_key = &delete_key; + hash_table->copy_key = ©_key; + hash_initialise(hash_table); + return hash_table; +} + diff --git a/addr_hash.h b/addr_hash.h new file mode 100644 index 0000000..4d666e9 --- /dev/null +++ b/addr_hash.h @@ -0,0 +1,23 @@ +/* + * addr_hash.h: + * + */ + +#ifndef __ADDR_HASH_H_ /* include guard */ +#define __ADDR_HASH_H_ + +#include +#include +#include +#include "hash.h" + +typedef struct { + struct in_addr src; + struct in_addr dst; +} addr_pair; + +typedef addr_pair key_type; /* index into hash table */ + +hash_type* addr_hash_create(); + +#endif /* __ADDR_HASH_H_ */ diff --git a/hash.c b/hash.c new file mode 100644 index 0000000..6f2a77d --- /dev/null +++ b/hash.c @@ -0,0 +1,112 @@ +/* hash table */ + +#include +#include +#include "hash.h" + +hash_status_enum hash_insert(hash_type* hash_table, void* key, void* rec) { + hash_node_type *p, *p0; + int bucket; + + /************************************************ + * allocate node for data and insert in table * + ************************************************/ + + + /* insert node at beginning of list */ + bucket = hash_table->hash(key); + if ((p = malloc(sizeof(hash_node_type))) == 0) + return HASH_STATUS_MEM_EXHAUSTED; + p0 = hash_table->table[bucket]; + hash_table->table[bucket] = p; + p->next = p0; + p->key = hash_table->copy_key(key); + p->rec = rec; + return HASH_STATUS_OK; +} + +hash_status_enum hash_delete(hash_type* hash_table, void* key) { + hash_node_type *p0, *p; + int bucket; + + /******************************************** + * delete node containing data from table * + ********************************************/ + + /* find node */ + p0 = 0; + bucket = hash_table->hash(key); + p = hash_table->table[bucket]; + while (p && !hash_table->compare(p->key, key)) { + p0 = p; + p = p->next; + } + if (!p) return HASH_STATUS_KEY_NOT_FOUND; + + /* p designates node to delete, remove it from list */ + if (p0) + /* not first node, p0 points to previous node */ + p0->next = p->next; + else + /* first node on chain */ + hash_table->table[bucket] = p->next; + + hash_table->delete_key(p->key); + free (p); + return HASH_STATUS_OK; +} + +hash_status_enum hash_find(hash_type* hash_table, void* key, void **rec) { + hash_node_type *p; + + /******************************* + * find node containing data * + *******************************/ + p = hash_table->table[hash_table->hash(key)]; + while (p && !hash_table->compare(p->key, key)) + p = p->next; + if (!p) return HASH_STATUS_KEY_NOT_FOUND; + *rec = p->rec; + return HASH_STATUS_OK; +} + +hash_status_enum hash_next_item(hash_type* hash_table, hash_node_type** ppnode) { + int i; + if(*ppnode != NULL) { + if((*ppnode)->next != NULL) { + *ppnode = (*ppnode)->next; + return HASH_STATUS_OK; + } + i = hash_table->hash((*ppnode)->key) + 1; + } + else { + /* first node */ + i = 0; + } + while(i < hash_table->size && hash_table->table[i] == NULL) { + i++; + } + if(i == hash_table->size) { + *ppnode = NULL; + return HASH_STATUS_KEY_NOT_FOUND; + } + *ppnode = hash_table->table[i]; + return HASH_STATUS_OK; +} + +/* + * Allocate and return a hash + */ +hash_status_enum hash_initialise(hash_type* hash_table) { + if ((hash_table->table = calloc(hash_table->size, sizeof(hash_node_type *))) == 0) { + fprintf (stderr, "out of memory (hash_table)\n"); + return HASH_STATUS_MEM_EXHAUSTED; + } + return HASH_STATUS_OK; +} + +hash_status_enum hash_destroy(hash_type* hash_table) { + free(hash_table->table); + return HASH_STATUS_OK; +} + diff --git a/hash.h b/hash.h new file mode 100644 index 0000000..b8f0d7b --- /dev/null +++ b/hash.h @@ -0,0 +1,39 @@ +/* + * addr_hash.h: + * + */ + +#ifndef __HASH_H_ /* include guard */ +#define __HASH_H_ + +/* implementation independent declarations */ +typedef enum { + HASH_STATUS_OK, + HASH_STATUS_MEM_EXHAUSTED, + HASH_STATUS_KEY_NOT_FOUND +} hash_status_enum; + +typedef struct node_tag { + struct node_tag *next; /* next node */ + void* key; /* key */ + void* rec; /* user data */ +} hash_node_type; + +typedef struct { + int (*compare) (void*, void*); + int (*hash) (void*); + void* (*copy_key) (void*); + void (*delete_key) (void*); + hash_node_type** table; + int size; +} hash_type; + + +hash_status_enum hash_initialise(hash_type*); +hash_status_enum hash_destroy(hash_type*); +hash_status_enum hash_insert(hash_type*, void* key, void *rec); +hash_status_enum hash_delete(hash_type* hash_table, void* key); +hash_status_enum hash_find(hash_type* hash_table, void* key, void** rec); +hash_status_enum hash_next_item(hash_type* hash_table, hash_node_type** ppnode); + +#endif /* __HASH_H_ */ diff --git a/iftop.c b/iftop.c new file mode 100644 index 0000000..030dced --- /dev/null +++ b/iftop.c @@ -0,0 +1,172 @@ +/* + * iftop.c: + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iftop.h" +#include "addr_hash.h" +#include "resolver.h" +#include "ui.h" + + + +hash_type* history; +time_t last_timestamp; +int history_pos = 0; +int history_len = 1; +pthread_mutex_t tick_mutex; + + + +#define CAPTURE_LENGTH 512 + +void init_history() { + history = addr_hash_create(); + last_timestamp = time(NULL); +} + +history_type* history_create() { + history_type* h; + if ((h = calloc(1, sizeof(history_type))) == 0) { + fprintf (stderr, "out of memory (history_type)\n"); + exit(1); + } + return h; +} + +void history_rotate() { + hash_node_type* n = NULL; + history_pos = (history_pos + 1) % HISTORY_LENGTH; + hash_next_item(history, &n); + while(n != NULL) { + hash_node_type* next = n; + history_type* d = (history_type*)n->rec; + hash_next_item(history, &next); + + if(d->last_write == history_pos) { + addr_pair key = *(addr_pair*)(n->key); + hash_delete(history, &key); + } + else { + d->recv[history_pos] = 0; + d->sent[history_pos] = 0; + } + n = next; + } + if(history_len < HISTORY_LENGTH) { + history_len++; + } +} + + +void tick() { + time_t t; + + pthread_mutex_lock(&tick_mutex); + + t = time(NULL); + if(t - last_timestamp >= RESOLUTION) { + //printf("TICKING\n"); + ui_print(); + history_rotate(); + last_timestamp = t; + } + + pthread_mutex_unlock(&tick_mutex); +} + +static void handle_packet(char* args, const struct pcap_pkthdr* pkthdr,const char* packet) +{ + struct ether_header *eptr; + eptr = (struct ether_header*)packet; + + tick(); + + if(ntohs(eptr->ether_type) == ETHERTYPE_IP) { + struct ip* iptr = (struct ip*)(packet + sizeof(struct ether_header)); + history_type* ht; + addr_pair ap; + + if(iptr->ip_src.s_addr < iptr->ip_dst.s_addr) { + ap.src = iptr->ip_src; + ap.dst = iptr->ip_dst; + } + else { + ap.src = iptr->ip_dst; + ap.dst = iptr->ip_src; + } + + /* Add the address to be resolved */ + resolve(&iptr->ip_dst, NULL, 0); + + if(hash_find(history, &ap, (void**)&ht) == HASH_STATUS_KEY_NOT_FOUND) { + ht = history_create(); + hash_insert(history, &ap, ht); + } + + /* Update record */ + ht->last_write = history_pos; + if(iptr->ip_src.s_addr < iptr->ip_dst.s_addr) { + ht->recv[history_pos] += ntohs(iptr->ip_len); + } + else { + ht->sent[history_pos] += ntohs(iptr->ip_len); + } + + } + fflush(stdout); +} + +/* + * packet capture thread + */ +void packet_loop(void* ptr) { + char errbuf[PCAP_ERRBUF_SIZE]; + char* device; + pcap_t* pd; + + resolver_initialise(); + + device = pcap_lookupdev(errbuf); + printf("Device: %s\n",device); + pd = pcap_open_live(device,CAPTURE_LENGTH,1,1000,errbuf); + if(pd == NULL) { + printf("pcap_open_live(): %s\n",errbuf); + exit(1); + } + printf("Begin loop\n"); + init_history(); + pcap_loop(pd,0,(pcap_handler)handle_packet,NULL); + printf("end loop\n"); +} + +static void finish(int sig) +{ + ui_finish(); + exit(0); +} + +int main(int argc, char **argv) { + pthread_t thread; + + (void) signal(SIGINT, finish); /* arrange interrupts to terminate */ + + pthread_mutex_init(&tick_mutex, NULL); + + pthread_create(&thread, NULL, (void*)&packet_loop, NULL); + + ui_loop(); + + return 0; +} diff --git a/iftop.h b/iftop.h new file mode 100644 index 0000000..2b75394 --- /dev/null +++ b/iftop.h @@ -0,0 +1,21 @@ +/* + * iftop.h: + * + */ + +#ifndef __IFTOP_H_ /* include guard */ +#define __IFTOP_H_ + +/* 5 * 60 / 3 */ +#define HISTORY_LENGTH 100 +#define RESOLUTION 3 + +typedef struct { + long recv[HISTORY_LENGTH]; + long sent[HISTORY_LENGTH]; + int last_write; +} history_type; + +void tick(); + +#endif /* __IFTOP_H_ */ diff --git a/ns_hash.c b/ns_hash.c new file mode 100644 index 0000000..bee461e --- /dev/null +++ b/ns_hash.c @@ -0,0 +1,64 @@ +/* hash table */ + +#include +#include +#include +#include +#include +#include "ns_hash.h" +#include "hash.h" + +#define hash_table_size 256 + +int ns_hash_compare(void* a, void* b) { + struct in_addr* aa = (struct in_addr*)a; + struct in_addr* bb = (struct in_addr*)b; + return (aa->s_addr == bb->s_addr); +} + +int ns_hash_hash(void* key) { + int hash; + long addr; + + addr = (long)((struct in_addr*)key)->s_addr; + + hash = ((addr & 0x000000FF) + + (addr & 0x0000FF00 >> 8) + + (addr & 0x00FF0000 >> 16) + + (addr & 0xFF000000 >> 24)) % 0xFF; + + return hash; +} + +void* ns_hash_copy_key(void* orig) { + struct in_addr* copy = malloc(sizeof(struct in_addr)); + if(copy == NULL) { + printf("Out of memory\n"); + exit(1); + } + *copy = *(struct in_addr*)orig; + return copy; +} + +void ns_hash_delete_key(void* key) { + free(key); +} + +/* + * Allocate and return a hash + */ +hash_type* ns_hash_create() { + hash_type* hash_table; + if ((hash_table = calloc(hash_table_size, sizeof(hash_type*))) == 0) { + fprintf (stderr, "out of memory (hashTable)\n"); + exit(1); + } + hash_table->size = hash_table_size; + hash_table->compare = &ns_hash_compare; + hash_table->hash = &ns_hash_hash; + hash_table->delete_key = &ns_hash_delete_key; + hash_table->copy_key = &ns_hash_copy_key; + hash_initialise(hash_table); + return hash_table; +} + diff --git a/ns_hash.h b/ns_hash.h new file mode 100644 index 0000000..be644cd --- /dev/null +++ b/ns_hash.h @@ -0,0 +1,18 @@ +/* + * ns_hash.h: + * + * Copyright (c) 2002 DecisionSoft Ltd. + * + */ + +#ifndef __NS_HASH_H_ /* include guard */ +#define __NS_HASH_H_ + +#include +#include +#include +#include "hash.h" + +hash_type* ns_hash_create(); + +#endif /* __NS_HASH_H_ */ diff --git a/resolver.c b/resolver.c new file mode 100644 index 0000000..6ceee19 --- /dev/null +++ b/resolver.c @@ -0,0 +1,143 @@ +/* + * resolver.c: + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ns_hash.h" + +#define RESOLVE_QUEUE_LENGTH 20 + +struct in_addr resolve_queue[RESOLVE_QUEUE_LENGTH]; + +pthread_cond_t resolver_queue_cond; +pthread_mutex_t resolver_queue_mutex; +pthread_mutex_t resolver_queue_access_mutex; + +hash_type* ns_hash; + +int head; +int tail; + +void resolver_worker(void* ptr) { + struct timespec delay; + delay.tv_sec = 0; + delay.tv_nsec = 500; + while(1) { + /* Wait until we are told that an address has been added to the + * queue + */ + pthread_cond_wait(&resolver_queue_cond, &resolver_queue_mutex); + + /* Keep resolving until the queue is empty */ + pthread_mutex_lock(&resolver_queue_access_mutex); + while(head != tail) { + struct in_addr addr = resolve_queue[tail]; + struct hostent hostbuf, *hp; + size_t hstbuflen; + char *tmphstbuf; + int res; + int herr; + + /* mutex always locked at this point */ + + tail = (tail + 1) % RESOLVE_QUEUE_LENGTH; + + pthread_mutex_unlock(&resolver_queue_access_mutex); + + + hstbuflen = 1024; + /* Allocate buffer, remember to free it to avoid memory leakage. */ + tmphstbuf = malloc (hstbuflen); + + while ((res = gethostbyaddr_r (&addr, sizeof(addr), AF_INET, + &hostbuf, tmphstbuf, hstbuflen, + &hp, &herr)) == ERANGE) { + /* Enlarge the buffer. */ + hstbuflen *= 2; + tmphstbuf = realloc (tmphstbuf, hstbuflen); + } + + /* + * Store the result in ns_hash + */ + pthread_mutex_lock(&resolver_queue_access_mutex); + + /* Check for errors. */ + if (res || hp == NULL) { + /* failed */ + //printf("[ Did not resolve %s ]\n", inet_ntoa(addr)); + /* Leave the unresolved IP in the hash */ + } + else { + /* success */ + char* hostname; + //printf("[ Resolved: %s ]\n", hp->h_name); + if(hash_find(ns_hash, &addr, (void**)&hostname) == HASH_STATUS_OK) { + hash_delete(ns_hash, &addr); + free(hostname); + } + else { + //printf("[ Warning: Could not find hash entry for key: %s ]\n", inet_ntoa(addr)); + } + hostname = strdup(hp->h_name); + hash_insert(ns_hash, &addr, (void*)hostname); + + } + free(tmphstbuf); + } + pthread_mutex_unlock(&resolver_queue_access_mutex); + } +} + +void resolver_initialise() { + pthread_t thread; + head = tail = 0; + + ns_hash = ns_hash_create(); + + pthread_mutex_init(&resolver_queue_mutex, NULL); + pthread_mutex_init(&resolver_queue_access_mutex, NULL); + pthread_cond_init(&resolver_queue_cond, NULL); + + pthread_create(&thread, NULL, (void*)&resolver_worker, NULL); + +} + +void resolve(struct in_addr* addr, char* result, int buflen) { + char* hostname; + + pthread_mutex_lock(&resolver_queue_access_mutex); + + if(hash_find(ns_hash, addr, (void**)&hostname) == HASH_STATUS_OK) { + /* Found => already resolved, or on the queue */ + } + else { + hostname = strdup(inet_ntoa(*addr)); + hash_insert(ns_hash, addr, hostname); + + if(((head + 1) % RESOLVE_QUEUE_LENGTH) == tail) { + /* queue full */ + } + else { + resolve_queue[head] = *addr; + head = (head + 1) % RESOLVE_QUEUE_LENGTH; + pthread_cond_signal(&resolver_queue_cond); + } + } + pthread_mutex_unlock(&resolver_queue_access_mutex); + + if(result != NULL && buflen > 1) { + strncpy(result, hostname, buflen - 1); + result[buflen - 1] = '\0'; + } +} diff --git a/resolver.h b/resolver.h new file mode 100644 index 0000000..efad57c --- /dev/null +++ b/resolver.h @@ -0,0 +1,15 @@ +/* + * resolver.h: + * + */ + +#ifndef __RESOLVER_H_ /* include guard */ +#define __RESOLVER_H_ + +#include + +void resolver_initialise(); + +void resolve(struct in_addr* addr, char* result, int buflen); + +#endif /* __RESOLVER_H_ */ diff --git a/sorted_list.c b/sorted_list.c new file mode 100644 index 0000000..50d0b06 --- /dev/null +++ b/sorted_list.c @@ -0,0 +1,59 @@ +/* + * sorted_list.c: + * + */ + +#include +#include +#include "sorted_list.h" + + +void sorted_list_insert(sorted_list_type* list, void* item) { + sorted_list_node *node, *p; + + p = &(list->root); + + while(p->next != NULL && list->compare(item, p->next->data) > 0) { + p = p->next; + } + + node = (sorted_list_node*)malloc(sizeof(sorted_list_node)); + if(node == NULL) { + fprintf(stderr,"Out of memory\n"); + exit(1); + } + + node->next = p->next; + node->data = item; + p->next = node; +} + + +sorted_list_node* sorted_list_next_item(sorted_list_type* list, sorted_list_node* prev) { + if(prev == NULL) { + return list->root.next; + } + else { + return prev->next; + } +} + +void sorted_list_destroy(sorted_list_type* list) { + sorted_list_node *p, *n; + p = list->root.next; + + while(p != NULL) { + n = p->next; + free(p); + p = n; + } + + list->root.next = NULL; +} + +void sorted_list_initialise(sorted_list_type* list) { + list->root.next = NULL; +} + + + diff --git a/sorted_list.h b/sorted_list.h new file mode 100644 index 0000000..734e69b --- /dev/null +++ b/sorted_list.h @@ -0,0 +1,25 @@ +/* + * sorted_list.h: + * + */ + +#ifndef __SORTED_LIST_H_ /* include guard */ +#define __SORTED_LIST_H_ + +typedef struct sorted_list_node_tag { + struct sorted_list_node_tag* next; + void* data; +} sorted_list_node; + +typedef struct { + sorted_list_node root; + int (*compare)(void*, void*); +} sorted_list_type; + +void sorted_list_initialise(sorted_list_type* list); +void sorted_list_insert(sorted_list_type* list, void* item); +sorted_list_node* sorted_list_next_item(sorted_list_type* list, sorted_list_node* prev); +void sorted_list_destroy(sorted_list_type* list); + + +#endif /* __SORTED_LIST_H_ */ diff --git a/ui.c b/ui.c new file mode 100644 index 0000000..9e76212 --- /dev/null +++ b/ui.c @@ -0,0 +1,153 @@ +/* + * ui.c: + * + */ + +#include +#include +#include +#include +#include "addr_hash.h" +#include "iftop.h" +#include "resolver.h" +#include "sorted_list.h" + +#define HOSTNAME_LENGTH 20 + +#define HISTORY_DIVISIONS 3 + +int history_divs[HISTORY_DIVISIONS] = {3, 20, 40}; + + +typedef struct host_pair_line_tag { + addr_pair* ap; + long recv[HISTORY_DIVISIONS]; + long sent[HISTORY_DIVISIONS]; +} host_pair_line; + + +extern hash_type* history; +extern int history_pos; +extern int history_len; + +int screen_line_compare(void* a, void* b) { + host_pair_line* aa = (host_pair_line*)a; + host_pair_line* bb = (host_pair_line*)b; + return(aa->recv[0] + aa->sent[0] < bb->recv[0] + bb->sent[0]); +} + +void readable_size(float n, char* buf, int bsize) { + if(n >= 102400) { + snprintf(buf, bsize, " %4.1fM", n / (1024 * 1024)); + } + else if(n >= 1024) { + snprintf(buf, bsize, " %4.1fK", n / 1024); + } + else { + snprintf(buf, bsize, " %4.0fb", n ); + } +} + +void ui_print() { + hash_node_type* n = NULL; + sorted_list_node* nn = NULL; + char hostname[HOSTNAME_LENGTH]; + char line[80]; // FIXME + int y = 2; + sorted_list_type screen_list; + + screen_list.compare = &screen_line_compare; + sorted_list_initialise(&screen_list); + + erase(); + + while(hash_next_item(history, &n) == HASH_STATUS_OK) { + history_type* d = (history_type*)n->rec; + host_pair_line* screen_line; + int i; + + screen_line = (host_pair_line*)calloc(1,sizeof(host_pair_line)); + screen_line->ap = (addr_pair*)n->key; + + for(i = 0; i < HISTORY_LENGTH; i++) { + int j; + int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH; + for(j = 0; j < HISTORY_DIVISIONS; j++) { + if(i < history_divs[j]) { + screen_line->recv[j] += d->recv[ii]; + screen_line->sent[j] += d->sent[ii]; + } + } + } + + sorted_list_insert(&screen_list, screen_line); + } + + while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) { + int x = 0; + int j; + host_pair_line* screen_line = (host_pair_line*)nn->data; + + resolve(&screen_line->ap->src, hostname, HOSTNAME_LENGTH); + sprintf(line, "%s ", hostname); + mvaddstr(y, x, line); + x += 20; + + resolve(&screen_line->ap->dst, hostname, HOSTNAME_LENGTH); + sprintf(line ,"=> %10s ", hostname); + mvaddstr(y, x, line); + x += 24; + + for(j = 0; j < HISTORY_DIVISIONS; j++) { + int t; + if(history_len < history_divs[j]) { + t = history_len * RESOLUTION; + } + else { + t = history_divs[j] * RESOLUTION; + } + readable_size(screen_line->sent[j] / t, line, 10); + mvaddstr(y, x, line); + x += strlen(line); + + readable_size(screen_line->recv[j] / t, line, 10); + mvaddstr(y, x, line); + x += strlen(line); + } + y++; + free(screen_line); + } + refresh(); + + sorted_list_destroy(&screen_list); +} + +void ui_loop() { + pthread_mutex_t tick_wait_mutex; + pthread_cond_t tick_wait_cond; + + + (void) initscr(); /* initialize the curses library */ + keypad(stdscr, TRUE); /* enable keyboard mapping */ + (void) nonl(); /* tell curses not to do NL->CR/NL on output */ + (void) cbreak(); /* take input chars one at a time, no wait for \n */ + (void) noecho(); /* don't echo input */ + + + pthread_mutex_init(&tick_wait_mutex, NULL); + pthread_cond_init(&tick_wait_cond, NULL); + while(1) { + struct timespec t; + t.tv_sec = time(NULL) + 1; + t.tv_nsec = 0; + + pthread_cond_timedwait(&tick_wait_cond, &tick_wait_mutex, &t); + //fprintf(stderr,"timeout tick\n"); + tick(); + } + +} + +void ui_finish() { + endwin(); +} diff --git a/ui.h b/ui.h new file mode 100644 index 0000000..723f811 --- /dev/null +++ b/ui.h @@ -0,0 +1,14 @@ +/* + * ui.h: + * + * + */ + +#ifndef __UI_H_ /* include guard */ +#define __UI_H_ + +void ui_print(); +void ui_loop(); +void ui_finish(); + +#endif /* __UI_H_ */