changeset 950:51c15f98a965

merge current version from 1.1 branch (927:877592751fee).
author Thomas Klausner <tk@giga.or.at>
date Thu, 21 Feb 2013 11:57:32 +0100
parents ad5c976e0dc7 (current diff) 877592751fee (diff)
children f97fa305467f
files include/freeDiameter/libfdproto.h libfdcore/fdd.l libfdcore/fdd.y libfdcore/peers.c libfdcore/sctp.c
diffstat 22 files changed, 452 insertions(+), 283 deletions(-) [+]
line wrap: on
line diff
--- a/INSTALL.FreeBSD	Thu Feb 21 11:52:53 2013 +0100
+++ b/INSTALL.FreeBSD	Thu Feb 21 11:57:32 2013 +0100
@@ -8,7 +8,7 @@
  cmake flex bison gnutls
 
 Then the cmake command had to look like:
- cmake -DFLEX_EXECUTABLE:FILEPATH=/usr/local/bin/flex ...
+ cmake -DFLEX_EXECUTABLE:FILEPATH=/usr/local/bin/flex -DSCTP_USE_MAPPED_ADDRESSES:BOOL=ON ...
 
 
 ---------------------
@@ -45,7 +45,7 @@
    # cd fD-build
    
 7) Run cmake for freeDiameter (add other flags as you see fit, see INSTALL for more details)
-   # /usr/local/bin/cmake -DFLEX_EXECUTABLE:FILEPATH=/usr/local/bin/flex ../freeDiameter
+   # /usr/local/bin/cmake -DFLEX_EXECUTABLE:FILEPATH=/usr/local/bin/flex -DSCTP_USE_MAPPED_ADDRESSES:BOOL=ON ../freeDiameter
 
 8) Compile, optionnaly test
    # make
--- a/extensions/app_radgw/rgwx_auth.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/extensions/app_radgw/rgwx_auth.c	Thu Feb 21 11:57:32 2013 +0100
@@ -457,7 +457,7 @@
 		
 		if (si_len) {
 			/* We already have the Session-Id, just use it */
-			CHECK_FCT( fd_sess_fromsid ( si, si_len, session, NULL) );
+			CHECK_FCT( fd_sess_fromsid_msg ( si, si_len, session, NULL) );
 		} else {
 			/* Create a new Session-Id string */
 			
@@ -495,6 +495,7 @@
 		value.os.len = sess_strlen;
 		CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
 		CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
+		CHECK_FCT( fd_msg_sess_set( *diam_fw, *session) );
 	}
 	
 	
--- a/extensions/app_radgw/rgwx_sip.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/extensions/app_radgw/rgwx_sip.c	Thu Feb 21 11:57:32 2013 +0100
@@ -479,6 +479,7 @@
 	value.os.len = sidlen;
 	CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
 	CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
+	CHECK_FCT( fd_msg_sess_set( *diam_fw, *session) );
 	
 	/*
 	If the RADIUS Access-Request message does not
--- a/extensions/app_sip/registrationtermination.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/extensions/app_sip/registrationtermination.c	Thu Feb 21 11:57:32 2013 +0100
@@ -147,15 +147,7 @@
 	// Create a new session 
 	{
 		#define APP_SIP_SID_OPT  "app_sip"
-		CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)APP_SIP_SID_OPT, CONSTSTRLEN(APP_SIP_SID_OPT) ));
-		os0_t sid;
-		size_t sidlen;
-		CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
-		CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
-		value.os.data = sid;
-		value.os.len  = sidlen;
-		CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
-		CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
+		CHECK_FCT( fd_msg_new_session( message, (os0_t)APP_SIP_SID_OPT, CONSTSTRLEN(APP_SIP_SID_OPT) ) );
 	}
 	
 	//Add the Auth-Application-Id 
--- a/extensions/test_app/ta_bench.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/extensions/test_app/ta_bench.c	Thu Feb 21 11:57:32 2013 +0100
@@ -121,7 +121,6 @@
 	struct avp * avp;
 	union avp_value val;
 	struct ta_mess_info * mi = NULL;
-	struct session *sess = NULL;
 	
 	TRACE_DEBUG(FULL, "Creating a new message for sending.");
 	
@@ -130,7 +129,7 @@
 	
 	/* Create a new session */
 	#define TEST_APP_SID_OPT  "app_testb"
-	CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
+	CHECK_FCT_DO( fd_msg_new_session( req, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
 	
 	/* Create the random value to store with the session */
 	mi = malloc(sizeof(struct ta_mess_info));
@@ -143,19 +142,6 @@
 	
 	/* Now set all AVPs values */
 	
-	/* Session-Id */
-	{
-		os0_t sid;
-		size_t sidlen;
-		CHECK_FCT_DO( fd_sess_getsid ( sess, &sid, &sidlen ), goto out );
-		CHECK_FCT_DO( fd_msg_avp_new ( ta_sess_id, 0, &avp ), goto out );
-		val.os.data = sid;
-		val.os.len  = sidlen;
-		CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
-		CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ), goto out );
-		
-	}
-	
 	/* Set the Destination-Realm AVP */
 	{
 		CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_realm, 0, &avp ), goto out  );
--- a/extensions/test_app/ta_cli.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/extensions/test_app/ta_cli.c	Thu Feb 21 11:57:32 2013 +0100
@@ -150,7 +150,8 @@
 	
 	/* Create a new session */
 	#define TEST_APP_SID_OPT  "app_test"
-	CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
+	CHECK_FCT_DO( fd_msg_new_session( req, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
+	CHECK_FCT_DO( fd_msg_sess_get(fd_g_config->cnf_dict, req, &sess, NULL), goto out );
 	
 	/* Create the random value to store with the session */
 	mi = malloc(sizeof(struct ta_mess_info));
@@ -163,19 +164,6 @@
 	
 	/* Now set all AVPs values */
 	
-	/* Session-Id */
-	{
-		os0_t sid;
-		size_t sidlen;
-		CHECK_FCT_DO( fd_sess_getsid ( sess, &sid, &sidlen ), goto out );
-		CHECK_FCT_DO( fd_msg_avp_new ( ta_sess_id, 0, &avp ), goto out );
-		val.os.data = sid;
-		val.os.len  = sidlen;
-		CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
-		CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ), goto out );
-		
-	}
-	
 	/* Set the Destination-Realm AVP */
 	{
 		CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_realm, 0, &avp ), goto out  );
--- a/extensions/test_sip/locationinfo.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/extensions/test_sip/locationinfo.c	Thu Feb 21 11:57:32 2013 +0100
@@ -41,7 +41,6 @@
 	struct dict_object * lir_model=NULL;
 	struct msg * message=NULL;
 	struct avp *avp=NULL;
-	struct session *sess=NULL;
 	union avp_value value;
 	
 	//Fake values START
@@ -61,15 +60,7 @@
 		
 	// Create a new session 
 	{
-		CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 ));
-		os0_t sid;
-		size_t sidlen;
-		CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
-		CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
-		value.os.data = sid;
-		value.os.len  = sidlen;
-		CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
-		CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
+		CHECK_FCT( fd_msg_new_session( message, (os0_t)"appsip", CONSTSTRLEN("appsip") ) );
 	}
 	
 	//Add the Auth-Application-Id 
--- a/extensions/test_sip/locationinfosl.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/extensions/test_sip/locationinfosl.c	Thu Feb 21 11:57:32 2013 +0100
@@ -41,7 +41,6 @@
 	struct dict_object * lir_model=NULL;
 	struct msg * message=NULL;
 	struct avp *avp=NULL;
-	struct session *sess=NULL;
 	union avp_value value;
 	
 	//Fake values START
@@ -61,15 +60,7 @@
 		
 	// Create a new session 
 	{
-		CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 ));
-		os0_t sid;
-		size_t sidlen;
-		CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
-		CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
-		value.os.data = sid;
-		value.os.len  = sidlen;
-		CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
-		CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
+		CHECK_FCT( fd_msg_new_session( message, (os0_t)"appsip", CONSTSTRLEN("appsip") ) );
 	}
 	
 	//Add the Auth-Application-Id 
--- a/extensions/test_sip/serverassignment.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/extensions/test_sip/serverassignment.c	Thu Feb 21 11:57:32 2013 +0100
@@ -41,7 +41,6 @@
 	struct dict_object * sar_model=NULL;
 	struct msg * message=NULL;
 	struct avp *avp=NULL;
-	struct session *sess=NULL;
 	union avp_value value;
 	
 	//Fake values START
@@ -70,15 +69,7 @@
 	
 	// Create a new session 
 	{
-		CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 ));
-		os0_t sid;
-		size_t sidlen;
-		CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
-		CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
-		value.os.data = sid;
-		value.os.len  = sidlen;
-		CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
-		CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
+		CHECK_FCT( fd_msg_new_session( message, (os0_t)"appsip", CONSTSTRLEN("appsip") ) );
 	}
 	
 	//Add the Auth-Application-Id 
--- a/extensions/test_sip/userauthorization.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/extensions/test_sip/userauthorization.c	Thu Feb 21 11:57:32 2013 +0100
@@ -41,7 +41,6 @@
 	struct dict_object * uar_model=NULL;
 	struct msg * message=NULL;
 	struct avp *avp=NULL;
-	struct session *sess=NULL;
 	union avp_value value;
 	
 	//Fake values START
@@ -66,15 +65,7 @@
 	
 	// Create a new session 
 	{
-		CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 ));
-		os0_t sid;
-		size_t sidlen;
-		CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
-		CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
-		value.os.data = sid;
-		value.os.len  = sidlen;
-		CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
-		CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
+		CHECK_FCT( fd_msg_new_session( message, (os0_t)"appsip", CONSTSTRLEN("appsip") ) );
 	}
 	
 	//Add the Auth-Application-Id 
--- a/include/freeDiameter/libfdproto.h	Thu Feb 21 11:52:53 2013 +0100
+++ b/include/freeDiameter/libfdproto.h	Thu Feb 21 11:57:32 2013 +0100
@@ -1157,6 +1157,26 @@
 	TYPE_OF_AVP			/* "what" points to a struct dict_object containing an AVP object. */
 };
 
+/****
+ Callbacks defined in libfdproto/dictionary_functions.c file -- see that file for usage. 
+ */
+
+/* Convert an Address type AVP into a struct sockaddr_storage */
+int fd_dictfct_Address_encode(void * data, union avp_value * avp_value);
+int fd_dictfct_Address_interpret(union avp_value * avp_value, void * interpreted);
+char * fd_dictfct_Address_dump(union avp_value * avp_value);
+
+/* Display the content of an AVP of type UTF8String in the log file */
+char * fd_dictfct_UTF8String_dump(union avp_value * avp_value);
+
+/* For Time AVPs, map with time_t value directly */
+int fd_dictfct_Time_encode(void * data, union avp_value * avp_value);
+int fd_dictfct_Time_interpret(union avp_value * avp_value, void * interpreted);
+char * fd_dictfct_Time_dump(union avp_value * avp_value);
+
+
+
+/****/
 
 /***
  *  API usage :
@@ -1187,7 +1207,7 @@
  }
  
 */
-	 
+
 /*
  ***************************************************************************
  *
@@ -1789,9 +1809,9 @@
  *  If diamId is NULL, the string is exactly the content of opt.
  *
  * RETURN VALUE:
- *  0      	: The session is created.
+ *  0      	: The session is created, the initial msg refcount is 1.
  *  EINVAL 	: A parameter is invalid.
- *  EALREADY	: A session with the same name already exists (returned in *session)
+ *  EALREADY	: A session with the same name already exists (returned in *session), the msg refcount is increased.
  *  ENOMEM	: Not enough memory to complete the operation
  */
 int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen );
@@ -2478,6 +2498,10 @@
  */
 int fd_msg_sess_get(struct dictionary * dict, struct msg * msg, struct session ** session, int * isnew);
 
+/* This one is used by the libfdcore, you should use fd_msg_new_session rather than fd_sess_new, when possible */
+int fd_msg_sess_set(struct msg * msg, struct session * session);
+
+
 /***************************************/
 /*   Manage AVP values                 */
 /***************************************/
--- a/libfdcore/dict_base_proto.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdcore/dict_base_proto.c	Thu Feb 21 11:57:32 2013 +0100
@@ -44,169 +44,6 @@
 /* The pointer for the global dictionary (initialized from main) */
 struct dictionary * fd_g_dict = NULL;
 
-/* The functions to encode and interpret the derived types defined in the base protocol */
-
-/* Address AVP <-> struct sockaddr_storage */
-static int Address_encode(void * data, union avp_value * avp_value)
-{
-	sSS * ss = (sSS *) data;
-	uint16_t AddressType = 0;
-	size_t	size = 0;
-	unsigned char * buf = NULL;
-	
-	TRACE_ENTRY("%p %p", data, avp_value);
-	CHECK_PARAMS( data && avp_value  );
-	
-	switch (ss->ss_family) {
-		case AF_INET:
-			{
-				/* We are encoding an IP address */
-				sSA4 * sin = (sSA4 *)ss;
-				
-				AddressType = 1;/* see http://www.iana.org/assignments/address-family-numbers/ */
-				size = 6;	/* 2 for AddressType + 4 for data */
-				
-				CHECK_MALLOC(  buf = malloc(size)  );
-				
-				/* may not work because of alignment: *(uint32_t *)(buf+2) = htonl(sin->sin_addr.s_addr); */
-				memcpy(buf + 2, &sin->sin_addr.s_addr, 4);
-			}
-			break;
-				
-		case AF_INET6:
-			{
-				/* We are encoding an IPv6 address */
-				sSA6 * sin6 = (sSA6 *)ss;
-				
-				AddressType = 2;/* see http://www.iana.org/assignments/address-family-numbers/ */
-				size = 18;	/* 2 for AddressType + 16 for data */
-				
-				CHECK_MALLOC(  buf = malloc(size)  );
-				
-				/* The order is already good here */
-				memcpy(buf + 2, &sin6->sin6_addr.s6_addr, 16);
-			}
-			break;
-				
-		default:
-			CHECK_PARAMS( AddressType = 0 );
-	}
-	
-	*(uint16_t *)buf = htons(AddressType);
-
-	avp_value->os.len = size;
-	avp_value->os.data = buf;
-	
-	return 0;
-}
-
-static int Address_interpret(union avp_value * avp_value, void * interpreted)
-{
-	uint16_t AddressType = 0;
-	unsigned char * buf;
-	
-	TRACE_ENTRY("%p %p", avp_value, interpreted);
-	
-	CHECK_PARAMS( avp_value && interpreted && (avp_value->os.len >= 2)  );
-	
-	AddressType = ntohs(*(uint16_t *)avp_value->os.data);
-	buf = &avp_value->os.data[2];
-	
-	switch (AddressType) {
-		case 1 /* IP */:
-			{
-				sSA4 * sin = (sSA4 *)interpreted;
-				
-				CHECK_PARAMS(  avp_value->os.len == 6  );
-				
-				sin->sin_family = AF_INET;
-				/* sin->sin_addr.s_addr = ntohl( * (uint32_t *) buf); -- may not work because of bad alignment */
-				memcpy(&sin->sin_addr.s_addr, buf, 4);
-			}
-			break;
-				
-		case 2 /* IP6 */:
-			{
-				sSA6 * sin6 = (sSA6 *)interpreted;
-				
-				CHECK_PARAMS(  avp_value->os.len == 18  );
-				
-				sin6->sin6_family = AF_INET6;
-				memcpy(&sin6->sin6_addr.s6_addr, buf, 16);
-			}
-			break;
-				
-		default:
-			CHECK_PARAMS( AddressType = 0 );
-	}
-	
-	return 0;
-}
-
-/* Dump the content of an Address AVP */
-static char * Address_dump(union avp_value * avp_value)
-{
-	char * ret;
-	#define STR_LEN	1024
-	union {
-		sSA	sa;
-		sSS	ss;
-		sSA4	sin;
-		sSA6	sin6;
-	} s;
-	uint16_t fam;
-	
-	memset(&s, 0, sizeof(s));
-	
-	CHECK_MALLOC_DO( ret = malloc(STR_LEN), return NULL );
-	
-	/* The first two octets represent the address family, http://www.iana.org/assignments/address-family-numbers/ */
-	if (avp_value->os.len < 2) {
-		snprintf(ret, STR_LEN, "[invalid length: %zd]", avp_value->os.len);
-		return ret;
-	}
-	
-	/* Following octets are the address in network byte order already */
-	fam = avp_value->os.data[0] << 8 | avp_value->os.data[1];
-	switch (fam) {
-		case 1:
-			/* IP */
-			s.sa.sa_family = AF_INET;
-			if (avp_value->os.len != 6) {
-				snprintf(ret, STR_LEN, "[invalid IP length: %zd]", avp_value->os.len);
-				return ret;
-			}
-			memcpy(&s.sin.sin_addr.s_addr, avp_value->os.data + 2, 4);
-			break;
-		case 2:
-			/* IP6 */
-			s.sa.sa_family = AF_INET6;
-			if (avp_value->os.len != 18) {
-				snprintf(ret, STR_LEN, "[invalid IP6 length: %zd]", avp_value->os.len);
-				return ret;
-			}
-			memcpy(&s.sin6.sin6_addr.s6_addr, avp_value->os.data + 2, 16);
-			break;
-		default:
-			snprintf(ret, STR_LEN, "[unsupported family: 0x%hx]", fam);
-			return ret;
-	}
-	
-	{
-		int rc = getnameinfo(&s.sa, sSAlen(&s.sa), ret, STR_LEN, NULL, 0, NI_NUMERICHOST);
-		if (rc)
-			snprintf(ret, STR_LEN, "%s", (char *)gai_strerror(rc));
-	}
-	
-	return ret;
-}
-
-static char * UTF8String_dump(union avp_value * avp_value)
-{
-	return strndup((char *)avp_value->os.data, 42); /* avoid very long strings */
-}
-
-
 
 
 #define CHECK_dict_new( _type, _data, _parent, _ref )				\
@@ -294,7 +131,7 @@
 				defined in [IANAADFAM].  The AddressType is used to discriminate
 				the content and format of the remaining octets.
 			*/
-			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"Address"		, Address_interpret	, Address_encode,	Address_dump	};
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"Address"		, fd_dictfct_Address_interpret	, fd_dictfct_Address_encode,	fd_dictfct_Address_dump	};
 			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
 		}
 		
@@ -313,7 +150,7 @@
 				SNTP [RFC4330] describes a procedure to extend the time to 2104.
 				This procedure MUST be supported by all DIAMETER nodes.
 			*/
-			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"Time"			, NULL			, NULL		, NULL		};
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"Time"			, fd_dictfct_Time_interpret	, fd_dictfct_Time_encode, 	fd_dictfct_Time_dump		};
 			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
 		}
 		
@@ -351,7 +188,7 @@
 				Note that the AVP Length field of an UTF8String is measured in
 				octets, not characters.
 			*/
-			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"UTF8String"		, NULL			, NULL	, UTF8String_dump	};
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"UTF8String"		, NULL			, NULL	, fd_dictfct_UTF8String_dump	};
 			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
 		}
 		
@@ -380,7 +217,7 @@
 				interactions between the Diameter protocol and Internationalized
 				Domain Name (IDNs).
 			*/
-			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"DiameterIdentity"	, NULL			, NULL		, UTF8String_dump	};
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"DiameterIdentity"	, NULL			, NULL		, fd_dictfct_UTF8String_dump	};
 			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
 		}
 		
@@ -435,7 +272,7 @@
 				aaa://host.example.com:6666;transport=tcp;protocol=diameter
 				aaa://host.example.com:1813;transport=udp;protocol=radius
 			*/
-			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"DiameterURI"		, NULL			, NULL		, UTF8String_dump	};
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"DiameterURI"		, NULL			, NULL		, fd_dictfct_UTF8String_dump	};
 			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
 		}
 		
@@ -497,7 +334,7 @@
 				supplied rules, for example to protect the access device owner's
 				infrastructure.
 			*/
-			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"IPFilterRule"		, NULL			, NULL		, UTF8String_dump	};
+			struct dict_type_data data = { AVP_TYPE_OCTETSTRING,	"IPFilterRule"		, NULL			, NULL		, fd_dictfct_UTF8String_dump	};
 			CHECK_dict_new( DICT_TYPE, &data , NULL, NULL);
 		}
 	}
--- a/libfdcore/fdd.l	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdcore/fdd.l	Thu Feb 21 11:57:32 2013 +0100
@@ -51,7 +51,8 @@
 #define YY_USER_ACTION { 						\
 	yylloc->first_column = yylloc->last_column + 1; 		\
 	yylloc->last_column = yylloc->first_column + yyleng - 1;	\
-	TRACE_DEBUG_ERROR("(%d:%d-%d:%d) matched rule %d, length=%d, txt='%s'\n",	\
+	TRACE_DEBUG_ERROR( 						\
+		"(%d:%d-%d:%d) matched rule %d, length=%d, txt='%s'\n",	\
 		yylloc->first_line, yylloc->first_column, 		\
 		yylloc->last_line, yylloc->last_column, 		\
 		yy_act, yyleng, yytext); 				\
@@ -144,7 +145,7 @@
 	/* Unrecognized token */
 <*>[[:alnum:]]+		|	/* This rule is only useful to print a complete token in error messages */
 	/* Unrecognized character */
-<*>.			{ 
+<*>.			{
 				TRACE_DEBUG_ERROR("Unrecognized text on line %d col %d: '%s'.\n", yylloc->first_line, yylloc->first_column, yytext);
 			 	return LEX_ERROR; 
 			}
--- a/libfdcore/fdd.y	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdcore/fdd.y	Thu Feb 21 11:57:32 2013 +0100
@@ -327,7 +327,7 @@
 				}
 				if (fd == NULL) {
 					int ret = errno;
-					TRACE_DEBUG(INFO, "Unable to open extension file %s for reading: %s\n", fname, strerror(ret));
+					TRACE_DEBUG_ERROR("Unable to open extension file %s for reading: %s\n", fname, strerror(ret));
 					yyerror (&yylloc, conf, "Error adding extension"); 
 					YYERROR;
 				}
@@ -501,7 +501,7 @@
 				fd = fopen($3, "r");
 				if (fd == NULL) {
 					int ret = errno;
-					TRACE_DEBUG(INFO, "Unable to open certificate file %s for reading: %s\n", $3, strerror(ret));
+					TRACE_DEBUG_ERROR("Unable to open certificate file %s for reading: %s\n", $3, strerror(ret));
 					yyerror (&yylloc, conf, "Error on file name"); 
 					YYERROR;
 				}
@@ -509,7 +509,7 @@
 				fd = fopen($5, "r");
 				if (fd == NULL) {
 					int ret = errno;
-					TRACE_DEBUG(INFO, "Unable to open private key file %s for reading: %s\n", $5, strerror(ret));
+					TRACE_DEBUG_ERROR("Unable to open private key file %s for reading: %s\n", $5, strerror(ret));
 					yyerror (&yylloc, conf, "Error on file name"); 
 					YYERROR;
 				}
@@ -532,7 +532,7 @@
 				fd = fopen($3, "rb");
 				if (fd == NULL) {
 					int ret = errno;
-					TRACE_DEBUG(INFO, "Unable to open CA file %s for reading: %s\n", $3, strerror(ret));
+					TRACE_DEBUG_ERROR("Unable to open CA file %s for reading: %s\n", $3, strerror(ret));
 					yyerror (&yylloc, conf, "Error on file name"); 
 					YYERROR;
 				}
@@ -572,7 +572,7 @@
 				fd = fopen($3, "rb");
 				if (fd == NULL) {
 					int ret = errno;
-					TRACE_DEBUG(INFO, "Unable to open CRL file %s for reading: %s\n", $3, strerror(ret));
+					TRACE_DEBUG_ERROR("Unable to open CRL file %s for reading: %s\n", $3, strerror(ret));
 					yyerror (&yylloc, conf, "Error on file name"); 
 					YYERROR;
 				}
@@ -615,7 +615,7 @@
 							conf->cnf_sec_data.prio_string,
 							&err_pos),
 						{ yyerror (&yylloc, conf, "Error setting Priority parameter.");
-						  fprintf(stderr, "Error at position : %s\n", err_pos);
+						  TRACE_DEBUG_ERROR("Error at position : %s\n", err_pos);
 						  YYERROR; } );
 			}
 			;
@@ -632,7 +632,7 @@
 				fd = fopen($3, "r");
 				if (fd == NULL) {
 					int ret = errno;
-					TRACE_DEBUG(INFO, "Unable to open DH file %s for reading: %s\n", $3, strerror(ret));
+					TRACE_DEBUG_ERROR("Unable to open DH file %s for reading: %s\n", $3, strerror(ret));
 					yyerror (&yylloc, conf, "Error on file name"); 
 					YYERROR;
 				}
--- a/libfdcore/messages.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdcore/messages.c	Thu Feb 21 11:57:32 2013 +0100
@@ -158,6 +158,9 @@
 	/* Add it to the message */
 	CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) );
 	
+	/* Save the session associated with the message */
+	CHECK_FCT( fd_msg_sess_set( msg, sess) );
+	
 	/* Done! */
 	return 0;
 }
@@ -283,7 +286,7 @@
 		if (set_e_bit)
 			hdr->msg_flags |= CMD_FLAG_ERROR;
 		else
-			hdr->msg_flags &= ! CMD_FLAG_ERROR;
+			hdr->msg_flags &= ~ CMD_FLAG_ERROR;
 	}
 	
 	if (std_err_msg || errormsg) {
--- a/libfdcore/peers.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdcore/peers.c	Thu Feb 21 11:57:32 2013 +0100
@@ -548,7 +548,7 @@
 	ev_data->cnx = *cnx;
 	ev_data->validate = !found;
 	
-	CHECK_FCT_DO( ret = fd_event_send(peer->p_events, FDEVP_CNX_INCOMING, sizeof(ev_data), ev_data), goto out );
+	CHECK_FCT_DO( ret = fd_event_send(peer->p_events, FDEVP_CNX_INCOMING, sizeof(*ev_data), ev_data), goto out );
 	
 out:	
 	CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
--- a/libfdcore/sctp.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdcore/sctp.c	Thu Feb 21 11:57:32 2013 +0100
@@ -653,7 +653,7 @@
 		#ifndef SCTP_USE_MAPPED_ADDRESSES
 		if (ep->sa.sa_family == AF_INET6)
 		#else /* SCTP_USE_MAPPED_ADDRESSES */
-		if (target_family == AF_INET6) {
+		if (target_family == AF_INET6)
 		#endif /* SCTP_USE_MAPPED_ADDRESSES */
 			sz = sizeof(sSA6);
 		else
@@ -1086,7 +1086,7 @@
 	
 	/* We will loop while all data is not received. */
 incomplete:
-	if (datasize == bufsz - sizeof(struct timespec)) {
+	while (datasize + sizeof(struct timespec) >= bufsz ) {
 		/* The buffer is full, enlarge it */
 		bufsz += mempagesz;
 		CHECK_MALLOC( data = realloc(data, bufsz ) );
--- a/libfdproto/CMakeLists.txt	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdproto/CMakeLists.txt	Thu Feb 21 11:57:32 2013 +0100
@@ -5,6 +5,7 @@
 SET(LFDPROTO_SRC
 	fdproto-internal.h
 	dictionary.c
+	dictionary_functions.c
 	dispatch.c
 	fifo.c
 	init.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfdproto/dictionary_functions.c	Thu Feb 21 11:57:32 2013 +0100
@@ -0,0 +1,331 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, 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.								 *
+*********************************************************************************************************/
+
+#include "fdproto-internal.h"
+
+/* This file contains helpers functions to be reused as callbacks in the struct dict_type_data structure.
+There are three callbacks there:
+
+ - type_encode    :
+ - type_interpret :
+ 	  Those two callbacks allow to manipulate more natural structures of data in the code, and to 
+	map transparently these natural structures with the AVP-encoded format by calling the functions
+	msg_avp_value_encode or msg_avp_value_interpret.
+ - type_dump : 
+ 	  This callback if provided gives a more human-readable debug information.
+
+ */
+
+/****************************/
+/*    Address  AVP  type    */
+/****************************/
+
+/* The interpret and encode functions work with a "struct sockaddr_storage" pointer for mapping 
+the contents of the AVP */
+
+int fd_dictfct_Address_encode(void * data, union avp_value * avp_value)
+{
+	sSS * ss = (sSS *) data;
+	uint16_t AddressType = 0;
+	size_t	size = 0;
+	unsigned char * buf = NULL;
+	
+	TRACE_ENTRY("%p %p", data, avp_value);
+	CHECK_PARAMS( data && avp_value  );
+	
+	switch (ss->ss_family) {
+		case AF_INET:
+			{
+				/* We are encoding an IP address */
+				sSA4 * sin = (sSA4 *)ss;
+				
+				AddressType = 1;/* see http://www.iana.org/assignments/address-family-numbers/ */
+				size = 6;	/* 2 for AddressType + 4 for data */
+				
+				CHECK_MALLOC(  buf = malloc(size)  );
+				
+				/* may not work because of alignment: *(uint32_t *)(buf+2) = htonl(sin->sin_addr.s_addr); */
+				memcpy(buf + 2, &sin->sin_addr.s_addr, 4);
+			}
+			break;
+				
+		case AF_INET6:
+			{
+				/* We are encoding an IPv6 address */
+				sSA6 * sin6 = (sSA6 *)ss;
+				
+				AddressType = 2;/* see http://www.iana.org/assignments/address-family-numbers/ */
+				size = 18;	/* 2 for AddressType + 16 for data */
+				
+				CHECK_MALLOC(  buf = malloc(size)  );
+				
+				/* The order is already good here */
+				memcpy(buf + 2, &sin6->sin6_addr.s6_addr, 16);
+			}
+			break;
+				
+		default:
+			CHECK_PARAMS( AddressType = 0 );
+	}
+	
+	*(uint16_t *)buf = htons(AddressType);
+
+	avp_value->os.len = size;
+	avp_value->os.data = buf;
+	
+	return 0;
+}
+
+int fd_dictfct_Address_interpret(union avp_value * avp_value, void * interpreted)
+{
+	uint16_t AddressType = 0;
+	unsigned char * buf;
+	
+	TRACE_ENTRY("%p %p", avp_value, interpreted);
+	
+	CHECK_PARAMS( avp_value && interpreted && (avp_value->os.len >= 2)  );
+	
+	AddressType = ntohs(*(uint16_t *)avp_value->os.data);
+	buf = &avp_value->os.data[2];
+	
+	switch (AddressType) {
+		case 1 /* IP */:
+			{
+				sSA4 * sin = (sSA4 *)interpreted;
+				
+				CHECK_PARAMS(  avp_value->os.len == 6  );
+				
+				sin->sin_family = AF_INET;
+				/* sin->sin_addr.s_addr = ntohl( * (uint32_t *) buf); -- may not work because of bad alignment */
+				memcpy(&sin->sin_addr.s_addr, buf, 4);
+			}
+			break;
+				
+		case 2 /* IP6 */:
+			{
+				sSA6 * sin6 = (sSA6 *)interpreted;
+				
+				CHECK_PARAMS(  avp_value->os.len == 18  );
+				
+				sin6->sin6_family = AF_INET6;
+				memcpy(&sin6->sin6_addr.s6_addr, buf, 16);
+			}
+			break;
+				
+		default:
+			CHECK_PARAMS( AddressType = 0 );
+	}
+	
+	return 0;
+}
+
+/* Dump the content of an Address AVP */
+char * fd_dictfct_Address_dump(union avp_value * avp_value)
+{
+	char * ret;
+	#define STR_LEN	1024
+	union {
+		sSA	sa;
+		sSS	ss;
+		sSA4	sin;
+		sSA6	sin6;
+	} s;
+	uint16_t fam;
+	
+	memset(&s, 0, sizeof(s));
+	
+	CHECK_MALLOC_DO( ret = malloc(STR_LEN), return NULL );
+	
+	/* The first two octets represent the address family, http://www.iana.org/assignments/address-family-numbers/ */
+	if (avp_value->os.len < 2) {
+		snprintf(ret, STR_LEN, "[invalid length: %zd]", avp_value->os.len);
+		return ret;
+	}
+	
+	/* Following octets are the address in network byte order already */
+	fam = avp_value->os.data[0] << 8 | avp_value->os.data[1];
+	switch (fam) {
+		case 1:
+			/* IP */
+			s.sa.sa_family = AF_INET;
+			if (avp_value->os.len != 6) {
+				snprintf(ret, STR_LEN, "[invalid IP length: %zd]", avp_value->os.len);
+				return ret;
+			}
+			memcpy(&s.sin.sin_addr.s_addr, avp_value->os.data + 2, 4);
+			break;
+		case 2:
+			/* IP6 */
+			s.sa.sa_family = AF_INET6;
+			if (avp_value->os.len != 18) {
+				snprintf(ret, STR_LEN, "[invalid IP6 length: %zd]", avp_value->os.len);
+				return ret;
+			}
+			memcpy(&s.sin6.sin6_addr.s6_addr, avp_value->os.data + 2, 16);
+			break;
+		default:
+			snprintf(ret, STR_LEN, "[unsupported family: 0x%hx]", fam);
+			return ret;
+	}
+	
+	{
+		int rc = getnameinfo(&s.sa, sSAlen(&s.sa), ret, STR_LEN, NULL, 0, NI_NUMERICHOST);
+		if (rc)
+			snprintf(ret, STR_LEN, "%s", (char *)gai_strerror(rc));
+	}
+	
+	return ret;
+}
+
+
+
+/*******************************/
+/*    UTF8String  AVP  type    */
+/*******************************/
+
+/* Dump the AVP in a natural human-readable format */
+char * fd_dictfct_UTF8String_dump(union avp_value * avp_value)
+{
+#define TRUNC_LEN	42 /* avoid very long strings */
+	char * ret = strndup((char *)avp_value->os.data, TRUNC_LEN); 
+	if (ret && (*ret != '\0')) {
+		/* We sanitize the returned string to avoid UTF8 boundary problem.
+		We do this whether the string is trucated at TRUNC_LEN or not, to avoid potential problem
+		with malformed AVP */
+
+		char * end = strchr(ret, '\0');
+		
+		while (end > ret) {
+			end--;
+			char b = *end;
+			/* after the position pointed by end, we have only \0s */
+			if ((b & 0x80) == 0) {
+				break; /* this is a single byte char, no problem */
+			} else {
+				/* this byte is start or cont. of multibyte sequence, as we do not know the next byte we need to delete it. */
+				*end = '\0';
+				if (b & 0x40)
+					break; /* This was a start byte, we can stop the loop */
+			}
+		}
+	}	
+	return ret;
+}
+
+
+/*******************************/
+/*    Time  AVP  type    */
+/*******************************/
+
+/* The interpret and encode functions work with a "time_t" pointer for mapping 
+the contents of the AVP */
+
+/* Unix Epoch starts 1970-01-01, NTP 0 is at 1900-01-01 */
+#define DIFF_EPOCH_TO_NTP ((365*(1970-1900) + 17ul) * 24 * 60 * 60)
+
+static int diameter_string_to_time_t(const char *str, size_t len, time_t *result) {
+    time_t time_stamp;
+    CHECK_PARAMS(len == 4);
+   
+    time_stamp = (((unsigned long)(str[0]&0xff))<<24) + ((str[1]&0xff)<<16) + ((str[2]&0xff)<<8) + ((str[3]&0xff));
+    time_stamp -= DIFF_EPOCH_TO_NTP;
+#ifdef FIX__NEEDED_FOR_YEAR_2036_AND_LATER
+/* NTP overflows in 2036; after that, values start at zero again */
+#define NTP_OVERFLOW_CORRECTION (0x100000000ull)
+    /* XXX: debug and find correct conversion */
+    if (str[0] & 0x80 == 0x00) {
+        time_stamp += NTP_OVERFLOW_CORRECTION;
+    }
+#endif
+    *result = time_stamp;
+    return 0;
+}
+
+static int time_t_to_diameter_string(time_t time_stamp, char **result) {
+    uint64_t out = time_stamp;
+    char *conv;
+    /* XXX: 2036 fix */
+    out += DIFF_EPOCH_TO_NTP;
+    CHECK_PARAMS( (out & 0xffffffff00000000) == 0);
+
+    CHECK_MALLOC(conv=(char *)malloc(5));
+    
+    conv[0] = (out>>24) & 0xff;
+    conv[1] = (out>>16) & 0xff;
+    conv[2] = (out>> 8) & 0xff;
+    conv[3] =  out      & 0xff;
+    conv[4] = '\0';
+    *result = conv;
+    return 0;
+}
+
+int fd_dictfct_Time_encode(void * data, union avp_value * avp_value)
+{
+	char * buf;
+	size_t len;
+	
+	TRACE_ENTRY("%p %p", data, avp_value);
+	CHECK_PARAMS( data && avp_value  );
+	
+	CHECK_FCT( time_t_to_diameter_string( *((time_t *)data), &buf) );
+	/* FIXME: return len from the function above? */ len = 4;
+	
+	avp_value->os.len = len;
+	avp_value->os.data = buf;
+	return 0;
+}
+
+int fd_dictfct_Time_interpret(union avp_value * avp_value, void * interpreted)
+{
+	TRACE_ENTRY("%p %p", avp_value, interpreted);
+	
+	CHECK_PARAMS( avp_value && interpreted );
+	
+	return diameter_string_to_time_t(avp_value->os.data, avp_value->os.len, interpreted);
+}
+
+char * fd_dictfct_Time_dump(union avp_value * avp_value)
+{
+	char * ret;
+	CHECK_MALLOC_DO( ret = malloc(STR_LEN), return NULL );
+	if (avp_value->os.len != 4) {
+		snprintf(ret, STR_LEN, "[invalid length: %zd]", avp_value->os.len);
+		return ret;
+	}
+	/* TODO: display the time as human-readable */
+	snprintf(ret, STR_LEN, "[TODO Time dump: 0x%02hhx%02hhx%02hhx%02hhx]", avp_value->os.data[0], avp_value->os.data[1], avp_value->os.data[2], avp_value->os.data[3]);
+	return ret;
+}
+
--- a/libfdproto/fdproto-internal.h	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdproto/fdproto-internal.h	Thu Feb 21 11:57:32 2013 +0100
@@ -69,6 +69,7 @@
 int fd_sess_ref_msg ( struct session * session );
 int fd_sess_reclaim_msg ( struct session ** session );
 
+
 /* For dump routines into string buffers */
 #include <stdarg.h>
 static __inline__ int dump_init_str(char **outstr, size_t *offset, size_t *outlen) 
--- a/libfdproto/messages.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdproto/messages.c	Thu Feb 21 11:57:32 2013 +0100
@@ -105,7 +105,7 @@
 /* Macro to cast a msg_avp_t */
 #define _A(_x) ((struct avp *)(_x))
 /* Check the type and eyecatcher */
-#define CHECK_AVP(_x) ((_C(_x)->type == MSG_AVP) && (_A(_x)->avp_eyec == MSG_AVP_EYEC))
+#define CHECK_AVP(_x) ((_x) && (_C(_x)->type == MSG_AVP) && (_A(_x)->avp_eyec == MSG_AVP_EYEC))
 
 /* The following structure represents an instance of a message (command and children AVPs). */
 struct msg {
@@ -238,7 +238,7 @@
 		new->avp_rawlen = (*avp)->avp_public.avp_len - GETAVPHDRSZ( (*avp)->avp_public.avp_flags );
 		if (new->avp_rawlen) {
 			CHECK_MALLOC(  new->avp_rawdata = malloc(new->avp_rawlen)  );
-			memset(new->avp_rawdata, 0xFF, new->avp_rawlen);
+			memset(new->avp_rawdata, 0x00, new->avp_rawlen);
 		}
 	}
 	
@@ -1215,6 +1215,20 @@
 	return 0;
 }
 
+/* Associate a session with a message, use only when the session was just created */
+int fd_msg_sess_set(struct msg * msg, struct session * session)
+{
+	TRACE_ENTRY("%p %p", msg, session);
+	
+	/* Check we received valid parameters */
+	CHECK_PARAMS( CHECK_MSG(msg) );
+	CHECK_PARAMS( session );
+	CHECK_PARAMS( msg->msg_sess == NULL );
+	
+	msg->msg_sess = session;
+	return 0;
+}
+
 
 /* Retrieve the session of the message */
 int fd_msg_sess_get(struct dictionary * dict, struct msg * msg, struct session ** session, int * new)
@@ -1260,8 +1274,13 @@
 	ASSERT( avp->avp_public.avp_value );
 	
 	/* Resolve the session and we are done */
-	CHECK_FCT( fd_sess_fromsid_msg ( avp->avp_public.avp_value->os.data, avp->avp_public.avp_value->os.len, &msg->msg_sess, new) );
-	*session = msg->msg_sess;
+	if (avp->avp_public.avp_value->os.len > 0) {
+		CHECK_FCT( fd_sess_fromsid_msg ( avp->avp_public.avp_value->os.data, avp->avp_public.avp_value->os.len, &msg->msg_sess, new) );
+		*session = msg->msg_sess;
+	} else {
+		TRACE_DEBUG(FULL, "Session-Id AVP with 0-byte length found in message %p", msg);
+		*session = NULL;
+	}
 	
 	return 0;
 }
@@ -1647,7 +1666,7 @@
 	while (offset < buflen) {
 		struct avp * avp;
 		
-		if (buflen - offset <= AVPHDRSZ_NOVEND) {
+		if (buflen - offset < AVPHDRSZ_NOVEND) {
 			TRACE_DEBUG(INFO, "truncated buffer: remaining only %d bytes", buflen - offset);
 			return EBADMSG;
 		}
@@ -1665,7 +1684,7 @@
 		offset += 8;
 		
 		if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
-			if (buflen - offset <= 4) {
+			if (buflen - offset < 4) {
 				TRACE_DEBUG(INFO, "truncated buffer: remaining only %d bytes for vendor and data", buflen - offset);
 				free(avp);
 				return EBADMSG;
@@ -1675,7 +1694,8 @@
 		}
 		
 		/* Check there is enough remaining data in the buffer */
-		if (buflen - offset < avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags)) {
+		if ( (avp->avp_public.avp_len > GETAVPHDRSZ(avp->avp_public.avp_flags))
+		&& (buflen - offset < avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags))) {
 			TRACE_DEBUG(INFO, "truncated buffer: remaining only %d bytes for data, and avp data size is %d", 
 					buflen - offset, 
 					avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags));
--- a/libfdproto/sessions.c	Thu Feb 21 11:52:53 2013 +0100
+++ b/libfdproto/sessions.c	Thu Feb 21 11:57:32 2013 +0100
@@ -359,7 +359,7 @@
 
 
 
-/* Create a new session object with the default timeout value, and link it */
+/* Create a new session object with the default timeout value, and link it. The refcount is increased by 1, whether the session existed or not */
 int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen )
 {
 	os0_t  sid = NULL;
@@ -460,16 +460,22 @@
 			} );
 	
 		fd_list_insert_before(li, &sess->chain_h); /* hash table */
+		sess->msg_cnt++;
 	} else {
 		free(sid);
+		
+		CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) ); 
+		(*session)->msg_cnt++;
+		CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) ); 
+		
 		/* it was found: was it previously destroyed? */
 		if ((*session)->is_destroyed == 0) {
 			ret = EALREADY;
 			goto out;
 		} else {
 			/* the session was marked destroyed, let's re-activate it. */
-			TODO("Re-creating a deleted session. Should investigate if this can lead to an issue... (need more feedback)");
 			sess = *session;
+			sess->is_destroyed = 0;
 			
 			/* update the expiry time */
 			CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &sess->timeout), { ASSERT(0); } );
@@ -500,7 +506,7 @@
 	CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); } ); /* if it fails, we might not pop the cleanup handler, but this should not happen -- and we'd have a serious problem otherwise */
 
 out:
-	;	
+	;
 	pthread_cleanup_pop(0);
 	CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) );
 	
@@ -511,8 +517,8 @@
 	return 0;
 }
 
-/* Find or create a session */
-int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * new)
+/* Find or create a session -- the msg refcount is increased */
+int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new)
 {
 	int ret;
 	
@@ -801,17 +807,19 @@
 }
 
 /* For the messages module */
-int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new)
+int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * new)
 {
 	TRACE_ENTRY("%p %zd %p %p", sid, len, session, new);
 	CHECK_PARAMS( sid && len && session );
 	
 	/* Get the session object */
-	CHECK_FCT( fd_sess_fromsid ( sid, len, session, new) );
+	CHECK_FCT( fd_sess_fromsid_msg ( sid, len, session, new) );
 	
-	/* Increase count */
-	CHECK_FCT( fd_sess_ref_msg ( *session ) );
-	
+	/* Decrease the refcount */
+	CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) );
+	(*session)->msg_cnt--; /* was increased in fd_sess_new */
+	CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) );
+		
 	/* Done */
 	return 0;
 }
@@ -832,16 +840,27 @@
 int fd_sess_reclaim_msg ( struct session ** session )
 {
 	int reclaim;
+	uint32_t hash;
 	
 	TRACE_ENTRY("%p", session);
 	CHECK_PARAMS( session && VALIDATE_SI(*session) );
 	
+	/* Lock the hash line to avoid possibility that session is freed while we are reclaiming */
+	hash = (*session)->hash;
+	CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash)) );
+	pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) ); 
+
 	/* Update the msg refcount */
 	CHECK_POSIX( pthread_mutex_lock(&(*session)->stlock) );
 	reclaim = (*session)->msg_cnt;
 	(*session)->msg_cnt = reclaim - 1;
 	CHECK_POSIX( pthread_mutex_unlock(&(*session)->stlock) );
 	
+	/* Ok, now unlock the hash line */
+	pthread_cleanup_pop( 0 );
+	CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) );
+	
+	/* and reclaim if no message references the session anymore */
 	if (reclaim == 1) {
 		CHECK_FCT(fd_sess_reclaim ( session ));
 	} else {
"Welcome to our mercurial repository"