Index: libfdproto/dictionary.c
===================================================================
--- libfdproto/dictionary.c	(revision 687)
+++ libfdproto/dictionary.c	(revision 706)
@@ -63,12 +63,14 @@
 	
 	union {
-		struct dict_vendor_data		vendor;
-		struct dict_application_data	application;
-		struct dict_type_data		type;
-		struct dict_enumval_data	enumval;
-		struct dict_avp_data		avp;
-		struct dict_cmd_data		cmd;
-		struct dict_rule_data		rule;
+		struct dict_vendor_data		vendor;		/* datastr_len = strlen(vendor_name) */
+		struct dict_application_data	application;	/* datastr_len = strlen(application_name) */
+		struct dict_type_data		type;		/* datastr_len = strlen(type_name) */
+		struct dict_enumval_data	enumval;	/* datastr_len = strlen(enum_name) */
+		struct dict_avp_data		avp;		/* datastr_len = strlen(avp_name) */
+		struct dict_cmd_data		cmd;		/* datastr_len = strlen(cmd_name) */
+		struct dict_rule_data		rule;		/* datastr_len = 0 */
 	} data;				/* The data of this object */
+	
+	size_t			datastr_len; /* cached length of the string inside the data. Saved when the object is created. */
 	
 	struct dict_object *	parent; /* The parent of this object, if any */
@@ -88,5 +90,5 @@
 	 list[0]: list of the vendors, ordered by their id. The sentinel is g_dict_vendors (vendor with id 0)
 	 list[1]: sentinel for the list of AVPs from this vendor, ordered by AVP code.
-	 list[2]: sentinel for the list of AVPs from this vendor, ordered by AVP name.
+	 list[2]: sentinel for the list of AVPs from this vendor, ordered by AVP name (fd_os_cmp).
 	 
 	 => APPLICATIONS:
@@ -97,9 +99,9 @@
 	 => TYPES:
 	 list[0]: list of the types, ordered by their names. The sentinel is g_list_types.
-	 list[1]: sentinel for the type_enum list of this type, ordered by their constant name.
+	 list[1]: sentinel for the type_enum list of this type, ordered by their constant name (fd_os_cmp).
 	 list[2]: sentinel for the type_enum list of this type, ordered by their constant value.
 	 
 	 => TYPE_ENUMS:
-	 list[0]: list of the contants for a given type, ordered by the constant name. Sentinel is a (list[1]) element of a TYPE object.
+	 list[0]: list of the contants for a given type, ordered by the constant name (fd_os_cmp). Sentinel is a (list[1]) element of a TYPE object.
 	 list[1]: list of the contants for a given type, ordered by the constant value. Sentinel is a (list[2]) element of a TYPE object.
 	 list[2]: not used
@@ -107,14 +109,14 @@
 	 => AVPS:
 	 list[0]: list of the AVP from a given vendor, ordered by avp code. Sentinel is a list[1] element of a VENDOR object.
-	 list[1]: list of the AVP from a given vendor, ordered by avp name. Sentinel is a list[2] element of a VENDOR object.
+	 list[1]: list of the AVP from a given vendor, ordered by avp name (fd_os_cmp). Sentinel is a list[2] element of a VENDOR object.
 	 list[2]: sentinel for the rule list that apply to this AVP.
 	 
 	 => COMMANDS:
-	 list[0]: list of the commands, ordered by their names. The sentinel is g_list_cmd_name.
+	 list[0]: list of the commands, ordered by their names (fd_os_cmp). The sentinel is g_list_cmd_name.
 	 list[1]: list of the commands, ordered by their command code and 'R' flag. The sentinel is g_list_cmd_code.
 	 list[2]: sentinel for the rule list that apply to this command.
 	 
 	 => RULES:
-	 list[0]: list of the rules for a given (grouped) AVP or Command, ordered by the AVP name to which they refer. sentinel is list[2] of a command or (grouped) avp.
+	 list[0]: list of the rules for a given (grouped) AVP or Command, ordered by the AVP vendor & code to which they refer. sentinel is list[2] of a command or (grouped) avp.
 	 list[1]: not used
 	 list[2]: not used.
@@ -223,8 +225,8 @@
 /* Functions to manage the objects creation and destruction. */
 
-/* Duplicate a string inplace */
-#define DUP_string( str ) {				\
-	char * __str = (str);				\
-	CHECK_MALLOC( (str) = strdup(__str) );		\
+/* Duplicate a string inplace, save its length */
+#define DUP_string_len( str, plen ) {		\
+	*(plen) = strlen((str));		\
+	str = os0dup( str, *(plen));		\
 }
 	
@@ -259,5 +261,5 @@
 
 /* Initialize the "data" part of an object */
-static int init_object_data(void * dest, void * source, enum dict_object_type type)
+static int init_object_data(struct dict_object * dest, void * source, enum dict_object_type type)
 {
 	TRACE_ENTRY("%p %p %d", dest, source, type);
@@ -265,5 +267,5 @@
 	
 	/* Generic: copy the full data structure */	
-	memcpy( dest, source, dict_obj_info[type].datasize );
+	memcpy( &dest->data, source, dict_obj_info[type].datasize );
 	
 	/* Then strings must be duplicated, not copied */
@@ -271,25 +273,25 @@
 	switch (type) {
 		case DICT_VENDOR:
-			DUP_string( ((struct dict_vendor_data *)dest)->vendor_name );
+			DUP_string_len( dest->data.vendor.vendor_name, &dest->datastr_len );
 			break;
 		
 		case DICT_APPLICATION:
-			DUP_string( ((struct dict_application_data *)dest)->application_name );
+			DUP_string_len( dest->data.application.application_name, &dest->datastr_len );
 			break;
 			
 		case DICT_TYPE:
-			DUP_string( ((struct dict_type_data *)dest)->type_name );
+			DUP_string_len( dest->data.type.type_name, &dest->datastr_len );
 			break;
 			
 		case DICT_ENUMVAL:
-			DUP_string( ((struct dict_enumval_data *)dest)->enum_name );
+			DUP_string_len( dest->data.enumval.enum_name, &dest->datastr_len );
 			break;
 
 		case DICT_AVP:
-			DUP_string( ((struct dict_avp_data *)dest)->avp_name );
+			DUP_string_len( dest->data.avp.avp_name, &dest->datastr_len );
 			break;
 			
 		case DICT_COMMAND:
-			DUP_string( ((struct dict_cmd_data *)dest)->cmd_name );
+			DUP_string_len( dest->data.cmd.cmd_name, &dest->datastr_len );
 			break;
 		
@@ -456,5 +458,5 @@
 	TRACE_ENTRY("%p %p", o1, o2);
 	
-	return strcmp( o1->data.type.type_name, o2->data.type.type_name );
+	return fd_os_cmp( o1->data.type.type_name, o1->datastr_len, o2->data.type.type_name, o2->datastr_len );
 }
 
@@ -464,5 +466,5 @@
 	TRACE_ENTRY("%p %p", o1, o2);
 	
-	return strcmp( o1->data.enumval.enum_name, o2->data.enumval.enum_name );
+	return fd_os_cmp( o1->data.enumval.enum_name, o1->datastr_len, o2->data.enumval.enum_name, o2->datastr_len );
 }
 
@@ -470,7 +472,4 @@
 static int order_enum_by_val  ( struct dict_object *o1, struct dict_object *o2 )
 {
-	size_t oslen;
-	int cmp = 0;
-	
 	TRACE_ENTRY("%p %p", o1, o2);
 	
@@ -478,9 +477,6 @@
 	switch ( o1->parent->data.type.type_base ) {
 		case AVP_TYPE_OCTETSTRING:
-			oslen = o1->data.enumval.enum_value.os.len;
-			if (o2->data.enumval.enum_value.os.len < oslen)
-				oslen = o2->data.enumval.enum_value.os.len;
-			cmp = memcmp(o1->data.enumval.enum_value.os.data, o2->data.enumval.enum_value.os.data, oslen );
-			return (cmp ? cmp : ORDER_scalar(o1->data.enumval.enum_value.os.len,o2->data.enumval.enum_value.os.len));
+			return fd_os_cmp( o1->data.enumval.enum_value.os.data, o1->data.enumval.enum_value.os.len, 
+					  o2->data.enumval.enum_value.os.data, o2->data.enumval.enum_value.os.len);
 		
 		case AVP_TYPE_INTEGER32:
@@ -522,5 +518,5 @@
 	TRACE_ENTRY("%p %p", o1, o2);
 	
-	return strcmp( o1->data.avp.avp_name, o2->data.avp.avp_name );
+	return fd_os_cmp( o1->data.avp.avp_name, o1->datastr_len, o2->data.avp.avp_name, o2->datastr_len );
 }
 
@@ -530,5 +526,5 @@
 	TRACE_ENTRY("%p %p", o1, o2);
 	
-	return strcmp( o1->data.cmd.cmd_name, o2->data.cmd.cmd_name );
+	return fd_os_cmp( o1->data.cmd.cmd_name, o1->datastr_len, o2->data.cmd.cmd_name, o2->datastr_len );
 }
 
@@ -555,5 +551,5 @@
 
 /* Compare two rule object by the AVP vendor & code that they refer (checks already performed) */
-static int order_rule_by_avpn ( struct dict_object *o1, struct dict_object *o2 )
+static int order_rule_by_avpvc ( struct dict_object *o1, struct dict_object *o2 )
 {
 	TRACE_ENTRY("%p %p", o1, o2);
@@ -590,11 +586,14 @@
 
 /* For search of strings in lists. isindex= 1 if the string is the ordering key of the list */
-#define SEARCH_string( str, sentinel, datafield, isindex ) {			\
-	char * __str = (char *) str;						\
+/* it is expected that object->datastr_len is the length of the datafield parameter */
+#define SEARCH_os0_l( str, len, sentinel, datafield, isindex ) {		\
+	char *  __str = (char *) (str);						\
+	size_t __strlen = (size_t)(len);					\
 	int __cmp;								\
 	struct fd_list * __li;							\
 	ret = 0;								\
 	for  (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) {	\
-		__cmp = strcmp(__str, _O(__li->o)->data. datafield );		\
+		__cmp = fd_os_cmp(__str, __strlen,				\
+			_O(__li->o)->data. datafield, _O(__li->o)->datastr_len);\
 		if (__cmp == 0) {						\
 			if (result)						\
@@ -611,25 +610,26 @@
 }
 
-/* For search of octetstrings in lists (not \0 terminated). */
-#define SEARCH_ocstring( ostr, length, sentinel, osdatafield, isindex ) {	\
-	unsigned char * __ostr = (unsigned char *) ostr;			\
+/* When len is not provided */
+#define SEARCH_os0( str, sentinel, datafield, isindex ) {			\
+	char *  _str = (char *) (str);						\
+	size_t  _strlen = strlen(_str);						\
+	SEARCH_os0_l( _str, _strlen, sentinel, datafield, isindex );		\
+}
+
+
+/* For search of octetstrings in lists. */
+#define SEARCH_os(  str, strlen, sentinel, osdatafield, isindex ) {		\
+	uint8_t * __str = (uint8_t *) (str);					\
+	size_t __strlen = (size_t)(strlen);					\
 	int __cmp;								\
-	size_t __len;								\
 	struct fd_list * __li;							\
 	ret = 0;								\
-	for  (__li = (sentinel); __li->next != (sentinel); __li = __li->next) {	\
-		__len = _O(__li->next->o)->data. osdatafield .len;		\
-		if ( __len > (length) )						\
-			__len = (length);					\
-		__cmp = memcmp(__ostr, 						\
-				_O(__li->next->o)->data. osdatafield .data, 	\
-				__len);						\
-		if (! __cmp) {							\
-			__cmp = ORDER_scalar( length,				\
-				_O(__li->next->o)->data. osdatafield .len); 	\
-		}								\
+	for  (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) {	\
+		__cmp = fd_os_cmp(__str, __strlen,				\
+			_O(__li->o)->data. osdatafield .data,			\
+			_O(__li->o)->data. osdatafield .len);			\
 		if (__cmp == 0) {						\
 			if (result)						\
-				*result = _O(__li->next->o);			\
+				*result = _O(__li->o);				\
 			goto end;						\
 		}								\
@@ -644,15 +644,17 @@
 
 /* For search of AVP name in rule lists. */
-#define SEARCH_ruleavpname( str, sentinel ) {					\
-	char * __str = (char *) str;						\
+#define SEARCH_ruleavpname( str, strlen, sentinel ) {				\
+	char * __str = (char *) (str);						\
+	size_t __strlen = (size_t) (strlen);					\
 	int __cmp;								\
 	struct fd_list * __li;							\
 	ret = 0;								\
-	for  (__li = (sentinel); __li->next != (sentinel); __li = __li->next) {	\
-		__cmp = strcmp(__str, 						\
-		  _O(__li->next->o)->data.rule.rule_avp->data.avp.avp_name);\
+	for  (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) {	\
+		__cmp = fd_os_cmp(__str, __strlen, 				\
+		  	_O(__li->o)->data.rule.rule_avp->data.avp.avp_name,	\
+			_O(__li->o)->data.rule.rule_avp->datastr_len);		\
 		if (__cmp == 0) {						\
 			if (result)						\
-				*result = _O(__li->next->o);			\
+				*result = _O(__li->o);				\
 			goto end;						\
 		}								\
@@ -677,9 +679,9 @@
 		goto end;							\
 	}									\
-	for  (__li = (sentinel); __li->next != (sentinel); __li = __li->next) {	\
-		__cmp= ORDER_scalar(value, _O(__li->next->o)->data. datafield );\
+	for  (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) {	\
+		__cmp= ORDER_scalar(value, _O(__li->o)->data. datafield );	\
 		if (__cmp == 0) {						\
 			if (result)						\
-				*result = _O(__li->next->o);			\
+				*result = _O(__li->o);				\
 			goto end;						\
 		}								\
@@ -698,13 +700,11 @@
 	struct fd_list * __li;							\
 	ret = 0;								\
-	for  (	  __li = (sentinel);	 					\
-		  __li->next != (sentinel); 					\
-		  __li = __li->next) {						\
+	for  (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) {	\
 		__cmp = ORDER_scalar(value, 					\
-				_O(__li->next->o)->data.cmd.cmd_code );		\
+				_O(__li->o)->data.cmd.cmd_code );		\
 		if (__cmp == 0) {						\
 			uint8_t __mask, __val;					\
-			__mask = _O(__li->next->o)->data.cmd.cmd_flag_mask;	\
-			__val  = _O(__li->next->o)->data.cmd.cmd_flag_val;	\
+			__mask = _O(__li->o)->data.cmd.cmd_flag_mask;		\
+			__val  = _O(__li->o)->data.cmd.cmd_flag_val;		\
 			if ( ! (__mask & CMD_FLAG_REQUEST) )			\
 				continue;					\
@@ -712,5 +712,5 @@
 				continue;					\
 			if (result)						\
-				*result = _O(__li->next->o);			\
+				*result = _O(__li->o);				\
 			goto end;						\
 		}								\
@@ -739,5 +739,5 @@
 		case VENDOR_BY_NAME:
 			/* "what" is a vendor name */
-			SEARCH_string( what, &dict->dict_vendors.list[0], vendor.vendor_name, 0);
+			SEARCH_os0( what, &dict->dict_vendors.list[0], vendor.vendor_name, 0);
 			break;
 			
@@ -771,5 +771,5 @@
 		case APPLICATION_BY_NAME:
 			/* "what" is an application name */
-			SEARCH_string( what, &dict->dict_applications.list[0], application.application_name, 0);
+			SEARCH_os0( what, &dict->dict_applications.list[0], application.application_name, 0);
 			break;
 			
@@ -801,5 +801,5 @@
 		case TYPE_BY_NAME:
 			/* "what" is a type name */
-			SEARCH_string( what, &dict->dict_types, type.type_name, 1);
+			SEARCH_os0( what, &dict->dict_types, type.type_name, 1);
 			break;
 			
@@ -850,10 +850,10 @@
 				if ( _what->search.enum_name != NULL ) {
 					/* We are looking for this string */
-					SEARCH_string(  _what->search.enum_name, &parent->list[1], enumval.enum_name, 1 );
+					SEARCH_os0(  _what->search.enum_name, &parent->list[1], enumval.enum_name, 1 );
 				} else {
 					/* We are looking for the value in enum_value */
 					switch (parent->data.type.type_base) {
 						case AVP_TYPE_OCTETSTRING:
-							SEARCH_ocstring( _what->search.enum_value.os.data, 
+							SEARCH_os(	 _what->search.enum_value.os.data, 
 									 _what->search.enum_value.os.len, 
 									 &parent->list[2], 
@@ -946,5 +946,5 @@
 		case AVP_BY_NAME:
 			/* "what" is the AVP name, vendor 0 */
-			SEARCH_string( what, &dict->dict_vendors.list[2], avp.avp_name, 1);
+			SEARCH_os0( what, &dict->dict_vendors.list[2], avp.avp_name, 1);
 			break;
 			
@@ -969,8 +969,8 @@
 				/* We now have our vendor = head of the appropriate avp list */
 				if (criteria == AVP_BY_NAME_AND_VENDOR) {
-					SEARCH_string( _what->avp_name, &vendor->list[2], avp.avp_name, 1);
+					SEARCH_os0( _what->avp_name, &vendor->list[2], avp.avp_name, 1);
 				} else {
 					/* AVP_BY_CODE_AND_VENDOR */
-					SEARCH_scalar( _what->avp_code, &vendor->list[1],  avp.avp_code, 1, (struct dict_object *)NULL );
+					SEARCH_scalar( _what->avp_code, &vendor->list[1], avp.avp_code, 1, (struct dict_object *)NULL );
 				}
 			}
@@ -980,11 +980,12 @@
 			{
 				struct fd_list * li;
+				size_t wl = strlen((char *)what);
 				
 				/* First, search for vendor 0 */
-				SEARCH_string( what, &dict->dict_vendors.list[2], avp.avp_name, 1);
+				SEARCH_os0_l( what, wl, &dict->dict_vendors.list[2], avp.avp_name, 1);
 				
 				/* If not found, loop for all vendors, until found */
 				for (li = dict->dict_vendors.list[0].next; li != &dict->dict_vendors.list[0]; li = li->next) {
-					SEARCH_string( what, &_O(li->o)->list[2], avp.avp_name, 1);
+					SEARCH_os0_l( what, wl, &_O(li->o)->list[2], avp.avp_name, 1);
 				}
 			}
@@ -1008,5 +1009,5 @@
 		case CMD_BY_NAME:
 			/* "what" is a command name */
-			SEARCH_string( what, &dict->dict_cmd_name, cmd.cmd_name, 1);
+			SEARCH_os0( what, &dict->dict_cmd_name, cmd.cmd_name, 1);
 			break;
 			
@@ -1096,5 +1097,5 @@
 				
 				/* Perform the search */
-				SEARCH_ruleavpname( avp->data.avp.avp_name, &parent->list[2]);
+				SEARCH_ruleavpname( avp->data.avp.avp_name, avp->datastr_len, &parent->list[2]);
 				
 			}
@@ -1274,21 +1275,21 @@
 	dump_object( &dict->dict_vendors, 0, 3, 0 );
 	
-	fd_log_debug("###### Dumping applications #######\n");
+	fd_log_debug("######          Dumping applications           #######\n");
 
 	dump_object( &dict->dict_applications, 0, 1, 0 );
 	
-	fd_log_debug("###### Dumping types #######\n");
+	fd_log_debug("######             Dumping types               #######\n");
 
 	dump_list( &dict->dict_types, 0, 2, 0 );
 	
-	fd_log_debug("###### Dumping commands per name #######\n");
+	fd_log_debug("######      Dumping commands per name          #######\n");
 
 	dump_list( &dict->dict_cmd_name, 0, 2, 0 );
 	
-	fd_log_debug("###### Dumping commands per code and flags #######\n");
+	fd_log_debug("######   Dumping commands per code and flags   #######\n");
 
 	dump_list( &dict->dict_cmd_code, 0, 0, 0 );
 	
-	fd_log_debug("###### Statistics #######\n");
+	fd_log_debug("######             Statistics                  #######\n");
 
 	for (i=1; i<=DICT_TYPE_MAX; i++)
@@ -1561,5 +1562,5 @@
 	/* Initialize the data of the new object */
 	init_object(new, type);
-	init_object_data(&new->data, data, type);
+	init_object_data(new, data, type);
 	new->dico = dict;
 	new->parent = parent;
@@ -1632,5 +1633,5 @@
 		case DICT_RULE:
 			/* A rule object is linked in list[2] of its parent command or AVP by the name of the AVP it refers */
-			ret = fd_list_insert_ordered ( &parent->list[2], &new->list[0], (int (*)(void*, void *))order_rule_by_avpn, (void **)&locref );
+			ret = fd_list_insert_ordered ( &parent->list[2], &new->list[0], (int (*)(void*, void *))order_rule_by_avpvc, (void **)&locref );
 			if (ret)
 				goto error_unlock;
@@ -1659,6 +1660,7 @@
 		switch (type) {
 			case DICT_VENDOR:
-				/* if we are here, it meas the two vendor id are identical */
-				if (strcmp(locref->data.vendor.vendor_name, new->data.vendor.vendor_name)) {
+				/* if we are here, it means the two vendors id are identical */
+				if (fd_os_cmp(locref->data.vendor.vendor_name, locref->datastr_len, 
+						new->data.vendor.vendor_name, new->datastr_len)) {
 					TRACE_DEBUG(FULL, "Conflicting vendor name");
 					break;
@@ -1670,5 +1672,6 @@
 			case DICT_APPLICATION:
 				/* got same id */
-				if (strcmp(locref->data.application.application_name, new->data.application.application_name)) {
+				if (fd_os_cmp(locref->data.application.application_name, locref->datastr_len, 
+						new->data.application.application_name, new->datastr_len)) {
 					TRACE_DEBUG(FULL, "Conflicting application name");
 					break;
@@ -1763,5 +1766,5 @@
 
 			case DICT_RULE:
-				/* Both rules point to the same AVPs */
+				/* Both rules point to the same AVPs (code & vendor) */
 				if (locref->data.rule.rule_position != new->data.rule.rule_position) {
 					TRACE_DEBUG(FULL, "Conflicting rule position");
@@ -1847,5 +1850,5 @@
 	struct dictionary * new = NULL;
 	
-	TRACE_ENTRY("");
+	TRACE_ENTRY("%p", dict);
 	
 	/* Sanity checks */
@@ -1865,5 +1868,7 @@
 	/* Initialize the sentinel for vendors and AVP lists */
 	init_object( &new->dict_vendors, DICT_VENDOR );
-	new->dict_vendors.data.vendor.vendor_name = "(no vendor)";
+	#define NO_VENDOR_NAME	"(no vendor)"
+	new->dict_vendors.data.vendor.vendor_name = NO_VENDOR_NAME;
+	new->dict_vendors.datastr_len = CONSTSTRLEN(NO_VENDOR_NAME);
 	new->dict_vendors.list[0].o = NULL; /* overwrite since element is also sentinel for this list. */
 	new->dict_vendors.dico = new;
@@ -1871,5 +1876,7 @@
 	/* Initialize the sentinel for applications */
 	init_object( &new->dict_applications, DICT_APPLICATION );
-	new->dict_applications.data.application.application_name = "Diameter Common Messages";
+	#define APPLICATION_0_NAME	"Diameter Common Messages"
+	new->dict_applications.data.application.application_name = APPLICATION_0_NAME;
+	new->dict_applications.datastr_len = CONSTSTRLEN(APPLICATION_0_NAME);
 	new->dict_applications.list[0].o = NULL; /* overwrite since since element is also sentinel for this list. */
 	new->dict_applications.dico = new;
@@ -1884,5 +1891,7 @@
 	/* Initialize the error command object */
 	init_object( &new->dict_cmd_error, DICT_COMMAND );
-	new->dict_cmd_error.data.cmd.cmd_name="(generic error format)";
+	#define GENERIC_ERROR_NAME	"(generic error format)"
+	new->dict_cmd_error.data.cmd.cmd_name = GENERIC_ERROR_NAME;
+	new->dict_cmd_error.datastr_len = CONSTSTRLEN(GENERIC_ERROR_NAME);
 	new->dict_cmd_error.data.cmd.cmd_flag_mask=CMD_FLAG_ERROR | CMD_FLAG_REQUEST | CMD_FLAG_RETRANSMIT;
 	new->dict_cmd_error.data.cmd.cmd_flag_val =CMD_FLAG_ERROR;
