1 /*********************************************************************************************************
2 * Software License Agreement (BSD License)                                                               *
3 * Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
4 *													 *
5 * Copyright (c) 2020, WIDE Project and NICT								 *
6 * All rights reserved.											 *
7 * 													 *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are  *
9 * permitted provided that the following conditions are met:						 *
10 * 													 *
11 * * Redistributions of source code must retain the above 						 *
12 *   copyright notice, this list of conditions and the 							 *
13 *   following disclaimer.										 *
14 *    													 *
15 * * Redistributions in binary form must reproduce the above 						 *
16 *   copyright notice, this list of conditions and the 							 *
17 *   following disclaimer in the documentation and/or other						 *
18 *   materials provided with the distribution.								 *
19 * 													 *
20 * * Neither the name of the WIDE Project or NICT nor the 						 *
21 *   names of its contributors may be used to endorse or 						 *
22 *   promote products derived from this software without 						 *
23 *   specific prior written permission of WIDE Project and 						 *
24 *   NICT.												 *
25 * 													 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
34 *********************************************************************************************************/
35 
36 #ifndef _LIBFDCORE_H
37 #define _LIBFDCORE_H
38 
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 #include <freeDiameter/libfdproto.h>
45 #include <gnutls/gnutls.h>
46 #include <gnutls/x509.h>
47 #include <regex.h>
48 
49 /* GNUTLS version */
50 #ifndef GNUTLS_VERSION
51 #define GNUTLS_VERSION LIBGNUTLS_VERSION
52 #endif /* GNUTLS_VERSION */
53 
54 /* GNUTLS calls debug level */
55 #ifndef GNUTLS_DBG_LEVEL
56 #define GNUTLS_DBG_LEVEL ANNOYING
57 #endif /* GNUTLS_DBG_LEVEL */
58 
59 
60 /* Check the return value of a GNUTLS function, log and propagate */
61 #define CHECK_GNUTLS_GEN( faillevel, __call__, __fallback__  ) { 					\
62 		CHECK_PRELUDE(__call__);								\
63 		if (__ret__ < 0) {									\
64 			LOG(faillevel, "TLS ERROR: in '%s' :\t%s",  #__call__ ,  gnutls_strerror(__ret__)); \
65 			__fallback__;									\
66 		}											\
67 }
68 
69 /* we use this macro to help debugging gnutls usage issues -- just change the content to display what you need */
70 #define GNUTLS_TRACE( __call__) {					\
71 	TRACE_CALL("Check: %s", #__call__ );				\
72 	(__call__);							\
73 }
74 
75 
76 #ifndef EXCLUDE_DEPRECATED
77 /* Macro for transition, replace with CHECK_GNUTLS_GEN */
78 #define CHECK_GNUTLS_DO( __call__, __fallback__ )	\
79 	CHECK_GNUTLS_GEN( FD_LOG_ERROR, __call__, __fallback__  )
80 
81 #endif /* EXCLUDE_DEPRECATED */
82 
83 
84 /*============================================================*/
85 /*                      INITIALIZATION                        */
86 /*============================================================*/
87 
88 
89 /* Initialize the libfdcore internals. This also initializes libfdproto */
90 int fd_core_initialize(void);
91 
92 /* A string describing the version of the library */
93 extern const char fd_core_version[];
94 
95 /* Parse the freeDiameter.conf configuration file, load the extensions */
96 int fd_core_parseconf(const char * conffile);
97 
98 /* Start the server & client threads */
99 int fd_core_start(void);
100 
101 /* Block until the framework has completed its initialization -- useful for extensions */
102 int fd_core_waitstartcomplete(void);
103 
104 /* Initialize shutdown of the framework */
105 int fd_core_shutdown(void);
106 
107 /* Wait for the shutdown to be complete -- this should always be called after fd_core_shutdown */
108 int fd_core_wait_shutdown_complete(void);
109 
110 
111 /*============================================================*/
112 /*                          CONFIG                            */
113 /*============================================================*/
114 
115 /* Structure to hold the configuration of the freeDiameter daemon */
116 #define	EYEC_CONFIG	0xC011F16
117 struct fd_config {
118 	int		 cnf_eyec;	/* Eye catcher: EYEC_CONFIG */
119 
120 	const char	*cnf_file;	/* Configuration file to parse, default is DEFAULT_CONF_FILE */
121 
122 	DiamId_t  	 cnf_diamid;	/* Diameter Identity of the local peer (FQDN -- ASCII) */
123 	size_t		 cnf_diamid_len;/* cached length of the previous string */
124 	DiamId_t	 cnf_diamrlm;	/* Diameter realm of the local peer, default to realm part of cnf_diamid */
125 	size_t		 cnf_diamrlm_len;/* length of the previous string */
126 
127 	unsigned int	 cnf_timer_tc;	/* The value in seconds of the default Tc timer */
128 	unsigned int 	 cnf_timer_tw;	/* The value in seconds of the default Tw timer */
129 
130 	uint16_t	 cnf_port;	/* the local port for legacy Diameter (default: 3868) in host byte order */
131 	uint16_t	 cnf_port_tls;	/* the local port for Diameter/TLS (default: 5868) in host byte order */
132 	uint16_t	 cnf_port_3436; /* Open an additional server port to listen to old TLS/SCTP clients (RFC3436, freeDiameter versions < 1.2.0) */
133 	uint16_t	 cnf_sctp_str;	/* default max number of streams for SCTP associations (def: 30) */
134 	struct fd_list	 cnf_endpoints;	/* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all). After servers are started, this is the actual list of endpoints including port information. */
135 	int		 cnf_thr_srv;	/* Number of threads per servers handling the connection state machines */
136 	int		 cnf_processing_peers_minimum;	/* Number of processing peers that must be connected before other peers may connect */
137 	regex_t		 cnf_processing_peers_pattern_regex;	/* Regex pattern for identifying processing peers */
138 	struct fd_list	 cnf_apps;	/* Applications locally supported (except relay, see flags). Use fd_disp_app_support to add one. list of struct fd_app. */
139 	uint16_t	 cnf_dispthr;	/* Number of dispatch threads to create */
140 	uint16_t     cnf_rtinthr;  /* Number of routing in threads to create */
141 	uint16_t     cnf_rtoutthr;  /* Number of routing out threads to create */
142 	uint16_t	 cnf_rr_in_answers;	/* include Route-Record AVP in answers */
143 	int		 cnf_qin_limit;	/* limit for incoming queue*/
144 	int		 cnf_qout_limit;	/* limit for outgoing queue */
145 	int		 cnf_qlocal_limit;	/* limit for local queue */
146 	struct {
147 		unsigned no_fwd : 1;	/* the peer does not relay messages (0xffffff app id) */
148 		unsigned no_ip4 : 1;	/* disable IP */
149 		unsigned no_ip6 : 1;	/* disable IPv6 */
150 		unsigned no_tcp : 1;	/* disable use of TCP */
151 		unsigned no_sctp: 1;	/* disable the use of SCTP */
152 		unsigned pr_tcp	: 1;	/* prefer TCP over SCTP */
153 		unsigned tls_alg: 1;	/* TLS algorithm for initiated cnx. 0: separate port. 1: inband-security (old) */
154 		unsigned no_bind: 1;	/* disable client bind to cnf_endpoints if non configured (bind all) */
155 	} 		 cnf_flags;
156 
157 	struct {
158 		int				 tls_disabled;
159 
160 		/* Credentials parameters (backup) */
161 		char *  			 cert_file;
162 		char *				 key_file;
163 
164 		char *  			 ca_file;
165 		int				 ca_file_nr;
166 		char *  			 crl_file;
167 
168 		char *				 prio_string;
169 		unsigned int 			 dh_bits;
170 		char *				 dh_file;
171 
172 		/* GNUTLS parameters */
173 		gnutls_priority_t 		 prio_cache;
174 		gnutls_dh_params_t 		 dh_cache;
175 
176 		/* GNUTLS server credential(s) */
177 		gnutls_certificate_credentials_t credentials; /* contains local cert + trust anchors */
178 		#ifdef GNUTLS_VERSION_300
179 		gnutls_x509_trust_list_t         trustlist; /* the logic to check local certificate has changed */
180 		#endif /* GNUTLS_VERSION_300 */
181 
182 	} 		 cnf_sec_data;
183 
184 	uint32_t	 cnf_orstateid;	/* The value to use in Origin-State-Id, default to random value */
185 	struct dictionary *cnf_dict;	/* pointer to the global dictionary */
186 	struct fifo	  *cnf_main_ev;	/* events for the daemon's main (struct fd_event items) */
187 };
188 extern struct fd_config *fd_g_config; /* The pointer to access the global configuration, initalized in main */
189 
190 
191 
192 /*============================================================*/
193 /*                         PEERS                              */
194 /*============================================================*/
195 
196 /* States of a peer */
197 enum peer_state {
198 	/* Stable states */
199 	STATE_NEW = 0,		/* The peer has been just been created, PSM thread not started yet */
200 	STATE_OPEN,		/* Connexion established */
201 
202 	/* Peer state machine */
203 	STATE_CLOSED,		/* No connection established, will re-attempt after TcTimer. */
204 	STATE_CLOSING,		/* the connection is being shutdown (DPR/DPA in progress) */
205 	STATE_WAITCNXACK,	/* Attempting to establish transport-level connection */
206 	STATE_WAITCNXACK_ELEC,	/* Received a CER from this same peer on an incoming connection (other peer object), while we were waiting for cnx ack */
207 	STATE_WAITCEA,		/* Connection established, CER sent, waiting for CEA */
208 	/* STATE_WAITRETURNS_ELEC, */	/* This state is not stable and therefore deprecated:
209 				   We have sent a CER on our initiated connection, and received a CER from the remote peer on another connection. Election.
210 				   If we win the election, we must disconnect the initiated connection and send a CEA on the other => we go to OPEN state.
211 				   If we lose, we disconnect the other connection (receiver) and fallback to WAITCEA state. */
212 	STATE_OPEN_HANDSHAKE,	/* TLS Handshake and validation are in progress in open state -- we use it only for debug purpose, it is never displayed */
213 
214 	/* Failover state machine */
215 	STATE_SUSPECT,		/* A DWR was sent and not answered within TwTime. Failover in progress. */
216 	STATE_REOPEN,		/* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */
217 
218 	/* Ordering issues with multistream & state machine. -- see top of p_psm.c for explanation */
219 	STATE_OPEN_NEW, 	/* after CEA is sent, until a new message is received. Force ordering in this state */
220 	STATE_CLOSING_GRACE,	/* after DPA is sent or received, give a short delay for messages in the pipe to be received. */
221 
222 	/* Error state */
223 	STATE_ZOMBIE		/* The PSM thread is not running anymore; it must be re-started or peer should be deleted. */
224 #define STATE_MAX STATE_ZOMBIE
225 };
226 /* The following macro is called in freeDiameter/p_psm.c */
227 #define DECLARE_STATE_STR()		\
228 const char *peer_state_str[] = { 	\
229 	  "STATE_NEW"			\
230 	, "STATE_OPEN"			\
231 	, "STATE_CLOSED"		\
232 	, "STATE_CLOSING"		\
233 	, "STATE_WAITCNXACK"		\
234 	, "STATE_WAITCNXACK_ELEC"	\
235 	, "STATE_WAITCEA"		\
236 	, "STATE_OPEN_HANDSHAKE"	\
237 	, "STATE_SUSPECT"		\
238 	, "STATE_REOPEN"		\
239 	, "STATE_OPEN_NEW"		\
240 	, "STATE_CLOSING_GRACE"		\
241 	, "STATE_ZOMBIE"		\
242 	};
243 extern const char *peer_state_str[];
244 #define STATE_STR(state) \
245 	(((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "<Invalid>")
246 
247 /* Constants for the peer_info structure below */
248 #define PI_P3_DEFAULT	0	/* Use any available protocol */
249 #define PI_P3_IP	1	/* Use only IP to connect to this peer */
250 #define PI_P3_IPv6	2	/* resp, IPv6 */
251 
252 #define PI_P4_DEFAULT	0	/* Attempt any available protocol */
253 #define PI_P4_TCP	1	/* Only use TCP */
254 #define PI_P4_SCTP	2	/* Only use SCTP */
255 
256 #define PI_ALGPREF_SCTP	0	/* SCTP is  attempted first (default) */
257 #define PI_ALGPREF_TCP	1	/* TCP is attempted first */
258 
259 #define PI_SEC_DEFAULT	0	/* New TLS security (handshake after connection, protecting also CER/CEA) */
260 #define PI_SEC_NONE	1	/* Transparent security with this peer (IPsec) */
261 #define PI_SEC_TLS_OLD	2	/* Old TLS security (use Inband-Security-Id AVP during CER/CEA) */
262 				/* Set sec = 3 to authorize use of (Inband-Security-Id == NONE) with this peer, sec = 2 only authorizing TLS */
263 
264 #define PI_SCTPSEC_DEF	0	/* Use DTLS over SCTP to connect to this peer (default) */
265 #define PI_SCTPSEC_3436	1	/* Use TLS over SCTP to connect to this peer (RFC3436) */
266 
267 #define PI_EXP_NONE	0	/* the peer entry does not expire */
268 #define PI_EXP_INACTIVE	1	/* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */
269 
270 #define PI_PRST_NONE	0	/* the peer entry is deleted after disconnection / error */
271 #define PI_PRST_ALWAYS	1	/* the peer entry is persistant (will be kept as ZOMBIE in case of error) */
272 
273 /* Information about a remote peer */
274 struct peer_info {
275 
276 	DiamId_t	pi_diamid;	/* (supposedly) UTF-8, \0 terminated. The Diameter Identity of the remote peer. */
277 	size_t		pi_diamidlen;	/* cached length of pi_diamid */
278 
279 	struct {
280 		struct {
281 			unsigned	pro3 :2;	/* PI_P3_* */
282 			unsigned	pro4 :2;	/* PI_P4_* */
283 			unsigned	alg :1;		/* PI_ALGPREF_* */
284 			unsigned	sec :2;		/* PI_SEC_* */
285 			unsigned	sctpsec :1;	/* PI_SCTPSEC_* */
286 			unsigned	exp :1;		/* PI_EXP_* */
287 			unsigned	persist :1;	/* PI_PRST_* */
288 
289 		}		pic_flags;	/* Flags influencing the connection to the remote peer */
290 
291 		DiamId_t	pic_realm;	/* If configured, the daemon will check the received realm in CER/CEA matches this. */
292 		uint16_t	pic_port; 	/* port to connect to. 0: default. */
293 
294 		uint32_t 	pic_lft;	/* lifetime of this peer when inactive (see pic_flags.exp definition) */
295 		int		pic_tctimer; 	/* use this value for TcTimer instead of global, if != 0 */
296 		int		pic_twtimer; 	/* use this value for TwTimer instead of global, if != 0 */
297 
298 		char *		pic_priority;	/* Priority string for GnuTLS if we don't use the default */
299 
300 	} config;	/* Configured data (static for this peer entry) */
301 
302 	struct {
303 
304 		/* enum peer_state	pir_state; */
305 		/* Since 1.1.0, read the state with fd_peer_getstate(peer). */
306 
307 		DiamId_t	pir_realm;	/* The received realm in CER/CEA. */
308 		size_t		pir_realmlen;	/* length of the realm */
309 
310 		uint32_t	pir_vendorid;	/* Content of the Vendor-Id AVP, or 0 by default */
311 		uint32_t	pir_orstate;	/* Origin-State-Id value */
312 		os0_t		pir_prodname;	/* copy of Product-Name AVP (\0 terminated) */
313 		uint32_t	pir_firmrev;	/* Content of the Firmware-Revision AVP */
314 		int		pir_relay;	/* The remote peer advertized the relay application */
315 		struct fd_list	pir_apps;	/* applications advertised by the remote peer, except relay (pi_flags.relay) */
316 		int		pir_isi;	/* Inband-Security-Id advertised (PI_SEC_* bits) */
317 
318 		uint32_t	pir_lastDC;	/* The last Disconnect-Cause value received */
319 
320 		int		pir_proto;	/* The L4 protocol currently used with the peer (IPPROTO_TCP or IPPROTO_SCTP) */
321 		const gnutls_datum_t 	*pir_cert_list; 	/* The (valid) credentials that the peer has presented, or NULL if TLS is not used */
322 								/* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo
323 								   see there for example of using this data */
324 		unsigned int 	pir_cert_list_size;		/* Number of certificates in the list */
325 
326 	} runtime;	/* Data populated after connection, may change between 2 connections -- not used by fd_peer_add */
327 
328 	struct fd_list	pi_endpoints;	/* Endpoint(s) of the remote peer (configured, discovered, or advertized). list of struct fd_endpoint. DNS resolved if empty. */
329 };
330 
331 
332 struct peer_hdr {
333 	struct fd_list	 chain;	/* Link into the list of all the peers, ordered by their Diameter Id (fd_os_cmp) */
334 	struct peer_info info;	/* The public data */
335 
336 	/* This header is followed by more data in the private peer structure definition */
337 };
338 
339 /* the global list of peers.
340   Since we are not expecting so many connections, we don't use a hash, but it might be changed.
341   The list items are peer_hdr structures (actually, fd_peer, but the cast is OK) */
342 extern struct fd_list fd_g_peers;
343 extern pthread_rwlock_t fd_g_peers_rw; /* protect the list */
344 
345 /*
346  * FUNCTION:	fd_peer_add
347  *
348  * PARAMETERS:
349  *  info 	: Information to create the peer.
350  *  orig_dbg	: A string indicating the origin of the peer information, for debug (ex: conf, redirect, ...)
351  *  cb		: optional, a callback to call (once) when the peer connection is established or failed
352  *  cb_data	: opaque data to pass to the callback.
353  *
354  * DESCRIPTION:
355  *  Add a peer to the list of peers to which the daemon must maintain a connexion.
356  *
357  *  The content of info parameter is copied, except for the list of endpoints if
358  * not empty, which is simply moved into the created object. It means that the list
359  * items must have been malloc'd, so that they can be freed.
360  *
361  *  If cb is not null, the callback is called when the connection is in OPEN state or
362  * when an error has occurred. The callback should use the pi_state information to
363  * determine which one it is. If the first parameter of the called callback is NULL, it
364  * means that the peer is being destroyed before attempt success / failure.
365  * cb is called to allow freeing cb_data in  * this case.
366  *
367  *  The orig_dbg string is only useful for easing debug, and can be left to NULL.
368  *
369  * RETURN VALUE:
370  *  0      	: The peer is added.
371  *  EINVAL 	: A parameter is invalid.
372  *  EEXIST 	: A peer with the same Diameter-Id is already in the list.
373  *  (other standard errors may be returned, too, with their standard meaning. Example:
374  *    ENOMEM 	: Memory allocation for the new object element failed.)
375  */
376 int fd_peer_add ( struct peer_info * info, const char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data );
377 
378 /*
379  * FUNCTION:	fd_peer_getbyid
380  *
381  * PARAMETERS:
382  *  diamid 	: an UTF8 string describing the diameter Id of the peer to seek
383  *  diamidlen	: length of the diamid
384  *  igncase	: perform an almost-case-insensitive search? (slower)
385  *  peer	: The peer is stored here if it exists.
386  *
387  * DESCRIPTION:
388  *   Search a peer by its Diameter-Id.
389  *
390  * RETURN VALUE:
391  *  0   : *peer has been updated (to NULL if the peer is not found).
392  * !0	: An error occurred.
393  */
394 int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer );
395 
396 /*
397  * FUNCTION:	fd_peer_get_state
398  *
399  * PARAMETERS:
400  *  peer	: The peer which state to read
401  *
402  * DESCRIPTION:
403  *   Returns the current state of the peer.
404  *
405  * RETURN VALUE:
406  *  -1  : peer is invalid
407  * >=0	: the state of the peer at the time of reading.
408  */
409 int fd_peer_get_state(struct peer_hdr *peer);
410 
411 /*
412  * FUNCTION:	fd_peer_cnx_proto_info
413  *
414  * PARAMETERS:
415  *  peer	: The peer which information to be read
416  *  buf		: Where to store the protocol information
417  *  len		: available space in bug
418  *
419  * DESCRIPTION:
420  *   Creates a string describing the current connection to this peer, e.g.: "TCP,TLS,soc#3".
421  *
422  * RETURN VALUE:
423  *  0   : buffer was written
424  * >=0	: error code.
425  */
426 int fd_peer_cnx_proto_info(struct peer_hdr *peer, char * buf, size_t len);
427 
428 /*
429  * FUNCTION:	fd_peer_get_load_pending
430  *
431  * PARAMETERS:
432  *  peer	: The peer which load to read
433  *  to_receive  : (out) number of requests sent to this peer without matching answer yet.
434  *  to_send     : (out) number of requests received from this peer and not yet answered.
435  *
436  * DESCRIPTION:
437  *   Returns the current number of requests sent to this peer
438  *  that have not been answered yet. This is an empirical indication
439  *  of the workload of this peer.
440  *
441  * RETURN VALUE:
442  *  0  : The load parameter has been updated. (it should have a positive value always)
443  * !0  : An error occurred
444  */
445 int fd_peer_get_load_pending(struct peer_hdr *peer, long * to_receive, long * to_send);
446 
447 /*
448  * FUNCTION:	fd_peer_validate_register
449  *
450  * PARAMETERS:
451  *  peer_validate 	: Callback as defined below.
452  *
453  * DESCRIPTION:
454  *  Add a callback to authorize / reject incoming peer connections.
455  * All registered callbacks are called until a callback sets auth = -1 or auth = 1.
456  * If no callback returns a clear decision, the default behavior is applied (reject unknown connections)
457  * The callbacks are called in FILO order of their registration.
458  *
459  * RETURN VALUE:
460  *  0   : The callback is added.
461  * !0	: An error occurred.
462  */
463 int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) );
464 /*
465  * CALLBACK:	peer_validate
466  *
467  * PARAMETERS:
468  *   info     : Structure containing information about the peer attempting the connection.
469  *   auth     : Store there the result if the peer is accepted (1), rejected (-1), or unknown (0).
470  *   cb2      : If != NULL and in case of PI_SEC_TLS_OLD, another callback to call after handshake (if auth = 1).
471  *
472  * DESCRIPTION:
473  *   This callback is called when a new connection is being established from an unknown peer,
474  * after the CER is received. An extension must register such callback with peer_validate_register.
475  *
476  *   The callback can learn if the peer has sent Inband-Security-Id AVPs in runtime.pir_isi fields.
477  * It can also learn if a handshake has already been performed in runtime.pir_cert_list field.
478  * The callback must set the value of config.pic_flags.sec appropriately to allow a connection without TLS.
479  *
480  *   If the old TLS mechanism is used,
481  * the extension may also need to check the credentials provided during the TLS
482  * exchange (remote certificate). For this purpose, it may set the address of a new callback
483  * to be called once the handshake is completed. This new callback receives the information
484  * structure as parameter (with pir_cert_list set) and returns 0 if the credentials are correct,
485  * or an error code otherwise. If the error code is received, the connection is closed and the
486  * peer is destroyed.
487  * Note that freeDiameter already achieves some usual checks. The callback may be used to enforce
488  * additional restrictions.
489  *
490  * RETURN VALUE:
491  *  0      	: The authorization decision has been written in the location pointed by auth.
492  *  !0 		: An error occurred.
493  */
494 
495 
496 
497 /*============================================================*/
498 /*                         MESSAGES                           */
499 /*============================================================*/
500 
501 /*
502  * FUNCTION:	fd_msg_send, fd_msg_send_timeout
503  *
504  * PARAMETERS:
505  *  pmsg 	: Location of the message to be sent on the network (set to NULL on function return to avoid double deletion).
506  *  anscb	: A callback to be called when corresponding answer is received, when sending a request (not used with answers)
507  *  anscb_data	: opaque data to be passed back to the anscb (or expirecb) when it is called.
508  *  expirecb    : (only for fd_msg_send_timeout) If the request did not get an answer before timeout, this callback is called.
509  *  timeout     : (only for fd_msg_send_timeout) sets the absolute time until when to wait for an answer. Past this time,
510  *                the expirecb is called with the request and the answer will be discarded if received later.
511  *
512  * DESCRIPTION:
513  *   Sends a message on the network. (actually simply queues it in a global queue, to be picked by a daemon's thread)
514  * For requests, the end-to-end id must be set (see fd_msg_get_eteid / MSGFL_ALLOC_ETEID).
515  * For answers, the message must be created with function fd_msg_new_answer_from_req.
516  *
517  * The routing module will handle sending to the correct peer, usually based on the Destination-Realm / Destination-Host AVP.
518  *
519  * If the msg is a request, there are two ways of receiving the answer:
520  *  - either having registered a callback in the dispatch module (see fd_disp_register)
521  *  - or provide a anscb callback here. If such callback is provided, it is called before the dispatch callbacks.
522  *    The prototype for this anscb callback function is:
523  *     void anscb(void * data, struct msg ** answer)
524  *	where:
525  *		data   : opaque data that was registered along with the callback.
526  *		answer : location of the pointer to the answer.
527  *      note1: on function return, if *answer is not NULL, the message is passed to the dispatch module for regular callbacks.
528  *	       otherwise, the callback must take care of freeing the message (fd_msg_free).
529  *	note2: the opaque data is not freed by the daemon in any case, extensions should ensure clean handling in fd_ext_fini.
530  *
531  * If no callback is registered to handle an answer, the message is discarded and an error is logged.
532  *
533  *  fd_msg_send_timeout is similar to fd_msg_send, except that it takes two additional arguments "expirecb" and "timeout".
534  * If the message parameter is an answer, there is no difference with fd_msg_send.
535  * Otherwise, if the corresponding answer (or error) is received before the timeout date elapses, everything occurs as with fd_msg_send.
536  * Otherwise, the request is removed from the queue (meaning the matching answer will be discarded upon reception) and passed to the expirecb
537  * function. Upon return, if the *msg parameter is not NULL, it is freed (not passed to other callbacks).
538  * expirecb is called in a dedicated thread.
539  *
540  *    The prototype for the expirecb callback function is:
541  *     void expirecb(void * data, struct peer_hdr * sentto, struct msg ** request)
542  *	where:
543  *		data   : opaque data that was registered along with the callback.
544  *              sentto : pointer to the peer to which the message was sent and no answer received within timeout.
545  *		request: location of the pointer to the request that was not answered.
546  *
547  * RETURN VALUE:
548  *  0      	: The message has been queued for sending (sending may fail asynchronously).
549  *  EINVAL 	: A parameter is invalid (ex: anscb provided but message is not a request).
550  *  ...
551  */
552 int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data );
553 int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout );
554 
555 /*
556  * FUNCTION:	fd_msg_add_result
557  *
558  * PARAMETERS:
559  *  msg		: A msg object -- it must be an answer.
560  *  vendor	: Vendor. If 0, add Result-Code else add Experimental-Result.
561  *  restype	: DICT_TYPE containing rescode (ex: from TYPE_BY_NAME "Enumerated(Result-Code)").
562  *  rescode	: The name of the returned error code (ex: "DIAMETER_INVALID_AVP").
563  *  errormsg	: (optional) human-readable error message to put in Error-Message AVP.
564  *  optavp	: (optional) If provided, the content will be put inside a Failed-AVP.
565  *  type_id	: 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host.
566  *
567  * DESCRIPTION:
568  *  This function adds a Result-Code AVP (if vendor is 0) or Experimental-Result AVP (vendor is not 0)
569  *  to a message, and optionally
570  *  - sets the 'E' error flag in the header,
571  *  - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs.
572  *
573  * RETURN VALUE:
574  *  0		: Operation complete.
575  *  !0		: an error occurred.
576  */
577 int fd_msg_add_result( struct msg * msg, vendor_id_t vendor, struct dict_object * restype, char * rescode, char * errormsg, struct avp * optavp, int type_id );
578 
579 /*
580  * FUNCTION:	fd_msg_rescode_set
581  *
582  * PARAMETERS:
583  *  msg		: A msg object -- it must be an answer.
584  *  rescode	: The name of the returned error code (ex: "DIAMETER_INVALID_AVP")
585  *  errormsg    : (optional) human-readable error message to put in Error-Message AVP
586  *  optavp	: (optional) If provided, the content will be put inside a Failed-AVP
587  *  type_id	: 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host.
588  *
589  * DESCRIPTION:
590  *  This function adds a Result-Code AVP to a message, and optionally
591  *  - sets the 'E' error flag in the header,
592  *  - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs.
593  *  Uses fd_msg_add_result with vendor 0 and restype for Enumerated(Result-Code).
594  *
595  * RETURN VALUE:
596  *  0		: Operation complete.
597  *  !0		: an error occurred.
598  */
599 int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id );
600 
601 /* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */
602 int fd_msg_add_origin ( struct msg * msg, int osi );
603 
604 /* Generate a new Session-Id and add it at the beginning of the message (opt is added at the end of the sid if provided) */
605 int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen );
606 
607 
608 /* Parse a message against our dictionary,
609 	return 0 in case of success.
610 	log parsing error & return error code in case of failure in parsing.
611 	In addition, if the error code is EBADMSG (the message does not follow our dictionary)
612 		if *msg was a request, *msg is NULL and *error contains the error message ready to send back on return
613 		if *msg was an answer, *msg is untouched and *error==*msg if *msg was an error message, *error is null otherwise */
614 int fd_msg_parse_or_error( struct msg ** msg, struct msg **error );
615 
616 
617 
618 
619 /*============================================================*/
620 /*                         DISPATCH                           */
621 /*============================================================*/
622 
623 /*
624  * FUNCTION:	fd_disp_app_support
625  *
626  * PARAMETERS:
627  *  app		: The dictionary object corresponding to the Application.
628  *  vendor	: (Optional) the dictionary object of a Vendor to claim support in Vendor-Specific-Application-Id
629  *  auth	: Support auth app part.
630  *  acct	: Support acct app part.
631  *
632  * DESCRIPTION:
633  *   Registers an application to be advertized in CER/CEA exchanges.
634  *  Messages with an application-id matching a registered value are passed to the dispatch module,
635  * while other messages are simply relayed or an error is returned (if local node does not relay)
636  *
637  * RETURN VALUE:
638  *  0      	: The application support is registered.
639  *  EINVAL 	: A parameter is invalid.
640  */
641 int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct );
642 
643 /* Note: if we want to support capabilities updates, we'll have to add possibility to remove an app as well... */
644 
645 
646 /*============================================================*/
647 /*                         ROUTING                            */
648 /*============================================================*/
649 
650 /* This file contains the definitions of types and functions involved in the routing decisions in freeDiameter,
651  * and that can be called by extensions.
652  *
653  * Three different type of messages must be distinguished:
654  *  - Messages received, and the peer is final recipient (IN messages)
655  *  - Messages received, and the peer is not final recipient (FWD messages)
656  *  - Message is locally generated (OUT messages)
657  *
658  * There are three global message queues (in queues.c) and also peers-specific queues (in struct fd_peer).
659  *
660  * (*) IN messages processing details:
661  *   - the message is received from the remote peer, a FDEVP_CNX_MSG_RECV event is generated for the peer.
662  *   - the PSM thread parses the buffer, does some verifications, handles non routable messages (fd_msg_is_routable)
663  *   - routable messages are queued in the fd_g_incoming global queue.
664  *   - a thread (routing-in) picks the message and takes the decision if it is handled locally or forwarded,
665  *       based on local capabilities (registered by extensions with fd_disp_app_support).
666  *   - If the message is handled locally, it is queued in fd_g_local.
667  *   - Another thread (dispatch.c) will handle this message and pass it to registered callbacks (see fd_disp_register in libfreeDiameter.h).
668  *
669  * (*) FWD messages details:
670  *   - The process is the same as for IN messages, until the routing-in threads makes its decision that the message is not handled locally.
671  *   - If the local peer does not relay message, an error DIAMETER_APPLICATION_UNSUPPORTED is returned.
672  *   - All callbacks registered with fd_rt_fwd_register are called for the message (see below).
673  *     - these callbacks will typically do proxying work. Note that adding the route-record is handled by the daemon.
674  *   - Once all callbacks have been called, the message is queued in the global fd_g_outgoing queue.
675  *   - The remaining processing is the same as for OUT messages, as described below.
676  *
677  * (*) OUT messages details:
678  *   - The message are picked from fd_g_outgoing (they are queued there as result of forwarding process or call to fd_msg_send.)
679  *   - The (routing-out) thread builds a list of possible destinations for the message, as follow:
680  *      - create a list of all known peers in the "OPEN" state.
681  *      - remove from that list all peers that are in a Route-Record AVP of the message, to avoid routing loops.
682  *      - remove also all peers that have previously replied an error message for this message.
683  *   - If the list is empty, create an error UNABLE_TO_DELIVER (note: should we trig dynamic discovery here???) and reply.
684  *   - Otherwise, call all callbacks registered by function fd_rt_out_register, with the list of peers and the message.
685  *   - Order the resulting list of peers by score (see below), and sent the message to the peer with highest (positive) score.
686  *    - in case the peer is no longer in the "OPEN" state, send the message to the second peer in the list.
687  *      - if no peer is in OPEN state anymore, restart the process of creating the list.
688  *   - Once a peer has been selected, the message is queued into that peer's outgoing queue.
689  *
690  * The following functions allow an extension to register or remove a callback as described above.
691  */
692 
693 /********** Forwarding callbacks: for Proxy operations ***********/
694 
695 /* Handle to registered callback */
696 struct fd_rt_fwd_hdl;
697 
698 /* Message direction for the callback */
699 enum fd_rt_fwd_dir {
700 	RT_FWD_REQ = 1,	/* The callback will be called on forwarded requests only */
701 	RT_FWD_ALL = 2,	/* The callback will be called on all forwarded messages (requests and answers )*/
702 	RT_FWD_ANS = 3	/* The callback will be called on answers and errors only */
703 };
704 
705 /*
706  * FUNCTION:	fd_rt_fwd_register
707  *
708  * PARAMETERS:
709  *  rt_fwd_cb	  : The callback function to register (see prototype below).
710  *  cbdata	  : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
711  *  dir           : One of the RT_FWD_* directions defined above.
712  *  handler       : On success, a handler to the registered callback is stored here.
713  *		   This handler will be used to unregister the cb.
714  *
715  * DESCRIPTION:
716  *   Register a new callback for forwarded messages. See explanations above.
717  * Note that there is no guaranteed order for the callbacks calls.
718  *
719  * RETURN VALUE:
720  *  0      	: The callback is registered.
721  *  EINVAL 	: A parameter is invalid.
722  *  ENOMEM	: Not enough memory to complete the operation
723  */
724 int fd_rt_fwd_register ( int (*rt_fwd_cb)(void * cbdata, struct msg ** msg), void * cbdata, enum fd_rt_fwd_dir dir, struct fd_rt_fwd_hdl ** handler );
725 /*
726  * CALLBACK:	rt_fwd_cb
727  *
728  * PARAMETERS:
729  *  data	: pointer to some data that was passed when the callback was registered (optional).
730  *  msg 	: The message that is being forwarded.
731  *
732  * DESCRIPTION:
733  *   This callback is called when a message is forwarded to another peer. It may for example add a Proxy-Info AVP.
734  *  The callback may also choose to handle the message in a more complex form. In that case, it must set *msg = NULL
735  *  and handle it differently. In such case, the forwarding thread will stop processing this message.
736  *
737  * RETURN VALUE:
738  *  0      	: Operation complete.
739  *  !0 		: An error occurred -- will result in daemon's termination.
740  */
741 
742 /*
743  * FUNCTION:	fd_rt_fwd_unregister
744  *
745  * PARAMETERS:
746  *  handler     : The handler of the callback that must be unregistered.
747  *  cbdata	: Will receive the data registered with the callback, that can be freed if needed.
748  *
749  * DESCRIPTION:
750  *   Removes a callback from the list of registered callbacks.
751  *
752  * RETURN VALUE:
753  *  0      	: The callback is unregistered.
754  *  EINVAL 	: A parameter is invalid.
755  */
756 int fd_rt_fwd_unregister ( struct fd_rt_fwd_hdl * handler, void ** cbdata );
757 
758 
759 /********** Out callbacks: for next hop routing decision operations ***********/
760 
761 /* Handle to registered callback */
762 struct fd_rt_out_hdl;
763 
764 enum fd_rt_out_score {
765 	FD_SCORE_NO_DELIVERY	 = -70,	/* We should not send this message to this candidate */
766 	FD_SCORE_SENT_REDIRECT	 = -60, /* If this peer previously sent a Redirect indication that applies to this message */
767 	FD_SCORE_INI		 =  -2, /* All candidates are initialized with this value */
768 	FD_SCORE_LOAD_BALANCE	 =   1,	/* Use this to differentiate between several peers with the same score */
769 	FD_SCORE_DEFAULT	 =   5,	/* The peer is a default route for all messages */
770 	FD_SCORE_DEFAULT_REALM	 =  10,	/* The peer is a default route for this realm */
771 	FD_SCORE_REALM		 =  15,	/* The peer belongs to Destination-Realm of the message */
772 	FD_SCORE_REDIR_HOST	 =  25,	/* If there is a redirect rule with ALL_HOST for these message and peer */
773 	FD_SCORE_REDIR_APP	 =  30,	/* If there is a redirect rule with ALL_APPLICATION for these message and peer */
774 	FD_SCORE_REDIR_REALM	 =  35,	/* If there is a redirect rule with ALL_REALM for these message and peer */
775 	FD_SCORE_REDIR_REALM_APP =  40,	/* If there is a redirect rule with REALM_AND_APPLICATION for these message and peer */
776 	FD_SCORE_REDIR_USER	 =  45,	/* If there is a redirect rule with ALL_USER for these message and peer */
777 	FD_SCORE_REDIR_SESSION	 =  50,	/* If there is a redirect rule with ALL_SESSION for these message and peer */
778 	FD_SCORE_REDIR_ONCE	 =  55,	/* If there is a redirect rule with DONT_CACHE for these message and peer */
779 	FD_SCORE_FINALDEST	 = 100	/* If the peer is the final recipient of the message (i.e. matching Destination-Host), it receives a big score. */
780 };
781 
782 /*
783  * FUNCTION:	fd_rt_out_register
784  *
785  * PARAMETERS:
786  *  rt_out_cb	  : The callback function to register (see prototype below).
787  *  cbdata	  : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
788  *  priority      : Order for calling this callback. The callbacks are called in reverse priority order (higher priority = called sooner).
789  *  handler       : On success, a handler to the registered callback is stored here.
790  *		   This handler will be used to unregister the cb.
791  *
792  * DESCRIPTION:
793  *   Register a new callback to handle OUT routing decisions. See explanations above.
794  *
795  * RETURN VALUE:
796  *  0      	: The callback is registered.
797  *  EINVAL 	: A parameter is invalid.
798  *  ENOMEM	: Not enough memory to complete the operation
799  */
800 int fd_rt_out_register ( int (*rt_out_cb)(void * cbdata, struct msg ** pmsg, struct fd_list * candidates), void * cbdata, int priority, struct fd_rt_out_hdl ** handler );
801 /*
802  * CALLBACK:	rt_out_cb
803  *
804  * PARAMETERS:
805  *  cbdata	: pointer to some data that was registered with the callback.
806  *  pmsg 	: pointer to the message that must be sent. upon return if *msg is NULL, the processing stops and the message is not sent.
807  *  list        : The list of peers to which the message may be sent to, as returned by fd_rtd_candidate_extract
808  *
809  * DESCRIPTION:
810  *   This callback must attribute a score (preferably from FD_SCORE_*) to each candidate peer in the list.
811  *  Once all registered callbacks have been called, the message is sent to the candidate with the highest score.
812  *  Note that each callback must *add* its locally-attributed score to the candidate current "score" parameter, not replace it!
813  *  Note also that this callback must be re-entrant since it may be called by several threads at the same time
814  *  (for different messages)
815  *
816  * RETURN VALUE:
817  *  0      	: Operation complete.
818  *  !0 		: An error occurred.
819  */
820 
821 /*
822  * FUNCTION:	fd_rt_out_unregister
823  *
824  * PARAMETERS:
825  *  handler     : The handler of the callback that must be unregistered.
826  *  cbdata	: Will receive the data registered with the callback, that can be freed if needed.
827  *
828  * DESCRIPTION:
829  *   Removes a callback from the list of registered callbacks.
830  *
831  * RETURN VALUE:
832  *  0      	: The callback is unregistered.
833  *  EINVAL 	: A parameter is invalid.
834  */
835 int fd_rt_out_unregister ( struct fd_rt_out_hdl * handler, void ** cbdata );
836 
837 
838 /*============================================================*/
839 /*                         EVENTS                             */
840 /*============================================================*/
841 
842 struct fd_event {
843 	int	 code; /* codespace depends on the queue */
844 	size_t 	 size;
845 	void    *data;
846 };
847 
848 /* Daemon's codespace: 1000->1999 (1500->1999 defined in fdcore-internal.h) */
849 enum {
850 	 FDEV_TERMINATE_INT= 1000	/* request to terminate. DO NOT USE. Use fd_core_shutdown() instead.  */
851 	,FDEV_TRIGGER			/* Trigger available for extensions. size is sizeof(int), data is int * */
852 };
853 
854 int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data);
855 int fd_event_get(struct fifo *queue, int * code, size_t * datasz, void ** data);
856 int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int * code, size_t * datasz, void ** data);
857 void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data));
858 const char * fd_ev_str(int event);
859 
860 /* for extensions */
861 int fd_event_trig_regcb(int trigger_val, const char * module, void (*cb)(void));
862 
863 #ifndef SWIG
864 DECLARE_FD_DUMP_PROTOTYPE(fd_event_trig_dump);
865 
866 /* The "old" FD_EV_DUMP_* events are replaced with direct calls to the following dump functions */
867 DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump);
868 
869 DECLARE_FD_DUMP_PROTOTYPE(fd_ext_dump);
870 #else /* SWIG */
871 DECLARE_FD_DUMP_PROTOTYPE_simple(fd_event_trig_dump);
872 DECLARE_FD_DUMP_PROTOTYPE_simple(fd_conf_dump);
873 DECLARE_FD_DUMP_PROTOTYPE_simple(fd_ext_dump);
874 #endif /* SWIG */
875 DECLARE_FD_DUMP_PROTOTYPE(fd_servers_dump, int details);
876 DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump_list, int details);
877 DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump, struct peer_hdr * p, int details);
878 
879 /*============================================================*/
880 /*                         ENDPOINTS                          */
881 /*============================================================*/
882 
883 struct fd_endpoint {
884 	struct fd_list  chain;	/* link in cnf_endpoints list */
885 
886 	union {
887 		sSS		ss;	/* the socket information. List is always ordered by ss value (memcmp) -- see fd_ep_add_merge */
888 		sSA4		sin;
889 		sSA6		sin6;
890 		sSA		sa;
891 	}
892 #ifdef SWIG /* nested anonymous unions are not supported yet */
893 			s
894 #endif /* SWIG */
895 	;
896 
897 #define	EP_FL_CONF	(1 << 0)	/* This endpoint is statically configured in a configuration file */
898 #define	EP_FL_DISC	(1 << 1)	/* This endpoint was resolved from the Diameter Identity or other DNS query */
899 #define	EP_FL_ADV	(1 << 2)	/* This endpoint was advertized in Diameter CER/CEA exchange */
900 #define	EP_FL_LL	(1 << 3)	/* Lower layer mechanism provided this endpoint */
901 #define	EP_FL_PRIMARY	(1 << 4)	/* This endpoint is primary in a multihomed SCTP association */
902 #define	EP_ACCEPTALL	(1 << 15)	/* This flag allows bypassing the address filter in fd_ep_add_merge. */
903 	uint32_t	flags;		/* Additional information about the endpoint */
904 
905 	/* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
906 };
907 
908 int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags );
909 int fd_ep_filter( struct fd_list * list, uint32_t flags );
910 int fd_ep_filter_family( struct fd_list * list, int af );
911 int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
912 DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump_one, int preamble, struct fd_endpoint * ep );
913 DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump, int preamble, int indent, struct fd_list * eps  );
914 
915 
916 /*============================================================*/
917 /*                         APPLICATIONS IDs                   */
918 /*============================================================*/
919 
920 struct fd_app {
921 	struct fd_list	 chain;	/* link in cnf_apps list. List ordered by appid. */
922 	struct {
923 		unsigned auth   : 1;
924 		unsigned acct   : 1;
925 	}		 flags;
926 	vendor_id_t	 vndid; /* if not 0, Vendor-Specific-App-Id AVP will be used */
927 	application_id_t appid;	/* The identifier of the application */
928 };
929 
930 int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct);
931 int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail);
932 int fd_app_check_common(struct fd_list * list1, struct fd_list * list2, int * common_found);
933 int fd_app_empty(struct fd_list * list);
934 
935 
936 
937 /*============================================================*/
938 /*                         MONITORING                         */
939 /*============================================================*/
940 
941 /* These functions allow an extension to collect state information about the
942  * framework, as well as being hooked at some key checkpoints in the processing
943  * for logging or statistics purpose.
944  */
945 
946 
947 /* CALLBACK: 	fd_hook_cb
948  *
949  * PARAMETERS:
950  *  type	: The type of hook that triggered this call, in case same cb is registered for several hooks.
951  *  msg 	: If relevant, the pointer to the message triggering the call. NULL otherwise.
952  *  peer        : If relevant, the pointer to the peer associated with the call. NULL otherwise.
953  *  other	: For some callbacks, the remaining information is passed in this parameter. See each hook detail.
954  *  permsgdata  : Structure associated with a given message, across several hooks.
955  *                 A different structure is associated with requests and corresponding answers.
956  *                 See fd_hook_data_hdl below for details.
957  *                 If no fd_hook_data_hdl is registered with this callback, this parameter is always NULL
958  *  regdata     : Data pointer stored at registration, opaque for the framework.
959  *
960  * DESCRIPTION:
961  *   When such callback is registered with fd_hook_register function, it will be called on matching events with
962  * the parameters as described in the list of fd_hook_type below. One can use this mechanism for e.g.:
963  *  - log completely the messages for safety / backup
964  *  - create statistics information on the throughput
965  *  - ...
966  *
967  *  IMPORTANT: the callback MUST NOT change the memory pointed by the different parameters (peer, message, ...)
968  *
969  * RETURN VALUE:
970  *  none.
971  */
972 
973 /* The available hooks in the framework */
974 enum fd_hook_type {
975 
976 	HOOK_DATA_RECEIVED = 0,
977 		/* Hook called as soon as a message has been received from the network, after TLS & boundary processing.
978 		 - {msg} is NULL.
979 		 - {peer} is NULL.
980 		 - {other} is a pointer to a struct fd_cnx_rcvdata containing the received buffer.
981 		 - {permsgdata} points to either a new empty structure allocated for this message (cf. fd_hook_data_hdl), or NULL if no hdl is registered.
982 		 */
983 
984 	HOOK_MESSAGE_RECEIVED,
985 		/* Hook called when a message has been received and the structure has been parsed successfully (list of AVPs).
986 		 - {msg} points to the parsed message. At this time, the objects have not been dictionary resolved. If you
987 		   try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
988 		 - {peer} is set if the message is received from a peer's connection, and NULL if the message is from a new client
989 		   connected and not yet identified
990 		 - {other} is NULL, or a char * identifying the connection when {peer} is null.
991 		 - {permsgdata} points to either a new empty structure allocated for this message or the one passed to HOOK_DATA_RECEIVED if used.
992 		 */
993 
994 	HOOK_MESSAGE_LOCAL,
995 		/* Hook called when a request message has been created locally by an extension and is being sent.
996 		 - {msg} points to the message.
997 		 - {peer} is NULL
998 		 - {other} is NULL
999 		 - {permsgdata} points to a new empty structure allocated for this request (cf. fd_hook_data_hdl)
1000 		 */
1001 
1002 	HOOK_MESSAGE_SENDING,
1003 		/* Hook called when a message is about to be sent to a peer. The message pointer cannot be modified here, but the content of the message
1004 		  could still be changed (for example add or remove some AVP. This is the last chance.
1005 		 - {msg} points to the message. Some objects may not have been dictionary resolved. If you
1006 		   try to call fd_msg_parse_dict, it will slow down the operation of the instance.
1007 		 - {peer} is the one the message is being sent to.
1008 		 - {other} is NULL.
1009 		 - {permsgdata} points to existing structure if any, or a new structure otherwise.
1010 		 */
1011 
1012 	HOOK_MESSAGE_SENT,
1013 		/* Hook called when a message has been sent to a peer. The message might be freed as soon as the hook function returns,
1014 		   so it is not safe to store the pointer for asynchronous processing.
1015 		 - {msg} points to the sent message. Again, the objects may not have been dictionary resolved. If you
1016 		   try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
1017 		 - {peer} is set if the message is sent to a peer's connection, and NULL if the message is sent to a new client
1018 		   connected and not yet identified, or being rejected
1019 		 - {other} is NULL.
1020 		 - {permsgdata} points to existing structure if any, or a new structure otherwise.
1021 		 */
1022 
1023 	HOOK_MESSAGE_FAILOVER,
1024 		/* Hook called when a message that was sent to a peer is being requeued, because e.g. the connection was torn down.
1025 		   In that case the message will go again through the routing process.
1026 		 - {msg} points to the corresponding request message (the answer is discarded). Again, the objects may not have been dictionary resolved. If you
1027 		   try to call fd_msg_parse_dict, it might slow down the operation of a relay agent, although this hook is not on the normal execution path.
1028 		 - {peer} is the peer this message was previously sent to.
1029 		 - {other} is NULL.
1030 		 - {permsgdata} points to existing structure if any, or a new structure otherwise.
1031 		 */
1032 
1033 	HOOK_MESSAGE_PARSING_ERROR,
1034 		/* Hook called when a message being processed cannot be parsed successfully.
1035 		 - {msg} points to the message if buffer was parsed successfully, or NULL otherwise. You should not call fd_msg_parse_dict on this in any case.
1036 		 - {peer} is NULL or the peer that received the message. If NULL and the message is not NULL, you can still retrieve the source from the message itself.
1037 		 - {other} is a char * pointer to the error message (human-readable) if {msg} is not NULL, a pointer to struct fd_cnx_rcvdata containing the received buffer otherwise.
1038 		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
1039 		 */
1040 
1041 	HOOK_MESSAGE_ROUTING_ERROR,
1042 		/* Hook called when a message being processed by the routing thread meets an error such as no remaining available peer for sending, based on routing callbacks decisions (maybe after retries).
1043 		 - {msg} points to the message. Again, the objects may not have been dictionary resolved. If you
1044 		   try to call fd_msg_parse_dict, it might slow down the operation of a relay agent, although this hook is not on the normal execution path.
1045 		 - {peer} is NULL.
1046 		 - {other} is a char * pointer to the error message (human-readable).
1047 		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
1048 		 */
1049 
1050 	HOOK_MESSAGE_ROUTING_FORWARD,
1051 		/* Hook called when a received message is deemed to be not handled locally by the routing_dispatch process.
1052 		   The decision of knowing which peer it will be sent to is not made yet (or if an error will be returned).
1053 		   The hook is trigged before the callbacks registered with fd_rt_fwd_register are called.
1054 		 - {msg} points to the message. Again, the objects may not have been dictionary resolved.
1055 		    If you try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
1056 		 - {peer} is NULL.
1057 		 - {other} is NULL.
1058 		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
1059 		 */
1060 
1061 	HOOK_MESSAGE_ROUTING_LOCAL,
1062 		/* Hook called when a received message is handled locally by the routing_dispatch process (i.e., not forwarded).
1063 		   The hook is trigged before the callbacks registered with fd_disp_register are called.
1064 		 - {msg} points to the message. Here, the message has been already parsed completely & successfully.
1065 		 - {peer} is NULL.
1066 		 - {other} is NULL.
1067 		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
1068 		 */
1069 
1070 	HOOK_MESSAGE_DROPPED,
1071 		/* Hook called when a message is being discarded by the framework because of some error condition (normal or abnormal).
1072 		   It is probably a good idea to log this for analysis / backup.
1073 		 - {msg} points to the message, which will be freed as soon as the hook returns.
1074 		 - {peer} may be NULL or a peer related to the event.
1075 		 - {other} is a char * pointer to the error message (human-readable).
1076 		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
1077 		 */
1078 
1079 	HOOK_PEER_CONNECT_FAILED,
1080 		/* Hook called when a connection attempt to/from a remote peer has failed. This hook is also called when the peer was in OPEN state and the connection is broken.
1081 		 - {msg} may be NULL (lower layer error, e.g. connection timeout) or points to a message showing the error (either invalid incoming message, or the CEA message sent or received with an error code).
1082 		 - {peer} may be NULL for incoming requests from unknown peers being rejected, otherwise it points to the peer structure associated with the attempt.
1083 		 - {other} is a char * pointer to the error message (human-readable).
1084 		 - {permsgdata} is always NULL for this hook.
1085 		 */
1086 
1087 	HOOK_PEER_CONNECT_SUCCESS,
1088 		/* Hook called when a connection attempt to/from a remote peer has succeeded (the peer moves to OPEN_HANDSHAKE or OPEN state).
1089 		    In case of deprecated TLS handshake after the CER/CEA exchange, this hook can still be followed by HOOK_PEER_CONNECT_FAILED if TLS handshake fails.
1090 		 - {msg} points to the CEA message sent or received (with a success code) -- in case it is sent, you can always get access to the matching CER.
1091 		 - {peer} points to the peer structure.
1092 		 - {other} is NULL.
1093 		 - {permsgdata} is always NULL for this hook.
1094 		 */
1095 
1096 	HOOK_MESSAGE_PARSING_ERROR2,
1097 		/* Hook called after an error message has been generated due to a dictionary parsing error.
1098 		 - {msg} points to the error message that has been generated.
1099 		 - {peer} is NULL. You can still retrieve the source from the message itself.
1100 		 - {other} is NULL
1101 		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
1102 		 Use this hook if you need to populate more data in the error being returned, from the error message.
1103 		 (e.g. some AVP need to be added to replies even if error case.
1104 		 */
1105 #define HOOK_LAST	HOOK_MESSAGE_PARSING_ERROR2
1106 };
1107 
1108 
1109 /* Type of the {permsgdata} pointer. It is up to each extension to define its own structure. This is opaque for the framework. */
1110 struct fd_hook_permsgdata;
1111 
1112 /* A handle that will be associated with the extension, and with the permsgdata structures. */
1113 struct fd_hook_data_hdl;
1114 
1115 /* The following structure is what is passed to the HOOK_DATA_RECEIVED hook */
1116 struct fd_cnx_rcvdata {
1117 	size_t  length;
1118 	uint8_t * buffer; /* internal note: the buffer is padded with a struct fd_msg_pmdl, not accounted for in length */
1119 };
1120 
1121 /* Function to register a new fd_hook_data_hdl. Should be called by your extension init function.
1122  * The arguments are the functions called to initialize a new fd_hook_permsgdata and to free this structure when the corresponding message is being freed.
1123  */
1124 /*
1125  * FUNCTION:	fd_hook_data_register
1126  *
1127  * PARAMETERS:
1128  *  permsgdata_size     : the size of the fd_hook_permsgdata structure.
1129  *  permsgdata_init_cb  : function called to initialize a new fd_hook_permsgdata structure, when a hook will be called for a message that does not have such structure yet.
1130  *                           The memory is already allocated and blanked, so you can pass NULL if no further handling is required.
1131  *  permsgdata_fini_cb  : function called when a message is being disposed. It should free the resources associated with the fd_hook_permsgdata.
1132  *                           You can pass NULL if no special handling is required. The memory of the permsgdata structure itself will be freed by the framework.
1133  *  new_handle          : On success, a handler to the registered callback is stored here.
1134  *		             This handler will be used to unregister the cb.
1135  *
1136  * DESCRIPTION:
1137  *   Register a new fd_hook_data_hdl. This handle is used during hooks registration (see below) in order to associate data with the messages, to allow keeping tracking of the message easily.
1138  *  Note that these handlers are statically allocated and cannot be unregistered. FD_HOOK_HANDLE_LIMIT handlers can be registered at maximum (recompile libfdproto if you change this value)
1139  *
1140  * RETURN VALUE:
1141  *  0      	: The callback is registered.
1142  *  EINVAL 	: A parameter is invalid.
1143  *  ENOSPC	: Too many handles already registered. You may need to increase the limit in the code.
1144  */
1145 int fd_hook_data_register(
1146 	size_t permsgdata_size,
1147 	void (*permsgdata_init_cb) (struct fd_hook_permsgdata *),
1148         void (*permsgdata_fini_cb) (struct fd_hook_permsgdata *),
1149         struct fd_hook_data_hdl **new_handle
1150 );
1151 
1152 /* A handler associated with a registered hook callback (for cleanup) */
1153 struct fd_hook_hdl;
1154 
1155 /* Helper for building a mask of hooks for registration */
1156 #define HOOK_MASK(hooklist...)	fd_hook_mask_helper(0, ## hooklist, -1)
1157 
1158 /*
1159  * FUNCTION:	fd_hook_register
1160  *
1161  * PARAMETERS:
1162  *  type_mask	  : A bitmask of fd_hook_type bits for which this cb is registered, e.g. HOOK_MASK( HOOK_MESSAGE_RECEIVED, HOOK_MESSAGE_SENT )
1163  *  fd_hook_cb	  : The callback function to register (see prototype above).
1164  *  regdata	  : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
1165  *  data_hdl      : If permsgdata is requested for the hooks, a handler registered with fd_hook_data_register. NULL otherwise.
1166  *  handler       : On success, a handler to the registered callback is stored here.
1167  *		   This handler can be used to unregister the cb.
1168  *
1169  * DESCRIPTION:
1170  *   Register a new hook in the framework. See explanations above.
1171  *
1172  * RETURN VALUE:
1173  *  0      	: The callback is registered.
1174  *  EEXIST      : Another callback is already registered for this type of hook (HOOK_DATA_RECEIVED).
1175  *  EINVAL 	: A parameter is invalid.
1176  *  ENOMEM	: Not enough memory to complete the operation
1177  */
1178 int fd_hook_register (  uint32_t type_mask,
1179 			void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata),
1180 			void  *regdata,
1181 			struct fd_hook_data_hdl *data_hdl,
1182 			struct fd_hook_hdl ** handler );
1183 
1184 /* Remove a hook registration */
1185 int fd_hook_unregister( struct fd_hook_hdl * handler );
1186 
1187 
1188 /* Use the following function to retrieve any pmd structure associated with a request matching the current answer. Returns NULL in case of error / no such structure */
1189 struct fd_hook_permsgdata * fd_hook_get_request_pmd(struct fd_hook_data_hdl *data_hdl, struct msg * answer);
1190 
1191 /* Use the following function to retrieve any pmd structure associated with a request. Returns NULL in case of error */
1192 struct fd_hook_permsgdata * fd_hook_get_pmd(struct fd_hook_data_hdl *data_hdl, struct msg * msg);
1193 
1194 
1195 /* The following is used by HOOK_MASK macro */
1196 uint32_t fd_hook_mask_helper(int dummy, ...);
1197 
1198 /*============================================================*/
1199 
1200 /*
1201  * The following allows an extension to retrieve stat information on the different fifo queues involved in the freeDiameter framework.
1202  * There are three global queues, plus per-peer queues.
1203  * This information can be used to build SNMP-like data for example, or quickly get a status of the framework to find the loaded path of execution / bottlenecks.
1204  */
1205 enum fd_stat_type {
1206 	/* For the following, no peer is associated with the stat */
1207 	STAT_G_LOCAL= 1,	/* Get statistics for the global queue of messages processed by local extensions */
1208 	STAT_G_INCOMING,	/* Get statistics for the global queue of received messages to be processed by routing_in thread */
1209 	STAT_G_OUTGOING,	/* Get statistics for the global queue of messages to be processed by routing_out thread */
1210 
1211 	/* For the following, the peer must be provided */
1212 	STAT_P_PSM,		/* Peer state machine queue (events to be processed for this peer, including received messages) */
1213 	STAT_P_TOSEND,		/* Queue of messages for sending to this peer */
1214 };
1215 
1216 /*
1217  * FUNCTION:	fd_stat_getstats
1218  *
1219  * PARAMETERS:
1220  *  stat	  : Which queue is being queried
1221  *  peer	  : (depending on the stat parameter) which peer is being queried
1222  *  current_count : (out) The number of items in the queue currently
1223  *  limit_count   : (out) The max number of items the queue accepts before becoming blocking -- 0 means no max.
1224  *  highest_count : (out) The highest count the queue has reached since startup
1225  *  total_count	  : (out) Total number of items that this queue has processed (always growing, use deltas for monitoring)
1226  *  total	  : (out) Cumulated time all items spent in this queue, including blocking time (always growing, use deltas for monitoring)
1227  *  blocking      : (out) Cumulated time threads trying to post new items were blocked (queue full).
1228  *  last          : (out) For the last element retrieved from the queue, how long it took between posting (including blocking) and poping
1229  *
1230  * DESCRIPTION:
1231  *   Get statistics information about a given queue.
1232  *  Any of the (out) parameters can be NULL if not requested.
1233  *
1234  * RETURN VALUE:
1235  *  0      	: The callback is registered.
1236  *  EINVAL 	: A parameter is invalid.
1237  */
1238 int fd_stat_getstats(enum fd_stat_type stat, struct peer_hdr * peer,
1239 			int * current_count, int * limit_count, int * highest_count, long long * total_count,
1240 			struct timespec * total, struct timespec * blocking, struct timespec * last);
1241 
1242 /*============================================================*/
1243 /*                         EOF                                */
1244 /*============================================================*/
1245 
1246 #ifdef __cplusplus
1247 }
1248 #endif
1249 
1250 #endif /* _LIBFDCORE_H */
1251