Mercurial > hg > freeDiameter
diff libfdproto/dictionary.c @ 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 | 026802543f57 |
children | 4a9f08d6b6ba |
line wrap: on
line diff
--- a/libfdproto/dictionary.c Mon Jan 31 17:22:21 2011 +0900 +++ b/libfdproto/dictionary.c Wed Feb 09 15:26:58 2011 +0900 @@ -62,15 +62,17 @@ struct dictionary *dico; /* The dictionary this object belongs to */ 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 */ struct fd_list list[NB_LISTS_PER_OBJ];/* used to chain objects.*/ @@ -87,7 +89,7 @@ => VENDORS: 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: list[0]: list of the applications, ordered by their id. The sentinel is g_dict_applications (application with id 0) @@ -96,26 +98,26 @@ => 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 => 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. @@ -222,10 +224,10 @@ /* 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)); \ } /* Initialize an object */ @@ -258,39 +260,39 @@ } /* 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); CHECK_PARAMS( dest && source && CHECK_TYPE(type) ); /* 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 */ /* This function might be simplified by always defining the "name" field as the first field of the structures, but... it's error-prone */ 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; default: @@ -455,7 +457,7 @@ { 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 ); } /* Compare two type_enum objects by their names (checks already performed) */ @@ -463,25 +465,19 @@ { 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 ); } /* Compare two type_enum objects by their values (checks already performed) */ 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); /* The comparison function depends on the type of data */ 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: return ORDER_scalar( o1->data.enumval.enum_value.i32, o2->data.enumval.enum_value.i32 ); @@ -521,7 +517,7 @@ { 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 ); } /* Compare two command objects by their names (checks already performed) */ @@ -529,7 +525,7 @@ { 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 ); } /* Compare two command objects by their codes and flags (request or answer) (checks already performed) */ @@ -554,7 +550,7 @@ } /* 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); @@ -589,13 +585,16 @@ } /* 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) \ *result = _O(__li->o); \ @@ -610,27 +609,28 @@ ret = ENOENT; \ } -/* 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; \ } \ if ((isindex) && (__cmp < 0)) \ @@ -643,17 +643,19 @@ } /* 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; \ } \ if (__cmp < 0) \ @@ -676,11 +678,11 @@ *result = _O(defaultobj); \ 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; \ } \ if ((isindex) && (__cmp < 0)) \ @@ -697,21 +699,19 @@ int __cmp; \ 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; \ if ( ( __val & CMD_FLAG_REQUEST ) != R_flag_val ) \ continue; \ if (result) \ - *result = _O(__li->next->o); \ + *result = _O(__li->o); \ goto end; \ } \ if (__cmp < 0) \ @@ -738,7 +738,7 @@ 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; case VENDOR_OF_APPLICATION: @@ -770,7 +770,7 @@ 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; case APPLICATION_OF_TYPE: @@ -800,7 +800,7 @@ switch (criteria) { 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; case TYPE_OF_ENUMVAL: @@ -849,12 +849,12 @@ 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], enumval.enum_value.os , @@ -945,7 +945,7 @@ 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; case AVP_BY_CODE_AND_VENDOR: @@ -968,10 +968,10 @@ /* 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 ); } } break; @@ -979,13 +979,14 @@ case AVP_BY_NAME_ALL_VENDORS: { 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); } } break; @@ -1007,7 +1008,7 @@ switch (criteria) { 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; case CMD_BY_CODE_R: @@ -1095,7 +1096,7 @@ CHECK_PARAMS( verify_object(avp) && (avp->type == DICT_AVP) ); /* 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]); } break; @@ -1273,23 +1274,23 @@ 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++) fd_log_debug(" %5d objects of type %s\n", dict->dict_count[i], dict_obj_info[i].name); @@ -1560,7 +1561,7 @@ /* 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; @@ -1631,7 +1632,7 @@ 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; break; @@ -1658,8 +1659,9 @@ /* We have a duplicate key in locref. Check if the pointed object is the same or not */ 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; } @@ -1669,7 +1671,8 @@ 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; } @@ -1762,7 +1765,7 @@ break; 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"); break; @@ -1846,7 +1849,7 @@ { struct dictionary * new = NULL; - TRACE_ENTRY(""); + TRACE_ENTRY("%p", dict); /* Sanity checks */ ASSERT( (sizeof(type_base_name) / sizeof(type_base_name[0])) == (AVP_TYPE_MAX + 1) ); @@ -1864,13 +1867,17 @@ /* 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; /* 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; @@ -1883,7 +1890,9 @@ /* 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; new->dict_cmd_error.dico = new;