1 /* -------------------------------------------------------------------------
2 * libtcp-portmon.h: tcp port monitoring library.
4 * Copyright (C) 2005 Philip Kovacs kovacsp3@comcast.net
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * --------------------------------------------------------------------------- */
21 #ifndef LIBTCP_PORTMON_H
22 #define LIBTCP_PORTMON_H
25 #include <netinet/in.h>
26 #include <netinet/tcp.h>
30 #include <sys/socket.h>
31 #include <arpa/inet.h>
34 /* ------------------------------------------------------------------------------------------------
35 * Each port monitor contains a connection hash whose contents changes dynamically as the monitor
36 * is presented with connections on each update cycle. This implementation maintains the health
37 * of this hash by enforcing several rules. First, the hash cannot contain more items than the
38 * TCP_CONNECTION_HASH_MAX_LOAD_PCT permits. For example, a 256 element hash with a max load of
39 * 0.5 cannot contain more than 128 connections. Additional connections are ignored by the monitor.
40 * The load factor of 0.5 is low enough to keep the hash running at near O(1) performanace at all
41 * times. As elements are removed from the hash, the hash slots are tagged vacated, as required
42 * by open address hashing. The vacated tags are essential as they enable the hash to find elements
43 * for which there were collisions during insert (requiring additional probing for an open slot).
44 * The problem with vacated slots (even though they are reused) is that, as they increase in number,
45 * esp. past about 1/4 of all slots, the average number of probes the hash has to perform increases
46 * from O(1) on average to O(n) worst case. To keep the hash healthy, we simply rebuild it when the
47 * percentage of vacated slots gets too high (above TCP_CONNECTION_HASH_MAX_VACATED_PCT). Rebuilding
48 * the hash takes O(n) on the number of elements, but it well worth it as it keeps the hash running
49 * at an average access time of O(1).
50 * ------------------------------------------------------------------------------------------------*/
52 #define TCP_CONNECTION_HASH_SIZE 256 /* connection hash size -- must be a power of two */
53 #define TCP_CONNECTION_HASH_MAX_LOAD_PCT 0.5 /* disallow inserts after this % load is exceeded */
54 #define TCP_CONNECIION_HASH_MAX_VACATED_PCT 0.25 /* rebalance hash after this % of vacated slots is exceeded */
55 #define TCP_CONNECIION_STARTING_AGE 1 /* connection deleted if unseen again after this # of refreshes */
57 /* ----------------------------------------------------------------------------------------
58 * The tcp port monitor collection also contains a hash to track the monitors it contains.
59 * This hash, unlike the connection hash describes above, is not very dynamic. Client of
60 * this library typically create a fixed number of monitors and let them run until program
61 * termination. For this reason, I haven't included any load governors or hash rebuilding
62 * steps as is done above. You may store up to TCP_MONITOR_HASH_SIZE monitors in this hash,
63 * but you _should_ remember that keeping the load low (e.g. max of 0.5) keeps the monitor
65 * ----------------------------------------------------------------------------------------*/
67 /* TODO: Make TCP_CONNECTION_HASH_SIZE and TCP_MONITOR_HASH_SIZE variables the client can supply */
69 #define TCP_MONITOR_HASH_SIZE 64 /* monitor hash size -- must be a power of two */
71 /* -------------------------------------------------------------------
72 * IMPLEMENTATION INTERFACE
74 * Implementation-specific interface begins here. Clients should not
75 * manipulate these structures directly, nor call the defined helper
76 * functions. Use the "Client interface" functions defined at bottom.
77 * ------------------------------------------------------------------- */
79 /* The inventory of peekable items within the port monitor. */
80 enum tcp_port_monitor_peekables { COUNT=0, REMOTEIP, REMOTEHOST, REMOTEPORT, LOCALIP, LOCALHOST, LOCALPORT, LOCALSERVICE };
82 /* -----------------------
83 * A single tcp connection
84 * ----------------------- */
85 typedef struct _tcp_connection_t {
88 in_addr_t remote_addr;
89 in_port_t remote_port;
95 /* ------------------------------------------------------------------------
96 * A tcp connection node/list
98 * Connections within each monitor are stored in a double-linked list.
99 * The age variable provides the mechanism for removing connections if they
100 * are not seen again in subsequent update cycles.
101 * ------------------------------------------------------------------------ */
102 typedef struct _tcp_connection_node_t {
103 tcp_connection_t connection;
104 struct _tcp_connection_node_t * p_prev;
105 struct _tcp_connection_node_t * p_next;
106 } tcp_connection_node_t;
108 typedef struct _tcp_connection_list_t {
109 tcp_connection_node_t * p_head;
110 tcp_connection_node_t * p_tail;
111 } tcp_connection_list_t;
116 typedef struct _tcp_port_monitor_t {
117 in_port_t port_range_begin;
118 in_port_t port_range_end; /* begin = end to monitor a single port */
119 tcp_connection_list_t connection_list; /* list of connections for this monitor */
120 hash_table_t hash; /* hash table contains pointers into monitor's connection list */
121 tcp_connection_t **p_peek; /* array of connection pointers for O(1) peeking by index */
122 } tcp_port_monitor_t;
124 /* -----------------------------------------------------------------------------
125 * Open-addressed hash implementation requires that we supply two hash functions
126 * and a match function to compare two hash elements for identity.
127 * ----------------------------------------------------------------------------- */
129 /* --------------------------------------------------
130 * Functions to hash the connections within a monitor
131 * --------------------------------------------------*/
133 /* First connection hash function */
134 int connection_hash_function_1( const void * /* p_data */ );
136 /* Second connection hash function */
137 int connection_hash_function_2( const void * /* p_data */ );
139 /* Connection match function returns non-zero if hash elements are identical. */
140 int connection_match_function( const void * /* p_data1 */, const void * /* p_data2 */ );
142 /* --------------------------------------------------
143 * Functions to hash the monitors within a collection
144 * --------------------------------------------------*/
146 /* First monitor hash function */
147 int monitor_hash_function_1( const void * /* p_data */ );
149 /* Second monitor hash function */
150 int monitor_hash_function_2( const void * /* p_data */ );
152 /* Monitor match function returns non-zero if hash elements are identical. */
153 int monitor_match_function( const void * /* p_data1 */, const void * /* p_data2 */ );
155 /* ------------------------
156 * A port monitor node/list
157 * ------------------------ */
158 typedef struct _tcp_port_monitor_node_t {
159 tcp_port_monitor_t * p_monitor;
160 struct _tcp_port_monitor_node_t *p_next;
161 } tcp_port_monitor_node_t;
163 typedef struct __tcp_port_monitor_list_t {
164 tcp_port_monitor_node_t * p_head;
165 tcp_port_monitor_node_t * p_tail;
166 } tcp_port_monitor_list_t;
168 /* ---------------------------------------
169 * A port monitor utility function typedef
170 * ---------------------------------------*/
171 typedef void (*tcp_port_monitor_function_ptr_t)( tcp_port_monitor_t * /* p_monitor */, void * /* p_void */ );
173 /* ---------------------------------------------------------------------------
174 * Port monitor utility functions implementing tcp_port_monitor_function_ptr_t
175 * ---------------------------------------------------------------------------*/
176 void destroy_tcp_port_monitor(
177 tcp_port_monitor_t * /* p_monitor */,
178 void * /* p_void (use NULL for this function) */
181 void age_tcp_port_monitor(
182 tcp_port_monitor_t * /* p_monitor */,
183 void * /* p_void (use NULL for this function) */
186 void maintain_tcp_port_monitor_hash(
187 tcp_port_monitor_t * /* p_monitor */,
188 void * /* p_void (use NULL for this function) */
191 void rebuild_tcp_port_monitor_peek_table(
192 tcp_port_monitor_t * /* p_monitor */,
193 void * /* p_void (use NULL for this function) */
196 void show_connection_to_tcp_port_monitor(
197 tcp_port_monitor_t * /* p_monitor */,
198 void * /* p_connection (client should cast) */
201 /* -----------------------------
202 * A tcp port monitor collection
203 * -----------------------------*/
204 typedef struct _tcp_port_monitor_collection_t {
205 tcp_port_monitor_list_t monitor_list; /* list of monitors for this collection */
206 hash_table_t hash; /* hash table contains pointers into collection's monitor list */
207 } tcp_port_monitor_collection_t;
209 /* ---------------------------------------------------------------------------------------
210 * Apply a tcp_port_monitor_function_ptr_t function to each port monitor in the collection.
211 * ---------------------------------------------------------------------------------------*/
212 void for_each_tcp_port_monitor_in_collection(
213 tcp_port_monitor_collection_t * /* p_collection */,
214 tcp_port_monitor_function_ptr_t /* p_function */,
215 void * /* p_function_args (for user arguments) */
219 /* ----------------------------------------------------------------------
222 * Clients should call only those functions below this line.
223 * ---------------------------------------------------------------------- */
225 /* ----------------------------------
226 * Client operations on port monitors
227 * ---------------------------------- */
229 /* Clients should first try to "find_tcp_port_monitor" before creating one
230 so that there are no redundant monitors. */
231 tcp_port_monitor_t * create_tcp_port_monitor(
232 in_port_t /* port_range_begin */,
233 in_port_t /* port_range_end */
236 /* Clients use this function to get connection data from the indicated port monitor.
237 The requested monitor value is copied into a client-supplied char buffer.
238 Returns 0 on success, -1 otherwise. */
239 int peek_tcp_port_monitor(
240 tcp_port_monitor_t * /* p_monitor */,
241 int /* item, ( item of interest, from tcp_port_monitor_peekables enum ) */,
242 int /* connection_index, ( 0 to number of connections in monitor - 1 )*/,
243 char * /* p_buffer, buffer to receive requested value */,
244 size_t /* buffer_size, size of p_buffer */
247 /* --------------------------------
248 * Client operations on collections
249 * -------------------------------- */
251 /* Create a monitor collection. Do this one first. */
252 tcp_port_monitor_collection_t * create_tcp_port_monitor_collection( void );
254 /* Destroy the monitor collection (and everything it contains). Do this one last. */
255 void destroy_tcp_port_monitor_collection(
256 tcp_port_monitor_collection_t * /* p_collection */
259 /* Updates the tcp statitics for all monitors within a collection */
260 void update_tcp_port_monitor_collection(
261 tcp_port_monitor_collection_t * /* p_collection */
264 /* After clients create a monitor, use this to add it to the collection.
265 Returns 0 on success, -1 otherwise. */
266 int insert_tcp_port_monitor_into_collection(
267 tcp_port_monitor_collection_t * /* p_collection */,
268 tcp_port_monitor_t * /* p_monitor */
271 /* Clients need a way to find monitors */
272 tcp_port_monitor_t * find_tcp_port_monitor(
273 tcp_port_monitor_collection_t * /* p_collection */,
274 in_port_t /* port_range_begin */,
275 in_port_t /* port_range_end */