diff include/freeDiameter/libfdproto.h @ 706:4ffbc9f1e922

Large UNTESTED commit with the following changes: * Improved DiameterIdentity handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7) * Cleanup in the session module to free only unreferenced sessions (#16) * Removed fd_cpu_flush_cache(), replaced by more robust alternatives. * Improved peer state machine algorithm to counter SCTP multistream race condition.
author Sebastien Decugis <sdecugis@nict.go.jp>
date Wed, 09 Feb 2011 15:26:58 +0900
parents f0cb8f465763
children 571b3abaa5df
line wrap: on
line diff
--- a/include/freeDiameter/libfdproto.h	Mon Jan 31 17:22:21 2011 +0900
+++ b/include/freeDiameter/libfdproto.h	Wed Feb 09 15:26:58 2011 +0900
@@ -44,6 +44,7 @@
  * The file contains the following parts:
  *	DEBUG
  *	MACROS
+ *      OCTET STRINGS
  *	THREADS
  *	LISTS
  *	DICTIONARY
@@ -566,6 +567,64 @@
 #define BUFSIZ 96
 #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)
 
 
 /*============================================================*/
@@ -601,13 +660,6 @@
 	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 
@@ -672,14 +724,6 @@
 
 
 
-/*============================================================*/
-/*                          HASH                              */
-/*============================================================*/
-
-/* Compute a hash value of a string (session id, diameter id, ...) */
-uint32_t fd_hash ( char * string, size_t len );
-
-
 
 /*============================================================*/
 /*                        DICTIONARY                          */
@@ -801,13 +845,13 @@
 /* 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 */
+	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_BY_NAME,		/* "what" points to a char * */
 	VENDOR_OF_APPLICATION	/* "what" points to a struct dict_object containing an application (see bellow) */
 };
 
@@ -871,13 +915,13 @@
 /* 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 */
+	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_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) */
 };
@@ -946,7 +990,7 @@
 	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 */
+	}           os;		/* Storage for an octet string */
 	int32_t     i32;	/* integer 32 */
 	int64_t     i64;	/* integer 64 */
 	uint32_t    u32;	/* unsigned 32 */
@@ -1010,7 +1054,7 @@
 /* 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 */
+	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, FILE * fstr);	/* cb called by fd_msg_dump_one for this type of data (if != NULL), to dump the AVP value in fstr */
@@ -1018,7 +1062,7 @@
 
 /* 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. */
 };
@@ -1067,7 +1111,7 @@
 
 /* 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. */
 };
 
@@ -1079,7 +1123,7 @@
 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;
+	char *			 type_name;
 	
 	/* Search criteria for the constant */
 	struct dict_enumval_data search; /* search.enum_value is used only if search.enum_name == NULL */
@@ -1182,7 +1226,7 @@
 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 */
+	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 */
@@ -1191,7 +1235,7 @@
 /* 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_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 */
 	AVP_BY_NAME_ALL_VENDORS /* "what" points to a string. Might be quite slow... */
@@ -1201,7 +1245,7 @@
 struct dict_avp_request {
 	vendor_id_t	 avp_vendor;
 	avp_code_t	 avp_code;
-	char		*avp_name;
+	char *		 avp_name;
 };
 
 
@@ -1309,14 +1353,14 @@
 /* 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 */
+	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_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. */
 	CMD_ANSWER		/* "what" points to a struct dict_object of a request command. The corresponding "Answer" command is returned. */
@@ -1589,10 +1633,10 @@
  *  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 );
+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) )
 
 	
 /*
@@ -1620,8 +1664,9 @@
  *
  * 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.
  *
  * DESCRIPTION: 
@@ -1638,13 +1683,13 @@
  *  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 );
+int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen );
 
 /*
  * FUNCTION:	fd_sess_fromsid
  *
  * 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.
  *  isnew	: if not NULL, set to 1 on return if the session object has been created, 0 if it was simply retrieved.
@@ -1658,26 +1703,26 @@
  *  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);
+int fd_sess_fromsid ( uint8_t * 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.
+ *  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.
+ *  0      	: The sid & len parameters have been updated.
  *  EINVAL 	: A parameter is invalid.
  */
-int fd_sess_getsid ( struct session * session, char ** sid );
+int fd_sess_getsid ( struct session * session, os0_t * sid, size_t * sidlen );
 
 /*
  * FUNCTION:	fd_sess_settimeout
@@ -1710,8 +1755,10 @@
  *  session	: Pointer to a session object.
  *
  * 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:
  *  0      	: The session no longer exists.
@@ -1726,10 +1773,11 @@
  *  session	: Pointer to a session object.
  *
  * DESCRIPTION: 
- *   Destroys the resources of a session, only if no session_state is associated with it.
+ *   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 no longer exists.
+ *  0      	: The session was reclaimed.
  *  EINVAL 	: A parameter is invalid.
  */
 int fd_sess_reclaim ( struct session ** session );
@@ -1801,27 +1849,29 @@
 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);
+/* 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) */
-void fd_rtd_candidate_del(struct rt_data * rtd, char * peerid, size_t sz /* if !0, peerid does not need to be \0 terminated */);
+/* 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 */
 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);
+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);
 
 /* 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. */
@@ -2238,7 +2288,7 @@
  *
  * 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)
  *
@@ -2251,8 +2301,8 @@
  *  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 );
+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 );
 
 /*
  * FUNCTION:	fd_msg_eteid_get
@@ -2369,7 +2419,7 @@
  *  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 );
+int fd_msg_bufferize ( struct msg * msg, uint8_t ** buffer, size_t * len );
 
 /*
  * FUNCTION:	fd_msg_parse_buffer
@@ -2391,7 +2441,7 @@
  *  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 );
+int fd_msg_parse_buffer ( uint8_t ** buffer, size_t buflen, struct msg ** msg );
 
 /* Parsing Error Information structure */
 struct fd_pei {
@@ -2653,6 +2703,7 @@
  *  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
+ *  error_code	: Upon return with action == DISP_ACT_ERROR, contains the error (such as "DIAMETER_UNABLE_TO_COMPLY")
  *
  * DESCRIPTION: 
  *   Call all handlers registered for a given message.
@@ -2665,7 +2716,7 @@
  *  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 );
+int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, char ** error_code );
 
 
 
"Welcome to our mercurial repository"