commit 3004ea063cbb186a63af99a2e13d7cb09f23360d Author: pdw <> Date: Sun Mar 24 16:22:26 2002 +0000 iftop diff --git a/.iftop.h.swp b/.iftop.h.swp new file mode 100644 index 0000000..641503e Binary files /dev/null and b/.iftop.h.swp differ diff --git a/.ui.c.swp b/.ui.c.swp new file mode 100644 index 0000000..e7fc685 Binary files /dev/null and b/.ui.c.swp differ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d606e77 --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +# Makefile: + +#CC = gcc + +CFLAGS += -g -Wall -I/usr/local/include +LDFLAGS += -g + +LDLIBS += -L/usr/local/lib -lpcap -lpthread -lcurses + +SRCS = iftop.c \ + addr_hash.c \ + hash.c \ + ns_hash.c \ + resolver.c \ + ui.c \ + sorted_list.c + +OBJS = $(SRCS:.c=.o) + +HDRS = addr_hash.h + +# If you do not have makedepend, you will need to remove references to depend +# and nodepend below. +iftop: depend $(OBJS) Makefile + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) + +%.o: %.c Makefile + $(CC) $(CFLAGS) -c -o $@ $< + +clean: nodepend + rm -f *~ *.o core iftop + +tags : + etags *.c *.h + +depend: + makedepend -- $(CFLAGS) -- $(SRCS) + touch depend + +nodepend: + makedepend -- -- + rm -f depend + +# DO NOT DELETE + + diff --git a/addr_hash.c b/addr_hash.c new file mode 100644 index 0000000..2040083 --- /dev/null +++ b/addr_hash.c @@ -0,0 +1,69 @@ +/* hash table */ + +#include +#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_ */