Navigation


Changeset 706:4ffbc9f1e922 in freeDiameter for libfdproto


Ignore:
Timestamp:
Feb 9, 2011, 3:26:58 PM (13 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

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.
Location:
libfdproto
Files:
1 added
9 edited

Legend:

Unmodified
Added
Removed
  • libfdproto/CMakeLists.txt

    r689 r706  
    1313        messages.c
    1414        msg_log.c
     15        ostr.c
    1516        rt_data.c
    1617        sessions.c
  • libfdproto/dictionary.c

    r687 r706  
    6363       
    6464        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 */
    7272        } 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. */
    7375       
    7476        struct dict_object *    parent; /* The parent of this object, if any */
     
    8890         list[0]: list of the vendors, ordered by their id. The sentinel is g_dict_vendors (vendor with id 0)
    8991         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).
    9193         
    9294         => APPLICATIONS:
     
    9799         => TYPES:
    98100         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).
    100102         list[2]: sentinel for the type_enum list of this type, ordered by their constant value.
    101103         
    102104         => 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.
    104106         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.
    105107         list[2]: not used
     
    107109         => AVPS:
    108110         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.
    110112         list[2]: sentinel for the rule list that apply to this AVP.
    111113         
    112114         => 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.
    114116         list[1]: list of the commands, ordered by their command code and 'R' flag. The sentinel is g_list_cmd_code.
    115117         list[2]: sentinel for the rule list that apply to this command.
    116118         
    117119         => 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.
    119121         list[1]: not used
    120122         list[2]: not used.
     
    223225/* Functions to manage the objects creation and destruction. */
    224226
    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));            \
    229231}
    230232       
     
    259261
    260262/* Initialize the "data" part of an object */
    261 static int init_object_data(void * dest, void * source, enum dict_object_type type)
     263static int init_object_data(struct dict_object * dest, void * source, enum dict_object_type type)
    262264{
    263265        TRACE_ENTRY("%p %p %d", dest, source, type);
     
    265267       
    266268        /* 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 );
    268270       
    269271        /* Then strings must be duplicated, not copied */
     
    271273        switch (type) {
    272274                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 );
    274276                        break;
    275277               
    276278                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 );
    278280                        break;
    279281                       
    280282                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 );
    282284                        break;
    283285                       
    284286                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 );
    286288                        break;
    287289
    288290                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 );
    290292                        break;
    291293                       
    292294                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 );
    294296                        break;
    295297               
     
    456458        TRACE_ENTRY("%p %p", o1, o2);
    457459       
    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 );
    459461}
    460462
     
    464466        TRACE_ENTRY("%p %p", o1, o2);
    465467       
    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 );
    467469}
    468470
     
    470472static int order_enum_by_val  ( struct dict_object *o1, struct dict_object *o2 )
    471473{
    472         size_t oslen;
    473         int cmp = 0;
    474        
    475474        TRACE_ENTRY("%p %p", o1, o2);
    476475       
     
    478477        switch ( o1->parent->data.type.type_base ) {
    479478                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);
    485481               
    486482                case AVP_TYPE_INTEGER32:
     
    522518        TRACE_ENTRY("%p %p", o1, o2);
    523519       
    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 );
    525521}
    526522
     
    530526        TRACE_ENTRY("%p %p", o1, o2);
    531527       
    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 );
    533529}
    534530
     
    555551
    556552/* Compare two rule object by the AVP vendor & code that they refer (checks already performed) */
    557 static int order_rule_by_avpn ( struct dict_object *o1, struct dict_object *o2 )
     553static int order_rule_by_avpvc ( struct dict_object *o1, struct dict_object *o2 )
    558554{
    559555        TRACE_ENTRY("%p %p", o1, o2);
     
    590586
    591587/* 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);                                        \
    594592        int __cmp;                                                              \
    595593        struct fd_list * __li;                                                  \
    596594        ret = 0;                                                                \
    597595        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);\
    599598                if (__cmp == 0) {                                               \
    600599                        if (result)                                             \
     
    611610}
    612611
    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);                                     \
    616624        int __cmp;                                                              \
    617         size_t __len;                                                           \
    618625        struct fd_list * __li;                                                  \
    619626        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);                   \
    631631                if (__cmp == 0) {                                               \
    632632                        if (result)                                             \
    633                                 *result = _O(__li->next->o);                    \
     633                                *result = _O(__li->o);                          \
    634634                        goto end;                                               \
    635635                }                                                               \
     
    644644
    645645/* 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);                                    \
    648649        int __cmp;                                                              \
    649650        struct fd_list * __li;                                                  \
    650651        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);          \
    654656                if (__cmp == 0) {                                               \
    655657                        if (result)                                             \
    656                                 *result = _O(__li->next->o);                    \
     658                                *result = _O(__li->o);                          \
    657659                        goto end;                                               \
    658660                }                                                               \
     
    677679                goto end;                                                       \
    678680        }                                                                       \
    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 );      \
    681683                if (__cmp == 0) {                                               \
    682684                        if (result)                                             \
    683                                 *result = _O(__li->next->o);                    \
     685                                *result = _O(__li->o);                          \
    684686                        goto end;                                               \
    685687                }                                                               \
     
    698700        struct fd_list * __li;                                                  \
    699701        ret = 0;                                                                \
    700         for  (    __li = (sentinel);                                            \
    701                   __li->next != (sentinel);                                     \
    702                   __li = __li->next) {                                          \
     702        for  (__li = (sentinel)->next; __li != (sentinel); __li = __li->next) { \
    703703                __cmp = ORDER_scalar(value,                                     \
    704                                 _O(__li->next->o)->data.cmd.cmd_code );         \
     704                                _O(__li->o)->data.cmd.cmd_code );               \
    705705                if (__cmp == 0) {                                               \
    706706                        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;            \
    709709                        if ( ! (__mask & CMD_FLAG_REQUEST) )                    \
    710710                                continue;                                       \
     
    712712                                continue;                                       \
    713713                        if (result)                                             \
    714                                 *result = _O(__li->next->o);                    \
     714                                *result = _O(__li->o);                          \
    715715                        goto end;                                               \
    716716                }                                                               \
     
    739739                case VENDOR_BY_NAME:
    740740                        /* "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);
    742742                        break;
    743743                       
     
    771771                case APPLICATION_BY_NAME:
    772772                        /* "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);
    774774                        break;
    775775                       
     
    801801                case TYPE_BY_NAME:
    802802                        /* "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);
    804804                        break;
    805805                       
     
    850850                                if ( _what->search.enum_name != NULL ) {
    851851                                        /* 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 );
    853853                                } else {
    854854                                        /* We are looking for the value in enum_value */
    855855                                        switch (parent->data.type.type_base) {
    856856                                                case AVP_TYPE_OCTETSTRING:
    857                                                         SEARCH_ocstring( _what->search.enum_value.os.data,
     857                                                        SEARCH_os(      _what->search.enum_value.os.data,
    858858                                                                         _what->search.enum_value.os.len,
    859859                                                                         &parent->list[2],
     
    946946                case AVP_BY_NAME:
    947947                        /* "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);
    949949                        break;
    950950                       
     
    969969                                /* We now have our vendor = head of the appropriate avp list */
    970970                                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);
    972972                                } else {
    973973                                        /* AVP_BY_CODE_AND_VENDOR */
    974                                         SEARCH_scalar( _what->avp_code, &vendor->list[1],  avp.avp_code, 1, (struct dict_object *)NULL );
     974                                        SEARCH_scalar( _what->avp_code, &vendor->list[1], avp.avp_code, 1, (struct dict_object *)NULL );
    975975                                }
    976976                        }
     
    980980                        {
    981981                                struct fd_list * li;
     982                                size_t wl = strlen((char *)what);
    982983                               
    983984                                /* 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);
    985986                               
    986987                                /* If not found, loop for all vendors, until found */
    987988                                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);
    989990                                }
    990991                        }
     
    10081009                case CMD_BY_NAME:
    10091010                        /* "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);
    10111012                        break;
    10121013                       
     
    10961097                               
    10971098                                /* 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]);
    10991100                               
    11001101                        }
     
    12741275        dump_object( &dict->dict_vendors, 0, 3, 0 );
    12751276       
    1276         fd_log_debug("###### Dumping applications #######\n");
     1277        fd_log_debug("######          Dumping applications          #######\n");
    12771278
    12781279        dump_object( &dict->dict_applications, 0, 1, 0 );
    12791280       
    1280         fd_log_debug("###### Dumping types #######\n");
     1281        fd_log_debug("######             Dumping types              #######\n");
    12811282
    12821283        dump_list( &dict->dict_types, 0, 2, 0 );
    12831284       
    1284         fd_log_debug("###### Dumping commands per name #######\n");
     1285        fd_log_debug("######      Dumping commands per name          #######\n");
    12851286
    12861287        dump_list( &dict->dict_cmd_name, 0, 2, 0 );
    12871288       
    1288         fd_log_debug("###### Dumping commands per code and flags #######\n");
     1289        fd_log_debug("######   Dumping commands per code and flags  #######\n");
    12891290
    12901291        dump_list( &dict->dict_cmd_code, 0, 0, 0 );
    12911292       
    1292         fd_log_debug("###### Statistics #######\n");
     1293        fd_log_debug("######             Statistics                  #######\n");
    12931294
    12941295        for (i=1; i<=DICT_TYPE_MAX; i++)
     
    15611562        /* Initialize the data of the new object */
    15621563        init_object(new, type);
    1563         init_object_data(&new->data, data, type);
     1564        init_object_data(new, data, type);
    15641565        new->dico = dict;
    15651566        new->parent = parent;
     
    16321633                case DICT_RULE:
    16331634                        /* 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_avpn, (void **)&locref );
     1635                        ret = fd_list_insert_ordered ( &parent->list[2], &new->list[0], (int (*)(void*, void *))order_rule_by_avpvc, (void **)&locref );
    16351636                        if (ret)
    16361637                                goto error_unlock;
     
    16591660                switch (type) {
    16601661                        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)) {
    16631665                                        TRACE_DEBUG(FULL, "Conflicting vendor name");
    16641666                                        break;
     
    16701672                        case DICT_APPLICATION:
    16711673                                /* 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)) {
    16731676                                        TRACE_DEBUG(FULL, "Conflicting application name");
    16741677                                        break;
     
    17631766
    17641767                        case DICT_RULE:
    1765                                 /* Both rules point to the same AVPs */
     1768                                /* Both rules point to the same AVPs (code & vendor) */
    17661769                                if (locref->data.rule.rule_position != new->data.rule.rule_position) {
    17671770                                        TRACE_DEBUG(FULL, "Conflicting rule position");
     
    18471850        struct dictionary * new = NULL;
    18481851       
    1849         TRACE_ENTRY("");
     1852        TRACE_ENTRY("%p", dict);
    18501853       
    18511854        /* Sanity checks */
     
    18651868        /* Initialize the sentinel for vendors and AVP lists */
    18661869        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);
    18681873        new->dict_vendors.list[0].o = NULL; /* overwrite since element is also sentinel for this list. */
    18691874        new->dict_vendors.dico = new;
     
    18711876        /* Initialize the sentinel for applications */
    18721877        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);
    18741881        new->dict_applications.list[0].o = NULL; /* overwrite since since element is also sentinel for this list. */
    18751882        new->dict_applications.dico = new;
     
    18841891        /* Initialize the error command object */
    18851892        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);
    18871896        new->dict_cmd_error.data.cmd.cmd_flag_mask=CMD_FLAG_ERROR | CMD_FLAG_REQUEST | CMD_FLAG_RETRANSMIT;
    18881897        new->dict_cmd_error.data.cmd.cmd_flag_val =CMD_FLAG_ERROR;
  • libfdproto/fdproto-internal.h

    r689 r706  
    6565
    6666/* Messages / sessions API */
    67 int fd_sess_fromsid_msg ( unsigned char * sid, size_t len, struct session ** session, int * new);
     67int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new);
    6868int fd_sess_ref_msg ( struct session * session );
    6969int fd_sess_reclaim_msg ( struct session ** session );
  • libfdproto/init.c

    r693 r706  
    3535
    3636#include "fdproto-internal.h"
    37 
    38 /* Only for CPU cache flush */
    39 pthread_mutex_t fd_cpu_mtx_dummy = PTHREAD_MUTEX_INITIALIZER;
    4037
    4138/* function to free the threadnames */
  • libfdproto/lists.c

    r662 r706  
    163163
    164164
    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                 else
    269                 {
    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 few
    284            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  
    8383        /* First, check if a value is already assigned to the current thread */
    8484        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        }
    8592        if (val != NULL) {
    86                 TRACE_DEBUG(FULL, "Freeing old thread name: %s", val);
    8793                free(val);
    8894        }
  • libfdproto/messages.c

    r704 r706  
    126126                        struct timespec timeout;
    127127                }                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 */
    129130};
    130131
     
    332333        if (sess && dict) {
    333334                struct dict_object * sess_id_avp;
    334                 char * sid;
     335                os0_t sid;
     336                size_t sidlen;
    335337                struct avp * avp;
    336338                union avp_value val;
    337339               
    338340                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 ) );
    340342                CHECK_FCT( fd_msg_avp_new ( sess_id_avp, 0, &avp ) );
    341                 val.os.data = (unsigned char *)sid;
    342                 val.os.len  = strlen(sid);
     343                val.os.data = sid;
     344                val.os.len  = sidlen;
    343345                CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
    344346                CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_FIRST_CHILD, avp ) );
     
    703705                msg->msg_public.msg_eteid
    704706                );
    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);
    707709}
    708710
     
    10121014}
    10131015
     1016/* cache the dictionary model for next function to avoid re-searching at every incoming message */
     1017static struct dict_object *cached_avp_rr_model = NULL;
     1018static struct dictionary  *cached_avp_rr_dict  = NULL;
     1019static pthread_mutex_t     cached_avp_rr_lock = PTHREAD_MUTEX_INITIALIZER;
     1020
    10141021/* 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);
     1022int 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);
    10181025       
    10191026        /* Check we received a valid message */
     
    10211028       
    10221029        /* 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;
    10241031       
    10251032        /* If the request is to cleanup the source, we are done */
     
    10291036       
    10301037        /* 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       
    10321041       
    10331042        if (add_rr) {
    1034                 struct dict_object      *avp_rr_model;
     1043                struct dict_object      *avp_rr_model = NULL;
    10351044                avp_code_t               code = AC_ROUTE_RECORD;
    10361045                struct avp              *avp;
    10371046                union avp_value          val;
    10381047               
    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                }
    10411066               
    10421067                /* Create the AVP with this model */
     
    10451070                /* Set the AVP value with the diameter id */
    10461071                memset(&val, 0, sizeof(val));
    1047                 val.os.data = (unsigned char *)diamid;
    1048                 val.os.len  = strlen(diamid);
     1072                val.os.data = (uint8_t *)diamid;
     1073                val.os.len  = diamidlen;
    10491074                CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
    10501075
     
    10571082}
    10581083
    1059 int fd_msg_source_get( struct msg * msg, char ** diamid )
    1060 {
    1061         TRACE_ENTRY( "%p %p", msg, diamid);
     1084int fd_msg_source_get( struct msg * msg, DiamId_t* diamid, size_t * diamidlen )
     1085{
     1086        TRACE_ENTRY( "%p %p %p", msg, diamid, diamidlen);
    10621087       
    10631088        /* Check we received valid parameters */
     
    10671092        /* Copy the informations */
    10681093        *diamid = msg->msg_src_id;
     1094       
     1095        if (diamidlen)
     1096                *diamidlen = msg->msg_src_id_len;
    10691097       
    10701098        /* done */
     
    22252253
    22262254/* Call all dispatch callbacks for a given message */
    2227 int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, const char ** error_code)
     2255int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, char ** error_code)
    22282256{
    22292257        struct dictionary  * dict;
  • libfdproto/rt_data.c

    r662 r706  
    5050/* Items of the errors list */
    5151struct 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 */
    5557        uint32_t        code;   /* the error code */
    5658};
     
    107109}
    108110
    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. */
     112int  fd_rtd_candidate_add(struct rt_data * rtd, DiamId_t peerid, size_t peeridlen, DiamId_t realm, size_t realmlen)
    111113{
    112114        struct fd_list * prev;
    113115        struct rtd_candidate * new;
    114116       
    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);
    117119       
    118120        /* 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 */
    119121        for (prev = rtd->candidates.prev; prev != &rtd->candidates; prev = prev->prev) {
    120122                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);
    122124                if (cmp > 0)
    123125                        break;
     
    127129        }
    128130       
     131        /* Create the new entry */
    129132        CHECK_MALLOC( new = malloc(sizeof(struct rtd_candidate)) );
    130133        memset(new, 0, sizeof(struct rtd_candidate) );
    131134        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 */
    135143        fd_list_insert_after(prev, &new->chain);
    136144       
     
    138146}
    139147
    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 */
     149void fd_rtd_candidate_del(struct rt_data * rtd, uint8_t * id, size_t idsz)
    142150{
    143151        struct fd_list * li;
    144152       
    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;
    147159       
    148160        for (li = rtd->candidates.next; li != &rtd->candidates; li = li->next) {
    149161                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);
    164164               
    165165                if (!cmp) {
     
    175175                        continue;
    176176               
    177                 /* The list is ordered only if not extracted */
     177                /* The list is guaranteed to be ordered only if not extracted */
    178178                if (! rtd->extracted)
    179179                        break;
     
    183183}
    184184
    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*/
     187int  fd_rtd_error_add(struct rt_data * rtd, DiamId_t sentto, size_t senttolen, uint8_t * origin, size_t originsz, uint32_t rcode)
    187188{
    188189        struct fd_list * li;
    189190        int match = 0;
    190191       
    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 */
    193194       
    194195        /* First add the new error entry */
    195196        for (li = rtd->errors.next; li != &rtd->errors; li = li->next) {
    196197                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);
    198199                if (cmp > 0)
    199200                        continue;
     
    203204        }
    204205       
    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 */
    206208        if (!match) {
    207209                /* Add a new entry in the error list */
     
    210212                memset(new, 0, sizeof(struct rtd_error));
    211213                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               
    213218                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;
    217230                }
     231after_origin:
    218232                new->code = rcode;
    219233                fd_list_insert_before(li, &new->chain);
     
    221235       
    222236        /* 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);
    224238        if (origin)
    225                 fd_rtd_candidate_del(rtd, (char *)origin, originsz);
     239                fd_rtd_candidate_del(rtd, origin, originsz);
    226240       
    227241        /* Done! */
     
    274288                        fd_list_move_end(candidates, &highest);
    275289                       
    276                         /* And the new high score is this reset */
     290                        /* And the new high score is set */
    277291                        hs = c->score;
    278292                }
  • libfdproto/sessions.c

    r691 r706  
    6969        int               eyec; /* An eye catcher also used to ensure the object is valid, must be SH_EYEC */
    7070        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 */
    7272        void             *opaque; /* a value that is passed as is to the cleanup callback */
    7373};
     
    8484        union {
    8585                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 */
    8787        };
    8888};
     
    9292        int             eyec;   /* Eyecatcher, SI_EYEC */
    9393       
    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 */
    9596        uint32_t        hash;   /* computed hash of sid */
    9697        struct fd_list  chain_h;/* chaining in the hash table of sessions. */
     
    102103        struct fd_list  states; /* Sentinel for the list of states of this session. */
    103104        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 */
    104106};
    105107
    106108/* Sessions hash table, to allow fast sid to session retrieval */
    107109static 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). */
    109111        pthread_mutex_t lock;           /* the mutex for this sublist -- we might probably change it to rwlock for a little optimization */
    110112} sess_hash [ 1 << SESS_HASH_SIZE ] ;
     
    132134/********************************************************************************************************/
    133135
    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. */
     137static struct session * new_session(os0_t sid, size_t sidlen, uint32_t hash)
    136138{
    137139        struct session * sess;
    138140       
    139         TRACE_ENTRY("%p %d", sid, sidlen);
     141        TRACE_ENTRY("%p %zd", sid, sidlen);
    140142        CHECK_PARAMS_DO( sid && sidlen, return NULL );
    141143       
     
    146148       
    147149        sess->sid  = sid;
    148         sess->hash = fd_hash(sid, sidlen);
     150        sess->sidlen = sidlen;
     151        sess->hash = hash;
    149152        fd_list_init(&sess->chain_h, sess);
    150153       
     
    157160       
    158161        return sess;
     162}
     163
     164/* destroy the session object. It should really be already unlinked... */
     165static 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);
    159173}
    160174       
     
    250264        TRACE_ENTRY("");
    251265        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       
    252269        return;
    253270}
    254271
    255272/* 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 )
     273int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state *, os0_t, void *), void * opaque )
    257274{
    258275        struct session_handler *new;
     
    299316                CHECK_POSIX(  pthread_mutex_lock(&sess_hash[i].lock)  );
    300317               
    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 */
    302319                        struct fd_list * li_st;
    303320                        struct session * sess = (struct session *)(li_si->o);
    304321                        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 */
    306323                                struct state * st = (struct state *)(li_st->o);
    307324                                /* The list is ordered */
     
    311328                                        /* This state belongs to the handler we are deleting, move the item to the deleted_states list */
    312329                                        fd_list_unlink(&st->chain);
    313                                         CHECK_MALLOC( st->sid = strdup(sess->sid) );
     330                                        st->sid = sess->sid;
    314331                                        fd_list_insert_before(&deleted_states, &st->chain);
    315332                                }
     
    326343                TRACE_DEBUG(FULL, "Calling cleanup handler for session '%s' and data %p", st->sid, st->state);
    327344                (*del->cleanup)(st->state, st->sid, del->opaque);
    328                 free(st->sid);
    329345                fd_list_unlink(&st->chain);
    330346                free(st);
     
    343359
    344360/* 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;
     361int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen )
     362{
     363        os0_t sid = NULL;
    348364        size_t sidlen;
     365        uint32_t hash;
    349366        struct session * sess;
    350367        struct fd_list * li;
    351368        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               
    356393        /* Ok, first create the identifier for the string */
    357         if (diamId == NULL) {
     394        if (diamid == NULL) {
    358395                /* 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;
    368398        } else {
    369399                uint32_t sid_h_cpy;
    370400                uint32_t sid_l_cpy;
    371401                /* "<diamId>;<high32>;<low32>[;opt]" */
    372                 sidlen = strlen(diamId);
     402                sidlen = diamidlen;
    373403                sidlen += 22; /* max size of ';<high32>;<low32>' */
    374404                if (opt)
    375                         sidlen += 1 + (optlen ?: strlen(opt)) ;
     405                        sidlen += 1 + optlen; /* ';opt' */
    376406                sidlen++; /* space for the final \0 also */
    377407                CHECK_MALLOC( sid = malloc(sidlen) );
     
    385415               
    386416                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);
    391418                } 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);
    393420                }
    394421        }
    395422       
    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);
    399424       
    400425        /* 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) {
    405430                int cmp;
    406431                struct session * s = (struct session *)(li->o);
    407432               
    408433                /* The list is ordered by hash and sid (in case of collisions) */
    409                 if (s->hash < sess->hash)
     434                if (s->hash < hash)
    410435                        continue;
    411                 if (s->hash > sess->hash)
     436                if (s->hash > hash)
    412437                        break;
    413438               
    414                 cmp = strcasecmp(s->sid, sess->sid);
     439                cmp = fd_os_cmp(s->sid, s->sidlen, sid, sidlen);
    415440                if (cmp < 0)
    416441                        continue;
     
    424449        }
    425450       
    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 */
    427452        if (!found) {
     453                CHECK_MALLOC_DO(sess = new_session(sid, sidlen, hash),
     454                        {
     455                                ret = ENOMEM;
     456                                goto out;
     457                        } );
     458       
    428459                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;
    439473                }
    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 */
    463494        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
     497out:
     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;
    471504       
    472505        *session = sess;
     
    475508
    476509/* Find or create a session */
    477 int fd_sess_fromsid ( char * sid, size_t len, struct session ** session, int * new)
     510int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * new)
    478511{
    479512        int ret;
     
    482515        CHECK_PARAMS( sid && session );
    483516       
     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       
    484521        /* 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 );
    486523        switch (ret) {
    487524                case 0:
     
    500537
    501538/* Get the sid of a session */
    502 int fd_sess_getsid ( struct session * session, char ** sid )
     539int fd_sess_getsid ( struct session * session, os0_t * sid, size_t * sidlen )
    503540{
    504541        TRACE_ENTRY("%p %p", session, sid);
     
    507544       
    508545        *sid = session->sid;
     546        if (sidlen)
     547                *sidlen = session->sidlen;
    509548       
    510549        return 0;
     
    543582        }
    544583
    545         #if 0
    546         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         #endif
    555 
    556584        /* We're done */
    557585        pthread_cleanup_pop(0);
     
    561589}
    562590
    563 /* Destroy a session immediatly */
     591/* Destroy the states associated to a session, and mark it destroyed. */
    564592int fd_sess_destroy ( struct session ** session )
    565593{
    566594        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 );
    567601       
    568602        TRACE_ENTRY("%p", session);
     
    572606        *session = NULL;
    573607       
    574         /* Unlink and invalidate */
     608        /* Lock the hash line */
    575609        CHECK_POSIX( pthread_mutex_lock( H_LOCK(sess->hash) ) );
    576610        pthread_cleanup_push( fd_cleanup_mutex, H_LOCK(sess->hash) );
     611       
     612        /* Unlink from the expiry list */
    577613        CHECK_POSIX_DO( pthread_mutex_lock( &exp_lock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } );
    578         fd_list_unlink( &sess->chain_h );
    579614        fd_list_unlink( &sess->expire ); /* no need to signal the condition here */
    580         sess->eyec = 0xdead;
    581615        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 */ } );
    586619        while (!FD_IS_LIST_EMPTY(&sess->states)) {
    587620                struct state * st = (struct state *)(sess->states.next->o);
    588621                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);
    591647                free(st);
    592648        }
    593649       
    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        }
    597656       
    598657        return 0;
     
    604663        struct session * sess;
    605664        uint32_t hash;
     665        int destroy_now = 0;
    606666       
    607667        TRACE_ENTRY("%p", session);
     
    612672        *session = NULL;
    613673       
    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 );
    616678        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 */
    617681        if (FD_IS_LIST_EMPTY(&sess->states)) {
    618                 fd_list_unlink( &sess->chain_h );
     682                /* In this case, we do as in destroy */
    619683                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       
    624693        CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); /* otherwise, cleanup not poped on FreeBSD */ } );
    625694        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);
    626697        CHECK_POSIX( pthread_mutex_unlock( H_LOCK(hash) ) );
     698       
     699        if (destroy_now)
     700                del_session(sess);
    627701       
    628702        return 0;
     
    638712       
    639713        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 );
    641715       
    642716        /* Lock the session state list */
     
    720794
    721795/* For the messages module */
    722 int fd_sess_fromsid_msg ( unsigned char * sid, size_t len, struct session ** session, int * new)
     796int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * new)
    723797{
    724798        TRACE_ENTRY("%p %zd %p %p", sid, len, session, new);
     
    726800       
    727801        /* 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) );
    729803       
    730804        /* Increase count */
     
    786860        } else {
    787861               
    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);
    789863
    790864                strftime(buf, sizeof(buf), "%D,%T", localtime_r( &session->timeout.tv_sec , &tm ));
Note: See TracChangeset for help on using the changeset viewer.