Added tcp port monitor support
[monky] / src / libtcp-portmon.h
1 /* -------------------------------------------------------------------------
2  * libtcp-portmon.h:  tcp port monitoring library.               
3  *
4  * Copyright (C) 2005  Philip Kovacs kovacsp3@comcast.net
5  *
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.
10  *
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.
15  *
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  * --------------------------------------------------------------------------- */
20
21 #ifndef LIBTCP_PORTMON_H
22 #define LIBTCP_PORTMON_H
23
24 #include <netdb.h>
25 #include <netinet/in.h>
26 #include <netinet/tcp.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/socket.h>
31 #include <arpa/inet.h>
32 #include "hash.h"
33
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  * ------------------------------------------------------------------------------------------------*/
51
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 */
56
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
64  * lookups at O(1).  
65  * ----------------------------------------------------------------------------------------*/
66
67 /* TODO: Make TCP_CONNECTION_HASH_SIZE and TCP_MONITOR_HASH_SIZE variables the client can supply */
68
69 #define TCP_MONITOR_HASH_SIZE 64                        /* monitor hash size -- must be a power of two */
70
71 /* -------------------------------------------------------------------
72  * IMPLEMENTATION INTERFACE
73  *
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  * ------------------------------------------------------------------- */
78
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 };
81
82 /* -----------------------
83  * A single tcp connection 
84  * ----------------------- */
85 typedef struct _tcp_connection_t {
86         in_addr_t local_addr;
87         in_port_t local_port;
88         in_addr_t remote_addr;
89         in_port_t remote_port;
90         unsigned int uid;
91         unsigned int inode;
92         int age;
93 } tcp_connection_t;
94
95 /* ------------------------------------------------------------------------
96  * A tcp connection node/list
97  *
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;
107
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;
112
113 /* --------------
114  * A port monitor 
115  * -------------- */
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;
123
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  * ----------------------------------------------------------------------------- */
128
129 /* --------------------------------------------------
130  * Functions to hash the connections within a monitor
131  * --------------------------------------------------*/
132
133 /* First connection hash function */
134 int connection_hash_function_1( const void * /* p_data */ );
135
136 /* Second connection hash function */
137 int connection_hash_function_2( const void * /* p_data */ );
138
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 */ );
141
142 /* --------------------------------------------------
143  * Functions to hash the monitors within a collection
144  * --------------------------------------------------*/
145
146 /* First monitor hash function */
147 int monitor_hash_function_1( const void * /* p_data */ );
148
149 /* Second monitor hash function */
150 int monitor_hash_function_2( const void * /* p_data */ );
151
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 */ );
154
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;
162
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;
167
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 */ );
172
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) */
179         );
180
181 void age_tcp_port_monitor(
182         tcp_port_monitor_t *                    /* p_monitor */,
183         void *                                  /* p_void (use NULL for this function) */
184         );
185
186 void maintain_tcp_port_monitor_hash(
187         tcp_port_monitor_t *                    /* p_monitor */,
188         void *                                  /* p_void (use NULL for this function) */
189         );
190
191 void rebuild_tcp_port_monitor_peek_table(
192         tcp_port_monitor_t *                    /* p_monitor */,
193         void *                                  /* p_void (use NULL for this function) */
194         );
195
196 void show_connection_to_tcp_port_monitor(
197         tcp_port_monitor_t *                    /* p_monitor */,
198         void *                                  /* p_connection (client should cast) */
199         );
200
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;
208
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) */
216         );
217
218
219 /* ----------------------------------------------------------------------
220  * CLIENT INTERFACE 
221  *
222  * Clients should call only those functions below this line.
223  * ---------------------------------------------------------------------- */
224
225 /* ----------------------------------
226  * Client operations on port monitors
227  * ---------------------------------- */
228
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 */ 
234         );
235
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 */
245         );
246
247 /* --------------------------------
248  * Client operations on collections
249  * -------------------------------- */
250
251 /* Create a monitor collection.  Do this one first. */
252 tcp_port_monitor_collection_t * create_tcp_port_monitor_collection( void );
253
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 */ 
257         );
258
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 */
262         );
263
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 */ 
269         );
270
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 */ 
276         );
277
278 #endif