Index: include/freeDiameter/CMakeLists.txt
===================================================================
--- include/freeDiameter/CMakeLists.txt	(revision 561)
+++ include/freeDiameter/CMakeLists.txt	(revision 658)
@@ -1,5 +1,5 @@
 #CMake configuration for freeDiameter include directory
 
-Project("freeDiameter include directory" C)
+Project("freeDiameter includes directory" C)
 
 ########################
@@ -68,6 +68,6 @@
 ENDIF (HAVE_CLOCK_GETTIME)
 
-# LFD_LIBS = libraries required by the libfreeDiameter.
-SET(LFD_LIBS ${CLOCK_GETTIME_LIBS} ${CMAKE_THREAD_LIBS_INIT})
+# LFDPROTO_LIBS = libraries required by the libfdproto.
+SET(LFDPROTO_LIBS ${CLOCK_GETTIME_LIBS} ${CMAKE_THREAD_LIBS_INIT})
 
 
@@ -98,6 +98,26 @@
 
 
-# FD_LIBS = libraries required by the daemon
-SET(FD_LIBS ${CMAKE_DL_LIBS} ${SCTP_LIBRARIES})
+# Require GNU TLS for building the library
+FIND_PACKAGE(GnuTLS REQUIRED)
+INCLUDE_DIRECTORIES(${GNUTLS_INCLUDE_DIR})
+
+find_path(GCRYPT_INCLUDE_DIR NAMES gcrypt.h)
+If ( NOT GCRYPT_INCLUDE_DIR )
+	MESSAGE(SEND_ERROR "Unable to find gcrypt.h, please install libgcrypt-dev or equivalent")
+Endif ( NOT GCRYPT_INCLUDE_DIR )
+MARK_AS_ADVANCED(GCRYPT_INCLUDE_DIR)
+INCLUDE_DIRECTORIES(${GCRYPT_INCLUDE_DIR})
+
+# Also we need libgcrypt to... display its version :(
+find_library(GCRYPT_LIBRARY 
+  NAMES gcrypt
+)
+If ( NOT GCRYPT_LIBRARY )
+	MESSAGE(SEND_ERROR "Unable to find libgcrypt, please install libgcrypt or equivalent")
+Endif ( NOT GCRYPT_LIBRARY )
+
+
+# LFDCORE_LIBS = libraries required by the libfdcore
+SET(LFDCORE_LIBS ${CMAKE_DL_LIBS} ${SCTP_LIBRARIES} ${GCRYPT_LIBRARY} ${GNUTLS_LIBRARIES})
 
 ##########################
@@ -111,6 +131,6 @@
 
 # Save some variables for the other directories
-SET(FD_LIBS  ${FD_LIBS}  PARENT_SCOPE)
-SET(LFD_LIBS ${LFD_LIBS} PARENT_SCOPE)
+SET(LFDPROTO_LIBS ${LFDPROTO_LIBS} PARENT_SCOPE)
+SET(LFDCORE_LIBS  ${LFDCORE_LIBS}  PARENT_SCOPE)
 SET(CMAKE_THREAD_LIBS_INIT ${CMAKE_THREAD_LIBS_INIT} PARENT_SCOPE)
 
@@ -119,5 +139,5 @@
 
 # The headers from this directory are required to develop new extensions for freeDiameter.
-INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/freeDiameter-host.h libfreeDiameter.h freeDiameter.h extension.h
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/freeDiameter-host.h libfdproto.h libfdcore.h extension.h
 	DESTINATION ${INSTALL_HEADERS_SUFFIX}
 	COMPONENT freeDiameter-dev)
Index: include/freeDiameter/extension.h
===================================================================
--- include/freeDiameter/extension.h	(revision 8)
+++ include/freeDiameter/extension.h	(revision 658)
@@ -3,5 +3,5 @@
 * Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
 *													 *
-* Copyright (c) 2009, WIDE Project and NICT								 *
+* Copyright (c) 2011, WIDE Project and NICT								 *
 * All rights reserved.											 *
 * 													 *
@@ -39,5 +39,5 @@
 /* Include definition of freeDiameter API */
 #include <freeDiameter/freeDiameter-host.h>
-#include <freeDiameter/freeDiameter.h>
+#include <freeDiameter/libfdcore.h>
 
 /* Macro that define the entry point of the extension */
Index: include/freeDiameter/freeDiameter-host.h.in
===================================================================
--- include/freeDiameter/freeDiameter-host.h.in	(revision 648)
+++ include/freeDiameter/freeDiameter-host.h.in	(revision 658)
@@ -75,3 +75,7 @@
 #cmakedefine DEFAULT_EXTENSIONS_PATH "@DEFAULT_EXTENSIONS_PATH@"
 
+#ifndef FD_DEFAULT_CONF_FILENAME
+#define FD_DEFAULT_CONF_FILENAME "freeDiameter.conf"
+#endif /* FD_DEFAULT_CONF_FILENAME */
+
 #endif /* FD_IS_CONFIG */
Index: include/freeDiameter/freeDiameter.h
===================================================================
--- include/freeDiameter/freeDiameter.h	(revision 648)
+++ 	(revision )
@@ -1,758 +1,0 @@
-/*********************************************************************************************************
-* Software License Agreement (BSD License)                                                               *
-* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
-*													 *
-* Copyright (c) 2011, WIDE Project and NICT								 *
-* All rights reserved.											 *
-* 													 *
-* Redistribution and use of this software in source and binary forms, with or without modification, are  *
-* permitted provided that the following conditions are met:						 *
-* 													 *
-* * Redistributions of source code must retain the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer.										 *
-*    													 *
-* * Redistributions in binary form must reproduce the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer in the documentation and/or other						 *
-*   materials provided with the distribution.								 *
-* 													 *
-* * Neither the name of the WIDE Project or NICT nor the 						 *
-*   names of its contributors may be used to endorse or 						 *
-*   promote products derived from this software without 						 *
-*   specific prior written permission of WIDE Project and 						 *
-*   NICT.												 *
-* 													 *
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
-* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
-* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
-* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
-* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
-* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
-* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
-*********************************************************************************************************/
-
-#ifndef _FREEDIAMETER_H
-#define _FREEDIAMETER_H
-
-
-#include <freeDiameter/libfreeDiameter.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-/* GNUTLS version */
-#ifndef GNUTLS_VERSION
-#define GNUTLS_VERSION LIBGNUTLS_VERSION
-#endif /* GNUTLS_VERSION */
-
-/* GNUTLS calls debug level */
-#ifndef GNUTLS_DBG_LEVEL
-#define GNUTLS_DBG_LEVEL ANNOYING
-#endif /* GNUTLS_DBG_LEVEL */
-
-/* Check the return value of a GNUTLS function, log and propagate */
-#define CHECK_GNUTLS_DO( __call__, __fallback__ ) {						\
-	int __ret__;										\
-	TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: " #__call__ );				\
-	__ret__ = (__call__);									\
-	if (__ret__ < 0) {									\
-		TRACE_DEBUG(INFO, "Error in '" #__call__ "':\t%s", gnutls_strerror(__ret__));	\
-		__fallback__;									\
-	}											\
-}
-
-/* For GNUTLS routines that do not return a value */
-#define GNUTLS_TRACE( __call__) {					\
-	TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: " #__call__ );	\
-	(__call__);							\
-}
-
-/* Structure to hold the configuration of the freeDiameter daemon */
-#define	EYEC_CONFIG	0xC011F16
-struct fd_config {
-	int		 cnf_eyec;	/* Eye catcher: EYEC_CONFIG */
-	
-	char		*cnf_file;	/* Configuration file to parse, default is DEFAULT_CONF_FILE */
-	
-	char   		*cnf_diamid;	/* Diameter Identity of the local peer (FQDN -- UTF-8) */
-	size_t		 cnf_diamid_len;	/* length of the previous string */
-	char		*cnf_diamrlm;	/* Diameter realm of the local peer, default to realm part of diam_id */
-	size_t		 cnf_diamrlm_len;/* length of the previous string */
-	
-	unsigned int	 cnf_timer_tc;	/* The value in seconds of the default Tc timer */
-	unsigned int 	 cnf_timer_tw;	/* The value in seconds of the default Tw timer */
-	
-	uint16_t	 cnf_port;	/* the local port for legacy Diameter (default: 3868) in host byte order */
-	uint16_t	 cnf_port_tls;	/* the local port for Diameter/TLS (default: 3869) in host byte order */
-	uint16_t	 cnf_sctp_str;	/* default max number of streams for SCTP associations (def: 30) */
-	struct fd_list	 cnf_endpoints;	/* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all) */
-	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. */
-	uint16_t	 cnf_dispthr;	/* Number of dispatch threads to create */
-	struct {
-		unsigned no_fwd : 1;	/* the peer does not relay messages (0xffffff app id) */
-		unsigned no_ip4 : 1;	/* disable IP */
-		unsigned no_ip6 : 1;	/* disable IPv6 */
-		unsigned no_tcp : 1;	/* disable use of TCP */
-		unsigned no_sctp: 1;	/* disable the use of SCTP */
-		unsigned pr_tcp	: 1;	/* prefer TCP over SCTP */
-		unsigned tls_alg: 1;	/* TLS algorithm for initiated cnx. 0: separate port. 1: inband-security (old) */
-	} 		 cnf_flags;
-	
-	struct {
-		/* Credentials parameters (backup) */
-		char *  			 cert_file;
-		char *				 key_file;
-		
-		char *  			 ca_file;
-		int				 ca_file_nr;
-		char *  			 crl_file;
-		
-		char *				 prio_string;
-		unsigned int 			 dh_bits;
-		char *				 dh_file;
-		
-		/* GNUTLS parameters */
-		gnutls_priority_t 		 prio_cache;
-		gnutls_dh_params_t 		 dh_cache;
-		
-		/* GNUTLS server credential(s) */
-		gnutls_certificate_credentials_t credentials;
-		
-	} 		 cnf_sec_data;
-	
-	uint32_t	 cnf_orstateid;	/* The value to use in Origin-State-Id, default to random value */
-	struct dictionary *cnf_dict;	/* pointer to the global dictionary */
-	struct fifo	  *cnf_main_ev;	/* events for the daemon's main (struct fd_event items) */
-};
-extern struct fd_config *fd_g_config; /* The pointer to access the global configuration, initalized in main */
-
-
-/***************************************/
-/*   Peers information                 */
-/***************************************/
-
-/* States of a peer */
-enum peer_state {
-	/* Stable states */
-	STATE_NEW = 0,		/* The peer has been just been created, PSM thread not started yet */
-	STATE_OPEN,		/* Connexion established */
-	
-	/* Peer state machine */
-	STATE_CLOSED,		/* No connection established, will re-attempt after TcTimer. */
-	STATE_CLOSING,		/* the connection is being shutdown (DPR/DPA in progress) */
-	STATE_WAITCNXACK,	/* Attempting to establish transport-level connection */
-	STATE_WAITCNXACK_ELEC,	/* Received a CER from this same peer on an incoming connection (other peer object), while we were waiting for cnx ack */
-	STATE_WAITCEA,		/* Connection established, CER sent, waiting for CEA */
-	/* STATE_WAITRETURNS_ELEC, */	/* This state is not stable and therefore deprecated:
-				   We have sent a CER on our initiated connection, and received a CER from the remote peer on another connection. Election.
-				   If we win the election, we must disconnect the initiated connection and send a CEA on the other => we go to OPEN state.
-				   If we lose, we disconnect the other connection (receiver) and fallback to WAITCEA state. */
-	STATE_OPEN_HANDSHAKE,	/* TLS Handshake and validation are in progress in open state -- we use it only for debug purpose, it is never displayed */
-	
-	/* Failover state machine */
-	STATE_SUSPECT,		/* A DWR was sent and not answered within TwTime. Failover in progress. */
-	STATE_REOPEN,		/* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */
-	
-	/* Error state */
-	STATE_ZOMBIE		/* The PSM thread is not running anymore; it must be re-started or peer should be deleted. */
-#define STATE_MAX STATE_ZOMBIE
-};
-/* The following macro is called in freeDiameter/p_psm.c */
-#define DECLARE_STATE_STR()		\
-const char *peer_state_str[] = { 	\
-	  "STATE_NEW"			\
-	, "STATE_OPEN"			\
-	, "STATE_CLOSED"		\
-	, "STATE_CLOSING"		\
-	, "STATE_WAITCNXACK"		\
-	, "STATE_WAITCNXACK_ELEC"	\
-	, "STATE_WAITCEA"		\
-	, "STATE_OPEN_HANDSHAKE"	\
-	, "STATE_SUSPECT"		\
-	, "STATE_REOPEN"		\
-	, "STATE_ZOMBIE"		\
-	};
-extern const char *peer_state_str[];
-#define STATE_STR(state) \
-	(((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "<Invalid>")
-
-/* Constants for the peer_info structure bellow */
-#define PI_P3_DEFAULT	0	/* Use any available protocol */
-#define PI_P3_IP	1	/* Use only IP to connect to this peer */
-#define PI_P3_IPv6	2	/* resp, IPv6 */
-
-#define PI_P4_DEFAULT	0	/* Attempt any available protocol */
-#define PI_P4_TCP	1	/* Only use TCP */
-#define PI_P4_SCTP	2	/* Only use SCTP */
-
-#define PI_ALGPREF_SCTP	0	/* SCTP is  attempted first (default) */
-#define PI_ALGPREF_TCP	1	/* TCP is attempted first */
-
-#define PI_SEC_DEFAULT	0	/* New TLS security (handshake after connection, protecting also CER/CEA) */
-#define PI_SEC_NONE	1	/* Transparent security with this peer (IPsec) */
-#define PI_SEC_TLS_OLD	2	/* Old TLS security (use Inband-Security-Id AVP during CER/CEA) */
-				/* Set sec = 3 to authorize use of (Inband-Security-Id == NONE) with this peer, sec = 2 only authorizing TLS */
-
-#define PI_EXP_NONE	0	/* the peer entry does not expire */
-#define PI_EXP_INACTIVE	1	/* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */
-
-#define PI_PRST_NONE	0	/* the peer entry is deleted after disconnection / error */
-#define PI_PRST_ALWAYS	1	/* the peer entry is persistant (will be kept as ZOMBIE in case of error) */
-			
-/* Information about a remote peer */
-struct peer_info {
-	
-	char * 		pi_diamid;	/* UTF-8, \0 terminated. The Diameter Identity of the remote peer. */
-	
-	struct {
-		struct {
-			unsigned	pro3 :2;	/* PI_P3_* */
-			unsigned	pro4 :2;	/* PI_P4_* */
-			unsigned	alg :1;		/* PI_ALGPREF_* */
-			unsigned	sec :2;		/* PI_SEC_* */
-			unsigned	exp :1;		/* PI_EXP_* */
-			unsigned	persist :1;	/* PI_PRST_* */
-			
-		}		pic_flags;	/* Flags influencing the connection to the remote peer */
-		
-		char * 		pic_realm;	/* If configured, the daemon will match the received realm in CER/CEA matches this. */
-		uint16_t	pic_port; 	/* port to connect to. 0: default. */
-		
-		uint32_t 	pic_lft;	/* lifetime of this peer when inactive (see pic_flags.exp definition) */
-		int		pic_tctimer; 	/* use this value for TcTimer instead of global, if != 0 */
-		int		pic_twtimer; 	/* use this value for TwTimer instead of global, if != 0 */
-		
-		char *		pic_priority;	/* Priority string for GnuTLS if we don't use the default */
-		
-	} config;	/* Configured data (static for this peer entry) */
-	
-	struct {
-		
-		enum peer_state	pir_state;	/* Current state of the peer in the state machine. fd_cpu_flush_cache() might be useful before reading. */
-		
-		char * 		pir_realm;	/* The received realm in CER/CEA. */
-		
-		uint32_t	pir_vendorid;	/* Content of the Vendor-Id AVP, or 0 by default */
-		uint32_t	pir_orstate;	/* Origin-State-Id value */
-		char *		pir_prodname;	/* copy of UTF-8 Product-Name AVP (\0 terminated) */
-		uint32_t	pir_firmrev;	/* Content of the Firmware-Revision AVP */
-		int		pir_relay;	/* The remote peer advertized the relay application */
-		struct fd_list	pir_apps;	/* applications advertised by the remote peer, except relay (pi_flags.relay) */
-		int		pir_isi;	/* Inband-Security-Id advertised (PI_SEC_* bits) */
-		
-		uint32_t	pir_lastDC;	/* The last Disconnect-Cause value received */
-		
-		int		pir_proto;	/* The L4 protocol currently used with the peer (IPPROTO_TCP or IPPROTO_SCTP) */
-		const gnutls_datum_t 	*pir_cert_list; 	/* The (valid) credentials that the peer has presented, or NULL if TLS is not used */
-								/* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo 
-								   see there for example of using this data */
-		unsigned int 	pir_cert_list_size;		/* Number of certificates in the list */
-		
-	} runtime;	/* Data populated after connection, may change between 2 connections -- not used by fd_peer_add */
-	
-	struct fd_list	pi_endpoints;	/* Endpoint(s) of the remote peer (configured, discovered, or advertized). list of struct fd_endpoint. DNS resolved if empty. */
-};
-
-
-struct peer_hdr {
-	struct fd_list	 chain;	/* List of all the peers, ordered by their Diameter Id */
-	struct peer_info info;	/* The public data */
-	
-	/* This header is followed by more data in the private peer structure definition */
-};
-
-/* the global list of peers. 
-  Since we are not expecting so many connections, we don't use a hash, but it might be changed.
-  The list items are peer_hdr structures (actually, fd_peer, but the cast is OK) */
-extern struct fd_list fd_g_peers;
-extern pthread_rwlock_t fd_g_peers_rw; /* protect the list */
-
-/*
- * FUNCTION:	fd_peer_add
- *
- * PARAMETERS:
- *  info 	: Information to create the peer.
- *  orig_dbg	: A string indicating the origin of the peer information, for debug (ex: conf, redirect, ...)
- *  cb		: optional, a callback to call (once) when the peer connection is established or failed
- *  cb_data	: opaque data to pass to the callback.
- *
- * DESCRIPTION: 
- *  Add a peer to the list of peers to which the daemon must maintain a connexion.
- *
- *  The content of info parameter is copied, except for the list of endpoints if 
- * not empty, which is simply moved into the created object. It means that the list
- * items must have been malloc'd, so that they can be freed.
- *
- *  If cb is not null, the callback is called when the connection is in OPEN state or
- * when an error has occurred. The callback should use the pi_state information to 
- * determine which one it is. If the first parameter of the called callback is NULL, it 
- * means that the peer is being destroyed before attempt success / failure. 
- * cb is called to allow freeing cb_data in  * this case.
- *
- *  The orig_dbg string is only useful for easing debug, and can be left to NULL.
- *
- * RETURN VALUE:
- *  0      	: The peer is added.
- *  EINVAL 	: A parameter is invalid.
- *  EEXIST 	: A peer with the same Diameter-Id is already in the list.
- *  (other standard errors may be returned, too, with their standard meaning. Example:
- *    ENOMEM 	: Memory allocation for the new object element failed.)
- */
-int fd_peer_add ( struct peer_info * info, char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data );
-
-/*
- * FUNCTION:	fd_peer_getbyid
- *
- * PARAMETERS:
- *  diamid 	: A \0 terminated string.
- *  peer	: The peer is stored here if it exists.
- *
- * DESCRIPTION: 
- *   Search a peer by its Diameter-Id.
- *
- * RETURN VALUE:
- *  0   : *peer has been updated (to NULL if the peer is not found).
- * !0	: An error occurred.
- */
-int fd_peer_getbyid( char * diamid, struct peer_hdr ** peer );
-
-/*
- * FUNCTION:	fd_peer_validate_register
- *
- * PARAMETERS:
- *  peer_validate 	: Callback as defined bellow.
- *
- * DESCRIPTION: 
- *  Add a callback to authorize / reject incoming peer connections.
- * All registered callbacks are called until a callback sets auth = -1 or auth = 1.
- * If no callback returns a clear decision, the default behavior is applied (reject unknown connections)
- * The callbacks are called in FILO order of their registration.
- *
- * RETURN VALUE:
- *  0   : The callback is added.
- * !0	: An error occurred.
- */
-int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) );
-/*
- * CALLBACK:	peer_validate
- *
- * PARAMETERS:
- *   info     : Structure containing information about the peer attempting the connection.
- *   auth     : Store there the result if the peer is accepted (1), rejected (-1), or unknown (0).
- *   cb2      : If != NULL and in case of PI_SEC_TLS_OLD, another callback to call after handshake (if auth = 1).
- *
- * DESCRIPTION: 
- *   This callback is called when a new connection is being established from an unknown peer,
- * after the CER is received. An extension must register such callback with peer_validate_register.
- *
- *   The callback can learn if the peer has sent Inband-Security-Id AVPs in runtime.pir_isi fields.
- * It can also learn if a handshake has already been performed in runtime.pir_cert_list field.
- * The callback must set the value of config.pic_flags.sec appropriately to allow a connection without TLS.
- *
- *   If the old TLS mechanism is used,
- * the extension may also need to check the credentials provided during the TLS
- * exchange (remote certificate). For this purpose, it may set the address of a new callback
- * to be called once the handshake is completed. This new callback receives the information
- * structure as parameter (with pir_cert_list set) and returns 0 if the credentials are correct,
- * or an error code otherwise. If the error code is received, the connection is closed and the 
- * peer is destroyed.
- * Note that freeDiameter already achieves some usual checks. The callback may be used to enforce
- * additional restrictions.
- *
- * RETURN VALUE:
- *  0      	: The authorization decision has been written in the location pointed by auth.
- *  !0 		: An error occurred.
- */
-
-/***************************************/
-/*   Sending a message on the network  */
-/***************************************/
-
-/*
- * FUNCTION:	fd_msg_send, fd_msg_send_timeout  
- *
- * PARAMETERS:
- *  pmsg 	: Location of the message to be sent on the network (set to NULL on function return to avoid double deletion).
- *  anscb	: A callback to be called when answer is received, if msg is a request (optional for fd_msg_send)
- *  anscb_data	: opaque data to be passed back to the anscb when it is called.
- *  timeout     : (only for fd_msg_send_timeout) sets the absolute time until when to wait for an answer. Past this time,
- *                the anscb is called with the request as parameter and the answer will be discarded when received.
- *
- * DESCRIPTION: 
- *   Sends a message on the network. (actually simply queues it in a global queue, to be picked by a daemon's thread)
- * For requests, the end-to-end id must be set (see fd_msg_get_eteid / MSGFL_ALLOC_ETEID).
- * For answers, the message must be created with function fd_msg_new_answ.
- *
- * The routing module will handle sending to the correct peer, usually based on the Destination-Realm / Destination-Host AVP.
- *
- * If the msg is a request, there are two ways of receiving the answer:
- *  - either having registered a callback in the dispatch module (see fd_disp_register)
- *  - or provide a callback as parameter here. If such callback is provided, it is called before the dispatch callbacks.
- *    The prototype for this callback function is:
- *     void anscb(void * data, struct msg ** answer)
- *	where:
- *		data   : opaque data that was registered along with the callback.
- *		answer : location of the pointer to the answer.
- *      note1: on function return, if *answer is not NULL, the message is passed to the dispatch module for regular callbacks.
- *	       otherwise, the callback must take care of freeing the message (fd_msg_free).
- *	note2: the opaque data is not freed by the daemon in any case, extensions should ensure clean handling in fd_ext_fini.
- * 
- * If no callback is registered to handle an answer, the message is discarded and an error is logged.
- *
- *  fd_msg_send_timeout is similar to fd_msg_send, except that it takes an additional argument "timeout" and can be called
- * only with requests as parameters, and an anscb callback.
- * If the matching answer or error is received before the timeout date passes, everything occurs as with fd_msg_send. Otherwise,
- * the request is removed from the queue (meaning the matching answer will be discarded upon reception) and passed to the answcb 
- * function. This function can easily distinguish between timeout case and answer case by checking if the message received is 
- * a request. Upon return, if the *msg parameter is not NULL, it is freed (not passed to other callbacks).
- *
- * RETURN VALUE:
- *  0      	: The message has been queued for sending (sending may fail asynchronously).
- *  EINVAL 	: A parameter is invalid (ex: anscb provided but message is not a request).
- *  ...
- */
-int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data );
-int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, const struct timespec *timeout );
-
-/*
- * FUNCTION:	fd_msg_rescode_set
- *
- * PARAMETERS:
- *  msg		: A msg object -- it must be an answer.
- *  rescode	: The name of the returned error code (ex: "DIAMETER_INVALID_AVP")
- *  errormsg    : (optional) human-readable error message to put in Error-Message AVP
- *  optavp	: (optional) If provided, the content will be put inside a Failed-AVP
- *  type_id	: 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host.
- *
- * DESCRIPTION: 
- *   This function adds a Result-Code AVP to a message, and optionally
- *  - sets the 'E' error flag in the header,
- *  - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs.
- *
- * RETURN VALUE:
- *  0      	: Operation complete.
- *  !0      	: an error occurred.
- */
-int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id );
-
-/* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */
-int fd_msg_add_origin ( struct msg * msg, int osi ); 
-
-/* Parse a message against our dictionary, and in case of error log and eventually build the error reply (on return and EBADMSG, *msg == NULL or *msg is the error message ready to send) */
-int fd_msg_parse_or_error( struct msg ** msg );
-
-
-/***************************************/
-/*   Dispatch module, daemon's part    */
-/***************************************/
-
-/*
- * FUNCTION:	fd_disp_app_support
- *
- * PARAMETERS:
- *  app		: The dictionary object corresponding to the Application.
- *  vendor	: (Optional) the dictionary object of a Vendor to claim support in Vendor-Specific-Application-Id
- *  auth	: Support auth app part.
- *  acct	: Support acct app part.
- *
- * DESCRIPTION: 
- *   Registers an application to be advertized in CER/CEA exchanges.
- *  Messages with an application-id matching a registered value are passed to the dispatch module,
- * while other messages are simply relayed or an error is returned (if local node does not relay)
- *
- * RETURN VALUE:
- *  0      	: The application support is registered.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct );
-
-/* Note: if we want to support capabilities updates, we'll have to add possibility to remove an app as well... */
-
-
-/***************************************/
-/*          Routing module             */
-/***************************************/
-
-/* This file contains the definitions of types and functions involved in the routing decisions in freeDiameter,
- * and that can be called by extensions. 
- *
- * Three different type of messages must be distinguished:
- *  - Messages received, and the peer is final recipient (IN messages)
- *  - Messages received, and the peer is not final recipient (FWD messages)
- *  - Message is locally generated (OUT messages)
- *
- * There are three global message queues (in queues.c) and also peers-specific queues (in struct fd_peer).
- *
- * (*) IN messages processing details:
- *   - the message is received from the remote peer, a FDEVP_CNX_MSG_RECV event is generated for the peer.
- *   - the PSM thread parses the buffer, does some verifications, handles non routable messages (fd_msg_is_routable)
- *   - routable messages are queued in the fd_g_incoming global queue.
- *   - a thread (routing-in) picks the message and takes the decision if it is handled locally or forwarded, 
- *       based on local capabilities (registered by extensions with fd_disp_app_support).
- *   - If the message is handled locally, it is queued in fd_g_local.
- *   - Another thread (dispatch.c) will handle this message and pass it to registered callbacks (see fd_disp_register in libfreeDiameter.h).
- *
- * (*) FWD messages details:
- *   - The process is the same as for IN messages, until the routing-in threads makes its decision that the message is not handled locally.
- *   - If the local peer does not relay message, an error DIAMETER_APPLICATION_UNSUPPORTED is returned.
- *   - All callbacks registered with fd_rt_fwd_register are called for the message (see bellow).
- *     - these callbacks will typically do proxying work. Note that adding the route-record is handled by the daemon.
- *   - Once all callbacks have been called, the message is queued in the global fd_g_outgoing queue.
- *   - The remaining processing is the same as for OUT messages, as described bellow.
- *
- * (*) OUT messages details:
- *   - The message are picked from fd_g_outgoing (they are queued there as result of forwarding process or call to fd_msg_send.)
- *   - The (routing-out) thread builds a list of possible destinations for the message, as follow:
- *      - create a list of all known peers in the "OPEN" state.
- *      - remove from that list all peers that are in a Route-Record AVP of the message, to avoid routing loops.
- *      - remove also all peers that have previously replied an error message for this message.
- *   - If the list is empty, create an error UNABLE_TO_DELIVER (note: should we trig dynamic discovery here???) and reply.
- *   - Otherwise, call all callbacks registered by function fd_rt_out_register, with the list of peers and the message.
- *   - Order the resulting list of peers by score (see bellow), and sent the message to the peer with highest (positive) score.
- *    - in case the peer is no longer in the "OPEN" state, send the message to the second peer in the list.
- *      - if no peer is in OPEN state anymore, restart the process of creating the list.
- *   - Once a peer has been selected, the message is queued into that peer's outgoing queue.
- *
- * The following functions allow an extension to register or remove a callback as described above.
- */
-
-/********** Forwarding callbacks: for Proxy operations ***********/
-
-/* Handle to registered callback */
-struct fd_rt_fwd_hdl;
-
-/* Message direction for the callback */
-enum fd_rt_fwd_dir {
-	RT_FWD_REQ = 1,	/* The callback will be called on forwarded requests only */
-	RT_FWD_ALL = 2,	/* The callback will be called on all forwarded messages (requests and answers )*/
-	RT_FWD_ANS = 3	/* The callback will be called on answers and errors only */
-};	
-
-/*
- * FUNCTION:	fd_rt_fwd_register
- *
- * PARAMETERS:
- *  rt_fwd_cb	  : The callback function to register (see prototype bellow).
- *  cbdata	  : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
- *  dir           : One of the RT_FWD_* directions defined above.
- *  handler       : On success, a handler to the registered callback is stored here. 
- *		   This handler will be used to unregister the cb.
- *
- * DESCRIPTION: 
- *   Register a new callback for forwarded messages. See explanations above. 
- * Note that there is no guaranteed order for the callbacks calls.
- *
- * RETURN VALUE:
- *  0      	: The callback is registered.
- *  EINVAL 	: A parameter is invalid.
- *  ENOMEM	: Not enough memory to complete the operation
- */
-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 );
-/*
- * CALLBACK:	rt_fwd_cb
- *
- * PARAMETERS:
- *  data	: pointer to some data that was passed when the callback was registered (optional).
- *  msg 	: The message that is being forwarded.
- *
- * DESCRIPTION: 
- *   This callback is called when a message is forwarded to another peer. It may for example add a Proxy-Info AVP.
- *  The callback may also choose to handle the message in a more complex form. In that case, it must set *msg = NULL
- *  and handle it differently. In such case, the forwarding thread will stop processing this message.
- *
- * RETURN VALUE:
- *  0      	: Operation complete.
- *  !0 		: An error occurred -- will result in daemon's termination.
- */
-
-/*
- * FUNCTION:	fd_rt_fwd_unregister
- *
- * PARAMETERS:
- *  handler     : The handler of the callback that must be unregistered.
- *  cbdata	: Will receive the data registered with the callback, that can be freed if needed.
- *
- * DESCRIPTION: 
- *   Removes a callback from the list of registered callbacks.
- *
- * RETURN VALUE:
- *  0      	: The callback is unregistered.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_rt_fwd_unregister ( struct fd_rt_fwd_hdl * handler, void ** cbdata );
-
-
-/********** Out callbacks: for next hop routing decision operations ***********/
-
-/* Handle to registered callback */
-struct fd_rt_out_hdl;
-
-enum fd_rt_out_score {
-	FD_SCORE_NO_DELIVERY	 = -70,	/* We should not send this message to this candidate */
-	FD_SCORE_INI		 =  -2, /* All candidates are initialized with this value */
-	FD_SCORE_LOAD_BALANCE	 =   1,	/* Use this to differentiate between several peers with the same score */
-	FD_SCORE_DEFAULT	 =   5,	/* The peer is a default route for all messages */
-	FD_SCORE_DEFAULT_REALM	 =  10,	/* The peer is a default route for this realm */
-	FD_SCORE_REALM		 =  15,	/* The peer belongs to Destination-Realm of the message */
-	FD_SCORE_REDIR_HOST	 =  25,	/* If there is a redirect rule with ALL_HOST for these message and peer */
-	FD_SCORE_REDIR_APP	 =  30,	/* If there is a redirect rule with ALL_APPLICATION for these message and peer */
-	FD_SCORE_REDIR_REALM	 =  35,	/* If there is a redirect rule with ALL_REALM for these message and peer */
-	FD_SCORE_REDIR_REALM_APP =  40,	/* If there is a redirect rule with REALM_AND_APPLICATION for these message and peer */
-	FD_SCORE_REDIR_USER	 =  45,	/* If there is a redirect rule with ALL_USER for these message and peer */
-	FD_SCORE_REDIR_SESSION	 =  50,	/* If there is a redirect rule with ALL_SESSION for these message and peer */
-	FD_SCORE_FINALDEST	 = 100	/* If the peer is the final recipient of the message (i.e. matching Destination-Host), it receives a big score. */
-};
-
-/*
- * FUNCTION:	fd_rt_out_register
- *
- * PARAMETERS:
- *  rt_out_cb	  : The callback function to register (see prototype bellow).
- *  cbdata	  : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
- *  priority      : Order for calling this callback. The callbacks are called in reverse priority order (higher priority = called sooner).
- *  handler       : On success, a handler to the registered callback is stored here. 
- *		   This handler will be used to unregister the cb.
- *
- * DESCRIPTION: 
- *   Register a new callback to handle OUT routing decisions. See explanations above. 
- *
- * RETURN VALUE:
- *  0      	: The callback is registered.
- *  EINVAL 	: A parameter is invalid.
- *  ENOMEM	: Not enough memory to complete the operation
- */
-int fd_rt_out_register ( int (*rt_out_cb)(void * cbdata, struct msg * msg, struct fd_list * candidates), void * cbdata, int priority, struct fd_rt_out_hdl ** handler );
-/*
- * CALLBACK:	rt_out_cb
- *
- * PARAMETERS:
- *  cbdata	: pointer to some data that was registered with the callback.
- *  msg 	: The message that must be sent.
- *  list        : The list of peers to which the message may be sent to, as returned by fd_rtd_candidate_extract
- *
- * DESCRIPTION: 
- *   This callback must attribute a score (preferably from FD_SCORE_*) to each candidate peer in the list.
- *  Once all registered callbacks have been called, the message is sent to the candidate with the highest score.
- *  Note that each callback must *add* its locally-attributed score to the candidate current "score" parameter, not replace it!
- *  Note also that this callback must be re-entrant since it may be called by several threads at the same time 
- *  (for different messages)
- *
- * RETURN VALUE:
- *  0      	: Operation complete.
- *  !0 		: An error occurred.
- */
-
-/*
- * FUNCTION:	fd_rt_out_unregister
- *
- * PARAMETERS:
- *  handler     : The handler of the callback that must be unregistered.
- *  cbdata	: Will receive the data registered with the callback, that can be freed if needed.
- *
- * DESCRIPTION: 
- *   Removes a callback from the list of registered callbacks.
- *
- * RETURN VALUE:
- *  0      	: The callback is unregistered.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_rt_out_unregister ( struct fd_rt_out_hdl * handler, void ** cbdata );
-
-
-/***************************************/
-/*   Events helpers                    */
-/***************************************/
-
-struct fd_event {
-	int	 code; /* codespace depends on the queue */
-	size_t 	 size;
-	void    *data;
-};
-
-/* Daemon's codespace: 1000->1999 (1500->1999 defined in fD.h) */
-enum {
-	 FDEV_TERMINATE	= 1000	/* request to terminate */
-	,FDEV_DUMP_DICT		/* Dump the content of the dictionary */
-	,FDEV_DUMP_EXT		/* Dump state of extensions */
-	,FDEV_DUMP_SERV		/* Dump the server socket status */
-	,FDEV_DUMP_QUEUES	/* Dump the message queues */
-	,FDEV_DUMP_CONFIG	/* Dump the configuration */
-	,FDEV_DUMP_PEERS	/* Dump the list of peers */
-};
-
-int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data);
-int fd_event_get(struct fifo *queue, int * code, size_t * datasz, void ** data);
-int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int * code, size_t * datasz, void ** data);
-void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data));
-const char * fd_ev_str(int event);
-
-
-/* The following function does not really use events, but it may be used 
-by extensions that need to start an action when the framework is fully initialized. 
-This function will block until all initializations are performed in the daemon.
-It is meant to be used as follow by extensions:
- - in initialization callback, create a new thread.
- - this new thread calls this function.
- - when the function returns, the thread can start working and using all framework features.
-*/
-int fd_wait_initialization_complete(void);
-
-
-/***************************************/
-/*   Endpoints lists helpers           */
-/***************************************/
-
-struct fd_endpoint {
-	struct fd_list  chain;	/* link in cnf_endpoints list */
-	
-	union {
-		sSS		ss;	/* the socket information. List is always ordered by ss value (memcmp) -- see fd_ep_add_merge */
-		sSA4		sin;
-		sSA6		sin6;
-		sSA		sa;
-	}
-#ifdef SWIG /* nested anonymous unions are not supported yet */
-			s
-#endif /* SWIG */
-	;
-	
-#define	EP_FL_CONF	(1 << 0)	/* This endpoint is statically configured in a configuration file */
-#define	EP_FL_DISC	(1 << 1)	/* This endpoint was resolved from the Diameter Identity or other DNS query */
-#define	EP_FL_ADV	(1 << 2)	/* This endpoint was advertized in Diameter CER/CEA exchange */
-#define	EP_FL_LL	(1 << 3)	/* Lower layer mechanism provided this endpoint */
-#define	EP_FL_PRIMARY	(1 << 4)	/* This endpoint is primary in a multihomed SCTP association */
-#define	EP_ACCEPTALL	(1 << 15)	/* This flag allows bypassing the address filter in fd_ep_add_merge. */
-	uint32_t	flags;		/* Additional information about the endpoint */
-		
-	/* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
-};
-
-int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags );
-int fd_ep_filter( struct fd_list * list, uint32_t flags );
-int fd_ep_filter_family( struct fd_list * list, int af );
-int fd_ep_filter_list( struct fd_list * list, struct fd_list * exclude_list );
-int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
-void fd_ep_dump_one( char * prefix, struct fd_endpoint * ep, char * suffix );
-void fd_ep_dump( int indent, struct fd_list * eps );
-
-/***************************************/
-/*   Applications lists helpers        */
-/***************************************/
-
-struct fd_app {
-	struct fd_list	 chain;	/* link in cnf_apps list. List ordered by appid. */
-	struct {
-		unsigned auth   : 1;
-		unsigned acct   : 1;
-	}		 flags;
-	vendor_id_t	 vndid; /* if not 0, Vendor-Specific-App-Id AVP will be used */
-	application_id_t appid;	/* The identifier of the application */
-};
-	
-int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct);
-int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail);
-int fd_app_check_common(struct fd_list * list1, struct fd_list * list2, int * common_found);
-int fd_app_empty(struct fd_list * list);
-
-#endif /* _FREEDIAMETER_H */
Index: include/freeDiameter/libfdcore.h
===================================================================
--- include/freeDiameter/libfdcore.h	(revision 658)
+++ include/freeDiameter/libfdcore.h	(revision 658)
@@ -0,0 +1,790 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2011, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+#ifndef _LIBFDCORE_H
+#define _LIBFDCORE_H
+
+
+#include <freeDiameter/libfdproto.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+/* GNUTLS version */
+#ifndef GNUTLS_VERSION
+#define GNUTLS_VERSION LIBGNUTLS_VERSION
+#endif /* GNUTLS_VERSION */
+
+/* GNUTLS calls debug level */
+#ifndef GNUTLS_DBG_LEVEL
+#define GNUTLS_DBG_LEVEL ANNOYING
+#endif /* GNUTLS_DBG_LEVEL */
+
+/* Check the return value of a GNUTLS function, log and propagate */
+#define CHECK_GNUTLS_DO( __call__, __fallback__ ) {						\
+	int __ret__;										\
+	TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: " #__call__ );				\
+	__ret__ = (__call__);									\
+	if (__ret__ < 0) {									\
+		TRACE_DEBUG(INFO, "Error in '" #__call__ "':\t%s", gnutls_strerror(__ret__));	\
+		__fallback__;									\
+	}											\
+}
+
+/* For GNUTLS routines that do not return a value */
+#define GNUTLS_TRACE( __call__) {					\
+	TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: " #__call__ );	\
+	(__call__);							\
+}
+
+
+/*============================================================*/
+/*                      INITIALIZATION                        */
+/*============================================================*/
+
+
+/* Initialize the libfdcore internals. This also initializes libfdproto */
+int fd_core_initialize(void);
+
+/* Return a string describing the version of the library */
+const char *fd_core_version(void);
+
+/* Parse the freeDiameter.conf configuration file, load the extensions */
+int fd_core_parseconf(char * conffile);
+
+/* Start the server & client threads */
+int fd_core_start(void);
+
+/* Block until the framework has completed its initialization -- useful for extensions */
+int fd_core_waitstartcomplete(void);
+
+/* Initialize shutdown of the framework */
+int fd_core_shutdown(void);
+
+/* Wait for the shutdown to be complete -- this should always be called after fd_core_shutdown */
+int fd_core_wait_shutdown_complete(void);
+
+
+/*============================================================*/
+/*                          CONFIG                            */
+/*============================================================*/
+
+/* Structure to hold the configuration of the freeDiameter daemon */
+#define	EYEC_CONFIG	0xC011F16
+struct fd_config {
+	int		 cnf_eyec;	/* Eye catcher: EYEC_CONFIG */
+	
+	char		*cnf_file;	/* Configuration file to parse, default is DEFAULT_CONF_FILE */
+	
+	char   		*cnf_diamid;	/* Diameter Identity of the local peer (FQDN -- UTF-8) */
+	size_t		 cnf_diamid_len;	/* length of the previous string */
+	char		*cnf_diamrlm;	/* Diameter realm of the local peer, default to realm part of diam_id */
+	size_t		 cnf_diamrlm_len;/* length of the previous string */
+	
+	unsigned int	 cnf_timer_tc;	/* The value in seconds of the default Tc timer */
+	unsigned int 	 cnf_timer_tw;	/* The value in seconds of the default Tw timer */
+	
+	uint16_t	 cnf_port;	/* the local port for legacy Diameter (default: 3868) in host byte order */
+	uint16_t	 cnf_port_tls;	/* the local port for Diameter/TLS (default: 3869) in host byte order */
+	uint16_t	 cnf_sctp_str;	/* default max number of streams for SCTP associations (def: 30) */
+	struct fd_list	 cnf_endpoints;	/* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all) */
+	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. */
+	uint16_t	 cnf_dispthr;	/* Number of dispatch threads to create */
+	struct {
+		unsigned no_fwd : 1;	/* the peer does not relay messages (0xffffff app id) */
+		unsigned no_ip4 : 1;	/* disable IP */
+		unsigned no_ip6 : 1;	/* disable IPv6 */
+		unsigned no_tcp : 1;	/* disable use of TCP */
+		unsigned no_sctp: 1;	/* disable the use of SCTP */
+		unsigned pr_tcp	: 1;	/* prefer TCP over SCTP */
+		unsigned tls_alg: 1;	/* TLS algorithm for initiated cnx. 0: separate port. 1: inband-security (old) */
+	} 		 cnf_flags;
+	
+	struct {
+		/* Credentials parameters (backup) */
+		char *  			 cert_file;
+		char *				 key_file;
+		
+		char *  			 ca_file;
+		int				 ca_file_nr;
+		char *  			 crl_file;
+		
+		char *				 prio_string;
+		unsigned int 			 dh_bits;
+		char *				 dh_file;
+		
+		/* GNUTLS parameters */
+		gnutls_priority_t 		 prio_cache;
+		gnutls_dh_params_t 		 dh_cache;
+		
+		/* GNUTLS server credential(s) */
+		gnutls_certificate_credentials_t credentials;
+		
+	} 		 cnf_sec_data;
+	
+	uint32_t	 cnf_orstateid;	/* The value to use in Origin-State-Id, default to random value */
+	struct dictionary *cnf_dict;	/* pointer to the global dictionary */
+	struct fifo	  *cnf_main_ev;	/* events for the daemon's main (struct fd_event items) */
+};
+extern struct fd_config *fd_g_config; /* The pointer to access the global configuration, initalized in main */
+
+
+
+/*============================================================*/
+/*                         PEERS                              */
+/*============================================================*/
+
+/* States of a peer */
+enum peer_state {
+	/* Stable states */
+	STATE_NEW = 0,		/* The peer has been just been created, PSM thread not started yet */
+	STATE_OPEN,		/* Connexion established */
+	
+	/* Peer state machine */
+	STATE_CLOSED,		/* No connection established, will re-attempt after TcTimer. */
+	STATE_CLOSING,		/* the connection is being shutdown (DPR/DPA in progress) */
+	STATE_WAITCNXACK,	/* Attempting to establish transport-level connection */
+	STATE_WAITCNXACK_ELEC,	/* Received a CER from this same peer on an incoming connection (other peer object), while we were waiting for cnx ack */
+	STATE_WAITCEA,		/* Connection established, CER sent, waiting for CEA */
+	/* STATE_WAITRETURNS_ELEC, */	/* This state is not stable and therefore deprecated:
+				   We have sent a CER on our initiated connection, and received a CER from the remote peer on another connection. Election.
+				   If we win the election, we must disconnect the initiated connection and send a CEA on the other => we go to OPEN state.
+				   If we lose, we disconnect the other connection (receiver) and fallback to WAITCEA state. */
+	STATE_OPEN_HANDSHAKE,	/* TLS Handshake and validation are in progress in open state -- we use it only for debug purpose, it is never displayed */
+	
+	/* Failover state machine */
+	STATE_SUSPECT,		/* A DWR was sent and not answered within TwTime. Failover in progress. */
+	STATE_REOPEN,		/* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */
+	
+	/* Error state */
+	STATE_ZOMBIE		/* The PSM thread is not running anymore; it must be re-started or peer should be deleted. */
+#define STATE_MAX STATE_ZOMBIE
+};
+/* The following macro is called in freeDiameter/p_psm.c */
+#define DECLARE_STATE_STR()		\
+const char *peer_state_str[] = { 	\
+	  "STATE_NEW"			\
+	, "STATE_OPEN"			\
+	, "STATE_CLOSED"		\
+	, "STATE_CLOSING"		\
+	, "STATE_WAITCNXACK"		\
+	, "STATE_WAITCNXACK_ELEC"	\
+	, "STATE_WAITCEA"		\
+	, "STATE_OPEN_HANDSHAKE"	\
+	, "STATE_SUSPECT"		\
+	, "STATE_REOPEN"		\
+	, "STATE_ZOMBIE"		\
+	};
+extern const char *peer_state_str[];
+#define STATE_STR(state) \
+	(((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "<Invalid>")
+
+/* Constants for the peer_info structure bellow */
+#define PI_P3_DEFAULT	0	/* Use any available protocol */
+#define PI_P3_IP	1	/* Use only IP to connect to this peer */
+#define PI_P3_IPv6	2	/* resp, IPv6 */
+
+#define PI_P4_DEFAULT	0	/* Attempt any available protocol */
+#define PI_P4_TCP	1	/* Only use TCP */
+#define PI_P4_SCTP	2	/* Only use SCTP */
+
+#define PI_ALGPREF_SCTP	0	/* SCTP is  attempted first (default) */
+#define PI_ALGPREF_TCP	1	/* TCP is attempted first */
+
+#define PI_SEC_DEFAULT	0	/* New TLS security (handshake after connection, protecting also CER/CEA) */
+#define PI_SEC_NONE	1	/* Transparent security with this peer (IPsec) */
+#define PI_SEC_TLS_OLD	2	/* Old TLS security (use Inband-Security-Id AVP during CER/CEA) */
+				/* Set sec = 3 to authorize use of (Inband-Security-Id == NONE) with this peer, sec = 2 only authorizing TLS */
+
+#define PI_EXP_NONE	0	/* the peer entry does not expire */
+#define PI_EXP_INACTIVE	1	/* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */
+
+#define PI_PRST_NONE	0	/* the peer entry is deleted after disconnection / error */
+#define PI_PRST_ALWAYS	1	/* the peer entry is persistant (will be kept as ZOMBIE in case of error) */
+			
+/* Information about a remote peer */
+struct peer_info {
+	
+	char * 		pi_diamid;	/* UTF-8, \0 terminated. The Diameter Identity of the remote peer. */
+	
+	struct {
+		struct {
+			unsigned	pro3 :2;	/* PI_P3_* */
+			unsigned	pro4 :2;	/* PI_P4_* */
+			unsigned	alg :1;		/* PI_ALGPREF_* */
+			unsigned	sec :2;		/* PI_SEC_* */
+			unsigned	exp :1;		/* PI_EXP_* */
+			unsigned	persist :1;	/* PI_PRST_* */
+			
+		}		pic_flags;	/* Flags influencing the connection to the remote peer */
+		
+		char * 		pic_realm;	/* If configured, the daemon will match the received realm in CER/CEA matches this. */
+		uint16_t	pic_port; 	/* port to connect to. 0: default. */
+		
+		uint32_t 	pic_lft;	/* lifetime of this peer when inactive (see pic_flags.exp definition) */
+		int		pic_tctimer; 	/* use this value for TcTimer instead of global, if != 0 */
+		int		pic_twtimer; 	/* use this value for TwTimer instead of global, if != 0 */
+		
+		char *		pic_priority;	/* Priority string for GnuTLS if we don't use the default */
+		
+	} config;	/* Configured data (static for this peer entry) */
+	
+	struct {
+		
+		enum peer_state	pir_state;	/* Current state of the peer in the state machine. fd_cpu_flush_cache() might be useful before reading. */
+		
+		char * 		pir_realm;	/* The received realm in CER/CEA. */
+		
+		uint32_t	pir_vendorid;	/* Content of the Vendor-Id AVP, or 0 by default */
+		uint32_t	pir_orstate;	/* Origin-State-Id value */
+		char *		pir_prodname;	/* copy of UTF-8 Product-Name AVP (\0 terminated) */
+		uint32_t	pir_firmrev;	/* Content of the Firmware-Revision AVP */
+		int		pir_relay;	/* The remote peer advertized the relay application */
+		struct fd_list	pir_apps;	/* applications advertised by the remote peer, except relay (pi_flags.relay) */
+		int		pir_isi;	/* Inband-Security-Id advertised (PI_SEC_* bits) */
+		
+		uint32_t	pir_lastDC;	/* The last Disconnect-Cause value received */
+		
+		int		pir_proto;	/* The L4 protocol currently used with the peer (IPPROTO_TCP or IPPROTO_SCTP) */
+		const gnutls_datum_t 	*pir_cert_list; 	/* The (valid) credentials that the peer has presented, or NULL if TLS is not used */
+								/* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo 
+								   see there for example of using this data */
+		unsigned int 	pir_cert_list_size;		/* Number of certificates in the list */
+		
+	} runtime;	/* Data populated after connection, may change between 2 connections -- not used by fd_peer_add */
+	
+	struct fd_list	pi_endpoints;	/* Endpoint(s) of the remote peer (configured, discovered, or advertized). list of struct fd_endpoint. DNS resolved if empty. */
+};
+
+
+struct peer_hdr {
+	struct fd_list	 chain;	/* List of all the peers, ordered by their Diameter Id */
+	struct peer_info info;	/* The public data */
+	
+	/* This header is followed by more data in the private peer structure definition */
+};
+
+/* the global list of peers. 
+  Since we are not expecting so many connections, we don't use a hash, but it might be changed.
+  The list items are peer_hdr structures (actually, fd_peer, but the cast is OK) */
+extern struct fd_list fd_g_peers;
+extern pthread_rwlock_t fd_g_peers_rw; /* protect the list */
+
+/*
+ * FUNCTION:	fd_peer_add
+ *
+ * PARAMETERS:
+ *  info 	: Information to create the peer.
+ *  orig_dbg	: A string indicating the origin of the peer information, for debug (ex: conf, redirect, ...)
+ *  cb		: optional, a callback to call (once) when the peer connection is established or failed
+ *  cb_data	: opaque data to pass to the callback.
+ *
+ * DESCRIPTION: 
+ *  Add a peer to the list of peers to which the daemon must maintain a connexion.
+ *
+ *  The content of info parameter is copied, except for the list of endpoints if 
+ * not empty, which is simply moved into the created object. It means that the list
+ * items must have been malloc'd, so that they can be freed.
+ *
+ *  If cb is not null, the callback is called when the connection is in OPEN state or
+ * when an error has occurred. The callback should use the pi_state information to 
+ * determine which one it is. If the first parameter of the called callback is NULL, it 
+ * means that the peer is being destroyed before attempt success / failure. 
+ * cb is called to allow freeing cb_data in  * this case.
+ *
+ *  The orig_dbg string is only useful for easing debug, and can be left to NULL.
+ *
+ * RETURN VALUE:
+ *  0      	: The peer is added.
+ *  EINVAL 	: A parameter is invalid.
+ *  EEXIST 	: A peer with the same Diameter-Id is already in the list.
+ *  (other standard errors may be returned, too, with their standard meaning. Example:
+ *    ENOMEM 	: Memory allocation for the new object element failed.)
+ */
+int fd_peer_add ( struct peer_info * info, char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data );
+
+/*
+ * FUNCTION:	fd_peer_getbyid
+ *
+ * PARAMETERS:
+ *  diamid 	: A \0 terminated string.
+ *  peer	: The peer is stored here if it exists.
+ *
+ * DESCRIPTION: 
+ *   Search a peer by its Diameter-Id.
+ *
+ * RETURN VALUE:
+ *  0   : *peer has been updated (to NULL if the peer is not found).
+ * !0	: An error occurred.
+ */
+int fd_peer_getbyid( char * diamid, struct peer_hdr ** peer );
+
+/*
+ * FUNCTION:	fd_peer_validate_register
+ *
+ * PARAMETERS:
+ *  peer_validate 	: Callback as defined bellow.
+ *
+ * DESCRIPTION: 
+ *  Add a callback to authorize / reject incoming peer connections.
+ * All registered callbacks are called until a callback sets auth = -1 or auth = 1.
+ * If no callback returns a clear decision, the default behavior is applied (reject unknown connections)
+ * The callbacks are called in FILO order of their registration.
+ *
+ * RETURN VALUE:
+ *  0   : The callback is added.
+ * !0	: An error occurred.
+ */
+int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) );
+/*
+ * CALLBACK:	peer_validate
+ *
+ * PARAMETERS:
+ *   info     : Structure containing information about the peer attempting the connection.
+ *   auth     : Store there the result if the peer is accepted (1), rejected (-1), or unknown (0).
+ *   cb2      : If != NULL and in case of PI_SEC_TLS_OLD, another callback to call after handshake (if auth = 1).
+ *
+ * DESCRIPTION: 
+ *   This callback is called when a new connection is being established from an unknown peer,
+ * after the CER is received. An extension must register such callback with peer_validate_register.
+ *
+ *   The callback can learn if the peer has sent Inband-Security-Id AVPs in runtime.pir_isi fields.
+ * It can also learn if a handshake has already been performed in runtime.pir_cert_list field.
+ * The callback must set the value of config.pic_flags.sec appropriately to allow a connection without TLS.
+ *
+ *   If the old TLS mechanism is used,
+ * the extension may also need to check the credentials provided during the TLS
+ * exchange (remote certificate). For this purpose, it may set the address of a new callback
+ * to be called once the handshake is completed. This new callback receives the information
+ * structure as parameter (with pir_cert_list set) and returns 0 if the credentials are correct,
+ * or an error code otherwise. If the error code is received, the connection is closed and the 
+ * peer is destroyed.
+ * Note that freeDiameter already achieves some usual checks. The callback may be used to enforce
+ * additional restrictions.
+ *
+ * RETURN VALUE:
+ *  0      	: The authorization decision has been written in the location pointed by auth.
+ *  !0 		: An error occurred.
+ */
+
+
+
+/*============================================================*/
+/*                         MESSAGES                           */
+/*============================================================*/
+
+/*
+ * FUNCTION:	fd_msg_send, fd_msg_send_timeout  
+ *
+ * PARAMETERS:
+ *  pmsg 	: Location of the message to be sent on the network (set to NULL on function return to avoid double deletion).
+ *  anscb	: A callback to be called when answer is received, if msg is a request (optional for fd_msg_send)
+ *  anscb_data	: opaque data to be passed back to the anscb when it is called.
+ *  timeout     : (only for fd_msg_send_timeout) sets the absolute time until when to wait for an answer. Past this time,
+ *                the anscb is called with the request as parameter and the answer will be discarded when received.
+ *
+ * DESCRIPTION: 
+ *   Sends a message on the network. (actually simply queues it in a global queue, to be picked by a daemon's thread)
+ * For requests, the end-to-end id must be set (see fd_msg_get_eteid / MSGFL_ALLOC_ETEID).
+ * For answers, the message must be created with function fd_msg_new_answ.
+ *
+ * The routing module will handle sending to the correct peer, usually based on the Destination-Realm / Destination-Host AVP.
+ *
+ * If the msg is a request, there are two ways of receiving the answer:
+ *  - either having registered a callback in the dispatch module (see fd_disp_register)
+ *  - or provide a callback as parameter here. If such callback is provided, it is called before the dispatch callbacks.
+ *    The prototype for this callback function is:
+ *     void anscb(void * data, struct msg ** answer)
+ *	where:
+ *		data   : opaque data that was registered along with the callback.
+ *		answer : location of the pointer to the answer.
+ *      note1: on function return, if *answer is not NULL, the message is passed to the dispatch module for regular callbacks.
+ *	       otherwise, the callback must take care of freeing the message (fd_msg_free).
+ *	note2: the opaque data is not freed by the daemon in any case, extensions should ensure clean handling in fd_ext_fini.
+ * 
+ * If no callback is registered to handle an answer, the message is discarded and an error is logged.
+ *
+ *  fd_msg_send_timeout is similar to fd_msg_send, except that it takes an additional argument "timeout" and can be called
+ * only with requests as parameters, and an anscb callback.
+ * If the matching answer or error is received before the timeout date passes, everything occurs as with fd_msg_send. Otherwise,
+ * the request is removed from the queue (meaning the matching answer will be discarded upon reception) and passed to the answcb 
+ * function. This function can easily distinguish between timeout case and answer case by checking if the message received is 
+ * a request. Upon return, if the *msg parameter is not NULL, it is freed (not passed to other callbacks).
+ *
+ * RETURN VALUE:
+ *  0      	: The message has been queued for sending (sending may fail asynchronously).
+ *  EINVAL 	: A parameter is invalid (ex: anscb provided but message is not a request).
+ *  ...
+ */
+int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data );
+int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, const struct timespec *timeout );
+
+/*
+ * FUNCTION:	fd_msg_rescode_set
+ *
+ * PARAMETERS:
+ *  msg		: A msg object -- it must be an answer.
+ *  rescode	: The name of the returned error code (ex: "DIAMETER_INVALID_AVP")
+ *  errormsg    : (optional) human-readable error message to put in Error-Message AVP
+ *  optavp	: (optional) If provided, the content will be put inside a Failed-AVP
+ *  type_id	: 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host.
+ *
+ * DESCRIPTION: 
+ *   This function adds a Result-Code AVP to a message, and optionally
+ *  - sets the 'E' error flag in the header,
+ *  - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0      	: an error occurred.
+ */
+int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id );
+
+/* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */
+int fd_msg_add_origin ( struct msg * msg, int osi ); 
+
+/* Parse a message against our dictionary, and in case of error log and eventually build the error reply (on return and EBADMSG, *msg == NULL or *msg is the error message ready to send) */
+int fd_msg_parse_or_error( struct msg ** msg );
+
+
+
+
+/*============================================================*/
+/*                         DISPATCH                           */
+/*============================================================*/
+
+/*
+ * FUNCTION:	fd_disp_app_support
+ *
+ * PARAMETERS:
+ *  app		: The dictionary object corresponding to the Application.
+ *  vendor	: (Optional) the dictionary object of a Vendor to claim support in Vendor-Specific-Application-Id
+ *  auth	: Support auth app part.
+ *  acct	: Support acct app part.
+ *
+ * DESCRIPTION: 
+ *   Registers an application to be advertized in CER/CEA exchanges.
+ *  Messages with an application-id matching a registered value are passed to the dispatch module,
+ * while other messages are simply relayed or an error is returned (if local node does not relay)
+ *
+ * RETURN VALUE:
+ *  0      	: The application support is registered.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct );
+
+/* Note: if we want to support capabilities updates, we'll have to add possibility to remove an app as well... */
+
+
+/*============================================================*/
+/*                         ROUTING                            */
+/*============================================================*/
+
+/* This file contains the definitions of types and functions involved in the routing decisions in freeDiameter,
+ * and that can be called by extensions. 
+ *
+ * Three different type of messages must be distinguished:
+ *  - Messages received, and the peer is final recipient (IN messages)
+ *  - Messages received, and the peer is not final recipient (FWD messages)
+ *  - Message is locally generated (OUT messages)
+ *
+ * There are three global message queues (in queues.c) and also peers-specific queues (in struct fd_peer).
+ *
+ * (*) IN messages processing details:
+ *   - the message is received from the remote peer, a FDEVP_CNX_MSG_RECV event is generated for the peer.
+ *   - the PSM thread parses the buffer, does some verifications, handles non routable messages (fd_msg_is_routable)
+ *   - routable messages are queued in the fd_g_incoming global queue.
+ *   - a thread (routing-in) picks the message and takes the decision if it is handled locally or forwarded, 
+ *       based on local capabilities (registered by extensions with fd_disp_app_support).
+ *   - If the message is handled locally, it is queued in fd_g_local.
+ *   - Another thread (dispatch.c) will handle this message and pass it to registered callbacks (see fd_disp_register in libfreeDiameter.h).
+ *
+ * (*) FWD messages details:
+ *   - The process is the same as for IN messages, until the routing-in threads makes its decision that the message is not handled locally.
+ *   - If the local peer does not relay message, an error DIAMETER_APPLICATION_UNSUPPORTED is returned.
+ *   - All callbacks registered with fd_rt_fwd_register are called for the message (see bellow).
+ *     - these callbacks will typically do proxying work. Note that adding the route-record is handled by the daemon.
+ *   - Once all callbacks have been called, the message is queued in the global fd_g_outgoing queue.
+ *   - The remaining processing is the same as for OUT messages, as described bellow.
+ *
+ * (*) OUT messages details:
+ *   - The message are picked from fd_g_outgoing (they are queued there as result of forwarding process or call to fd_msg_send.)
+ *   - The (routing-out) thread builds a list of possible destinations for the message, as follow:
+ *      - create a list of all known peers in the "OPEN" state.
+ *      - remove from that list all peers that are in a Route-Record AVP of the message, to avoid routing loops.
+ *      - remove also all peers that have previously replied an error message for this message.
+ *   - If the list is empty, create an error UNABLE_TO_DELIVER (note: should we trig dynamic discovery here???) and reply.
+ *   - Otherwise, call all callbacks registered by function fd_rt_out_register, with the list of peers and the message.
+ *   - Order the resulting list of peers by score (see bellow), and sent the message to the peer with highest (positive) score.
+ *    - in case the peer is no longer in the "OPEN" state, send the message to the second peer in the list.
+ *      - if no peer is in OPEN state anymore, restart the process of creating the list.
+ *   - Once a peer has been selected, the message is queued into that peer's outgoing queue.
+ *
+ * The following functions allow an extension to register or remove a callback as described above.
+ */
+
+/********** Forwarding callbacks: for Proxy operations ***********/
+
+/* Handle to registered callback */
+struct fd_rt_fwd_hdl;
+
+/* Message direction for the callback */
+enum fd_rt_fwd_dir {
+	RT_FWD_REQ = 1,	/* The callback will be called on forwarded requests only */
+	RT_FWD_ALL = 2,	/* The callback will be called on all forwarded messages (requests and answers )*/
+	RT_FWD_ANS = 3	/* The callback will be called on answers and errors only */
+};	
+
+/*
+ * FUNCTION:	fd_rt_fwd_register
+ *
+ * PARAMETERS:
+ *  rt_fwd_cb	  : The callback function to register (see prototype bellow).
+ *  cbdata	  : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
+ *  dir           : One of the RT_FWD_* directions defined above.
+ *  handler       : On success, a handler to the registered callback is stored here. 
+ *		   This handler will be used to unregister the cb.
+ *
+ * DESCRIPTION: 
+ *   Register a new callback for forwarded messages. See explanations above. 
+ * Note that there is no guaranteed order for the callbacks calls.
+ *
+ * RETURN VALUE:
+ *  0      	: The callback is registered.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOMEM	: Not enough memory to complete the operation
+ */
+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 );
+/*
+ * CALLBACK:	rt_fwd_cb
+ *
+ * PARAMETERS:
+ *  data	: pointer to some data that was passed when the callback was registered (optional).
+ *  msg 	: The message that is being forwarded.
+ *
+ * DESCRIPTION: 
+ *   This callback is called when a message is forwarded to another peer. It may for example add a Proxy-Info AVP.
+ *  The callback may also choose to handle the message in a more complex form. In that case, it must set *msg = NULL
+ *  and handle it differently. In such case, the forwarding thread will stop processing this message.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0 		: An error occurred -- will result in daemon's termination.
+ */
+
+/*
+ * FUNCTION:	fd_rt_fwd_unregister
+ *
+ * PARAMETERS:
+ *  handler     : The handler of the callback that must be unregistered.
+ *  cbdata	: Will receive the data registered with the callback, that can be freed if needed.
+ *
+ * DESCRIPTION: 
+ *   Removes a callback from the list of registered callbacks.
+ *
+ * RETURN VALUE:
+ *  0      	: The callback is unregistered.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_rt_fwd_unregister ( struct fd_rt_fwd_hdl * handler, void ** cbdata );
+
+
+/********** Out callbacks: for next hop routing decision operations ***********/
+
+/* Handle to registered callback */
+struct fd_rt_out_hdl;
+
+enum fd_rt_out_score {
+	FD_SCORE_NO_DELIVERY	 = -70,	/* We should not send this message to this candidate */
+	FD_SCORE_INI		 =  -2, /* All candidates are initialized with this value */
+	FD_SCORE_LOAD_BALANCE	 =   1,	/* Use this to differentiate between several peers with the same score */
+	FD_SCORE_DEFAULT	 =   5,	/* The peer is a default route for all messages */
+	FD_SCORE_DEFAULT_REALM	 =  10,	/* The peer is a default route for this realm */
+	FD_SCORE_REALM		 =  15,	/* The peer belongs to Destination-Realm of the message */
+	FD_SCORE_REDIR_HOST	 =  25,	/* If there is a redirect rule with ALL_HOST for these message and peer */
+	FD_SCORE_REDIR_APP	 =  30,	/* If there is a redirect rule with ALL_APPLICATION for these message and peer */
+	FD_SCORE_REDIR_REALM	 =  35,	/* If there is a redirect rule with ALL_REALM for these message and peer */
+	FD_SCORE_REDIR_REALM_APP =  40,	/* If there is a redirect rule with REALM_AND_APPLICATION for these message and peer */
+	FD_SCORE_REDIR_USER	 =  45,	/* If there is a redirect rule with ALL_USER for these message and peer */
+	FD_SCORE_REDIR_SESSION	 =  50,	/* If there is a redirect rule with ALL_SESSION for these message and peer */
+	FD_SCORE_FINALDEST	 = 100	/* If the peer is the final recipient of the message (i.e. matching Destination-Host), it receives a big score. */
+};
+
+/*
+ * FUNCTION:	fd_rt_out_register
+ *
+ * PARAMETERS:
+ *  rt_out_cb	  : The callback function to register (see prototype bellow).
+ *  cbdata	  : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
+ *  priority      : Order for calling this callback. The callbacks are called in reverse priority order (higher priority = called sooner).
+ *  handler       : On success, a handler to the registered callback is stored here. 
+ *		   This handler will be used to unregister the cb.
+ *
+ * DESCRIPTION: 
+ *   Register a new callback to handle OUT routing decisions. See explanations above. 
+ *
+ * RETURN VALUE:
+ *  0      	: The callback is registered.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOMEM	: Not enough memory to complete the operation
+ */
+int fd_rt_out_register ( int (*rt_out_cb)(void * cbdata, struct msg * msg, struct fd_list * candidates), void * cbdata, int priority, struct fd_rt_out_hdl ** handler );
+/*
+ * CALLBACK:	rt_out_cb
+ *
+ * PARAMETERS:
+ *  cbdata	: pointer to some data that was registered with the callback.
+ *  msg 	: The message that must be sent.
+ *  list        : The list of peers to which the message may be sent to, as returned by fd_rtd_candidate_extract
+ *
+ * DESCRIPTION: 
+ *   This callback must attribute a score (preferably from FD_SCORE_*) to each candidate peer in the list.
+ *  Once all registered callbacks have been called, the message is sent to the candidate with the highest score.
+ *  Note that each callback must *add* its locally-attributed score to the candidate current "score" parameter, not replace it!
+ *  Note also that this callback must be re-entrant since it may be called by several threads at the same time 
+ *  (for different messages)
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0 		: An error occurred.
+ */
+
+/*
+ * FUNCTION:	fd_rt_out_unregister
+ *
+ * PARAMETERS:
+ *  handler     : The handler of the callback that must be unregistered.
+ *  cbdata	: Will receive the data registered with the callback, that can be freed if needed.
+ *
+ * DESCRIPTION: 
+ *   Removes a callback from the list of registered callbacks.
+ *
+ * RETURN VALUE:
+ *  0      	: The callback is unregistered.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_rt_out_unregister ( struct fd_rt_out_hdl * handler, void ** cbdata );
+
+
+/*============================================================*/
+/*                         EVENTS                             */
+/*============================================================*/
+
+struct fd_event {
+	int	 code; /* codespace depends on the queue */
+	size_t 	 size;
+	void    *data;
+};
+
+/* Daemon's codespace: 1000->1999 (1500->1999 defined in fdcore-internal.h) */
+enum {
+	 FDEV_TERMINATE	= 1000	/* request to terminate */
+	,FDEV_DUMP_DICT		/* Dump the content of the dictionary */
+	,FDEV_DUMP_EXT		/* Dump state of extensions */
+	,FDEV_DUMP_SERV		/* Dump the server socket status */
+	,FDEV_DUMP_QUEUES	/* Dump the message queues */
+	,FDEV_DUMP_CONFIG	/* Dump the configuration */
+	,FDEV_DUMP_PEERS	/* Dump the list of peers */
+	,FDEV_TRIGGER		/* Trigger available for extensions. size is sizeof(int), data is int * */
+};
+
+int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data);
+int fd_event_get(struct fifo *queue, int * code, size_t * datasz, void ** data);
+int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int * code, size_t * datasz, void ** data);
+void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data));
+const char * fd_ev_str(int event);
+
+/* for extensions */
+int fd_event_trig_regcb(int trigger_val, const char * module, void (*cb)(void));
+void fd_event_trig_dump();
+
+
+/*============================================================*/
+/*                         ENDPOINTS                          */
+/*============================================================*/
+
+struct fd_endpoint {
+	struct fd_list  chain;	/* link in cnf_endpoints list */
+	
+	union {
+		sSS		ss;	/* the socket information. List is always ordered by ss value (memcmp) -- see fd_ep_add_merge */
+		sSA4		sin;
+		sSA6		sin6;
+		sSA		sa;
+	}
+#ifdef SWIG /* nested anonymous unions are not supported yet */
+			s
+#endif /* SWIG */
+	;
+	
+#define	EP_FL_CONF	(1 << 0)	/* This endpoint is statically configured in a configuration file */
+#define	EP_FL_DISC	(1 << 1)	/* This endpoint was resolved from the Diameter Identity or other DNS query */
+#define	EP_FL_ADV	(1 << 2)	/* This endpoint was advertized in Diameter CER/CEA exchange */
+#define	EP_FL_LL	(1 << 3)	/* Lower layer mechanism provided this endpoint */
+#define	EP_FL_PRIMARY	(1 << 4)	/* This endpoint is primary in a multihomed SCTP association */
+#define	EP_ACCEPTALL	(1 << 15)	/* This flag allows bypassing the address filter in fd_ep_add_merge. */
+	uint32_t	flags;		/* Additional information about the endpoint */
+		
+	/* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
+};
+
+int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags );
+int fd_ep_filter( struct fd_list * list, uint32_t flags );
+int fd_ep_filter_family( struct fd_list * list, int af );
+int fd_ep_filter_list( struct fd_list * list, struct fd_list * exclude_list );
+int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
+void fd_ep_dump_one( char * prefix, struct fd_endpoint * ep, char * suffix );
+void fd_ep_dump( int indent, struct fd_list * eps );
+
+
+/*============================================================*/
+/*                         APPLICATIONS IDs                   */
+/*============================================================*/
+
+struct fd_app {
+	struct fd_list	 chain;	/* link in cnf_apps list. List ordered by appid. */
+	struct {
+		unsigned auth   : 1;
+		unsigned acct   : 1;
+	}		 flags;
+	vendor_id_t	 vndid; /* if not 0, Vendor-Specific-App-Id AVP will be used */
+	application_id_t appid;	/* The identifier of the application */
+};
+	
+int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct);
+int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail);
+int fd_app_check_common(struct fd_list * list1, struct fd_list * list2, int * common_found);
+int fd_app_empty(struct fd_list * list);
+
+#endif /* _LIBFDCORE_H */
Index: include/freeDiameter/libfdproto.h
===================================================================
--- include/freeDiameter/libfdproto.h	(revision 658)
+++ include/freeDiameter/libfdproto.h	(revision 658)
@@ -0,0 +1,2794 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2011, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY S_OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* This file contains the definitions of functions and types used by the libfreeDiameter library.
+ *
+ * This library is meant to be used by both the freeDiameter daemon and its extensions.
+ * It provides the tools to manipulate Diameter messages and related data.
+ * This file should always be included as #include <freeDiameter/libfreeDiameter.h>
+ *
+ * If any change is made to this file, you must increment the FD_PROJECT_VERSION_API version.
+ *
+ * The file contains the following parts:
+ *	DEBUG
+ *	MACROS
+ *	THREADS
+ *	LISTS
+ *	DICTIONARY
+ *	SESSIONS
+ *	MESSAGES
+ *	DISPATCH
+ *	QUEUES
+ */
+
+#ifndef _LIBFDPROTO_H
+#define _LIBFDPROTO_H
+
+#ifndef FD_IS_CONFIG
+#error "You must include 'freeDiameter-host.h' before this file."
+#endif /* FD_IS_CONFIG */
+
+#include <pthread.h>
+#include <sched.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef DEBUG
+#include <libgen.h>	/* for basename if --dbg_file is specified */
+#endif /* DEBUG */
+
+/*============================================================*/
+/*                          INIT                              */
+/*============================================================*/
+
+/* This function must be called first, before any call to another library function */
+int fd_libproto_init(void); /* note if you are using libfdcore, it handles this already */
+
+/* Call this one when the application terminates, to destroy internal threads */
+void fd_libproto_fini(void);
+
+
+/*============================================================*/
+/*                          DEBUG                             */
+/*============================================================*/
+
+
+/*
+ * FUNCTION:	fd_log_debug
+ *
+ * PARAMETERS:
+ *  format 	: Same format string as in the printf function
+ *  ...		: Same list as printf
+ *
+ * DESCRIPTION: 
+ *  Log internal information for use of developpers only.
+ * The format and arguments may contain UTF-8 encoded data. The
+ * output medium (file or console) is expected to support this encoding.
+ *
+ * This function assumes that a global mutex called "fd_log_lock" exists
+ * in the address space of the current process.
+ *
+ * RETURN VALUE:
+ *  None.
+ */
+void fd_log_debug ( const char * format, ... );
+extern pthread_mutex_t	fd_log_lock;
+extern char * fd_debug_one_function;
+extern char * fd_debug_one_file;
+
+/*
+ * FUNCTION:	fd_log_threadname
+ *
+ * PARAMETERS:
+ *  name 	: \0-terminated string containing a name to identify the current thread.
+ *
+ * DESCRIPTION: 
+ *  Name the current thread, useful for debugging multi-threaded problems.
+ *
+ * This function assumes that a global thread-specific key called "fd_log_thname" exists
+ * in the address space of the current process.
+ *
+ * RETURN VALUE:
+ *  None.
+ */
+void fd_log_threadname ( char * name );
+extern pthread_key_t	fd_log_thname;
+
+/*
+ * FUNCTION:	fd_log_time
+ *
+ * PARAMETERS:
+ *  ts	 	: The timestamp to log, or NULL for "now"
+ *  buf 	: An array where the time must be stored
+ *  len		: size of the buffer
+ *
+ * DESCRIPTION: 
+ *  Writes the timestamp (in human readable format) in a buffer. 
+ *
+ * RETURN VALUE:
+ *  pointer to buf.
+ */
+char * fd_log_time ( struct timespec * ts, char * buf, size_t len );
+
+
+/*============================================================*/
+/*                    DEBUG MACROS                            */
+/*============================================================*/
+
+#ifndef ASSERT
+#define ASSERT(x) assert(x)
+#endif /* ASSERT */
+
+/* levels definitions */
+#define NONE 0	/* Display no debug message */
+#define INFO 1	/* Display errors only */
+#define FULL 2  /* Display additional information to follow code execution */
+#define ANNOYING 4 /* Very verbose, for example in loops */
+#define FCTS 6  /* Display entry parameters of most functions */
+#define CALL 9  /* Display calls to most functions (with CHECK macros) */
+
+/* Default level is INFO */
+#ifndef TRACE_LEVEL 
+#define TRACE_LEVEL INFO
+#endif /* TRACE_LEVEL */
+
+/* The level of the file being compiled. */
+static int local_debug_level = TRACE_LEVEL;
+
+/* A global level, changed by configuration or cmd line for example. default is 0. */
+extern int fd_g_debug_lvl;
+
+/* Some portability code to get nice function name in __PRETTY_FUNCTION__ */
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+#  define __func__ __FUNCTION__
+# else /* __GNUC__ >= 2 */
+#  define __func__ "<unknown>"
+# endif /* __GNUC__ >= 2 */
+#endif /* __STDC_VERSION__ < 199901L */
+#ifndef __PRETTY_FUNCTION__
+#define __PRETTY_FUNCTION__ __func__
+#endif /* __PRETTY_FUNCTION__ */
+
+/* A version of __FILE__ without the full path */
+static char * file_bname = NULL;
+#define __STRIPPED_FILE__	(file_bname ?: (file_bname = basename((char *)__FILE__)))
+
+
+/* Boolean for tracing at a certain level */
+#ifdef DEBUG
+#define TRACE_BOOL(_level_) ( ((_level_) <= local_debug_level + fd_g_debug_lvl) 					\
+				|| (fd_debug_one_function && !strcmp(fd_debug_one_function, __PRETTY_FUNCTION__)) 	\
+				|| (fd_debug_one_file && !strcmp(fd_debug_one_file, __STRIPPED_FILE__) ) )
+#else /* DEBUG */
+#define TRACE_BOOL(_level_) ((_level_) <= local_debug_level + fd_g_debug_lvl)
+#endif /* DEBUG */
+
+
+/*************
+ The general debug macro, each call results in two lines of debug messages (change the macro for more compact output) 
+ *************/
+#ifdef DEBUG
+/* In DEBUG mode, we add (a lot of) meta-information along each trace. This makes multi-threading problems easier to debug. */
+#define TRACE_DEBUG(level,format,args... ) {											\
+	if ( TRACE_BOOL(level) ) {												\
+		char __buf[25];													\
+		const char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
+		fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"								\
+			  "\t%s|%*s" format "\n",  										\
+					__thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
+					(level < FULL)?"@":" ",level, "", ## args); 						\
+	}															\
+}
+#else /* DEBUG */
+/* Do not print thread, function, ... only the message itself in this case, unless the debug level is set > FULL. */
+#define TRACE_DEBUG(level,format,args... ) {												\
+	if ( TRACE_BOOL(level) ) {													\
+		if (fd_g_debug_lvl > FULL) {												\
+			char __buf[25];													\
+			const char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
+			fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"								\
+				  "\t%s|%*s" format "\n",  										\
+						__thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
+						(level < FULL)?"@":" ",level, "", ## args); 						\
+		} else {														\
+			fd_log_debug(format "\n", ## args); 										\
+		}															\
+	}																\
+}
+#endif /* DEBUG */
+
+/*************
+ Derivatives from this macro 
+ ************/
+/* Helper for function entry -- for very detailed trace of the execution */
+#define TRACE_ENTRY(_format,_args... ) \
+	TRACE_DEBUG(FCTS, "[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );
+
+/* Helper for debugging by adding traces -- for debuging a specific location of the code */
+#define TRACE_HERE()	\
+	TRACE_DEBUG(NONE, " -- debug checkpoint %d -- ", fd_breakhere());
+int fd_breakhere(void);
+
+/* Helper for tracing the CHECK_* macros bellow -- very very verbose code execution! */
+#define TRACE_DEBUG_ALL( str ) 	\
+	TRACE_DEBUG(CALL, str );
+
+/* For development only, to keep track of TODO locations in the code */
+#ifndef ERRORS_ON_TODO
+#define TODO( _msg, _args... ) \
+	TRACE_DEBUG(NONE, "TODO: " _msg , ##_args);
+#else /* ERRORS_ON_TODO */
+#define TODO( _msg, _args... ) \
+	"TODO" = _msg ## _args; /* just a stupid compilation error to spot the todo */
+#endif /* ERRORS_ON_TODO */
+
+/* Trace a binary buffer content */
+#define TRACE_DEBUG_BUFFER(level, prefix, buf, bufsz, suffix ) {								\
+	if ( TRACE_BOOL(level) ) {												\
+		char __ts[25];													\
+		int __i;													\
+		size_t __sz = (size_t)(bufsz);											\
+		uint8_t * __buf = (uint8_t *)(buf);										\
+		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
+		fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"								\
+			  "\t%s|%*s" prefix ,  											\
+					__thn, fd_log_time(NULL, __ts, sizeof(__ts)), __PRETTY_FUNCTION__, __FILE__, __LINE__,	\
+					(level < FULL)?"@":" ",level, ""); 							\
+		for (__i = 0; __i < __sz; __i++) {										\
+			fd_log_debug("%02.2hhx", __buf[__i]);									\
+		}														\
+		fd_log_debug(suffix "\n");											\
+	}															\
+}
+
+/* Some aliases to socket addresses structures */
+#define sSS	struct sockaddr_storage
+#define sSA	struct sockaddr
+#define sSA4	struct sockaddr_in
+#define sSA6	struct sockaddr_in6
+
+/* The sockaddr length of a sSS structure */
+#define sSAlen( _sa_ )	\
+	( (socklen_t) ( (((sSA *)_sa_)->sa_family == AF_INET) ? (sizeof(sSA4)) :		\
+				((((sSA *)_sa_)->sa_family == AF_INET6) ? (sizeof(sSA6)) :	\
+					0 ) ) )
+
+/* Dump one sockaddr Node information */
+#define sSA_DUMP_NODE( sa, flag ) {				\
+	sSA * __sa = (sSA *)(sa);				\
+	char __addrbuf[INET6_ADDRSTRLEN];			\
+	if (__sa) {						\
+	  int __rc = getnameinfo(__sa, 				\
+	  		sSAlen(__sa),				\
+			__addrbuf,				\
+			sizeof(__addrbuf),			\
+			NULL,					\
+			0,					\
+			flag);					\
+	  if (__rc)						\
+	  	fd_log_debug("%s", (char *)gai_strerror(__rc));	\
+	  else							\
+	  	fd_log_debug("%s", &__addrbuf[0]);		\
+	} else {						\
+		fd_log_debug("(NULL / ANY)");			\
+	}							\
+}
+/* Same but with the port (service) also */
+#define sSA_DUMP_NODE_SERV( sa, flag ) {				\
+	sSA * __sa = (sSA *)(sa);					\
+	char __addrbuf[INET6_ADDRSTRLEN];				\
+	char __servbuf[32];						\
+	if (__sa) {							\
+	  int __rc = getnameinfo(__sa, 					\
+	  		sSAlen(__sa),					\
+			__addrbuf,					\
+			sizeof(__addrbuf),				\
+			__servbuf,					\
+			sizeof(__servbuf),				\
+			flag);						\
+	  if (__rc)							\
+	  	fd_log_debug("%s", (char *)gai_strerror(__rc));		\
+	  else								\
+	  	fd_log_debug("[%s]:%s", &__addrbuf[0],&__servbuf[0]);	\
+	} else {							\
+		fd_log_debug("(NULL / ANY)");				\
+	}								\
+}
+
+/* Inside a debug trace */
+#define TRACE_DEBUG_sSA(level, prefix, sa, flags, suffix ) {										\
+	if ( TRACE_BOOL(level) ) {												\
+		char __buf[25];													\
+		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
+		fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"								\
+			  "\t%s|%*s" prefix ,  											\
+					__thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
+					(level < FULL)?"@":" ",level, ""); 							\
+		sSA_DUMP_NODE_SERV( sa, flags );										\
+		fd_log_debug(suffix "\n");											\
+	}															\
+}
+
+/* Report an error */
+#define TRACE_DEBUG_ERROR(format,args... ) \
+	TRACE_DEBUG(NONE, format, ##args)
+
+/******************
+ Optimized code: remove all debugging code
+ **/
+#ifdef STRIP_DEBUG_CODE
+#undef TRACE_DEBUG
+#undef TRACE_BOOL
+#undef TRACE_DEBUG_sSA
+#undef TRACE_DEBUG_BUFFER
+#undef TRACE_DEBUG_ERROR
+#define TRACE_DEBUG(level,format,args... )
+#define TRACE_BOOL(_level_) (0)
+#define TRACE_DEBUG_BUFFER(level, prefix, buf, bufsz, suffix )
+#define TRACE_DEBUG_sSA(level, prefix, sa, flags, suffix )
+#define TRACE_DEBUG_ERROR(format,args... ) {	\
+	fd_log_debug(format "\n", ## args); 	\
+}
+#endif /* STRIP_DEBUG_CODE */
+
+
+/*============================================================*/
+/*                  ERROR CHECKING MACRO                      */
+/*============================================================*/
+
+/* Macros to check a return value and branch out in case of error.
+ * These macro should be used only when errors are improbable, not for expected errors.
+ */
+
+/* Check the return value of a system function and execute fallback in case of error */
+#define CHECK_SYS_DO( __call__, __fallback__  ) { 					\
+	int __ret__;									\
+	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
+	__ret__ = (__call__);								\
+	if (__ret__ < 0) {								\
+		int __err__ = errno;	/* We may handle EINTR here */			\
+		TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "' :\t%s", strerror(__err__));\
+		__fallback__;								\
+	}										\
+}
+/* Check the return value of a system function, return error code on error */
+#define CHECK_SYS( __call__  ) { 							\
+	int __ret__;									\
+	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
+	__ret__ = (__call__);								\
+	if (__ret__ < 0) {								\
+		int __err__ = errno;	/* We may handle EINTR here */			\
+		TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "' :\t%s", strerror(__err__));\
+		return __err__;								\
+	}										\
+}
+
+/* Check the return value of a POSIX function and execute fallback in case of error or special value */
+#define CHECK_POSIX_DO2( __call__, __speval__, __fallback1__, __fallback2__ ) {			\
+	int __ret__;										\
+	TRACE_DEBUG_ALL( "Check POSIX: " #__call__ );						\
+	__ret__ = (__call__);									\
+	if (__ret__ != 0) {									\
+		if (__ret__ == (__speval__)) {							\
+			__fallback1__;								\
+		} else {									\
+			TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "':\t%s", strerror(__ret__));	\
+			__fallback2__;								\
+		}										\
+	}											\
+}
+
+/* Check the return value of a POSIX function and execute fallback in case of error */
+#define CHECK_POSIX_DO( __call__, __fallback__ ) 					\
+	CHECK_POSIX_DO2( (__call__), 0, , __fallback__ );
+
+/* Check the return value of a POSIX function and return it if error */
+#define CHECK_POSIX( __call__ ) { 							\
+	int __v__;									\
+	CHECK_POSIX_DO( __v__ = (__call__), return __v__ );				\
+}
+
+/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
+#define CHECK_MALLOC_DO( __call__, __fallback__ ) { 					\
+	void *  __ret__;								\
+	TRACE_DEBUG_ALL( "Check MALLOC: " #__call__ );					\
+	__ret__ = (void *)( __call__ );							\
+	if (__ret__ == NULL) {								\
+		int __err__ = errno;							\
+		TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "':\t%s", strerror(__err__));	\
+		__fallback__;								\
+	}										\
+}
+
+/* Check that a memory allocator did not return NULL, otherwise return ENOMEM */
+#define CHECK_MALLOC( __call__ )							\
+	CHECK_MALLOC_DO( __call__, return ENOMEM );
+
+
+/* Check parameters at function entry, execute fallback on error */
+#define CHECK_PARAMS_DO( __bool__, __fallback__ )						\
+	TRACE_DEBUG_ALL( "Check PARAMS: " #__bool__ );						\
+	if ( ! (__bool__) ) {									\
+		TRACE_DEBUG_ERROR("Warning: Invalid parameter received in '" #__bool__ "'");	\
+		__fallback__;									\
+	}
+/* Check parameters at function entry, return EINVAL if the boolean is false (similar to assert) */
+#define CHECK_PARAMS( __bool__ )							\
+	CHECK_PARAMS_DO( __bool__, return EINVAL );
+
+/* Check the return value of an internal function, log and propagate */
+#define CHECK_FCT_DO( __call__, __fallback__ ) {					\
+	int __ret__;									\
+	TRACE_DEBUG_ALL( "Check FCT: " #__call__ );					\
+	__ret__ = (__call__);								\
+	if (__ret__ != 0) {								\
+		TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "':\t%s", strerror(__ret__));	\
+		__fallback__;								\
+	}										\
+}
+/* Check the return value of a function call, return any error code */
+#define CHECK_FCT( __call__ ) {								\
+	int __v__;									\
+	CHECK_FCT_DO( __v__ = (__call__), return __v__ );				\
+}
+
+
+
+/*============================================================*/
+/*                  OTHER MACROS                              */
+/*============================================================*/
+
+
+/* helper macros (pre-processor hacks to allow macro arguments) */
+#define __tostr( arg )  #arg
+#define _stringize( arg ) __tostr( arg )
+#define __agr( arg1, arg2 ) arg1 ## arg2
+#define _aggregate( arg1, arg2 ) __agr( arg1, arg2 )
+
+
+/* A l4 protocol name (TCP / SCTP) */
+#ifdef DISABLE_SCTP
+#define IPPROTO_NAME( _proto )					\
+	(((_proto) == IPPROTO_TCP) ? "TCP" :			\
+			"Unknown")
+#else /* DISABLE_SCTP */
+#define IPPROTO_NAME( _proto )					\
+	( ((_proto) == IPPROTO_TCP) ? "TCP" :			\
+		(((_proto) == IPPROTO_SCTP) ? "SCTP" :		\
+			"Unknown"))
+#endif /* DISABLE_SCTP */
+
+/* Define the value of IP loopback address */
+#ifndef INADDR_LOOPBACK 
+#define INADDR_LOOPBACK	inet_addr("127.0.0.1")
+#endif /* INADDR_LOOPBACK */
+
+#ifndef INADDR_BROADCAST
+#define	INADDR_BROADCAST	((in_addr_t) 0xffffffff)
+#endif /* INADDR_BROADCAST */
+
+/* An IP equivalent to IN6_IS_ADDR_LOOPBACK */
+#ifndef IN_IS_ADDR_LOOPBACK
+#define IN_IS_ADDR_LOOPBACK(a) \
+  ((((long int) (a)->s_addr) & ntohl(0xff000000)) == ntohl(0x7f000000))
+#endif /* IN_IS_ADDR_LOOPBACK */
+
+/* An IP equivalent to IN6_IS_ADDR_UNSPECIFIED */
+#ifndef IN_IS_ADDR_UNSPECIFIED
+#define IN_IS_ADDR_UNSPECIFIED(a) \
+  (((long int) (a)->s_addr) == 0x00000000)
+#endif /* IN_IS_ADDR_UNSPECIFIED */
+
+/* create a V4MAPPED address */
+#define IN6_ADDR_V4MAP( a6, a4 ) {			\
+	((uint32_t *)(a6))[0] = 0;			\
+	((uint32_t *)(a6))[1] = 0;			\
+	((uint32_t *)(a6))[2] = htonl(0xffff);		\
+	((uint32_t *)(a6))[3] = (uint32_t)(a4);		\
+}
+
+/* Retrieve a v4 value from V4MAPPED address ( takes a s6_addr as param) */
+#define IN6_ADDR_V4UNMAP( a6 ) 				\
+	(((in_addr_t *)(a6))[3])
+
+
+/* We provide macros to convert 64 bit values to and from network byte-order, on systems where it is not already provided. */
+#ifndef HAVE_NTOHLL	/* Defined by the cmake step, if the ntohll symbol is defined on the system */
+# if HOST_BIG_ENDIAN
+    /* In big-endian systems, we don't have to change the values, since the order is the same as network */
+#   define ntohll(x) (x)
+#   define htonll(x) (x)
+# else /* HOST_BIG_ENDIAN */
+    /* For these systems, we must reverse the bytes. Use ntohl and htonl on sub-32 blocs, and inverse these blocs. */
+#   define ntohll(x) (typeof (x))( (((uint64_t)ntohl( (uint32_t)(x))) << 32 ) | ((uint64_t) ntohl( ((uint64_t)(x)) >> 32 ))) 
+#   define htonll(x) (typeof (x))( (((uint64_t)htonl( (uint32_t)(x))) << 32 ) | ((uint64_t) htonl( ((uint64_t)(x)) >> 32 ))) 
+# endif /* HOST_BIG_ENDIAN */
+#endif /* HAVE_NTOHLL */
+
+/* This macro will give the next multiple of 4 for an integer (used for padding sizes of AVP). */
+#define PAD4(_x) ((_x) + ( (4 - (_x)) & 3 ) )
+
+/* Useful to display any value as (safe) ASCII (will garbage UTF-8 output...) */
+#define ASCII(_c) ( ((_c < 32) || (_c > 127)) ? ( _c ? '?' : ' ' ) : _c )
+
+/* Compare timespec structures */
+#define TS_IS_INFERIOR( ts1, ts2 ) 		\
+	(    ((ts1)->tv_sec  < (ts2)->tv_sec ) 	\
+	  || (((ts1)->tv_sec  == (ts2)->tv_sec ) && ((ts1)->tv_nsec < (ts2)->tv_nsec) ))
+
+/* This gives a good size for buffered reads */
+#ifndef BUFSIZ
+#define BUFSIZ 96
+#endif /* BUFSIZ */
+
+
+
+/*============================================================*/
+/*                          THREADS                           */
+/*============================================================*/
+
+/* Terminate a thread */
+static __inline__ int fd_thr_term(pthread_t * th)
+{
+	void * th_ret = NULL;
+	
+	CHECK_PARAMS(th);
+	
+	/* Test if it was already terminated */
+	if (*th == (pthread_t)NULL)
+		return 0;
+	
+	/* Cancel the thread if it is still running - ignore error if it was already terminated */
+	(void) pthread_cancel(*th);
+	
+	/* Then join the thread */
+	CHECK_POSIX( pthread_join(*th, &th_ret) );
+	
+	if (th_ret == PTHREAD_CANCELED) {
+		TRACE_DEBUG(ANNOYING, "The thread %p was canceled", *th);
+	} else {
+		TRACE_DEBUG(CALL, "The thread %p returned %x", *th, th_ret);
+	}
+	
+	/* Clean the location */
+	*th = (pthread_t)NULL;
+	
+	return 0;
+}
+
+/* Force flushing the cache of a CPU before reading a shared memory area (use only for atomic reads such as int and void*) */
+extern pthread_mutex_t fd_cpu_mtx_dummy; /* only for the macro bellow, so that we have reasonably fresh pir_state value when needed */
+#define fd_cpu_flush_cache() {				\
+	(void)pthread_mutex_lock(&fd_cpu_mtx_dummy);	\
+	(void)pthread_mutex_unlock(&fd_cpu_mtx_dummy);	\
+}
+
+
+/*************
+ Cancelation cleanup handlers for common objects 
+ *************/
+static __inline__ void fd_cleanup_mutex( void * mutex )
+{
+	CHECK_POSIX_DO( pthread_mutex_unlock((pthread_mutex_t *)mutex), /* */);
+}
+		
+static __inline__ void fd_cleanup_rwlock( void * rwlock )
+{
+	CHECK_POSIX_DO( pthread_rwlock_unlock((pthread_rwlock_t *)rwlock), /* */);
+}
+
+static __inline__ void fd_cleanup_buffer( void * buffer )
+{
+	free(buffer);
+}
+static __inline__ void fd_cleanup_socket(void * sockptr)
+{
+	if (sockptr && (*(int *)sockptr > 0)) {
+		CHECK_SYS_DO( close(*(int *)sockptr), /* ignore */ );
+		*(int *)sockptr = -1;
+	}
+}
+
+
+/*============================================================*/
+/*                          LISTS                             */
+/*============================================================*/
+
+/* The following structure represents a chained list element  */
+struct fd_list {
+	struct fd_list 	*next; /* next element in the list */
+	struct fd_list 	*prev; /* previous element in the list */
+	struct fd_list 	*head; /* head of the list */
+	void		*o;    /* additional pointer, used for any purpose (ex: start of the parent object) */
+};
+
+/* Initialize a list element */
+#define FD_LIST_INITIALIZER( _list_name ) \
+	{ .next = & _list_name, .prev = & _list_name, .head = & _list_name, .o = NULL }
+#define FD_LIST_INITIALIZER_O( _list_name, _obj ) \
+	{ .next = & _list_name, .prev = & _list_name, .head = & _list_name, .o = _obj }
+void fd_list_init ( struct fd_list * list, void * obj );
+
+/* Return boolean, true if the list is empty */
+#define FD_IS_LIST_EMPTY( _list ) ((((struct fd_list *)(_list))->head == (_list)) && (((struct fd_list *)(_list))->next == (_list)))
+
+/* Insert an item in a list at known position */
+void fd_list_insert_after  ( struct fd_list * ref, struct fd_list * item );
+void fd_list_insert_before ( struct fd_list * ref, struct fd_list * item );
+
+/* Move all elements from a list at the end of another */
+void fd_list_move_end(struct fd_list * ref, struct fd_list * senti);
+
+/* Insert an item in an ordered list -- ordering function must be provided. If duplicate object found, EEXIST and it is returned in ref_duplicate */
+int fd_list_insert_ordered( struct fd_list * head, struct fd_list * item, int (*cmp_fct)(void *, void *), void ** ref_duplicate);
+
+/* Unlink an item from a list */
+void fd_list_unlink ( struct fd_list * item );
+
+
+
+/*============================================================*/
+/*                          HASH                              */
+/*============================================================*/
+
+/* Compute a hash value of a string (session id, diameter id, ...) */
+uint32_t fd_hash ( char * string, size_t len );
+
+
+
+/*============================================================*/
+/*                        DICTIONARY                          */
+/*============================================================*/
+
+/* Structure that contains the complete dictionary definitions */
+struct dictionary;
+
+/* Structure that contains a dictionary object */
+struct dict_object;
+
+/* Types of object in the dictionary. */
+enum dict_object_type {
+	DICT_VENDOR	= 1,	/* Vendor */
+	DICT_APPLICATION,	/* Diameter Application */
+	DICT_TYPE,		/* AVP data type */
+	DICT_ENUMVAL,		/* Named constant (value of an enumerated AVP type) */
+	DICT_AVP,		/* AVP */
+	DICT_COMMAND,		/* Diameter Command */
+	DICT_RULE		/* a Rule for AVP in command or grouped AVP */
+#define DICT_TYPE_MAX	DICT_RULE
+};
+	
+/* Initialize a dictionary */
+int fd_dict_init(struct dictionary ** dict);
+/* Destroy a dictionary */
+int fd_dict_fini(struct dictionary ** dict);
+
+/*
+ * FUNCTION:	fd_dict_new
+ *
+ * PARAMETERS:
+ *  dict	: Pointer to the dictionnary where the object is created
+ *  type 	: What kind of object must be created
+ *  data 	: pointer to the data for the object. 
+ *          	 type parameter is used to determine the type of data (see bellow for detail).
+ *  parent 	: a reference to a parent object, if needed.
+ *  ref 	: upon successful creation, reference to new object is stored here if !null.
+ *
+ * DESCRIPTION: 
+ *  Create a new object in the dictionary. 
+ *  See following object sections in this header file for more information on data and parent parameters format.
+ *
+ * RETURN VALUE:
+ *  0      	: The object is created in the dictionary.
+ *  EINVAL 	: A parameter is invalid.
+ *  EEXIST 	: This object is already defined in the dictionary (with conflicting data). 
+ *                If "ref" is not NULL, it points to the existing element on return.
+ *  (other standard errors may be returned, too, with their standard meaning. Example:
+ *    ENOMEM 	: Memory allocation for the new object element failed.)
+ */
+int fd_dict_new ( struct dictionary * dict, enum dict_object_type type, void * data, struct dict_object * parent, struct dict_object ** ref );
+
+/*
+ * FUNCTION: 	fd_dict_search
+ *
+ * PARAMETERS:
+ *  dict	: Pointer to the dictionnary where the object is searched
+ *  type 	: type of object that is being searched
+ *  criteria 	: how the object must be searched. See object-related sections bellow for more information.
+ *  what 	: depending on criteria, the data that must be searched.
+ *  result 	: On successful return, pointer to the object is stored here.
+ *  retval	: this value is returned if the object is not found and result is not NULL.
+ *
+ * DESCRIPTION: 
+ *   Perform a search in the dictionary. 
+ *   See the object-specific sections bellow to find how to look for each objects.
+ *   If the "result" parameter is NULL, the function is used to check if an object is in the dictionary.
+ *   Otherwise, a reference to the object is stored in result if found.
+ *   If result is not NULL and the object is not found, retval is returned (should be 0 or ENOENT usually)
+ *
+ * RETURN VALUE:
+ *  0      	: The object has been found in the dictionary, or *result is NULL.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOENT	: No matching object has been found, and result was NULL.
+ */
+int fd_dict_search ( struct dictionary * dict, enum dict_object_type type, int criteria, void * what, struct dict_object ** result, int retval );
+
+/* Special case: get the generic error command object */
+int fd_dict_get_error_cmd(struct dictionary * dict, struct dict_object ** obj);
+
+/*
+ * FUNCTION:	fd_dict_getval
+ *
+ * PARAMETERS:
+ *  object 	: Pointer to a dictionary object.
+ *  data 	: pointer to a structure to hold the data for the object.
+ *          	  The type is the same as "data" parameter in fd_dict_new function.
+ *
+ * DESCRIPTION: 
+ *  Retrieve content of a dictionary object.
+ *  See following object sections in this header file for more information on data and parent parameters format.
+ *
+ * RETURN VALUE:
+ *  0      	: The content of the object has been retrieved.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_dict_getval ( struct dict_object * object, void * val);
+int fd_dict_gettype ( struct dict_object * object, enum dict_object_type * type);
+int fd_dict_getdict ( struct dict_object * object, struct dictionary ** dict);
+
+/* Debug functions */
+void fd_dict_dump_object(struct dict_object * obj);
+void fd_dict_dump(struct dictionary * dict);
+
+/*
+ ***************************************************************************
+ *
+ * Vendor object 
+ *
+ * These types are used to manage vendors in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold a Vendor ID: "SMI Network Management Private Enterprise Codes" (RFC3232) */
+typedef uint32_t	vendor_id_t;
+
+/* Type to hold data associated to a vendor */
+struct dict_vendor_data {
+	vendor_id_t	 vendor_id;	/* ID of a vendor */
+	char 		*vendor_name;	/* The name of this vendor */
+};
+
+/* The criteria for searching a vendor object in the dictionary */
+enum {
+	VENDOR_BY_ID = 10,	/* "what" points to a vendor_id_t */
+	VENDOR_BY_NAME,		/* "what" points to a string */
+	VENDOR_OF_APPLICATION	/* "what" points to a struct dict_object containing an application (see bellow) */
+};
+
+/***
+ *  API usage :
+
+Note: the value of "vendor_name" is copied when the object is created, and the string may be disposed afterwards.
+On the other side, when value is retrieved with dict_getval, the string is not copied and MUST NOT be freed. It will
+be freed automatically along with the object itself with call to dict_fini later.
+ 
+- fd_dict_new:
+ The "parent" parameter is not used for vendors. 
+ Sample code to create a vendor:
+ {
+	 int ret;
+	 struct dict_object * myvendor;
+	 struct dict_vendor_data myvendordata = { 23455, "my vendor name" };  -- just an example...
+	 ret = fd_dict_new ( dict, DICT_VENDOR, &myvendordata, NULL, &myvendor );
+ }
+
+- fd_dict_search:
+ Sample codes to look for a vendor object, by its id or name:
+ {
+	 int ret;
+	 struct dict_object * vendor_found;
+	 vendor_id_t vendorid = 23455;
+	 ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_BY_ID, &vendorid, &vendor_found, ENOENT);
+	 - or -
+	 ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_BY_NAME, "my vendor name", &vendor_found, ENOENT);
+ }
+ 
+ - fd_dict_getval:
+ Sample code to retrieve the data from a vendor object:
+ {
+	 int ret;
+	 struct dict_object * myvendor;
+	 struct dict_vendor_data myvendordata;
+	 ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_BY_NAME, "my vendor name", &myvendor, ENOENT);
+	 ret = fd_dict_getval ( myvendor, &myvendordata );
+	 printf("my vendor id: %d\n", myvendordata.vendor_id );
+ }
+		 
+*/
+		
+/* Special function: */
+uint32_t * fd_dict_get_vendorid_list(struct dictionary * dict);
+	 
+/*
+ ***************************************************************************
+ *
+ * Application object 
+ *
+ * These types are used to manage Diameter applications in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold a Diameter application ID: IANA assigned value for this application. */
+typedef uint32_t	application_id_t;
+
+/* Type to hold data associated to an application */
+struct dict_application_data {
+	application_id_t	 application_id;	/* ID of the application */
+	char 			*application_name;	/* The name of this application */
+};
+
+/* The criteria for searching an application object in the dictionary */
+enum {
+	APPLICATION_BY_ID = 20,		/* "what" points to a application_id_t */
+	APPLICATION_BY_NAME,		/* "what" points to a string */
+	APPLICATION_OF_TYPE,		/* "what" points to a struct dict_object containing a type object (see bellow) */
+	APPLICATION_OF_COMMAND		/* "what" points to a struct dict_object containing a command (see bellow) */
+};
+
+/***
+ *  API usage :
+
+The "parent" parameter of dict_new may point to a vendor object to inform of what vendor defines the application.
+for standard-track applications, the "parent" parameter should be NULL.
+The vendor associated to an application is retrieved with VENDOR_OF_APPLICATION search criteria on vendors.
+
+- fd_dict_new:
+ Sample code for application creation:
+ {
+	 int ret;
+	 struct dict_object * vendor;
+	 struct dict_object * appl;
+	 struct dict_vendor_data vendor_data = {
+		 23455,
+		 "my vendor name"
+	 };
+	 struct dict_application_data app_data = {
+		 9789,
+		 "my vendor's application"
+	 };
+	
+	 ret = fd_dict_new ( dict, DICT_VENDOR, &vendor_data, NULL, &vendor );
+	 ret = fd_dict_new ( dict, DICT_APPLICATION, &app_data, vendor, &appl );
+ }
+
+- fd_dict_search:
+ Sample code to retrieve the vendor of an application
+ {
+	 int ret;
+	 struct dict_object * vendor, * appli;
+	 
+	 ret = fd_dict_search ( dict, DICT_APPLICATION, APPLICATION_BY_NAME, "my vendor's application", &appli, ENOENT);
+	 ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_OF_APPLICATION, appli, &vendor, ENOENT);
+ }
+ 
+ - fd_dict_getval:
+ Sample code to retrieve the data from an application object:
+ {
+	 int ret;
+	 struct dict_object * appli;
+	 struct dict_application_data appl_data;
+	 ret = fd_dict_search ( dict, DICT_APPLICATION, APPLICATION_BY_NAME, "my vendor's application", &appli, ENOENT);
+	 ret = fd_dict_getval ( appli, &appl_data );
+	 printf("my application id: %s\n", appl_data.application_id );
+ }
+
+*/
+
+/*
+ ***************************************************************************
+ *
+ * Type object 
+ *
+ * These types are used to manage AVP data types in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to store any AVP value */ 
+union avp_value {
+	struct {
+		uint8_t *data;	/* bytes buffer */
+		size_t   len;	/* length of the data buffer */
+	}           os;		/* Storage for an octet string, data is alloc'd and must be freed */
+	int32_t     i32;	/* integer 32 */
+	int64_t     i64;	/* integer 64 */
+	uint32_t    u32;	/* unsigned 32 */
+	uint64_t    u64;	/* unsigned 64 */
+	float       f32;	/* float 32 */
+	double 	    f64;	/* float 64 */
+};
+
+/* These are the basic AVP types defined in RFC3588bis */
+enum dict_avp_basetype {
+	AVP_TYPE_GROUPED,
+	AVP_TYPE_OCTETSTRING,
+	AVP_TYPE_INTEGER32,
+	AVP_TYPE_INTEGER64,
+	AVP_TYPE_UNSIGNED32,
+	AVP_TYPE_UNSIGNED64,
+	AVP_TYPE_FLOAT32,
+	AVP_TYPE_FLOAT64
+#define AVP_TYPE_MAX AVP_TYPE_FLOAT64
+};
+
+/* Callbacks that can be associated with a derived type to easily interpret the AVP value. */
+/*
+ * CALLBACK:	dict_avpdata_interpret
+ *
+ * PARAMETERS:
+ *   val         : Pointer to the AVP value that must be interpreted.
+ *   interpreted : The result of interpretation is stored here. The format and meaning depends on each type.
+ *
+ * DESCRIPTION: 
+ *   This callback can be provided with a derived type in order to facilitate the interpretation of formated data.
+ *  For example, when an AVP of type "Address" is received, it can be used to convert the octetstring into a struct sockaddr.
+ *  This callback is not called directly, but through the message's API msg_avp_value_interpret function.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0 		: An error occurred, the error code is returned.
+ */
+typedef int (*dict_avpdata_interpret) (union avp_value * value, void * interpreted);
+/*
+ * CALLBACK:	dict_avpdata_encode
+ *
+ * PARAMETERS:
+ *   data	: The formated data that must be stored in the AVP value.
+ *   val	: Pointer to the AVP value storage area where the data must be stored.
+ *
+ * DESCRIPTION: 
+ *   This callback can be provided with a derived type in order to facilitate the encoding of formated data.
+ *  For example, it can be used to convert a struct sockaddr in an AVP value of type Address.
+ *  This callback is not called directly, but through the message's API msg_avp_value_encode function.
+ *  If the callback is defined for an OctetString based type, the created string must be malloc'd. free will be called 
+ *  automatically later.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0 		: An error occurred, the error code is returned.
+ */
+typedef int (*dict_avpdata_encode) (void * data, union avp_value * val);
+
+
+/* Type to hold data associated to a derived AVP data type */
+struct dict_type_data {
+	enum dict_avp_basetype	 type_base;	/* How the data of such AVP must be interpreted */
+	char 			*type_name;	/* The name of this type */
+	dict_avpdata_interpret	 type_interpret;/* cb to convert the AVP value in more comprehensive format (or NULL) */
+	dict_avpdata_encode	 type_encode;	/* cb to convert formatted data into an AVP value (or NULL) */
+	void			(*type_dump)(union avp_value * val);	/* cb called by fd_msg_dump_one for this type of data (if != NULL), to dump the AVP value in debug */
+};
+
+/* The criteria for searching a type object in the dictionary */
+enum {
+	TYPE_BY_NAME = 30,		/* "what" points to a string */
+	TYPE_OF_ENUMVAL,		/* "what" points to a struct dict_object containing an enumerated constant (DICT_ENUMVAL, see bellow). */
+	TYPE_OF_AVP			/* "what" points to a struct dict_object containing an AVP object. */
+};
+
+
+/***
+ *  API usage :
+
+- fd_dict_new:
+ The "parent" parameter may point to an application object, when a type is defined by a Diameter application. 
+ 
+ Sample code:
+ {
+	 int ret;
+	 struct dict_object * mytype;
+	 struct dict_type_data mytypedata = 
+		{ 
+		 AVP_TYPE_OCTETSTRING,
+		 "Address",
+		 NULL,
+		 NULL
+		};
+	 ret = fd_dict_new ( dict, DICT_TYPE, &mytypedata, NULL, &mytype );
+ }
+
+- fd_dict_search:
+ Sample code:
+ {
+	 int ret;
+	 struct dict_object * address_type;
+	 ret = fd_dict_search ( dict, DICT_TYPE, TYPE_BY_NAME, "Address", &address_type, ENOENT);
+ }
+ 
+*/
+	 
+/*
+ ***************************************************************************
+ *
+ * Enumerated values object 
+ *
+ * These types are used to manage named constants of some AVP,
+ * for enumerated types. freeDiameter allows constants for types others than Unsigned32
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold data of named constants for AVP */
+struct dict_enumval_data {
+	char 		*enum_name;	/* The name of this constant */
+	union avp_value  enum_value;	/* Value of the constant. Union term depends on parent type's base type. */
+};
+
+/* The criteria for searching a constant in the dictionary */
+enum {
+	ENUMVAL_BY_STRUCT = 40,	/* "what" points to a struct dict_enumval_request as defined bellow */
+};
+
+struct dict_enumval_request {
+	/* Identifier of the parent type, one of the following must not be NULL */
+	struct dict_object	*type_obj;
+	char			*type_name;
+	
+	/* Search criteria for the constant */
+	struct dict_enumval_data search; /* search.enum_value is used only if search.enum_name == NULL */
+};
+
+/***
+ *  API usage :
+
+- fd_dict_new:
+ The "parent" parameter must point to a derived type object. 
+ Sample code to create a type "Boolean" with two constants "True" and "False":
+ {
+	 int ret;
+	 struct dict_object * type_boolean;
+	 struct dict_type_data type_boolean_data = 
+		{ 
+		 AVP_TYPE_INTEGER32,
+		 "Boolean",
+		 NULL,
+		 NULL
+		};
+	 struct dict_enumval_data boolean_false =
+	 	{
+		 .enum_name="False",
+		 .enum_value.i32 = 0
+	 	};
+	 struct dict_enumval_data boolean_true =
+	 	{
+		 .enum_name="True",
+		 .enum_value.i32 = -1
+	 	};
+	 ret = fd_dict_new ( dict, DICT_TYPE, &type_boolean_data, NULL, &type_boolean );
+	 ret = fd_dict_new ( dict, DICT_ENUMVAL, &boolean_false, type_boolean, NULL );
+	 ret = fd_dict_new ( dict, DICT_ENUMVAL, &boolean_true , type_boolean, NULL );
+	 
+ }
+
+- fd_dict_search:
+ Sample code to look for a constant name, by its value:
+ {
+	 int ret;
+	 struct dict_object * value_found;
+	 struct dict_enumval_request boolean_by_value =
+	 	{
+		 .type_name = "Boolean",
+		 .search.enum_name=NULL,
+		 .search.enum_value.i32 = -1
+	 	};
+	 
+	 ret = fd_dict_search ( dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &boolean_by_value, &value_found, ENOENT);
+ }
+ 
+ - fd_dict_getval:
+ Sample code to retrieve the data from a constant object:
+ {
+	 int ret;
+	 struct dict_object * value_found;
+	 struct dict_enumval_data boolean_data = NULL;
+	 struct dict_enumval_request boolean_by_value =
+	 	{
+		 .type_name = "Boolean",
+		 .search.enum_name=NULL,
+		 .search.enum_value.i32 = 0
+	 	};
+	 
+	 ret = fd_dict_search ( dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &boolean_by_value, &value_found, ENOENT);
+	 ret = fd_dict_getval ( value_found, &boolean_data );
+	 printf(" Boolean with value 0: %s", boolean_data.enum_name );
+ }
+*/
+	 
+/*
+ ***************************************************************************
+ *
+ * AVP object 
+ *
+ * These objects are used to manage AVP definitions in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold an AVP code. For vendor 0, these codes are assigned by IANA. Otherwise, it is managed by the vendor */
+typedef uint32_t	avp_code_t;
+
+/* Values of AVP flags */
+#define	AVP_FLAG_VENDOR	  	0x80
+#define	AVP_FLAG_MANDATORY	0x40
+#define	AVP_FLAG_RESERVED3	0x20
+#define	AVP_FLAG_RESERVED4	0x10
+#define	AVP_FLAG_RESERVED5	0x08
+#define	AVP_FLAG_RESERVED6	0x04
+#define	AVP_FLAG_RESERVED7	0x02
+#define	AVP_FLAG_RESERVED8	0x01
+
+/* For dumping flags and values */
+#define DUMP_AVPFL_str	"%c%c"
+#define DUMP_AVPFL_val(_val) (_val & AVP_FLAG_VENDOR)?'V':'-' , (_val & AVP_FLAG_MANDATORY)?'M':'-'
+
+/* Type to hold data associated to an avp */
+struct dict_avp_data {
+	avp_code_t	 	 avp_code;	/* Code of the avp */
+	vendor_id_t	 	 avp_vendor;	/* Vendor of the AVP, or 0 */
+	char			*avp_name;	/* Name of this AVP */
+	uint8_t		 	 avp_flag_mask;	/* Mask of fixed AVP flags */
+	uint8_t		 	 avp_flag_val;	/* Values of the fixed flags */
+	enum dict_avp_basetype 	 avp_basetype;	/* Basic type of data found in the AVP */
+};
+
+/* The criteria for searching an avp object in the dictionary */
+enum {
+	AVP_BY_CODE = 50,	/* "what" points to an avp_code_t, vendor is always 0 */
+	AVP_BY_NAME,		/* "what" points to a string, vendor is always 0 */
+	AVP_BY_CODE_AND_VENDOR,	/* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_code are set */
+	AVP_BY_NAME_AND_VENDOR,	/* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_name are set */
+	AVP_BY_NAME_ALL_VENDORS /* "what" points to a string. Might be quite slow... */
+};
+
+/* Struct used for some researchs */
+struct dict_avp_request {
+	vendor_id_t	 avp_vendor;
+	avp_code_t	 avp_code;
+	char		*avp_name;
+};
+
+
+/***
+ *  API usage :
+
+If "parent" parameter is not NULL during AVP creation, it must point to a DICT_TYPE object. 
+The extended type is then attached to the AVP. In case where it is an enumerated type, the value of 
+AVP is automatically interpreted in debug messages, and in message checks.
+The derived type of an AVP can be retrieved with: dict_search ( DICT_TYPE, TYPE_OF_AVP, avp, ... )
+
+To create the rules (ABNF) for children of Grouped AVP, see the DICT_RULE related part.
+
+- fd_dict_new:
+ Sample code for AVP creation:
+ {
+	 int ret;
+	 struct dict_object * user_name_avp;
+	 struct dict_object * boolean_type;
+	 struct dict_object * sample_boolean_avp;
+	 struct dict_avp_data user_name_data = {
+		 1,					// code
+		 0,					// vendor
+		 "User-Name",				// name
+		 AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY,	// fixed mask: V and M values must always be defined as follow. other flags can be set or cleared
+		 AVP_FLAG_MANDATORY,			// the V flag must be cleared, the M flag must be set.
+		 AVP_TYPE_OCTETSTRING			// User-Name AVP contains OctetString data (further precision such as UTF8String can be given with a parent derived type)
+	 };
+	 struct dict_avp_data sample_boolean_data = {
+		 31337,
+		 23455,
+		 "Sample-Boolean",
+		 AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY,
+		 AVP_FLAG_VENDOR,
+		 AVP_TYPE_INTEGER32			// This MUST be the same as parent type's
+	 };
+	
+ 	 -- Create an AVP with a base type --
+	 ret = fd_dict_new ( dict, DICT_AVP, &user_name_data, NULL, &user_name_avp );
+	 
+	 -- Create an AVP with a derived type --
+	 ret = fd_dict_search ( dict, DICT_TYPE, TYPE_BY_NAME, "Boolean", &boolean_type, ENOENT);
+	 ret = fd_dict_new ( dict, DICT_AVP, &sample_boolean_data , boolean_type, &sample_boolean_avp );
+	 
+ }
+
+- fd_dict_search:
+ Sample code to look for an AVP
+ {
+	 int ret;
+	 struct dict_object * avp_username;
+	 struct dict_object * avp_sampleboolean;
+	 struct dict_avp_request avpvendorboolean =
+	 	{
+		 .avp_vendor = 23455,
+		 .avp_name   = "Sample-Boolean"
+	 	};
+	 
+	 ret = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME, "User-Name", &avp_username, ENOENT);
+	 
+	 ret = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &avpvendorboolean, &avp_sampleboolean, ENOENT);
+	 
+ }
+ 
+ - fd_dict_getval:
+ Sample code to retrieve the data from an AVP object:
+ {
+	 int ret;
+	 struct dict_object * avp_username;
+	 struct dict_avp_data user_name_data;
+	 ret = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME, "User-Name", &avp_username, ENOENT);
+	 ret = fd_dict_getval ( avp_username, &user_name_data );
+	 printf("User-Name code: %d\n", user_name_data.avp_code );
+ }
+
+*/
+
+/*
+ ***************************************************************************
+ *
+ * Command object 
+ *
+ * These types are used to manage commands objects in the dictionary
+ *
+ ***************************************************************************
+ */
+
+/* Type to hold a Diameter command code: IANA assigned values. 0x0-0x7fffff=standard, 0x800000-0xfffffd=vendors, 0xfffffe-0xffffff=experimental */
+typedef uint32_t	command_code_t;
+
+/* Values of command flags */
+#define CMD_FLAG_REQUEST	0x80
+#define CMD_FLAG_PROXIABLE	0x40
+#define CMD_FLAG_ERROR		0x20
+#define CMD_FLAG_RETRANSMIT	0x10
+#define CMD_FLAG_RESERVED5	0x08
+#define CMD_FLAG_RESERVED6	0x04
+#define CMD_FLAG_RESERVED7	0x02
+#define CMD_FLAG_RESERVED8	0x01
+
+/* For dumping flags and values */
+#define DUMP_CMDFL_str	"%c%c%c%c"
+#define DUMP_CMDFL_val(_val) (_val & CMD_FLAG_REQUEST)?'R':'-' , (_val & CMD_FLAG_PROXIABLE)?'P':'-' , (_val & CMD_FLAG_ERROR)?'E':'-' , (_val & CMD_FLAG_RETRANSMIT)?'T':'-'
+
+/* Type to hold data associated to a command */
+struct dict_cmd_data {
+	command_code_t	 cmd_code;	/* code of the command */
+	char		*cmd_name;	/* Name of the command */
+	uint8_t		 cmd_flag_mask;	/* Mask of fixed-value flags */
+	uint8_t		 cmd_flag_val;	/* values of the fixed flags */
+};
+
+/* The criteria for searching an avp object in the dictionary */
+enum {
+	CMD_BY_NAME = 60,	/* "what" points to a string */
+	CMD_BY_CODE_R,		/* "what" points to a command_code_t. The "Request" command is returned. */
+	CMD_BY_CODE_A,		/* "what" points to a command_code_t. The "Answer" command is returned. */
+	CMD_ANSWER		/* "what" points to a struct dict_object of a request command. The corresponding "Answer" command is returned. */
+};
+
+
+/***
+ *  API usage :
+
+The "parent" parameter of dict_new may point to an application object to inform of what application defines the command.
+The application associated to a command is retrieved with APPLICATION_OF_COMMAND search criteria on applications.
+
+To create the rules for children of commands, see the DICT_RULE related part.
+
+Note that the "Request" and "Answer" commands are two independant objects. This allows to have different rules for each.
+
+- fd_dict_new:
+ Sample code for command creation:
+ {
+	 int ret;
+	 struct dict_object * cer;
+	 struct dict_object * cea;
+	 struct dict_cmd_data ce_data = {
+		 257,					// code
+		 "Capabilities-Exchange-Request",	// name
+		 CMD_FLAG_REQUEST,			// mask
+		 CMD_FLAG_REQUEST			// value. Only the "R" flag is constrained here, set.
+	 };
+	
+	 ret = fd_dict_new (dict,  DICT_COMMAND, &ce_data, NULL, &cer );
+	 
+	 ce_data.cmd_name = "Capabilities-Exchange-Answer";
+	 ce_data.cmd_flag_val = 0;			// Same constraint on "R" flag, but this time it must be cleared.
+
+	 ret = fd_dict_new ( dict, DICT_COMMAND, &ce_data, NULL, &cea );
+ }
+
+- fd_dict_search:
+ Sample code to look for a command
+ {
+	 int ret;
+	 struct dict_object * cer, * cea;
+	 command_code_t	code = 257;
+	 ret = fd_dict_search ( dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer, ENOENT);
+	 ret = fd_dict_search ( dict, DICT_COMMAND, CMD_BY_CODE_R, &code, &cer, ENOENT);
+ }
+ 
+ - fd_dict_getval:
+ Sample code to retrieve the data from a command object:
+ {
+	 int ret;
+	 struct dict_object * cer;
+	 struct dict_object * cea;
+	 struct dict_cmd_data cea_data;
+	 ret = fd_dict_search ( dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer, ENOENT);
+	 ret = fd_dict_search ( dict, DICT_COMMAND, CMD_ANSWER, cer, &cea, ENOENT);
+	 ret = fd_dict_getval ( cea, &cea_data );
+	 printf("Answer to CER: %s\n", cea_data.cmd_name );
+ }
+
+*/
+
+/*
+ ***************************************************************************
+ *
+ * Rule object
+ *
+ * These objects are used to manage rules in the dictionary (ABNF implementation)
+ * This is used for checking messages validity (more powerful than a DTD)
+ *
+ ***************************************************************************
+ */
+
+/* This defines the kind of rule that is defined */
+enum rule_position {
+	RULE_FIXED_HEAD = 1,	/* The AVP must be at the head of the group. The rule_order field is used to specify the position. */
+	RULE_REQUIRED,		/* The AVP must be present in the parent, but its position is not defined. */
+	RULE_OPTIONAL,		/* The AVP may be present in the message. Used to specify a max number of occurences for example */
+	RULE_FIXED_TAIL		/* The AVP must be at the end of the group. The rule_order field is used to specify the position. */
+};
+
+/* Content of a RULE object data */
+struct dict_rule_data {
+	struct dict_object	*rule_avp;	/* Pointer to the AVP object that is concerned by this rule */
+	enum rule_position	 rule_position;	/* The position in which the rule_avp must appear in the parent */
+	unsigned		 rule_order;	/* for RULE_FIXED_* rules, the place. 1,2,3.. for HEAD rules; ...,3,2,1 for TAIL rules. */
+	int	 		 rule_min;	/* Minimum number of occurences. -1 means "default": 0 for optional rules, 1 for other rules */
+	int			 rule_max;	/* Maximum number of occurences. -1 means no maximum. 0 means the AVP is forbidden. */
+};
+
+/* The criteria for searching a rule in the dictionary */
+enum {
+	RULE_BY_AVP_AND_PARENT = 70	/* "what" points to a struct dict_rule_request -- see bellow. This is used to query "what is the rule for this AVP in this group?" */
+};
+
+/* Structure for querying the dictionary about a rule */
+struct dict_rule_request {
+	struct dict_object	*rule_parent;	/* The grouped avp or command to which the rule apply */
+	struct dict_object	*rule_avp;	/* The AVP concerned by this rule */
+};
+
+
+/***
+ *  API usage :
+
+The "parent" parameter can not be NULL. It points to the object (grouped avp or command) to which this rule apply (i.e. for which the ABNF is defined).
+
+- fd_dict_new:
+ Sample code for rule creation. Let's create the Proxy-Info grouped AVP for example.
+ {
+	int ret;
+	struct dict_object * proxy_info_avp;
+	struct dict_object * proxy_host_avp;
+	struct dict_object * proxy_state_avp;
+	struct dict_object * diameteridentity_type;
+	struct dict_rule_data rule_data;
+	struct dict_type_data di_type_data = { AVP_TYPE_OCTETSTRING, "DiameterIdentity", NULL, NULL };
+	struct dict_avp_data proxy_info_data = { 284, 0, "Proxy-Info", AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, AVP_FLAG_MANDATORY, AVP_TYPE_GROUPED };
+	struct dict_avp_data proxy_host_data = { 280, 0, "Proxy-Host", AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, AVP_FLAG_MANDATORY, AVP_TYPE_OCTETSTRING };
+	struct dict_avp_data proxy_state_data = { 33, 0, "Proxy-State",AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, AVP_FLAG_MANDATORY, AVP_TYPE_OCTETSTRING };
+	
+	-- Create the parent AVP
+	ret = fd_dict_new ( dict, DICT_AVP, &proxy_info_data, NULL, &proxy_info_avp );
+	
+	-- Create the first child AVP.
+	ret = fd_dict_new ( dict, DICT_TYPE, &di_type_data, NULL, &diameteridentity_type );
+	ret = fd_dict_new ( dict, DICT_AVP, &proxy_host_data, diameteridentity_type, &proxy_host_avp );
+	
+	-- Create the other child AVP
+	ret = fd_dict_new ( dict, DICT_AVP, &proxy_state_data, NULL, &proxy_state_avp );
+	
+	-- Now we can create the rules. Both children AVP are mandatory.
+	rule_data.rule_position = RULE_REQUIRED;
+	rule_data.rule_min = -1;
+	rule_data.rule_max = -1;
+	
+	rule_data.rule_avp = proxy_host_avp;
+	ret = fd_dict_new ( dict, DICT_RULE, &rule_data, proxy_info_avp, NULL );
+	
+	rule_data.rule_avp = proxy_state_avp;
+	ret = fd_dict_new ( dict, DICT_RULE, &rule_data, proxy_info_avp, NULL );
+}
+
+- fd_dict_search and fd_dict_getval are similar to previous examples.
+
+*/
+		
+/* Define some hard-coded values */
+/* Application */
+#define AI_RELAY			0xffffffff
+
+/* Commands Codes */
+#define CC_CAPABILITIES_EXCHANGE	257
+#define CC_RE_AUTH			258
+#define CC_ACCOUNTING			271
+#define CC_ABORT_SESSION		274
+#define CC_SESSION_TERMINATION		275
+#define CC_DEVICE_WATCHDOG		280
+#define CC_DISCONNECT_PEER		282
+
+/* AVPs (Vendor 0) */
+#define AC_USER_NAME			1
+#define AC_PROXY_STATE			33
+#define AC_HOST_IP_ADDRESS		257
+#define AC_AUTH_APPLICATION_ID		258
+#define AC_ACCT_APPLICATION_ID		259
+#define AC_VENDOR_SPECIFIC_APPLICATION_ID 260
+#define AC_REDIRECT_HOST_USAGE		261
+#define AC_REDIRECT_MAX_CACHE_TIME	262
+#define AC_SESSION_ID 			263
+#define AC_ORIGIN_HOST			264
+#define AC_SUPPORTED_VENDOR_ID		265
+#define AC_VENDOR_ID			266
+#define AC_FIRMWARE_REVISION		267
+#define AC_RESULT_CODE			268
+#define AC_PRODUCT_NAME			269
+#define AC_DISCONNECT_CAUSE		273
+#define ACV_DC_REBOOTING			0
+#define ACV_DC_BUSY				1
+#define ACV_DC_NOT_FRIEND			2
+#define AC_ORIGIN_STATE_ID		278
+#define AC_FAILED_AVP			279
+#define AC_PROXY_HOST			280
+#define AC_ERROR_MESSAGE		281
+#define AC_ROUTE_RECORD			282
+#define AC_DESTINATION_REALM		283
+#define AC_PROXY_INFO			284
+#define AC_REDIRECT_HOST		292
+#define AC_DESTINATION_HOST		293
+#define AC_ERROR_REPORTING_HOST		294
+#define AC_ORIGIN_REALM			296
+#define AC_INBAND_SECURITY_ID		299
+#define ACV_ISI_NO_INBAND_SECURITY		0
+#define ACV_ISI_TLS				1
+
+/* Error codes */
+#define ER_DIAMETER_SUCCESS			2001
+#define ER_DIAMETER_REALM_NOT_SERVED		3003
+#define ER_DIAMETER_TOO_BUSY			3004
+#define ER_DIAMETER_REDIRECT_INDICATION		3006
+#define ER_ELECTION_LOST			4003
+
+
+/*============================================================*/
+/*                         SESSIONS                           */
+/*============================================================*/
+
+/* Modules that want to associate a state with a Session-Id must first register a handler of this type */
+struct session_handler;
+
+/* This opaque structure represents a session associated with a Session-Id */
+struct session;
+
+/* The state information that a module associate with a session -- each module defines its own data format */
+typedef void session_state;
+
+/* The following function must be called to activate the session expiry mechanism */
+int fd_sess_start(void);
+
+/*
+ * FUNCTION:	fd_sess_handler_create
+ *
+ * PARAMETERS:
+ *  handler	: location where the new handler must be stored.
+ *  cleanup	: a callback function that must be called when the session with associated data is destroyed.
+ *  opaque      : A pointer that is passed to the cleanup callback -- the content is never examined by the framework.
+ *
+ * DESCRIPTION: 
+ *  Create a new session handler. This is needed by a module to associate a state with a session object.
+ * The cleanup handler is called when the session timeout expires, or fd_sess_destroy is called. It must free
+ * the state associated with the session, and eventually trig other actions (send a STR, ...).
+ *
+ * RETURN VALUE:
+ *  0      	: The new handler has been created.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOMEM	: Not enough memory to complete the operation
+ */
+int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, char * sid, void * opaque), void * opaque );
+/* Macro to avoid casting everywhere */
+#define fd_sess_handler_create( _handler, _cleanup, _opaque ) \
+	fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, char *, void *))(_cleanup), (void *)(_opaque) )
+
+	
+/*
+ * FUNCTION:	fd_sess_handler_destroy
+ *
+ * PARAMETERS:
+ *  handler	: location of an handler created by fd_sess_handler_create.
+ *  opaque      : the opaque pointer registered with the callback is restored here (if ! NULL).
+ *
+ * DESCRIPTION: 
+ *  This destroys a session handler (typically called when an application is shutting down).
+ * If sessions states are registered with this handler, the cleanup callback is called on them.
+ *
+ * RETURN VALUE:
+ *  0      	: The handler was destroyed.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOMEM	: Not enough memory to complete the operation
+ */
+int fd_sess_handler_destroy ( struct session_handler ** handler, void **opaque );
+
+
+
+/*
+ * FUNCTION:	fd_sess_new
+ *
+ * PARAMETERS:
+ *  session	  : The location where the session object will be created upon success.
+ *  diamId	  : \0-terminated string containing a Diameter Identity.
+ *  opt           : Additional string. Usage is described bellow.
+ *  optlen	  : if opt is \0-terminated, this can be 0. Otherwise, the length of opt.
+ *
+ * DESCRIPTION: 
+ *   Create a new session object. The Session-Id string associated with this session is generated as follow:
+ *  If diamId parameter is provided, the string is created according to the RFC: <diamId>;<high32>;<low32>[;opt] where
+ *    diamId is a Diameter Identity.
+ *    high32 and low32 are the parts of a monotonic 64 bits counter initialized to (time, 0) at startup.
+ *    opt is an optional string that can be concatenated to the identifier.
+ *  If diamId is NULL, the string is exactly the content of opt.
+ *
+ * RETURN VALUE:
+ *  0      	: The session is created.
+ *  EINVAL 	: A parameter is invalid.
+ *  EALREADY	: A session with the same name already exists (returned in *session)
+ *  ENOMEM	: Not enough memory to complete the operation
+ */
+int fd_sess_new ( struct session ** session, char * diamId, char * opt, size_t optlen );
+
+/*
+ * FUNCTION:	fd_sess_fromsid
+ *
+ * PARAMETERS:
+ *  sid	  	: pointer to a string containing a Session-Id (UTF-8).
+ *  len		: length of the sid string (which does not need to be '\0'-terminated)
+ *  session	: On success, pointer to the session object created / retrieved.
+ *  isnew	: if not NULL, set to 1 on return if the session object has been created, 0 if it was simply retrieved.
+ *
+ * DESCRIPTION: 
+ *   Retrieve a session object from a Session-Id string. In case no session object was previously existing with this 
+ *  id, a new object is silently created (equivalent to fd_sess_new with flag SESSION_NEW_FULL).
+ *
+ * RETURN VALUE:
+ *  0      	: The session parameter has been updated.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOMEM	: Not enough memory to complete the operation
+ */
+int fd_sess_fromsid ( char * sid, size_t len, struct session ** session, int * isnew);
+
+/*
+ * FUNCTION:	fd_sess_getsid
+ *
+ * PARAMETERS:
+ *  session	: Pointer to a session object.
+ *  sid	  	: On success, the location of a (\0-terminated) string is stored here.
+ *
+ * DESCRIPTION: 
+ *   Retrieve the session identifier (Session-Id) corresponding to a session object.
+ *  The returned sid is an UTF-8 string terminated by \0, suitable for calls to strlen and strcpy.
+ *  It may be used for example to set the value of an AVP.
+ *  Note that the sid string is not copied, just its reference... do not free it!
+ *
+ * RETURN VALUE:
+ *  0      	: The sid parameter has been updated.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_sess_getsid ( struct session * session, char ** sid );
+
+/*
+ * FUNCTION:	fd_sess_settimeout
+ *
+ * PARAMETERS:
+ *  session	: The session for which to set the timeout.
+ *  timeout	: The date when the session times out.
+ *
+ * DESCRIPTION: 
+ *   Set the lifetime for a given session object. This function may be 
+ * called several times on the same object to update the timeout value.
+ *   When the timeout date is reached, the cleanup handler of each 
+ * module that registered data with this session is called, then the 
+ * session is cleared.
+ *
+ *   There is a possible race condition between cleanup of the session
+ * and use of its data; applications should ensure that they are not 
+ * using data from a session that is about to expire / expired.
+ *
+ * RETURN VALUE:
+ *  0      	: The session timeout has been updated.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_sess_settimeout( struct session * session, const struct timespec * timeout );
+
+/*
+ * FUNCTION:	fd_sess_destroy
+ *
+ * PARAMETERS:
+ *  session	: Pointer to a session object.
+ *
+ * DESCRIPTION: 
+ *   Destroys a session an all associated data, if any.
+ * Equivalent to a session timeout expired, but the effect is immediate.
+ *
+ * RETURN VALUE:
+ *  0      	: The session no longer exists.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_sess_destroy ( struct session ** session );
+
+/*
+ * FUNCTION:	fd_sess_reclaim
+ *
+ * PARAMETERS:
+ *  session	: Pointer to a session object.
+ *
+ * DESCRIPTION: 
+ *   Destroys the resources of a session, only if no session_state is associated with it.
+ *
+ * RETURN VALUE:
+ *  0      	: The session no longer exists.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_sess_reclaim ( struct session ** session );
+
+
+
+
+/*
+ * FUNCTION:	fd_sess_state_store
+ *
+ * PARAMETERS:
+ *  handler	: The handler with which the state is registered.
+ *  session	: The session object with which the state is registered.
+ *  state	: An application state (opaque data) to store with the session.
+ *
+ * DESCRIPTION: 
+ *  Stores an application state with a session. This state can later be retrieved
+ * with fd_sess_state_retrieve, or implicitly in the cleanup handler when the session
+ * is destroyed.
+ *
+ * RETURN VALUE:
+ *  0      	: The state has been stored.
+ *  EINVAL 	: A parameter is invalid.
+ *  EALREADY	: Data was already associated with this session and client.
+ *  ENOMEM	: Not enough memory to complete the operation
+ */
+int fd_sess_state_store_internal ( struct session_handler * handler, struct session * session, session_state ** state );
+#define fd_sess_state_store( _handler, _session, _state ) \
+	fd_sess_state_store_internal( (_handler), (_session), (void *)(_state) )
+
+/*
+ * FUNCTION:	fd_sess_state_retrieve
+ *
+ * PARAMETERS:
+ *  handler	: The handler with which the state was registered.
+ *  session	: The session object with which the state was registered.
+ *  state	: Location where the state must be saved if it is found.
+ *
+ * DESCRIPTION: 
+ *  Retrieves a state saved by fd_sess_state_store.
+ * After this function has been called, the state is no longer associated with 
+ * the session. A new call to fd_sess_state_store must be performed in order to
+ * store again the data with the session.
+ *
+ * RETURN VALUE:
+ *  0      	: *state is updated (NULL or points to the state if it was found).
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_sess_state_retrieve_internal ( struct session_handler * handler, struct session * session, session_state ** state ); 
+#define fd_sess_state_retrieve( _handler, _session, _state ) \
+	fd_sess_state_retrieve_internal( (_handler), (_session), (void *)(_state) )
+
+
+/* For debug */
+void fd_sess_dump(int level, struct session * session);
+void fd_sess_dump_hdl(int level, struct session_handler * handler);
+
+/*============================================================*/
+/*                         ROUTING                            */
+/*============================================================*/
+
+/* The following functions are helpers for the routing module. 
+  The routing data is stored in the message itself. */
+
+/* Structure that contains the routing data for a message */
+struct rt_data;
+
+/* Following functions are helpers to create the routing data of a message */
+int  fd_rtd_init(struct rt_data ** rtd);
+void fd_rtd_free(struct rt_data ** rtd);
+
+/* Add a peer to the candidates list */
+int  fd_rtd_candidate_add(struct rt_data * rtd, char * peerid, char * realm);
+
+/* Remove a peer from the candidates (if it is found) */
+void fd_rtd_candidate_del(struct rt_data * rtd, char * peerid, size_t sz /* if !0, peerid does not need to be \0 terminated */);
+
+/* Extract the list of valid candidates, and initialize their scores to 0 */
+void fd_rtd_candidate_extract(struct rt_data * rtd, struct fd_list ** candidates, int ini_score);
+
+/* If a peer returned a protocol error for this message, save it so that we don't try to send it there again */
+int  fd_rtd_error_add(struct rt_data * rtd, char * sentto, uint8_t * origin, size_t originsz, uint32_t rcode);
+
+/* The extracted list items have the following structure: */
+struct rtd_candidate {
+	struct fd_list	chain;	/* link in the list returned by the previous fct */
+	char *		diamid;	/* the diameter Id of the peer */
+	char *		realm;	/* the diameter realm of the peer (if known) */
+	int		score;	/* the current routing score for this peer, see fd_rt_out_register definition for details */
+};
+
+/* Reorder the list of peers */
+int  fd_rtd_candidate_reorder(struct fd_list * candidates);
+
+/* Note : it is fine for a callback to add a new entry in the candidates list after the list has been extracted. The diamid must then be malloc'd. */
+/* Beware that this could lead to routing loops */
+
+/*============================================================*/
+/*                         MESSAGES                           */
+/*============================================================*/
+
+/* The following types are opaque */
+struct	msg;	/* A message: command with children AVPs (possibly grand children) */
+struct	avp;	/* AVP object */
+
+/* Some details about chaining:
+ *
+ *  A message is made of a header ( msg ) and 0 or more AVPs ( avp ).
+ * The structure is a kind of tree, where some AVPs (grouped AVPs) can contain other AVPs.
+ * Exemple:
+ * msg
+ *  |-avp
+ *  |-gavp
+ *  |   |-avp
+ *  |   |-avp
+ *  |   \-avp
+ *  |-avp
+ *  \-avp
+ *
+ */
+
+/* The following type is used to point to either a msg or an AVP */
+typedef void msg_or_avp;
+
+/* The Diameter protocol version */
+#define DIAMETER_VERSION	1
+
+/* In the two following types, some fields are marked (READONLY). 
+ * This means that the content of these fields will be overwritten by the daemon so modifying it is useless.
+ */
+
+/* The following structure represents the header of a message. All data is in host byte order. */
+struct msg_hdr {
+	uint8_t		 msg_version;		/* (READONLY) Version of Diameter: must be DIAMETER_VERSION. */
+	uint32_t	 msg_length;		/* (READONLY)(3 bytes) indicates the length of the message */
+	uint8_t		 msg_flags;		/* Message flags: CMD_FLAG_* */
+	command_code_t	 msg_code;		/* (3 bytes) the command-code. See dictionary-api.h for more detail */
+	application_id_t msg_appl;		/* The application issuing this message */
+	uint32_t	 msg_hbhid;		/* The Hop-by-Hop identifier of the message */
+	uint32_t	 msg_eteid;		/* The End-to-End identifier of the message */
+};
+
+/* The following structure represents the visible content of an AVP. All data is in host byte order. */
+struct avp_hdr {
+	avp_code_t	 avp_code;		/* the AVP Code */
+	uint8_t		 avp_flags;		/* AVP_FLAG_* flags */
+	uint32_t	 avp_len;		/* (READONLY)(Only 3 bytes are used) the length of the AVP as described in the RFC */
+	vendor_id_t	 avp_vendor;		/* Only used if AVP_FLAG_VENDOR is present */
+	union avp_value *avp_value;		/* pointer to the value of the AVP. NULL means that the value is not set / not understood.
+						   One should not directly change this value. Use the msg_avp_setvalue function instead.
+						   The content of the pointed structure can be changed directly, with this restriction:
+						     if the AVP is an OctetString, and you change the value of the pointer avp_value->os.data, then
+						     you must call free() on the previous value, and the new one must be free()-able.
+						 */
+};
+
+/* The following enum is used to browse inside message hierarchy (msg, gavp, avp) */
+enum msg_brw_dir {
+	MSG_BRW_NEXT = 1,	/* Get the next element at the same level, or NULL if this is the last element. */
+	MSG_BRW_PREV,		/* Get the previous element at the same level, or NULL if this is the first element. */
+	MSG_BRW_FIRST_CHILD,	/* Get the first child AVP of this element, if any. */
+	MSG_BRW_LAST_CHILD,	/* Get the last child AVP of this element, if any. */
+	MSG_BRW_PARENT,		/* Get the parent element of this element, if any. Only the msg_t object has no parent. */
+	MSG_BRW_WALK		/* This is equivalent to FIRST_CHILD or NEXT or PARENT->next, first that is not NULL. Use this to walk inside all AVPs. */
+};
+
+/* Some flags used in the functions bellow */
+#define AVPFL_SET_BLANK_VALUE	0x01	/* When creating an AVP, initialize its value to a blank area */
+#define AVPFL_MAX		AVPFL_SET_BLANK_VALUE	/* The biggest valid flag value */
+	
+#define MSGFL_ALLOC_ETEID	0x01	/* When creating a message, a new end-to-end ID is allocated and set in the message */
+#define MSGFL_ANSW_ERROR	0x02	/* When creating an answer message, set the 'E' bit and use the generic error ABNF instead of command-specific ABNF */
+#define MSGFL_ANSW_NOSID	0x04	/* When creating an answer message, do not add the Session-Id even if present in request */
+#define MSGFL_MAX		MSGFL_ANSW_NOSID	/* The biggest valid flag value */
+
+/**************************************************/
+/*   Message creation, manipulation, disposal     */
+/**************************************************/
+/*
+ * FUNCTION:	fd_msg_avp_new
+ *
+ * PARAMETERS:
+ *  model 	: Pointer to a DICT_AVP dictionary object describing the avp to create, or NULL.
+ *  flags	: Flags to use in creation (AVPFL_*).
+ *  avp 	: Upon success, pointer to the new avp is stored here.
+ *
+ * DESCRIPTION: 
+ *   Create a new AVP instance.
+ *
+ * RETURN VALUE:
+ *  0      	: The AVP is created.
+ *  EINVAL 	: A parameter is invalid.
+ *  (other standard errors may be returned, too, with their standard meaning. Example:
+ *    ENOMEM 	: Memory allocation for the new avp failed.)
+ */
+int fd_msg_avp_new ( struct dict_object * model, int flags, struct avp ** avp );
+
+/*
+ * FUNCTION:	fd_msg_new
+ *
+ * PARAMETERS:
+ *  model 	: Pointer to a DICT_COMMAND dictionary object describing the message to create, or NULL.
+ *  flags	: combination of MSGFL_* flags.
+ *  msg 	: Upon success, pointer to the new message is stored here.
+ *
+ * DESCRIPTION: 
+ *   Create a new empty Diameter message. 
+ *
+ * RETURN VALUE:
+ *  0      	: The message is created.
+ *  EINVAL 	: A parameter is invalid.
+ *  (other standard errors may be returned, too, with their standard meaning. Example:
+ *    ENOMEM 	: Memory allocation for the new message failed.)
+ */
+int fd_msg_new ( struct dict_object * model, int flags, struct msg ** msg );
+
+/*
+ * FUNCTION:	msg_new_answer_from_req
+ *
+ * PARAMETERS:
+ *  dict	: Pointer to the dictionary containing the model of the query.
+ *  msg		: The location of the query on function call. Updated by the location of answer message on return.
+ *  flag        : Pass MSGFL_ANSW_ERROR to indicate if the answer is an error message (will set the 'E' bit)
+ *
+ * DESCRIPTION: 
+ *   This function creates the empty answer message corresponding to a request.
+ *  The header is set properly (R flag, ccode, appid, hbhid, eteid)
+ *  The Session-Id AVP is copied if present.
+ *  The calling code should usually call fd_msg_rescode_set function on the answer.
+ *  Upon return, the original query may be retrieved by calling fd_msg_answ_getq on the message.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0      	: an error occurred.
+ */
+int fd_msg_new_answer_from_req ( struct dictionary * dict, struct msg ** msg, int flag );
+
+/*
+ * FUNCTION:	fd_msg_browse
+ *
+ * PARAMETERS:
+ *  reference 	: Pointer to a struct msg or struct avp.
+ *  dir         : Direction for browsing
+ *  found       : If not NULL, updated with the element that has been found, if any, or NULL if no element was found / an error occurred.
+ *  depth	: If not NULL, points to an integer representing the "depth" of this object in the tree. This is a relative value, updated on return.
+ *
+ * DESCRIPTION: 
+ *   Explore the content of a message object (hierarchy). If "found" is null, only error checking is performed.
+ *  If "depth" is provided, it is updated as follow on successful function return:
+ *   - not modified for MSG_BRW_NEXT and MSG_BRW_PREV.
+ *   - *depth = *depth + 1 for MSG_BRW_FIRST_CHILD and MSG_BRW_LAST_CHILD.
+ *   - *depth = *depth - 1 for MSG_BRW_PARENT.
+ *   - *depth = *depth + X for MSG_BRW_WALK, with X between 1 (returned the 1st child) and -N (returned the Nth parent's next).
+ *
+ * RETURN VALUE:
+ *  0      	: found has been updated (if non NULL).
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOENT	: No element has been found where requested, and "found" was NULL (otherwise, *found is set to NULL and 0 is returned). 
+ */
+int fd_msg_browse_internal ( msg_or_avp * reference, enum msg_brw_dir dir, msg_or_avp ** found, int * depth );
+/* Macro to avoid having to cast the third parameter everywhere */
+#define fd_msg_browse( ref, dir, found, depth )	\
+	fd_msg_browse_internal( (ref), (dir), (void *)(found), (depth) )
+
+
+/*
+ * FUNCTION:	fd_msg_avp_add
+ *
+ * PARAMETERS:
+ *  reference 	: Pointer to a valid msg or avp.
+ *  dir         : location where the new AVP should be inserted, relative to the reference. MSG_BRW_PARENT and MSG_BRW_WALK are not valid.
+ *  avp         : pointer to the AVP object that must be inserted.
+ *
+ * DESCRIPTION: 
+ *   Adds an AVP into an object that can contain it: grouped AVP or message.
+ * Note that the added AVP will be freed at the same time as the object it is added to, 
+ * so it should not be freed after the call to this function.
+ *
+ * RETURN VALUE:
+ *  0      	: The AVP has been added.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_avp_add ( msg_or_avp * reference, enum msg_brw_dir dir, struct avp *avp);
+
+/*
+ * FUNCTION:	fd_msg_search_avp
+ *
+ * PARAMETERS:
+ *  msg 	: The message structure in which to search the AVP.
+ *  what 	: The dictionary model of the AVP to search.
+ *  avp		: location where the AVP reference is stored if found.
+ *
+ * DESCRIPTION: 
+ *   Search the first top-level AVP of a given model inside a message.
+ * Note: only the first instance of the AVP is returned by this function.
+ * Note: only top-level AVPs are searched, not inside grouped AVPs.
+ * Use msg_browse if you need more advanced research features.
+ *
+ * RETURN VALUE:
+ *  0      	: The AVP has been found.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOENT	: No AVP has been found, and "avp" was NULL (otherwise, *avp is set to NULL and 0 returned).
+ */
+int fd_msg_search_avp ( struct msg * msg, struct dict_object * what, struct avp ** avp );
+
+/*
+ * FUNCTION:	fd_msg_free
+ *
+ * PARAMETERS:
+ *  object      : pointer to the message or AVP object that must be unlinked and freed.
+ *
+ * DESCRIPTION: 
+ *   Unlink and free a message or AVP object and its children.
+ *  If the object is an AVP linked into a message, the AVP is removed before being freed.
+ *
+ * RETURN VALUE:
+ *  0      	: The message has been freed.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_free ( msg_or_avp * object );
+
+/***************************************/
+/*   Dump functions                    */
+/***************************************/
+/*
+ * FUNCTION:	fd_msg_dump_*
+ *
+ * PARAMETERS:
+ *  level	: the log level (INFO, FULL, ...) at which the object is dumped
+ *  obj		: A msg or avp object.
+ *
+ * DESCRIPTION: 
+ *   These functions dump the content of a message to the debug log
+ * either recursively or only the object itself.
+ *
+ * RETURN VALUE:
+ *   -
+ */
+void fd_msg_dump_walk ( int level, msg_or_avp *obj );
+void fd_msg_dump_one  ( int level, msg_or_avp *obj );
+
+
+/*********************************************/
+/*   Message metadata management functions   */
+/*********************************************/
+/*
+ * FUNCTION:	fd_msg_model
+ *
+ * PARAMETERS:
+ *  reference 	: Pointer to a valid msg or avp.
+ *  model       : on success, pointer to the dictionary model of this command or AVP. NULL if the model is unknown.
+ *
+ * DESCRIPTION: 
+ *   Retrieve the dictionary object describing this message or avp. If the object is unknown or the fd_msg_parse_dict has not been called,
+ *  *model is set to NULL.
+ *
+ * RETURN VALUE:
+ *  0      	: The model has been set.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_model ( msg_or_avp * reference, struct dict_object ** model );
+
+/*
+ * FUNCTION:	fd_msg_hdr
+ *
+ * PARAMETERS:
+ *  msg 	: Pointer to a valid message object.
+ *  pdata 	: Upon success, pointer to the msg_hdr structure of this message. The fields may be modified.
+ *
+ * DESCRIPTION: 
+ *   Retrieve location of modifiable section of a message. 
+ *
+ * RETURN VALUE:
+ *  0      	: The location has been written.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_hdr ( struct msg *msg, struct msg_hdr ** pdata );
+
+/*
+ * FUNCTION:	fd_msg_avp_hdr
+ *
+ * PARAMETERS:
+ *  avp 	: Pointer to a valid avp object.
+ *  pdata 	: Upon success, pointer to the avp_hdr structure of this avp. The fields may be modified.
+ *
+ * DESCRIPTION: 
+ *   Retrieve location of modifiable data of an avp. 
+ *
+ * RETURN VALUE:
+ *  0      	: The location has been written.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_avp_hdr ( struct avp *avp, struct avp_hdr ** pdata );
+
+/*
+ * FUNCTION:	fd_msg_answ_associate, fd_msg_answ_getq, fd_msg_answ_detach
+ *
+ * PARAMETERS:
+ *  answer	: the received answer message
+ *  query	: the corresponding query that had been sent
+ *
+ * DESCRIPTION:
+ *  fd_msg_answ_associate associates a query msg with the received answer. 
+ * Query is retrieved with fd_msg_answ_getq.
+ * If answer message is freed, the query is also freed.
+ * If the msg_answ_detach function is called, the association is removed.
+ * This is meant to be called from the daemon only.
+ *
+ * RETURN VALUE:
+ *  0 	  : ok
+ *  EINVAL: a parameter is invalid
+ */
+int fd_msg_answ_associate( struct msg * answer, struct msg * query );
+int fd_msg_answ_getq     ( struct msg * answer, struct msg ** query );
+int fd_msg_answ_detach   ( struct msg * answer );
+
+/*
+ * FUNCTION:	fd_msg_anscb_associate, fd_msg_anscb_get
+ *
+ * PARAMETERS:
+ *  msg		: the answer message
+ *  anscb	: the callback to associate with the message
+ *  data	: the data to pass to the callback
+ *  timeout     : (optional, use NULL if no timeout) a timeout associated with calling the cb.
+ *
+ * DESCRIPTION:
+ *  Associate or retrieve a callback with an answer message.
+ * This is meant to be called from the daemon only.
+ *
+ * RETURN VALUE:
+ *  0 	  : ok
+ *  EINVAL: a parameter is invalid
+ */
+int fd_msg_anscb_associate( struct msg * msg, void ( *anscb)(void *, struct msg **), void  * data, const struct timespec *timeout );
+int fd_msg_anscb_get      ( struct msg * msg, void (**anscb)(void *, struct msg **), void ** data );
+struct timespec *fd_msg_anscb_gettimeout( struct msg * msg ); /* returns NULL or a valid non-0 timespec */
+
+/*
+ * FUNCTION:	fd_msg_rt_associate, fd_msg_rt_get
+ *
+ * PARAMETERS:
+ *  msg		: the query message to be sent
+ *  list	: the ordered list of possible next-peers
+ *
+ * DESCRIPTION:
+ *  Associate a routing list with a query, and retrieve it.
+ * If the message is freed, the list is also freed.
+ *
+ * RETURN VALUE:
+ *  0 	  : ok
+ *  EINVAL: a parameter is invalid
+ */
+int fd_msg_rt_associate( struct msg * msg, struct rt_data ** rtd );
+int fd_msg_rt_get      ( struct msg * msg, struct rt_data ** rtd );
+
+/*
+ * FUNCTION:	fd_msg_is_routable
+ *
+ * PARAMETERS:
+ *  msg		: A msg object.
+ *
+ * DESCRIPTION: 
+ *   This function returns a boolean telling if a given message is routable in the Diameter network, 
+ *  or if it is a local link message only (ex: CER/CEA, DWR/DWA, ...).
+ *
+ * RETURN VALUE:
+ *  0      	: The message is not routable / an error occurred.
+ *  1      	: The message is routable.
+ */
+int fd_msg_is_routable ( struct msg * msg );
+
+/*
+ * FUNCTION:	fd_msg_source_(g/s)et
+ *
+ * PARAMETERS:
+ *  msg		: A msg object.
+ *  diamid	: The diameter id of the peer from which this message was received.
+ *  add_rr	: if true, a Route-Record AVP is added to the message with content diamid. In that case, dict must be supplied.
+ *  dict	: a dictionary with definition of Route-Record AVP (if add_rr is true)
+ *
+ * DESCRIPTION: 
+ *   Store or retrieve the diameted id of the peer from which this message was received.
+ * Will be used for example by the routing module to add the Route-Record AVP in forwarded requests,
+ * or to direct answers to the appropriate peer.
+ *
+ * RETURN VALUE:
+ *  0      	: Operation complete.
+ *  !0      	: an error occurred.
+ */
+int fd_msg_source_set( struct msg * msg, char * diamid, int add_rr, struct dictionary * dict );
+int fd_msg_source_get( struct msg * msg, char ** diamid );
+
+/*
+ * FUNCTION:	fd_msg_eteid_get
+ *
+ * PARAMETERS:
+ *  -
+ *
+ * DESCRIPTION: 
+ *   Get a new unique end-to-end id value for the local peer.
+ *
+ * RETURN VALUE:
+ *  The new assigned value. No error code is defined.
+ */
+uint32_t fd_msg_eteid_get ( void );
+
+
+/*
+ * FUNCTION:	fd_msg_sess_get
+ *
+ * PARAMETERS:
+ *  dict	: the dictionary that contains the Session-Id AVP definition
+ *  msg		: A valid message.
+ *  session	: Location to store the session pointer when retrieved.
+ *  isnew	: Indicates if the session has been created.
+ *
+ * DESCRIPTION:
+ *  This function retrieves or creates the session object corresponding to a message.
+ * If the message does not contain a Session-Id AVP, *session == NULL on return.
+ * Note that the Session-Id AVP must never be modified after created in a message.
+ *
+ * RETURN VALUE:
+ *  0 : success
+ * !0 : standard error code.
+ */
+int fd_msg_sess_get(struct dictionary * dict, struct msg * msg, struct session ** session, int * isnew);
+
+/***************************************/
+/*   Manage AVP values                 */
+/***************************************/
+
+/*
+ * FUNCTION:	fd_msg_avp_setvalue
+ *
+ * PARAMETERS:
+ *  avp 	: Pointer to a valid avp object with a NULL avp_value pointer. The model must be known.
+ *  value 	: pointer to an avp_value. The content will be COPIED into the internal storage area. 
+ *		 If data type is an octetstring, the data is also copied.
+ * 		 If value is a NULL pointer, the previous data is erased and value is unset in the AVP.
+ *
+ * DESCRIPTION: 
+ *   Initialize the avp_value field of an AVP header.
+ *
+ * RETURN VALUE:
+ *  0      	: The avp_value pointer has been set.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_avp_setvalue ( struct avp *avp, union avp_value *value );
+
+/*
+ * FUNCTION:	fd_msg_avp_value_encode
+ *
+ * PARAMETERS:
+ *  avp 	: Pointer to a valid avp object with a NULL avp_value. The model must be known.
+ *  data 	: Pointer to the data that must be encoded as AVP value and stored in the AVP.
+ *		 This is only valid for AVPs of derived type for which type_data_encode callback is set. (ex: Address type)
+ *
+ * DESCRIPTION: 
+ *   Initialize the avp_value field of an AVP object from formatted data, using the AVP's type "type_data_encode" callback.
+ *
+ * RETURN VALUE:
+ *  0      	: The avp_value has been set.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOTSUP 	: There is no appropriate callback registered with this AVP's type.
+ */
+int fd_msg_avp_value_encode ( void *data, struct avp *avp );
+/*
+ * FUNCTION:	fd_msg_avp_value_interpret
+ *
+ * PARAMETERS:
+ *  avp 	: Pointer to a valid avp object with a non-NULL avp_value value.
+ *  data 	: Upon success, formatted interpretation of the AVP value is stored here.
+ *
+ * DESCRIPTION: 
+ *   Interpret the content of an AVP of Derived type and store the result in data pointer. The structure
+ * of the data pointer is dependent on the AVP type. This function calls the "type_data_interpret" callback 
+ * of the type.
+ *
+ * RETURN VALUE:
+ *  0      	: The avp_value has been set.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOTSUP 	: There is no appropriate callback registered with this AVP's type.
+ */
+int fd_msg_avp_value_interpret ( struct avp *avp, void *data );
+
+
+/***************************************/
+/*   Message parsing functions         */
+/***************************************/
+
+/*
+ * FUNCTION:	fd_msg_bufferize
+ *
+ * PARAMETERS:
+ *  msg		: A valid msg object. All AVPs must have a value set. 
+ *  buffer 	: Upon success, this points to a buffer (malloc'd) containing the message ready for network transmission (or security transformations). 
+ *		 The buffer may be freed after use.
+ *  len		: if not NULL, the size of the buffer is written here. In any case, this size is updated in the msg header.
+ *
+ * DESCRIPTION: 
+ *   Renders a message in memory as a buffer that can be sent over the network to the next peer.
+ *
+ * RETURN VALUE:
+ *  0      	: The location has been written.
+ *  EINVAL 	: The buffer does not contain a valid Diameter message.
+ *  ENOMEM	: Unable to allocate enough memory to create the buffer object.
+ */
+int fd_msg_bufferize ( struct msg * msg, unsigned char ** buffer, size_t * len );
+
+/*
+ * FUNCTION:	fd_msg_parse_buffer
+ *
+ * PARAMETERS:
+ *  buffer 	: Pointer to a buffer containing a message received from the network. 
+ *  buflen	: the size in bytes of the buffer.
+ *  msg		: Upon success, this points to a valid msg object. No AVP value is resolved in this object, nor grouped AVP.
+ *
+ * DESCRIPTION: 
+ *   This function parses a buffer an creates a msg object to represent the structure of the message.
+ *  Since no dictionary lookup is performed, the values of the AVPs are not interpreted. To interpret the values,
+ *  the returned message object must be passed to fd_msg_parse_dict function.
+ *  The buffer pointer is saved inside the message and will be freed when not needed anymore.
+ *
+ * RETURN VALUE:
+ *  0      	: The location has been written.
+ *  ENOMEM	: Unable to allocate enough memory to create the msg object.
+ *  EBADMSG	: The buffer does not contain a valid Diameter message (or is truncated).
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_parse_buffer ( unsigned char ** buffer, size_t buflen, struct msg ** msg );
+
+/* Parsing Error Information structure */
+struct fd_pei {
+	char *		pei_errcode;	/* name of the error code to use */
+	struct avp *	pei_avp;	/* pointer to invalid or missing AVP (to be freed) */
+	char *		pei_message;	/* Overwrite default message if needed */
+	int		pei_protoerr; 	/* do we set the 'E' bit in the error message ? */
+};
+
+/*
+ * FUNCTION:	fd_msg_parse_dict
+ *
+ * PARAMETERS:
+ *  object	: A msg or AVP object as returned by fd_msg_parse_buffer.
+ *  dict	: the dictionary containing the objects definitions to use for resolving all AVPs.
+ *  error_info	: If not NULL, will contain the detail about error upon return. May be used to generate an error reply.
+ *
+ * DESCRIPTION: 
+ *   This function looks up for the command and each children AVP definitions in the dictionary.
+ *  If the dictionary definition is found, avp_model is set and the value of the AVP is interpreted accordingly and:
+ *   - for grouped AVPs, the children AVP are created and interpreted also.
+ *   - for numerical AVPs, the value is converted to host byte order and saved in the avp_value field.
+ *   - for octetstring AVPs, the string is copied into a new buffer and its address is saved in avp_value. 
+ *  If the dictionary definition is not found, avp_model is set to NULL and
+ *  the content of the AVP is saved as an octetstring in an internal structure. avp_value is NULL.
+ *  As a result, after this function has been called, there is no more dependency of the msg object to the message buffer, that is freed.
+ *
+ * RETURN VALUE:
+ *  0      	: The message has been fully parsed as described.
+ *  EINVAL 	: The msg parameter is invalid for this operation.
+ *  ENOMEM	: Unable to allocate enough memory to complete the operation.
+ *  ENOTSUP	: No dictionary definition for the command or one of the mandatory AVP was found.
+ */
+int fd_msg_parse_dict ( msg_or_avp * object, struct dictionary * dict, struct fd_pei * error_info );
+
+/*
+ * FUNCTION:	fd_msg_parse_rules
+ *
+ * PARAMETERS:
+ *  object	: A msg or grouped avp object that must be verified.
+ *  dict	: The dictionary containing the rules definitions.
+ *  error_info	: If not NULL, the first problem information will be saved here.
+ *
+ * DESCRIPTION: 
+ *   Check that the children of the object do not conflict with the dictionary rules (ABNF compliance).
+ *
+ * RETURN VALUE:
+ *  0      	: The message has been fully parsed and complies to the defined rules.
+ *  EBADMSG	: A conflict was detected, or a mandatory AVP is unknown in the dictionary.
+ *  EINVAL 	: The msg or avp object is invalid for this operation.
+ *  ENOMEM	: Unable to allocate enough memory to complete the operation.
+ */
+int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct fd_pei * error_info);
+
+
+
+/*
+ * FUNCTION:	fd_msg_update_length
+ *
+ * PARAMETERS:
+ *  object 	: Pointer to a valid msg or avp. 
+ *
+ * DESCRIPTION: 
+ *   Update the length field of the object passed as parameter.
+ * As a side effect, all children objects are also updated. Therefore, all avp_value fields of
+ * the children AVPs must be set, or an error will occur.
+ *
+ * RETURN VALUE:
+ *  0      	: The size has been recomputed.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_msg_update_length ( msg_or_avp * object );
+
+
+/*============================================================*/
+/*                         DISPATCH                           */
+/*============================================================*/
+
+/* Dispatch module (passing incoming messages to extensions registered callbacks)
+ * is split between the library and the daemon.
+ *
+ * The library provides the support for associating dispatch callbacks with
+ * dictionary objects.
+ *
+ * The daemon is responsible for calling the callbacks for a message when appropriate.
+ *
+ *
+ * The dispatch module has two main roles:
+ *  - help determine if a message can be handled locally (during the routing step)
+ *        This decision involves only the application-id of the message.
+ *  - pass the message to the callback(s) that will handle it (during the dispatch step)
+ *
+ * The first role is handled by the daemon.
+ *
+ * About the second, these are the possibilities for registering a dispatch callback:
+ *
+ * -> For All messages.
+ *  This callback is called for all messages that are handled locally. This should be used only
+ *  for debug purpose.
+ *
+ * -> by AVP value (constants only).
+ *  This callback will be called when a message is received and contains an AVP with a specified enumerated value.
+ *
+ * -> by AVP.
+ *  This callback will be called when the received message contains a certain AVP.
+ *
+ * -> by command-code.
+ *  This callback will be called when the message is a specific command (and 'R' flag).
+ *
+ * -> by application.
+ *  This callback will be called when the message has a specific application-id.
+ *
+ * ( by vendor: would this be useful? it may be added later)
+ */
+enum disp_how {
+	DISP_HOW_ANY = 1,		/* Any message. This should be only used for debug. */
+	DISP_HOW_APPID,			/* Any message with the specified application-id */
+	DISP_HOW_CC,			/* Messages of the specified command-code (request or answer). App id may be specified. */
+	DISP_HOW_AVP,			/* Messages containing a specific AVP. Command-code and App id may be specified. */
+	DISP_HOW_AVP_ENUMVAL		/* Messages containing a specific AVP with a specific enumerated value. Command-code and App id may be specified. */
+};
+/*
+ * Several criteria may be selected at the same time, for example command-code AND application id.
+ *
+ * If several callbacks are registered for the same object, they are called in the order they were registered.
+ * The order in which the callbacks are called is:
+ *  DISP_HOW_ANY
+ *  DISP_HOW_AVP_ENUMVAL & DISP_HOW_AVP
+ *  DISP_HOW_CC
+ *  DISP_HOW_APPID
+ */
+
+/* When a callback is registered, a "when" argument is passed in addition to the disp_how value,
+ * to specify which values the criteria must match. */
+struct disp_when {
+	struct dict_object *	app;
+	struct dict_object *	command;
+	struct dict_object *	avp;
+	struct dict_object *	value;
+};
+
+/* Note that all the dictionary objects should really belong to the same dictionary!
+ *
+ * Here is the details on this "when" argument, depending on the disp_how value.
+ *
+ * DISP_HOW_ANY.
+ *  In this case, "when" must be NULL.
+ *
+ * DISP_HOW_APPID.
+ *  Only the "app_id" field must be set, other fields are ignored. It points to a dictionary object of type DICT_APPLICATION.
+ *
+ * DISP_HOW_CC.
+ *  The "command" field must be defined and point to a dictionary object of type DICT_COMMAND.
+ *  The "app_id" may be also set. In the case it is set, it restricts the callback to be called only with this command-code and app id.
+ *  The other fields are ignored.
+ *
+ * DISP_HOW_AVP.
+ *  The "avp" field of the structure must be set and point to a dictionary object of type DICT_AVP.
+ *  The "app_id" field may be set to restrict the messages matching to a specific app id.
+ *  The "command" field may also be set to a valid DICT_COMMAND object.
+ *  The content of the "value" field is ignored.
+ *
+ * DISP_HOW_AVP_ENUMVAL.
+ *  All fields have the same constraints and meaning as in DISP_REG_AVP. In addition, the "value" field must be set
+ *  and points to a valid DICT_ENUMVAL object. 
+ *
+ * Here is a sumary of the fields: ( M : must be set; m : may be set; 0 : ignored )
+ *  field:     app_id    command     avp    value
+ * APPID :       M          0         0       0
+ * CC    :       m          M         0       0
+ * AVP   :       m          m         M       0
+ * ENUMVA:       m          m         M       M
+ */
+
+enum disp_action {
+	DISP_ACT_CONT,	/* The next handler should be called, unless *msg == NULL. */
+	DISP_ACT_SEND,	/* The updated message must be sent. No further callback is called. */
+	DISP_ACT_ERROR	/* An error must be created and sent as a reply -- not valid for callbacks, only for fd_msg_dispatch. */
+};
+/* The callbacks that are registered have the following prototype:
+ *  	int dispatch_callback( struct msg ** msg, struct avp * avp, struct session * session, enum disp_action * action );
+ *
+ * CALLBACK:	dispatch_callback
+ *
+ * PARAMETERS:
+ *  msg 	: the received message on function entry. may be updated to answer on return (see description)
+ *  avp 	: for callbacks registered with DISP_HOW_AVP or DISP_HOW_AVP_ENUMVAL, direct link to the triggering AVP.
+ *  session	: if the message contains a Session-Id AVP, the corresponding session object, NULL otherwise.
+ *  opaque      : An opaque pointer that is registered along the session handler.
+ *  action	: upon return, this tells the daemon what to do next.
+ *
+ * DESCRIPTION: 
+ *   Called when a received message matchs the condition for which the callback was registered.
+ * This callback may do any kind of processing on the message, including:
+ *  - create an answer for a request.
+ *  - proxy a request or message, add / remove the Proxy-Info AVP, then forward the message.
+ *  - update a routing table or start a connection with a new peer, then forward the message.
+ *  - ...
+ * 
+ * When *action == DISP_ACT_SEND on callback return, the msg pointed by *msg is passed to the routing module for sending.
+ * When *action == DISP_ACT_CONT, the next registered callback is called.
+ *  When the last callback gives also DISP_ACT_CONT action value, a default handler is called. It's behavior is as follow:
+ *   - if the message is an answer, it is discarded.
+ *   - if the message is a request, it is passed again to the routing stack, and marked as non-local handling.
+ *
+ * RETURN VALUE:
+ *  0      	: The callback executed successfully and updated *action appropriately.
+ *  !0		: standard errors. In case of error, the message is discarded.
+ */
+
+/* This structure represents a handler for a registered callback, allowing its de-registration */
+struct disp_hdl;
+
+/*
+ * FUNCTION:	fd_disp_register
+ *
+ * PARAMETERS:
+ *  cb 		  : The callback function to register (see dispatch_callback description above).
+ *  how	  	  : How the callback must be registered.
+ *  when          : Values that must match, depending on the how argument.
+ *  opaque        : A pointer that is passed back to the handler. The content is not interpreted by the framework.
+ *  handle        : On success, a handler to the registered callback is stored here if not NULL. 
+ *		   This handler can be used to unregister the cb.
+ *
+ * DESCRIPTION: 
+ *   Register a new callback to handle messages delivered locally.
+ *
+ * RETURN VALUE:
+ *  0      	: The callback is registered.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOMEM	: Not enough memory to complete the operation
+ */
+int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, void *, enum disp_action *), 
+			enum disp_how how, struct disp_when * when, void * opaque, struct disp_hdl ** handle );
+
+/*
+ * FUNCTION:	fd_disp_unregister
+ *
+ * PARAMETERS:
+ *  handle       : Location of the handle of the callback that must be unregistered.
+ *  opaque       : If not NULL, the opaque data that was registered is restored here.
+ *
+ * DESCRIPTION: 
+ *   Removes a callback previously registered by fd_disp_register.
+ *
+ * RETURN VALUE:
+ *  0      	: The callback is unregistered.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_disp_unregister ( struct disp_hdl ** handle, void ** opaque );
+
+/* Destroy all handlers */
+void fd_disp_unregister_all ( void );
+
+/*
+ * FUNCTION:	fd_msg_dispatch
+ *
+ * PARAMETERS:
+ *  msg 	: A msg object that have already been fd_msg_parse_dict.
+ *  session	: The session corresponding to this object, if any.
+ *  action	: Upon return, the action that must be taken on the message
+ *
+ * DESCRIPTION: 
+ *   Call all handlers registered for a given message.
+ *  The session must have already been resolved on entry.
+ *  The msg pointed may be updated during this process.
+ *  Upon return, the action parameter points to what must be done next.
+ *
+ * RETURN VALUE:
+ *  0      	: Success.
+ *  EINVAL 	: A parameter is invalid.
+ *  (other errors)
+ */
+int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, const char ** error_code );
+
+
+
+/*============================================================*/
+/*                     QUEUES                                 */
+/*============================================================*/
+
+/* Management of FIFO queues of elements */
+
+/* A queue is an opaque object */
+struct fifo;
+
+/*
+ * FUNCTION:	fd_fifo_new
+ *
+ * PARAMETERS:
+ *  queue	: Upon success, a pointer to the new queue is saved here.
+ *
+ * DESCRIPTION: 
+ *  Create a new empty queue.
+ *
+ * RETURN VALUE :
+ *  0		: The queue has been initialized successfully.
+ *  EINVAL 	: The parameter is invalid.
+ *  ENOMEM	: Not enough memory to complete the creation.  
+ */
+int fd_fifo_new ( struct fifo ** queue );
+
+/*
+ * FUNCTION:	fd_fifo_del
+ *
+ * PARAMETERS:
+ *  queue	: Pointer to an empty queue to delete.
+ *
+ * DESCRIPTION: 
+ *  Destroys a queue. This is only possible if no thread is waiting for an element,
+ * and the queue is empty.
+ *
+ * RETURN VALUE:
+ *  0		: The queue has been destroyed successfully.
+ *  EINVAL 	: The parameter is invalid.
+ */
+int fd_fifo_del ( struct fifo  ** queue );
+
+/*
+ * FUNCTION:	fd_fifo_move
+ *
+ * PARAMETERS:
+ *  oldq	: Location of a FIFO that is to be emptied.
+ *  newq	: A FIFO that will receive the old data.
+ *  loc_update	: if non NULL, a place to store the pointer to new FIFO atomically with the move.
+ *
+ * DESCRIPTION: 
+ *  Empties a queue and move its content to another one atomically.
+ *
+ * RETURN VALUE:
+ *  0		: The queue has been destroyed successfully.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_fifo_move ( struct fifo * oldq, struct fifo * newq, struct fifo ** loc_update );
+
+/*
+ * FUNCTION:	fd_fifo_length
+ *
+ * PARAMETERS:
+ *  queue	: The queue from which to retrieve the number of elements.
+ *  length	: Upon success, the current number of elements in the queue is stored here.
+ *
+ * DESCRIPTION: 
+ *  Retrieve the number of elements in a queue.
+ *
+ * RETURN VALUE:
+ *  0		: The length of the queue has been written.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_fifo_length ( struct fifo * queue, int * length );
+int fd_fifo_length_noerr ( struct fifo * queue ); /* no error checking version */
+
+/*
+ * FUNCTION:	fd_fifo_setthrhd
+ *
+ * PARAMETERS:
+ *  queue	: The queue for which the thresholds are being set.
+ *  data	: An opaque pointer that is passed to h_cb and l_cb callbacks.
+ *  high        : The high-level threshold. If the number of elements in the queue increase to this value, h_cb is called.
+ *  h_cb        : if not NULL, a callback to call when the queue lengh is bigger than "high".
+ *  low         : The low-level threshold. Must be < high.
+ *  l_cb        : If the number of elements decrease to low, this callback is called.
+ *
+ * DESCRIPTION: 
+ *  This function allows to adjust the number of producer / consumer threads of a queue.
+ * If the consumer are slower than the producers, the number of elements in the queue increase.
+ * By setting a "high" value, we allow a callback to be called when this number is too high.
+ * The typical use would be to create an additional consumer thread in this callback.
+ * If the queue continues to grow, the callback will be called again when the length is 2 * high, then 3*high, ... N * high
+ * (the callback itself should implement a limit on the number of consumers that can be created)
+ * When the queue starts to decrease, and the number of elements go under ((N - 1) * high + low, the l_cb callback is called
+ * and would typially stop one of the consumer threads. If the queue continues to reduce, l_cb is again called at (N-2)*high + low,
+ * and so on.
+ *
+ * Since there is no destructor for the data pointer, if cleanup operations are required, they should be performed in
+ * l_cb when the length of the queue is becoming < low.
+ *
+ * Note that the callbacks are called synchronously, during fd_fifo_post or fd_fifo_get. Their operation should be quick.
+ *
+ * RETURN VALUE:
+ *  0		: The thresholds have been set
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_fifo_setthrhd ( struct fifo * queue, void * data, uint16_t high, void (*h_cb)(struct fifo *, void **), uint16_t low, void (*l_cb)(struct fifo *, void **) );
+
+/*
+ * FUNCTION:	fd_fifo_post
+ *
+ * PARAMETERS:
+ *  queue	: The queue in which the element must be posted.
+ *  item	: The element that is put in the queue.
+ *
+ * DESCRIPTION: 
+ *  An element is added in a queue. Elements are retrieved from the queue in FIFO order
+ *  with the fd_fifo_get, fd_fifo_tryget, or fd_fifo_timedget functions.
+ *
+ * RETURN VALUE:
+ *  0		: The element is queued.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOMEM 	: Not enough memory to complete the operation.
+ */
+int fd_fifo_post_int ( struct fifo * queue, void ** item );
+#define fd_fifo_post(queue, item) \
+	fd_fifo_post_int((queue), (void *)(item))
+
+/*
+ * FUNCTION:	fd_fifo_get
+ *
+ * PARAMETERS:
+ *  queue	: The queue from which the first element must be retrieved.
+ *  item	: On return, the first element of the queue is stored here.
+ *
+ * DESCRIPTION: 
+ *  This function retrieves the first element from a queue. If the queue is empty, the function will block the 
+ * thread until a new element is posted to the queue, or until the thread is canceled (in which case the 
+ * function does not return).
+ *
+ * RETURN VALUE:
+ *  0		: A new element has been retrieved.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_fifo_get_int ( struct fifo * queue, void ** item );
+#define fd_fifo_get(queue, item) \
+	fd_fifo_get_int((queue), (void *)(item))
+
+/*
+ * FUNCTION:	fd_fifo_tryget
+ *
+ * PARAMETERS:
+ *  queue	: The queue from which the element must be retrieved.
+ *  item	: On return, the first element of the queue is stored here.
+ *
+ * DESCRIPTION: 
+ *  This function is similar to fd_fifo_get, except that it will not block if 
+ * the queue is empty, but return EWOULDBLOCK instead.
+ *
+ * RETURN VALUE:
+ *  0		: A new element has been retrieved.
+ *  EINVAL 	: A parameter is invalid.
+ *  EWOULDBLOCK : The queue was empty.
+ */
+int fd_fifo_tryget_int ( struct fifo * queue, void ** item );
+#define fd_fifo_tryget(queue, item) \
+	fd_fifo_tryget_int((queue), (void *)(item))
+
+/*
+ * FUNCTION:	fd_fifo_timedget
+ *
+ * PARAMETERS:
+ *  queue	: The queue from which the element must be retrieved.
+ *  item	: On return, the element is stored here.
+ *  abstime	: the absolute time until which we allow waiting for an item.
+ *
+ * DESCRIPTION: 
+ *  This function is similar to fd_fifo_get, except that it will block if the queue is empty 
+ * only until the absolute time abstime (see pthread_cond_timedwait for + info).
+ * If the queue is still empty when the time expires, the function returns ETIMEDOUT
+ *
+ * RETURN VALUE:
+ *  0		: A new item has been retrieved.
+ *  EINVAL 	: A parameter is invalid.
+ *  ETIMEDOUT   : The time out has passed and no item has been received.
+ */
+int fd_fifo_timedget_int ( struct fifo * queue, void ** item, const struct timespec *abstime );
+#define fd_fifo_timedget(queue, item, abstime) \
+	fd_fifo_timedget_int((queue), (void *)(item), (abstime))
+
+/* Dump a fifo list and optionally its inner elements -- beware of deadlocks! */
+void fd_fifo_dump(int level, char * name, struct fifo * queue, void (*dump_item)(int level, void * item));
+
+#endif /* _LIBFDPROTO_H */
Index: include/freeDiameter/libfreeDiameter.h
===================================================================
--- include/freeDiameter/libfreeDiameter.h	(revision 653)
+++ 	(revision )
@@ -1,2814 +1,0 @@
-/*********************************************************************************************************
-* Software License Agreement (BSD License)                                                               *
-* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
-*													 *
-* Copyright (c) 2011, WIDE Project and NICT								 *
-* All rights reserved.											 *
-* 													 *
-* Redistribution and use of this software in source and binary forms, with or without modification, are  *
-* permitted provided that the following conditions are met:						 *
-* 													 *
-* * Redistributions of source code must retain the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer.										 *
-*    													 *
-* * Redistributions in binary form must reproduce the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer in the documentation and/or other						 *
-*   materials provided with the distribution.								 *
-* 													 *
-* * Neither the name of the WIDE Project or NICT nor the 						 *
-*   names of its contributors may be used to endorse or 						 *
-*   promote products derived from this software without 						 *
-*   specific prior written permission of WIDE Project and 						 *
-*   NICT.												 *
-* 													 *
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
-* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
-* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
-* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
-* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
-* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY S_OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
-* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
-*********************************************************************************************************/
-
-/* This file contains the definitions of functions and types used by the libfreeDiameter library.
- *
- * This library is meant to be used by both the freeDiameter daemon and its extensions.
- * It provides the tools to manipulate Diameter messages and related data.
- * This file should always be included as #include <freeDiameter/libfreeDiameter.h>
- *
- * If any change is made to this file, you must increment the FD_PROJECT_VERSION_API version.
- *
- * The file contains the following parts:
- *	DEBUG
- *	MACROS
- *	THREADS
- *	LISTS
- *	DICTIONARY
- *	SESSIONS
- *	MESSAGES
- *	DISPATCH
- *	QUEUES
- */
-
-#ifndef _LIBFREEDIAMETER_H
-#define _LIBFREEDIAMETER_H
-
-#ifndef FD_IS_CONFIG
-#error "You must include 'freeDiameter-host.h' before this file."
-#endif /* FD_IS_CONFIG */
-
-#include <pthread.h>
-#include <sched.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#ifdef DEBUG
-#include <libgen.h>	/* for basename if --dbg_file is specified */
-#endif /* DEBUG */
-
-/*============================================================*/
-/*                          INIT                              */
-/*============================================================*/
-
-/* This function must be called first, before any call to another library function */
-/* If the parameter is not 0, the support for signals (fd_sig_register) is enabled, otherwise it is disabled */
-/* The function must be called while the application is single-threaded to enable support for signals */
-int fd_lib_init(int support_signals);
-
-/* Call this one when the application terminates, to destroy internal threads */
-void fd_lib_fini(void);
-
-
-/*============================================================*/
-/*                          DEBUG                             */
-/*============================================================*/
-
-
-/*
- * FUNCTION:	fd_log_debug
- *
- * PARAMETERS:
- *  format 	: Same format string as in the printf function
- *  ...		: Same list as printf
- *
- * DESCRIPTION: 
- *  Log internal information for use of developpers only.
- * The format and arguments may contain UTF-8 encoded data. The
- * output medium (file or console) is expected to support this encoding.
- *
- * This function assumes that a global mutex called "fd_log_lock" exists
- * in the address space of the current process.
- *
- * RETURN VALUE:
- *  None.
- */
-void fd_log_debug ( const char * format, ... );
-extern pthread_mutex_t	fd_log_lock;
-extern char * fd_debug_one_function;
-extern char * fd_debug_one_file;
-
-/*
- * FUNCTION:	fd_log_threadname
- *
- * PARAMETERS:
- *  name 	: \0-terminated string containing a name to identify the current thread.
- *
- * DESCRIPTION: 
- *  Name the current thread, useful for debugging multi-threaded problems.
- *
- * This function assumes that a global thread-specific key called "fd_log_thname" exists
- * in the address space of the current process.
- *
- * RETURN VALUE:
- *  None.
- */
-void fd_log_threadname ( char * name );
-extern pthread_key_t	fd_log_thname;
-
-/*
- * FUNCTION:	fd_log_time
- *
- * PARAMETERS:
- *  ts	 	: The timestamp to log, or NULL for "now"
- *  buf 	: An array where the time must be stored
- *  len		: size of the buffer
- *
- * DESCRIPTION: 
- *  Writes the timestamp (in human readable format) in a buffer. 
- *
- * RETURN VALUE:
- *  pointer to buf.
- */
-char * fd_log_time ( struct timespec * ts, char * buf, size_t len );
-
-
-/*============================================================*/
-/*                    DEBUG MACROS                            */
-/*============================================================*/
-
-#ifndef ASSERT
-#define ASSERT(x) assert(x)
-#endif /* ASSERT */
-
-/* levels definitions */
-#define NONE 0	/* Display no debug message */
-#define INFO 1	/* Display errors only */
-#define FULL 2  /* Display additional information to follow code execution */
-#define ANNOYING 4 /* Very verbose, for example in loops */
-#define FCTS 6  /* Display entry parameters of most functions */
-#define CALL 9  /* Display calls to most functions (with CHECK macros) */
-
-/* Default level is INFO */
-#ifndef TRACE_LEVEL 
-#define TRACE_LEVEL INFO
-#endif /* TRACE_LEVEL */
-
-/* The level of the file being compiled. */
-static int local_debug_level = TRACE_LEVEL;
-
-/* A global level, changed by configuration or cmd line for example. default is 0. */
-extern int fd_g_debug_lvl;
-
-/* Some portability code to get nice function name in __PRETTY_FUNCTION__ */
-#if __STDC_VERSION__ < 199901L
-# if __GNUC__ >= 2
-#  define __func__ __FUNCTION__
-# else /* __GNUC__ >= 2 */
-#  define __func__ "<unknown>"
-# endif /* __GNUC__ >= 2 */
-#endif /* __STDC_VERSION__ < 199901L */
-#ifndef __PRETTY_FUNCTION__
-#define __PRETTY_FUNCTION__ __func__
-#endif /* __PRETTY_FUNCTION__ */
-
-/* A version of __FILE__ without the full path */
-static char * file_bname = NULL;
-#define __STRIPPED_FILE__	(file_bname ?: (file_bname = basename((char *)__FILE__)))
-
-
-/* Boolean for tracing at a certain level */
-#ifdef DEBUG
-#define TRACE_BOOL(_level_) ( ((_level_) <= local_debug_level + fd_g_debug_lvl) 					\
-				|| (fd_debug_one_function && !strcmp(fd_debug_one_function, __PRETTY_FUNCTION__)) 	\
-				|| (fd_debug_one_file && !strcmp(fd_debug_one_file, __STRIPPED_FILE__) ) )
-#else /* DEBUG */
-#define TRACE_BOOL(_level_) ((_level_) <= local_debug_level + fd_g_debug_lvl)
-#endif /* DEBUG */
-
-
-/*************
- The general debug macro, each call results in two lines of debug messages (change the macro for more compact output) 
- *************/
-#ifdef DEBUG
-/* In DEBUG mode, we add (a lot of) meta-information along each trace. This makes multi-threading problems easier to debug. */
-#define TRACE_DEBUG(level,format,args... ) {											\
-	if ( TRACE_BOOL(level) ) {												\
-		char __buf[25];													\
-		const char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-		fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"								\
-			  "\t%s|%*s" format "\n",  										\
-					__thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
-					(level < FULL)?"@":" ",level, "", ## args); 						\
-	}															\
-}
-#else /* DEBUG */
-/* Do not print thread, function, ... only the message itself in this case, unless the debug level is set > FULL. */
-#define TRACE_DEBUG(level,format,args... ) {												\
-	if ( TRACE_BOOL(level) ) {													\
-		if (fd_g_debug_lvl > FULL) {												\
-			char __buf[25];													\
-			const char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-			fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"								\
-				  "\t%s|%*s" format "\n",  										\
-						__thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
-						(level < FULL)?"@":" ",level, "", ## args); 						\
-		} else {														\
-			fd_log_debug(format "\n", ## args); 										\
-		}															\
-	}																\
-}
-#endif /* DEBUG */
-
-/*************
- Derivatives from this macro 
- ************/
-/* Helper for function entry -- for very detailed trace of the execution */
-#define TRACE_ENTRY(_format,_args... ) \
-	TRACE_DEBUG(FCTS, "[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );
-
-/* Helper for debugging by adding traces -- for debuging a specific location of the code */
-#define TRACE_HERE()	\
-	TRACE_DEBUG(NONE, " -- debug checkpoint %d -- ", fd_breakhere());
-int fd_breakhere(void);
-
-/* Helper for tracing the CHECK_* macros bellow -- very very verbose code execution! */
-#define TRACE_DEBUG_ALL( str ) 	\
-	TRACE_DEBUG(CALL, str );
-
-/* For development only, to keep track of TODO locations in the code */
-#ifndef ERRORS_ON_TODO
-#define TODO( _msg, _args... ) \
-	TRACE_DEBUG(NONE, "TODO: " _msg , ##_args);
-#else /* ERRORS_ON_TODO */
-#define TODO( _msg, _args... ) \
-	"TODO" = _msg ## _args; /* just a stupid compilation error to spot the todo */
-#endif /* ERRORS_ON_TODO */
-
-/* Trace a binary buffer content */
-#define TRACE_DEBUG_BUFFER(level, prefix, buf, bufsz, suffix ) {								\
-	if ( TRACE_BOOL(level) ) {												\
-		char __ts[25];													\
-		int __i;													\
-		size_t __sz = (size_t)(bufsz);											\
-		uint8_t * __buf = (uint8_t *)(buf);										\
-		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-		fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"								\
-			  "\t%s|%*s" prefix ,  											\
-					__thn, fd_log_time(NULL, __ts, sizeof(__ts)), __PRETTY_FUNCTION__, __FILE__, __LINE__,	\
-					(level < FULL)?"@":" ",level, ""); 							\
-		for (__i = 0; __i < __sz; __i++) {										\
-			fd_log_debug("%02.2hhx", __buf[__i]);									\
-		}														\
-		fd_log_debug(suffix "\n");											\
-	}															\
-}
-
-/* Some aliases to socket addresses structures */
-#define sSS	struct sockaddr_storage
-#define sSA	struct sockaddr
-#define sSA4	struct sockaddr_in
-#define sSA6	struct sockaddr_in6
-
-/* The sockaddr length of a sSS structure */
-#define sSAlen( _sa_ )	\
-	( (socklen_t) ( (((sSA *)_sa_)->sa_family == AF_INET) ? (sizeof(sSA4)) :		\
-				((((sSA *)_sa_)->sa_family == AF_INET6) ? (sizeof(sSA6)) :	\
-					0 ) ) )
-
-/* Dump one sockaddr Node information */
-#define sSA_DUMP_NODE( sa, flag ) {				\
-	sSA * __sa = (sSA *)(sa);				\
-	char __addrbuf[INET6_ADDRSTRLEN];			\
-	if (__sa) {						\
-	  int __rc = getnameinfo(__sa, 				\
-	  		sSAlen(__sa),				\
-			__addrbuf,				\
-			sizeof(__addrbuf),			\
-			NULL,					\
-			0,					\
-			flag);					\
-	  if (__rc)						\
-	  	fd_log_debug("%s", (char *)gai_strerror(__rc));	\
-	  else							\
-	  	fd_log_debug("%s", &__addrbuf[0]);		\
-	} else {						\
-		fd_log_debug("(NULL / ANY)");			\
-	}							\
-}
-/* Same but with the port (service) also */
-#define sSA_DUMP_NODE_SERV( sa, flag ) {				\
-	sSA * __sa = (sSA *)(sa);					\
-	char __addrbuf[INET6_ADDRSTRLEN];				\
-	char __servbuf[32];						\
-	if (__sa) {							\
-	  int __rc = getnameinfo(__sa, 					\
-	  		sSAlen(__sa),					\
-			__addrbuf,					\
-			sizeof(__addrbuf),				\
-			__servbuf,					\
-			sizeof(__servbuf),				\
-			flag);						\
-	  if (__rc)							\
-	  	fd_log_debug("%s", (char *)gai_strerror(__rc));		\
-	  else								\
-	  	fd_log_debug("[%s]:%s", &__addrbuf[0],&__servbuf[0]);	\
-	} else {							\
-		fd_log_debug("(NULL / ANY)");				\
-	}								\
-}
-
-/* Inside a debug trace */
-#define TRACE_DEBUG_sSA(level, prefix, sa, flags, suffix ) {										\
-	if ( TRACE_BOOL(level) ) {												\
-		char __buf[25];													\
-		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-		fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"								\
-			  "\t%s|%*s" prefix ,  											\
-					__thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
-					(level < FULL)?"@":" ",level, ""); 							\
-		sSA_DUMP_NODE_SERV( sa, flags );										\
-		fd_log_debug(suffix "\n");											\
-	}															\
-}
-
-/* Report an error */
-#define TRACE_DEBUG_ERROR(format,args... ) \
-	TRACE_DEBUG(NONE, format, ##args)
-
-/******************
- Optimized code: remove all debugging code
- **/
-#ifdef STRIP_DEBUG_CODE
-#undef TRACE_DEBUG
-#undef TRACE_BOOL
-#undef TRACE_DEBUG_sSA
-#undef TRACE_DEBUG_BUFFER
-#undef TRACE_DEBUG_ERROR
-#define TRACE_DEBUG(level,format,args... )
-#define TRACE_BOOL(_level_) (0)
-#define TRACE_DEBUG_BUFFER(level, prefix, buf, bufsz, suffix )
-#define TRACE_DEBUG_sSA(level, prefix, sa, flags, suffix )
-#define TRACE_DEBUG_ERROR(format,args... ) {	\
-	fd_log_debug(format "\n", ## args); 	\
-}
-#endif /* STRIP_DEBUG_CODE */
-
-
-/*============================================================*/
-/*                  ERROR CHECKING MACRO                      */
-/*============================================================*/
-
-/* Macros to check a return value and branch out in case of error.
- * These macro should be used only when errors are improbable, not for expected errors.
- */
-
-/* Check the return value of a system function and execute fallback in case of error */
-#define CHECK_SYS_DO( __call__, __fallback__  ) { 					\
-	int __ret__;									\
-	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ < 0) {								\
-		int __err__ = errno;	/* We may handle EINTR here */			\
-		TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "' :\t%s", strerror(__err__));\
-		__fallback__;								\
-	}										\
-}
-/* Check the return value of a system function, return error code on error */
-#define CHECK_SYS( __call__  ) { 							\
-	int __ret__;									\
-	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ < 0) {								\
-		int __err__ = errno;	/* We may handle EINTR here */			\
-		TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "' :\t%s", strerror(__err__));\
-		return __err__;								\
-	}										\
-}
-
-/* Check the return value of a POSIX function and execute fallback in case of error or special value */
-#define CHECK_POSIX_DO2( __call__, __speval__, __fallback1__, __fallback2__ ) {			\
-	int __ret__;										\
-	TRACE_DEBUG_ALL( "Check POSIX: " #__call__ );						\
-	__ret__ = (__call__);									\
-	if (__ret__ != 0) {									\
-		if (__ret__ == (__speval__)) {							\
-			__fallback1__;								\
-		} else {									\
-			TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "':\t%s", strerror(__ret__));	\
-			__fallback2__;								\
-		}										\
-	}											\
-}
-
-/* Check the return value of a POSIX function and execute fallback in case of error */
-#define CHECK_POSIX_DO( __call__, __fallback__ ) 					\
-	CHECK_POSIX_DO2( (__call__), 0, , __fallback__ );
-
-/* Check the return value of a POSIX function and return it if error */
-#define CHECK_POSIX( __call__ ) { 							\
-	int __v__;									\
-	CHECK_POSIX_DO( __v__ = (__call__), return __v__ );				\
-}
-
-/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
-#define CHECK_MALLOC_DO( __call__, __fallback__ ) { 					\
-	void *  __ret__;								\
-	TRACE_DEBUG_ALL( "Check MALLOC: " #__call__ );					\
-	__ret__ = (void *)( __call__ );							\
-	if (__ret__ == NULL) {								\
-		int __err__ = errno;							\
-		TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "':\t%s", strerror(__err__));	\
-		__fallback__;								\
-	}										\
-}
-
-/* Check that a memory allocator did not return NULL, otherwise return ENOMEM */
-#define CHECK_MALLOC( __call__ )							\
-	CHECK_MALLOC_DO( __call__, return ENOMEM );
-
-
-/* Check parameters at function entry, execute fallback on error */
-#define CHECK_PARAMS_DO( __bool__, __fallback__ )						\
-	TRACE_DEBUG_ALL( "Check PARAMS: " #__bool__ );						\
-	if ( ! (__bool__) ) {									\
-		TRACE_DEBUG_ERROR("Warning: Invalid parameter received in '" #__bool__ "'");	\
-		__fallback__;									\
-	}
-/* Check parameters at function entry, return EINVAL if the boolean is false (similar to assert) */
-#define CHECK_PARAMS( __bool__ )							\
-	CHECK_PARAMS_DO( __bool__, return EINVAL );
-
-/* Check the return value of an internal function, log and propagate */
-#define CHECK_FCT_DO( __call__, __fallback__ ) {					\
-	int __ret__;									\
-	TRACE_DEBUG_ALL( "Check FCT: " #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ != 0) {								\
-		TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "':\t%s", strerror(__ret__));	\
-		__fallback__;								\
-	}										\
-}
-/* Check the return value of a function call, return any error code */
-#define CHECK_FCT( __call__ ) {								\
-	int __v__;									\
-	CHECK_FCT_DO( __v__ = (__call__), return __v__ );				\
-}
-
-
-
-/*============================================================*/
-/*                  OTHER MACROS                              */
-/*============================================================*/
-
-
-/* helper macros (pre-processor hacks to allow macro arguments) */
-#define __tostr( arg )  #arg
-#define _stringize( arg ) __tostr( arg )
-#define __agr( arg1, arg2 ) arg1 ## arg2
-#define _aggregate( arg1, arg2 ) __agr( arg1, arg2 )
-
-
-/* A l4 protocol name (TCP / SCTP) */
-#ifdef DISABLE_SCTP
-#define IPPROTO_NAME( _proto )					\
-	(((_proto) == IPPROTO_TCP) ? "TCP" :			\
-			"Unknown")
-#else /* DISABLE_SCTP */
-#define IPPROTO_NAME( _proto )					\
-	( ((_proto) == IPPROTO_TCP) ? "TCP" :			\
-		(((_proto) == IPPROTO_SCTP) ? "SCTP" :		\
-			"Unknown"))
-#endif /* DISABLE_SCTP */
-
-/* Define the value of IP loopback address */
-#ifndef INADDR_LOOPBACK 
-#define INADDR_LOOPBACK	inet_addr("127.0.0.1")
-#endif /* INADDR_LOOPBACK */
-
-#ifndef INADDR_BROADCAST
-#define	INADDR_BROADCAST	((in_addr_t) 0xffffffff)
-#endif /* INADDR_BROADCAST */
-
-/* An IP equivalent to IN6_IS_ADDR_LOOPBACK */
-#ifndef IN_IS_ADDR_LOOPBACK
-#define IN_IS_ADDR_LOOPBACK(a) \
-  ((((long int) (a)->s_addr) & ntohl(0xff000000)) == ntohl(0x7f000000))
-#endif /* IN_IS_ADDR_LOOPBACK */
-
-/* An IP equivalent to IN6_IS_ADDR_UNSPECIFIED */
-#ifndef IN_IS_ADDR_UNSPECIFIED
-#define IN_IS_ADDR_UNSPECIFIED(a) \
-  (((long int) (a)->s_addr) == 0x00000000)
-#endif /* IN_IS_ADDR_UNSPECIFIED */
-
-/* create a V4MAPPED address */
-#define IN6_ADDR_V4MAP( a6, a4 ) {			\
-	((uint32_t *)(a6))[0] = 0;			\
-	((uint32_t *)(a6))[1] = 0;			\
-	((uint32_t *)(a6))[2] = htonl(0xffff);		\
-	((uint32_t *)(a6))[3] = (uint32_t)(a4);		\
-}
-
-/* Retrieve a v4 value from V4MAPPED address ( takes a s6_addr as param) */
-#define IN6_ADDR_V4UNMAP( a6 ) 				\
-	(((in_addr_t *)(a6))[3])
-
-
-/* We provide macros to convert 64 bit values to and from network byte-order, on systems where it is not already provided. */
-#ifndef HAVE_NTOHLL	/* Defined by the cmake step, if the ntohll symbol is defined on the system */
-# if HOST_BIG_ENDIAN
-    /* In big-endian systems, we don't have to change the values, since the order is the same as network */
-#   define ntohll(x) (x)
-#   define htonll(x) (x)
-# else /* HOST_BIG_ENDIAN */
-    /* For these systems, we must reverse the bytes. Use ntohl and htonl on sub-32 blocs, and inverse these blocs. */
-#   define ntohll(x) (typeof (x))( (((uint64_t)ntohl( (uint32_t)(x))) << 32 ) | ((uint64_t) ntohl( ((uint64_t)(x)) >> 32 ))) 
-#   define htonll(x) (typeof (x))( (((uint64_t)htonl( (uint32_t)(x))) << 32 ) | ((uint64_t) htonl( ((uint64_t)(x)) >> 32 ))) 
-# endif /* HOST_BIG_ENDIAN */
-#endif /* HAVE_NTOHLL */
-
-/* This macro will give the next multiple of 4 for an integer (used for padding sizes of AVP). */
-#define PAD4(_x) ((_x) + ( (4 - (_x)) & 3 ) )
-
-/* Useful to display any value as (safe) ASCII (will garbage UTF-8 output...) */
-#define ASCII(_c) ( ((_c < 32) || (_c > 127)) ? ( _c ? '?' : ' ' ) : _c )
-
-/* Compare timespec structures */
-#define TS_IS_INFERIOR( ts1, ts2 ) 		\
-	(    ((ts1)->tv_sec  < (ts2)->tv_sec ) 	\
-	  || (((ts1)->tv_sec  == (ts2)->tv_sec ) && ((ts1)->tv_nsec < (ts2)->tv_nsec) ))
-
-/* This gives a good size for buffered reads */
-#ifndef BUFSIZ
-#define BUFSIZ 96
-#endif /* BUFSIZ */
-
-
-
-/*============================================================*/
-/*                          THREADS                           */
-/*============================================================*/
-
-/* Terminate a thread */
-static __inline__ int fd_thr_term(pthread_t * th)
-{
-	void * th_ret = NULL;
-	
-	CHECK_PARAMS(th);
-	
-	/* Test if it was already terminated */
-	if (*th == (pthread_t)NULL)
-		return 0;
-	
-	/* Cancel the thread if it is still running - ignore error if it was already terminated */
-	(void) pthread_cancel(*th);
-	
-	/* Then join the thread */
-	CHECK_POSIX( pthread_join(*th, &th_ret) );
-	
-	if (th_ret == PTHREAD_CANCELED) {
-		TRACE_DEBUG(ANNOYING, "The thread %p was canceled", *th);
-	} else {
-		TRACE_DEBUG(CALL, "The thread %p returned %x", *th, th_ret);
-	}
-	
-	/* Clean the location */
-	*th = (pthread_t)NULL;
-	
-	return 0;
-}
-
-/* Force flushing the cache of a CPU before reading a shared memory area (use only for atomic reads such as int and void*) */
-extern pthread_mutex_t fd_cpu_mtx_dummy; /* only for the macro bellow, so that we have reasonably fresh pir_state value when needed */
-#define fd_cpu_flush_cache() {				\
-	(void)pthread_mutex_lock(&fd_cpu_mtx_dummy);	\
-	(void)pthread_mutex_unlock(&fd_cpu_mtx_dummy);	\
-}
-
-
-/*************
- Cancelation cleanup handlers for common objects 
- *************/
-static __inline__ void fd_cleanup_mutex( void * mutex )
-{
-	CHECK_POSIX_DO( pthread_mutex_unlock((pthread_mutex_t *)mutex), /* */);
-}
-		
-static __inline__ void fd_cleanup_rwlock( void * rwlock )
-{
-	CHECK_POSIX_DO( pthread_rwlock_unlock((pthread_rwlock_t *)rwlock), /* */);
-}
-
-static __inline__ void fd_cleanup_buffer( void * buffer )
-{
-	free(buffer);
-}
-static __inline__ void fd_cleanup_socket(void * sockptr)
-{
-	if (sockptr && (*(int *)sockptr > 0)) {
-		CHECK_SYS_DO( close(*(int *)sockptr), /* ignore */ );
-		*(int *)sockptr = -1;
-	}
-}
-
-/*============================================================*/
-/*                          SIGNALS                           */
-/*============================================================*/
-
-/* Register a new callback to be called on reception of a given signal (it receives the signal as parameter) */
-/* EALREADY will be returned if there is already a callback registered on this signal */
-/* NOTE: the signal handler will be called from a new detached thread */
-int fd_sig_register(int signal, char * modname, void (*callback)(int signal));
-
-/* Remove the handler for a given signal */
-int fd_sig_unregister(int signal);
-
-/* Dump list of handlers */
-void fd_sig_dump(int level, int indent);
-
-/* Name of signals */
-const char * fd_sig_abbrev(int signal);
-
-
-/*============================================================*/
-/*                          LISTS                             */
-/*============================================================*/
-
-/* The following structure represents a chained list element  */
-struct fd_list {
-	struct fd_list 	*next; /* next element in the list */
-	struct fd_list 	*prev; /* previous element in the list */
-	struct fd_list 	*head; /* head of the list */
-	void		*o;    /* additional pointer, used for any purpose (ex: start of the parent object) */
-};
-
-/* Initialize a list element */
-#define FD_LIST_INITIALIZER( _list_name ) \
-	{ .next = & _list_name, .prev = & _list_name, .head = & _list_name, .o = NULL }
-#define FD_LIST_INITIALIZER_O( _list_name, _obj ) \
-	{ .next = & _list_name, .prev = & _list_name, .head = & _list_name, .o = _obj }
-void fd_list_init ( struct fd_list * list, void * obj );
-
-/* Return boolean, true if the list is empty */
-#define FD_IS_LIST_EMPTY( _list ) ((((struct fd_list *)(_list))->head == (_list)) && (((struct fd_list *)(_list))->next == (_list)))
-
-/* Insert an item in a list at known position */
-void fd_list_insert_after  ( struct fd_list * ref, struct fd_list * item );
-void fd_list_insert_before ( struct fd_list * ref, struct fd_list * item );
-
-/* Move all elements from a list at the end of another */
-void fd_list_move_end(struct fd_list * ref, struct fd_list * senti);
-
-/* Insert an item in an ordered list -- ordering function must be provided. If duplicate object found, EEXIST and it is returned in ref_duplicate */
-int fd_list_insert_ordered( struct fd_list * head, struct fd_list * item, int (*cmp_fct)(void *, void *), void ** ref_duplicate);
-
-/* Unlink an item from a list */
-void fd_list_unlink ( struct fd_list * item );
-
-
-
-/*============================================================*/
-/*                          HASH                              */
-/*============================================================*/
-
-/* Compute a hash value of a string (session id, diameter id, ...) */
-uint32_t fd_hash ( char * string, size_t len );
-
-
-
-/*============================================================*/
-/*                        DICTIONARY                          */
-/*============================================================*/
-
-/* Structure that contains the complete dictionary definitions */
-struct dictionary;
-
-/* Structure that contains a dictionary object */
-struct dict_object;
-
-/* Types of object in the dictionary. */
-enum dict_object_type {
-	DICT_VENDOR	= 1,	/* Vendor */
-	DICT_APPLICATION,	/* Diameter Application */
-	DICT_TYPE,		/* AVP data type */
-	DICT_ENUMVAL,		/* Named constant (value of an enumerated AVP type) */
-	DICT_AVP,		/* AVP */
-	DICT_COMMAND,		/* Diameter Command */
-	DICT_RULE		/* a Rule for AVP in command or grouped AVP */
-#define DICT_TYPE_MAX	DICT_RULE
-};
-	
-/* Initialize a dictionary */
-int fd_dict_init(struct dictionary ** dict);
-/* Destroy a dictionary */
-int fd_dict_fini(struct dictionary ** dict);
-
-/*
- * FUNCTION:	fd_dict_new
- *
- * PARAMETERS:
- *  dict	: Pointer to the dictionnary where the object is created
- *  type 	: What kind of object must be created
- *  data 	: pointer to the data for the object. 
- *          	 type parameter is used to determine the type of data (see bellow for detail).
- *  parent 	: a reference to a parent object, if needed.
- *  ref 	: upon successful creation, reference to new object is stored here if !null.
- *
- * DESCRIPTION: 
- *  Create a new object in the dictionary. 
- *  See following object sections in this header file for more information on data and parent parameters format.
- *
- * RETURN VALUE:
- *  0      	: The object is created in the dictionary.
- *  EINVAL 	: A parameter is invalid.
- *  EEXIST 	: This object is already defined in the dictionary (with conflicting data). 
- *                If "ref" is not NULL, it points to the existing element on return.
- *  (other standard errors may be returned, too, with their standard meaning. Example:
- *    ENOMEM 	: Memory allocation for the new object element failed.)
- */
-int fd_dict_new ( struct dictionary * dict, enum dict_object_type type, void * data, struct dict_object * parent, struct dict_object ** ref );
-
-/*
- * FUNCTION: 	fd_dict_search
- *
- * PARAMETERS:
- *  dict	: Pointer to the dictionnary where the object is searched
- *  type 	: type of object that is being searched
- *  criteria 	: how the object must be searched. See object-related sections bellow for more information.
- *  what 	: depending on criteria, the data that must be searched.
- *  result 	: On successful return, pointer to the object is stored here.
- *  retval	: this value is returned if the object is not found and result is not NULL.
- *
- * DESCRIPTION: 
- *   Perform a search in the dictionary. 
- *   See the object-specific sections bellow to find how to look for each objects.
- *   If the "result" parameter is NULL, the function is used to check if an object is in the dictionary.
- *   Otherwise, a reference to the object is stored in result if found.
- *   If result is not NULL and the object is not found, retval is returned (should be 0 or ENOENT usually)
- *
- * RETURN VALUE:
- *  0      	: The object has been found in the dictionary, or *result is NULL.
- *  EINVAL 	: A parameter is invalid.
- *  ENOENT	: No matching object has been found, and result was NULL.
- */
-int fd_dict_search ( struct dictionary * dict, enum dict_object_type type, int criteria, void * what, struct dict_object ** result, int retval );
-
-/* Special case: get the generic error command object */
-int fd_dict_get_error_cmd(struct dictionary * dict, struct dict_object ** obj);
-
-/*
- * FUNCTION:	fd_dict_getval
- *
- * PARAMETERS:
- *  object 	: Pointer to a dictionary object.
- *  data 	: pointer to a structure to hold the data for the object.
- *          	  The type is the same as "data" parameter in fd_dict_new function.
- *
- * DESCRIPTION: 
- *  Retrieve content of a dictionary object.
- *  See following object sections in this header file for more information on data and parent parameters format.
- *
- * RETURN VALUE:
- *  0      	: The content of the object has been retrieved.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_dict_getval ( struct dict_object * object, void * val);
-int fd_dict_gettype ( struct dict_object * object, enum dict_object_type * type);
-int fd_dict_getdict ( struct dict_object * object, struct dictionary ** dict);
-
-/* Debug functions */
-void fd_dict_dump_object(struct dict_object * obj);
-void fd_dict_dump(struct dictionary * dict);
-
-/*
- ***************************************************************************
- *
- * Vendor object 
- *
- * These types are used to manage vendors in the dictionary
- *
- ***************************************************************************
- */
-
-/* Type to hold a Vendor ID: "SMI Network Management Private Enterprise Codes" (RFC3232) */
-typedef uint32_t	vendor_id_t;
-
-/* Type to hold data associated to a vendor */
-struct dict_vendor_data {
-	vendor_id_t	 vendor_id;	/* ID of a vendor */
-	char 		*vendor_name;	/* The name of this vendor */
-};
-
-/* The criteria for searching a vendor object in the dictionary */
-enum {
-	VENDOR_BY_ID = 10,	/* "what" points to a vendor_id_t */
-	VENDOR_BY_NAME,		/* "what" points to a string */
-	VENDOR_OF_APPLICATION	/* "what" points to a struct dict_object containing an application (see bellow) */
-};
-
-/***
- *  API usage :
-
-Note: the value of "vendor_name" is copied when the object is created, and the string may be disposed afterwards.
-On the other side, when value is retrieved with dict_getval, the string is not copied and MUST NOT be freed. It will
-be freed automatically along with the object itself with call to dict_fini later.
- 
-- fd_dict_new:
- The "parent" parameter is not used for vendors. 
- Sample code to create a vendor:
- {
-	 int ret;
-	 struct dict_object * myvendor;
-	 struct dict_vendor_data myvendordata = { 23455, "my vendor name" };  -- just an example...
-	 ret = fd_dict_new ( dict, DICT_VENDOR, &myvendordata, NULL, &myvendor );
- }
-
-- fd_dict_search:
- Sample codes to look for a vendor object, by its id or name:
- {
-	 int ret;
-	 struct dict_object * vendor_found;
-	 vendor_id_t vendorid = 23455;
-	 ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_BY_ID, &vendorid, &vendor_found, ENOENT);
-	 - or -
-	 ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_BY_NAME, "my vendor name", &vendor_found, ENOENT);
- }
- 
- - fd_dict_getval:
- Sample code to retrieve the data from a vendor object:
- {
-	 int ret;
-	 struct dict_object * myvendor;
-	 struct dict_vendor_data myvendordata;
-	 ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_BY_NAME, "my vendor name", &myvendor, ENOENT);
-	 ret = fd_dict_getval ( myvendor, &myvendordata );
-	 printf("my vendor id: %d\n", myvendordata.vendor_id );
- }
-		 
-*/
-		
-/* Special function: */
-uint32_t * fd_dict_get_vendorid_list(struct dictionary * dict);
-	 
-/*
- ***************************************************************************
- *
- * Application object 
- *
- * These types are used to manage Diameter applications in the dictionary
- *
- ***************************************************************************
- */
-
-/* Type to hold a Diameter application ID: IANA assigned value for this application. */
-typedef uint32_t	application_id_t;
-
-/* Type to hold data associated to an application */
-struct dict_application_data {
-	application_id_t	 application_id;	/* ID of the application */
-	char 			*application_name;	/* The name of this application */
-};
-
-/* The criteria for searching an application object in the dictionary */
-enum {
-	APPLICATION_BY_ID = 20,		/* "what" points to a application_id_t */
-	APPLICATION_BY_NAME,		/* "what" points to a string */
-	APPLICATION_OF_TYPE,		/* "what" points to a struct dict_object containing a type object (see bellow) */
-	APPLICATION_OF_COMMAND		/* "what" points to a struct dict_object containing a command (see bellow) */
-};
-
-/***
- *  API usage :
-
-The "parent" parameter of dict_new may point to a vendor object to inform of what vendor defines the application.
-for standard-track applications, the "parent" parameter should be NULL.
-The vendor associated to an application is retrieved with VENDOR_OF_APPLICATION search criteria on vendors.
-
-- fd_dict_new:
- Sample code for application creation:
- {
-	 int ret;
-	 struct dict_object * vendor;
-	 struct dict_object * appl;
-	 struct dict_vendor_data vendor_data = {
-		 23455,
-		 "my vendor name"
-	 };
-	 struct dict_application_data app_data = {
-		 9789,
-		 "my vendor's application"
-	 };
-	
-	 ret = fd_dict_new ( dict, DICT_VENDOR, &vendor_data, NULL, &vendor );
-	 ret = fd_dict_new ( dict, DICT_APPLICATION, &app_data, vendor, &appl );
- }
-
-- fd_dict_search:
- Sample code to retrieve the vendor of an application
- {
-	 int ret;
-	 struct dict_object * vendor, * appli;
-	 
-	 ret = fd_dict_search ( dict, DICT_APPLICATION, APPLICATION_BY_NAME, "my vendor's application", &appli, ENOENT);
-	 ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_OF_APPLICATION, appli, &vendor, ENOENT);
- }
- 
- - fd_dict_getval:
- Sample code to retrieve the data from an application object:
- {
-	 int ret;
-	 struct dict_object * appli;
-	 struct dict_application_data appl_data;
-	 ret = fd_dict_search ( dict, DICT_APPLICATION, APPLICATION_BY_NAME, "my vendor's application", &appli, ENOENT);
-	 ret = fd_dict_getval ( appli, &appl_data );
-	 printf("my application id: %s\n", appl_data.application_id );
- }
-
-*/
-
-/*
- ***************************************************************************
- *
- * Type object 
- *
- * These types are used to manage AVP data types in the dictionary
- *
- ***************************************************************************
- */
-
-/* Type to store any AVP value */ 
-union avp_value {
-	struct {
-		uint8_t *data;	/* bytes buffer */
-		size_t   len;	/* length of the data buffer */
-	}           os;		/* Storage for an octet string, data is alloc'd and must be freed */
-	int32_t     i32;	/* integer 32 */
-	int64_t     i64;	/* integer 64 */
-	uint32_t    u32;	/* unsigned 32 */
-	uint64_t    u64;	/* unsigned 64 */
-	float       f32;	/* float 32 */
-	double 	    f64;	/* float 64 */
-};
-
-/* These are the basic AVP types defined in RFC3588bis */
-enum dict_avp_basetype {
-	AVP_TYPE_GROUPED,
-	AVP_TYPE_OCTETSTRING,
-	AVP_TYPE_INTEGER32,
-	AVP_TYPE_INTEGER64,
-	AVP_TYPE_UNSIGNED32,
-	AVP_TYPE_UNSIGNED64,
-	AVP_TYPE_FLOAT32,
-	AVP_TYPE_FLOAT64
-#define AVP_TYPE_MAX AVP_TYPE_FLOAT64
-};
-
-/* Callbacks that can be associated with a derived type to easily interpret the AVP value. */
-/*
- * CALLBACK:	dict_avpdata_interpret
- *
- * PARAMETERS:
- *   val         : Pointer to the AVP value that must be interpreted.
- *   interpreted : The result of interpretation is stored here. The format and meaning depends on each type.
- *
- * DESCRIPTION: 
- *   This callback can be provided with a derived type in order to facilitate the interpretation of formated data.
- *  For example, when an AVP of type "Address" is received, it can be used to convert the octetstring into a struct sockaddr.
- *  This callback is not called directly, but through the message's API msg_avp_value_interpret function.
- *
- * RETURN VALUE:
- *  0      	: Operation complete.
- *  !0 		: An error occurred, the error code is returned.
- */
-typedef int (*dict_avpdata_interpret) (union avp_value * value, void * interpreted);
-/*
- * CALLBACK:	dict_avpdata_encode
- *
- * PARAMETERS:
- *   data	: The formated data that must be stored in the AVP value.
- *   val	: Pointer to the AVP value storage area where the data must be stored.
- *
- * DESCRIPTION: 
- *   This callback can be provided with a derived type in order to facilitate the encoding of formated data.
- *  For example, it can be used to convert a struct sockaddr in an AVP value of type Address.
- *  This callback is not called directly, but through the message's API msg_avp_value_encode function.
- *  If the callback is defined for an OctetString based type, the created string must be malloc'd. free will be called 
- *  automatically later.
- *
- * RETURN VALUE:
- *  0      	: Operation complete.
- *  !0 		: An error occurred, the error code is returned.
- */
-typedef int (*dict_avpdata_encode) (void * data, union avp_value * val);
-
-
-/* Type to hold data associated to a derived AVP data type */
-struct dict_type_data {
-	enum dict_avp_basetype	 type_base;	/* How the data of such AVP must be interpreted */
-	char 			*type_name;	/* The name of this type */
-	dict_avpdata_interpret	 type_interpret;/* cb to convert the AVP value in more comprehensive format (or NULL) */
-	dict_avpdata_encode	 type_encode;	/* cb to convert formatted data into an AVP value (or NULL) */
-	void			(*type_dump)(union avp_value * val);	/* cb called by fd_msg_dump_one for this type of data (if != NULL), to dump the AVP value in debug */
-};
-
-/* The criteria for searching a type object in the dictionary */
-enum {
-	TYPE_BY_NAME = 30,		/* "what" points to a string */
-	TYPE_OF_ENUMVAL,		/* "what" points to a struct dict_object containing an enumerated constant (DICT_ENUMVAL, see bellow). */
-	TYPE_OF_AVP			/* "what" points to a struct dict_object containing an AVP object. */
-};
-
-
-/***
- *  API usage :
-
-- fd_dict_new:
- The "parent" parameter may point to an application object, when a type is defined by a Diameter application. 
- 
- Sample code:
- {
-	 int ret;
-	 struct dict_object * mytype;
-	 struct dict_type_data mytypedata = 
-		{ 
-		 AVP_TYPE_OCTETSTRING,
-		 "Address",
-		 NULL,
-		 NULL
-		};
-	 ret = fd_dict_new ( dict, DICT_TYPE, &mytypedata, NULL, &mytype );
- }
-
-- fd_dict_search:
- Sample code:
- {
-	 int ret;
-	 struct dict_object * address_type;
-	 ret = fd_dict_search ( dict, DICT_TYPE, TYPE_BY_NAME, "Address", &address_type, ENOENT);
- }
- 
-*/
-	 
-/*
- ***************************************************************************
- *
- * Enumerated values object 
- *
- * These types are used to manage named constants of some AVP,
- * for enumerated types. freeDiameter allows constants for types others than Unsigned32
- *
- ***************************************************************************
- */
-
-/* Type to hold data of named constants for AVP */
-struct dict_enumval_data {
-	char 		*enum_name;	/* The name of this constant */
-	union avp_value  enum_value;	/* Value of the constant. Union term depends on parent type's base type. */
-};
-
-/* The criteria for searching a constant in the dictionary */
-enum {
-	ENUMVAL_BY_STRUCT = 40,	/* "what" points to a struct dict_enumval_request as defined bellow */
-};
-
-struct dict_enumval_request {
-	/* Identifier of the parent type, one of the following must not be NULL */
-	struct dict_object	*type_obj;
-	char			*type_name;
-	
-	/* Search criteria for the constant */
-	struct dict_enumval_data search; /* search.enum_value is used only if search.enum_name == NULL */
-};
-
-/***
- *  API usage :
-
-- fd_dict_new:
- The "parent" parameter must point to a derived type object. 
- Sample code to create a type "Boolean" with two constants "True" and "False":
- {
-	 int ret;
-	 struct dict_object * type_boolean;
-	 struct dict_type_data type_boolean_data = 
-		{ 
-		 AVP_TYPE_INTEGER32,
-		 "Boolean",
-		 NULL,
-		 NULL
-		};
-	 struct dict_enumval_data boolean_false =
-	 	{
-		 .enum_name="False",
-		 .enum_value.i32 = 0
-	 	};
-	 struct dict_enumval_data boolean_true =
-	 	{
-		 .enum_name="True",
-		 .enum_value.i32 = -1
-	 	};
-	 ret = fd_dict_new ( dict, DICT_TYPE, &type_boolean_data, NULL, &type_boolean );
-	 ret = fd_dict_new ( dict, DICT_ENUMVAL, &boolean_false, type_boolean, NULL );
-	 ret = fd_dict_new ( dict, DICT_ENUMVAL, &boolean_true , type_boolean, NULL );
-	 
- }
-
-- fd_dict_search:
- Sample code to look for a constant name, by its value:
- {
-	 int ret;
-	 struct dict_object * value_found;
-	 struct dict_enumval_request boolean_by_value =
-	 	{
-		 .type_name = "Boolean",
-		 .search.enum_name=NULL,
-		 .search.enum_value.i32 = -1
-	 	};
-	 
-	 ret = fd_dict_search ( dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &boolean_by_value, &value_found, ENOENT);
- }
- 
- - fd_dict_getval:
- Sample code to retrieve the data from a constant object:
- {
-	 int ret;
-	 struct dict_object * value_found;
-	 struct dict_enumval_data boolean_data = NULL;
-	 struct dict_enumval_request boolean_by_value =
-	 	{
-		 .type_name = "Boolean",
-		 .search.enum_name=NULL,
-		 .search.enum_value.i32 = 0
-	 	};
-	 
-	 ret = fd_dict_search ( dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &boolean_by_value, &value_found, ENOENT);
-	 ret = fd_dict_getval ( value_found, &boolean_data );
-	 printf(" Boolean with value 0: %s", boolean_data.enum_name );
- }
-*/
-	 
-/*
- ***************************************************************************
- *
- * AVP object 
- *
- * These objects are used to manage AVP definitions in the dictionary
- *
- ***************************************************************************
- */
-
-/* Type to hold an AVP code. For vendor 0, these codes are assigned by IANA. Otherwise, it is managed by the vendor */
-typedef uint32_t	avp_code_t;
-
-/* Values of AVP flags */
-#define	AVP_FLAG_VENDOR	  	0x80
-#define	AVP_FLAG_MANDATORY	0x40
-#define	AVP_FLAG_RESERVED3	0x20
-#define	AVP_FLAG_RESERVED4	0x10
-#define	AVP_FLAG_RESERVED5	0x08
-#define	AVP_FLAG_RESERVED6	0x04
-#define	AVP_FLAG_RESERVED7	0x02
-#define	AVP_FLAG_RESERVED8	0x01
-
-/* For dumping flags and values */
-#define DUMP_AVPFL_str	"%c%c"
-#define DUMP_AVPFL_val(_val) (_val & AVP_FLAG_VENDOR)?'V':'-' , (_val & AVP_FLAG_MANDATORY)?'M':'-'
-
-/* Type to hold data associated to an avp */
-struct dict_avp_data {
-	avp_code_t	 	 avp_code;	/* Code of the avp */
-	vendor_id_t	 	 avp_vendor;	/* Vendor of the AVP, or 0 */
-	char			*avp_name;	/* Name of this AVP */
-	uint8_t		 	 avp_flag_mask;	/* Mask of fixed AVP flags */
-	uint8_t		 	 avp_flag_val;	/* Values of the fixed flags */
-	enum dict_avp_basetype 	 avp_basetype;	/* Basic type of data found in the AVP */
-};
-
-/* The criteria for searching an avp object in the dictionary */
-enum {
-	AVP_BY_CODE = 50,	/* "what" points to an avp_code_t, vendor is always 0 */
-	AVP_BY_NAME,		/* "what" points to a string, vendor is always 0 */
-	AVP_BY_CODE_AND_VENDOR,	/* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_code are set */
-	AVP_BY_NAME_AND_VENDOR,	/* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_name are set */
-	AVP_BY_NAME_ALL_VENDORS /* "what" points to a string. Might be quite slow... */
-};
-
-/* Struct used for some researchs */
-struct dict_avp_request {
-	vendor_id_t	 avp_vendor;
-	avp_code_t	 avp_code;
-	char		*avp_name;
-};
-
-
-/***
- *  API usage :
-
-If "parent" parameter is not NULL during AVP creation, it must point to a DICT_TYPE object. 
-The extended type is then attached to the AVP. In case where it is an enumerated type, the value of 
-AVP is automatically interpreted in debug messages, and in message checks.
-The derived type of an AVP can be retrieved with: dict_search ( DICT_TYPE, TYPE_OF_AVP, avp, ... )
-
-To create the rules (ABNF) for children of Grouped AVP, see the DICT_RULE related part.
-
-- fd_dict_new:
- Sample code for AVP creation:
- {
-	 int ret;
-	 struct dict_object * user_name_avp;
-	 struct dict_object * boolean_type;
-	 struct dict_object * sample_boolean_avp;
-	 struct dict_avp_data user_name_data = {
-		 1,					// code
-		 0,					// vendor
-		 "User-Name",				// name
-		 AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY,	// fixed mask: V and M values must always be defined as follow. other flags can be set or cleared
-		 AVP_FLAG_MANDATORY,			// the V flag must be cleared, the M flag must be set.
-		 AVP_TYPE_OCTETSTRING			// User-Name AVP contains OctetString data (further precision such as UTF8String can be given with a parent derived type)
-	 };
-	 struct dict_avp_data sample_boolean_data = {
-		 31337,
-		 23455,
-		 "Sample-Boolean",
-		 AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY,
-		 AVP_FLAG_VENDOR,
-		 AVP_TYPE_INTEGER32			// This MUST be the same as parent type's
-	 };
-	
- 	 -- Create an AVP with a base type --
-	 ret = fd_dict_new ( dict, DICT_AVP, &user_name_data, NULL, &user_name_avp );
-	 
-	 -- Create an AVP with a derived type --
-	 ret = fd_dict_search ( dict, DICT_TYPE, TYPE_BY_NAME, "Boolean", &boolean_type, ENOENT);
-	 ret = fd_dict_new ( dict, DICT_AVP, &sample_boolean_data , boolean_type, &sample_boolean_avp );
-	 
- }
-
-- fd_dict_search:
- Sample code to look for an AVP
- {
-	 int ret;
-	 struct dict_object * avp_username;
-	 struct dict_object * avp_sampleboolean;
-	 struct dict_avp_request avpvendorboolean =
-	 	{
-		 .avp_vendor = 23455,
-		 .avp_name   = "Sample-Boolean"
-	 	};
-	 
-	 ret = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME, "User-Name", &avp_username, ENOENT);
-	 
-	 ret = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &avpvendorboolean, &avp_sampleboolean, ENOENT);
-	 
- }
- 
- - fd_dict_getval:
- Sample code to retrieve the data from an AVP object:
- {
-	 int ret;
-	 struct dict_object * avp_username;
-	 struct dict_avp_data user_name_data;
-	 ret = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME, "User-Name", &avp_username, ENOENT);
-	 ret = fd_dict_getval ( avp_username, &user_name_data );
-	 printf("User-Name code: %d\n", user_name_data.avp_code );
- }
-
-*/
-
-/*
- ***************************************************************************
- *
- * Command object 
- *
- * These types are used to manage commands objects in the dictionary
- *
- ***************************************************************************
- */
-
-/* Type to hold a Diameter command code: IANA assigned values. 0x0-0x7fffff=standard, 0x800000-0xfffffd=vendors, 0xfffffe-0xffffff=experimental */
-typedef uint32_t	command_code_t;
-
-/* Values of command flags */
-#define CMD_FLAG_REQUEST	0x80
-#define CMD_FLAG_PROXIABLE	0x40
-#define CMD_FLAG_ERROR		0x20
-#define CMD_FLAG_RETRANSMIT	0x10
-#define CMD_FLAG_RESERVED5	0x08
-#define CMD_FLAG_RESERVED6	0x04
-#define CMD_FLAG_RESERVED7	0x02
-#define CMD_FLAG_RESERVED8	0x01
-
-/* For dumping flags and values */
-#define DUMP_CMDFL_str	"%c%c%c%c"
-#define DUMP_CMDFL_val(_val) (_val & CMD_FLAG_REQUEST)?'R':'-' , (_val & CMD_FLAG_PROXIABLE)?'P':'-' , (_val & CMD_FLAG_ERROR)?'E':'-' , (_val & CMD_FLAG_RETRANSMIT)?'T':'-'
-
-/* Type to hold data associated to a command */
-struct dict_cmd_data {
-	command_code_t	 cmd_code;	/* code of the command */
-	char		*cmd_name;	/* Name of the command */
-	uint8_t		 cmd_flag_mask;	/* Mask of fixed-value flags */
-	uint8_t		 cmd_flag_val;	/* values of the fixed flags */
-};
-
-/* The criteria for searching an avp object in the dictionary */
-enum {
-	CMD_BY_NAME = 60,	/* "what" points to a string */
-	CMD_BY_CODE_R,		/* "what" points to a command_code_t. The "Request" command is returned. */
-	CMD_BY_CODE_A,		/* "what" points to a command_code_t. The "Answer" command is returned. */
-	CMD_ANSWER		/* "what" points to a struct dict_object of a request command. The corresponding "Answer" command is returned. */
-};
-
-
-/***
- *  API usage :
-
-The "parent" parameter of dict_new may point to an application object to inform of what application defines the command.
-The application associated to a command is retrieved with APPLICATION_OF_COMMAND search criteria on applications.
-
-To create the rules for children of commands, see the DICT_RULE related part.
-
-Note that the "Request" and "Answer" commands are two independant objects. This allows to have different rules for each.
-
-- fd_dict_new:
- Sample code for command creation:
- {
-	 int ret;
-	 struct dict_object * cer;
-	 struct dict_object * cea;
-	 struct dict_cmd_data ce_data = {
-		 257,					// code
-		 "Capabilities-Exchange-Request",	// name
-		 CMD_FLAG_REQUEST,			// mask
-		 CMD_FLAG_REQUEST			// value. Only the "R" flag is constrained here, set.
-	 };
-	
-	 ret = fd_dict_new (dict,  DICT_COMMAND, &ce_data, NULL, &cer );
-	 
-	 ce_data.cmd_name = "Capabilities-Exchange-Answer";
-	 ce_data.cmd_flag_val = 0;			// Same constraint on "R" flag, but this time it must be cleared.
-
-	 ret = fd_dict_new ( dict, DICT_COMMAND, &ce_data, NULL, &cea );
- }
-
-- fd_dict_search:
- Sample code to look for a command
- {
-	 int ret;
-	 struct dict_object * cer, * cea;
-	 command_code_t	code = 257;
-	 ret = fd_dict_search ( dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer, ENOENT);
-	 ret = fd_dict_search ( dict, DICT_COMMAND, CMD_BY_CODE_R, &code, &cer, ENOENT);
- }
- 
- - fd_dict_getval:
- Sample code to retrieve the data from a command object:
- {
-	 int ret;
-	 struct dict_object * cer;
-	 struct dict_object * cea;
-	 struct dict_cmd_data cea_data;
-	 ret = fd_dict_search ( dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer, ENOENT);
-	 ret = fd_dict_search ( dict, DICT_COMMAND, CMD_ANSWER, cer, &cea, ENOENT);
-	 ret = fd_dict_getval ( cea, &cea_data );
-	 printf("Answer to CER: %s\n", cea_data.cmd_name );
- }
-
-*/
-
-/*
- ***************************************************************************
- *
- * Rule object
- *
- * These objects are used to manage rules in the dictionary (ABNF implementation)
- * This is used for checking messages validity (more powerful than a DTD)
- *
- ***************************************************************************
- */
-
-/* This defines the kind of rule that is defined */
-enum rule_position {
-	RULE_FIXED_HEAD = 1,	/* The AVP must be at the head of the group. The rule_order field is used to specify the position. */
-	RULE_REQUIRED,		/* The AVP must be present in the parent, but its position is not defined. */
-	RULE_OPTIONAL,		/* The AVP may be present in the message. Used to specify a max number of occurences for example */
-	RULE_FIXED_TAIL		/* The AVP must be at the end of the group. The rule_order field is used to specify the position. */
-};
-
-/* Content of a RULE object data */
-struct dict_rule_data {
-	struct dict_object	*rule_avp;	/* Pointer to the AVP object that is concerned by this rule */
-	enum rule_position	 rule_position;	/* The position in which the rule_avp must appear in the parent */
-	unsigned		 rule_order;	/* for RULE_FIXED_* rules, the place. 1,2,3.. for HEAD rules; ...,3,2,1 for TAIL rules. */
-	int	 		 rule_min;	/* Minimum number of occurences. -1 means "default": 0 for optional rules, 1 for other rules */
-	int			 rule_max;	/* Maximum number of occurences. -1 means no maximum. 0 means the AVP is forbidden. */
-};
-
-/* The criteria for searching a rule in the dictionary */
-enum {
-	RULE_BY_AVP_AND_PARENT = 70	/* "what" points to a struct dict_rule_request -- see bellow. This is used to query "what is the rule for this AVP in this group?" */
-};
-
-/* Structure for querying the dictionary about a rule */
-struct dict_rule_request {
-	struct dict_object	*rule_parent;	/* The grouped avp or command to which the rule apply */
-	struct dict_object	*rule_avp;	/* The AVP concerned by this rule */
-};
-
-
-/***
- *  API usage :
-
-The "parent" parameter can not be NULL. It points to the object (grouped avp or command) to which this rule apply (i.e. for which the ABNF is defined).
-
-- fd_dict_new:
- Sample code for rule creation. Let's create the Proxy-Info grouped AVP for example.
- {
-	int ret;
-	struct dict_object * proxy_info_avp;
-	struct dict_object * proxy_host_avp;
-	struct dict_object * proxy_state_avp;
-	struct dict_object * diameteridentity_type;
-	struct dict_rule_data rule_data;
-	struct dict_type_data di_type_data = { AVP_TYPE_OCTETSTRING, "DiameterIdentity", NULL, NULL };
-	struct dict_avp_data proxy_info_data = { 284, 0, "Proxy-Info", AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, AVP_FLAG_MANDATORY, AVP_TYPE_GROUPED };
-	struct dict_avp_data proxy_host_data = { 280, 0, "Proxy-Host", AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, AVP_FLAG_MANDATORY, AVP_TYPE_OCTETSTRING };
-	struct dict_avp_data proxy_state_data = { 33, 0, "Proxy-State",AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, AVP_FLAG_MANDATORY, AVP_TYPE_OCTETSTRING };
-	
-	-- Create the parent AVP
-	ret = fd_dict_new ( dict, DICT_AVP, &proxy_info_data, NULL, &proxy_info_avp );
-	
-	-- Create the first child AVP.
-	ret = fd_dict_new ( dict, DICT_TYPE, &di_type_data, NULL, &diameteridentity_type );
-	ret = fd_dict_new ( dict, DICT_AVP, &proxy_host_data, diameteridentity_type, &proxy_host_avp );
-	
-	-- Create the other child AVP
-	ret = fd_dict_new ( dict, DICT_AVP, &proxy_state_data, NULL, &proxy_state_avp );
-	
-	-- Now we can create the rules. Both children AVP are mandatory.
-	rule_data.rule_position = RULE_REQUIRED;
-	rule_data.rule_min = -1;
-	rule_data.rule_max = -1;
-	
-	rule_data.rule_avp = proxy_host_avp;
-	ret = fd_dict_new ( dict, DICT_RULE, &rule_data, proxy_info_avp, NULL );
-	
-	rule_data.rule_avp = proxy_state_avp;
-	ret = fd_dict_new ( dict, DICT_RULE, &rule_data, proxy_info_avp, NULL );
-}
-
-- fd_dict_search and fd_dict_getval are similar to previous examples.
-
-*/
-		
-/* Define some hard-coded values */
-/* Application */
-#define AI_RELAY			0xffffffff
-
-/* Commands Codes */
-#define CC_CAPABILITIES_EXCHANGE	257
-#define CC_RE_AUTH			258
-#define CC_ACCOUNTING			271
-#define CC_ABORT_SESSION		274
-#define CC_SESSION_TERMINATION		275
-#define CC_DEVICE_WATCHDOG		280
-#define CC_DISCONNECT_PEER		282
-
-/* AVPs (Vendor 0) */
-#define AC_USER_NAME			1
-#define AC_PROXY_STATE			33
-#define AC_HOST_IP_ADDRESS		257
-#define AC_AUTH_APPLICATION_ID		258
-#define AC_ACCT_APPLICATION_ID		259
-#define AC_VENDOR_SPECIFIC_APPLICATION_ID 260
-#define AC_REDIRECT_HOST_USAGE		261
-#define AC_REDIRECT_MAX_CACHE_TIME	262
-#define AC_SESSION_ID 			263
-#define AC_ORIGIN_HOST			264
-#define AC_SUPPORTED_VENDOR_ID		265
-#define AC_VENDOR_ID			266
-#define AC_FIRMWARE_REVISION		267
-#define AC_RESULT_CODE			268
-#define AC_PRODUCT_NAME			269
-#define AC_DISCONNECT_CAUSE		273
-#define ACV_DC_REBOOTING			0
-#define ACV_DC_BUSY				1
-#define ACV_DC_NOT_FRIEND			2
-#define AC_ORIGIN_STATE_ID		278
-#define AC_FAILED_AVP			279
-#define AC_PROXY_HOST			280
-#define AC_ERROR_MESSAGE		281
-#define AC_ROUTE_RECORD			282
-#define AC_DESTINATION_REALM		283
-#define AC_PROXY_INFO			284
-#define AC_REDIRECT_HOST		292
-#define AC_DESTINATION_HOST		293
-#define AC_ERROR_REPORTING_HOST		294
-#define AC_ORIGIN_REALM			296
-#define AC_INBAND_SECURITY_ID		299
-#define ACV_ISI_NO_INBAND_SECURITY		0
-#define ACV_ISI_TLS				1
-
-/* Error codes */
-#define ER_DIAMETER_SUCCESS			2001
-#define ER_DIAMETER_REALM_NOT_SERVED		3003
-#define ER_DIAMETER_TOO_BUSY			3004
-#define ER_DIAMETER_REDIRECT_INDICATION		3006
-#define ER_ELECTION_LOST			4003
-
-
-/*============================================================*/
-/*                         SESSIONS                           */
-/*============================================================*/
-
-/* Modules that want to associate a state with a Session-Id must first register a handler of this type */
-struct session_handler;
-
-/* This opaque structure represents a session associated with a Session-Id */
-struct session;
-
-/* The state information that a module associate with a session -- each module defines its own data format */
-typedef void session_state;
-
-/* The following function must be called to activate the session expiry mechanism */
-int fd_sess_start(void);
-
-/*
- * FUNCTION:	fd_sess_handler_create
- *
- * PARAMETERS:
- *  handler	: location where the new handler must be stored.
- *  cleanup	: a callback function that must be called when the session with associated data is destroyed.
- *  opaque      : A pointer that is passed to the cleanup callback -- the content is never examined by the framework.
- *
- * DESCRIPTION: 
- *  Create a new session handler. This is needed by a module to associate a state with a session object.
- * The cleanup handler is called when the session timeout expires, or fd_sess_destroy is called. It must free
- * the state associated with the session, and eventually trig other actions (send a STR, ...).
- *
- * RETURN VALUE:
- *  0      	: The new handler has been created.
- *  EINVAL 	: A parameter is invalid.
- *  ENOMEM	: Not enough memory to complete the operation
- */
-int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, char * sid, void * opaque), void * opaque );
-/* Macro to avoid casting everywhere */
-#define fd_sess_handler_create( _handler, _cleanup, _opaque ) \
-	fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, char *, void *))(_cleanup), (void *)(_opaque) )
-
-	
-/*
- * FUNCTION:	fd_sess_handler_destroy
- *
- * PARAMETERS:
- *  handler	: location of an handler created by fd_sess_handler_create.
- *  opaque      : the opaque pointer registered with the callback is restored here (if ! NULL).
- *
- * DESCRIPTION: 
- *  This destroys a session handler (typically called when an application is shutting down).
- * If sessions states are registered with this handler, the cleanup callback is called on them.
- *
- * RETURN VALUE:
- *  0      	: The handler was destroyed.
- *  EINVAL 	: A parameter is invalid.
- *  ENOMEM	: Not enough memory to complete the operation
- */
-int fd_sess_handler_destroy ( struct session_handler ** handler, void **opaque );
-
-
-
-/*
- * FUNCTION:	fd_sess_new
- *
- * PARAMETERS:
- *  session	  : The location where the session object will be created upon success.
- *  diamId	  : \0-terminated string containing a Diameter Identity.
- *  opt           : Additional string. Usage is described bellow.
- *  optlen	  : if opt is \0-terminated, this can be 0. Otherwise, the length of opt.
- *
- * DESCRIPTION: 
- *   Create a new session object. The Session-Id string associated with this session is generated as follow:
- *  If diamId parameter is provided, the string is created according to the RFC: <diamId>;<high32>;<low32>[;opt] where
- *    diamId is a Diameter Identity.
- *    high32 and low32 are the parts of a monotonic 64 bits counter initialized to (time, 0) at startup.
- *    opt is an optional string that can be concatenated to the identifier.
- *  If diamId is NULL, the string is exactly the content of opt.
- *
- * RETURN VALUE:
- *  0      	: The session is created.
- *  EINVAL 	: A parameter is invalid.
- *  EALREADY	: A session with the same name already exists (returned in *session)
- *  ENOMEM	: Not enough memory to complete the operation
- */
-int fd_sess_new ( struct session ** session, char * diamId, char * opt, size_t optlen );
-
-/*
- * FUNCTION:	fd_sess_fromsid
- *
- * PARAMETERS:
- *  sid	  	: pointer to a string containing a Session-Id (UTF-8).
- *  len		: length of the sid string (which does not need to be '\0'-terminated)
- *  session	: On success, pointer to the session object created / retrieved.
- *  isnew	: if not NULL, set to 1 on return if the session object has been created, 0 if it was simply retrieved.
- *
- * DESCRIPTION: 
- *   Retrieve a session object from a Session-Id string. In case no session object was previously existing with this 
- *  id, a new object is silently created (equivalent to fd_sess_new with flag SESSION_NEW_FULL).
- *
- * RETURN VALUE:
- *  0      	: The session parameter has been updated.
- *  EINVAL 	: A parameter is invalid.
- *  ENOMEM	: Not enough memory to complete the operation
- */
-int fd_sess_fromsid ( char * sid, size_t len, struct session ** session, int * isnew);
-
-/*
- * FUNCTION:	fd_sess_getsid
- *
- * PARAMETERS:
- *  session	: Pointer to a session object.
- *  sid	  	: On success, the location of a (\0-terminated) string is stored here.
- *
- * DESCRIPTION: 
- *   Retrieve the session identifier (Session-Id) corresponding to a session object.
- *  The returned sid is an UTF-8 string terminated by \0, suitable for calls to strlen and strcpy.
- *  It may be used for example to set the value of an AVP.
- *  Note that the sid string is not copied, just its reference... do not free it!
- *
- * RETURN VALUE:
- *  0      	: The sid parameter has been updated.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_sess_getsid ( struct session * session, char ** sid );
-
-/*
- * FUNCTION:	fd_sess_settimeout
- *
- * PARAMETERS:
- *  session	: The session for which to set the timeout.
- *  timeout	: The date when the session times out.
- *
- * DESCRIPTION: 
- *   Set the lifetime for a given session object. This function may be 
- * called several times on the same object to update the timeout value.
- *   When the timeout date is reached, the cleanup handler of each 
- * module that registered data with this session is called, then the 
- * session is cleared.
- *
- *   There is a possible race condition between cleanup of the session
- * and use of its data; applications should ensure that they are not 
- * using data from a session that is about to expire / expired.
- *
- * RETURN VALUE:
- *  0      	: The session timeout has been updated.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_sess_settimeout( struct session * session, const struct timespec * timeout );
-
-/*
- * FUNCTION:	fd_sess_destroy
- *
- * PARAMETERS:
- *  session	: Pointer to a session object.
- *
- * DESCRIPTION: 
- *   Destroys a session an all associated data, if any.
- * Equivalent to a session timeout expired, but the effect is immediate.
- *
- * RETURN VALUE:
- *  0      	: The session no longer exists.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_sess_destroy ( struct session ** session );
-
-/*
- * FUNCTION:	fd_sess_reclaim
- *
- * PARAMETERS:
- *  session	: Pointer to a session object.
- *
- * DESCRIPTION: 
- *   Destroys the resources of a session, only if no session_state is associated with it.
- *
- * RETURN VALUE:
- *  0      	: The session no longer exists.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_sess_reclaim ( struct session ** session );
-
-
-
-
-/*
- * FUNCTION:	fd_sess_state_store
- *
- * PARAMETERS:
- *  handler	: The handler with which the state is registered.
- *  session	: The session object with which the state is registered.
- *  state	: An application state (opaque data) to store with the session.
- *
- * DESCRIPTION: 
- *  Stores an application state with a session. This state can later be retrieved
- * with fd_sess_state_retrieve, or implicitly in the cleanup handler when the session
- * is destroyed.
- *
- * RETURN VALUE:
- *  0      	: The state has been stored.
- *  EINVAL 	: A parameter is invalid.
- *  EALREADY	: Data was already associated with this session and client.
- *  ENOMEM	: Not enough memory to complete the operation
- */
-int fd_sess_state_store_internal ( struct session_handler * handler, struct session * session, session_state ** state );
-#define fd_sess_state_store( _handler, _session, _state ) \
-	fd_sess_state_store_internal( (_handler), (_session), (void *)(_state) )
-
-/*
- * FUNCTION:	fd_sess_state_retrieve
- *
- * PARAMETERS:
- *  handler	: The handler with which the state was registered.
- *  session	: The session object with which the state was registered.
- *  state	: Location where the state must be saved if it is found.
- *
- * DESCRIPTION: 
- *  Retrieves a state saved by fd_sess_state_store.
- * After this function has been called, the state is no longer associated with 
- * the session. A new call to fd_sess_state_store must be performed in order to
- * store again the data with the session.
- *
- * RETURN VALUE:
- *  0      	: *state is updated (NULL or points to the state if it was found).
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_sess_state_retrieve_internal ( struct session_handler * handler, struct session * session, session_state ** state ); 
-#define fd_sess_state_retrieve( _handler, _session, _state ) \
-	fd_sess_state_retrieve_internal( (_handler), (_session), (void *)(_state) )
-
-
-/* For debug */
-void fd_sess_dump(int level, struct session * session);
-void fd_sess_dump_hdl(int level, struct session_handler * handler);
-
-/*============================================================*/
-/*                         ROUTING                            */
-/*============================================================*/
-
-/* The following functions are helpers for the routing module. 
-  The routing data is stored in the message itself. */
-
-/* Structure that contains the routing data for a message */
-struct rt_data;
-
-/* Following functions are helpers to create the routing data of a message */
-int  fd_rtd_init(struct rt_data ** rtd);
-void fd_rtd_free(struct rt_data ** rtd);
-
-/* Add a peer to the candidates list */
-int  fd_rtd_candidate_add(struct rt_data * rtd, char * peerid, char * realm);
-
-/* Remove a peer from the candidates (if it is found) */
-void fd_rtd_candidate_del(struct rt_data * rtd, char * peerid, size_t sz /* if !0, peerid does not need to be \0 terminated */);
-
-/* Extract the list of valid candidates, and initialize their scores to 0 */
-void fd_rtd_candidate_extract(struct rt_data * rtd, struct fd_list ** candidates, int ini_score);
-
-/* If a peer returned a protocol error for this message, save it so that we don't try to send it there again */
-int  fd_rtd_error_add(struct rt_data * rtd, char * sentto, uint8_t * origin, size_t originsz, uint32_t rcode);
-
-/* The extracted list items have the following structure: */
-struct rtd_candidate {
-	struct fd_list	chain;	/* link in the list returned by the previous fct */
-	char *		diamid;	/* the diameter Id of the peer */
-	char *		realm;	/* the diameter realm of the peer (if known) */
-	int		score;	/* the current routing score for this peer, see fd_rt_out_register definition for details */
-};
-
-/* Reorder the list of peers */
-int  fd_rtd_candidate_reorder(struct fd_list * candidates);
-
-/* Note : it is fine for a callback to add a new entry in the candidates list after the list has been extracted. The diamid must then be malloc'd. */
-/* Beware that this could lead to routing loops */
-
-/*============================================================*/
-/*                         MESSAGES                           */
-/*============================================================*/
-
-/* The following types are opaque */
-struct	msg;	/* A message: command with children AVPs (possibly grand children) */
-struct	avp;	/* AVP object */
-
-/* Some details about chaining:
- *
- *  A message is made of a header ( msg ) and 0 or more AVPs ( avp ).
- * The structure is a kind of tree, where some AVPs (grouped AVPs) can contain other AVPs.
- * Exemple:
- * msg
- *  |-avp
- *  |-gavp
- *  |   |-avp
- *  |   |-avp
- *  |   \-avp
- *  |-avp
- *  \-avp
- *
- */
-
-/* The following type is used to point to either a msg or an AVP */
-typedef void msg_or_avp;
-
-/* The Diameter protocol version */
-#define DIAMETER_VERSION	1
-
-/* In the two following types, some fields are marked (READONLY). 
- * This means that the content of these fields will be overwritten by the daemon so modifying it is useless.
- */
-
-/* The following structure represents the header of a message. All data is in host byte order. */
-struct msg_hdr {
-	uint8_t		 msg_version;		/* (READONLY) Version of Diameter: must be DIAMETER_VERSION. */
-	uint32_t	 msg_length;		/* (READONLY)(3 bytes) indicates the length of the message */
-	uint8_t		 msg_flags;		/* Message flags: CMD_FLAG_* */
-	command_code_t	 msg_code;		/* (3 bytes) the command-code. See dictionary-api.h for more detail */
-	application_id_t msg_appl;		/* The application issuing this message */
-	uint32_t	 msg_hbhid;		/* The Hop-by-Hop identifier of the message */
-	uint32_t	 msg_eteid;		/* The End-to-End identifier of the message */
-};
-
-/* The following structure represents the visible content of an AVP. All data is in host byte order. */
-struct avp_hdr {
-	avp_code_t	 avp_code;		/* the AVP Code */
-	uint8_t		 avp_flags;		/* AVP_FLAG_* flags */
-	uint32_t	 avp_len;		/* (READONLY)(Only 3 bytes are used) the length of the AVP as described in the RFC */
-	vendor_id_t	 avp_vendor;		/* Only used if AVP_FLAG_VENDOR is present */
-	union avp_value *avp_value;		/* pointer to the value of the AVP. NULL means that the value is not set / not understood.
-						   One should not directly change this value. Use the msg_avp_setvalue function instead.
-						   The content of the pointed structure can be changed directly, with this restriction:
-						     if the AVP is an OctetString, and you change the value of the pointer avp_value->os.data, then
-						     you must call free() on the previous value, and the new one must be free()-able.
-						 */
-};
-
-/* The following enum is used to browse inside message hierarchy (msg, gavp, avp) */
-enum msg_brw_dir {
-	MSG_BRW_NEXT = 1,	/* Get the next element at the same level, or NULL if this is the last element. */
-	MSG_BRW_PREV,		/* Get the previous element at the same level, or NULL if this is the first element. */
-	MSG_BRW_FIRST_CHILD,	/* Get the first child AVP of this element, if any. */
-	MSG_BRW_LAST_CHILD,	/* Get the last child AVP of this element, if any. */
-	MSG_BRW_PARENT,		/* Get the parent element of this element, if any. Only the msg_t object has no parent. */
-	MSG_BRW_WALK		/* This is equivalent to FIRST_CHILD or NEXT or PARENT->next, first that is not NULL. Use this to walk inside all AVPs. */
-};
-
-/* Some flags used in the functions bellow */
-#define AVPFL_SET_BLANK_VALUE	0x01	/* When creating an AVP, initialize its value to a blank area */
-#define AVPFL_MAX		AVPFL_SET_BLANK_VALUE	/* The biggest valid flag value */
-	
-#define MSGFL_ALLOC_ETEID	0x01	/* When creating a message, a new end-to-end ID is allocated and set in the message */
-#define MSGFL_ANSW_ERROR	0x02	/* When creating an answer message, set the 'E' bit and use the generic error ABNF instead of command-specific ABNF */
-#define MSGFL_ANSW_NOSID	0x04	/* When creating an answer message, do not add the Session-Id even if present in request */
-#define MSGFL_MAX		MSGFL_ANSW_NOSID	/* The biggest valid flag value */
-
-/**************************************************/
-/*   Message creation, manipulation, disposal     */
-/**************************************************/
-/*
- * FUNCTION:	fd_msg_avp_new
- *
- * PARAMETERS:
- *  model 	: Pointer to a DICT_AVP dictionary object describing the avp to create, or NULL.
- *  flags	: Flags to use in creation (AVPFL_*).
- *  avp 	: Upon success, pointer to the new avp is stored here.
- *
- * DESCRIPTION: 
- *   Create a new AVP instance.
- *
- * RETURN VALUE:
- *  0      	: The AVP is created.
- *  EINVAL 	: A parameter is invalid.
- *  (other standard errors may be returned, too, with their standard meaning. Example:
- *    ENOMEM 	: Memory allocation for the new avp failed.)
- */
-int fd_msg_avp_new ( struct dict_object * model, int flags, struct avp ** avp );
-
-/*
- * FUNCTION:	fd_msg_new
- *
- * PARAMETERS:
- *  model 	: Pointer to a DICT_COMMAND dictionary object describing the message to create, or NULL.
- *  flags	: combination of MSGFL_* flags.
- *  msg 	: Upon success, pointer to the new message is stored here.
- *
- * DESCRIPTION: 
- *   Create a new empty Diameter message. 
- *
- * RETURN VALUE:
- *  0      	: The message is created.
- *  EINVAL 	: A parameter is invalid.
- *  (other standard errors may be returned, too, with their standard meaning. Example:
- *    ENOMEM 	: Memory allocation for the new message failed.)
- */
-int fd_msg_new ( struct dict_object * model, int flags, struct msg ** msg );
-
-/*
- * FUNCTION:	msg_new_answer_from_req
- *
- * PARAMETERS:
- *  dict	: Pointer to the dictionary containing the model of the query.
- *  msg		: The location of the query on function call. Updated by the location of answer message on return.
- *  flag        : Pass MSGFL_ANSW_ERROR to indicate if the answer is an error message (will set the 'E' bit)
- *
- * DESCRIPTION: 
- *   This function creates the empty answer message corresponding to a request.
- *  The header is set properly (R flag, ccode, appid, hbhid, eteid)
- *  The Session-Id AVP is copied if present.
- *  The calling code should usually call fd_msg_rescode_set function on the answer.
- *  Upon return, the original query may be retrieved by calling fd_msg_answ_getq on the message.
- *
- * RETURN VALUE:
- *  0      	: Operation complete.
- *  !0      	: an error occurred.
- */
-int fd_msg_new_answer_from_req ( struct dictionary * dict, struct msg ** msg, int flag );
-
-/*
- * FUNCTION:	fd_msg_browse
- *
- * PARAMETERS:
- *  reference 	: Pointer to a struct msg or struct avp.
- *  dir         : Direction for browsing
- *  found       : If not NULL, updated with the element that has been found, if any, or NULL if no element was found / an error occurred.
- *  depth	: If not NULL, points to an integer representing the "depth" of this object in the tree. This is a relative value, updated on return.
- *
- * DESCRIPTION: 
- *   Explore the content of a message object (hierarchy). If "found" is null, only error checking is performed.
- *  If "depth" is provided, it is updated as follow on successful function return:
- *   - not modified for MSG_BRW_NEXT and MSG_BRW_PREV.
- *   - *depth = *depth + 1 for MSG_BRW_FIRST_CHILD and MSG_BRW_LAST_CHILD.
- *   - *depth = *depth - 1 for MSG_BRW_PARENT.
- *   - *depth = *depth + X for MSG_BRW_WALK, with X between 1 (returned the 1st child) and -N (returned the Nth parent's next).
- *
- * RETURN VALUE:
- *  0      	: found has been updated (if non NULL).
- *  EINVAL 	: A parameter is invalid.
- *  ENOENT	: No element has been found where requested, and "found" was NULL (otherwise, *found is set to NULL and 0 is returned). 
- */
-int fd_msg_browse_internal ( msg_or_avp * reference, enum msg_brw_dir dir, msg_or_avp ** found, int * depth );
-/* Macro to avoid having to cast the third parameter everywhere */
-#define fd_msg_browse( ref, dir, found, depth )	\
-	fd_msg_browse_internal( (ref), (dir), (void *)(found), (depth) )
-
-
-/*
- * FUNCTION:	fd_msg_avp_add
- *
- * PARAMETERS:
- *  reference 	: Pointer to a valid msg or avp.
- *  dir         : location where the new AVP should be inserted, relative to the reference. MSG_BRW_PARENT and MSG_BRW_WALK are not valid.
- *  avp         : pointer to the AVP object that must be inserted.
- *
- * DESCRIPTION: 
- *   Adds an AVP into an object that can contain it: grouped AVP or message.
- * Note that the added AVP will be freed at the same time as the object it is added to, 
- * so it should not be freed after the call to this function.
- *
- * RETURN VALUE:
- *  0      	: The AVP has been added.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_msg_avp_add ( msg_or_avp * reference, enum msg_brw_dir dir, struct avp *avp);
-
-/*
- * FUNCTION:	fd_msg_search_avp
- *
- * PARAMETERS:
- *  msg 	: The message structure in which to search the AVP.
- *  what 	: The dictionary model of the AVP to search.
- *  avp		: location where the AVP reference is stored if found.
- *
- * DESCRIPTION: 
- *   Search the first top-level AVP of a given model inside a message.
- * Note: only the first instance of the AVP is returned by this function.
- * Note: only top-level AVPs are searched, not inside grouped AVPs.
- * Use msg_browse if you need more advanced research features.
- *
- * RETURN VALUE:
- *  0      	: The AVP has been found.
- *  EINVAL 	: A parameter is invalid.
- *  ENOENT	: No AVP has been found, and "avp" was NULL (otherwise, *avp is set to NULL and 0 returned).
- */
-int fd_msg_search_avp ( struct msg * msg, struct dict_object * what, struct avp ** avp );
-
-/*
- * FUNCTION:	fd_msg_free
- *
- * PARAMETERS:
- *  object      : pointer to the message or AVP object that must be unlinked and freed.
- *
- * DESCRIPTION: 
- *   Unlink and free a message or AVP object and its children.
- *  If the object is an AVP linked into a message, the AVP is removed before being freed.
- *
- * RETURN VALUE:
- *  0      	: The message has been freed.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_msg_free ( msg_or_avp * object );
-
-/***************************************/
-/*   Dump functions                    */
-/***************************************/
-/*
- * FUNCTION:	fd_msg_dump_*
- *
- * PARAMETERS:
- *  level	: the log level (INFO, FULL, ...) at which the object is dumped
- *  obj		: A msg or avp object.
- *
- * DESCRIPTION: 
- *   These functions dump the content of a message to the debug log
- * either recursively or only the object itself.
- *
- * RETURN VALUE:
- *   -
- */
-void fd_msg_dump_walk ( int level, msg_or_avp *obj );
-void fd_msg_dump_one  ( int level, msg_or_avp *obj );
-
-
-/*********************************************/
-/*   Message metadata management functions   */
-/*********************************************/
-/*
- * FUNCTION:	fd_msg_model
- *
- * PARAMETERS:
- *  reference 	: Pointer to a valid msg or avp.
- *  model       : on success, pointer to the dictionary model of this command or AVP. NULL if the model is unknown.
- *
- * DESCRIPTION: 
- *   Retrieve the dictionary object describing this message or avp. If the object is unknown or the fd_msg_parse_dict has not been called,
- *  *model is set to NULL.
- *
- * RETURN VALUE:
- *  0      	: The model has been set.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_msg_model ( msg_or_avp * reference, struct dict_object ** model );
-
-/*
- * FUNCTION:	fd_msg_hdr
- *
- * PARAMETERS:
- *  msg 	: Pointer to a valid message object.
- *  pdata 	: Upon success, pointer to the msg_hdr structure of this message. The fields may be modified.
- *
- * DESCRIPTION: 
- *   Retrieve location of modifiable section of a message. 
- *
- * RETURN VALUE:
- *  0      	: The location has been written.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_msg_hdr ( struct msg *msg, struct msg_hdr ** pdata );
-
-/*
- * FUNCTION:	fd_msg_avp_hdr
- *
- * PARAMETERS:
- *  avp 	: Pointer to a valid avp object.
- *  pdata 	: Upon success, pointer to the avp_hdr structure of this avp. The fields may be modified.
- *
- * DESCRIPTION: 
- *   Retrieve location of modifiable data of an avp. 
- *
- * RETURN VALUE:
- *  0      	: The location has been written.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_msg_avp_hdr ( struct avp *avp, struct avp_hdr ** pdata );
-
-/*
- * FUNCTION:	fd_msg_answ_associate, fd_msg_answ_getq, fd_msg_answ_detach
- *
- * PARAMETERS:
- *  answer	: the received answer message
- *  query	: the corresponding query that had been sent
- *
- * DESCRIPTION:
- *  fd_msg_answ_associate associates a query msg with the received answer. 
- * Query is retrieved with fd_msg_answ_getq.
- * If answer message is freed, the query is also freed.
- * If the msg_answ_detach function is called, the association is removed.
- * This is meant to be called from the daemon only.
- *
- * RETURN VALUE:
- *  0 	  : ok
- *  EINVAL: a parameter is invalid
- */
-int fd_msg_answ_associate( struct msg * answer, struct msg * query );
-int fd_msg_answ_getq     ( struct msg * answer, struct msg ** query );
-int fd_msg_answ_detach   ( struct msg * answer );
-
-/*
- * FUNCTION:	fd_msg_anscb_associate, fd_msg_anscb_get
- *
- * PARAMETERS:
- *  msg		: the answer message
- *  anscb	: the callback to associate with the message
- *  data	: the data to pass to the callback
- *  timeout     : (optional, use NULL if no timeout) a timeout associated with calling the cb.
- *
- * DESCRIPTION:
- *  Associate or retrieve a callback with an answer message.
- * This is meant to be called from the daemon only.
- *
- * RETURN VALUE:
- *  0 	  : ok
- *  EINVAL: a parameter is invalid
- */
-int fd_msg_anscb_associate( struct msg * msg, void ( *anscb)(void *, struct msg **), void  * data, const struct timespec *timeout );
-int fd_msg_anscb_get      ( struct msg * msg, void (**anscb)(void *, struct msg **), void ** data );
-struct timespec *fd_msg_anscb_gettimeout( struct msg * msg ); /* returns NULL or a valid non-0 timespec */
-
-/*
- * FUNCTION:	fd_msg_rt_associate, fd_msg_rt_get
- *
- * PARAMETERS:
- *  msg		: the query message to be sent
- *  list	: the ordered list of possible next-peers
- *
- * DESCRIPTION:
- *  Associate a routing list with a query, and retrieve it.
- * If the message is freed, the list is also freed.
- *
- * RETURN VALUE:
- *  0 	  : ok
- *  EINVAL: a parameter is invalid
- */
-int fd_msg_rt_associate( struct msg * msg, struct rt_data ** rtd );
-int fd_msg_rt_get      ( struct msg * msg, struct rt_data ** rtd );
-
-/*
- * FUNCTION:	fd_msg_is_routable
- *
- * PARAMETERS:
- *  msg		: A msg object.
- *
- * DESCRIPTION: 
- *   This function returns a boolean telling if a given message is routable in the Diameter network, 
- *  or if it is a local link message only (ex: CER/CEA, DWR/DWA, ...).
- *
- * RETURN VALUE:
- *  0      	: The message is not routable / an error occurred.
- *  1      	: The message is routable.
- */
-int fd_msg_is_routable ( struct msg * msg );
-
-/*
- * FUNCTION:	fd_msg_source_(g/s)et
- *
- * PARAMETERS:
- *  msg		: A msg object.
- *  diamid	: The diameter id of the peer from which this message was received.
- *  add_rr	: if true, a Route-Record AVP is added to the message with content diamid. In that case, dict must be supplied.
- *  dict	: a dictionary with definition of Route-Record AVP (if add_rr is true)
- *
- * DESCRIPTION: 
- *   Store or retrieve the diameted id of the peer from which this message was received.
- * Will be used for example by the routing module to add the Route-Record AVP in forwarded requests,
- * or to direct answers to the appropriate peer.
- *
- * RETURN VALUE:
- *  0      	: Operation complete.
- *  !0      	: an error occurred.
- */
-int fd_msg_source_set( struct msg * msg, char * diamid, int add_rr, struct dictionary * dict );
-int fd_msg_source_get( struct msg * msg, char ** diamid );
-
-/*
- * FUNCTION:	fd_msg_eteid_get
- *
- * PARAMETERS:
- *  -
- *
- * DESCRIPTION: 
- *   Get a new unique end-to-end id value for the local peer.
- *
- * RETURN VALUE:
- *  The new assigned value. No error code is defined.
- */
-uint32_t fd_msg_eteid_get ( void );
-
-
-/*
- * FUNCTION:	fd_msg_sess_get
- *
- * PARAMETERS:
- *  dict	: the dictionary that contains the Session-Id AVP definition
- *  msg		: A valid message.
- *  session	: Location to store the session pointer when retrieved.
- *  isnew	: Indicates if the session has been created.
- *
- * DESCRIPTION:
- *  This function retrieves or creates the session object corresponding to a message.
- * If the message does not contain a Session-Id AVP, *session == NULL on return.
- * Note that the Session-Id AVP must never be modified after created in a message.
- *
- * RETURN VALUE:
- *  0 : success
- * !0 : standard error code.
- */
-int fd_msg_sess_get(struct dictionary * dict, struct msg * msg, struct session ** session, int * isnew);
-
-/***************************************/
-/*   Manage AVP values                 */
-/***************************************/
-
-/*
- * FUNCTION:	fd_msg_avp_setvalue
- *
- * PARAMETERS:
- *  avp 	: Pointer to a valid avp object with a NULL avp_value pointer. The model must be known.
- *  value 	: pointer to an avp_value. The content will be COPIED into the internal storage area. 
- *		 If data type is an octetstring, the data is also copied.
- * 		 If value is a NULL pointer, the previous data is erased and value is unset in the AVP.
- *
- * DESCRIPTION: 
- *   Initialize the avp_value field of an AVP header.
- *
- * RETURN VALUE:
- *  0      	: The avp_value pointer has been set.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_msg_avp_setvalue ( struct avp *avp, union avp_value *value );
-
-/*
- * FUNCTION:	fd_msg_avp_value_encode
- *
- * PARAMETERS:
- *  avp 	: Pointer to a valid avp object with a NULL avp_value. The model must be known.
- *  data 	: Pointer to the data that must be encoded as AVP value and stored in the AVP.
- *		 This is only valid for AVPs of derived type for which type_data_encode callback is set. (ex: Address type)
- *
- * DESCRIPTION: 
- *   Initialize the avp_value field of an AVP object from formatted data, using the AVP's type "type_data_encode" callback.
- *
- * RETURN VALUE:
- *  0      	: The avp_value has been set.
- *  EINVAL 	: A parameter is invalid.
- *  ENOTSUP 	: There is no appropriate callback registered with this AVP's type.
- */
-int fd_msg_avp_value_encode ( void *data, struct avp *avp );
-/*
- * FUNCTION:	fd_msg_avp_value_interpret
- *
- * PARAMETERS:
- *  avp 	: Pointer to a valid avp object with a non-NULL avp_value value.
- *  data 	: Upon success, formatted interpretation of the AVP value is stored here.
- *
- * DESCRIPTION: 
- *   Interpret the content of an AVP of Derived type and store the result in data pointer. The structure
- * of the data pointer is dependent on the AVP type. This function calls the "type_data_interpret" callback 
- * of the type.
- *
- * RETURN VALUE:
- *  0      	: The avp_value has been set.
- *  EINVAL 	: A parameter is invalid.
- *  ENOTSUP 	: There is no appropriate callback registered with this AVP's type.
- */
-int fd_msg_avp_value_interpret ( struct avp *avp, void *data );
-
-
-/***************************************/
-/*   Message parsing functions         */
-/***************************************/
-
-/*
- * FUNCTION:	fd_msg_bufferize
- *
- * PARAMETERS:
- *  msg		: A valid msg object. All AVPs must have a value set. 
- *  buffer 	: Upon success, this points to a buffer (malloc'd) containing the message ready for network transmission (or security transformations). 
- *		 The buffer may be freed after use.
- *  len		: if not NULL, the size of the buffer is written here. In any case, this size is updated in the msg header.
- *
- * DESCRIPTION: 
- *   Renders a message in memory as a buffer that can be sent over the network to the next peer.
- *
- * RETURN VALUE:
- *  0      	: The location has been written.
- *  EINVAL 	: The buffer does not contain a valid Diameter message.
- *  ENOMEM	: Unable to allocate enough memory to create the buffer object.
- */
-int fd_msg_bufferize ( struct msg * msg, unsigned char ** buffer, size_t * len );
-
-/*
- * FUNCTION:	fd_msg_parse_buffer
- *
- * PARAMETERS:
- *  buffer 	: Pointer to a buffer containing a message received from the network. 
- *  buflen	: the size in bytes of the buffer.
- *  msg		: Upon success, this points to a valid msg object. No AVP value is resolved in this object, nor grouped AVP.
- *
- * DESCRIPTION: 
- *   This function parses a buffer an creates a msg object to represent the structure of the message.
- *  Since no dictionary lookup is performed, the values of the AVPs are not interpreted. To interpret the values,
- *  the returned message object must be passed to fd_msg_parse_dict function.
- *  The buffer pointer is saved inside the message and will be freed when not needed anymore.
- *
- * RETURN VALUE:
- *  0      	: The location has been written.
- *  ENOMEM	: Unable to allocate enough memory to create the msg object.
- *  EBADMSG	: The buffer does not contain a valid Diameter message (or is truncated).
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_msg_parse_buffer ( unsigned char ** buffer, size_t buflen, struct msg ** msg );
-
-/* Parsing Error Information structure */
-struct fd_pei {
-	char *		pei_errcode;	/* name of the error code to use */
-	struct avp *	pei_avp;	/* pointer to invalid or missing AVP (to be freed) */
-	char *		pei_message;	/* Overwrite default message if needed */
-	int		pei_protoerr; 	/* do we set the 'E' bit in the error message ? */
-};
-
-/*
- * FUNCTION:	fd_msg_parse_dict
- *
- * PARAMETERS:
- *  object	: A msg or AVP object as returned by fd_msg_parse_buffer.
- *  dict	: the dictionary containing the objects definitions to use for resolving all AVPs.
- *  error_info	: If not NULL, will contain the detail about error upon return. May be used to generate an error reply.
- *
- * DESCRIPTION: 
- *   This function looks up for the command and each children AVP definitions in the dictionary.
- *  If the dictionary definition is found, avp_model is set and the value of the AVP is interpreted accordingly and:
- *   - for grouped AVPs, the children AVP are created and interpreted also.
- *   - for numerical AVPs, the value is converted to host byte order and saved in the avp_value field.
- *   - for octetstring AVPs, the string is copied into a new buffer and its address is saved in avp_value. 
- *  If the dictionary definition is not found, avp_model is set to NULL and
- *  the content of the AVP is saved as an octetstring in an internal structure. avp_value is NULL.
- *  As a result, after this function has been called, there is no more dependency of the msg object to the message buffer, that is freed.
- *
- * RETURN VALUE:
- *  0      	: The message has been fully parsed as described.
- *  EINVAL 	: The msg parameter is invalid for this operation.
- *  ENOMEM	: Unable to allocate enough memory to complete the operation.
- *  ENOTSUP	: No dictionary definition for the command or one of the mandatory AVP was found.
- */
-int fd_msg_parse_dict ( msg_or_avp * object, struct dictionary * dict, struct fd_pei * error_info );
-
-/*
- * FUNCTION:	fd_msg_parse_rules
- *
- * PARAMETERS:
- *  object	: A msg or grouped avp object that must be verified.
- *  dict	: The dictionary containing the rules definitions.
- *  error_info	: If not NULL, the first problem information will be saved here.
- *
- * DESCRIPTION: 
- *   Check that the children of the object do not conflict with the dictionary rules (ABNF compliance).
- *
- * RETURN VALUE:
- *  0      	: The message has been fully parsed and complies to the defined rules.
- *  EBADMSG	: A conflict was detected, or a mandatory AVP is unknown in the dictionary.
- *  EINVAL 	: The msg or avp object is invalid for this operation.
- *  ENOMEM	: Unable to allocate enough memory to complete the operation.
- */
-int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct fd_pei * error_info);
-
-
-
-/*
- * FUNCTION:	fd_msg_update_length
- *
- * PARAMETERS:
- *  object 	: Pointer to a valid msg or avp. 
- *
- * DESCRIPTION: 
- *   Update the length field of the object passed as parameter.
- * As a side effect, all children objects are also updated. Therefore, all avp_value fields of
- * the children AVPs must be set, or an error will occur.
- *
- * RETURN VALUE:
- *  0      	: The size has been recomputed.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_msg_update_length ( msg_or_avp * object );
-
-
-/*============================================================*/
-/*                         DISPATCH                           */
-/*============================================================*/
-
-/* Dispatch module (passing incoming messages to extensions registered callbacks)
- * is split between the library and the daemon.
- *
- * The library provides the support for associating dispatch callbacks with
- * dictionary objects.
- *
- * The daemon is responsible for calling the callbacks for a message when appropriate.
- *
- *
- * The dispatch module has two main roles:
- *  - help determine if a message can be handled locally (during the routing step)
- *        This decision involves only the application-id of the message.
- *  - pass the message to the callback(s) that will handle it (during the dispatch step)
- *
- * The first role is handled by the daemon.
- *
- * About the second, these are the possibilities for registering a dispatch callback:
- *
- * -> For All messages.
- *  This callback is called for all messages that are handled locally. This should be used only
- *  for debug purpose.
- *
- * -> by AVP value (constants only).
- *  This callback will be called when a message is received and contains an AVP with a specified enumerated value.
- *
- * -> by AVP.
- *  This callback will be called when the received message contains a certain AVP.
- *
- * -> by command-code.
- *  This callback will be called when the message is a specific command (and 'R' flag).
- *
- * -> by application.
- *  This callback will be called when the message has a specific application-id.
- *
- * ( by vendor: would this be useful? it may be added later)
- */
-enum disp_how {
-	DISP_HOW_ANY = 1,		/* Any message. This should be only used for debug. */
-	DISP_HOW_APPID,			/* Any message with the specified application-id */
-	DISP_HOW_CC,			/* Messages of the specified command-code (request or answer). App id may be specified. */
-	DISP_HOW_AVP,			/* Messages containing a specific AVP. Command-code and App id may be specified. */
-	DISP_HOW_AVP_ENUMVAL		/* Messages containing a specific AVP with a specific enumerated value. Command-code and App id may be specified. */
-};
-/*
- * Several criteria may be selected at the same time, for example command-code AND application id.
- *
- * If several callbacks are registered for the same object, they are called in the order they were registered.
- * The order in which the callbacks are called is:
- *  DISP_HOW_ANY
- *  DISP_HOW_AVP_ENUMVAL & DISP_HOW_AVP
- *  DISP_HOW_CC
- *  DISP_HOW_APPID
- */
-
-/* When a callback is registered, a "when" argument is passed in addition to the disp_how value,
- * to specify which values the criteria must match. */
-struct disp_when {
-	struct dict_object *	app;
-	struct dict_object *	command;
-	struct dict_object *	avp;
-	struct dict_object *	value;
-};
-
-/* Note that all the dictionary objects should really belong to the same dictionary!
- *
- * Here is the details on this "when" argument, depending on the disp_how value.
- *
- * DISP_HOW_ANY.
- *  In this case, "when" must be NULL.
- *
- * DISP_HOW_APPID.
- *  Only the "app_id" field must be set, other fields are ignored. It points to a dictionary object of type DICT_APPLICATION.
- *
- * DISP_HOW_CC.
- *  The "command" field must be defined and point to a dictionary object of type DICT_COMMAND.
- *  The "app_id" may be also set. In the case it is set, it restricts the callback to be called only with this command-code and app id.
- *  The other fields are ignored.
- *
- * DISP_HOW_AVP.
- *  The "avp" field of the structure must be set and point to a dictionary object of type DICT_AVP.
- *  The "app_id" field may be set to restrict the messages matching to a specific app id.
- *  The "command" field may also be set to a valid DICT_COMMAND object.
- *  The content of the "value" field is ignored.
- *
- * DISP_HOW_AVP_ENUMVAL.
- *  All fields have the same constraints and meaning as in DISP_REG_AVP. In addition, the "value" field must be set
- *  and points to a valid DICT_ENUMVAL object. 
- *
- * Here is a sumary of the fields: ( M : must be set; m : may be set; 0 : ignored )
- *  field:     app_id    command     avp    value
- * APPID :       M          0         0       0
- * CC    :       m          M         0       0
- * AVP   :       m          m         M       0
- * ENUMVA:       m          m         M       M
- */
-
-enum disp_action {
-	DISP_ACT_CONT,	/* The next handler should be called, unless *msg == NULL. */
-	DISP_ACT_SEND,	/* The updated message must be sent. No further callback is called. */
-	DISP_ACT_ERROR	/* An error must be created and sent as a reply -- not valid for callbacks, only for fd_msg_dispatch. */
-};
-/* The callbacks that are registered have the following prototype:
- *  	int dispatch_callback( struct msg ** msg, struct avp * avp, struct session * session, enum disp_action * action );
- *
- * CALLBACK:	dispatch_callback
- *
- * PARAMETERS:
- *  msg 	: the received message on function entry. may be updated to answer on return (see description)
- *  avp 	: for callbacks registered with DISP_HOW_AVP or DISP_HOW_AVP_ENUMVAL, direct link to the triggering AVP.
- *  session	: if the message contains a Session-Id AVP, the corresponding session object, NULL otherwise.
- *  opaque      : An opaque pointer that is registered along the session handler.
- *  action	: upon return, this tells the daemon what to do next.
- *
- * DESCRIPTION: 
- *   Called when a received message matchs the condition for which the callback was registered.
- * This callback may do any kind of processing on the message, including:
- *  - create an answer for a request.
- *  - proxy a request or message, add / remove the Proxy-Info AVP, then forward the message.
- *  - update a routing table or start a connection with a new peer, then forward the message.
- *  - ...
- * 
- * When *action == DISP_ACT_SEND on callback return, the msg pointed by *msg is passed to the routing module for sending.
- * When *action == DISP_ACT_CONT, the next registered callback is called.
- *  When the last callback gives also DISP_ACT_CONT action value, a default handler is called. It's behavior is as follow:
- *   - if the message is an answer, it is discarded.
- *   - if the message is a request, it is passed again to the routing stack, and marked as non-local handling.
- *
- * RETURN VALUE:
- *  0      	: The callback executed successfully and updated *action appropriately.
- *  !0		: standard errors. In case of error, the message is discarded.
- */
-
-/* This structure represents a handler for a registered callback, allowing its de-registration */
-struct disp_hdl;
-
-/*
- * FUNCTION:	fd_disp_register
- *
- * PARAMETERS:
- *  cb 		  : The callback function to register (see dispatch_callback description above).
- *  how	  	  : How the callback must be registered.
- *  when          : Values that must match, depending on the how argument.
- *  opaque        : A pointer that is passed back to the handler. The content is not interpreted by the framework.
- *  handle        : On success, a handler to the registered callback is stored here if not NULL. 
- *		   This handler can be used to unregister the cb.
- *
- * DESCRIPTION: 
- *   Register a new callback to handle messages delivered locally.
- *
- * RETURN VALUE:
- *  0      	: The callback is registered.
- *  EINVAL 	: A parameter is invalid.
- *  ENOMEM	: Not enough memory to complete the operation
- */
-int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, void *, enum disp_action *), 
-			enum disp_how how, struct disp_when * when, void * opaque, struct disp_hdl ** handle );
-
-/*
- * FUNCTION:	fd_disp_unregister
- *
- * PARAMETERS:
- *  handle       : Location of the handle of the callback that must be unregistered.
- *  opaque       : If not NULL, the opaque data that was registered is restored here.
- *
- * DESCRIPTION: 
- *   Removes a callback previously registered by fd_disp_register.
- *
- * RETURN VALUE:
- *  0      	: The callback is unregistered.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_disp_unregister ( struct disp_hdl ** handle, void ** opaque );
-
-/* Destroy all handlers */
-void fd_disp_unregister_all ( void );
-
-/*
- * FUNCTION:	fd_msg_dispatch
- *
- * PARAMETERS:
- *  msg 	: A msg object that have already been fd_msg_parse_dict.
- *  session	: The session corresponding to this object, if any.
- *  action	: Upon return, the action that must be taken on the message
- *
- * DESCRIPTION: 
- *   Call all handlers registered for a given message.
- *  The session must have already been resolved on entry.
- *  The msg pointed may be updated during this process.
- *  Upon return, the action parameter points to what must be done next.
- *
- * RETURN VALUE:
- *  0      	: Success.
- *  EINVAL 	: A parameter is invalid.
- *  (other errors)
- */
-int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, const char ** error_code );
-
-
-
-/*============================================================*/
-/*                     QUEUES                                 */
-/*============================================================*/
-
-/* Management of FIFO queues of elements */
-
-/* A queue is an opaque object */
-struct fifo;
-
-/*
- * FUNCTION:	fd_fifo_new
- *
- * PARAMETERS:
- *  queue	: Upon success, a pointer to the new queue is saved here.
- *
- * DESCRIPTION: 
- *  Create a new empty queue.
- *
- * RETURN VALUE :
- *  0		: The queue has been initialized successfully.
- *  EINVAL 	: The parameter is invalid.
- *  ENOMEM	: Not enough memory to complete the creation.  
- */
-int fd_fifo_new ( struct fifo ** queue );
-
-/*
- * FUNCTION:	fd_fifo_del
- *
- * PARAMETERS:
- *  queue	: Pointer to an empty queue to delete.
- *
- * DESCRIPTION: 
- *  Destroys a queue. This is only possible if no thread is waiting for an element,
- * and the queue is empty.
- *
- * RETURN VALUE:
- *  0		: The queue has been destroyed successfully.
- *  EINVAL 	: The parameter is invalid.
- */
-int fd_fifo_del ( struct fifo  ** queue );
-
-/*
- * FUNCTION:	fd_fifo_move
- *
- * PARAMETERS:
- *  oldq	: Location of a FIFO that is to be emptied.
- *  newq	: A FIFO that will receive the old data.
- *  loc_update	: if non NULL, a place to store the pointer to new FIFO atomically with the move.
- *
- * DESCRIPTION: 
- *  Empties a queue and move its content to another one atomically.
- *
- * RETURN VALUE:
- *  0		: The queue has been destroyed successfully.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_fifo_move ( struct fifo * oldq, struct fifo * newq, struct fifo ** loc_update );
-
-/*
- * FUNCTION:	fd_fifo_length
- *
- * PARAMETERS:
- *  queue	: The queue from which to retrieve the number of elements.
- *  length	: Upon success, the current number of elements in the queue is stored here.
- *
- * DESCRIPTION: 
- *  Retrieve the number of elements in a queue.
- *
- * RETURN VALUE:
- *  0		: The length of the queue has been written.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_fifo_length ( struct fifo * queue, int * length );
-int fd_fifo_length_noerr ( struct fifo * queue ); /* no error checking version */
-
-/*
- * FUNCTION:	fd_fifo_setthrhd
- *
- * PARAMETERS:
- *  queue	: The queue for which the thresholds are being set.
- *  data	: An opaque pointer that is passed to h_cb and l_cb callbacks.
- *  high        : The high-level threshold. If the number of elements in the queue increase to this value, h_cb is called.
- *  h_cb        : if not NULL, a callback to call when the queue lengh is bigger than "high".
- *  low         : The low-level threshold. Must be < high.
- *  l_cb        : If the number of elements decrease to low, this callback is called.
- *
- * DESCRIPTION: 
- *  This function allows to adjust the number of producer / consumer threads of a queue.
- * If the consumer are slower than the producers, the number of elements in the queue increase.
- * By setting a "high" value, we allow a callback to be called when this number is too high.
- * The typical use would be to create an additional consumer thread in this callback.
- * If the queue continues to grow, the callback will be called again when the length is 2 * high, then 3*high, ... N * high
- * (the callback itself should implement a limit on the number of consumers that can be created)
- * When the queue starts to decrease, and the number of elements go under ((N - 1) * high + low, the l_cb callback is called
- * and would typially stop one of the consumer threads. If the queue continues to reduce, l_cb is again called at (N-2)*high + low,
- * and so on.
- *
- * Since there is no destructor for the data pointer, if cleanup operations are required, they should be performed in
- * l_cb when the length of the queue is becoming < low.
- *
- * Note that the callbacks are called synchronously, during fd_fifo_post or fd_fifo_get. Their operation should be quick.
- *
- * RETURN VALUE:
- *  0		: The thresholds have been set
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_fifo_setthrhd ( struct fifo * queue, void * data, uint16_t high, void (*h_cb)(struct fifo *, void **), uint16_t low, void (*l_cb)(struct fifo *, void **) );
-
-/*
- * FUNCTION:	fd_fifo_post
- *
- * PARAMETERS:
- *  queue	: The queue in which the element must be posted.
- *  item	: The element that is put in the queue.
- *
- * DESCRIPTION: 
- *  An element is added in a queue. Elements are retrieved from the queue in FIFO order
- *  with the fd_fifo_get, fd_fifo_tryget, or fd_fifo_timedget functions.
- *
- * RETURN VALUE:
- *  0		: The element is queued.
- *  EINVAL 	: A parameter is invalid.
- *  ENOMEM 	: Not enough memory to complete the operation.
- */
-int fd_fifo_post_int ( struct fifo * queue, void ** item );
-#define fd_fifo_post(queue, item) \
-	fd_fifo_post_int((queue), (void *)(item))
-
-/*
- * FUNCTION:	fd_fifo_get
- *
- * PARAMETERS:
- *  queue	: The queue from which the first element must be retrieved.
- *  item	: On return, the first element of the queue is stored here.
- *
- * DESCRIPTION: 
- *  This function retrieves the first element from a queue. If the queue is empty, the function will block the 
- * thread until a new element is posted to the queue, or until the thread is canceled (in which case the 
- * function does not return).
- *
- * RETURN VALUE:
- *  0		: A new element has been retrieved.
- *  EINVAL 	: A parameter is invalid.
- */
-int fd_fifo_get_int ( struct fifo * queue, void ** item );
-#define fd_fifo_get(queue, item) \
-	fd_fifo_get_int((queue), (void *)(item))
-
-/*
- * FUNCTION:	fd_fifo_tryget
- *
- * PARAMETERS:
- *  queue	: The queue from which the element must be retrieved.
- *  item	: On return, the first element of the queue is stored here.
- *
- * DESCRIPTION: 
- *  This function is similar to fd_fifo_get, except that it will not block if 
- * the queue is empty, but return EWOULDBLOCK instead.
- *
- * RETURN VALUE:
- *  0		: A new element has been retrieved.
- *  EINVAL 	: A parameter is invalid.
- *  EWOULDBLOCK : The queue was empty.
- */
-int fd_fifo_tryget_int ( struct fifo * queue, void ** item );
-#define fd_fifo_tryget(queue, item) \
-	fd_fifo_tryget_int((queue), (void *)(item))
-
-/*
- * FUNCTION:	fd_fifo_timedget
- *
- * PARAMETERS:
- *  queue	: The queue from which the element must be retrieved.
- *  item	: On return, the element is stored here.
- *  abstime	: the absolute time until which we allow waiting for an item.
- *
- * DESCRIPTION: 
- *  This function is similar to fd_fifo_get, except that it will block if the queue is empty 
- * only until the absolute time abstime (see pthread_cond_timedwait for + info).
- * If the queue is still empty when the time expires, the function returns ETIMEDOUT
- *
- * RETURN VALUE:
- *  0		: A new item has been retrieved.
- *  EINVAL 	: A parameter is invalid.
- *  ETIMEDOUT   : The time out has passed and no item has been received.
- */
-int fd_fifo_timedget_int ( struct fifo * queue, void ** item, const struct timespec *abstime );
-#define fd_fifo_timedget(queue, item, abstime) \
-	fd_fifo_timedget_int((queue), (void *)(item), (abstime))
-
-/* Dump a fifo list and optionally its inner elements -- beware of deadlocks! */
-void fd_fifo_dump(int level, char * name, struct fifo * queue, void (*dump_item)(int level, void * item));
-
-#endif /* _LIBFREEDIAMETER_H */
