*
* Copyright (C) 2005 Philip Kovacs kovacsp3@comcast.net
*
+ * $Id$
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
#ifndef LIBTCP_PORTMON_H
#define LIBTCP_PORTMON_H
-#include <netdb.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+
+#include <math.h>
+#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
+
#include "hash.h"
/* ------------------------------------------------------------------------------------------------
* Each port monitor contains a connection hash whose contents changes dynamically as the monitor
* is presented with connections on each update cycle. This implementation maintains the health
* of this hash by enforcing several rules. First, the hash cannot contain more items than the
- * TCP_CONNECTION_HASH_MAX_LOAD_PCT permits. For example, a 256 element hash with a max load of
- * 0.5 cannot contain more than 128 connections. Additional connections are ignored by the monitor.
+ * TCP_CONNECTION_HASH_MAX_LOAD_RATIO permits. For example, a 512 element hash with a max load of
+ * 0.5 cannot contain more than 256 connections. Additional connections are ignored by the monitor.
* The load factor of 0.5 is low enough to keep the hash running at near O(1) performanace at all
* times. As elements are removed from the hash, the hash slots are tagged vacated, as required
* by open address hashing. The vacated tags are essential as they enable the hash to find elements
* The problem with vacated slots (even though they are reused) is that, as they increase in number,
* esp. past about 1/4 of all slots, the average number of probes the hash has to perform increases
* from O(1) on average to O(n) worst case. To keep the hash healthy, we simply rebuild it when the
- * percentage of vacated slots gets too high (above TCP_CONNECTION_HASH_MAX_VACATED_PCT). Rebuilding
- * the hash takes O(n) on the number of elements, but it well worth it as it keeps the hash running
- * at an average access time of O(1).
+ * percentage of vacated slots gets too high (above TCP_CONNECTION_HASH_MAX_VACATED_RATIO).
+ * Rebuilding the hash takes O(n) on the number of elements, but it well worth it as it keeps the
+ * hash running at an average access time of O(1).
* ------------------------------------------------------------------------------------------------*/
-#define TCP_CONNECTION_HASH_SIZE 256 /* connection hash size -- must be a power of two */
-#define TCP_CONNECTION_HASH_MAX_LOAD_PCT 0.5 /* disallow inserts after this % load is exceeded */
-#define TCP_CONNECIION_HASH_MAX_VACATED_PCT 0.25 /* rebalance hash after this % of vacated slots is exceeded */
-#define TCP_CONNECIION_STARTING_AGE 1 /* connection deleted if unseen again after this # of refreshes */
+#define TCP_CONNECTION_HASH_SIZE_DEFAULT 512 /* connection hash size default -- must be a power of two */
+#define TCP_CONNECTION_HASH_SIZE_MAX 65536 /* connection hash size maximum -- must be a power of two */
+#define TCP_CONNECTION_HASH_MAX_LOAD_RATIO 0.5 /* disallow inserts after this load ratio is exceeded */
+#define TCP_CONNECTION_HASH_MAX_VACATED_RATIO 0.25 /* rebalance hash after this ratio of vacated slots is exceeded */
+#define TCP_CONNECTION_STARTING_AGE 1 /* connection deleted if unseen again after this # of refreshes */
/* ----------------------------------------------------------------------------------------
* The tcp port monitor collection also contains a hash to track the monitors it contains.
- * This hash, unlike the connection hash describes above, is not very dynamic. Client of
+ * This hash, unlike the connection hash describes above, is not very dynamic. Clients of
* this library typically create a fixed number of monitors and let them run until program
- * termination. For this reason, I haven't included any load governors or hash rebuilding
- * steps as is done above. You may store up to TCP_MONITOR_HASH_SIZE monitors in this hash,
- * but you _should_ remember that keeping the load low (e.g. max of 0.5) keeps the monitor
- * lookups at O(1).
+ * termination. For this reason, I haven't included any hash rebuilding code as is done
+ * above. You may store up to TCP_MONITOR_HASH_SIZE_MAX monitors in this hash, but you
+ * should remember that keeping the load low (e.g. 0.5) keeps the monitor lookups at O(1).
* ----------------------------------------------------------------------------------------*/
-/* TODO: Make TCP_CONNECTION_HASH_SIZE and TCP_MONITOR_HASH_SIZE variables the client can supply */
-
-#define TCP_MONITOR_HASH_SIZE 64 /* monitor hash size -- must be a power of two */
+#define TCP_MONITOR_HASH_SIZE_DEFAULT 32 /* monitor hash size default -- must be a power of two */
+#define TCP_MONITOR_HASH_SIZE_MAX 512 /* monitor hash size maximum -- must be a power of two */
+#define TCP_MONITOR_HASH_MAX_LOAD_RATIO 0.5 /* disallow new monitors after this load ratio is exceeded */
/* -------------------------------------------------------------------
* IMPLEMENTATION INTERFACE
* ------------------------------------------------------------------- */
/* The inventory of peekable items within the port monitor. */
-enum tcp_port_monitor_peekables { COUNT=0, REMOTEIP, REMOTEHOST, REMOTEPORT, LOCALIP, LOCALHOST, LOCALPORT, LOCALSERVICE };
+enum tcp_port_monitor_peekables { COUNT=0, REMOTEIP, REMOTEHOST, REMOTEPORT, REMOTESERVICE, LOCALIP, LOCALHOST, LOCALPORT, LOCALSERVICE };
-/* -----------------------
+/* ------------------------------------------------------------------------
* A single tcp connection
- * ----------------------- */
+ *
+ * The age variable provides the mechanism for removing connections if they
+ * are not seen again in subsequent update cycles.
+ * ------------------------------------------------------------------------ */
typedef struct _tcp_connection_t {
in_addr_t local_addr;
in_port_t local_port;
in_addr_t remote_addr;
in_port_t remote_port;
- unsigned int uid;
- unsigned int inode;
int age;
} tcp_connection_t;
+/* ----------------------------------
+ * Copy a connection
+ *
+ * Returns 0 on success, -1 otherwise
+ * ----------------------------------*/
+int copy_tcp_connection(
+ tcp_connection_t * /* p_dest_connection */,
+ const tcp_connection_t * /* p_source_connection */
+ );
+
/* ------------------------------------------------------------------------
* A tcp connection node/list
*
* Connections within each monitor are stored in a double-linked list.
- * The age variable provides the mechanism for removing connections if they
- * are not seen again in subsequent update cycles.
* ------------------------------------------------------------------------ */
typedef struct _tcp_connection_node_t {
tcp_connection_t connection;
void * /* p_function_args (for user arguments) */
);
+/* ----------------------------------------------------------------------------------------
+ * Calculate an efficient hash size based on the desired number of elements and load factor.
+ * ---------------------------------------------------------------------------------------- */
+int calc_efficient_hash_size(
+ int /* min_elements, the minimum number of elements to store */,
+ int /* max_hash_size, the maximum permissible hash size */,
+ double /* max_load_factor, the fractional load we wish not to exceed, e.g. 0.5 */
+ );
/* ----------------------------------------------------------------------
* CLIENT INTERFACE
* Clients should call only those functions below this line.
* ---------------------------------------------------------------------- */
+/* struct to hold monitor creation arguments */
+typedef struct _tcp_port_monitor_args_t {
+ int min_port_monitor_connections; /* monitor must support tracking at least this many connections */
+} tcp_port_monitor_args_t;
+
+
+/* struct to hold collection creation arguments */
+typedef struct _tcp_port_monitor_collection_args_t {
+ int min_port_monitors; /* collection must support creation of at least this many monitors */
+} tcp_port_monitor_collection_args_t;
+
/* ----------------------------------
* Client operations on port monitors
* ---------------------------------- */
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 */
+ in_port_t /* port_range_end */,
+ tcp_port_monitor_args_t * /* p_creation_args, NULL ok for library defaults */
);
/* 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 */,
+ const tcp_port_monitor_t * /* p_monitor */,
int /* item, ( item of interest, from tcp_port_monitor_peekables enum ) */,
int /* connection_index, ( 0 to number of connections in monitor - 1 )*/,
char * /* p_buffer, buffer to receive requested value */,
* -------------------------------- */
/* Create a monitor collection. Do this one first. */
-tcp_port_monitor_collection_t * create_tcp_port_monitor_collection( void );
+tcp_port_monitor_collection_t * create_tcp_port_monitor_collection(
+ tcp_port_monitor_collection_args_t * /* p_creation_args, NULL ok for library defaults */
+ );
/* Destroy the monitor collection (and everything it contains). Do this one last. */
void destroy_tcp_port_monitor_collection(
/* Clients need a way to find monitors */
tcp_port_monitor_t * find_tcp_port_monitor(
- tcp_port_monitor_collection_t * /* p_collection */,
+ const tcp_port_monitor_collection_t * /* p_collection */,
in_port_t /* port_range_begin */,
in_port_t /* port_range_end */
);