X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Flibtcp-portmon.c;h=bedcae5f51a58d401dd60ce1fd759d3497741be5;hb=841c0c962fd208c69a21f4f278167dde597dc278;hp=7b3a3dcdb1ac996587aefcc8e718798146928578;hpb=35f5de56b2b00e2b9956fe598515ebe324064b39;p=monky diff --git a/src/libtcp-portmon.c b/src/libtcp-portmon.c index 7b3a3dc..bedcae5 100644 --- a/src/libtcp-portmon.c +++ b/src/libtcp-portmon.c @@ -1,9 +1,9 @@ -/* ------------------------------------------------------------------------- - * libtcp-portmon.c: tcp port monitoring library. +/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=c * - * Copyright (C) 2005 Philip Kovacs kovacsp3@comcast.net - * - * $Id$ + * libtcp-portmon.c: tcp port monitoring library. + * + * Copyright (C) 2005-2007 Philip Kovacs pkovacs@users.sourceforge.net * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,10 +17,17 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * --------------------------------------------------------------------------- */ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif #include "libtcp-portmon.h" +#include /* ------------------------------------------------------------------- * IMPLEMENTATION INTERFACE @@ -30,507 +37,393 @@ * functions. Use the "Client interface" functions defined at bottom. * ------------------------------------------------------------------- */ -/* ----------------------------------------------------------------------------- - * Open-addressed hash implementation requires that we supply two hash functions - * and a match function to compare two hash elements for identity. - * ----------------------------------------------------------------------------- */ - -/* -------------------------------------------------- - * Functions to hash the connections within a monitor - * --------------------------------------------------*/ - -#define CONNECTION_HASH_KEY_LEN 17 - -/* ---------------------------------------------------------------------------------- - * First connection hash function: DJB with a 65521 prime modulus to govern the range. - * ----------------------------------------------------------------------------------*/ -int connection_hash_function_1( const void *p_data ) +/* ----------------------------------- + * Copy a tcp_connection_t + * + * Returns 0 on success, -1 otherwise. + * ----------------------------------- */ +int copy_tcp_connection(tcp_connection_t *p_dest_connection, + const tcp_connection_t *p_source_connection) { - tcp_connection_t *p_conn; - char key[CONNECTION_HASH_KEY_LEN]; - unsigned int hash = 5381; - unsigned int i = 0; - - if ( !p_data ) - return -1; - - memset(key,0,sizeof(key)); - - /* p_data is a pointer to tcp_connection_t */ - p_conn = (tcp_connection_t *)p_data; - - /* key is a hex representation of the connection */ - snprintf(key, CONNECTION_HASH_KEY_LEN, "%08X%04X%04X", - p_conn->remote_addr, p_conn->remote_port, p_conn->local_port); -#ifdef HASH_DEBUG - fprintf(stderr,"--- key=[%s]\n",key); -#endif + if (!p_dest_connection || !p_source_connection) { + return -1; + } - for(i = 0; i < CONNECTION_HASH_KEY_LEN-1; i++) - { - hash = ((hash << 5) + hash) + (key[i]); - } + p_dest_connection->local_addr = p_source_connection->local_addr; + p_dest_connection->local_port = p_source_connection->local_port; + p_dest_connection->remote_addr = p_source_connection->remote_addr; + p_dest_connection->remote_port = p_source_connection->remote_port; + p_dest_connection->age = p_source_connection->age; - return (hash & 0x7FFFFFFF) % 65521; + return 0; } -/* ------------------------------------------------------------------------- - * Second connection hash function: DEK, modified to return odd numbers only, - * as required for open-address hashing using double-hash probing. - * Also uses a 65521 prime modulus to govern the range. - * -------------------------------------------------------------------------*/ -int connection_hash_function_2( const void *p_data ) +/* ------------------------------------------- + * Port monitor utility functions implementing + * tcp_port_monitor_function_ptr_t + * ------------------------------------------- */ +void destroy_tcp_port_monitor(tcp_port_monitor_t *p_monitor, void *p_void) { - tcp_connection_t *p_conn; - char key[CONNECTION_HASH_KEY_LEN]; - unsigned int hash = CONNECTION_HASH_KEY_LEN-1; - unsigned int i = 0; + tcp_connection_node_t *p_node, *p_temp; - if ( !p_data ) - return -1; + if (!p_monitor || p_void) { /* p_void should be NULL in this context */ + return; + } - memset(key,0,sizeof(key)); + /* destroy the monitor's peek array */ + free(p_monitor->p_peek); - /* p_data is a pointer to a tcp_connection_t */ - p_conn = (tcp_connection_t *)p_data; + /* destroy the monitor's connection list */ + for (p_node = p_monitor->connection_list.p_head; p_node != NULL; ) { + /* p_temp is for the next iteration */ + p_temp = p_node->p_next; - /* key is a hex representation of the connection */ - snprintf(key, CONNECTION_HASH_KEY_LEN, "%08X%04X%04X", - p_conn->remote_addr, p_conn->remote_port, p_conn->local_port); + free(p_node); - for(i = 0; i < CONNECTION_HASH_KEY_LEN-1; i++) - { - hash = ((hash << 5) ^ (hash >> 27)) ^ (key[i]); - } - return (( hash & 0x7FFFFFFF ) % 65521 ) | 0x00000001; -} + p_node = p_temp; + } -/* ------------------------------------------------------------------------- - * Connection Match function returns non-zero if hash elements are identical. - * -------------------------------------------------------------------------*/ -int connection_match_function( const void *p_data1, const void *p_data2 ) -{ - tcp_connection_t *p_conn1, *p_conn2; - - if ( !p_data1 || !p_data2 ) - return 0; - - /* p_data1, p_data2 are pointers to tcp_connection_t */ - p_conn1 = (tcp_connection_t *)p_data1; - p_conn2 = (tcp_connection_t *)p_data2; - - return (p_conn1->local_addr == p_conn2->local_addr && - p_conn1->local_port == p_conn2->local_port && - p_conn1->remote_addr == p_conn2->remote_addr && - p_conn1->remote_port == p_conn2->remote_port ); + /* destroy the monitor's hash */ + g_hash_table_destroy(p_monitor->hash); + p_monitor->hash = NULL; + + /* destroy the monitor */ + free(p_monitor); + p_monitor = NULL; } -/* -------------------------------------------------- - * Functions to hash the monitors within a collection - * --------------------------------------------------*/ +void age_tcp_port_monitor(tcp_port_monitor_t *p_monitor, void *p_void) +{ + /* Run through the monitor's connections and decrement the age variable. + * If the age goes negative, we remove the connection from the monitor. + * Function takes O(n) time on the number of connections. */ -#define MONITOR_HASH_KEY_LEN 9 + tcp_connection_node_t *p_node, *p_temp; + tcp_connection_t *p_conn; -/* ------------------------------------------------------------------------------- - * First monitor hash function: DJB with a 65521 prime modulus to govern the range. - * -------------------------------------------------------------------------------*/ -int monitor_hash_function_1( const void *p_data ) -{ - tcp_port_monitor_t *p_monitor; - char key[MONITOR_HASH_KEY_LEN]; - unsigned int hash = 5381; - unsigned int i = 0; - - if ( !p_data ) - return -1; - - memset(key,0,sizeof(key)); - - /* p_data is a pointer to tcp_port_monitor_t */ - p_monitor = (tcp_port_monitor_t *)p_data; - - /* key is a hex representation of the starting port concatenated to the ending port */ - snprintf(key, MONITOR_HASH_KEY_LEN, "%04X%04X", - p_monitor->port_range_begin, p_monitor->port_range_end ); -#ifdef HASH_DEBUG - fprintf(stderr,"--- key=[%s]\n",key); -#endif + if (!p_monitor || p_void) { /* p_void should be NULL in this context */ + return; + } - for(i = 0; i < MONITOR_HASH_KEY_LEN-1; i++) - { - hash = ((hash << 5) + hash) + (key[i]); - } + if (!p_monitor->p_peek) { + return; + } - return (hash & 0x7FFFFFFF) % 65521; -} + for (p_node = p_monitor->connection_list.p_head; p_node; ) { + if (--p_node->connection.age >= 0) { + p_node = p_node->p_next; + continue; + } -/* ----------------------------------------------------------------------- - * Second monitor hash function: DEK, modified to return odd numbers only, - * as required for open-address hashing using double-hash probing. - * Also uses a 65521 prime modulus to govern the range. - * -----------------------------------------------------------------------*/ -int monitor_hash_function_2( const void *p_data ) -{ - tcp_port_monitor_t *p_monitor; - char key[MONITOR_HASH_KEY_LEN]; - unsigned int hash = MONITOR_HASH_KEY_LEN-1; - unsigned int i = 0; + /* connection on p_node is old. remove connection from the hash. */ + p_conn = &p_node->connection; +#ifdef HASH_DEBUG + fprintf(stderr, "monitor hash removal of connection [%s]", p_conn->key); + if (!g_hash_table_remove(p_monitor->hash, + (gconstpointer) p_conn->key)) { + fprintf(stderr, " - ERROR NOT FOUND\n"); + return; + } + fprintf(stderr, " - OK\n"); +#else + if (!g_hash_table_remove(p_monitor->hash, + (gconstpointer) p_conn)) { + return; + } +#endif - if ( !p_data ) - return -1; + /* splice p_node out of the connection_list */ + if (p_node->p_prev != NULL) { + p_node->p_prev->p_next = p_node->p_next; + } + if (p_node->p_next != NULL) { + p_node->p_next->p_prev = p_node->p_prev; + } - memset(key,0,sizeof(key)); + /* correct the list head and tail if necessary */ + if (p_monitor->connection_list.p_head == p_node) { + p_monitor->connection_list.p_head = p_node->p_next; + } + if (p_monitor->connection_list.p_tail == p_node) { + p_monitor->connection_list.p_tail = p_node->p_prev; + } - /* p_data is a pointer to a tcp_port_monitor_t */ - p_monitor = (tcp_port_monitor_t *)p_data; + /* p_temp is for the next iteration */ + p_temp = p_node->p_next; - /* key is a hex representation of the starting port concatenated to the ending port */ - snprintf(key, MONITOR_HASH_KEY_LEN, "%04X%04X", - p_monitor->port_range_begin, p_monitor->port_range_end ); + /* destroy the node */ + free(p_node); - for(i = 0; i < MONITOR_HASH_KEY_LEN-1; i++) - { - hash = ((hash << 5) ^ (hash >> 27)) ^ (key[i]); - } - return (( hash & 0x7FFFFFFF ) % 65521 ) | 0x00000001; + p_node = p_temp; + } } -/* ---------------------------------------------------------------------- - * Monitor match function returns non-zero if hash elements are identical. - * ----------------------------------------------------------------------*/ -int monitor_match_function( const void *p_data1, const void *p_data2 ) +void rebuild_tcp_port_monitor_peek_table(tcp_port_monitor_t *p_monitor, + void *p_void) { - tcp_port_monitor_t *p_monitor1, *p_monitor2; + /* Run through the monitor's connections and rebuild the peek table of + * connection pointers. This is done so peeking into the monitor can be + * done in O(1) time instead of O(n) time for each peek. */ + + tcp_connection_node_t *p_node; + int i = 0; - if ( !p_data1 || !p_data2 ) - return 0; + if (!p_monitor || p_void) { /* p_void should be NULL in this context */ + return; + } - /* p_data1, p_data2 are pointers to tcp_connection_t */ - p_monitor1 = (tcp_port_monitor_t *)p_data1; - p_monitor2 = (tcp_port_monitor_t *)p_data2; + /* zero out the peek array */ + memset(p_monitor->p_peek, 0, p_monitor->max_port_monitor_connections * + sizeof(tcp_connection_t *)); - return (p_monitor1->port_range_begin == p_monitor1->port_range_begin && - p_monitor2->port_range_end == p_monitor2->port_range_end); + for (p_node = p_monitor->connection_list.p_head; p_node != NULL; + p_node = p_node->p_next, i++) { + p_monitor->p_peek[i] = &p_node->connection; + } } -/* --------------------------------------------------------------------------- - * Port monitor utility functions implementing tcp_port_monitor_function_ptr_t - * ---------------------------------------------------------------------------*/ -void destroy_tcp_port_monitor( - tcp_port_monitor_t * p_monitor, - void * p_void - ) +void show_connection_to_tcp_port_monitor(tcp_port_monitor_t *p_monitor, + void *p_void) { - tcp_connection_node_t *p_node, *p_temp; + /* The monitor gets to look at each connection to see if it falls within + * the monitor's port range of interest. Connections of interest are first + * looked up in the hash to see if they are already there. If they are, we + * reset the age of the connection so it is not deleted. If the connection + * is not in the hash, we add it, but only if we haven't exceeded the + * maximum connection limit for the monitor. + * The function takes O(1) time. */ + + tcp_connection_node_t *p_node; + tcp_connection_t *p_connection, *p_conn_hash; + + if (!p_monitor || !p_void) { + return; + } - if ( !p_monitor || p_void ) /* p_void should be NULL in this context */ - return; + /* This p_connection is on caller's stack and not the heap. + * If we are interested, we will create a copy of the connection + * (on the heap) and add it to our list. */ + p_connection = (tcp_connection_t *) p_void; - /* destroy the monitor's hash */ - hash_destroy(&p_monitor->hash); + /* inspect the local port number of the connection to see if we're + * interested. */ + if ((p_monitor->port_range_begin <= p_connection->local_port) + && (p_connection->local_port <= p_monitor->port_range_end)) { + /* the connection is in the range of the monitor. */ - /* destroy the monitor's peek array */ - free( p_monitor->p_peek ); + /* first check the hash to see if the connection is already there. */ + if ((p_conn_hash = g_hash_table_lookup(p_monitor->hash, + (gconstpointer) p_connection))) { + /* it's already in the hash. reset the age of the connection. */ + p_conn_hash->age = TCP_CONNECTION_STARTING_AGE; - /* destroy the monitor's connection list */ - for ( p_node=p_monitor->connection_list.p_head; p_node!=NULL; ) - { - /* p_temp is for the next iteration */ - p_temp = p_node->p_next; - - free( p_node ); + return; + } - p_node = p_temp; - } + /* Connection is not yet in the hash. + * Add it if max_connections not exceeded. */ + if (g_hash_table_size(p_monitor->hash) + >= p_monitor->max_port_monitor_connections) { + return; + } - /* destroy the monitor */ - free( p_monitor ); - p_monitor=NULL; -} + /* create a new connection node */ + if ((p_node = (tcp_connection_node_t *) + calloc(1, sizeof(tcp_connection_node_t))) == NULL) { + return; + } -void age_tcp_port_monitor( - tcp_port_monitor_t * p_monitor, - void * p_void - ) -{ - /* Run through the monitor's connections and decrement the age variable. - * If the age goes negative, we remove the connection from the monitor. - * Function takes O(n) time on the number of connections. */ - - tcp_connection_node_t *p_node, *p_temp; - tcp_connection_t *p_conn; - void *p_cast; - - if ( !p_monitor || p_void ) /* p_void should be NULL in this context */ - return; - - if ( !p_monitor->p_peek ) - return; - - for ( p_node = p_monitor->connection_list.p_head; p_node != NULL; ) - { - if ( --p_node->connection.age >= 0 ) { - p_node = p_node->p_next; - continue; - } - - /* connection on p_node is old. remove connection from the hash. */ - p_conn = &p_node->connection; - p_cast = (void *)p_conn; - if ( hash_remove( &p_monitor->hash, &p_cast ) != 0 ) { + /* copy the connection data */ + if (copy_tcp_connection(&p_node->connection, p_connection) != 0) { + /* error copying the connection data. deallocate p_node to + * avoid leaks and return. */ + free(p_node); + return; + } + + p_node->connection.age = TCP_CONNECTION_STARTING_AGE; + p_node->p_next = NULL; + + /* insert it into the monitor's hash table */ #ifdef HASH_DEBUG - fprintf(stderr, "--- hash_remove error\n"); + fprintf(stderr, "monitor hash insert of connection [%s]\n", + p_node->connection.key); #endif - return; - } - - /* splice p_node out of the connection_list */ - if ( p_node->p_prev != NULL ) - p_node->p_prev->p_next = p_node->p_next; - if ( p_node->p_next != NULL ) - p_node->p_next->p_prev = p_node->p_prev; + g_hash_table_insert(p_monitor->hash, + (gpointer) &p_node->connection, (gpointer) &p_node->connection); + + /* append the node to the monitor's connection list */ + if (p_monitor->connection_list.p_tail == NULL) { + /* assume p_head is NULL too */ + p_monitor->connection_list.p_head = p_node; + p_monitor->connection_list.p_tail = p_node; + p_node->p_prev = NULL; + } else { + p_monitor->connection_list.p_tail->p_next = p_node; + p_node->p_prev = p_monitor->connection_list.p_tail; + p_monitor->connection_list.p_tail = p_node; + } + } +} - /* correct the list head and tail if necessary */ - if ( p_monitor->connection_list.p_head == p_node ) - p_monitor->connection_list.p_head = p_node->p_next; - if ( p_monitor->connection_list.p_tail == p_node ) - p_monitor->connection_list.p_tail = p_node->p_prev; +/* ------------------------------------------------------------------------ + * Apply a tcp_port_monitor_function_ptr_t function to each port monitor in + * the collection. + * ------------------------------------------------------------------------ */ +void for_each_tcp_port_monitor_in_collection( + tcp_port_monitor_collection_t *p_collection, + tcp_port_monitor_function_ptr_t p_function, void *p_function_args) +{ + tcp_port_monitor_node_t *p_current_node, *p_next_node; - /* p_temp is for the next iteration */ - p_temp = p_node->p_next; + if (!p_collection || !p_function) { + return; + } - /* destroy the node */ - free( p_node ); + /* for each monitor in the collection */ + for (p_current_node = p_collection->monitor_list.p_head; + p_current_node != NULL; p_current_node = p_next_node) { + p_next_node = p_current_node->p_next; /* do this first! */ - p_node = p_temp; - } + if (p_current_node->p_monitor) { + /* apply the function with the given arguments */ + p_function(p_current_node->p_monitor, p_function_args); + } + } } -void maintain_tcp_port_monitor_hash( - tcp_port_monitor_t * p_monitor, - void * p_void - ) -{ - /* Check the number of vacated slots in the hash. If it exceeds our maximum - * threshold (should be about 1/4 of the hash table), then the hash table - * performance degrades from O(1) toward O(n) as the number of vacated slots - * climbs. This is avoided by clearing the hash and reinserting the entries. - * The benefit of open-addressing hashing does come with this price -- - * you must rebalance it occasionally. */ +static const unsigned char prefix_4on6[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff +}; - tcp_connection_node_t *p_node; - double vacated_load; +union sockaddr_in46 { + struct sockaddr_in sa4; + struct sockaddr_in6 sa6; + struct sockaddr sa; +}; - if ( !p_monitor || p_void ) /* p_void should be NULL in this context */ - return; +/* checks whether the address is a IPv4-mapped IPv6 address */ +static int is_4on6(const struct in6_addr *addr) +{ + return ! memcmp(&addr->s6_addr, prefix_4on6, sizeof(prefix_4on6)); +} - vacated_load = (double)p_monitor->hash.vacated / (double)p_monitor->hash.positions; -#ifdef HASH_DEBUG - fprintf(stderr,"--- num vacated is %d, vacated factor is %.3f\n", p_monitor->hash.vacated, vacated_load ); -#endif - if ( vacated_load <= TCP_CONNECIION_HASH_MAX_VACATED_RATIO ) - { - /* hash is fine and needs no rebalancing */ - return; - } -#ifdef HASH_DEBUG - fprintf(stderr,"--- rebuilding hash\n"); -#endif - - /* rebuild the hash */ - memset( p_monitor->hash.pp_table, 0, p_monitor->hash.positions * sizeof(void **)); - p_monitor->hash.size = 0; - p_monitor->hash.vacated = 0; +/* converts the address to appropriate textual representation (IPv6, IPv4 or fqdn) */ +static void print_host(char *p_buffer, size_t buffer_size, const struct in6_addr *addr, int fqdn) +{ + union sockaddr_in46 sa; + socklen_t slen; + + memset(&sa, 0, sizeof(sa)); + + if(is_4on6(addr)) { + sa.sa4.sin_family = AF_INET; + memcpy(&sa.sa4.sin_addr.s_addr, &addr->s6_addr[12], 4); + slen = sizeof(sa.sa4); + } else { + sa.sa6.sin6_family = AF_INET6; + memcpy(&sa.sa6.sin6_addr, addr, sizeof(struct in6_addr)); + slen = sizeof(sa.sa6); + } - for ( p_node=p_monitor->connection_list.p_head; p_node!=NULL; p_node=p_node->p_next ) - { - if ( hash_insert( &p_monitor->hash, (void *)&p_node->connection ) != 0 ) - { -#ifdef HASH_DEBUG - fprintf(stderr,"--- hash_insert error\n"); -#endif - ; - } - } + getnameinfo(&sa.sa, slen, p_buffer, buffer_size, NULL, 0, fqdn?0:NI_NUMERICHOST); } -void rebuild_tcp_port_monitor_peek_table( - tcp_port_monitor_t * p_monitor, - void * p_void - ) +/* converts the textual representation of an IPv4 or IPv6 address to struct in6_addr */ +static void string_to_addr(struct in6_addr *addr, const char *p_buffer) { - /* Run through the monitori's connections and rebuild the peek table - * of connection pointers. This is done so peeking into the monitor - * can be done in O(1) time instead of O(n) time for each peek. */ - - tcp_connection_node_t *p_node; - int i = 0; + size_t i; - if ( !p_monitor || p_void ) /* p_void should be NULL in this context */ - return; + if(strlen(p_buffer) < 32) { //IPv4 address + i = sizeof(prefix_4on6); + memcpy(addr->s6_addr, prefix_4on6, i); + } else { + i = 0; + } - /* zero out the peek array */ - memset( p_monitor->p_peek, 0, p_monitor->hash.positions * sizeof(tcp_connection_t *) ); + for( ; i < sizeof(addr->s6_addr); i+=4, p_buffer+=8) { + sscanf(p_buffer, "%8x", (unsigned *)&addr->s6_addr[i]); + } +} - for ( p_node=p_monitor->connection_list.p_head; p_node!=NULL; p_node=p_node->p_next, i++ ) - { - p_monitor->p_peek[i] = &p_node->connection; - } +/* hash function for tcp_connections */ +static guint tcp_connection_hash(gconstpointer A) +{ + const tcp_connection_t *a = (const tcp_connection_t *) A; + guint hash = 0; + size_t i; + + hash = hash*47 + a->local_port; + hash = hash*47 + a->remote_port; + for(i = 0; i < sizeof(a->local_addr.s6_addr); ++i) + hash = hash*47 + a->local_addr.s6_addr[i]; + for(i = 0; i < sizeof(a->remote_addr.s6_addr); ++i) + hash = hash*47 + a->remote_addr.s6_addr[i]; + + return hash; } -void show_connection_to_tcp_port_monitor( - tcp_port_monitor_t * p_monitor, - void * p_void - ) +/* comparison function for tcp_connections */ +static gboolean tcp_connection_equal(gconstpointer A, gconstpointer B) { - /* The monitor gets to look at each connection to see if it falls within - * the monitor's port range of interest. Connections of interest are first - * looked up in the hash to see if they are already there. If they are, we - * reset the age of the connection so it is not deleted. If the connection - * is not in the hash, we add it, but only if the hash is not saturated. - * The function takes O(1) time. */ - - tcp_connection_node_t *p_node; - void *p_cast; - - if ( !p_monitor || !p_void ) - return; - - tcp_connection_t *p_connection = (tcp_connection_t *)p_void; - - /* inspect the local port number of the connection to see if we're interested. */ - if ( (p_monitor->port_range_begin <= p_connection->local_port) && - (p_connection->local_port <= p_monitor->port_range_end) ) - { - /* the connection is in the range of the monitor. */ - - /* first check the hash to see if the connection is already there. */ - p_cast = (void *)p_connection; - if ( hash_lookup( &p_monitor->hash, &p_cast ) == 0 ) - { - p_connection = (tcp_connection_t *)p_cast; - /* it's already in the hash. reset the age of the connection. */ - if ( p_connection != NULL ) - { - p_connection->age = TCP_CONNECIION_STARTING_AGE; - } + const tcp_connection_t *a = (const tcp_connection_t *) A; + const tcp_connection_t *b = (const tcp_connection_t *) B; - return; - } + return a->local_port == b->local_port && a->remote_port == b->remote_port && + ! memcmp(&a->local_addr, &b->local_addr, sizeof(a->local_addr)) && + ! memcmp(&a->remote_addr.s6_addr, &b->remote_addr, sizeof(a->remote_addr)); +} - /* Connection is not yet in the hash. We will try to add it, but only if the hash is not - * yet saturated. We assume the hash is saturated (and therefore ignore this connection) - * if our load factor cap is now exceeded. The benefit of limiting connections in this way - * is that the hash will continue to function at an average (1) speed by keeping the load - * load factor down. Of course the downside is that each port monitor has a strict maximum - * connection limit. */ +/* adds connections from file to the collection */ +static void process_file(tcp_port_monitor_collection_t *p_collection, const char *file) +{ + FILE *fp; + char buf[256]; + char local_addr[40]; + char remote_addr[40]; + tcp_connection_t conn; + unsigned long inode, uid, state; - if ( (double)p_monitor->hash.size / (double)p_monitor->hash.positions >= TCP_CONNECTION_HASH_MAX_LOAD_RATIO ) - { - /* hash exceeds our load limit is now "full" */ + if ((fp = fopen(file, "r")) == NULL) { return; } - /* create a new connection node */ - if ( (p_node = (tcp_connection_node_t *) calloc(1, sizeof(tcp_connection_node_t))) == NULL ) - return; - - p_node->connection = *p_connection; /* bitwise copy of the struct */ - p_node->connection.age = TCP_CONNECIION_STARTING_AGE; - p_node->p_next = NULL; - - /* insert it into the monitor's hash table */ - if ( hash_insert( &p_monitor->hash, (void *)&p_node->connection ) != 0 ) - { - /* error inserting into hash. delete the connection node we just created, so no leaks. */ -#ifdef HASH_DEBUG - fprintf(stderr, "--- hash_insert error\n"); -#endif - free(p_node); - return; - } + /* ignore field name line */ + fgets(buf, 255, fp); - /* append the node to the monitor's connection list */ - if ( p_monitor->connection_list.p_tail == NULL ) /* assume p_head is NULL too */ - { - p_monitor->connection_list.p_head = p_node; - p_monitor->connection_list.p_tail = p_node; - p_node->p_prev = NULL; - } - else - { - p_monitor->connection_list.p_tail->p_next = p_node; - p_node->p_prev = p_monitor->connection_list.p_tail; - p_monitor->connection_list.p_tail = p_node; - } - } -} + /* read all tcp connections */ + while (fgets(buf, sizeof(buf), fp) != NULL) { -/* --------------------------------------------------------------------------------------- - * Apply a tcp_port_monitor_function_ptr_t function to each port monitor in the collection. - * ---------------------------------------------------------------------------------------*/ -void for_each_tcp_port_monitor_in_collection( - tcp_port_monitor_collection_t * p_collection, - tcp_port_monitor_function_ptr_t p_function, - void * p_function_args - ) -{ - tcp_port_monitor_node_t * p_current_node, * p_next_node; - - if ( !p_collection || !p_function ) - return; + if (sscanf(buf, + "%*d: %39[0-9a-fA-F]:%hx %39[0-9a-fA-F]:%hx %lx %*x:%*x %*x:%*x %*x %lu %*d %lu", + local_addr, &conn.local_port, + remote_addr, &conn.remote_port, + (unsigned long *) &state, (unsigned long *) &uid, + (unsigned long *) &inode) != 7) { + fprintf(stderr, "/proc/net/tcp: bad file format\n"); + } + /** TCP_ESTABLISHED equals 1, but is not (always??) included **/ + //if ((inode == 0) || (state != TCP_ESTABLISHED)) { + if((inode == 0) || (state != 1)) { + continue; + } - /* for each monitor in the collection */ - for ( p_current_node = p_collection->monitor_list.p_head; p_current_node != NULL; ) - { - p_next_node = p_current_node->p_next; /* do this first! */ + string_to_addr(&conn.local_addr, local_addr); + string_to_addr(&conn.remote_addr, remote_addr); - if ( p_current_node->p_monitor ) - { - /* apply the function with the given arguments */ - (*p_function)( p_current_node->p_monitor, p_function_args ); + /* show the connection to each port monitor. */ + for_each_tcp_port_monitor_in_collection(p_collection, + &show_connection_to_tcp_port_monitor, (void *) &conn); } - p_current_node = p_next_node; - } - + fclose(fp); } -/* ---------------------------------------------------------------------------------------- - * Calculate an efficient hash size based on the desired number of elements and load factor. - * ---------------------------------------------------------------------------------------- */ -int calc_efficient_hash_size( - int min_elements, - int max_hash_size, - double max_load_factor - ) -{ - double min_size, hash_size, log_base_2; - - /* the size of the hash will the smallest power of two such that the minimum number - of desired elements does not exceed the maximum load factor. */ - - min_size = (double)min_elements / max_load_factor; /* starting point */ - - /* now adjust size up to nearest power of two */ - log_base_2 = (double) (int) ( log(min_size) / log(2) ) ; /* lop off fractional portion of log */ - - hash_size = pow(2,log_base_2) >= min_size ? min_size : pow(2,(double)++log_base_2); - - /* respect the maximum */ - hash_size = hash_size <= max_hash_size ? hash_size : max_hash_size; - - /* - fprintf(stderr,"hash size is %d, based on %d min_elements and %.02f max load, %d maximum\n", - (int)hash_size, min_elements, max_load_factor, max_hash_size); - */ - - return hash_size; -} - /* ---------------------------------------------------------------------- - * CLIENT INTERFACE + * CLIENT INTERFACE * * Clients should call only those functions below this line. * ---------------------------------------------------------------------- */ @@ -540,150 +433,133 @@ int calc_efficient_hash_size( * ---------------------------------- */ /* Clients should first try to "find_tcp_port_monitor" before creating one - so that there are no redundant monitors. */ -tcp_port_monitor_t * create_tcp_port_monitor( - in_port_t port_range_begin, - in_port_t port_range_end, - tcp_port_monitor_args_t * p_creation_args - ) + * so that there are no redundant monitors. */ +tcp_port_monitor_t *create_tcp_port_monitor(in_port_t port_range_begin, + in_port_t port_range_end, tcp_port_monitor_args_t *p_creation_args) { - tcp_port_monitor_t * p_monitor; - - /* create the monitor */ - p_monitor = (tcp_port_monitor_t *) calloc(1, sizeof(tcp_port_monitor_t) ); - if ( !p_monitor ) - return NULL; - - /* create the monitor's connection hash */ - if ( hash_create( &p_monitor->hash, - p_creation_args && p_creation_args->min_port_monitor_connections > 0 ? - calc_efficient_hash_size( p_creation_args->min_port_monitor_connections, - TCP_CONNECTION_HASH_SIZE_MAX, - TCP_CONNECTION_HASH_MAX_LOAD_RATIO ) : - TCP_CONNECTION_HASH_SIZE_DEFAULT, - &connection_hash_function_1, &connection_hash_function_2, - &connection_match_function, NULL ) != 0 ) - { - /* we failed to create the hash, so destroy the monitor completely so we don't leak */ - destroy_tcp_port_monitor(p_monitor,NULL); - return NULL; - } - - /* create the monitor's peek array */ - if ( (p_monitor->p_peek = (tcp_connection_t **) calloc( p_monitor->hash.positions, sizeof(tcp_connection_t *))) == NULL ) - { - /* we failed to create the peek array, so destroy the monitor completely, again, so we don't leak */ - destroy_tcp_port_monitor(p_monitor,NULL); - return NULL ; - } - - p_monitor->port_range_begin = port_range_begin; - p_monitor->port_range_end = port_range_end; - - p_monitor->connection_list.p_head = NULL; - p_monitor->connection_list.p_tail = NULL; - - return p_monitor; -} + tcp_port_monitor_t *p_monitor; -/* Clients use this function to get connection data from the indicated port monitor. - The requested monitor value is copied into a client-supplied char buffer. - Returns 0 on success, -1 otherwise. */ -int peek_tcp_port_monitor( - tcp_port_monitor_t * p_monitor, - int item, - int connection_index, - char * p_buffer, - size_t buffer_size - ) -{ - struct hostent *p_hostent; - struct servent *p_servent; - struct in_addr net; + /* create the monitor */ + p_monitor = (tcp_port_monitor_t *) calloc(1, sizeof(tcp_port_monitor_t)); + if (!p_monitor) { + return NULL; + } - if ( !p_monitor || !p_buffer || connection_index < 0 ) - return(-1); + p_monitor->max_port_monitor_connections = + p_creation_args->max_port_monitor_connections; - memset(p_buffer, 0, buffer_size); - memset(&net, 0, sizeof(net)); + /* build the monitor key for the collection hash */ + g_sprintf(p_monitor->key, ":%04X :%04X", port_range_begin, port_range_end); - /* if the connection index is out of range, we simply return with no error - * having first cleared the client-supplied buffer. */ - if ( (item!=COUNT) && (connection_index > p_monitor->hash.size - 1) ) - return(0); - - switch (item) { + /* create the monitor's connection hash */ + if ((p_monitor->hash = g_hash_table_new(tcp_connection_hash, tcp_connection_equal)) == NULL) { + /* we failed to create the hash, so destroy the monitor completely + * so we don't leak */ + destroy_tcp_port_monitor(p_monitor, NULL); + return NULL; + } - case COUNT: - - snprintf( p_buffer, buffer_size, "%d" , p_monitor->hash.size ); - break; + /* create the monitor's peek array */ + if ((p_monitor->p_peek = (tcp_connection_t **) + calloc(p_monitor->max_port_monitor_connections, + sizeof(tcp_connection_t *))) == NULL) { + /* we failed to create the peek array, + * so destroy the monitor completely, again, so we don't leak */ + destroy_tcp_port_monitor(p_monitor, NULL); + return NULL; + } - case REMOTEIP: + p_monitor->port_range_begin = port_range_begin; + p_monitor->port_range_end = port_range_end; - net.s_addr = p_monitor->p_peek[ connection_index ]->remote_addr; - snprintf( p_buffer, buffer_size, "%s", inet_ntoa( net ) ); - break; + p_monitor->connection_list.p_head = NULL; + p_monitor->connection_list.p_tail = NULL; - case REMOTEHOST: + return p_monitor; +} - p_hostent = gethostbyaddr( &p_monitor->p_peek[ connection_index ]->remote_addr, sizeof(in_addr_t), AF_INET); - /* if no host name found, just use ip address. */ - if ( !p_hostent || !p_hostent->h_name ) - { - net.s_addr = p_monitor->p_peek[ connection_index ]->remote_addr; - snprintf( p_buffer, buffer_size, "%s", inet_ntoa( net ) ); - break; +/* Clients use this function to get connection data from the indicated + * port monitor. + * The requested monitor value is copied into a client-supplied char buffer. + * Returns 0 on success, -1 otherwise. */ +int peek_tcp_port_monitor(const tcp_port_monitor_t *p_monitor, int item, + int connection_index, char *p_buffer, size_t buffer_size) +{ + struct sockaddr_in sa; + + if (!p_monitor || !p_buffer || connection_index < 0) { + return -1; } - snprintf( p_buffer, buffer_size, "%s", p_hostent->h_name ); - break; - case REMOTEPORT: + memset(p_buffer, 0, buffer_size); + memset(&sa, 0, sizeof(sa)); - snprintf( p_buffer, buffer_size, "%d", p_monitor->p_peek[ connection_index ]->remote_port ); - break; + sa.sin_family = AF_INET; - case LOCALIP: + /* if the connection index is out of range, we simply return with no error, + * having first cleared the client-supplied buffer. */ + if ((item != COUNT) && (connection_index + > (int) g_hash_table_size(p_monitor->hash) - 1)) { + return 0; + } - net.s_addr = p_monitor->p_peek[ connection_index ]->local_addr; - snprintf( p_buffer, buffer_size, "%s", inet_ntoa( net ) ); - break; + switch (item) { - case LOCALHOST: + case COUNT: - p_hostent = gethostbyaddr( &p_monitor->p_peek[ connection_index ]->local_addr, sizeof(in_addr_t), AF_INET); - /* if no host name found, just use ip address. */ - if ( !p_hostent || !p_hostent->h_name ) - { - net.s_addr = p_monitor->p_peek[ connection_index ]->local_addr; - snprintf( p_buffer, buffer_size, "%s", inet_ntoa( net ) ); - break; - } - snprintf( p_buffer, buffer_size, "%s", p_hostent->h_name ); - break; + snprintf(p_buffer, buffer_size, "%d", + g_hash_table_size(p_monitor->hash)); + break; - case LOCALPORT: + case REMOTEIP: - snprintf( p_buffer, buffer_size, "%d", p_monitor->p_peek[ connection_index ]->local_port ); - break; + print_host(p_buffer, buffer_size, &p_monitor->p_peek[connection_index]->remote_addr, 0); + break; - case LOCALSERVICE: + case REMOTEHOST: - p_servent = getservbyport( htons(p_monitor->p_peek[ connection_index ]->local_port ), "tcp" ); - /* if no service name found for the port, just use the port number. */ - if ( !p_servent || !p_servent->s_name ) - { - snprintf( p_buffer, buffer_size, "%d", p_monitor->p_peek[ connection_index ]->local_port ); - break; - } - snprintf( p_buffer, buffer_size, "%s", p_servent->s_name ); - break; + print_host(p_buffer, buffer_size, &p_monitor->p_peek[connection_index]->remote_addr, 1); + break; + + case REMOTEPORT: + + snprintf(p_buffer, buffer_size, "%d", + p_monitor->p_peek[connection_index]->remote_port); + break; + + case REMOTESERVICE: + + sa.sin_port=htons(p_monitor->p_peek[connection_index]->remote_port); + getnameinfo((struct sockaddr *) &sa, sizeof(struct sockaddr_in), NULL, 0, p_buffer, buffer_size, NI_NUMERICHOST); + break; + + case LOCALIP: + + print_host(p_buffer, buffer_size, &p_monitor->p_peek[connection_index]->local_addr, 0); + break; + + case LOCALHOST: + + print_host(p_buffer, buffer_size, &p_monitor->p_peek[connection_index]->local_addr, 1); + break; + + case LOCALPORT: + + snprintf(p_buffer, buffer_size, "%d", + p_monitor->p_peek[connection_index]->local_port); + break; - default: - return(-1); - } + case LOCALSERVICE: - return(0); + sa.sin_port=htons(p_monitor->p_peek[connection_index]->local_port); + getnameinfo((struct sockaddr *) &sa, sizeof(struct sockaddr_in), NULL, 0, p_buffer, buffer_size, NI_NUMERICHOST); + break; + + default: + return -1; + } + + return 0; } /* -------------------------------- @@ -691,210 +567,149 @@ int peek_tcp_port_monitor( * -------------------------------- */ /* Create a monitor collection. Do this one first. */ -tcp_port_monitor_collection_t * create_tcp_port_monitor_collection( - tcp_port_monitor_collection_args_t * p_creation_args - ) +tcp_port_monitor_collection_t *create_tcp_port_monitor_collection(void) { - tcp_port_monitor_collection_t * p_collection; - - p_collection = (tcp_port_monitor_collection_t *) calloc( 1, sizeof( tcp_port_monitor_collection_t ) ); - if ( !p_collection ) - return NULL; - - /* create the collection's monitor hash */ - if ( hash_create( &p_collection->hash, - p_creation_args && p_creation_args->min_port_monitors > 0 ? - calc_efficient_hash_size( p_creation_args->min_port_monitors, - TCP_MONITOR_HASH_SIZE_MAX, - TCP_MONITOR_HASH_MAX_LOAD_RATIO ) : - TCP_MONITOR_HASH_SIZE_DEFAULT, - &monitor_hash_function_1, &monitor_hash_function_2, - &monitor_match_function, NULL ) != 0 ) - { - /* we failed to create the hash, so destroy the monitor completely so we don't leak */ - destroy_tcp_port_monitor_collection(p_collection); - return NULL; - } - - p_collection->monitor_list.p_head = NULL; - p_collection->monitor_list.p_tail = NULL; - - return p_collection; + tcp_port_monitor_collection_t *p_collection; + + p_collection = (tcp_port_monitor_collection_t *) + calloc(1, sizeof(tcp_port_monitor_collection_t)); + if (!p_collection) { + return NULL; + } + + /* create the collection's monitor hash */ + if ((p_collection->hash = g_hash_table_new(g_str_hash, g_str_equal)) + == NULL) { + /* we failed to create the hash, + * so destroy the monitor completely so we don't leak */ + destroy_tcp_port_monitor_collection(p_collection); + return NULL; + } + + p_collection->monitor_list.p_head = NULL; + p_collection->monitor_list.p_tail = NULL; + + return p_collection; } -/* Destroy the monitor collection (and the monitors inside). Do this one last. */ -void destroy_tcp_port_monitor_collection( - tcp_port_monitor_collection_t * p_collection - ) +/* Destroy the monitor collection (and the monitors inside). + * Do this one last. */ +void destroy_tcp_port_monitor_collection( + tcp_port_monitor_collection_t *p_collection) { - tcp_port_monitor_node_t * p_current_node, * p_next_node; - - if ( !p_collection ) - return; - - /* destroy the collection's hash */ - hash_destroy( &p_collection->hash ); - - /* destroy the monitors */ - for_each_tcp_port_monitor_in_collection( - p_collection, - &destroy_tcp_port_monitor, - NULL - ); - - /* next destroy the empty monitor nodes */ - for ( p_current_node = p_collection->monitor_list.p_head; p_current_node != NULL; ) - { - p_next_node = p_current_node->p_next; /* do this first! */ - - free( p_current_node ); - p_current_node = p_next_node; - } - - free( p_collection ); - p_collection=NULL; + tcp_port_monitor_node_t *p_current_node, *p_next_node; + + if (!p_collection) { + return; + } + + /* destroy the monitors */ + for_each_tcp_port_monitor_in_collection(p_collection, + &destroy_tcp_port_monitor, NULL); + + /* next destroy the empty monitor nodes */ + for (p_current_node = p_collection->monitor_list.p_head; + p_current_node != NULL; p_current_node = p_next_node) { + p_next_node = p_current_node->p_next; /* do this first! */ + + free(p_current_node); + } + + /* destroy the collection's hash */ + g_hash_table_destroy(p_collection->hash); + p_collection->hash = NULL; + + free(p_collection); + p_collection = NULL; } /* Updates the tcp statistics for all monitors within a collection */ void update_tcp_port_monitor_collection( - tcp_port_monitor_collection_t * p_collection - ) + tcp_port_monitor_collection_t *p_collection) { - FILE *fp; - char buf[256]; - tcp_connection_t conn; - unsigned long state; - - if ( !p_collection ) + if (!p_collection) { return; + } + + process_file(p_collection, "/proc/net/tcp"); + process_file(p_collection, "/proc/net/tcp6"); /* age the connections in all port monitors. */ - for_each_tcp_port_monitor_in_collection( - p_collection, - &age_tcp_port_monitor, - NULL - ); - - /* read tcp data from /proc/net/tcp */ - if ( ( fp = fopen("/proc/net/tcp", "r" ) ) == NULL ) - return; + for_each_tcp_port_monitor_in_collection(p_collection, + &age_tcp_port_monitor, NULL); - /* ignore field name line */ - fgets(buf, 255, fp); + /* rebuild the connection peek tables of all monitors + * so clients can peek in O(1) time */ + for_each_tcp_port_monitor_in_collection(p_collection, + &rebuild_tcp_port_monitor_peek_table, NULL); +} - /* read all tcp connections */ - while (fgets (buf, sizeof (buf), fp) != NULL) { +/* After clients create a monitor, use this to add it to the collection. + * Returns 0 on success, -1 otherwise. */ +int insert_tcp_port_monitor_into_collection( + tcp_port_monitor_collection_t *p_collection, + tcp_port_monitor_t *p_monitor) +{ + tcp_port_monitor_node_t *p_node; - if ( sscanf (buf, "%*d: %lx:%lx %lx:%lx %lx %*x:%*x %*x:%*x %*x %lu %*d %lu", - (unsigned long *)&conn.local_addr, (unsigned long *)&conn.local_port, - (unsigned long *)&conn.remote_addr, (unsigned long *)&conn.remote_port, - (unsigned long *)&state, (unsigned long *)&conn.uid, (unsigned long *)&conn.inode) != 7 ) + if (!p_collection || !p_monitor) { + return -1; + } - fprintf( stderr, "/proc/net/tcp: bad file format\n" ); + /* create a container node for this monitor */ + p_node = (tcp_port_monitor_node_t *) + calloc(1, sizeof(tcp_port_monitor_node_t)); + if (!p_node) { + return -1; + } - if ((conn.inode == 0) || (state != TCP_ESTABLISHED)) continue; + /* populate the node */ + p_node->p_monitor = p_monitor; + p_node->p_next = NULL; - /* show the connection to each port monitor. */ - for_each_tcp_port_monitor_in_collection( - p_collection, - &show_connection_to_tcp_port_monitor, - (void *) &conn - ); - } + /* add a pointer to this monitor to the collection's hash */ +#ifdef HASH_DEBUG + fprintf(stderr, "collection hash insert of monitor [%s]\n", p_monitor->key); +#endif + g_hash_table_insert(p_collection->hash, (gpointer) p_monitor->key, + (gpointer) p_monitor); + + /* tail of the container gets this node */ + if (!p_collection->monitor_list.p_tail) { + p_collection->monitor_list.p_tail = p_node; + } else { + /* p_next of the tail better be NULL */ + if (p_collection->monitor_list.p_tail->p_next != NULL) { + return -1; + } - fclose(fp); + /* splice node onto tail */ + p_collection->monitor_list.p_tail->p_next = p_node; + p_collection->monitor_list.p_tail = p_node; + } - /* check the health of the monitor hashes and rebuild them if nedded */ - for_each_tcp_port_monitor_in_collection( - p_collection, - &maintain_tcp_port_monitor_hash, - NULL - ); - - /* rebuild the connection peek tables of all monitors so clients can peek in O(1) time */ - for_each_tcp_port_monitor_in_collection( - p_collection, - &rebuild_tcp_port_monitor_peek_table, - NULL - ); -} + /* if this was the first element added */ + if (!p_collection->monitor_list.p_head) { + p_collection->monitor_list.p_head = p_collection->monitor_list.p_tail; + } -/* After clients create a monitor, use this to add it to the collection. - Returns 0 on success, -1 otherwise. */ -int insert_tcp_port_monitor_into_collection( - tcp_port_monitor_collection_t * p_collection, - tcp_port_monitor_t * p_monitor - ) -{ - tcp_port_monitor_node_t * p_node; - - if ( !p_collection || !p_monitor ) - return (-1); - - /* create a container node for this monitor */ - p_node = (tcp_port_monitor_node_t *) calloc( 1, sizeof(tcp_port_monitor_node_t) ); - if ( !p_node ) - return (-1); - - /* populate the node */ - p_node->p_monitor = p_monitor; - p_node->p_next = NULL; - - /* add a pointer to this monitor to the collection's hash */ - if ( hash_insert( &p_collection->hash, (void *)p_monitor ) != 0 ) - { - /* error inserting into hash. destroy the monitor's container node so no leaks */ - free( p_node ); - return (-1); - } - - /* tail of the container gets this node */ - if ( !p_collection->monitor_list.p_tail ) - p_collection->monitor_list.p_tail = p_node; - else - { - /* p_next of the tail better be NULL */ - if ( p_collection->monitor_list.p_tail->p_next != NULL ) - return (-1); - - /* splice node onto tail */ - p_collection->monitor_list.p_tail->p_next = p_node; - p_collection->monitor_list.p_tail = p_node; - } - - /* if this was the first element added */ - if ( !p_collection->monitor_list.p_head ) - p_collection->monitor_list.p_head = p_collection->monitor_list.p_tail; - - return 0; + return 0; } /* Clients need a way to find monitors */ -tcp_port_monitor_t * find_tcp_port_monitor( - tcp_port_monitor_collection_t * p_collection, - in_port_t port_range_begin, - in_port_t port_range_end - ) +tcp_port_monitor_t *find_tcp_port_monitor( + const tcp_port_monitor_collection_t *p_collection, + in_port_t port_range_begin, in_port_t port_range_end) { - tcp_port_monitor_t monitor,*p_monitor; - void *p_cast; - - if ( !p_collection ) - return NULL; - - /* need a monitor object to use for searching the hash */ - monitor.port_range_begin = port_range_begin; - monitor.port_range_end = port_range_end; - p_monitor = &monitor; - p_cast = (void *)p_monitor; - - /* simple hash table lookup */ - if ( hash_lookup( &p_collection->hash, &p_cast ) == 0 ) - { - /* found the monitor and p_cast now points to it */ - p_monitor = (tcp_port_monitor_t *)p_cast; - return( p_monitor ); - } - - return NULL; /* monitor not found */ + tcp_port_monitor_t *p_monitor; + gchar key[12]; + + if (!p_collection) { + return NULL; + } + + /* is monitor in hash? */ + g_sprintf(key, ":%04X :%04X", port_range_begin, port_range_end); + p_monitor = g_hash_table_lookup(p_collection->hash, (gconstpointer) key); + return p_monitor; }