Index: include/freeDiameter/libfdproto.h
===================================================================
--- include/freeDiameter/libfdproto.h	(revision 705)
+++ include/freeDiameter/libfdproto.h	(revision 706)
@@ -45,4 +45,5 @@
  *	DEBUG
  *	MACROS
+ *      OCTET STRINGS
  *	THREADS
  *	LISTS
@@ -567,4 +568,62 @@
 #endif /* BUFSIZ */
 
+/* This gives the length of a const string */
+#define CONSTSTRLEN( str ) (sizeof(str) - 1)
+
+
+/*============================================================*/
+/*                         BINARY STRINGS                     */
+/*============================================================*/
+
+/* Compute a hash value of a binary string. 
+The hash must remain local to this machine, there is no guarantee that same input
+will give same output on a different system (endianness) */
+uint32_t fd_os_hash ( uint8_t * string, size_t len );
+
+/* This type used for binary strings that contain no \0 except as their last character. 
+It means some string operations can be used on it. */
+typedef uint8_t * os0_t;
+
+/* Same as strdup but for os0_t strings */
+os0_t os0dup_int(os0_t s, size_t l);
+#define os0dup( _s, _l)  (void *)os0dup_int((os0_t)(_s), _l)
+
+/* Check that an octet string value can be used as os0_t */
+static __inline__ int fd_os_is_valid_os0(uint8_t * os, size_t oslen) {
+	/* The only situation where it is not valid is when it contains a \0 inside the octet string */
+	return (memchr(os, '\0', oslen) == NULL);
+}
+
+/* The following type denotes a verified DiameterIdentity value (that contains only pure letters, digits, hyphen, dot) */
+typedef char * DiamId_t;
+
+/* Maximum length of a hostname we accept */
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 512
+#endif /* HOST_NAME_MAX */
+
+/* Check if a binary string contains a valid Diameter Identity value.
+  rfc3588 states explicitely that such a Diameter Identity consists only of ASCII characters. */
+int fd_os_is_valid_DiameterIdentity(uint8_t * os, size_t ossz);
+
+/* This checks a string is a valid DiameterIdentity and applies IDNA transformations otherwise (xn--...) */
+int fd_os_validate_DiameterIdentity(char ** id, size_t * outsz, int memory /* 0: *id can be realloc'd. 1: *id must be malloc'd on output (was static) */ );
+
+/* Create an order relationship for binary strings (not needed to be \0 terminated). 
+   It does NOT mimic strings relationships so that it is more efficient. It is case sensitive.
+   (the strings are actually first ordered by their lengh, then by their bytes contents)
+   returns: -1 if os1 < os2;  +1 if os1 > os2;  0 if they are equal */
+int fd_os_cmp_int(os0_t os1, size_t os1sz, os0_t os2, size_t os2sz);
+#define fd_os_cmp(_o1, _l1, _o2, _l2)  fd_os_cmp_int((os0_t)(_o1), _l1, (os0_t)(_o2), _l2)
+
+/* A roughly case-insensitive variant, which actually only compares ASCII chars (0-127) in a case-insentitive maneer 
+  -- this should be OK with (old) DNS names. Not sure how it works with IDN...
+  -- it also clearly does not support locales where a lowercase letter uses more space than upper case, such as ß -> ss
+ It is slower than fd_os_cmp... 
+ This function should give the same order as fd_os_cmp, except when it finds 2 strings to be equal.
+ Note that the result is NOT the same as strcasecmp !!!
+ */
+int fd_os_almostcasecmp_int(uint8_t * os1, size_t os1sz, uint8_t * os2, size_t os2sz);
+#define fd_os_almostcasecmp(_o1, _l1, _o2, _l2)  fd_os_almostcasecmp_int((os0_t)(_o1), _l1, (os0_t)(_o2), _l2)
 
 
@@ -602,11 +661,4 @@
 }
 
-/* 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);	\
-}
-
 
 /*************
@@ -673,12 +725,4 @@
 
 
-/*============================================================*/
-/*                          HASH                              */
-/*============================================================*/
-
-/* Compute a hash value of a string (session id, diameter id, ...) */
-uint32_t fd_hash ( char * string, size_t len );
-
-
 
 /*============================================================*/
@@ -802,5 +846,5 @@
 struct dict_vendor_data {
 	vendor_id_t	 vendor_id;	/* ID of a vendor */
-	char 		*vendor_name;	/* The name of this vendor */
+	char *	 	 vendor_name;	/* The name of this vendor */
 };
 
@@ -808,5 +852,5 @@
 enum {
 	VENDOR_BY_ID = 10,	/* "what" points to a vendor_id_t */
-	VENDOR_BY_NAME,		/* "what" points to a string */
+	VENDOR_BY_NAME,		/* "what" points to a char * */
 	VENDOR_OF_APPLICATION	/* "what" points to a struct dict_object containing an application (see bellow) */
 };
@@ -872,5 +916,5 @@
 struct dict_application_data {
 	application_id_t	 application_id;	/* ID of the application */
-	char 			*application_name;	/* The name of this application */
+	char *	 		 application_name;	/* The name of this application */
 };
 
@@ -878,5 +922,5 @@
 enum {
 	APPLICATION_BY_ID = 20,		/* "what" points to a application_id_t */
-	APPLICATION_BY_NAME,		/* "what" points to a string */
+	APPLICATION_BY_NAME,		/* "what" points to a char * */
 	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) */
@@ -947,5 +991,5 @@
 		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 */
+	}           os;		/* Storage for an octet string */
 	int32_t     i32;	/* integer 32 */
 	int64_t     i64;	/* integer 64 */
@@ -1011,5 +1055,5 @@
 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 */
+	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) */
@@ -1019,5 +1063,5 @@
 /* The criteria for searching a type object in the dictionary */
 enum {
-	TYPE_BY_NAME = 30,		/* "what" points to a string */
+	TYPE_BY_NAME = 30,		/* "what" points to a char * */
 	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. */
@@ -1068,5 +1112,5 @@
 /* Type to hold data of named constants for AVP */
 struct dict_enumval_data {
-	char 		*enum_name;	/* The name of this constant */
+	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. */
 };
@@ -1080,5 +1124,5 @@
 	/* Identifier of the parent type, one of the following must not be NULL */
 	struct dict_object	*type_obj;
-	char			*type_name;
+	char *			 type_name;
 	
 	/* Search criteria for the constant */
@@ -1183,5 +1227,5 @@
 	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 */
+	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 */
@@ -1192,5 +1236,5 @@
 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_NAME,		/* "what" points to a char *, 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 */
@@ -1202,5 +1246,5 @@
 	vendor_id_t	 avp_vendor;
 	avp_code_t	 avp_code;
-	char		*avp_name;
+	char *		 avp_name;
 };
 
@@ -1310,5 +1354,5 @@
 struct dict_cmd_data {
 	command_code_t	 cmd_code;	/* code of the command */
-	char		*cmd_name;	/* Name 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 */
@@ -1317,5 +1361,5 @@
 /* The criteria for searching an avp object in the dictionary */
 enum {
-	CMD_BY_NAME = 60,	/* "what" points to a string */
+	CMD_BY_NAME = 60,	/* "what" points to a char * */
 	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. */
@@ -1590,8 +1634,8 @@
  *  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 );
+int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, os0_t 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) )
+	fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, os0_t, void *))(_cleanup), (void *)(_opaque) )
 
 	
@@ -1621,6 +1665,7 @@
  * 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.
+ *  diamid	  : a Diameter Identity, or NULL.
+ *  diamidlen	  : if diamid is \0-terminated, this can be 0. Otherwise, the length of diamid.
+ *  opt           : Additional string, or NULL. Usage is described bellow.
  *  optlen	  : if opt is \0-terminated, this can be 0. Otherwise, the length of opt.
  *
@@ -1639,5 +1684,5 @@
  *  ENOMEM	: Not enough memory to complete the operation
  */
-int fd_sess_new ( struct session ** session, char * diamId, char * opt, size_t optlen );
+int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen );
 
 /*
@@ -1645,5 +1690,5 @@
  *
  * PARAMETERS:
- *  sid	  	: pointer to a string containing a Session-Id (UTF-8).
+ *  sid	  	: pointer to a string containing a Session-Id (should be 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.
@@ -1659,5 +1704,5 @@
  *  ENOMEM	: Not enough memory to complete the operation
  */
-int fd_sess_fromsid ( char * sid, size_t len, struct session ** session, int * isnew);
+int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * isnew);
 
 /*
@@ -1666,17 +1711,17 @@
  * PARAMETERS:
  *  session	: Pointer to a session object.
- *  sid	  	: On success, the location of a (\0-terminated) string is stored here.
+ *  sid	  	: On success, the location of the sid 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.
+ *  The returned sid is a \0-terminated binary string which might be UTF-8 (but there is no guarantee in the framework).
  *  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 );
+ *  0      	: The sid & len parameters have been updated.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_sess_getsid ( struct session * session, os0_t * sid, size_t * sidlen );
 
 /*
@@ -1711,6 +1756,8 @@
  *
  * DESCRIPTION: 
- *   Destroys a session an all associated data, if any.
+ *   Destroys all associated states of a session, if any.
  * Equivalent to a session timeout expired, but the effect is immediate.
+ * The session itself is marked as deleted, and will be freed when it is not referenced 
+ * by any message anymore.
  *
  * RETURN VALUE:
@@ -1727,8 +1774,9 @@
  *
  * DESCRIPTION: 
- *   Destroys the resources of a session, only if no session_state is associated with it.
- *
- * RETURN VALUE:
- *  0      	: The session no longer exists.
+ *   Equivalent to fd_sess_destroy, only if no session_state is associated with the session.
+ *  Otherwise, this function has no effect (except that it sets *session to NULL).
+ *
+ * RETURN VALUE:
+ *  0      	: The session was reclaimed.
  *  EINVAL 	: A parameter is invalid.
  */
@@ -1802,9 +1850,9 @@
 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 */);
+/* Add a peer to the candidates list. */
+int  fd_rtd_candidate_add(struct rt_data * rtd, DiamId_t peerid, size_t peeridlen, DiamId_t realm, size_t realmlen);
+
+/* Remove a peer from the candidates (if it is found). The search is case-insensitive. */
+void fd_rtd_candidate_del(struct rt_data * rtd, uint8_t * id, size_t idsz);
 
 /* Extract the list of valid candidates, and initialize their scores to 0 */
@@ -1812,15 +1860,17 @@
 
 /* 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);
+int  fd_rtd_error_add(struct rt_data * rtd, DiamId_t sentto, size_t senttolen, 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) */
+	DiamId_t	diamid;	/* the diameter Id of the peer */
+	size_t		diamidlen; /* cached size of the diamid string */
+	DiamId_t	realm;	/* the diameter realm of the peer */
+	size_t		realmlen; /* cached size of realm */
 	int		score;	/* the current routing score for this peer, see fd_rt_out_register definition for details */
 };
 
-/* Reorder the list of peers */
+/* Reorder the list of peers by score */
 int  fd_rtd_candidate_reorder(struct fd_list * candidates);
 
@@ -2239,5 +2289,5 @@
  * PARAMETERS:
  *  msg		: A msg object.
- *  diamid	: The diameter id of the peer from which this message was received.
+ *  diamid,len	: 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)
@@ -2252,6 +2302,6 @@
  *  !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 );
+int fd_msg_source_set( struct msg * msg, DiamId_t diamid, size_t diamidlen, int add_rr, struct dictionary * dict );
+int fd_msg_source_get( struct msg * msg, DiamId_t *diamid, size_t * diamidlen );
 
 /*
@@ -2370,5 +2420,5 @@
  *  ENOMEM	: Unable to allocate enough memory to create the buffer object.
  */
-int fd_msg_bufferize ( struct msg * msg, unsigned char ** buffer, size_t * len );
+int fd_msg_bufferize ( struct msg * msg, uint8_t ** buffer, size_t * len );
 
 /*
@@ -2392,5 +2442,5 @@
  *  EINVAL 	: A parameter is invalid.
  */
-int fd_msg_parse_buffer ( unsigned char ** buffer, size_t buflen, struct msg ** msg );
+int fd_msg_parse_buffer ( uint8_t ** buffer, size_t buflen, struct msg ** msg );
 
 /* Parsing Error Information structure */
@@ -2654,4 +2704,5 @@
  *  session	: The session corresponding to this object, if any.
  *  action	: Upon return, the action that must be taken on the message
+ *  error_code	: Upon return with action == DISP_ACT_ERROR, contains the error (such as "DIAMETER_UNABLE_TO_COMPLY")
  *
  * DESCRIPTION: 
@@ -2666,5 +2717,5 @@
  *  (other errors)
  */
-int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, const char ** error_code );
+int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, char ** error_code );
 
 
