Changeset 706:4ffbc9f1e922 in freeDiameter for libfdproto
- Timestamp:
- Feb 9, 2011, 3:26:58 PM (13 years ago)
- Branch:
- default
- Phase:
- public
- Location:
- libfdproto
- Files:
-
- 1 added
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
libfdproto/CMakeLists.txt
r689 r706 13 13 messages.c 14 14 msg_log.c 15 ostr.c 15 16 rt_data.c 16 17 sessions.c -
libfdproto/dictionary.c
r687 r706 63 63 64 64 union { 65 struct dict_vendor_data vendor; 66 struct dict_application_data application; 67 struct dict_type_data type; 68 struct dict_enumval_data enumval; 69 struct dict_avp_data avp; 70 struct dict_cmd_data cmd; 71 struct dict_rule_data rule; 65 struct dict_vendor_data vendor; /* datastr_len = strlen(vendor_name) */ 66 struct dict_application_data application; /* datastr_len = strlen(application_name) */ 67 struct dict_type_data type; /* datastr_len = strlen(type_name) */ 68 struct dict_enumval_data enumval; /* datastr_len = strlen(enum_name) */ 69 struct dict_avp_data avp; /* datastr_len = strlen(avp_name) */ 70 struct dict_cmd_data cmd; /* datastr_len = strlen(cmd_name) */ 71 struct dict_rule_data rule; /* datastr_len = 0 */ 72 72 } data; /* The data of this object */ 73 74 size_t datastr_len; /* cached length of the string inside the data. Saved when the object is created. */ 73 75 74 76 struct dict_object * parent; /* The parent of this object, if any */ … … 88 90 list[0]: list of the vendors, ordered by their id. The sentinel is g_dict_vendors (vendor with id 0) 89 91 list[1]: sentinel for the list of AVPs from this vendor, ordered by AVP code. 90 list[2]: sentinel for the list of AVPs from this vendor, ordered by AVP name .92 list[2]: sentinel for the list of AVPs from this vendor, ordered by AVP name (fd_os_cmp). 91 93 92 94 => APPLICATIONS: … … 97 99 => TYPES: 98 100 list[0]: list of the types, ordered by their names. The sentinel is g_list_types. 99 list[1]: sentinel for the type_enum list of this type, ordered by their constant name .101 list[1]: sentinel for the type_enum list of this type, ordered by their constant name (fd_os_cmp). 100 102 list[2]: sentinel for the type_enum list of this type, ordered by their constant value. 101 103 102 104 => TYPE_ENUMS: 103 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.105 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. 104 106 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. 105 107 list[2]: not used … … 107 109 => AVPS: 108 110 list[0]: list of the AVP from a given vendor, ordered by avp code. Sentinel is a list[1] element of a VENDOR object. 109 list[1]: list of the AVP from a given vendor, ordered by avp name . Sentinel is a list[2] element of a VENDOR object.111 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. 110 112 list[2]: sentinel for the rule list that apply to this AVP. 111 113 112 114 => COMMANDS: 113 list[0]: list of the commands, ordered by their names . The sentinel is g_list_cmd_name.115 list[0]: list of the commands, ordered by their names (fd_os_cmp). The sentinel is g_list_cmd_name. 114 116 list[1]: list of the commands, ordered by their command code and 'R' flag. The sentinel is g_list_cmd_code. 115 117 list[2]: sentinel for the rule list that apply to this command. 116 118 117 119 => RULES: 118 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.120 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. 119 121 list[1]: not used 120 122 list[2]: not used. … … 223 225 /* Functions to manage the objects creation and destruction. */ 224 226 225 /* Duplicate a string inplace */226 #define DUP_string ( str ) {\227 char * __str = (str);\228 CHECK_MALLOC( (str) = strdup(__str)); \227 /* Duplicate a string inplace, save its length */ 228 #define DUP_string_len( str, plen ) { \ 229 *(plen) = strlen((str)); \ 230 str = os0dup( str, *(plen)); \ 229 231 } 230 232 … … 259 261 260 262 /* Initialize the "data" part of an object */ 261 static int init_object_data( void* dest, void * source, enum dict_object_type type)263 static int init_object_data(struct dict_object * dest, void * source, enum dict_object_type type) 262 264 { 263 265 TRACE_ENTRY("%p %p %d", dest, source, type); … … 265 267 266 268 /* Generic: copy the full data structure */ 267 memcpy( dest, source, dict_obj_info[type].datasize );269 memcpy( &dest->data, source, dict_obj_info[type].datasize ); 268 270 269 271 /* Then strings must be duplicated, not copied */ … … 271 273 switch (type) { 272 274 case DICT_VENDOR: 273 DUP_string ( ((struct dict_vendor_data *)dest)->vendor_name);275 DUP_string_len( dest->data.vendor.vendor_name, &dest->datastr_len ); 274 276 break; 275 277 276 278 case DICT_APPLICATION: 277 DUP_string ( ((struct dict_application_data *)dest)->application_name);279 DUP_string_len( dest->data.application.application_name, &dest->datastr_len ); 278 280 break; 279 281 280 282 case DICT_TYPE: 281 DUP_string ( ((struct dict_type_data *)dest)->type_name);283 DUP_string_len( dest->data.type.type_name, &dest->datastr_len ); 282 284 break; 283 285 284 286 case DICT_ENUMVAL: 285 DUP_string ( ((struct dict_enumval_data *)dest)->enum_name);287 DUP_string_len( dest->data.enumval.enum_name, &dest->datastr_len ); 286 288 break; 287 289 288 290 case DICT_AVP: 289 DUP_string ( ((struct dict_avp_data *)dest)->avp_name);291 DUP_string_len( dest->data.avp.avp_name, &dest->datastr_len ); 290 292 break; 291 293 292 294 case DICT_COMMAND: 293 DUP_string ( ((struct dict_cmd_data *)dest)->cmd_name);295 DUP_string_len( dest->data.cmd.cmd_name, &dest->datastr_len ); 294 296 break; 295 297 … … 456 458 TRACE_ENTRY("%p %p", o1, o2); 457 459 458 return strcmp( o1->data.type.type_name, o2->data.type.type_name);460 return fd_os_cmp( o1->data.type.type_name, o1->datastr_len, o2->data.type.type_name, o2->datastr_len ); 459 461 } 460 462 … … 464 466 TRACE_ENTRY("%p %p", o1, o2); 465 467 466 return strcmp( o1->data.enumval.enum_name, o2->data.enumval.enum_name);468 return fd_os_cmp( o1->data.enumval.enum_name, o1->datastr_len, o2->data.enumval.enum_name, o2->datastr_len ); 467 469 } 468 470 … … 470 472 static int order_enum_by_val ( struct dict_object *o1, struct dict_object *o2 ) 471 473 { 472 size_t oslen;473 int cmp = 0;474 475 474 TRACE_ENTRY("%p %p", o1, o2); 476 475 … … 478 477 switch ( o1->parent->data.type.type_base ) { 479 478 case AVP_TYPE_OCTETSTRING: 480 oslen = o1->data.enumval.enum_value.os.len; 481 if (o2->data.enumval.enum_value.os.len < oslen) 482 oslen = o2->data.enumval.enum_value.os.len; 483 cmp = memcmp(o1->data.enumval.enum_value.os.data, o2->data.enumval.enum_value.os.data, oslen ); 484 return (cmp ? cmp : ORDER_scalar(o1->data.enumval.enum_value.os.len,o2->data.enumval.enum_value.os.len)); 479 return fd_os_cmp( o1->data.enumval.enum_value.os.data, o1->data.enumval.enum_value.os.len, 480 o2->data.enumval.enum_value.os.data, o2->data.enumval.enum_value.os.len); 485 481 486 482 case AVP_TYPE_INTEGER32: … … 522 518 TRACE_ENTRY("%p %p", o1, o2); 523 519 524 return strcmp( o1->data.avp.avp_name, o2->data.avp.avp_name);520 return fd_os_cmp( o1->data.avp.avp_name, o1->datastr_len, o2->data.avp.avp_name, o2->datastr_len ); 525 521 } 526 522 … … 530 526 TRACE_ENTRY("%p %p", o1, o2); 531 527 532 return strcmp( o1->data.cmd.cmd_name, o2->data.cmd.cmd_name);528 return fd_os_cmp( o1->data.cmd.cmd_name, o1->datastr_len, o2->data.cmd.cmd_name, o2->datastr_len ); 533 529 } 534 530 … … 555 551 556 552 /* Compare two rule object by the AVP vendor & code that they refer (checks already performed) */ 557 static int order_rule_by_avp n( struct dict_object *o1, struct dict_object *o2 )553 static int order_rule_by_avpvc ( struct dict_object *o1, struct dict_object *o2 ) 558 554 { 559 555 TRACE_ENTRY("%p %p", o1, o2); … … 590 586 591 587 /* For search of strings in lists. isindex= 1 if the string is the ordering key of the list */ 592 #define SEARCH_string( str, sentinel, datafield, isindex ) { \ 593 char * __str = (char *) str; \ 588 /* it is expected that object->datastr_len is the length of the datafield parameter */ 589 #define SEARCH_os0_l( str, len, sentinel, datafield, isindex ) { \ 590 char * __str = (char *) (str); \ 591 size_t __strlen = (size_t)(len); \ 594 592 int __cmp; \ 595 593 struct fd_list * __li; \ 596 594 ret = 0; \ 597 595 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \ 598 __cmp = strcmp(__str, _O(__li->o)->data. datafield ); \ 596 __cmp = fd_os_cmp(__str, __strlen, \ 597 _O(__li->o)->data. datafield, _O(__li->o)->datastr_len);\ 599 598 if (__cmp == 0) { \ 600 599 if (result) \ … … 611 610 } 612 611 613 /* For search of octetstrings in lists (not \0 terminated). */ 614 #define SEARCH_ocstring( ostr, length, sentinel, osdatafield, isindex ) { \ 615 unsigned char * __ostr = (unsigned char *) ostr; \ 612 /* When len is not provided */ 613 #define SEARCH_os0( str, sentinel, datafield, isindex ) { \ 614 char * _str = (char *) (str); \ 615 size_t _strlen = strlen(_str); \ 616 SEARCH_os0_l( _str, _strlen, sentinel, datafield, isindex ); \ 617 } 618 619 620 /* For search of octetstrings in lists. */ 621 #define SEARCH_os( str, strlen, sentinel, osdatafield, isindex ) { \ 622 uint8_t * __str = (uint8_t *) (str); \ 623 size_t __strlen = (size_t)(strlen); \ 616 624 int __cmp; \ 617 size_t __len; \618 625 struct fd_list * __li; \ 619 626 ret = 0; \ 620 for (__li = (sentinel); __li->next != (sentinel); __li = __li->next) { \ 621 __len = _O(__li->next->o)->data. osdatafield .len; \ 622 if ( __len > (length) ) \ 623 __len = (length); \ 624 __cmp = memcmp(__ostr, \ 625 _O(__li->next->o)->data. osdatafield .data, \ 626 __len); \ 627 if (! __cmp) { \ 628 __cmp = ORDER_scalar( length, \ 629 _O(__li->next->o)->data. osdatafield .len); \ 630 } \ 627 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \ 628 __cmp = fd_os_cmp(__str, __strlen, \ 629 _O(__li->o)->data. osdatafield .data, \ 630 _O(__li->o)->data. osdatafield .len); \ 631 631 if (__cmp == 0) { \ 632 632 if (result) \ 633 *result = _O(__li-> next->o);\633 *result = _O(__li->o); \ 634 634 goto end; \ 635 635 } \ … … 644 644 645 645 /* For search of AVP name in rule lists. */ 646 #define SEARCH_ruleavpname( str, sentinel ) { \ 647 char * __str = (char *) str; \ 646 #define SEARCH_ruleavpname( str, strlen, sentinel ) { \ 647 char * __str = (char *) (str); \ 648 size_t __strlen = (size_t) (strlen); \ 648 649 int __cmp; \ 649 650 struct fd_list * __li; \ 650 651 ret = 0; \ 651 for (__li = (sentinel); __li->next != (sentinel); __li = __li->next) { \ 652 __cmp = strcmp(__str, \ 653 _O(__li->next->o)->data.rule.rule_avp->data.avp.avp_name);\ 652 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \ 653 __cmp = fd_os_cmp(__str, __strlen, \ 654 _O(__li->o)->data.rule.rule_avp->data.avp.avp_name, \ 655 _O(__li->o)->data.rule.rule_avp->datastr_len); \ 654 656 if (__cmp == 0) { \ 655 657 if (result) \ 656 *result = _O(__li-> next->o);\658 *result = _O(__li->o); \ 657 659 goto end; \ 658 660 } \ … … 677 679 goto end; \ 678 680 } \ 679 for (__li = (sentinel) ; __li->next!= (sentinel); __li = __li->next) { \680 __cmp= ORDER_scalar(value, _O(__li-> next->o)->data. datafield );\681 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \ 682 __cmp= ORDER_scalar(value, _O(__li->o)->data. datafield ); \ 681 683 if (__cmp == 0) { \ 682 684 if (result) \ 683 *result = _O(__li-> next->o);\685 *result = _O(__li->o); \ 684 686 goto end; \ 685 687 } \ … … 698 700 struct fd_list * __li; \ 699 701 ret = 0; \ 700 for ( __li = (sentinel); \ 701 __li->next != (sentinel); \ 702 __li = __li->next) { \ 702 for (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \ 703 703 __cmp = ORDER_scalar(value, \ 704 _O(__li-> next->o)->data.cmd.cmd_code ); \704 _O(__li->o)->data.cmd.cmd_code ); \ 705 705 if (__cmp == 0) { \ 706 706 uint8_t __mask, __val; \ 707 __mask = _O(__li-> next->o)->data.cmd.cmd_flag_mask;\708 __val = _O(__li-> next->o)->data.cmd.cmd_flag_val;\707 __mask = _O(__li->o)->data.cmd.cmd_flag_mask; \ 708 __val = _O(__li->o)->data.cmd.cmd_flag_val; \ 709 709 if ( ! (__mask & CMD_FLAG_REQUEST) ) \ 710 710 continue; \ … … 712 712 continue; \ 713 713 if (result) \ 714 *result = _O(__li-> next->o);\714 *result = _O(__li->o); \ 715 715 goto end; \ 716 716 } \ … … 739 739 case VENDOR_BY_NAME: 740 740 /* "what" is a vendor name */ 741 SEARCH_ string( what, &dict->dict_vendors.list[0], vendor.vendor_name, 0);741 SEARCH_os0( what, &dict->dict_vendors.list[0], vendor.vendor_name, 0); 742 742 break; 743 743 … … 771 771 case APPLICATION_BY_NAME: 772 772 /* "what" is an application name */ 773 SEARCH_ string( what, &dict->dict_applications.list[0], application.application_name, 0);773 SEARCH_os0( what, &dict->dict_applications.list[0], application.application_name, 0); 774 774 break; 775 775 … … 801 801 case TYPE_BY_NAME: 802 802 /* "what" is a type name */ 803 SEARCH_ string( what, &dict->dict_types, type.type_name, 1);803 SEARCH_os0( what, &dict->dict_types, type.type_name, 1); 804 804 break; 805 805 … … 850 850 if ( _what->search.enum_name != NULL ) { 851 851 /* We are looking for this string */ 852 SEARCH_ string( _what->search.enum_name, &parent->list[1], enumval.enum_name, 1 );852 SEARCH_os0( _what->search.enum_name, &parent->list[1], enumval.enum_name, 1 ); 853 853 } else { 854 854 /* We are looking for the value in enum_value */ 855 855 switch (parent->data.type.type_base) { 856 856 case AVP_TYPE_OCTETSTRING: 857 SEARCH_o cstring(_what->search.enum_value.os.data,857 SEARCH_os( _what->search.enum_value.os.data, 858 858 _what->search.enum_value.os.len, 859 859 &parent->list[2], … … 946 946 case AVP_BY_NAME: 947 947 /* "what" is the AVP name, vendor 0 */ 948 SEARCH_ string( what, &dict->dict_vendors.list[2], avp.avp_name, 1);948 SEARCH_os0( what, &dict->dict_vendors.list[2], avp.avp_name, 1); 949 949 break; 950 950 … … 969 969 /* We now have our vendor = head of the appropriate avp list */ 970 970 if (criteria == AVP_BY_NAME_AND_VENDOR) { 971 SEARCH_ string( _what->avp_name, &vendor->list[2], avp.avp_name, 1);971 SEARCH_os0( _what->avp_name, &vendor->list[2], avp.avp_name, 1); 972 972 } else { 973 973 /* AVP_BY_CODE_AND_VENDOR */ 974 SEARCH_scalar( _what->avp_code, &vendor->list[1], 974 SEARCH_scalar( _what->avp_code, &vendor->list[1], avp.avp_code, 1, (struct dict_object *)NULL ); 975 975 } 976 976 } … … 980 980 { 981 981 struct fd_list * li; 982 size_t wl = strlen((char *)what); 982 983 983 984 /* First, search for vendor 0 */ 984 SEARCH_ string( what, &dict->dict_vendors.list[2], avp.avp_name, 1);985 SEARCH_os0_l( what, wl, &dict->dict_vendors.list[2], avp.avp_name, 1); 985 986 986 987 /* If not found, loop for all vendors, until found */ 987 988 for (li = dict->dict_vendors.list[0].next; li != &dict->dict_vendors.list[0]; li = li->next) { 988 SEARCH_ string( what, &_O(li->o)->list[2], avp.avp_name, 1);989 SEARCH_os0_l( what, wl, &_O(li->o)->list[2], avp.avp_name, 1); 989 990 } 990 991 } … … 1008 1009 case CMD_BY_NAME: 1009 1010 /* "what" is a command name */ 1010 SEARCH_ string( what, &dict->dict_cmd_name, cmd.cmd_name, 1);1011 SEARCH_os0( what, &dict->dict_cmd_name, cmd.cmd_name, 1); 1011 1012 break; 1012 1013 … … 1096 1097 1097 1098 /* Perform the search */ 1098 SEARCH_ruleavpname( avp->data.avp.avp_name, &parent->list[2]);1099 SEARCH_ruleavpname( avp->data.avp.avp_name, avp->datastr_len, &parent->list[2]); 1099 1100 1100 1101 } … … 1274 1275 dump_object( &dict->dict_vendors, 0, 3, 0 ); 1275 1276 1276 fd_log_debug("###### Dumping applications#######\n");1277 fd_log_debug("###### Dumping applications #######\n"); 1277 1278 1278 1279 dump_object( &dict->dict_applications, 0, 1, 0 ); 1279 1280 1280 fd_log_debug("###### Dumping types#######\n");1281 fd_log_debug("###### Dumping types #######\n"); 1281 1282 1282 1283 dump_list( &dict->dict_types, 0, 2, 0 ); 1283 1284 1284 fd_log_debug("###### Dumping commands per name#######\n");1285 fd_log_debug("###### Dumping commands per name #######\n"); 1285 1286 1286 1287 dump_list( &dict->dict_cmd_name, 0, 2, 0 ); 1287 1288 1288 fd_log_debug("###### Dumping commands per code and flags#######\n");1289 fd_log_debug("###### Dumping commands per code and flags #######\n"); 1289 1290 1290 1291 dump_list( &dict->dict_cmd_code, 0, 0, 0 ); 1291 1292 1292 fd_log_debug("###### Statistics#######\n");1293 fd_log_debug("###### Statistics #######\n"); 1293 1294 1294 1295 for (i=1; i<=DICT_TYPE_MAX; i++) … … 1561 1562 /* Initialize the data of the new object */ 1562 1563 init_object(new, type); 1563 init_object_data( &new->data, data, type);1564 init_object_data(new, data, type); 1564 1565 new->dico = dict; 1565 1566 new->parent = parent; … … 1632 1633 case DICT_RULE: 1633 1634 /* A rule object is linked in list[2] of its parent command or AVP by the name of the AVP it refers */ 1634 ret = fd_list_insert_ordered ( &parent->list[2], &new->list[0], (int (*)(void*, void *))order_rule_by_avp n, (void **)&locref );1635 ret = fd_list_insert_ordered ( &parent->list[2], &new->list[0], (int (*)(void*, void *))order_rule_by_avpvc, (void **)&locref ); 1635 1636 if (ret) 1636 1637 goto error_unlock; … … 1659 1660 switch (type) { 1660 1661 case DICT_VENDOR: 1661 /* if we are here, it meas the two vendor id are identical */ 1662 if (strcmp(locref->data.vendor.vendor_name, new->data.vendor.vendor_name)) { 1662 /* if we are here, it means the two vendors id are identical */ 1663 if (fd_os_cmp(locref->data.vendor.vendor_name, locref->datastr_len, 1664 new->data.vendor.vendor_name, new->datastr_len)) { 1663 1665 TRACE_DEBUG(FULL, "Conflicting vendor name"); 1664 1666 break; … … 1670 1672 case DICT_APPLICATION: 1671 1673 /* got same id */ 1672 if (strcmp(locref->data.application.application_name, new->data.application.application_name)) { 1674 if (fd_os_cmp(locref->data.application.application_name, locref->datastr_len, 1675 new->data.application.application_name, new->datastr_len)) { 1673 1676 TRACE_DEBUG(FULL, "Conflicting application name"); 1674 1677 break; … … 1763 1766 1764 1767 case DICT_RULE: 1765 /* Both rules point to the same AVPs */1768 /* Both rules point to the same AVPs (code & vendor) */ 1766 1769 if (locref->data.rule.rule_position != new->data.rule.rule_position) { 1767 1770 TRACE_DEBUG(FULL, "Conflicting rule position"); … … 1847 1850 struct dictionary * new = NULL; 1848 1851 1849 TRACE_ENTRY(" ");1852 TRACE_ENTRY("%p", dict); 1850 1853 1851 1854 /* Sanity checks */ … … 1865 1868 /* Initialize the sentinel for vendors and AVP lists */ 1866 1869 init_object( &new->dict_vendors, DICT_VENDOR ); 1867 new->dict_vendors.data.vendor.vendor_name = "(no vendor)"; 1870 #define NO_VENDOR_NAME "(no vendor)" 1871 new->dict_vendors.data.vendor.vendor_name = NO_VENDOR_NAME; 1872 new->dict_vendors.datastr_len = CONSTSTRLEN(NO_VENDOR_NAME); 1868 1873 new->dict_vendors.list[0].o = NULL; /* overwrite since element is also sentinel for this list. */ 1869 1874 new->dict_vendors.dico = new; … … 1871 1876 /* Initialize the sentinel for applications */ 1872 1877 init_object( &new->dict_applications, DICT_APPLICATION ); 1873 new->dict_applications.data.application.application_name = "Diameter Common Messages"; 1878 #define APPLICATION_0_NAME "Diameter Common Messages" 1879 new->dict_applications.data.application.application_name = APPLICATION_0_NAME; 1880 new->dict_applications.datastr_len = CONSTSTRLEN(APPLICATION_0_NAME); 1874 1881 new->dict_applications.list[0].o = NULL; /* overwrite since since element is also sentinel for this list. */ 1875 1882 new->dict_applications.dico = new; … … 1884 1891 /* Initialize the error command object */ 1885 1892 init_object( &new->dict_cmd_error, DICT_COMMAND ); 1886 new->dict_cmd_error.data.cmd.cmd_name="(generic error format)"; 1893 #define GENERIC_ERROR_NAME "(generic error format)" 1894 new->dict_cmd_error.data.cmd.cmd_name = GENERIC_ERROR_NAME; 1895 new->dict_cmd_error.datastr_len = CONSTSTRLEN(GENERIC_ERROR_NAME); 1887 1896 new->dict_cmd_error.data.cmd.cmd_flag_mask=CMD_FLAG_ERROR | CMD_FLAG_REQUEST | CMD_FLAG_RETRANSMIT; 1888 1897 new->dict_cmd_error.data.cmd.cmd_flag_val =CMD_FLAG_ERROR; -
libfdproto/fdproto-internal.h
r689 r706 65 65 66 66 /* Messages / sessions API */ 67 int fd_sess_fromsid_msg ( u nsigned char* sid, size_t len, struct session ** session, int * new);67 int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new); 68 68 int fd_sess_ref_msg ( struct session * session ); 69 69 int fd_sess_reclaim_msg ( struct session ** session ); -
libfdproto/init.c
r693 r706 35 35 36 36 #include "fdproto-internal.h" 37 38 /* Only for CPU cache flush */39 pthread_mutex_t fd_cpu_mtx_dummy = PTHREAD_MUTEX_INITIALIZER;40 37 41 38 /* function to free the threadnames */ -
libfdproto/lists.c
r662 r706 163 163 164 164 165 /********************************************************************************************************/166 /* Hash function -- credits to Austin Appleby, thank you ^^ */167 /* See http://murmurhash.googlepages.com for more information on this function */168 169 /* the strings are NOT always aligned properly (ex: received in RADIUS message), so we use the aligned MurmurHash2 function as needed */170 #define _HASH_MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }171 uint32_t fd_hash ( char * string, size_t len )172 {173 uint32_t hash = len;174 char * data = string;175 176 const unsigned int m = 0x5bd1e995;177 const int r = 24;178 int align = (long)string & 3;179 180 if (!align || (len < 4)) {181 182 /* In case data is aligned, MurmurHash2 function */183 while(len >= 4)184 {185 /* Mix 4 bytes at a time into the hash */186 uint32_t k = *(uint32_t *)data; /* We don't care about the byte order */187 188 _HASH_MIX(hash, k, m);189 190 data += 4;191 len -= 4;192 }193 194 /* Handle the last few bytes of the input */195 switch(len) {196 case 3: hash ^= data[2] << 16;197 case 2: hash ^= data[1] << 8;198 case 1: hash ^= data[0];199 hash *= m;200 }201 202 } else {203 /* Unaligned data, use alignment-safe slower version */204 205 /* Pre-load the temp registers */206 uint32_t t = 0, d = 0;207 switch(align)208 {209 case 1: t |= data[2] << 16;210 case 2: t |= data[1] << 8;211 case 3: t |= data[0];212 }213 t <<= (8 * align);214 215 data += 4-align;216 len -= 4-align;217 218 /* From this point, "data" can be read by chunks of 4 bytes */219 220 int sl = 8 * (4-align);221 int sr = 8 * align;222 223 /* Mix */224 while(len >= 4)225 {226 uint32_t k;227 228 d = *(unsigned int *)data;229 k = (t >> sr) | (d << sl);230 231 _HASH_MIX(hash, k, m);232 233 t = d;234 235 data += 4;236 len -= 4;237 }238 239 /* Handle leftover data in temp registers */240 d = 0;241 if(len >= align)242 {243 uint32_t k;244 245 switch(align)246 {247 case 3: d |= data[2] << 16;248 case 2: d |= data[1] << 8;249 case 1: d |= data[0];250 }251 252 k = (t >> sr) | (d << sl);253 _HASH_MIX(hash, k, m);254 255 data += align;256 len -= align;257 258 /* Handle tail bytes */259 260 switch(len)261 {262 case 3: hash ^= data[2] << 16;263 case 2: hash ^= data[1] << 8;264 case 1: hash ^= data[0];265 hash *= m;266 };267 }268 else269 {270 switch(len)271 {272 case 3: d |= data[2] << 16;273 case 2: d |= data[1] << 8;274 case 1: d |= data[0];275 case 0: hash ^= (t >> sr) | (d << sl);276 hash *= m;277 }278 }279 280 281 }282 283 /* Do a few final mixes of the hash to ensure the last few284 bytes are well-incorporated. */285 hash ^= hash >> 13;286 hash *= m;287 hash ^= hash >> 15;288 289 return hash;290 } -
libfdproto/log.c
r687 r706 83 83 /* First, check if a value is already assigned to the current thread */ 84 84 val = pthread_getspecific(fd_log_thname); 85 if (TRACE_BOOL(ANNOYING)) { 86 if (val) { 87 fd_log_debug("(Thread '%s' renamed to '%s')\n", (char *)val, name); 88 } else { 89 fd_log_debug("(Thread %p named '%s')\n", pthread_self(), name?:"(nil)"); 90 } 91 } 85 92 if (val != NULL) { 86 TRACE_DEBUG(FULL, "Freeing old thread name: %s", val);87 93 free(val); 88 94 } -
libfdproto/messages.c
r704 r706 126 126 struct timespec timeout; 127 127 } msg_cb; /* Callback to be called when an answer is received, if not NULL */ 128 char * msg_src_id; /* Diameter Id of the peer this message was received from. This string is malloc'd and must be freed */ 128 DiamId_t msg_src_id; /* Diameter Id of the peer this message was received from. This string is malloc'd and must be freed */ 129 size_t msg_src_id_len; /* cached length of this string */ 129 130 }; 130 131 … … 332 333 if (sess && dict) { 333 334 struct dict_object * sess_id_avp; 334 char * sid; 335 os0_t sid; 336 size_t sidlen; 335 337 struct avp * avp; 336 338 union avp_value val; 337 339 338 340 CHECK_FCT( fd_dict_search( dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &sess_id_avp, ENOENT) ); 339 CHECK_FCT( fd_sess_getsid ( sess, &sid ) );341 CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ) ); 340 342 CHECK_FCT( fd_msg_avp_new ( sess_id_avp, 0, &avp ) ); 341 val.os.data = (unsigned char *)sid;342 val.os.len = s trlen(sid);343 val.os.data = sid; 344 val.os.len = sidlen; 343 345 CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) ); 344 346 CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_FIRST_CHILD, avp ) ); … … 703 705 msg->msg_public.msg_eteid 704 706 ); 705 fd_log_debug_fstr(fstr, INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p asso:%d sess:%p src:%s \n",706 INOBJHDRVAL, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.fct, msg->msg_cb.data, msg->msg_query, msg->msg_associated, msg->msg_sess, msg->msg_src_id?:"(nil)" );707 fd_log_debug_fstr(fstr, INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p asso:%d sess:%p src:%s(%zd)\n", 708 INOBJHDRVAL, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.fct, msg->msg_cb.data, msg->msg_query, msg->msg_associated, msg->msg_sess, msg->msg_src_id?:"(nil)", msg->msg_src_id_len); 707 709 } 708 710 … … 1012 1014 } 1013 1015 1016 /* cache the dictionary model for next function to avoid re-searching at every incoming message */ 1017 static struct dict_object *cached_avp_rr_model = NULL; 1018 static struct dictionary *cached_avp_rr_dict = NULL; 1019 static pthread_mutex_t cached_avp_rr_lock = PTHREAD_MUTEX_INITIALIZER; 1020 1014 1021 /* Associate source peer */ 1015 int fd_msg_source_set( struct msg * msg, char * diamid, int add_rr, struct dictionary * dict )1016 { 1017 TRACE_ENTRY( "%p %p % d %p", msg, diamid, add_rr, dict);1022 int fd_msg_source_set( struct msg * msg, DiamId_t diamid, size_t diamidlen, int add_rr, struct dictionary * dict ) 1023 { 1024 TRACE_ENTRY( "%p %p %zd %d %p", msg, diamid, diamidlen, add_rr, dict); 1018 1025 1019 1026 /* Check we received a valid message */ … … 1021 1028 1022 1029 /* Cleanup any previous source */ 1023 free(msg->msg_src_id); msg->msg_src_id = NULL; 1030 free(msg->msg_src_id); msg->msg_src_id = NULL; msg->msg_src_id_len = 0; 1024 1031 1025 1032 /* If the request is to cleanup the source, we are done */ … … 1029 1036 1030 1037 /* Otherwise save the new informations */ 1031 CHECK_MALLOC( msg->msg_src_id = strdup(diamid) ); 1038 CHECK_MALLOC( msg->msg_src_id = os0dup(diamid, diamidlen) ); 1039 msg->msg_src_id_len = diamidlen; 1040 1032 1041 1033 1042 if (add_rr) { 1034 struct dict_object *avp_rr_model ;1043 struct dict_object *avp_rr_model = NULL; 1035 1044 avp_code_t code = AC_ROUTE_RECORD; 1036 1045 struct avp *avp; 1037 1046 union avp_value val; 1038 1047 1039 /* Find the model for Route-Record in the dictionary */ 1040 CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_CODE, &code, &avp_rr_model, ENOENT) ); 1048 /* Lock the cached values */ 1049 CHECK_POSIX( pthread_mutex_lock(&cached_avp_rr_lock) ); 1050 if (cached_avp_rr_dict == dict) { 1051 avp_rr_model = cached_avp_rr_model; 1052 } 1053 CHECK_POSIX( pthread_mutex_unlock(&cached_avp_rr_lock) ); 1054 1055 /* If it was not cached */ 1056 if (!avp_rr_model) { 1057 /* Find the model for Route-Record in the dictionary */ 1058 CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_CODE, &code, &avp_rr_model, ENOENT) ); 1059 1060 /* Now cache this result */ 1061 CHECK_POSIX( pthread_mutex_lock(&cached_avp_rr_lock) ); 1062 cached_avp_rr_dict = dict; 1063 cached_avp_rr_model = avp_rr_model; 1064 CHECK_POSIX( pthread_mutex_unlock(&cached_avp_rr_lock) ); 1065 } 1041 1066 1042 1067 /* Create the AVP with this model */ … … 1045 1070 /* Set the AVP value with the diameter id */ 1046 1071 memset(&val, 0, sizeof(val)); 1047 val.os.data = (u nsigned char*)diamid;1048 val.os.len = strlen(diamid);1072 val.os.data = (uint8_t *)diamid; 1073 val.os.len = diamidlen; 1049 1074 CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) ); 1050 1075 … … 1057 1082 } 1058 1083 1059 int fd_msg_source_get( struct msg * msg, char ** diamid)1060 { 1061 TRACE_ENTRY( "%p %p ", msg, diamid);1084 int fd_msg_source_get( struct msg * msg, DiamId_t* diamid, size_t * diamidlen ) 1085 { 1086 TRACE_ENTRY( "%p %p %p", msg, diamid, diamidlen); 1062 1087 1063 1088 /* Check we received valid parameters */ … … 1067 1092 /* Copy the informations */ 1068 1093 *diamid = msg->msg_src_id; 1094 1095 if (diamidlen) 1096 *diamidlen = msg->msg_src_id_len; 1069 1097 1070 1098 /* done */ … … 2225 2253 2226 2254 /* Call all dispatch callbacks for a given message */ 2227 int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, c onst char ** error_code)2255 int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, char ** error_code) 2228 2256 { 2229 2257 struct dictionary * dict; -
libfdproto/rt_data.c
r662 r706 50 50 /* Items of the errors list */ 51 51 struct rtd_error { 52 struct fd_list chain; /* link in the list, ordered by nexthop */ 53 char * nexthop;/* the peer the message was sent to */ 54 char * erh; /* the origin of the error */ 52 struct fd_list chain; /* link in the list, ordered by nexthop (fd_os_cmp) */ 53 DiamId_t nexthop;/* the peer the message was sent to */ 54 size_t nexthoplen; /* cached string length */ 55 DiamId_t erh; /* the origin of the error */ 56 size_t erhlen; /* cached string length */ 55 57 uint32_t code; /* the error code */ 56 58 }; … … 107 109 } 108 110 109 /* Add a peer to the candidates list */110 int fd_rtd_candidate_add(struct rt_data * rtd, char * peerid, char * realm)111 /* Add a peer to the candidates list. The source is our local peer list, so no need to care for the case here. */ 112 int fd_rtd_candidate_add(struct rt_data * rtd, DiamId_t peerid, size_t peeridlen, DiamId_t realm, size_t realmlen) 111 113 { 112 114 struct fd_list * prev; 113 115 struct rtd_candidate * new; 114 116 115 TRACE_ENTRY("%p %p ", rtd, peerid);116 CHECK_PARAMS(rtd && peerid );117 TRACE_ENTRY("%p %p %zd %p %zd", rtd, peerid, peeridlen, realm, realmlen); 118 CHECK_PARAMS(rtd && peerid && peeridlen); 117 119 118 120 /* Since the peers are ordered when they are added (fd_g_activ_peers) we search for the position from the end -- this should be efficient */ 119 121 for (prev = rtd->candidates.prev; prev != &rtd->candidates; prev = prev->prev) { 120 122 struct rtd_candidate * cp = (struct rtd_candidate *) prev; 121 int cmp = strcmp(peerid, cp->diamid);123 int cmp = fd_os_cmp(peerid, peeridlen, cp->diamid, cp->diamidlen); 122 124 if (cmp > 0) 123 125 break; … … 127 129 } 128 130 131 /* Create the new entry */ 129 132 CHECK_MALLOC( new = malloc(sizeof(struct rtd_candidate)) ); 130 133 memset(new, 0, sizeof(struct rtd_candidate) ); 131 134 fd_list_init(&new->chain, NULL); 132 CHECK_MALLOC( new->diamid = strdup(peerid) ); 133 CHECK_MALLOC( new->realm = strdup(realm) ); 134 135 CHECK_MALLOC( new->diamid = os0dup(peerid, peeridlen) ) 136 new->diamidlen = peeridlen; 137 if (realm) { 138 CHECK_MALLOC( new->realm = os0dup(realm, realmlen) ) 139 new->realmlen = realmlen; 140 } 141 142 /* insert in the list at the correct position */ 135 143 fd_list_insert_after(prev, &new->chain); 136 144 … … 138 146 } 139 147 140 /* Remove a peer from the candidates (if it is found) */141 void fd_rtd_candidate_del(struct rt_data * rtd, char * peerid, size_t sz /* if !0, peerid does not need to be \0 terminated */)148 /* Remove a peer from the candidates (if it is found). Case insensitive search since the names are received from other peers */ 149 void fd_rtd_candidate_del(struct rt_data * rtd, uint8_t * id, size_t idsz) 142 150 { 143 151 struct fd_list * li; 144 152 145 TRACE_ENTRY("%p %p %zd", rtd, peerid, sz); 146 CHECK_PARAMS_DO( rtd && peerid , return ); 153 TRACE_ENTRY("%p %p %zd", rtd, id, idsz); 154 CHECK_PARAMS_DO( rtd && id && idsz, return ); 155 156 if (!fd_os_is_valid_DiameterIdentity(id, idsz)) 157 /* it cannot be in the list */ 158 return; 147 159 148 160 for (li = rtd->candidates.next; li != &rtd->candidates; li = li->next) { 149 161 struct rtd_candidate * c = (struct rtd_candidate *) li; 150 int cmp; 151 if (sz) { 152 cmp = strncmp(peerid, c->diamid, sz); 153 if (!cmp) { 154 int len = strlen(c->diamid); 155 if (sz < len) 156 cmp = -1; 157 else if (sz == len) 158 cmp = 0; 159 else cmp = 1; 160 } 161 } else { 162 cmp = strcmp(peerid, c->diamid); 163 } 162 163 int cmp = fd_os_almostcasecmp(id, idsz, c->diamid, c->diamidlen); 164 164 165 165 if (!cmp) { … … 175 175 continue; 176 176 177 /* The list is ordered only if not extracted */177 /* The list is guaranteed to be ordered only if not extracted */ 178 178 if (! rtd->extracted) 179 179 break; … … 183 183 } 184 184 185 /* If a peer returned a protocol error for this message, save it so that we don't try to send it there again */ 186 int fd_rtd_error_add(struct rt_data * rtd, char * sentto, uint8_t * origin, size_t originsz, uint32_t rcode) 185 /* If a peer returned a protocol error for this message, save it so that we don't try to send it there again. 186 Case insensitive search since the names are received from other peers*/ 187 int fd_rtd_error_add(struct rt_data * rtd, DiamId_t sentto, size_t senttolen, uint8_t * origin, size_t originsz, uint32_t rcode) 187 188 { 188 189 struct fd_list * li; 189 190 int match = 0; 190 191 191 TRACE_ENTRY("%p %p % p %d", rtd, sentto, origin, rcode);192 CHECK_PARAMS( rtd && sentto ); /* origin may be NULL */192 TRACE_ENTRY("%p %p %zd %p %zd %u", rtd, sentto, senttolen, origin, originsz, rcode); 193 CHECK_PARAMS( rtd && sentto && senttolen ); /* origin may be NULL */ 193 194 194 195 /* First add the new error entry */ 195 196 for (li = rtd->errors.next; li != &rtd->errors; li = li->next) { 196 197 struct rtd_error * e = (struct rtd_error *) li; 197 int cmp = strcmp(sentto, e->nexthop);198 int cmp = fd_os_cmp(sentto, senttolen, e->nexthop, e->nexthoplen); 198 199 if (cmp > 0) 199 200 continue; … … 203 204 } 204 205 205 /* If we already had this entry, we should not have sent the message again to this peer... anyway... */ 206 /* If we already had this entry, we should not have sent the message again to this peer... anyway, let's close our eyes. */ 207 /* in the normal case, we save the error */ 206 208 if (!match) { 207 209 /* Add a new entry in the error list */ … … 210 212 memset(new, 0, sizeof(struct rtd_error)); 211 213 fd_list_init(&new->chain, NULL); 212 CHECK_MALLOC(new->nexthop = strdup(sentto)); 214 215 CHECK_MALLOC(new->nexthop = os0dup(sentto, senttolen)); 216 new->nexthoplen = senttolen; 217 213 218 if (origin) { 214 CHECK_MALLOC( new->erh = malloc(originsz + 1) ); 215 memcpy(new->erh, origin, originsz); 216 new->erh[originsz] = '\0'; 219 if (!originsz) { 220 originsz=strlen((char *)origin); 221 } else { 222 if (!fd_os_is_valid_DiameterIdentity(origin, originsz)){ 223 TRACE_DEBUG(FULL, "Received error %d from peer with invalid Origin-Host AVP, not saved", rcode); 224 origin = NULL; 225 goto after_origin; 226 } 227 } 228 CHECK_MALLOC( new->erh = (DiamId_t)os0dup(origin, originsz) ); 229 new->erhlen = originsz; 217 230 } 231 after_origin: 218 232 new->code = rcode; 219 233 fd_list_insert_before(li, &new->chain); … … 221 235 222 236 /* Finally, remove this (these) peers from the candidate list */ 223 fd_rtd_candidate_del(rtd, sentto, 0);237 fd_rtd_candidate_del(rtd, (os0_t)sentto, senttolen); 224 238 if (origin) 225 fd_rtd_candidate_del(rtd, (char *)origin, originsz);239 fd_rtd_candidate_del(rtd, origin, originsz); 226 240 227 241 /* Done! */ … … 274 288 fd_list_move_end(candidates, &highest); 275 289 276 /* And the new high score is this reset */290 /* And the new high score is set */ 277 291 hs = c->score; 278 292 } -
libfdproto/sessions.c
r691 r706 69 69 int eyec; /* An eye catcher also used to ensure the object is valid, must be SH_EYEC */ 70 70 int id; /* A unique integer to identify this handler */ 71 void (*cleanup)(session_state *, char *, void *); /* The cleanup function to be called for cleaning a state */71 void (*cleanup)(session_state *, os0_t, void *); /* The cleanup function to be called for cleaning a state */ 72 72 void *opaque; /* a value that is passed as is to the cleanup callback */ 73 73 }; … … 84 84 union { 85 85 struct session_handler *hdl; /* The handler for which this state was registered */ 86 char *sid; /* For deleted state, the sid of the session it belong to */86 os0_t sid; /* For deleted state, the sid of the session it belong to */ 87 87 }; 88 88 }; … … 92 92 int eyec; /* Eyecatcher, SI_EYEC */ 93 93 94 char * sid; /* The \0-terminated Session-Id */ 94 os0_t sid; /* The \0-terminated Session-Id */ 95 size_t sidlen; /* cached length of sid */ 95 96 uint32_t hash; /* computed hash of sid */ 96 97 struct fd_list chain_h;/* chaining in the hash table of sessions. */ … … 102 103 struct fd_list states; /* Sentinel for the list of states of this session. */ 103 104 int msg_cnt;/* Reference counter for the messages pointing to this session */ 105 int is_destroyed; /* boolean telling if fd_sess_detroy has been called on this */ 104 106 }; 105 107 106 108 /* Sessions hash table, to allow fast sid to session retrieval */ 107 109 static struct { 108 struct fd_list sentinel; /* sentinel element for this sublist */110 struct fd_list sentinel; /* sentinel element for this sublist. The sublist is ordered by hash value, then fd_os_cmp(sid). */ 109 111 pthread_mutex_t lock; /* the mutex for this sublist -- we might probably change it to rwlock for a little optimization */ 110 112 } sess_hash [ 1 << SESS_HASH_SIZE ] ; … … 132 134 /********************************************************************************************************/ 133 135 134 /* Initialize a session object. It is not linked now. sid must be already malloc'ed. */135 static struct session * new_session( char * sid, size_t sidlen)136 /* Initialize a session object. It is not linked now. sid must be already malloc'ed. The hash has already been computed. */ 137 static struct session * new_session(os0_t sid, size_t sidlen, uint32_t hash) 136 138 { 137 139 struct session * sess; 138 140 139 TRACE_ENTRY("%p % d", sid, sidlen);141 TRACE_ENTRY("%p %zd", sid, sidlen); 140 142 CHECK_PARAMS_DO( sid && sidlen, return NULL ); 141 143 … … 146 148 147 149 sess->sid = sid; 148 sess->hash = fd_hash(sid, sidlen); 150 sess->sidlen = sidlen; 151 sess->hash = hash; 149 152 fd_list_init(&sess->chain_h, sess); 150 153 … … 157 160 158 161 return sess; 162 } 163 164 /* destroy the session object. It should really be already unlinked... */ 165 static void del_session(struct session * s) 166 { 167 ASSERT(FD_IS_LIST_EMPTY(&s->states)); 168 free(s->sid); 169 fd_list_unlink(&s->chain_h); 170 fd_list_unlink(&s->expire); 171 CHECK_POSIX_DO( pthread_mutex_destroy(&s->stlock), /* continue */ ); 172 free(s); 159 173 } 160 174 … … 250 264 TRACE_ENTRY(""); 251 265 CHECK_FCT_DO( fd_thr_term(&exp_thr), /* continue */ ); 266 267 /* Destroy all sessions in the hash table, and the hash table itself? -- How to do it without a race condition ? */ 268 252 269 return; 253 270 } 254 271 255 272 /* Create a new handler */ 256 int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, char * sid, void * opaque), void * opaque )273 int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state *, os0_t, void *), void * opaque ) 257 274 { 258 275 struct session_handler *new; … … 299 316 CHECK_POSIX( pthread_mutex_lock(&sess_hash[i].lock) ); 300 317 301 for (li_si = sess_hash[i].sentinel.next; li_si != &sess_hash[i].sentinel; li_si = li_si->next) { 318 for (li_si = sess_hash[i].sentinel.next; li_si != &sess_hash[i].sentinel; li_si = li_si->next) { /* for each session in the hash line */ 302 319 struct fd_list * li_st; 303 320 struct session * sess = (struct session *)(li_si->o); 304 321 CHECK_POSIX( pthread_mutex_lock(&sess->stlock) ); 305 for (li_st = sess->states.next; li_st != &sess->states; li_st = li_st->next) { 322 for (li_st = sess->states.next; li_st != &sess->states; li_st = li_st->next) { /* for each state in this session */ 306 323 struct state * st = (struct state *)(li_st->o); 307 324 /* The list is ordered */ … … 311 328 /* This state belongs to the handler we are deleting, move the item to the deleted_states list */ 312 329 fd_list_unlink(&st->chain); 313 CHECK_MALLOC( st->sid = strdup(sess->sid) );330 st->sid = sess->sid; 314 331 fd_list_insert_before(&deleted_states, &st->chain); 315 332 } … … 326 343 TRACE_DEBUG(FULL, "Calling cleanup handler for session '%s' and data %p", st->sid, st->state); 327 344 (*del->cleanup)(st->state, st->sid, del->opaque); 328 free(st->sid);329 345 fd_list_unlink(&st->chain); 330 346 free(st); … … 343 359 344 360 /* Create a new session object with the default timeout value, and link it */ 345 int fd_sess_new ( struct session ** session, char * diamId, char* opt, size_t optlen )346 { 347 char *sid = NULL;361 int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen ) 362 { 363 os0_t sid = NULL; 348 364 size_t sidlen; 365 uint32_t hash; 349 366 struct session * sess; 350 367 struct fd_list * li; 351 368 int found = 0; 352 353 TRACE_ENTRY("%p %p %p %d", session, diamId, opt, optlen); 354 CHECK_PARAMS( session && (diamId || opt) ); 355 369 int ret = 0; 370 371 TRACE_ENTRY("%p %p %zd %p %zd", session, diamid, diamidlen, opt, optlen); 372 CHECK_PARAMS( session && (diamid || opt) ); 373 374 if (diamid) { 375 if (!diamidlen) { 376 diamidlen = strlen(diamid); 377 } 378 /* We check if the string is a valid DiameterIdentity */ 379 CHECK_PARAMS( fd_os_is_valid_DiameterIdentity((uint8_t *)diamid, diamidlen) ); 380 } else { 381 diamidlen = 0; 382 } 383 if (opt) { 384 if (!optlen) { 385 optlen = strlen((char *)opt); 386 } else { 387 CHECK_PARAMS( fd_os_is_valid_os0(opt, optlen) ); 388 } 389 } else { 390 optlen = 0; 391 } 392 356 393 /* Ok, first create the identifier for the string */ 357 if (diam Id == NULL) {394 if (diamid == NULL) { 358 395 /* opt is the full string */ 359 if (optlen) { 360 CHECK_MALLOC( sid = malloc(optlen + 1) ); 361 strncpy(sid, opt, optlen); 362 sid[optlen] = '\0'; 363 sidlen = optlen; 364 } else { 365 CHECK_MALLOC( sid = strdup(opt) ); 366 sidlen = strlen(sid); 367 } 396 CHECK_MALLOC( sid = os0dup(opt, optlen) ); 397 sidlen = optlen; 368 398 } else { 369 399 uint32_t sid_h_cpy; 370 400 uint32_t sid_l_cpy; 371 401 /* "<diamId>;<high32>;<low32>[;opt]" */ 372 sidlen = strlen(diamId);402 sidlen = diamidlen; 373 403 sidlen += 22; /* max size of ';<high32>;<low32>' */ 374 404 if (opt) 375 sidlen += 1 + (optlen ?: strlen(opt)) ;405 sidlen += 1 + optlen; /* ';opt' */ 376 406 sidlen++; /* space for the final \0 also */ 377 407 CHECK_MALLOC( sid = malloc(sidlen) ); … … 385 415 386 416 if (opt) { 387 if (optlen) 388 sidlen = snprintf(sid, sidlen, "%s;%u;%u;%.*s", diamId, sid_h_cpy, sid_l_cpy, (int)optlen, opt); 389 else 390 sidlen = snprintf(sid, sidlen, "%s;%u;%u;%s", diamId, sid_h_cpy, sid_l_cpy, opt); 417 sidlen = snprintf((char*)sid, sidlen, "%.*s;%u;%u;%.*s", (int)diamidlen, diamid, sid_h_cpy, sid_l_cpy, (int)optlen, opt); 391 418 } else { 392 sidlen = snprintf( sid, sidlen, "%s;%u;%u", diamId, sid_h_cpy, sid_l_cpy);419 sidlen = snprintf((char*)sid, sidlen, "%.*s;%u;%u", (int)diamidlen, diamid, sid_h_cpy, sid_l_cpy); 393 420 } 394 421 } 395 422 396 /* Initialize the session object now, to spend less time inside locked section later. 397 * Cons: we malloc then free if there is already a session with same SID; we could malloc later to avoid this. */ 398 CHECK_MALLOC( sess = new_session(sid, sidlen) ); 423 hash = fd_os_hash(sid, sidlen); 399 424 400 425 /* Now find the place to add this object in the hash table. */ 401 CHECK_POSIX( pthread_mutex_lock( H_LOCK( sess->hash) ) );402 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK( sess->hash) );403 404 for (li = H_LIST( sess->hash)->next; li != H_LIST(sess->hash); li = li->next) {426 CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash) ) ); 427 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) ); 428 429 for (li = H_LIST(hash)->next; li != H_LIST(hash); li = li->next) { 405 430 int cmp; 406 431 struct session * s = (struct session *)(li->o); 407 432 408 433 /* The list is ordered by hash and sid (in case of collisions) */ 409 if (s->hash < sess->hash)434 if (s->hash < hash) 410 435 continue; 411 if (s->hash > sess->hash)436 if (s->hash > hash) 412 437 break; 413 438 414 cmp = strcasecmp(s->sid, sess->sid);439 cmp = fd_os_cmp(s->sid, s->sidlen, sid, sidlen); 415 440 if (cmp < 0) 416 441 continue; … … 424 449 } 425 450 426 /* If the session did not exist, we can link it in global tables */451 /* If the session did not exist, we can create it & link it in global tables */ 427 452 if (!found) { 453 CHECK_MALLOC_DO(sess = new_session(sid, sidlen, hash), 454 { 455 ret = ENOMEM; 456 goto out; 457 } ); 458 428 459 fd_list_insert_before(li, &sess->chain_h); /* hash table */ 429 430 /* We must also insert in the expiry list */ 431 CHECK_POSIX( pthread_mutex_lock( &exp_lock ) ); 432 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock ); 433 434 /* Find the position in that list. We take it in reverse order */ 435 for (li = exp_sentinel.prev; li != &exp_sentinel; li = li->prev) { 436 struct session * s = (struct session *)(li->o); 437 if (TS_IS_INFERIOR( &s->timeout, &sess->timeout ) ) 438 break; 460 } else { 461 /* it was found: was it previously destroyed? */ 462 if ((*session)->is_destroyed == 0) { 463 ret = EALREADY; 464 goto out; 465 } else { 466 /* the session was marked destroyed, let's re-activate it. */ 467 TODO("Re-creating a deleted session. Should investigate if this can lead to an issue... (need more feedback)"); 468 sess = *session; 469 470 /* update the expiry time */ 471 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &sess->timeout), { ASSERT(0); } ); 472 sess->timeout.tv_sec += SESS_DEFAULT_LIFETIME; 439 473 } 440 fd_list_insert_after( li, &sess->expire ); 441 442 /* We added a new expiring element, we must signal */ 443 if (li == &exp_sentinel) { 444 CHECK_POSIX_DO( pthread_cond_signal(&exp_cond), { ASSERT(0); } ); /* if it fails, we might not pop the cleanup handlers, but this should not happen -- and we'd have a serious problem otherwise */ 445 } 446 447 #if 0 448 if (TRACE_BOOL(ANNOYING)) { 449 TRACE_DEBUG(FULL, "-- Updated session expiry list --"); 450 for (li = exp_sentinel.next; li != &exp_sentinel; li = li->next) { 451 struct session * s = (struct session *)(li->o); 452 fd_sess_dump(FULL, s); 453 } 454 TRACE_DEBUG(FULL, "-- end of expiry list --"); 455 } 456 #endif 457 458 /* We're done */ 459 pthread_cleanup_pop(0); 460 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 */ 461 } 462 474 } 475 476 /* We must insert in the expiry list */ 477 CHECK_POSIX( pthread_mutex_lock( &exp_lock ) ); 478 pthread_cleanup_push( fd_cleanup_mutex, &exp_lock ); 479 480 /* Find the position in that list. We take it in reverse order */ 481 for (li = exp_sentinel.prev; li != &exp_sentinel; li = li->prev) { 482 struct session * s = (struct session *)(li->o); 483 if (TS_IS_INFERIOR( &s->timeout, &sess->timeout ) ) 484 break; 485 } 486 fd_list_insert_after( li, &sess->expire ); 487 488 /* We added a new expiring element, we must signal */ 489 if (li == &exp_sentinel) { 490 CHECK_POSIX_DO( pthread_cond_signal(&exp_cond), { ASSERT(0); } ); /* if it fails, we might not pop the cleanup handlers, but this should not happen -- and we'd have a serious problem otherwise */ 491 } 492 493 /* We're done with the locked part */ 463 494 pthread_cleanup_pop(0); 464 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(sess->hash) ) ); 465 466 /* If a session already existed, we must destroy the new element */ 467 if (found) { 468 CHECK_FCT( fd_sess_destroy( &sess ) ); /* we could avoid locking this time for optimization */ 469 return EALREADY; 470 } 495 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 */ 496 497 out: 498 ; 499 pthread_cleanup_pop(0); 500 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) ); 501 502 if (ret) /* in case of error */ 503 return ret; 471 504 472 505 *session = sess; … … 475 508 476 509 /* Find or create a session */ 477 int fd_sess_fromsid ( char* sid, size_t len, struct session ** session, int * new)510 int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * new) 478 511 { 479 512 int ret; … … 482 515 CHECK_PARAMS( sid && session ); 483 516 517 if (!fd_os_is_valid_os0(sid,len)) { 518 TRACE_DEBUG(INFO, "Warning: a Session-Id value contains \\0 chars... (len:%zd, begin:'%.*s')\n => Debug messages may be truncated.", len, len, sid); 519 } 520 484 521 /* All the work is done in sess_new */ 485 ret = fd_sess_new ( session, NULL, sid, len );522 ret = fd_sess_new ( session, NULL, 0, sid, len ); 486 523 switch (ret) { 487 524 case 0: … … 500 537 501 538 /* Get the sid of a session */ 502 int fd_sess_getsid ( struct session * session, char ** sid)539 int fd_sess_getsid ( struct session * session, os0_t * sid, size_t * sidlen ) 503 540 { 504 541 TRACE_ENTRY("%p %p", session, sid); … … 507 544 508 545 *sid = session->sid; 546 if (sidlen) 547 *sidlen = session->sidlen; 509 548 510 549 return 0; … … 543 582 } 544 583 545 #if 0546 if (TRACE_BOOL(ANNOYING)) {547 TRACE_DEBUG(FULL, "-- Updated session expiry list --");548 for (li = exp_sentinel.next; li != &exp_sentinel; li = li->next) {549 struct session * s = (struct session *)(li->o);550 fd_sess_dump(FULL, s);551 }552 TRACE_DEBUG(FULL, "-- end of expiry list --");553 }554 #endif555 556 584 /* We're done */ 557 585 pthread_cleanup_pop(0); … … 561 589 } 562 590 563 /* Destroy a session immediatly*/591 /* Destroy the states associated to a session, and mark it destroyed. */ 564 592 int fd_sess_destroy ( struct session ** session ) 565 593 { 566 594 struct session * sess; 595 int destroy_now; 596 os0_t sid; 597 int ret = 0; 598 599 /* place to save the list of states to be cleaned up. We do it after finding them to avoid deadlocks. the "o" field becomes a copy of the sid. */ 600 struct fd_list deleted_states = FD_LIST_INITIALIZER( deleted_states ); 567 601 568 602 TRACE_ENTRY("%p", session); … … 572 606 *session = NULL; 573 607 574 /* Unlink and invalidate */608 /* Lock the hash line */ 575 609 CHECK_POSIX( pthread_mutex_lock( H_LOCK(sess->hash) ) ); 576 610 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(sess->hash) ); 611 612 /* Unlink from the expiry list */ 577 613 CHECK_POSIX_DO( pthread_mutex_lock( &exp_lock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } ); 578 fd_list_unlink( &sess->chain_h );579 614 fd_list_unlink( &sess->expire ); /* no need to signal the condition here */ 580 sess->eyec = 0xdead;581 615 CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } ); 582 pthread_cleanup_pop(0); 583 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(sess->hash) ) ); 584 585 /* Now destroy all states associated -- we don't take the lock since nobody can access this session anymore (in theory) */ 616 617 /* Now move all states associated to this session into deleted_states */ 618 CHECK_POSIX_DO( pthread_mutex_lock( &sess->stlock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } ); 586 619 while (!FD_IS_LIST_EMPTY(&sess->states)) { 587 620 struct state * st = (struct state *)(sess->states.next->o); 588 621 fd_list_unlink(&st->chain); 589 TRACE_DEBUG(FULL, "Calling handler %p cleanup for state registered with session '%s'", st->hdl, sess->sid); 590 (*st->hdl->cleanup)(st->state, sess->sid, st->hdl->opaque); 622 fd_list_insert_before(&deleted_states, &st->chain); 623 } 624 CHECK_POSIX_DO( pthread_mutex_unlock( &sess->stlock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } ); 625 626 /* Mark the session as destroyed */ 627 destroy_now = (sess->msg_cnt == 0); 628 if (destroy_now) { 629 fd_list_unlink( &sess->chain_h ); 630 sid = sess->sid; 631 } else { 632 sess->is_destroyed = 1; 633 CHECK_MALLOC_DO( sid = os0dup(sess->sid, sess->sidlen), ret = ENOMEM ); 634 } 635 pthread_cleanup_pop(0); 636 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(sess->hash) ) ); 637 638 if (ret) 639 return ret; 640 641 /* Now, really delete the states */ 642 while (!FD_IS_LIST_EMPTY(&deleted_states)) { 643 struct state * st = (struct state *)(deleted_states.next->o); 644 fd_list_unlink(&st->chain); 645 TRACE_DEBUG(FULL, "Calling handler %p cleanup for state %p registered with session '%s'", st->hdl, st, sid); 646 (*st->hdl->cleanup)(st->state, sid, st->hdl->opaque); 591 647 free(st); 592 648 } 593 649 594 /* Finally, destroy the session itself */ 595 free(sess->sid); 596 free(sess); 650 /* Finally, destroy the session itself, if it is not referrenced by any message anymore */ 651 if (destroy_now) { 652 del_session(sess); 653 } else { 654 free(sid); 655 } 597 656 598 657 return 0; … … 604 663 struct session * sess; 605 664 uint32_t hash; 665 int destroy_now = 0; 606 666 607 667 TRACE_ENTRY("%p", session); … … 612 672 *session = NULL; 613 673 614 CHECK_POSIX( pthread_mutex_lock( H_LOCK(sess->hash) ) ); 615 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(sess->hash) ); 674 CHECK_POSIX( pthread_mutex_lock( H_LOCK(hash) ) ); 675 pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(hash) ); 676 CHECK_POSIX_DO( pthread_mutex_lock( &sess->stlock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } ); 677 pthread_cleanup_push( fd_cleanup_mutex, &sess->stlock ); 616 678 CHECK_POSIX_DO( pthread_mutex_lock( &exp_lock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } ); 679 680 /* We only do something if the states list is empty */ 617 681 if (FD_IS_LIST_EMPTY(&sess->states)) { 618 fd_list_unlink( &sess->chain_h );682 /* In this case, we do as in destroy */ 619 683 fd_list_unlink( &sess->expire ); 620 sess->eyec = 0xdead; 621 free(sess->sid); 622 free(sess); 623 } 684 destroy_now = (sess->msg_cnt == 0); 685 if (destroy_now) { 686 fd_list_unlink(&sess->chain_h); 687 } else { 688 /* just mark it as destroyed, it will be freed when the last message stops referencing it */ 689 sess->is_destroyed = 1; 690 } 691 } 692 624 693 CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } ); 625 694 pthread_cleanup_pop(0); 695 CHECK_POSIX_DO( pthread_mutex_unlock( &sess->stlock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } ); 696 pthread_cleanup_pop(0); 626 697 CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) ); 698 699 if (destroy_now) 700 del_session(sess); 627 701 628 702 return 0; … … 638 712 639 713 TRACE_ENTRY("%p %p %p", handler, session, state); 640 CHECK_PARAMS( handler && VALIDATE_SH(handler) && session && VALIDATE_SI(session) && state );714 CHECK_PARAMS( handler && VALIDATE_SH(handler) && session && VALIDATE_SI(session) && (!session->is_destroyed) && state ); 641 715 642 716 /* Lock the session state list */ … … 720 794 721 795 /* For the messages module */ 722 int fd_sess_fromsid_msg ( u nsigned char* sid, size_t len, struct session ** session, int * new)796 int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new) 723 797 { 724 798 TRACE_ENTRY("%p %zd %p %p", sid, len, session, new); … … 726 800 727 801 /* Get the session object */ 728 CHECK_FCT( fd_sess_fromsid ( (char *)sid, len, session, new) );802 CHECK_FCT( fd_sess_fromsid ( sid, len, session, new) ); 729 803 730 804 /* Increase count */ … … 786 860 } else { 787 861 788 fd_log_debug("\t %*s sid '%s' , hash %x\n", level, "", session->sid, session->hash);862 fd_log_debug("\t %*s sid '%s'(%zd), hash %x\n", level, "", session->sid, session->sidlen, session->hash); 789 863 790 864 strftime(buf, sizeof(buf), "%D,%T", localtime_r( &session->timeout.tv_sec , &tm ));
Note: See TracChangeset
for help on using the changeset viewer.