Navigation


Changeset 706:4ffbc9f1e922 in freeDiameter


Ignore:
Timestamp:
Feb 9, 2011, 3:26:58 PM (10 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.
Files:
1 added
59 edited
1 moved

Legend:

Unmodified
Added
Removed
  • contrib/debian/changelog

    r683 r706  
    55    libfreeDiameter renamed as libfdproto.
    66    This closes #15.
    7   * API version bumped to version 4 accordingly.
     7  * API version bumped to version 4.
    88  * Improved fd_dict_new() when the same object already exists.
    99  * Improvements to dict_legacy_xml extension.
     
    1313  * Allow default signals such as SIGTSTP (ctrl-z) to be used with
    1414    freeDiameterd
     15  * Improved DiameterIdentity handling (esp. interationalization issues),
     16    and improve efficiency of some string operations in peers, sessions,
     17    and dictionary modules (closes #7)
     18  * Cleanup in the session module to free only unreferenced sessions (#16)
     19  * Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
     20  * Improved peer state machine algorithm to counter SCTP multistream race
     21    condition.
    1522
    16  -- Sebastien Decugis <sdecugis@nict.go.jp>  Tue, 18 Jan 2011 15:13:00 +0900
     23 -- Sebastien Decugis <sdecugis@nict.go.jp>  Mon, 07 Feb 2011 17:24:20 +0900
    1724
    1825freediameter (1.0.4) UNRELEASED; urgency=low
  • doc/dbg_interactive.py.sample

    r688 r706  
    105105############# Hash ############
    106106
    107 hex(fd_hash("hello world"))     # It accepts binary data
     107hex(fd_os_hash("hello world"))  # It accepts binary data
    108108
    109109
  • doc/freediameter.conf.sample

    r578 r706  
    211211#  ConnectTo = "2001:200:903:2::202:1";
    212212#  TLS_Prio = "NORMAL";
     213#  Realm = "realm.net"; # Reject the peer if it does not advertise this realm.
    213214# Examples:
    214215#ConnectPeer = "aaa.wide.ad.jp";
  • extensions/app_radgw/rgw_clients.c

    r554 r706  
    8686        int                      is_local; /* true if the RADIUS client runs on the same host -- we use Diameter Identity in that case */
    8787        enum rgw_cli_type        type; /* is it a proxy ? */
    88         char                    *fqdn;
     88        DiamId_t                 fqdn; /* malloc'd here */
    8989        size_t                   fqdn_len;
    90         char                    *realm;
    91         char                    **aliases;
     90        DiamId_t                 realm; /* references another string, do not free */
     91        size_t                   realm_len;
     92        struct {
     93                os0_t            name;
     94                size_t           len;
     95        }                       *aliases; /* Received aliases */
    9296        size_t                   aliases_nb;
    9397       
     
    210214{
    211215        struct rgw_client *tmp = NULL;
    212         char buf[255];
     216        DiamId_t fqdn;
     217        size_t fqdn_len;
    213218        int ret, i;
    214219        int loc = 0;
     
    220225                loc = 1;
    221226        } else {
     227                char buf[255];
    222228       
    223229                /* Search FQDN for the client */
     
    227233                        return EINVAL;
    228234                }
     235                fqdn = &buf[0];
     236                CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&fqdn, &fqdn_len, 1),
     237                        {
     238                                TRACE_DEBUG(INFO, "Unable to use resolved peer name '%s' as DiameterIdentity: %s", buf, strerror(ret));
     239                                return ret;
     240                        } );
    229241        }
    230242       
     
    246258        } else {
    247259                /* Copy the fqdn */
    248                 CHECK_MALLOC( tmp->fqdn = strdup(buf) );
    249                 tmp->fqdn_len = strlen(tmp->fqdn);
     260                tmp->fqdn = fqdn;
     261                tmp->fqdn_len = fqdn_len;
     262
    250263                /* Find an appropriate realm */
    251                 tmp->realm = strchr(tmp->fqdn, '.');
    252                 if (tmp->realm)
     264                tmp->realm = strchr(fqdn, '.');
     265                if (tmp->realm) {
    253266                        tmp->realm += 1;
    254                 if ((!tmp->realm) || (*tmp->realm == '\0')) /* in case the fqdn was "localhost." for example, if it is possible... */
     267                        tmp->realm_len = tmp->fqdn_len - (tmp->realm - fqdn);
     268                }
     269                if ((!tmp->realm) || (*tmp->realm == '\0')) { /* in case the fqdn was "localhost." for example, if it is possible... */
    255270                        tmp->realm = fd_g_config->cnf_diamrlm;
     271                        tmp->realm_len = fd_g_config->cnf_diamrlm_len;
     272                }
    256273        }
    257274       
     
    282299                /* Free the data */
    283300                for (idx = 0; idx < client->aliases_nb; idx++)
    284                         free(client->aliases[idx]);
     301                        free(client->aliases[idx].name);
    285302                free(client->aliases);
    286303                free(client->fqdn);
     
    532549        int valid_nas_info = 0;
    533550        struct radius_attr_hdr *nas_ip = NULL, *nas_ip6 = NULL, *nas_id = NULL;
    534         char * oh_str = NULL;
    535         char * or_str = NULL;
    536         char * rr_str = NULL;
     551        size_t nas_id_len;
     552        char * oh_str = NULL; size_t oh_strlen; int oh_free = 0;
     553        char * or_str = NULL; size_t or_strlen;
     554        char * rr_str = NULL; size_t rr_strlen;
    537555        char buf[REVERSE_DNS_SIZE_MAX]; /* to store DNS lookups results */
    538556       
     
    555573                if ((attr->type == RADIUS_ATTR_NAS_IDENTIFIER) && (attr_len > 0)) {
    556574                        nas_id = attr;
     575                        nas_id_len = attr_len;
    557576                        continue;
    558577                }
     
    568587               
    569588                /* Get information on this peer */
    570                 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     589                CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    571590               
    572591                goto diameter;
     
    619638                                return EINVAL;
    620639                        } else {
     640                                int ret;
     641                                sSS ss;
    621642                                /* the peer is configured as a proxy, or running on localhost, so accept the message */
    622                                 sSS ss;
    623643                               
    624644                                /* In that case, the cli will be stored as Route-Record and the NAS-IP-Address as origin */
    625645                                if (!cli->is_local) {
    626646                                        rr_str = cli->fqdn;
     647                                        rr_strlen = cli->fqdn_len;
    627648                                }
    628649                               
     
    641662                                        {
    642663                                                if (cli->is_local) {
    643                                                         CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     664                                                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    644665                                                        goto diameter;
    645666                                                }
     
    648669                                                return EINVAL;
    649670                                        } );
     671                                       
     672                                oh_str = &buf[0];
     673                                CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&oh_str, &oh_strlen, 1),
     674                                        {
     675                                                if (cli->is_local) {
     676                                                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
     677                                                        goto diameter;
     678                                                }
     679                                               
     680                                                TRACE_DEBUG(INFO, "Unable to use resolved client name '%s' as DiameterIdentity: %s", buf, strerror(ret));
     681                                                return ret;
     682                                        } );
     683                                oh_free = 1;
    650684                               
    651                                 oh_str = &buf[0];
    652685                                or_str = strchr(oh_str, '.');
    653686                                if (or_str) {
     
    655688                                        if (*or_str == '\0')
    656689                                                or_str = NULL; /* Discard this realm, we will use the local realm later */
     690                                        else
     691                                                or_strlen = oh_strlen - (or_str - oh_str);
    657692                                }
    658693                        }
    659694                } else {
    660695                        /* The attribute matches the source address, just use this in origin-host */
    661                         CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     696                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    662697                }
    663698               
     
    668703        if (cli->is_local) {
    669704                /* Simple: we use our own configuration */
    670                 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     705                CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    671706                goto diameter;
    672707        }
     
    697732               
    698733                /* first, check if the nas_id is the fqdn of the peer or a known alias */
    699                 if ((cli->fqdn_len == (nas_id->length - sizeof(struct radius_attr_hdr)))
    700                 && (!strncasecmp((char *)(nas_id + 1), cli->fqdn, nas_id->length - sizeof(struct radius_attr_hdr)))) {
     734                if (!fd_os_almostcasecmp(nas_id + 1, nas_id_len,
     735                                                cli->fqdn, cli->fqdn_len)) {
    701736                        TRACE_DEBUG(FULL, "NAS-Identifier contains the fqdn of the client");
    702737                        found = 1;
    703738                } else {
    704739                        for (idx = 0; idx < cli->aliases_nb; idx++) {
    705                                 if (((nas_id->length - sizeof(struct radius_attr_hdr)) == strlen(cli->aliases[idx]))
    706                                 && (!strncasecmp((char *)(nas_id + 1), cli->aliases[idx], nas_id->length - sizeof(struct radius_attr_hdr)))) {
     740                                if (!fd_os_cmp(nas_id + 1, nas_id_len,
     741                                                cli->aliases[idx].name, cli->aliases[idx].len)) {
    707742                                        TRACE_DEBUG(FULL, "NAS-Identifier valid value found in the cache");
    708743                                        found = 1;
     
    714749                if (found) {
    715750                        /* The NAS-Identifier matches the source IP */
    716                         CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     751                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    717752
    718753                        goto diameter;
     
    720755               
    721756                /* Attempt DNS resolution of the identifier */
    722                 ASSERT( nas_id->length - sizeof(struct radius_attr_hdr) < sizeof(buf) );
    723                 memcpy(buf, nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr));
     757                ASSERT( nas_id_len < sizeof(buf) );
     758                memcpy(buf, nas_id + 1, nas_id_len);
    724759                buf[nas_id->length - sizeof(struct radius_attr_hdr)] = '\0';
    725760               
     
    745780                                if (cli->type == RGW_CLI_NAS) {
    746781                                        TRACE_DEBUG(INFO, "The NAS-Identifier value '%.*s' resolves to a different IP than the client's, discarding the message. \nConfigure this client as a Proxy if this message should be valid.",
    747                                                 nas_id->length - sizeof(struct radius_attr_hdr), nas_id + 1);
     782                                                nas_id_len, nas_id + 1);
    748783                                        return EINVAL;
    749784                                } else {
     
    751786                                        if (!cli->is_local) {
    752787                                                rr_str = cli->fqdn;
     788                                                rr_strlen = cli->fqdn_len;
    753789                                        }
    754790                                        oh_str = &buf[0]; /* The canonname resolved */
     791                                        CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&oh_str, &oh_strlen, 1),
     792                                                {
     793                                                        TRACE_DEBUG(INFO, "Unable to use resolved client name '%s' as DiameterIdentity: %s", buf, strerror(ret));
     794                                                        return ret;
     795                                                } );
     796                                        oh_free = 1;
    755797                                        or_str = strchr(oh_str, '.');
    756798                                        if (or_str) {
     
    758800                                                if (*or_str == '\0')
    759801                                                        or_str = NULL; /* Discard this realm, we will use the local realm later */
     802                                                else
     803                                                        or_strlen = oh_strlen - (or_str - oh_str);
    760804                                        }
    761805                                }
    762806                        } else {
    763807                                /* It is a valid alias, save it */
    764                                 CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(char *)) );
    765                                 CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1] = malloc( 1 + nas_id->length - sizeof(struct radius_attr_hdr) ));
    766                                 memcpy( cli->aliases[cli->aliases_nb + 1], nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr));
    767                                 *(cli->aliases[cli->aliases_nb + 1] + nas_id->length - sizeof(struct radius_attr_hdr)) = '\0';
     808                                CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(cli->aliases[0])) );
     809                               
     810                                CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1].name = os0dup(nas_id + 1, nas_id_len ) );
     811                                cli->aliases[cli->aliases_nb + 1].len = nas_id_len;
     812
    768813                                cli->aliases_nb ++;
    769                                 TRACE_DEBUG(FULL, "Saved valid alias for client: '%s' -> '%s'", cli->aliases[cli->aliases_nb + 1], cli->fqdn);
    770                                 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     814                                TRACE_DEBUG(FULL, "Saved valid alias for client: '%.*s' -> '%s'", nas_id_len, nas_id + 1, cli->fqdn);
     815                                CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    771816                        }
    772817                } else {
     
    774819                        TRACE_DEBUG(INFO, "NAS-Identifier '%s' cannot be resolved: %s. Ignoring...", buf, gai_strerror(ret));
    775820                        /* Assume this is a valid identifier for the client */
    776                         CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
     821                        CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
    777822                }
    778823        }
     
    781826diameter:
    782827        ASSERT(oh_str); /* If it is not defined here, there is a bug... */
    783         if (!or_str)
     828        if (!or_str) {
    784829                or_str = fd_g_config->cnf_diamrlm; /* Use local realm in that case */
     830                or_strlen = fd_g_config->cnf_diamrlm_len;
     831        }
    785832       
    786833        /* Create an empty Diameter message so that extensions can store their AVPs */
     
    791838        memset(&avp_val, 0, sizeof(avp_val));
    792839        avp_val.os.data = (unsigned char *)oh_str;
    793         avp_val.os.len = strlen(oh_str);
     840        avp_val.os.len = oh_strlen;
    794841        CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    795842        CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
     
    799846        memset(&avp_val, 0, sizeof(avp_val));
    800847        avp_val.os.data = (unsigned char *)or_str;
    801         avp_val.os.len = strlen(or_str);
     848        avp_val.os.len = or_strlen;
    802849        CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    803850        CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
     
    807854                memset(&avp_val, 0, sizeof(avp_val));
    808855                avp_val.os.data = (unsigned char *)rr_str;
    809                 avp_val.os.len = strlen(rr_str);
     856                avp_val.os.len = rr_strlen;
    810857                CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    811858                CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
    812859        }
    813860       
     861        if (oh_free)
     862                free(oh_str);
     863       
    814864        /* Done! */
    815865        return 0;
    816866}
    817867
    818 int rgw_clients_get_origin(struct rgw_client *cli, char **fqdn, char **realm)
    819 {
    820         TRACE_ENTRY("%p %p %p", cli, fqdn, realm);
    821         CHECK_PARAMS(cli && fqdn);
     868int rgw_clients_get_origin(struct rgw_client *cli, DiamId_t *fqdn, size_t *fqdnlen, DiamId_t *realm, size_t *realmlen)
     869{
     870        TRACE_ENTRY("%p %p %p %p %p", cli, fqdn, fqdnlen, realm, realmlen);
     871        CHECK_PARAMS(cli && fqdn && fqdnlen);
    822872       
    823873        if (cli->is_local) {
    824874                *fqdn = fd_g_config->cnf_diamid;
     875                *fqdnlen = fd_g_config->cnf_diamid_len;
    825876                if (realm)
    826877                        *realm= fd_g_config->cnf_diamrlm;
     878                if (realmlen)
     879                        *realmlen= fd_g_config->cnf_diamrlm_len;
    827880        } else {
    828881                *fqdn = cli->fqdn;
     882                *fqdnlen = cli->fqdn_len;
    829883                if (realm)
    830884                        *realm= cli->realm;
     885                if (realmlen)
     886                        *realmlen= cli->realm_len;
    831887        }
    832888               
  • extensions/app_radgw/rgw_common.h

    r403 r706  
    5959int    rgw_clients_getkey(struct rgw_client * cli, unsigned char **key, size_t *key_len);
    6060char * rgw_clients_id(struct rgw_client *cli);
    61 int    rgw_clients_get_origin(struct rgw_client *cli, char **fqdn, char **realm);
     61int    rgw_clients_get_origin(struct rgw_client *cli, DiamId_t *fqdn, size_t *fqdnlen, DiamId_t *realm, size_t *realmlen);
    6262
    6363/* Each plugin must provide the following structure. */
  • extensions/app_radgw/rgw_servers.c

    r553 r706  
    148148                CHECK_FCT_DO( rgw_msg_parse(&buf[0], len, &msg),
    149149                        {
    150                                 char * cliname = NULL;
    151                                 CHECK_FCT_DO( rgw_clients_get_origin(nas_info, &cliname, NULL), );
     150                                DiamId_t cliname = NULL;
     151                                size_t clisz;
     152                                CHECK_FCT_DO( rgw_clients_get_origin(nas_info, &cliname, &clisz, NULL, NULL), );
    152153                                TRACE_DEBUG(INFO, "Discarding invalid RADIUS message from '%s'", cliname);
    153154                                rgw_clients_dispose(&nas_info);
  • extensions/app_radgw/rgwx_acct.c

    r705 r706  
    306306        const char * prefix = "Diameter/";
    307307        size_t pref_len;
    308         uint8_t * si = NULL;
     308        os0_t si = NULL;
    309309        size_t si_len = 0;
    310         uint8_t * un = NULL;
     310        os0_t un = NULL;
    311311        size_t un_len = 0;
    312312       
     
    487487        /* Create the Session-Id AVP if needed */
    488488        if (!*session) {
    489                 CHECK_FCT( fd_sess_fromsid ( (char *)/* cast should be removed later */si, si_len, session, NULL) );
     489                CHECK_FCT( fd_sess_fromsid ( si, si_len, session, NULL) );
    490490               
    491491                TRACE_DEBUG(FULL, "[acct.rgwx] Translating new accounting message for session '%.*s'...", si_len, si);
     
    663663                                        char * attr_val, *auth_val;
    664664                                        attr_val = (char *)(attr + 1);
    665                                         auth_val = attr_val + strlen(CLASS_AAI_PREFIX);
    666                                         if (    (attr->length > sizeof(struct radius_attr_hdr) + strlen(CLASS_AAI_PREFIX)  )
    667                                                 && (attr->length < sizeof(struct radius_attr_hdr) + strlen(CLASS_AAI_PREFIX) + sizeof(buf))
    668                                                 && ! strncmp(attr_val, CLASS_AAI_PREFIX, strlen(CLASS_AAI_PREFIX))) {
     665                                        auth_val = attr_val + CONSTSTRLEN(CLASS_AAI_PREFIX);
     666                                        if (    (attr->length > sizeof(struct radius_attr_hdr) + CONSTSTRLEN(CLASS_AAI_PREFIX)  )
     667                                                && (attr->length < sizeof(struct radius_attr_hdr) + CONSTSTRLEN(CLASS_AAI_PREFIX) + sizeof(buf))
     668                                                && ! strncmp(attr_val, CLASS_AAI_PREFIX, CONSTSTRLEN(CLASS_AAI_PREFIX))) {
    669669                                       
    670670                                                memset(buf, 0, sizeof(buf));
    671                                                 memcpy(buf, auth_val, attr->length - sizeof(struct radius_attr_hdr) - strlen(CLASS_AAI_PREFIX));
     671                                                memcpy(buf, auth_val, attr->length - sizeof(struct radius_attr_hdr) - CONSTSTRLEN(CLASS_AAI_PREFIX));
    672672                                                if (sscanf(buf, "%u", &auth_appl) == 1) {
    673673                                                        TRACE_DEBUG(ANNOYING, "Found Class attribute with '%s' prefix (attr #%d), AAI:%u.", CLASS_AAI_PREFIX, idx, auth_appl);
     
    13011301                struct msg * str = NULL;
    13021302                struct msg_hdr * hdr = NULL;
    1303                 char * fqdn;
    1304                 char * realm;
     1303                DiamId_t fqdn;
     1304                size_t fqdn_len;
     1305                DiamId_t realm;
     1306                size_t realm_len;
    13051307                union avp_value avp_val;
    13061308               
     
    13231325
    13241326                /* Get information on the NAS */
    1325                 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
     1327                CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &fqdn_len, &realm, &realm_len) );
    13261328
    13271329                /* Add the Origin-Host as next AVP */
     
    13291331                memset(&avp_val, 0, sizeof(avp_val));
    13301332                avp_val.os.data = (unsigned char *)fqdn;
    1331                 avp_val.os.len = strlen(fqdn);
     1333                avp_val.os.len = fqdn_len;
    13321334                CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    13331335                CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_LAST_CHILD, avp) );
     
    13371339                memset(&avp_val, 0, sizeof(avp_val));
    13381340                avp_val.os.data = (unsigned char *)realm;
    1339                 avp_val.os.len = strlen(realm);
     1341                avp_val.os.len = realm_len;
    13401342                CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
    13411343                CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_LAST_CHILD, avp) );
  • extensions/app_radgw/rgwx_auth.c

    r705 r706  
    239239        const char * prefix = "Diameter/";
    240240        size_t pref_len;
    241         uint8_t * dh = NULL;
     241        os0_t dh = NULL;
    242242        size_t dh_len = 0;
    243         uint8_t * dr = NULL;
     243        os0_t dr = NULL;
    244244        size_t dr_len = 0;
    245         uint8_t * si = NULL;
     245        os0_t si = NULL;
    246246        size_t si_len = 0;
    247         uint8_t * un = NULL;
     247        os0_t un = NULL;
    248248        size_t un_len = 0;
    249249        size_t nattr_used = 0;
     
    293293                 and/or to the NAS-Identifier attribute.  (Note that the RADIUS
    294294                 NAS-Identifier is not required to be an FQDN.)
    295                      -> done in rgw_msg_create_base.
     295                     -> done in rgw_clients_create_origin.
    296296
    297297              -  The response MUST have an Origin-AAA-Protocol AVP added,
     
    453453        /* Create the session if it is not already done */
    454454        if (*session == NULL) {
    455                 char * sess_str = NULL;
     455                os0_t sess_str = NULL;
     456                size_t sess_strlen;
    456457               
    457458                if (si_len) {
    458459                        /* We already have the Session-Id, just use it */
    459                         CHECK_FCT( fd_sess_fromsid ( (char *) /* this cast will be removed later */ si, si_len, session, NULL) );
     460                        CHECK_FCT( fd_sess_fromsid ( si, si_len, session, NULL) );
    460461                } else {
    461462                        /* Create a new Session-Id string */
    462463                       
    463                         char * fqdn;
    464                         char * realm;
     464                        DiamId_t fqdn;
     465                        size_t fqdnlen;
     466                        DiamId_t realm;
     467                        size_t realmlen;
    465468                       
    466469                        /* Get information on the RADIUS client */
    467                         CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
     470                        CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &fqdnlen, &realm, &realmlen) );
    468471                       
    469472                        /* If we have a user name, create the new session with it */
    470473                        if (un) {
    471474                                int len;
    472                                 /* If not found, create a new Session-Id. The format is: {fqdn;hi32;lo32;username;diamid} */
     475                                /* If not found, create a new Session-Id. Our format is: {fqdn;hi32;lo32;username;diamid} */
    473476                                CHECK_MALLOC( sess_str = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) );
    474                                 len = sprintf(sess_str, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid);
    475                                 CHECK_FCT( fd_sess_new(session, fqdn, sess_str, len) );
     477                                len = sprintf((char *)sess_str, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid);
     478                                CHECK_FCT( fd_sess_new(session, fqdn, fqdnlen, sess_str, len) );
    476479                                free(sess_str);
    477480                        } else {
     
    483486               
    484487                /* Now, add the Session-Id AVP at beginning of Diameter message */
    485                 CHECK_FCT( fd_sess_getsid(*session, &sess_str) );
     488                CHECK_FCT( fd_sess_getsid(*session, &sess_str, &sess_strlen) );
    486489               
    487490                TRACE_DEBUG(FULL, "[auth.rgwx] Translating new message for session '%s'...", sess_str);
     
    489492                /* Add the Session-Id AVP as first AVP */
    490493                CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
    491                 value.os.data = (unsigned char *)sess_str;
    492                 value.os.len = strlen(sess_str);
     494                value.os.data = sess_str;
     495                value.os.len = sess_strlen;
    493496                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
    494497                CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
     
    564567                        /* This macro converts a RADIUS attribute to a Diameter AVP of type OctetString */
    565568                        #define CONV2DIAM_STR( _dictobj_ )      \
    566                                 CHECK_PARAMS( attr->length >= 2 );                                              \
     569                                CHECK_PARAMS( attr->length >= sizeof(struct radius_attr_hdr) );                 \
    567570                                /* Create the AVP with the specified dictionary model */                        \
    568571                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
    569                                 value.os.len = attr->length - 2;                                                \
    570                                 value.os.data = (unsigned char *)(attr + 1);                                    \
     572                                value.os.len = attr->length - sizeof(struct radius_attr_hdr);                   \
     573                                value.os.data = (os0_t)(attr + 1);                                              \
    571574                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
    572575                                /* Add the AVP in the Diameter message. */                                      \
     
    575578                        /* Same thing, for scalar AVPs of 32 bits */
    576579                        #define CONV2DIAM_32B( _dictobj_ )      \
    577                                 CHECK_PARAMS( attr->length == 6 );                                              \
     580                                CHECK_PARAMS( attr->length == sizeof(struct radius_attr_hdr)+sizeof(uint32_t) );\
    578581                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
    579582                                {                                                                               \
     
    589592                        /* And the 64b version */
    590593                        #define CONV2DIAM_64B( _dictobj_ )      \
    591                                 CHECK_PARAMS( attr->length == 10);                                              \
     594                                CHECK_PARAMS( attr->length == sizeof(struct radius_attr_hdr)+sizeof(uint64_t) );\
    592595                                CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
    593596                                {                                                                               \
     
    609612                              -  The Destination-Realm AVP is created from the information found
    610613                                 in the RADIUS User-Name attribute.
    611                                         -> done in rgw_msg_create_base
     614                                        -> done in rgw_clients_create_origin
    612615                        */
    613616                        case RADIUS_ATTR_USER_NAME:
  • extensions/app_radgw/rgwx_debug.c

    r356 r706  
    102102                fd_log_debug(" Diameter session: NULL pointer\n");
    103103        } else {
    104                 char * str;
    105                 CHECK_FCT( fd_sess_getsid(*session, &str) );
     104                os0_t str;
     105                size_t str_len;
     106                CHECK_FCT( fd_sess_getsid(*session, &str, &str_len) );
    106107
    107108                fd_log_debug(" Diameter session: %s\n", str);
  • extensions/app_radgw/rgwx_sip.c

    r705 r706  
    5858/* This macro converts a RADIUS attribute to a Diameter AVP of type OctetString */
    5959#define CONV2DIAM_STR( _dictobj_ )      \
    60         CHECK_PARAMS( attr->length >= 2 );                                              \
     60        CHECK_PARAMS( attr->length >= sizeof(struct radius_attr_hdr) );                 \
    6161        /* Create the AVP with the specified dictionary model */                        \
    6262        CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
    63         value.os.len = attr->length - 2;                                                \
    64         value.os.data = (unsigned char *)(attr + 1);                                    \
     63        value.os.len = attr->length - sizeof(struct radius_attr_hdr);                   \
     64        value.os.data = (os0_t)(attr + 1);                                              \
    6565        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
    6666        /* Add the AVP in the Diameter message. */                                      \
     
    6868
    6969#define CONV2DIAM_STR_AUTH( _dictobj_ ) \
    70         CHECK_PARAMS( attr->length >= 2 );                                              \
     70        CHECK_PARAMS( attr->length >= sizeof(struct radius_attr_hdr) );                 \
    7171        /* Create the AVP with the specified dictionary model */                        \
    7272        CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
    73         value.os.len = attr->length - 2;                                                \
    74         value.os.data = (unsigned char *)(attr + 1);                                    \
     73        value.os.len = attr->length - sizeof(struct radius_attr_hdr);                   \
     74        value.os.data = (os0_t)(attr + 1);                                              \
    7575        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
    7676        /* Add the AVP in the Diameter message. */                                      \
    77         CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );           \
     77        CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );                   \
    7878               
    7979/* Same thing, for scalar AVPs of 32 bits */
    8080#define CONV2DIAM_32B( _dictobj_ )      \
    81         CHECK_PARAMS( attr->length == 6 );                                              \
     81        CHECK_PARAMS( attr->length == sizeof(struct radius_attr_hdr)+sizeof(uint32_t) );\
    8282        CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) );                    \
    8383        {                                                                               \
    8484                uint8_t * v = (uint8_t *)(attr + 1);                                    \
    8585                value.u32  = (v[0] << 24)                                               \
    86                            | (v[1] << 16)                                               \
    87                            | (v[2] <<  8)                                               \
    88                            |  v[3] ;                                                    \
     86                           | (v[1] << 16)                                               \
     87                           | (v[2] <<  8)                                               \
     88                           |  v[3] ;                                                    \
    8989        }                                                                               \
    9090        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                               \
    91         CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
     91        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );               \
    9292                               
    9393                               
     
    145145{
    146146        struct fd_list chain;
    147     char * sid;
     147    os0_t sid;
    148148    size_t sidlen;
    149     char * nonce;
     149    os0_t nonce;
    150150    size_t noncelen;
    151151   
    152152};
    153153
    154 static int nonce_add_element(char * nonce, size_t noncelen,char * sid, size_t sidlen, struct rgwp_config * state)
     154static int nonce_add_element(os0_t nonce, size_t noncelen, os0_t sid, size_t sidlen, struct rgwp_config * state)
    155155{
    156156        CHECK_PARAMS(nonce && state && sid && sidlen && noncelen);
     
    159159        CHECK_MALLOC(newelt=malloc(sizeof(noncechain)));
    160160       
    161         CHECK_MALLOC(newelt->nonce=malloc(noncelen));
    162         memcpy(newelt->nonce,nonce,noncelen);
     161        CHECK_MALLOC(newelt->nonce= os0dup(nonce, noncelen));
    163162        newelt->noncelen=noncelen;
    164163       
    165         CHECK_MALLOC(newelt->sid=malloc(sidlen));
    166         memcpy(newelt->sid,sid,sidlen);
     164        CHECK_MALLOC(newelt->sid=os0dup(sid, sidlen));
    167165        newelt->sidlen=sidlen;
    168166       
     
    198196*/
    199197//Retrieve sid from nonce
    200 static char * nonce_get_sid(char * nonce, size_t noncelen, size_t * sidlen, struct rgwp_config *state)
     198static os0_t nonce_get_sid(os0_t nonce, size_t noncelen, size_t * sidlen, struct rgwp_config *state)
    201199{
    202200        struct fd_list * li;
    203         char *sid=NULL;
     201        os0_t sid=NULL;
    204202       
    205203        CHECK_PARAMS_DO(nonce && state && noncelen && sidlen, return NULL);
    206204        *sidlen=0;
    207205       
    208         //**Start mutex
     206        // **Start mutex
    209207        CHECK_POSIX_DO(pthread_mutex_lock(&state->nonce_mutex),);
    210208        for(li=state->listnonce.next;li!=&state->listnonce;li=li->next)
     
    212210                noncechain *temp=(noncechain *)li;
    213211               
    214                 if(temp->noncelen==noncelen && strncmp(temp->nonce,nonce, noncelen)==0)
     212                if (!fd_os_cmp(temp->nonce, temp->noncelen, nonce, noncelen))
    215213                {
    216214                        fd_list_unlink (li);
     
    224222        }
    225223        CHECK_POSIX_DO(pthread_mutex_unlock(&state->nonce_mutex),);
    226         //***Stop mutex
     224        // ***Stop mutex
    227225        return sid;
    228226}
     
    230228static void nonce_deletelistnonce(struct rgwp_config *state)
    231229{
    232         //**Start mutex
     230        // **Start mutex
    233231        CHECK_POSIX_DO(pthread_mutex_lock(&state->nonce_mutex),);
    234232        while(!(FD_IS_LIST_EMPTY(&state->listnonce)) )
     
    243241        }
    244242        CHECK_POSIX_DO(pthread_mutex_unlock(&state->nonce_mutex),);
    245         //***Stop mutex
     243        // ***Stop mutex
    246244}
    247245
     
    338336        int got_Dresponse = 0;
    339337        int got_Dalgorithm = 0;
    340         char * sid = NULL;
    341         char * un=NULL;
     338        os0_t sid = NULL;
     339        size_t sidlen;
     340        os0_t un=NULL;
    342341        size_t  un_len;
    343342        size_t nattr_used = 0;
     
    352351        if(*session)
    353352        {
    354                 TRACE_DEBUG(INFO,"We are not supposed to receive a session in radSIP plugin.");
     353                TRACE_DEBUG(INFO,"INTERNAL ERROR: We are not supposed to receive a session in radSIP plugin.");
    355354                return EINVAL;
    356355        }
     
    371370                                {
    372371                                        TRACE_DEBUG(ANNOYING, "Found a User-Name attribute: '%.*s'", attr->length- sizeof(struct radius_attr_hdr), (char *)(attr+1));
    373                                         un = (char *)(attr + 1);
     372                                        un = (os0_t)(attr + 1);
    374373                                        un_len =attr->length - sizeof(struct radius_attr_hdr);
    375374                                }
     
    396395                                got_Dnonce = 1;
    397396                               
    398                                 size_t sidlen;
    399                                
    400                                 sid=nonce_get_sid((char *)(attr+1),attr->length-2,&sidlen,cs);
     397                                sid=nonce_get_sid((os0_t)(attr+1), attr->length - sizeof(struct radius_attr_hdr), &sidlen, cs);
    401398                                if(!sid)
    402399                                {
     
    406403                                CHECK_FCT(fd_sess_fromsid (sid, sidlen, session, NULL));
    407404                                free(sid);
    408                                                                
     405                                                       
    409406                               
    410407                        break;
     
    432429        if (!*session) {
    433430               
    434                 char * fqdn;
    435                 char * realm;
     431                DiamId_t fqdn;
     432                size_t fqdn_len;
     433                DiamId_t realm;
     434                size_t realm_len;
    436435               
    437436               
     
    439438               
    440439                /* Get information on the RADIUS client */
    441                 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) );
    442                
    443                 int len;
     440                CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &fqdn_len, &realm, &realm_len) );
     441               
    444442                /* Create a new Session-Id. The format is: {fqdn;hi32;lo32;username;diamid} */
    445443                CHECK_MALLOC( sid = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) );
    446                 len = sprintf(sid, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid);
    447                 CHECK_FCT( fd_sess_new(session, fqdn, sid, len) );
     444                sidlen = sprintf((char *)sid, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid);
     445                CHECK_FCT( fd_sess_new(session, fqdn, fqdn_len, sid, sidlen) );
    448446                free(sid);
    449447        }
     
    453451       
    454452        int i = 0;
    455         if (un) {
    456                 /* Is there an '@' in the user name? We don't care for decorated NAI here */
    457                 for (i = un_len - 2; i > 0; i--) {
    458                         if (un[i] == '@') {
    459                                 i++;
    460                                 break;
    461                         }
     453       
     454        /* Is there an '@' in the user name? We don't care for decorated NAI here */
     455        for (i = un_len - 2; i > 0; i--) {
     456                if (un[i] == '@') {
     457                        i++;
     458                        break;
    462459                }
    463460        }
     461
    464462        if (i == 0) {
    465463                /* Not found in the User-Name => we use the local domain of this gateway */
    466                 value.os.data = (unsigned char *)fd_g_config->cnf_diamrlm;
     464                value.os.data = (os0_t)fd_g_config->cnf_diamrlm;
    467465                value.os.len  = fd_g_config->cnf_diamrlm_len;
    468466        } else {
    469                 value.os.data = (unsigned char *)(un + i);
     467                value.os.data = un + i;
    470468                value.os.len  = un_len - i;
    471469        }
     
    475473       
    476474        /* Now, add the Session-Id AVP at beginning of Diameter message */
    477         CHECK_FCT( fd_sess_getsid(*session, &sid) );
     475        CHECK_FCT( fd_sess_getsid(*session, &sid, &sidlen) );
    478476       
    479477        TRACE_DEBUG(FULL, "[sip.rgwx] Translating new message for session '%s'...", sid);
     
    481479        /* Add the Session-Id AVP as first AVP */
    482480        CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) );
    483         value.os.data = (unsigned char *)sid;
    484         value.os.len = strlen(sid);
     481        value.os.data = sid;
     482        value.os.len = sidlen;
    485483        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
    486484        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) );
     
    552550                CHECK_FCT( fd_msg_avp_add ( auth_data, MSG_BRW_LAST_CHILD, auth) );
    553551        }
    554         char * temp=NULL,*sipuri=NULL;
    555552
    556553        for (idx = 0; idx < rad_req->attr_used; idx++)
     
    597594                        {
    598595                                //We extract Realm from Digest_URI
    599                                 char *realm=NULL;
    600                        
    601                                 CHECK_MALLOC(temp=malloc(attr->length -1));
    602                                 strncpy(temp, (char *)(attr + 1), attr->length -2);
    603                                 temp[attr->length-2] = '\0';
    604                        
    605                                 realm = strtok( (char *)(temp), "@" );
    606                                 realm = strtok( NULL, "@" );
    607                                 free(temp);
    608                                 temp=NULL;
     596                                DiamId_t realm=NULL;
     597                                size_t realm_len;
     598                                os0_t temp;
     599                               
     600                                temp = (os0_t)(attr + 1);
     601                               
     602                                for (i=attr->length - sizeof(struct radius_attr_hdr) - 1; i>=0; i--) {
     603                                        if (temp[i] == '@') {
     604                                                realm = (DiamId_t)temp + i + 1;
     605                                                CHECK_FCT_DO( fd_os_validate_DiameterIdentity(&realm, &realm_len, 1),
     606                                                        realm = NULL );
     607                                                break;
     608                                        }
     609                                }
     610                       
    609611                                if(realm!=NULL)
    610612                                {
    611613                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Realm, 0, &avp ) );
    612                                         value.os.data=(unsigned char *)realm;
    613                                         value.os.len=strlen(realm);
     614                                        value.os.data=(os0_t)realm;
     615                                        value.os.len=realm_len;
    614616                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
    615617                                        CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );
     
    617619                                        //We add SIP-Server-URI AVP because SIP server is registrar (through gateway)
    618620                                        CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Server_URI, 0, &avp ) );
    619                                         value.os.data=(unsigned char *)realm;
    620                                         value.os.len=strlen(realm);
     621                                        value.os.data=(os0_t)realm;
     622                                        value.os.len=realm_len;
    621623                                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
    622624                                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
    623625                                       
     626                                        free(realm);
    624627                                }
    625628                                else
     
    641644                        //We add SIP-Server-URI AVP because SIP server is registrar (through gateway)
    642645                        CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Server_URI, 0, &avp ) );
    643                        
    644                        
    645                         CHECK_MALLOC(temp=malloc(attr->length -1));
    646                         strncpy(temp, (char *)(attr + 1), attr->length -2);
    647                        
    648                        
    649                         CHECK_MALLOC(sipuri=malloc(attr->length +3));
    650                         strcpy(sipuri,"sip:");
    651                         strcat(sipuri,(const char *)temp);
    652                         value.os.data=(unsigned char *)sipuri;
    653                         value.os.len=attr->length +2;
     646                        os0_t temp;
     647                        #define SIP_PREFIX      "sip:"
     648                        size_t temp_len = attr->length - sizeof(struct radius_attr_hdr) + CONSTSTRLEN(SIP_PREFIX) + 1;
     649                        CHECK_MALLOC( temp = malloc(temp_len) );
     650                        temp_len = snprintf((char *)temp, temp_len, SIP_PREFIX "%.*s", attr->length - sizeof(struct radius_attr_hdr), (char *)(attr + 1));
     651                       
     652                        value.os.data=temp;
     653                        value.os.len=temp_len;
    654654                       
    655655                        free(temp);
    656                         temp=NULL;
     656                       
    657657                        CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );
    658658                        CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) );
     
    689689                        {
    690690                                //[Note 3] If Digest-Algorithm is missing, 'MD5' is assumed.
     691                                #define DIGEST_ALGO_MD5 "MD5"
    691692                                                                               
    692693                                CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Algorithm, 0, &avp ) );                     
    693694                                                                               
    694                                 value.os.data = (unsigned char *)"MD5";
    695                                 value.os.len = strlen((const char *)value.os.data);
     695                                value.os.data = (os0_t)DIGEST_ALGO_MD5;
     696                                value.os.len = CONSTSTRLEN(DIGEST_ALGO_MD5) - 1;
    696697                                CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) );                                       
    697698                                CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) );   
     
    831832                                        /* Retrieve the request identified which was stored in the session */
    832833                                        if (session) {
    833                                                 char *sid=NULL;
     834                                                os0_t sid=NULL;
    834835                                                size_t sidlen;
    835                                                 fd_sess_getsid (session, &sid );
    836                                                 sidlen=strlen(sid);
     836                                                fd_sess_getsid (session, &sid, &sidlen );
    837837                                               
    838                                                 nonce_add_element((char *)ahdr->avp_value->os.data,ahdr->avp_value->os.len, sid,sidlen, cs);
     838                                                nonce_add_element(ahdr->avp_value->os.data, ahdr->avp_value->os.len, sid, sidlen, cs);
    839839                                        }
    840840                                        break;
  • extensions/app_sip/registrationtermination.c

    r639 r706  
    147147        // Create a new session
    148148        {
    149                 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "app_sip", 7 ));
    150                 char * sid;
    151                 CHECK_FCT( fd_sess_getsid ( sess, &sid ));
     149                #define APP_SIP_SID_OPT  "app_sip"
     150                CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)APP_SIP_SID_OPT, CONSTSTRLEN(APP_SIP_SID_OPT) ));
     151                os0_t sid;
     152                size_t sidlen;
     153                CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
    152154                CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
    153                 value.os.data = (uint8_t *)sid;
    154                 value.os.len  = strlen(sid);
     155                value.os.data = sid;
     156                value.os.len  = sidlen;
    155157                CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
    156158                CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
  • extensions/dbg_interactive/dbg_interactive.i

    r662 r706  
    152152
    153153/* Overwrite declaration to apply typemaps */
    154 int fd_sess_fromsid ( char * STRING, size_t LENGTH, struct session ** OUTPUT, int * BOOL_OUT);
     154int fd_sess_fromsid ( unsigned char * STRING, size_t LENGTH, struct session ** OUTPUT, int * BOOL_OUT);
    155155
    156156
  • extensions/dbg_interactive/messages.i

    r688 r706  
    341341       
    342342        /* Get the source */
    343         char *source() {
    344                 char * s = NULL;
    345                 int ret = fd_msg_source_get($self, &s);
    346                 if (ret != 0) {
    347                         DI_ERROR(ret, NULL, NULL);
    348                         return NULL;
    349                 }
    350                 return s;
     343        %cstring_output_allocate_size(char ** outid, size_t * outlen, /* do not free */);
     344        void source(char ** outid, size_t * outlen) {
     345                int ret = fd_msg_source_get($self, outid, outlen);
     346                if (ret != 0) {
     347                        DI_ERROR(ret, NULL, NULL);
     348                        return;
     349                }
     350                return;
    351351        }
    352352       
  • extensions/dbg_interactive/peers.i

    r640 r706  
    9797
    9898%inline %{
    99 static struct peer_hdr * peer_search(char *diamid) {
     99static struct peer_hdr * peer_search(char *STRING, size_t LENGTH) {
    100100        struct peer_hdr *r = NULL;
    101         int ret = fd_peer_getbyid( diamid, &r );
     101        int ret = fd_peer_getbyid( STRING, LENGTH, 0, &r );
    102102        if (ret) {
    103103                DI_ERROR(ret, NULL, NULL);
  • extensions/dbg_interactive/routing.i

    r640 r706  
    5555                fd_rtd_free(&r);
    5656        }
    57         void add(char * peerid, char * realm) {
    58                 int ret = fd_rtd_candidate_add($self, peerid, realm);
     57        %apply (char *STRING, int LENGTH) { (char * peerid, size_t peeridlen) };
     58        %apply (char *STRING, int LENGTH) { (char * realm, size_t realmlen) };
     59        void add(char * peerid, size_t peeridlen, char * realm, size_t realmlen) {
     60                int ret = fd_rtd_candidate_add($self, peerid, peeridlen, realm, realmlen);
    5961                if (ret != 0) {
    6062                        DI_ERROR(ret, NULL, NULL);
     
    6264        }
    6365        void remove(char * STRING, size_t LENGTH) {
    64                 fd_rtd_candidate_del($self, STRING, LENGTH);
    65         }
    66         void error(char * dest, char * STRING, size_t LENGTH, uint32_t rcode) {
    67                 int ret =  fd_rtd_error_add($self, dest, (uint8_t *)STRING, LENGTH, rcode);
     66                fd_rtd_candidate_del($self, (os0_t)STRING, LENGTH);
     67        }
     68        void error(char * peerid, size_t peeridlen, char * STRING, size_t LENGTH, uint32_t rcode) {
     69                int ret =  fd_rtd_error_add($self, peerid, peeridlen, (os0_t)STRING, LENGTH, rcode);
    6870                if (ret != 0) {
    6971                        DI_ERROR(ret, NULL, NULL);
  • extensions/dbg_interactive/sessions.i

    r639 r706  
    4040%{
    4141/* call it (might be called from a different thread than the interpreter, when session times out) */
    42 static void call_the_python_cleanup_callback(session_state * state, char * sid, void * cb) {
     42static void call_the_python_cleanup_callback(session_state * state, os0_t sid, void * cb) {
    4343        PyObject *result;
    4444        if (!cb) {
     
    100100                int ret;
    101101                struct session * s = NULL;
    102                 ret = fd_sess_new(&s, fd_g_config->cnf_diamid, "dbg_interactive", sizeof("dbg_interactive"));
     102                ret = fd_sess_new(&s, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"dbg_interactive", CONSTSTRLEN("dbg_interactive"));
    103103                if (ret != 0) {
    104104                        DI_ERROR(ret, NULL, NULL);
     
    110110                int ret;
    111111                struct session * s = NULL;
    112                 ret = fd_sess_new(&s, diamid, STRING, LENGTH);
     112                ret = fd_sess_new(&s, diamid, 0, (os0_t)STRING, LENGTH);
    113113                if (ret != 0) {
    114114                        DI_ERROR(ret, NULL, NULL);
     
    120120                int ret, n;
    121121                struct session * s = NULL;
    122                 ret = fd_sess_fromsid(STRING, LENGTH, &s, &n);
     122                ret = fd_sess_fromsid((os0_t)STRING, LENGTH, &s, &n);
    123123                if (ret != 0) {
    124124                        DI_ERROR(ret, NULL, NULL);
     
    144144                return;
    145145        }
    146         char * getsid() {
     146       
     147        %cstring_output_allocate_size(char ** outsid, size_t * sidlen, /* do not free */);
     148        void getsid(char ** outsid, size_t * sidlen) {
    147149                int ret;
    148                 char * sid = NULL;
    149                 ret = fd_sess_getsid( $self, &sid);
     150                ret = fd_sess_getsid( $self, (void *)outsid, sidlen);
    150151                if (ret != 0) {
    151152                        DI_ERROR(ret, NULL, NULL);
    152                         return NULL;
     153                        return;
    153154                }
    154                 return sid;
     155                return;
    155156        }
    156157        void settimeout(long seconds) {
  • extensions/test_app/ta_bench.c

    r662 r706  
    130130       
    131131        /* Create a new session */
    132         CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, "app_test", 8 ), goto out );
     132        #define TEST_APP_SID_OPT  "app_testb"
     133        CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
    133134       
    134135        /* Create the random value to store with the session */
     
    145146        /* Session-Id */
    146147        {
    147                 char * sid;
    148                 CHECK_FCT_DO( fd_sess_getsid ( sess, &sid ), goto out );
     148                os0_t sid;
     149                size_t sidlen;
     150                CHECK_FCT_DO( fd_sess_getsid ( sess, &sid, &sidlen ), goto out );
    149151                CHECK_FCT_DO( fd_msg_avp_new ( ta_sess_id, 0, &avp ), goto out );
    150                 val.os.data = (uint8_t *)sid;
    151                 val.os.len  = strlen(sid);
     152                val.os.data = sid;
     153                val.os.len  = sidlen;
    152154                CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
    153155                CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ), goto out );
  • extensions/test_app/ta_cli.c

    r662 r706  
    150150       
    151151        /* Create a new session */
    152         CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, "app_test", 8 ), goto out );
     152        #define TEST_APP_SID_OPT  "app_test"
     153        CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
    153154       
    154155        /* Create the random value to store with the session */
     
    165166        /* Session-Id */
    166167        {
    167                 char * sid;
    168                 CHECK_FCT_DO( fd_sess_getsid ( sess, &sid ), goto out );
     168                os0_t sid;
     169                size_t sidlen;
     170                CHECK_FCT_DO( fd_sess_getsid ( sess, &sid, &sidlen ), goto out );
    169171                CHECK_FCT_DO( fd_msg_avp_new ( ta_sess_id, 0, &avp ), goto out );
    170                 val.os.data = (uint8_t *)sid;
    171                 val.os.len  = strlen(sid);
     172                val.os.data = sid;
     173                val.os.len  = sidlen;
    172174                CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
    173175                CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ), goto out );
  • extensions/test_netemul/tne_process.c

    r691 r706  
    8888                /* Duplicate eventually, unless deactivated */
    8989                if (tne_conf.dupl_proba != 0.0) {
    90                         char * src;
     90                        DiamId_t src;
     91                        size_t srclen;
    9192                        /* Pick a random value in [0, 1] */
    9293                        double my_rand = drand48();
    9394                        m = pi->chain.o;
    94                         CHECK_FCT( fd_msg_source_get(m, &src) );
     95                        CHECK_FCT( fd_msg_source_get(m, &src, &srclen) );
    9596                       
    9697                        while (my_rand < (double) tne_conf.dupl_proba) {
     
    105106                                CHECK_FCT( fd_msg_bufferize(m, &buf, &len) );
    106107                                CHECK_FCT( fd_msg_parse_buffer(&buf, len, &nm) );
    107                                 CHECK_FCT( fd_msg_source_set(nm, src, 0, NULL) );
     108                                CHECK_FCT( fd_msg_source_set(nm, src, srclen, 0, NULL) );
    108109                                CHECK_FCT( fd_msg_hdr(nm, &nh) );
    109110                                nh->msg_flags |= CMD_FLAG_RETRANSMIT; /* Add the 'T' flag */
  • extensions/test_sip/locationinfo.c

    r639 r706  
    6262        // Create a new session
    6363        {
    64                 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "appsip", 6 ));
    65                 char * sid;
    66                 CHECK_FCT( fd_sess_getsid ( sess, &sid ));
     64                CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 ));
     65                os0_t sid;
     66                size_t sidlen;
     67                CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
    6768                CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
    68                 value.os.data = (uint8_t *)sid;
    69                 value.os.len  = strlen(sid);
     69                value.os.data = sid;
     70                value.os.len  = sidlen;
    7071                CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
    7172                CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
  • extensions/test_sip/locationinfosl.c

    r639 r706  
    6262        // Create a new session
    6363        {
    64                 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "appsip", 6 ));
    65                 char * sid;
    66                 CHECK_FCT( fd_sess_getsid ( sess, &sid ));
     64                CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 ));
     65                os0_t sid;
     66                size_t sidlen;
     67                CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
    6768                CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
    68                 value.os.data = (uint8_t *)sid;
    69                 value.os.len  = strlen(sid);
     69                value.os.data = sid;
     70                value.os.len  = sidlen;
    7071                CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
    7172                CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
  • extensions/test_sip/serverassignment.c

    r639 r706  
    7171        // Create a new session
    7272        {
    73                 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "appsip", 6 ));
    74                 char * sid;
    75                 CHECK_FCT( fd_sess_getsid ( sess, &sid ));
     73                CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 ));
     74                os0_t sid;
     75                size_t sidlen;
     76                CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
    7677                CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
    77                 value.os.data = (uint8_t *)sid;
    78                 value.os.len  = strlen(sid);
     78                value.os.data = sid;
     79                value.os.len  = sidlen;
    7980                CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
    8081                CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
  • extensions/test_sip/userauthorization.c

    r639 r706  
    6767        // Create a new session
    6868        {
    69                 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "appsip", 6 ));
    70                 char * sid;
    71                 CHECK_FCT( fd_sess_getsid ( sess, &sid ));
     69                CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 ));
     70                os0_t sid;
     71                size_t sidlen;
     72                CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ));
    7273                CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp ));
    73                 value.os.data = (uint8_t *)sid;
    74                 value.os.len  = strlen(sid);
     74                value.os.data = sid;
     75                value.os.len  = sidlen;
    7576                CHECK_FCT( fd_msg_avp_setvalue( avp, &value ));
    7677                CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp ));
  • include/freeDiameter/libfdcore.h

    r658 r706  
    108108        char            *cnf_file;      /* Configuration file to parse, default is DEFAULT_CONF_FILE */
    109109       
    110         char            *cnf_diamid;    /* Diameter Identity of the local peer (FQDN -- UTF-8) */
    111         size_t           cnf_diamid_len;        /* length of the previous string */
    112         char            *cnf_diamrlm;   /* Diameter realm of the local peer, default to realm part of diam_id */
     110        DiamId_t         cnf_diamid;    /* Diameter Identity of the local peer (FQDN -- ASCII) */
     111        size_t           cnf_diamid_len;/* cached length of the previous string */
     112        DiamId_t         cnf_diamrlm;   /* Diameter realm of the local peer, default to realm part of cnf_diamid */
    113113        size_t           cnf_diamrlm_len;/* length of the previous string */
    114114       
     
    187187        STATE_SUSPECT,          /* A DWR was sent and not answered within TwTime. Failover in progress. */
    188188        STATE_REOPEN,           /* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */
     189       
     190        /* Ordering issues with multistream & state machine. -- see top of p_psm.c for explanation */
     191        STATE_OPEN_NEW,         /* after CEA is sent, until a new message is received. Force ordering in this state */
     192        STATE_CLOSING_GRACE,    /* after DPA is sent or received, give a short delay for messages in the pipe to be received. */
    189193       
    190194        /* Error state */
     
    205209        , "STATE_SUSPECT"               \
    206210        , "STATE_REOPEN"                \
     211        , "STATE_OPEN_NEW"              \
     212        , "STATE_CLOSING_GRACE"         \
    207213        , "STATE_ZOMBIE"                \
    208214        };
     
    237243struct peer_info {
    238244       
    239         char *          pi_diamid;      /* UTF-8, \0 terminated. The Diameter Identity of the remote peer. */
     245        DiamId_t        pi_diamid;      /* (supposedly) UTF-8, \0 terminated. The Diameter Identity of the remote peer. */
     246        size_t          pi_diamidlen;   /* cached length of pi_diamid */
    240247       
    241248        struct {
     
    250257                }               pic_flags;      /* Flags influencing the connection to the remote peer */
    251258               
    252                 char *          pic_realm;      /* If configured, the daemon will match the received realm in CER/CEA matches this. */
     259                DiamId_t        pic_realm;      /* If configured, the daemon will check the received realm in CER/CEA matches this. */
    253260                uint16_t        pic_port;       /* port to connect to. 0: default. */
    254261               
     
    263270        struct {
    264271               
    265                 enum peer_state pir_state;      /* Current state of the peer in the state machine. fd_cpu_flush_cache() might be useful before reading. */
    266                
    267                 char *          pir_realm;      /* The received realm in CER/CEA. */
     272                /* enum peer_state      pir_state; */
     273                /* Since 1.1.0, read the state with fd_peer_getstate(peer). */
     274               
     275                DiamId_t        pir_realm;      /* The received realm in CER/CEA. */
     276                size_t          pir_realmlen;   /* length of the realm */
    268277               
    269278                uint32_t        pir_vendorid;   /* Content of the Vendor-Id AVP, or 0 by default */
    270279                uint32_t        pir_orstate;    /* Origin-State-Id value */
    271                 char *          pir_prodname;   /* copy of UTF-8 Product-Name AVP (\0 terminated) */
     280                os0_t           pir_prodname;   /* copy of Product-Name AVP (\0 terminated) */
    272281                uint32_t        pir_firmrev;    /* Content of the Firmware-Revision AVP */
    273282                int             pir_relay;      /* The remote peer advertized the relay application */
     
    290299
    291300struct peer_hdr {
    292         struct fd_list   chain; /* List of all the peers, ordered by their Diameter Id */
     301        struct fd_list   chain; /* Link into the list of all the peers, ordered by their Diameter Id (fd_os_cmp) */
    293302        struct peer_info info;  /* The public data */
    294303       
     
    339348 *
    340349 * PARAMETERS:
    341  *  diamid      : A \0 terminated string.
     350 *  diamid      : an UTF8 string describing the diameter Id of the peer to seek
     351 *  diamidlen   : length of the diamid
     352 *  igncase     : perform an almost-case-insensitive search? (slower)
    342353 *  peer        : The peer is stored here if it exists.
    343354 *
     
    349360 * !0   : An error occurred.
    350361 */
    351 int fd_peer_getbyid( char * diamid, struct peer_hdr ** peer );
     362int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer );
     363
     364/*
     365 * FUNCTION:    fd_peer_get_state
     366 *
     367 * PARAMETERS:
     368 *  peer        : The peer which state to read
     369 *
     370 * DESCRIPTION:
     371 *   Returns the current state of the peer.
     372 *
     373 * RETURN VALUE:
     374 *  -1  : peer is invalid
     375 * >=0  : the state of the peer at the time of reading.
     376 */
     377int fd_peer_get_state(struct peer_hdr *peer);
    352378
    353379/*
     
    474500/* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */
    475501int fd_msg_add_origin ( struct msg * msg, int osi );
     502
     503/* Generate a new Session-Id and add it at the beginning of the message (opt is added at the end of the sid if provided) */
     504int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen );
     505
    476506
    477507/* Parse a message against our dictionary, and in case of error log and eventually build the error reply (on return and EBADMSG, *msg == NULL or *msg is the error message ready to send) */
  • include/freeDiameter/libfdproto.h

    r705 r706  
    4545 *      DEBUG
    4646 *      MACROS
     47 *      OCTET STRINGS
    4748 *      THREADS
    4849 *      LISTS
     
    567568#endif /* BUFSIZ */
    568569
     570/* This gives the length of a const string */
     571#define CONSTSTRLEN( str ) (sizeof(str) - 1)
     572
     573
     574/*============================================================*/
     575/*                         BINARY STRINGS                     */
     576/*============================================================*/
     577
     578/* Compute a hash value of a binary string.
     579The hash must remain local to this machine, there is no guarantee that same input
     580will give same output on a different system (endianness) */
     581uint32_t fd_os_hash ( uint8_t * string, size_t len );
     582
     583/* This type used for binary strings that contain no \0 except as their last character.
     584It means some string operations can be used on it. */
     585typedef uint8_t * os0_t;
     586
     587/* Same as strdup but for os0_t strings */
     588os0_t os0dup_int(os0_t s, size_t l);
     589#define os0dup( _s, _l)  (void *)os0dup_int((os0_t)(_s), _l)
     590
     591/* Check that an octet string value can be used as os0_t */
     592static __inline__ int fd_os_is_valid_os0(uint8_t * os, size_t oslen) {
     593        /* The only situation where it is not valid is when it contains a \0 inside the octet string */
     594        return (memchr(os, '\0', oslen) == NULL);
     595}
     596
     597/* The following type denotes a verified DiameterIdentity value (that contains only pure letters, digits, hyphen, dot) */
     598typedef char * DiamId_t;
     599
     600/* Maximum length of a hostname we accept */
     601#ifndef HOST_NAME_MAX
     602#define HOST_NAME_MAX 512
     603#endif /* HOST_NAME_MAX */
     604
     605/* Check if a binary string contains a valid Diameter Identity value.
     606  rfc3588 states explicitely that such a Diameter Identity consists only of ASCII characters. */
     607int fd_os_is_valid_DiameterIdentity(uint8_t * os, size_t ossz);
     608
     609/* This checks a string is a valid DiameterIdentity and applies IDNA transformations otherwise (xn--...) */
     610int fd_os_validate_DiameterIdentity(char ** id, size_t * outsz, int memory /* 0: *id can be realloc'd. 1: *id must be malloc'd on output (was static) */ );
     611
     612/* Create an order relationship for binary strings (not needed to be \0 terminated).
     613   It does NOT mimic strings relationships so that it is more efficient. It is case sensitive.
     614   (the strings are actually first ordered by their lengh, then by their bytes contents)
     615   returns: -1 if os1 < os2;  +1 if os1 > os2;  0 if they are equal */
     616int fd_os_cmp_int(os0_t os1, size_t os1sz, os0_t os2, size_t os2sz);
     617#define fd_os_cmp(_o1, _l1, _o2, _l2)  fd_os_cmp_int((os0_t)(_o1), _l1, (os0_t)(_o2), _l2)
     618
     619/* A roughly case-insensitive variant, which actually only compares ASCII chars (0-127) in a case-insentitive maneer
     620  -- this should be OK with (old) DNS names. Not sure how it works with IDN...
     621  -- it also clearly does not support locales where a lowercase letter uses more space than upper case, such as ß -> ss
     622 It is slower than fd_os_cmp...
     623 This function should give the same order as fd_os_cmp, except when it finds 2 strings to be equal.
     624 Note that the result is NOT the same as strcasecmp !!!
     625 */
     626int fd_os_almostcasecmp_int(uint8_t * os1, size_t os1sz, uint8_t * os2, size_t os2sz);
     627#define fd_os_almostcasecmp(_o1, _l1, _o2, _l2)  fd_os_almostcasecmp_int((os0_t)(_o1), _l1, (os0_t)(_o2), _l2)
    569628
    570629
     
    602661}
    603662
    604 /* Force flushing the cache of a CPU before reading a shared memory area (use only for atomic reads such as int and void*) */
    605 extern pthread_mutex_t fd_cpu_mtx_dummy; /* only for the macro bellow, so that we have reasonably fresh pir_state value when needed */
    606 #define fd_cpu_flush_cache() {                          \
    607         (void)pthread_mutex_lock(&fd_cpu_mtx_dummy);    \
    608         (void)pthread_mutex_unlock(&fd_cpu_mtx_dummy);  \
    609 }
    610 
    611663
    612664/*************
     
    673725
    674726
    675 /*============================================================*/
    676 /*                          HASH                              */
    677 /*============================================================*/
    678 
    679 /* Compute a hash value of a string (session id, diameter id, ...) */
    680 uint32_t fd_hash ( char * string, size_t len );
    681 
    682 
    683727
    684728/*============================================================*/
     
    802846struct dict_vendor_data {
    803847        vendor_id_t      vendor_id;     /* ID of a vendor */
    804         char            *vendor_name;   /* The name of this vendor */
     848        char *           vendor_name;   /* The name of this vendor */
    805849};
    806850
     
    808852enum {
    809853        VENDOR_BY_ID = 10,      /* "what" points to a vendor_id_t */
    810         VENDOR_BY_NAME,         /* "what" points to a string */
     854        VENDOR_BY_NAME,         /* "what" points to a char * */
    811855        VENDOR_OF_APPLICATION   /* "what" points to a struct dict_object containing an application (see bellow) */
    812856};
     
    872916struct dict_application_data {
    873917        application_id_t         application_id;        /* ID of the application */
    874         char                    *application_name;      /* The name of this application */
     918        char *                   application_name;      /* The name of this application */
    875919};
    876920
     
    878922enum {
    879923        APPLICATION_BY_ID = 20,         /* "what" points to a application_id_t */
    880         APPLICATION_BY_NAME,            /* "what" points to a string */
     924        APPLICATION_BY_NAME,            /* "what" points to a char * */
    881925        APPLICATION_OF_TYPE,            /* "what" points to a struct dict_object containing a type object (see bellow) */
    882926        APPLICATION_OF_COMMAND          /* "what" points to a struct dict_object containing a command (see bellow) */
     
    947991                uint8_t *data;  /* bytes buffer */
    948992                size_t   len;   /* length of the data buffer */
    949         }           os;         /* Storage for an octet string, data is alloc'd and must be freed */
     993        }           os;         /* Storage for an octet string */
    950994        int32_t     i32;        /* integer 32 */
    951995        int64_t     i64;        /* integer 64 */
     
    10111055struct dict_type_data {
    10121056        enum dict_avp_basetype   type_base;     /* How the data of such AVP must be interpreted */
    1013         char                    *type_name;     /* The name of this type */
     1057        char *                   type_name;     /* The name of this type */
    10141058        dict_avpdata_interpret   type_interpret;/* cb to convert the AVP value in more comprehensive format (or NULL) */
    10151059        dict_avpdata_encode      type_encode;   /* cb to convert formatted data into an AVP value (or NULL) */
     
    10191063/* The criteria for searching a type object in the dictionary */
    10201064enum {
    1021         TYPE_BY_NAME = 30,              /* "what" points to a string */
     1065        TYPE_BY_NAME = 30,              /* "what" points to a char * */
    10221066        TYPE_OF_ENUMVAL,                /* "what" points to a struct dict_object containing an enumerated constant (DICT_ENUMVAL, see bellow). */
    10231067        TYPE_OF_AVP                     /* "what" points to a struct dict_object containing an AVP object. */
     
    10681112/* Type to hold data of named constants for AVP */
    10691113struct dict_enumval_data {
    1070         char            *enum_name;     /* The name of this constant */
     1114        char *           enum_name;     /* The name of this constant */
    10711115        union avp_value  enum_value;    /* Value of the constant. Union term depends on parent type's base type. */
    10721116};
     
    10801124        /* Identifier of the parent type, one of the following must not be NULL */
    10811125        struct dict_object      *type_obj;
    1082         char                    *type_name;
     1126        char *                   type_name;
    10831127       
    10841128        /* Search criteria for the constant */
     
    11831227        avp_code_t               avp_code;      /* Code of the avp */
    11841228        vendor_id_t              avp_vendor;    /* Vendor of the AVP, or 0 */
    1185         char                    *avp_name;      /* Name of this AVP */
     1229        char *                   avp_name;      /* Name of this AVP */
    11861230        uint8_t                  avp_flag_mask; /* Mask of fixed AVP flags */
    11871231        uint8_t                  avp_flag_val;  /* Values of the fixed flags */
     
    11921236enum {
    11931237        AVP_BY_CODE = 50,       /* "what" points to an avp_code_t, vendor is always 0 */
    1194         AVP_BY_NAME,            /* "what" points to a string, vendor is always 0 */
     1238        AVP_BY_NAME,            /* "what" points to a char *, vendor is always 0 */
    11951239        AVP_BY_CODE_AND_VENDOR, /* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_code are set */
    11961240        AVP_BY_NAME_AND_VENDOR, /* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_name are set */
     
    12021246        vendor_id_t      avp_vendor;
    12031247        avp_code_t       avp_code;
    1204         char            *avp_name;
     1248        char *           avp_name;
    12051249};
    12061250
     
    13101354struct dict_cmd_data {
    13111355        command_code_t   cmd_code;      /* code of the command */
    1312         char            *cmd_name;      /* Name of the command */
     1356        char *           cmd_name;      /* Name of the command */
    13131357        uint8_t          cmd_flag_mask; /* Mask of fixed-value flags */
    13141358        uint8_t          cmd_flag_val;  /* values of the fixed flags */
     
    13171361/* The criteria for searching an avp object in the dictionary */
    13181362enum {
    1319         CMD_BY_NAME = 60,       /* "what" points to a string */
     1363        CMD_BY_NAME = 60,       /* "what" points to a char * */
    13201364        CMD_BY_CODE_R,          /* "what" points to a command_code_t. The "Request" command is returned. */
    13211365        CMD_BY_CODE_A,          /* "what" points to a command_code_t. The "Answer" command is returned. */
     
    15901634 *  ENOMEM      : Not enough memory to complete the operation
    15911635 */
    1592 int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, char * sid, void * opaque), void * opaque );
     1636int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, os0_t sid, void * opaque), void * opaque );
    15931637/* Macro to avoid casting everywhere */
    15941638#define fd_sess_handler_create( _handler, _cleanup, _opaque ) \
    1595         fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, char *, void *))(_cleanup), (void *)(_opaque) )
     1639        fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, os0_t, void *))(_cleanup), (void *)(_opaque) )
    15961640
    15971641       
     
    16211665 * PARAMETERS:
    16221666 *  session       : The location where the session object will be created upon success.
    1623  *  diamId        : \0-terminated string containing a Diameter Identity.
    1624  *  opt           : Additional string. Usage is described bellow.
     1667 *  diamid        : a Diameter Identity, or NULL.
     1668 *  diamidlen     : if diamid is \0-terminated, this can be 0. Otherwise, the length of diamid.
     1669 *  opt           : Additional string, or NULL. Usage is described bellow.
    16251670 *  optlen        : if opt is \0-terminated, this can be 0. Otherwise, the length of opt.
    16261671 *
     
    16391684 *  ENOMEM      : Not enough memory to complete the operation
    16401685 */
    1641 int fd_sess_new ( struct session ** session, char * diamId, char * opt, size_t optlen );
     1686int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen );
    16421687
    16431688/*
     
    16451690 *
    16461691 * PARAMETERS:
    1647  *  sid         : pointer to a string containing a Session-Id (UTF-8).
     1692 *  sid         : pointer to a string containing a Session-Id (should be UTF-8).
    16481693 *  len         : length of the sid string (which does not need to be '\0'-terminated)
    16491694 *  session     : On success, pointer to the session object created / retrieved.
     
    16591704 *  ENOMEM      : Not enough memory to complete the operation
    16601705 */
    1661 int fd_sess_fromsid ( char * sid, size_t len, struct session ** session, int * isnew);
     1706int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * isnew);
    16621707
    16631708/*
     
    16661711 * PARAMETERS:
    16671712 *  session     : Pointer to a session object.
    1668  *  sid         : On success, the location of a (\0-terminated) string is stored here.
     1713 *  sid         : On success, the location of the sid is stored here.
    16691714 *
    16701715 * DESCRIPTION:
    16711716 *   Retrieve the session identifier (Session-Id) corresponding to a session object.
    1672  *  The returned sid is an UTF-8 string terminated by \0, suitable for calls to strlen and strcpy.
     1717 *  The returned sid is a \0-terminated binary string which might be UTF-8 (but there is no guarantee in the framework).
    16731718 *  It may be used for example to set the value of an AVP.
    16741719 *  Note that the sid string is not copied, just its reference... do not free it!
    16751720 *
    16761721 * RETURN VALUE:
    1677  *  0           : The sid parameter has been updated.
    1678  *  EINVAL      : A parameter is invalid.
    1679  */
    1680 int fd_sess_getsid ( struct session * session, char ** sid );
     1722 *  0           : The sid & len parameters have been updated.
     1723 *  EINVAL      : A parameter is invalid.
     1724 */
     1725int fd_sess_getsid ( struct session * session, os0_t * sid, size_t * sidlen );
    16811726
    16821727/*
     
    17111756 *
    17121757 * DESCRIPTION:
    1713  *   Destroys a session an all associated data, if any.
     1758 *   Destroys all associated states of a session, if any.
    17141759 * Equivalent to a session timeout expired, but the effect is immediate.
     1760 * The session itself is marked as deleted, and will be freed when it is not referenced
     1761 * by any message anymore.
    17151762 *
    17161763 * RETURN VALUE:
     
    17271774 *
    17281775 * DESCRIPTION:
    1729  *   Destroys the resources of a session, only if no session_state is associated with it.
    1730  *
    1731  * RETURN VALUE:
    1732  *  0           : The session no longer exists.
     1776 *   Equivalent to fd_sess_destroy, only if no session_state is associated with the session.
     1777 *  Otherwise, this function has no effect (except that it sets *session to NULL).
     1778 *
     1779 * RETURN VALUE:
     1780 *  0           : The session was reclaimed.
    17331781 *  EINVAL      : A parameter is invalid.
    17341782 */
     
    18021850void fd_rtd_free(struct rt_data ** rtd);
    18031851
    1804 /* Add a peer to the candidates list */
    1805 int  fd_rtd_candidate_add(struct rt_data * rtd, char * peerid, char * realm);
    1806 
    1807 /* Remove a peer from the candidates (if it is found) */
    1808 void fd_rtd_candidate_del(struct rt_data * rtd, char * peerid, size_t sz /* if !0, peerid does not need to be \0 terminated */);
     1852/* Add a peer to the candidates list. */
     1853int  fd_rtd_candidate_add(struct rt_data * rtd, DiamId_t peerid, size_t peeridlen, DiamId_t realm, size_t realmlen);
     1854
     1855/* Remove a peer from the candidates (if it is found). The search is case-insensitive. */
     1856void fd_rtd_candidate_del(struct rt_data * rtd, uint8_t * id, size_t idsz);
    18091857
    18101858/* Extract the list of valid candidates, and initialize their scores to 0 */
     
    18121860
    18131861/* If a peer returned a protocol error for this message, save it so that we don't try to send it there again */
    1814 int  fd_rtd_error_add(struct rt_data * rtd, char * sentto, uint8_t * origin, size_t originsz, uint32_t rcode);
     1862int  fd_rtd_error_add(struct rt_data * rtd, DiamId_t sentto, size_t senttolen, uint8_t * origin, size_t originsz, uint32_t rcode);
    18151863
    18161864/* The extracted list items have the following structure: */
    18171865struct rtd_candidate {
    18181866        struct fd_list  chain;  /* link in the list returned by the previous fct */
    1819         char *          diamid; /* the diameter Id of the peer */
    1820         char *          realm;  /* the diameter realm of the peer (if known) */
     1867        DiamId_t        diamid; /* the diameter Id of the peer */
     1868        size_t          diamidlen; /* cached size of the diamid string */
     1869        DiamId_t        realm;  /* the diameter realm of the peer */
     1870        size_t          realmlen; /* cached size of realm */
    18211871        int             score;  /* the current routing score for this peer, see fd_rt_out_register definition for details */
    18221872};
    18231873
    1824 /* Reorder the list of peers */
     1874/* Reorder the list of peers by score */
    18251875int  fd_rtd_candidate_reorder(struct fd_list * candidates);
    18261876
     
    22392289 * PARAMETERS:
    22402290 *  msg         : A msg object.
    2241  *  diamid      : The diameter id of the peer from which this message was received.
     2291 *  diamid,len  : The diameter id of the peer from which this message was received.
    22422292 *  add_rr      : if true, a Route-Record AVP is added to the message with content diamid. In that case, dict must be supplied.
    22432293 *  dict        : a dictionary with definition of Route-Record AVP (if add_rr is true)
     
    22522302 *  !0          : an error occurred.
    22532303 */
    2254 int fd_msg_source_set( struct msg * msg, char * diamid, int add_rr, struct dictionary * dict );
    2255 int fd_msg_source_get( struct msg * msg, char ** diamid );
     2304int fd_msg_source_set( struct msg * msg, DiamId_t diamid, size_t diamidlen, int add_rr, struct dictionary * dict );
     2305int fd_msg_source_get( struct msg * msg, DiamId_t *diamid, size_t * diamidlen );
    22562306
    22572307/*
     
    23702420 *  ENOMEM      : Unable to allocate enough memory to create the buffer object.
    23712421 */
    2372 int fd_msg_bufferize ( struct msg * msg, unsigned char ** buffer, size_t * len );
     2422int fd_msg_bufferize ( struct msg * msg, uint8_t ** buffer, size_t * len );
    23732423
    23742424/*
     
    23922442 *  EINVAL      : A parameter is invalid.
    23932443 */
    2394 int fd_msg_parse_buffer ( unsigned char ** buffer, size_t buflen, struct msg ** msg );
     2444int fd_msg_parse_buffer ( uint8_t ** buffer, size_t buflen, struct msg ** msg );
    23952445
    23962446/* Parsing Error Information structure */
     
    26542704 *  session     : The session corresponding to this object, if any.
    26552705 *  action      : Upon return, the action that must be taken on the message
     2706 *  error_code  : Upon return with action == DISP_ACT_ERROR, contains the error (such as "DIAMETER_UNABLE_TO_COMPLY")
    26562707 *
    26572708 * DESCRIPTION:
     
    26662717 *  (other errors)
    26672718 */
    2668 int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, const char ** error_code );
     2719int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, char ** error_code );
    26692720
    26702721
  • libfdcore/cnxctx.c

    r662 r706  
    5151 */
    5252
    53 /* Note: this file could be moved to libfreeDiameter instead, but since it uses gnuTLS we prefer to keep it in the daemon */
    54 
    5553/* Lifetime of a cnxctx object:
    5654 * 1) Creation
     
    158156        TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled...");
    159157        ASSERT(0);
    160         CHECK_FCT_DO( ENOTSUP, );
    161         return NULL;
     158        CHECK_FCT_DO( ENOTSUP, return NULL);
    162159#else /* DISABLE_SCTP */
    163160        struct cnxctx * cnx = NULL;
     
    249246                int  rc;
    250247               
    251                 /* Numeric values for debug */
    252248                rc = getnameinfo((sSA *)&ss, sSAlen(&ss), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    253249                if (rc) {
     
    256252                }
    257253               
    258                 snprintf(cli->cc_id, sizeof(cli->cc_id), "{%s} (%d) <- [%s]:%s (%d)",
    259                                 IPPROTO_NAME(cli->cc_proto), serv->cc_socket,
    260                                 addrbuf, portbuf, cli->cc_socket);
    261                
    262                 /* Name for log messages */
     254                /* Numeric values for debug... */
     255                snprintf(cli->cc_id, sizeof(cli->cc_id), "%s from [%s]:%s (%d<-%d)",
     256                                IPPROTO_NAME(cli->cc_proto), addrbuf, portbuf, serv->cc_socket, cli->cc_socket);
     257               
     258               
     259                /* ...Name for log messages */
    263260                rc = getnameinfo((sSA *)&ss, sSAlen(&ss), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0);
    264261                if (rc)
     
    334331                int  rc;
    335332               
    336                 /* Numeric values for debug */
     333                /* Numeric values for debug... */
    337334                rc = getnameinfo(sa, addrlen, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    338335                if (rc) {
     
    341338                }
    342339               
    343                 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "{TCP} -> [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
    344                
    345                 /* Name for log messages */
     340                snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP to [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
     341               
     342                /* ...Name for log messages */
    346343                rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
    347344                if (rc)
     
    356353{
    357354#ifdef DISABLE_SCTP
    358         TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled...");
     355        TRACE_DEBUG(INFO, "This function should never be called when SCTP is disabled...");
    359356        ASSERT(0);
    360         CHECK_FCT_DO( ENOTSUP, );
    361         return NULL;
     357        CHECK_FCT_DO( ENOTSUP, return NULL);
    362358#else /* DISABLE_SCTP */
    363359        int sock = 0;
     
    416412                int  rc;
    417413               
    418                 /* Numeric values for debug */
     414                /* Numeric values for debug... */
    419415                rc = getnameinfo((sSA *)&primary, sSAlen(&primary), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    420416                if (rc) {
     
    423419                }
    424420               
    425                 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "{SCTP} -> [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
    426                
    427                 /* Name for log messages */
     421                snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP to [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
     422               
     423                /* ...Name for log messages */
    428424                rc = getnameinfo((sSA *)&primary, sSAlen(&primary), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
    429425                if (rc)
     
    454450
    455451/* Set the hostname to check during handshake */
    456 void fd_cnx_sethostname(struct cnxctx * conn, char * hn)
     452void fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn)
    457453{
    458454        CHECK_PARAMS_DO( conn, return );
     
    460456}
    461457
     458/* We share a lock with many threads but we hold it only very short time so it is OK */
     459static pthread_mutex_t state_lock = PTHREAD_MUTEX_INITIALIZER;
     460uint32_t fd_cnx_getstate(struct cnxctx * conn)
     461{
     462        uint32_t st;
     463        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     464        st = conn->cc_state;
     465        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     466        return st;
     467}
     468int  fd_cnx_teststate(struct cnxctx * conn, uint32_t flag)
     469{
     470        uint32_t st;
     471        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     472        st = conn->cc_state;
     473        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     474        return st & flag;
     475}
     476void fd_cnx_addstate(struct cnxctx * conn, uint32_t orstate)
     477{
     478        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     479        conn->cc_state |= orstate;
     480        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     481}
     482void fd_cnx_setstate(struct cnxctx * conn, uint32_t abstate)
     483{
     484        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     485        conn->cc_state = abstate;
     486        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     487}
     488
     489
    462490/* Return the TLS state of a connection */
    463491int fd_cnx_getTLS(struct cnxctx * conn)
    464492{
    465493        CHECK_PARAMS_DO( conn, return 0 );
    466         fd_cpu_flush_cache();
    467         return conn->cc_status & CC_STATUS_TLS;
    468 }
     494        return fd_cnx_teststate(conn, CC_STATUS_TLS);
     495}
     496
     497/* Return true if the connection supports unordered delivery of messages */
     498int fd_cnx_isMultichan(struct cnxctx * conn)
     499{
     500        CHECK_PARAMS_DO( conn, return 0 );
     501        #ifdef DISABLE_SCTP
     502        if (conn->cc_proto == IPPROTO_SCTP)
     503                return (conn->cc_sctp_para.str_in > 1) || (conn->cc_sctp_para.str_out > 1);
     504        #endif /* DISABLE_SCTP */
     505        return 0;
     506}
     507
    469508
    470509/* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
     
    508547}
    509548
    510 /* Retrieve a list of all IP addresses of the local system from the kernel, using */
     549/* Retrieve a list of all IP addresses of the local system from the kernel, using getifaddrs */
    511550int fd_cnx_get_local_eps(struct fd_list * list)
    512551{
    513552        struct ifaddrs *iflist, *cur;
     553       
    514554        CHECK_SYS(getifaddrs(&iflist));
    515555       
     
    543583        CHECK_PARAMS_DO( conn, goto fatal );
    544584       
    545         TRACE_DEBUG(FULL, "Error flag set for socket %d (%s / %s)", conn->cc_socket, conn->cc_remid, conn->cc_id);
     585        TRACE_DEBUG(FULL, "Error flag set for socket %d (%s, %s)", conn->cc_socket, conn->cc_id, conn->cc_remid);
    546586       
    547587        /* Mark the error */
    548         fd_cpu_flush_cache();
    549         conn->cc_status |= CC_STATUS_ERROR;
     588        fd_cnx_addstate(conn, CC_STATUS_ERROR);
    550589       
    551590        /* Report the error if not reported yet, and not closing */
    552         if ((!(conn->cc_status & CC_STATUS_CLOSING )) && (!(conn->cc_status & CC_STATUS_SIGNALED )))  {
     591        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING | CC_STATUS_SIGNALED ))  {
    553592                TRACE_DEBUG(FULL, "Sending FDEVP_CNX_ERROR event");
    554                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), goto fatal);
    555                 conn->cc_status |= CC_STATUS_SIGNALED;
    556         }
    557         fd_cpu_flush_cache();
     593                CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_ERROR, 0, NULL), goto fatal);
     594                fd_cnx_addstate(conn, CC_STATUS_SIGNALED);
     595        }
    558596        return;
    559597fatal:
    560598        /* An unrecoverable error occurred, stop the daemon */
     599        ASSERT(0);
    561600        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );       
    562601}
     
    583622        /* Handle special case of timeout */
    584623        if ((ret < 0) && (errno == EAGAIN)) {
    585                 fd_cpu_flush_cache();
    586                 if (! (conn->cc_status & CC_STATUS_CLOSING))
     624                if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
    587625                        goto again; /* don't care, just ignore */
    588626                if (!timedout) {
     
    592630        }
    593631       
    594         CHECK_SYS_DO(ret, /* continue */);
    595        
    596632        /* Mark the error */
    597         if (ret <= 0)
     633        if (ret <= 0) {
     634                CHECK_SYS_DO(ret, /* continue, this is only used to log the error here */);
    598635                fd_cnx_markerror(conn);
     636        }
    599637       
    600638        return ret;
     
    610648        /* Handle special case of timeout */
    611649        if ((ret < 0) && (errno == EAGAIN)) {
    612                 fd_cpu_flush_cache();
    613                 if (! (conn->cc_status & CC_STATUS_CLOSING))
     650                if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
    614651                        goto again; /* don't care, just ignore */
    615652                if (!timedout) {
     
    643680       
    644681        ASSERT( conn->cc_proto == IPPROTO_TCP );
    645         ASSERT( ! (conn->cc_status & CC_STATUS_TLS) );
    646         ASSERT( Target_Queue(conn) );
     682        ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) );
     683        ASSERT( fd_cnx_target_queue(conn) );
    647684       
    648685        /* Receive from a TCP connection: we have to rebuild the message boundaries */
     
    666703
    667704                /* Check the received word is a valid begining of a Diameter message */
    668                 if ((header[0] != DIAMETER_VERSION)     /* defined in <libfreeDiameter.h> */
     705                if ((header[0] != DIAMETER_VERSION)     /* defined in <libfdproto.h> */
    669706                   || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
    670707                        /* The message is suspect */
     
    691728               
    692729                /* We have received a complete message, pass it to the daemon */
    693                 fd_cpu_flush_cache();
    694                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
     730                CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
    695731               
    696732        } while (conn->cc_loop);
     
    726762       
    727763        ASSERT( conn->cc_proto == IPPROTO_SCTP );
    728         ASSERT( ! (conn->cc_status & CC_STATUS_TLS) );
    729         ASSERT( Target_Queue(conn) );
     764        ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) );
     765        ASSERT( fd_cnx_target_queue(conn) );
    730766       
    731767        do {
    732                 fd_cpu_flush_cache();
    733                 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event, &conn->cc_status), goto fatal );
     768                CHECK_FCT_DO( fd_sctp_recvmeta(conn, NULL, &buf, &bufsz, &event), goto fatal );
    734769                if (event == FDEVP_CNX_ERROR) {
    735770                        fd_cnx_markerror(conn);
     
    742777                }
    743778               
    744                 fd_cpu_flush_cache();
    745                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto fatal );
     779                CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, bufsz, buf), goto fatal );
    746780               
    747781        } while (conn->cc_loop || (event != FDEVP_CNX_MSG_RECV));
     
    763797        TRACE_ENTRY("%p %i", conn, loop);
    764798       
    765         CHECK_PARAMS( conn && Target_Queue(conn) && (!(conn->cc_status & CC_STATUS_TLS)) && (!conn->cc_loop));
     799        CHECK_PARAMS( conn && fd_cnx_target_queue(conn) && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && (!conn->cc_loop));
    766800       
    767801        /* Release resources in case of a previous call was already made */
     
    803837                        switch (ret) {
    804838                                case GNUTLS_E_REHANDSHAKE:
    805                                         fd_cpu_flush_cache();
    806                                         if (!(conn->cc_status & CC_STATUS_CLOSING))
     839                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING))
    807840                                                CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
    808841                                                        {
     
    815848                                case GNUTLS_E_AGAIN:
    816849                                case GNUTLS_E_INTERRUPTED:
    817                                         fd_cpu_flush_cache();
    818                                         if (!(conn->cc_status & CC_STATUS_CLOSING))
     850                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING))
    819851                                                goto again;
    820852                                        TRACE_DEBUG(FULL, "Connection is closing, so abord gnutls_record_recv now.");
     
    849881                        switch (ret) {
    850882                                case GNUTLS_E_REHANDSHAKE:
    851                                         fd_cpu_flush_cache();
    852                                         if (!(conn->cc_status & CC_STATUS_CLOSING))
     883                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING))
    853884                                                CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
    854885                                                        {
     
    861892                                case GNUTLS_E_AGAIN:
    862893                                case GNUTLS_E_INTERRUPTED:
    863                                         fd_cpu_flush_cache();
    864                                         if (!(conn->cc_status & CC_STATUS_CLOSING))
     894                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING))
    865895                                                goto again;
    866896                                        TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now.");
     
    927957               
    928958                /* We have received a complete message, pass it to the daemon */
    929                 fd_cpu_flush_cache();
    930                 CHECK_FCT_DO( ret = fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg),
     959                CHECK_FCT_DO( ret = fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg),
    931960                        {
    932961                                free(newmsg);
     
    956985        }
    957986       
    958         ASSERT( conn->cc_status & CC_STATUS_TLS );
    959         ASSERT( Target_Queue(conn) );
     987        ASSERT( fd_cnx_teststate(conn, CC_STATUS_TLS) );
     988        ASSERT( fd_cnx_target_queue(conn) );
    960989
    961990        /* The next function only returns when there is an error on the socket */       
     
    12151244{
    12161245        TRACE_ENTRY( "%p %d %p %p", conn, mode, priority, alt_creds);
    1217         CHECK_PARAMS( conn && (!(conn->cc_status & CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
     1246        CHECK_PARAMS( conn && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
    12181247
    12191248        /* Save the mode */
     
    12481277
    12491278        /* Mark the connection as protected from here, so that the gnutls credentials will be freed */
    1250         fd_cpu_flush_cache();
    1251         conn->cc_status |= CC_STATUS_TLS;
    1252 
     1279        fd_cnx_addstate(conn, CC_STATUS_TLS);
     1280       
    12531281        /* Handshake master session */
    12541282        {
     
    12991327{
    13001328        TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size);
    1301         CHECK_PARAMS( conn && (conn->cc_status & CC_STATUS_TLS) && cert_list && cert_list_size );
     1329        CHECK_PARAMS( conn && fd_cnx_teststate(conn, CC_STATUS_TLS) && cert_list && cert_list_size );
    13021330       
    13031331        /* This function only works for X.509 certificates. */
     
    13601388}
    13611389
     1390/* Where the events are sent */
     1391struct fifo * fd_cnx_target_queue(struct cnxctx * conn)
     1392{
     1393        struct fifo *q;
     1394        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     1395        q = conn->cc_alt ?: conn->cc_incoming;
     1396        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     1397        return q;
     1398}
     1399
    13621400/* Set an alternate FIFO list to send FDEVP_CNX_* events to */
    13631401int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo)
    13641402{
     1403        int ret;
    13651404        TRACE_ENTRY( "%p %p", conn, alt_fifo );
    13661405        CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming );
    13671406       
    13681407        /* The magic function does it all */
    1369         CHECK_FCT( fd_fifo_move( conn->cc_incoming, alt_fifo, &conn->cc_alt ) );
    1370        
    1371         return 0;
     1408        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     1409        CHECK_FCT_DO( ret = fd_fifo_move( conn->cc_incoming, alt_fifo, &conn->cc_alt ), );
     1410        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     1411       
     1412        return ret;
    13721413}
    13731414
     
    13791420        TRACE_ENTRY("%p %p %zd", conn, buf, len);
    13801421        do {
    1381                 fd_cpu_flush_cache();
    1382                 if (conn->cc_status & CC_STATUS_TLS) {
     1422                if (fd_cnx_teststate(conn, CC_STATUS_TLS)) {
    13831423                        CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent),  );
    13841424                } else {
     
    13941434}
    13951435
    1396 /* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time, so we don't protect. */
     1436/* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time (on the same conn), so we don't protect. */
    13971437int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len, uint32_t flags)
    13981438{
    13991439        TRACE_ENTRY("%p %p %zd %x", conn, buf, len, flags);
    14001440       
    1401         CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! (conn->cc_status & CC_STATUS_ERROR)) && buf && len);
    1402 
    1403         TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, (conn->cc_status & CC_STATUS_TLS) ? "TLS-protected ":"", conn->cc_id);
     1441        CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! fd_cnx_teststate(conn, CC_STATUS_ERROR)) && buf && len);
     1442
     1443        TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, fd_cnx_teststate(conn, CC_STATUS_TLS) ? "TLS-protected ":"", conn->cc_id);
    14041444       
    14051445        switch (conn->cc_proto) {
     
    14101450#ifndef DISABLE_SCTP
    14111451                case IPPROTO_SCTP: {
    1412                         if (flags & FD_CNX_BROADCAST) {
    1413                                 /* Send the buffer over all other streams */
    1414                                 uint16_t str;
    1415                                 fd_cpu_flush_cache();
    1416                                 if (conn->cc_status & CC_STATUS_TLS) {
    1417                                         for ( str=1; str < conn->cc_sctp_para.pairs; str++) {
    1418                                                 ssize_t ret;
    1419                                                 size_t sent = 0;
    1420                                                 do {
    1421                                                         CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctps_data.array[str].session, buf + sent, len - sent), );
    1422                                                         if (ret <= 0)
    1423                                                                 return ENOTCONN;
    1424 
    1425                                                         sent += ret;
    1426                                                 } while ( sent < len );
    1427                                         }
    1428                                 } else {
    1429                                         for ( str=1; str < conn->cc_sctp_para.str_out; str++) {
    1430                                                 CHECK_FCT_DO( fd_sctp_sendstr(conn->cc_socket, str, buf, len, &conn->cc_status), { fd_cnx_markerror(conn); return ENOTCONN; } );
    1431                                         }
    1432                                 }
    1433                                
    1434                                 /* Set the ORDERED flag also so that it is sent over stream 0 as well */
    1435                                 flags &= FD_CNX_ORDERED;
    1436                         }
    1437                        
    14381452                        if (flags & FD_CNX_ORDERED) {
    14391453                                /* We send over stream #0 */
     
    14441458                                int another_str = 0; /* do we send over stream #0 ? */
    14451459                               
    1446                                 if ((conn->cc_sctp_para.str_out > 1) && ((! (conn->cc_status & CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1)))  {
     1460                                if ((conn->cc_sctp_para.str_out > 1) && ((!fd_cnx_teststate(conn, CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1)))  {
    14471461                                        /* Update the id of the stream we will send this message over */
    14481462                                        conn->cc_sctp_para.next += 1;
    1449                                         conn->cc_sctp_para.next %= ((conn->cc_status & CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);
     1463                                        conn->cc_sctp_para.next %= (fd_cnx_teststate(conn, CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);
    14501464                                        another_str = (conn->cc_sctp_para.next ? 1 : 0);
    14511465                                }
     
    14541468                                        CHECK_FCT( send_simple(conn, buf, len) );
    14551469                                } else {
    1456                                         if (!(conn->cc_status & CC_STATUS_TLS)) {
    1457                                                 CHECK_FCT_DO( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len, &conn->cc_status), { fd_cnx_markerror(conn); return ENOTCONN; } );
     1470                                        if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) {
     1471                                                CHECK_FCT_DO( fd_sctp_sendstr(conn, conn->cc_sctp_para.next, buf, len), { fd_cnx_markerror(conn); return ENOTCONN; } );
    14581472                                        } else {
    14591473                                                /* push the record to the appropriate session */
     
    14961510        CHECK_PARAMS_DO(conn, return);
    14971511       
    1498         fd_cpu_flush_cache();
    1499         conn->cc_status |= CC_STATUS_CLOSING;
     1512        fd_cnx_addstate(conn, CC_STATUS_CLOSING);
    15001513       
    15011514        /* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */
    1502         if (conn->cc_status & CC_STATUS_TLS) {
     1515        if (fd_cnx_teststate(conn, CC_STATUS_TLS)) {
    15031516#ifndef DISABLE_SCTP
    15041517                if (conn->cc_sctp_para.pairs > 1) {
    1505                         if (! (conn->cc_status & CC_STATUS_ERROR )) {
     1518                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR )) {
    15061519                                /* Bye on master session */
    15071520                                CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
    15081521                        }
    15091522
    1510                         if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
     1523                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
    15111524                                /* and other stream pairs */
    15121525                                fd_sctps_bye(conn);
    15131526                        }
    15141527
    1515                         if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
     1528                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
    15161529                                /* Now wait for all decipher threads to terminate */
    15171530                                fd_sctps_waitthreadsterm(conn);
     
    15331546                } else {
    15341547#endif /* DISABLE_SCTP */
    1535                 /* We are not using the sctps wrapper layer */
    1536                         if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
     1548                /* We are TLS, but not using the sctps wrapper layer */
     1549                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
    15371550                                /* Master session */
    15381551                                CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
    15391552                        }
    15401553
    1541                         if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
     1554                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
    15421555                                /* In this case, just wait for thread rcvthr_tls_single to terminate */
    15431556                                if (conn->cc_rcvthr != (pthread_t)NULL) {
     
    15551568                                conn->cc_tls_para.session = NULL;
    15561569                        }
    1557                
    15581570#ifndef DISABLE_SCTP
    15591571                }
  • libfdcore/cnxctx.h

    r662 r706  
    4848        int             cc_family;      /* AF_INET or AF_INET6 (mixed) */
    4949        int             cc_proto;       /* IPPROTO_TCP or IPPROTO_SCTP */
    50         uint32_t        cc_status;      /* True if the object is being destroyed: we don't send events anymore */
     50       
     51        uint32_t        cc_state;       /* True if the object is being destroyed: we don't send events anymore. access with fd_cnx_getstate() */
    5152        #define         CC_STATUS_CLOSING       1
    5253        #define         CC_STATUS_ERROR         2
     
    5960        struct fifo *   cc_incoming;    /* FIFO queue of events received on the connection, FDEVP_CNX_* */
    6061        struct fifo *   cc_alt;         /* alternate fifo to send FDEVP_CNX_* events to. */
    61         #define Target_Queue(cnx)       ((cnx)->cc_alt ?: (cnx)->cc_incoming)
    6262
    6363        /* If cc_tls == true */
    6464        struct {
    65                 char                            *cn;            /* If not NULL, remote certif will be checked to match this Common Name */
     65                DiamId_t                         cn;            /* If not NULL, remote certif will be checked to match this Common Name */
    6666                int                              mode;          /* GNUTLS_CLIENT / GNUTLS_SERVER */
    6767                gnutls_session_t                 session;       /* Session object (stream #0 in case of SCTP) */
     
    8484
    8585void fd_cnx_markerror(struct cnxctx * conn);
     86uint32_t fd_cnx_getstate(struct cnxctx * conn);
     87int  fd_cnx_teststate(struct cnxctx * conn, uint32_t flag);
     88void fd_cnx_addstate(struct cnxctx * conn, uint32_t orstate);
     89void fd_cnx_setstate(struct cnxctx * conn, uint32_t abstate);
     90struct fifo * fd_cnx_target_queue(struct cnxctx * conn);
     91
    8692
    8793/* Socket */
     
    109115int fd_sctp_get_remote_ep(int sock, struct fd_list * list);
    110116int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary );
    111 int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len, uint32_t * cc_closing);
    112 int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event, uint32_t * cc_closing);
     117int fd_sctp_sendstr(struct cnxctx * conn, uint16_t strid, uint8_t * buf, size_t len);
     118int fd_sctp_recvmeta(struct cnxctx * conn, uint16_t * strid, uint8_t ** buf, size_t * len, int *event);
    113119
    114120/* TLS over SCTP (multi-stream) */
  • libfdcore/config.c

    r686 r706  
    146146{
    147147        extern FILE * fddin;
     148        char * orig = NULL;
    148149       
    149150        /* Attempt to find the configuration file */
     
    154155        if ((fddin == NULL) && (*fd_g_config->cnf_file != '/')) {
    155156                /* We got a relative path, attempt to add the default directory prefix */
    156                 char * bkp = fd_g_config->cnf_file;
    157                 CHECK_MALLOC( fd_g_config->cnf_file = malloc(strlen(bkp) + strlen(DEFAULT_CONF_PATH) + 2) ); /* we will not free it, but not important */
    158                 sprintf( fd_g_config->cnf_file, DEFAULT_CONF_PATH "/%s", bkp );
     157                orig = fd_g_config->cnf_file;
     158                CHECK_MALLOC( fd_g_config->cnf_file = malloc(strlen(orig) + strlen(DEFAULT_CONF_PATH) + 2) ); /* we will not free it, but not important */
     159                sprintf( fd_g_config->cnf_file, DEFAULT_CONF_PATH "/%s", orig );
    159160                fddin = fopen(fd_g_config->cnf_file, "r");
    160161        }
    161162        if (fddin == NULL) {
    162163                int ret = errno;
    163                 fprintf(stderr, "Unable to open configuration file %s for reading: %s\n", fd_g_config->cnf_file, strerror(ret));
     164                if (orig) {
     165                        fprintf(stderr, "Unable to open configuration file for reading\n"
     166                                        "Tried the following locations:\n"
     167                                        " - %s\n"
     168                                        " - %s\n"
     169                                        "Error: %s\n", orig, fd_g_config->cnf_file, strerror(ret));
     170                } else {
     171                        fprintf(stderr, "Unable to open '%s' for reading: %s\n", fd_g_config->cnf_file, strerror(ret));
     172                }
    164173                return ret;
    165174        }
     
    178187        }
    179188       
     189        /* If the CA is not provided, let's use the same file (assuming self-signed certificate) */
     190        if (! fd_g_config->cnf_sec_data.ca_file) {
     191                CHECK_MALLOC( fd_g_config->cnf_sec_data.ca_file = strdup(fd_g_config->cnf_sec_data.cert_file) );
     192                CHECK_GNUTLS_DO( fd_g_config->cnf_sec_data.ca_file_nr += gnutls_certificate_set_x509_trust_file(
     193                                        fd_g_config->cnf_sec_data.credentials,
     194                                        fd_g_config->cnf_sec_data.ca_file,
     195                                        GNUTLS_X509_FMT_PEM),
     196                                {
     197                                        TRACE_DEBUG(INFO, "Unable to use the local certificate as trusted security anchor (CA), please provide a valid TLS_CA='...' directive.");
     198                                        return EINVAL;
     199                                } );
     200        }
     201       
     202       
    180203        /* Resolve hostname if not provided */
    181204        if (fd_g_config->cnf_diamid == NULL) {
    182 #ifndef HOST_NAME_MAX
    183 #define HOST_NAME_MAX 1024
    184 #endif /* HOST_NAME_MAX */
    185205                char buf[HOST_NAME_MAX + 1];
    186206                struct addrinfo hints, *info;
     
    202222                        return EINVAL;
    203223                }
    204                 CHECK_MALLOC( fd_g_config->cnf_diamid = strdup(info->ai_canonname) );
     224                fd_g_config->cnf_diamid = info->ai_canonname;
     225                CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 1) );
    205226                freeaddrinfo(info);
    206         }
    207        
    208         /* cache the length of the diameter id for the session module */
    209         fd_g_config->cnf_diamid_len = strlen(fd_g_config->cnf_diamid);
     227        } else {
     228                CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 0) );
     229        }
    210230       
    211231        /* Handle the realm part */
     
    220240                                        fd_g_config->cnf_diamid);
    221241                        return EINVAL;
    222                 }               
    223                
    224                 CHECK_MALLOC( fd_g_config->cnf_diamrlm = strdup( start + 1 )  );
    225         }
    226         fd_g_config->cnf_diamrlm_len = strlen(fd_g_config->cnf_diamrlm);
     242                }
     243               
     244                fd_g_config->cnf_diamrlm = start + 1;
     245                CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 1) );
     246        } else {
     247                CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 0) );
     248        }
    227249       
    228250        /* Validate some flags */
  • libfdcore/core.c

    r693 r706  
    4545GCRY_THREAD_OPTION_PTHREAD_IMPL;
    4646
    47 /* Signal extensions when the framework is completly initialized */
     47/* Signal extensions when the framework is completly initialized (they are waiting in fd_core_waitstartcomplete()) */
    4848static int             is_ready = 0;
    4949static pthread_mutex_t is_ready_mtx = PTHREAD_MUTEX_INITIALIZER;
     
    6262/* Thread that process incoming events on the main queue -- and terminates the framework when requested */
    6363static pthread_t core_runner = (pthread_t)NULL;
     64
     65/* How the thread is terminated */
    6466enum core_mode {
    6567        CORE_MODE_EVENTS,
  • libfdcore/extensions.c

    r695 r706  
    5757        struct fd_ext_info * new;
    5858       
    59         TRACE_ENTRY("%p(%s) %p(%s)", filename, filename?filename:"", conffile, conffile?conffile:"");
     59        TRACE_ENTRY("%p %p", filename, conffile);
    6060       
    6161        /* Check the filename is valid */
     
    106106                ext->handler = dlopen(ext->filename, RTLD_LAZY | RTLD_GLOBAL);
    107107#else /* DEBUG */
    108                 /* We resolve immediatly so it's easier to find problems in ABI */
     108                /* We resolve symbols immediatly so it's easier to find problems in ABI */
    109109                ext->handler = dlopen(ext->filename, RTLD_NOW | RTLD_GLOBAL);
    110110#endif /* DEBUG */
  • libfdcore/fdcore-internal.h

    r662 r706  
    138138        char            *p_dbgorig;
    139139       
     140        /* State of the peer, and its lock */
     141        enum peer_state  p_state;
     142        pthread_mutex_t  p_state_mtx;
     143       
    140144        /* Chaining in peers sublists */
    141145        struct fd_list   p_actives;     /* list of peers in the STATE_OPEN state -- used by routing */
     
    147151                unsigned pf_responder   : 1;    /* The peer has been created to handle incoming connection */
    148152                unsigned pf_delete      : 1;    /* Destroy the peer when the connection is terminated */
     153                unsigned pf_localterm   : 1;    /* If the latest DPR/DPA was initiated from this side */
    149154               
    150155                unsigned pf_dw_pending  : 1;    /* A DWR message was sent and not answered yet */
     
    192197#define CHECK_PEER( _p ) \
    193198        (((_p) != NULL) && (((struct fd_peer *)(_p))->p_eyec == EYEC_PEER))
     199
     200#define fd_peer_getstate(peer)  fd_peer_get_state((struct peer_hdr *)(peer))
     201
    194202
    195203/* Events codespace for struct fd_peer->p_events */
     
    308316int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer);
    309317int fd_p_dp_initiate(struct fd_peer * peer, char * reason);
     318int fd_p_dp_newdelay(struct fd_peer * peer);
    310319
    311320/* Active peers -- routing process should only ever take the read lock, the write lock is managed by PSMs */
     
    327336struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
    328337int             fd_cnx_start_clear(struct cnxctx * conn, int loop);
    329 void            fd_cnx_sethostname(struct cnxctx * conn, char * hn);
     338void            fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn);
    330339int             fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds);
    331340char *          fd_cnx_getid(struct cnxctx * conn);
    332341int             fd_cnx_getproto(struct cnxctx * conn);
    333342int             fd_cnx_getTLS(struct cnxctx * conn);
     343int             fd_cnx_isMultichan(struct cnxctx * conn);
    334344int             fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
    335345int             fd_cnx_get_local_eps(struct fd_list * list);
     
    343353/* Flags for the fd_cnx_send function : */
    344354#define FD_CNX_ORDERED          (1 << 0)        /* All messages sent with this flag set will be delivered in the same order. No guarantee on other messages */
    345 #define FD_CNX_BROADCAST        (1 << 1)        /* The message is sent over all stream pairs, in case of SCTP. No effect on TCP */
    346355
    347356#endif /* _FDCORE_INTERNAL_H */
  • libfdcore/fdd.y

    r662 r706  
    236236appservthreads:         APPSERVTHREADS '=' INTEGER ';'
    237237                        {
    238                                 CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1024),
     238                                CHECK_PARAMS_DO( ($3 > 0) && ($3 < 256),
    239239                                        { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
    240240                                conf->cnf_dispthr = (uint16_t)$3;
  • libfdcore/messages.c

    r688 r706  
    3636#include "fdcore-internal.h"
    3737
     38static struct dict_object * dict_avp_SI  = NULL; /* Session-Id */
    3839static struct dict_object * dict_avp_OH  = NULL; /* Origin-Host */
    3940static struct dict_object * dict_avp_OR  = NULL; /* Origin-Realm */
     
    5455       
    5556        /* Initialize the dictionary objects that we may use frequently */
     57        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id",         &dict_avp_SI , ENOENT)  );
    5658        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host",        &dict_avp_OH  , ENOENT)  );
    5759        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm",       &dict_avp_OR  , ENOENT)  );
     
    8991        /* Set its value */
    9092        memset(&val, 0, sizeof(val));
    91         val.os.data = (unsigned char *)fd_g_config->cnf_diamid;
     93        val.os.data = (os0_t)fd_g_config->cnf_diamid;
    9294        val.os.len  = fd_g_config->cnf_diamid_len;
    9395        CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) );
     
    102104        /* Set its value */
    103105        memset(&val, 0, sizeof(val));
    104         val.os.data = (unsigned char *)fd_g_config->cnf_diamrlm;
     106        val.os.data = (os0_t)fd_g_config->cnf_diamrlm;
    105107        val.os.len  = fd_g_config->cnf_diamrlm_len;
    106108        CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) );
     
    124126        return 0;
    125127}
     128
     129/* Create a new Session-Id and add at the beginning of the message. */
     130int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen )
     131{
     132        union avp_value val;
     133        struct avp * avp  = NULL;
     134        struct session * sess = NULL;
     135        os0_t sid;
     136        size_t sidlen;
     137       
     138        TRACE_ENTRY("%p %p %zd", msg, opt, optlen);
     139        CHECK_PARAMS(  msg  );
     140       
     141        /* Check there is not already a session in the message */
     142        CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, NULL) );
     143        CHECK_PARAMS( sess == NULL );
     144       
     145        /* Ok, now create the session */
     146        CHECK_FCT( fd_sess_new ( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, opt, optlen ) );
     147        CHECK_FCT( fd_sess_getsid( sess, &sid, &sidlen) );
     148       
     149        /* Create an AVP to hold it */
     150        CHECK_FCT( fd_msg_avp_new( dict_avp_SI, 0, &avp ) );
     151       
     152        /* Set its value */
     153        memset(&val, 0, sizeof(val));
     154        val.os.data = sid;
     155        val.os.len  = sidlen;
     156        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     157       
     158        /* Add it to the message */
     159        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) );
     160       
     161        /* Done! */
     162        return 0;
     163}
     164
    126165
    127166/* Add Result-Code and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */
     
    147186                memset(&req, 0, sizeof(struct dict_enumval_request));
    148187               
    149                 /* First, get the enumerated type of the Result-Code AVP */
     188                /* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */
    150189                CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT  )  );
    151190               
     
    184223                /* Set its value */
    185224                memset(&val, 0, sizeof(val));
    186                 val.os.data = (unsigned char *)fd_g_config->cnf_diamid;
     225                val.os.data = (uint8_t *)fd_g_config->cnf_diamid;
    187226                val.os.len  = fd_g_config->cnf_diamid_len;
    188227                CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) );
     
    246285               
    247286                if (errormsg) {
    248                         val.os.data = (unsigned char *)errormsg;
     287                        val.os.data = (uint8_t *)errormsg;
    249288                        val.os.len  = strlen(errormsg);
    250289                } else {
    251                         val.os.data = (unsigned char *)rescode;
     290                        val.os.data = (uint8_t *)rescode;
    252291                        val.os.len  = strlen(rescode);
    253292                }
     
    311350        if      ((ret != EBADMSG)       /* Parsing grouped AVP failed / Conflicting rule found */
    312351                && (ret != ENOTSUP))    /* Command is not supported / Mandatory AVP is not supported */
    313                 return ret;
     352                return ret; /* 0 or another error */
    314353       
    315354        TRACE_DEBUG(INFO, "A message does not comply to the dictionary and/or rules (%s)", pei.pei_errcode);
  • libfdcore/p_ce.c

    r688 r706  
    3838/* This file contains code to handle Capabilities Exchange messages (CER and CEA) and election process */
    3939
    40 /* Compilation option:
    41  USE_CEA_BROADCAST
    42         Define this to enable sending multiple copies of the CEA in case of SCTP connection.
    43         This avoids a race condition when sending an application message over a different stream
    44         than the CEA, it might be delivered first and thus ignored.
    45 */
    46 
    4740/* Save a connection as peer's principal */
    4841static int set_peer_cnx(struct fd_peer * peer, struct cnxctx **cnx)
     
    8881}
    8982
    90 /* Election: compare the Diameter Ids, return true if the election is won */
     83/* Election: compare the Diameter Ids by lexical order, return true if the election is won */
    9184static __inline__ int election_result(struct fd_peer * peer)
    9285{
     
    245238static void cleanup_remote_CE_info(struct fd_peer * peer)
    246239{
     240        /* free linked information */
    247241        free(peer->p_hdr.info.runtime.pir_realm);
    248         peer->p_hdr.info.runtime.pir_realm = NULL;
    249         peer->p_hdr.info.runtime.pir_vendorid = 0;
    250         peer->p_hdr.info.runtime.pir_orstate = 0;
    251242        free(peer->p_hdr.info.runtime.pir_prodname);
    252         peer->p_hdr.info.runtime.pir_prodname = NULL;
    253         peer->p_hdr.info.runtime.pir_firmrev = 0;
    254         peer->p_hdr.info.runtime.pir_relay = 0;
    255         peer->p_hdr.info.runtime.pir_isi = 0;
    256243        while (!FD_IS_LIST_EMPTY(&peer->p_hdr.info.runtime.pir_apps)) {
    257244                struct fd_list * li = peer->p_hdr.info.runtime.pir_apps.next;
     
    259246                free(li);
    260247        }
    261        
    262         fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_ADV /* Remove previously advertised endpoints */ );
     248        /* note: pir_cert_list needs not be freed (belongs to gnutls) */
     249       
     250        /* cleanup the area */
     251        memset(&peer->p_hdr.info.runtime, 0, sizeof(peer->p_hdr.info.runtime));
     252       
     253        /* reinit the list */
     254        fd_list_init(&peer->p_hdr.info.runtime.pir_apps, peer);
     255
     256        /* Remove previously advertised endpoints */
     257        fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_ADV );
    263258}
    264259
    265260/* Extract information sent by the remote peer and save it in our peer structure */
    266 static int save_remote_CE_info(struct msg * msg, struct fd_peer * peer, char ** error_code, uint32_t *rc)
     261static int save_remote_CE_info(struct msg * msg, struct fd_peer * peer, struct fd_pei * error, uint32_t *rc)
    267262{
    268263        struct avp * avp = NULL;
     
    309304                               
    310305                                /* We check that the value matches what we know, otherwise disconnect the peer */
    311                                 /* here also, using strcasecmp on (supposed) UTF8 data might be bad idea... to be improved */
    312                                 if (strncasecmp((char *)hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid, hdr->avp_value->os.len)) {
     306                                if (fd_os_almostcasecmp(hdr->avp_value->os.data, hdr->avp_value->os.len,
     307                                                        peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen)) {
    313308                                        TRACE_DEBUG(INFO, "Received a message with Origin-Host set to '%.*s' while expecting '%s'\n",
    314309                                                        hdr->avp_value->os.len, hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid);
    315                                         *error_code = "DIAMETER_UNKNOWN_PEER";
     310                                        error->pei_errcode = "ER_DIAMETER_AVP_NOT_ALLOWED";
     311                                        error->pei_message = "Your Origin-Host value does not match my configuration.";
     312                                        error->pei_avp = avp;
    316313                                        return EINVAL;
    317314                                }
     
    330327                                /* In case of multiple AVPs */
    331328                                if (peer->p_hdr.info.runtime.pir_realm) {
    332                                         TRACE_DEBUG(INFO, "Ignored multiple instances of the Origin-Realm AVP");
    333                                         goto next;
    334                                 }
    335                                
    336                                 /* Save the value -- we don't change the case to avoid risking breaking UTF-8 with poor tolower() impls. */
    337                                 CHECK_MALLOC(  peer->p_hdr.info.runtime.pir_realm = calloc( hdr->avp_value->os.len + 1, 1 )  );
    338                                 memcpy(peer->p_hdr.info.runtime.pir_realm, hdr->avp_value->os.data, hdr->avp_value->os.len);
     329                                        TRACE_DEBUG(INFO, "Multiple instances of the Origin-Realm AVP");
     330                                        error->pei_errcode = "ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
     331                                        error->pei_message = "I found several Origin-Realm AVPs";
     332                                        error->pei_avp = avp;
     333                                        return EINVAL;
     334                                }
     335                               
     336                                /* If the octet string contains a \0 */
     337                                if (!fd_os_is_valid_DiameterIdentity(hdr->avp_value->os.data, hdr->avp_value->os.len)) {
     338                                        error->pei_errcode = "ER_DIAMETER_INVALID_AVP_VALUE";
     339                                        error->pei_message = "Your Origin-Realm contains invalid characters.";
     340                                        error->pei_avp = avp;
     341                                        return EINVAL;
     342                                }
     343                               
     344                                /* Save the value */
     345                                CHECK_MALLOC(  peer->p_hdr.info.runtime.pir_realm = os0dup( hdr->avp_value->os.data, hdr->avp_value->os.len )  );
     346                                peer->p_hdr.info.runtime.pir_realmlen = hdr->avp_value->os.len;
    339347                                break;
    340348
     
    352360                                        /* Get the sockaddr value */
    353361                                        memset(&ss, 0, sizeof(ss));
    354                                         CHECK_FCT( fd_msg_avp_value_interpret( avp, &ss) );
     362                                        CHECK_FCT_DO( fd_msg_avp_value_interpret( avp, &ss),
     363                                                {
     364                                                        /* in case of error, assume the AVP value was wrong */
     365                                                        error->pei_errcode = "ER_DIAMETER_INVALID_AVP_VALUE";
     366                                                        error->pei_avp = avp;
     367                                                        return EINVAL;
     368                                                } );
    355369
    356370                                        /* Save this endpoint in the list as advertized */
     
    370384                                /* In case of multiple AVPs */
    371385                                if (peer->p_hdr.info.runtime.pir_vendorid) {
    372                                         TRACE_DEBUG(INFO, "Ignored multiple instances of the Vendor-Id AVP");
    373                                         goto next;
     386                                        TRACE_DEBUG(INFO, "Multiple instances of the Vendor-Id AVP");
     387                                        error->pei_errcode = "ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
     388                                        error->pei_message = "I found several Vendor-Id AVPs";
     389                                        error->pei_avp = avp;
     390                                        return EINVAL;
    374391                                }
    375392                               
     
    388405                                /* In case of multiple AVPs */
    389406                                if (peer->p_hdr.info.runtime.pir_prodname) {
    390                                         TRACE_DEBUG(INFO, "Ignored multiple instances of the Product-Name AVP");
    391                                         goto next;
     407                                        TRACE_DEBUG(INFO, "Multiple instances of the Product-Name AVP");
     408                                        error->pei_errcode = "ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
     409                                        error->pei_message = "I found several Product-Name AVPs";
     410                                        error->pei_avp = avp;
     411                                        return EINVAL;
    392412                                }
    393413
     
    407427                                /* In case of multiple AVPs */
    408428                                if (peer->p_hdr.info.runtime.pir_orstate) {
    409                                         TRACE_DEBUG(INFO, "Ignored multiple instances of the Origin-State-Id AVP");
    410                                         goto next;
     429                                        TRACE_DEBUG(INFO, "Multiple instances of the Origin-State-Id AVP");
     430                                        error->pei_errcode = "ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
     431                                        error->pei_message = "I found several Origin-State-Id AVPs";
     432                                        error->pei_avp = avp;
     433                                        return EINVAL;
    411434                                }
    412435                               
     
    423446                                }
    424447                               
    425                                 TRACE_DEBUG(FULL, "'%s' supports a subset of vendor %d features.", peer->p_hdr.info.pi_diamid, hdr->avp_value->u32);
     448                                TRACE_DEBUG(FULL, "'%s' claims support for a subset of vendor %d features.", peer->p_hdr.info.pi_diamid, hdr->avp_value->u32);
     449                                /* not that it makes a difference for us...
     450                                 -- if an application actually needs this info, we could save it somewhere.
     451                                */
    426452                                break;
    427453
     
    477503                                                TRACE_DEBUG(FULL, "Invalid Vendor-Specific-Application-Id AVP received, ignored");
    478504                                                fd_msg_dump_one(FULL, avp);
     505                                                error->pei_errcode = "ER_DIAMETER_INVALID_AVP_VALUE";
     506                                                error->pei_avp = avp;
     507                                                return EINVAL;
    479508                                        } else {
    480509                                                /* Add an entry in the list */
     
    510539                               
    511540                                if (hdr->avp_value->u32 == AI_RELAY) {
     541                                        /* Not clear if the relay application can be inside this AVP... */
    512542                                        peer->p_hdr.info.runtime.pir_relay = 1;
    513543                                } else {
    514                                         /* Not clear if the relay application can be inside this AVP... */
    515544                                        CHECK_FCT( fd_app_merge(&peer->p_hdr.info.runtime.pir_apps, hdr->avp_value->u32, 0, 0, 1) );
    516545                                }
     
    537566                                        goto next;
    538567                                }
    539                                 ASSERT( hdr->avp_value->u32 < 32 ); /* if false, we have to change the code bellow */
     568                                if (hdr->avp_value->u32 >= 32 ) {
     569                                        error->pei_errcode = "ER_DIAMETER_INVALID_AVP_VALUE";
     570                                        error->pei_message = "I don't support this Inband-Security-Id value (yet).";
     571                                        error->pei_avp = avp;
     572                                        return EINVAL;
     573                                }
    540574                                peer->p_hdr.info.runtime.pir_isi |= (1 << hdr->avp_value->u32);
    541575                                break;
     
    559593        CHECK_FCT( fd_msg_new ( fd_dict_cmd_CER, MSGFL_ALLOC_ETEID, cer ) );
    560594       
    561         /* Do we need Inband-Security-Id AVPs ? */
     595        /* Do we need Inband-Security-Id AVPs ? If we're already using TLS, we don't... */
    562596        if (!fd_cnx_getTLS(cnx)) {
    563                 isi_none = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE; /* we add it event if the peer does not use the old mechanism */
     597                isi_none = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE; /* we add it even if the peer does not use the old mechanism, it is impossible to distinguish */
    564598                isi_tls  = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD;
    565599        }
     
    587621
    588622/* Reject an incoming connection attempt */
    589 static void receiver_reject(struct cnxctx * recv_cnx, struct msg ** cer, char * rescode, char * errormsg)
     623static void receiver_reject(struct cnxctx ** recv_cnx, struct msg ** cer, struct fd_pei * error)
    590624{
    591625        /* Create and send the CEA with appropriate error code */
    592626        CHECK_FCT_DO( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ), goto destroy );
    593         CHECK_FCT_DO( fd_msg_rescode_set(*cer, rescode, errormsg, NULL, 1 ), goto destroy );
    594         CHECK_FCT_DO( fd_out_send(cer, recv_cnx, NULL, FD_CNX_ORDERED), goto destroy );
     627        CHECK_FCT_DO( fd_msg_rescode_set(*cer, error->pei_errcode, error->pei_message, error->pei_avp, 1 ), goto destroy );
     628        CHECK_FCT_DO( fd_out_send(cer, *recv_cnx, NULL, FD_CNX_ORDERED), goto destroy );
    595629       
    596630        /* And now destroy this connection */
    597631destroy:
    598         fd_cnx_destroy(recv_cnx);
     632        fd_cnx_destroy(*recv_cnx);
     633        *recv_cnx = NULL;
    599634        if (*cer) {
    600635                fd_msg_log(FD_MSG_LOG_DROPPED, *cer, "An error occurred while rejecting a CER.");
     
    614649       
    615650        /* Are we doing an election ? */
    616         fd_cpu_flush_cache();
    617         if (peer->p_hdr.info.runtime.pir_state == STATE_WAITCNXACK_ELEC) {
     651        if (fd_peer_getstate(peer) == STATE_WAITCNXACK_ELEC) {
    618652                if (election_result(peer)) {
    619653                        /* Close initiator connection */
     
    624658
    625659                } else {
     660                        struct fd_pei pei;
     661                        memset(&pei, 0, sizeof(pei));
     662                        pei.pei_errcode = "ELECTION_LOST";
    626663
    627664                        /* Answer an ELECTION LOST to the receiver side */
    628                         receiver_reject(peer->p_receiver, &peer->p_cer, "ELECTION_LOST", NULL);
    629                         peer->p_receiver = NULL;
     665                        receiver_reject(&peer->p_receiver, &peer->p_cer, &pei);
    630666                        CHECK_FCT( to_waitcea(peer, initiator) );
    631667                }
     
    641677int fd_p_ce_msgrcv(struct msg ** msg, int req, struct fd_peer * peer)
    642678{
    643         char * ec;
    644679        uint32_t rc = 0;
     680        int st;
     681        struct fd_pei pei;
     682       
    645683        TRACE_ENTRY("%p %p", msg, peer);
    646684        CHECK_PARAMS( msg && *msg && CHECK_PEER(peer) );
     
    656694               
    657695                /* Set the error code */
    658                 CHECK_FCT( fd_msg_rescode_set(*msg, "DIAMETER_COMMAND_UNSUPPORTED", "No CER allowed in current state", NULL, 1 ) );
     696                CHECK_FCT( fd_msg_rescode_set(*msg, "ER_DIAMETER_UNABLE_TO_COMPLY", "No CER allowed in current state", NULL, 1 ) );
    659697
    660698                /* msg now contains an answer message to send back */
     
    663701       
    664702        /* If the state is not WAITCEA, just discard the message */
    665         fd_cpu_flush_cache();
    666         if (req || (peer->p_hdr.info.runtime.pir_state != STATE_WAITCEA)) {
     703        if (req || ((st = fd_peer_getstate(peer)) != STATE_WAITCEA)) {
    667704                if (*msg) {
    668                         fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Received CER/CEA while in '%s' state.\n", STATE_STR(peer->p_hdr.info.runtime.pir_state));
     705                        fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Received CER/CEA while in '%s' state.\n", STATE_STR(st));
    669706                        CHECK_FCT_DO( fd_msg_free(*msg), /* continue */);
    670707                        *msg = NULL;
     
    674711        }
    675712       
     713        memset(&pei, 0, sizeof(pei));
     714       
    676715        /* Save info from the CEA into the peer */
    677         CHECK_FCT_DO( save_remote_CE_info(*msg, peer, &ec, &rc), goto cleanup );
     716        CHECK_FCT_DO( save_remote_CE_info(*msg, peer, &pei, &rc), goto cleanup );
    678717       
    679718        /* Dispose of the message, we don't need it anymore */
     
    701740                default:
    702741                        /* In any other case, we abort all attempts to connect to this peer */
    703                         TRACE_DEBUG(INFO, "Peer %s replied a CEA with Result-Code AVP %d, aborting connection attempts.", peer->p_hdr.info.pi_diamid, rc);
     742                        TRACE_DEBUG(INFO, "Peer %s replied a CEA with Result-Code %d, aborting connection attempts.", peer->p_hdr.info.pi_diamid, rc);
    704743                        return EINVAL;
    705744        }
     
    751790}
    752791
    753 /* Handle the receiver side to go to OPEN state (any election is resolved) */
     792/* Handle the receiver side to go to OPEN or OPEN_NEW state (any election is resolved) */
    754793int fd_p_ce_process_receiver(struct fd_peer * peer)
    755794{
    756         char * ec = NULL;
     795        struct fd_pei pei;
    757796        struct msg * msg = NULL;
    758797        int isi = 0;
    759798        int fatal = 0;
     799        int tls_sync=0;
    760800       
    761801        TRACE_ENTRY("%p", peer);
     
    765805        peer->p_cer = NULL;
    766806       
     807        memset(&pei, 0, sizeof(pei));
     808       
    767809        /* Parse the content of the received CER */
    768         CHECK_FCT_DO( save_remote_CE_info(msg, peer, &ec, NULL), goto error_abort );
     810        CHECK_FCT_DO( save_remote_CE_info(msg, peer, &pei, NULL), goto error_abort );
     811       
     812        /* Validate the realm if needed */
     813        if (peer->p_hdr.info.config.pic_realm) {
     814                size_t len = strlen(peer->p_hdr.info.config.pic_realm);
     815                if (fd_os_almostcasecmp(peer->p_hdr.info.config.pic_realm, len, peer->p_hdr.info.runtime.pir_realm, peer->p_hdr.info.runtime.pir_realmlen)) {
     816                        TRACE_DEBUG(INFO, "Rejected CER from peer '%s', realm mismatch with configured value (returning DIAMETER_UNKNOWN_PEER).\n", peer->p_hdr.info.pi_diamid);
     817                        pei.pei_errcode = "DIAMETER_UNKNOWN_PEER"; /* maybe AVP_NOT_ALLOWED would be better fit? */
     818                        goto error_abort;
     819                }
     820        }
    769821       
    770822        /* Validate the peer if needed */
     
    773825                if (res < 0) {
    774826                        TRACE_DEBUG(INFO, "Rejected CER from peer '%s', validation failed (returning DIAMETER_UNKNOWN_PEER).\n", peer->p_hdr.info.pi_diamid);
    775                         ec = "DIAMETER_UNKNOWN_PEER";
     827                        pei.pei_errcode = "DIAMETER_UNKNOWN_PEER";
    776828                        goto error_abort;
    777829                }
     
    785837                if (!got_common) {
    786838                        TRACE_DEBUG(INFO, "No common application with peer '%s', sending DIAMETER_NO_COMMON_APPLICATION", peer->p_hdr.info.pi_diamid);
    787                         ec = "DIAMETER_NO_COMMON_APPLICATION";
     839                        pei.pei_errcode = "DIAMETER_NO_COMMON_APPLICATION";
    788840                        fatal = 1;
    789841                        goto error_abort;
     
    835887                if (!isi) {
    836888                        TRACE_DEBUG(INFO, "No common security mechanism with '%s', sending DIAMETER_NO_COMMON_SECURITY", peer->p_hdr.info.pi_diamid);
    837                         ec = "DIAMETER_NO_COMMON_SECURITY";
     889                        pei.pei_errcode = "DIAMETER_NO_COMMON_SECURITY";
    838890                        fatal = 1;
    839891                        goto error_abort;
     
    849901        CHECK_FCT( fd_msg_rescode_set(msg, "DIAMETER_SUCCESS", NULL, NULL, 0 ) );
    850902        CHECK_FCT( add_CE_info(msg, peer->p_cnxctx, isi & PI_SEC_TLS_OLD, isi & PI_SEC_NONE) );
    851 #ifdef USE_CEA_BROADCAST
    852         CHECK_FCT( fd_out_send(&msg, peer->p_cnxctx, peer, (isi & PI_SEC_TLS_OLD) ? FD_CNX_ORDERED : FD_CNX_BROADCAST) ); /* Broadcast in order to avoid further messages sent over a different stream be delivered first... */
    853 #else /* USE_CEA_BROADCAST */
    854903        CHECK_FCT( fd_out_send(&msg, peer->p_cnxctx, peer, FD_CNX_ORDERED ) );
    855 #endif /* USE_CEA_BROADCAST */
    856904       
    857905        /* Handshake if needed */
     
    878926                                }  );
    879927                }
    880                
     928                tls_sync = 1;
    881929        } else {
    882930                if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
     
    891939                CHECK_FCT( fd_p_dw_reopen(peer) );
    892940        } else {
    893                 fd_psm_change_state(peer, STATE_OPEN );
    894                 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
     941                if ((!tls_sync) && (fd_cnx_isMultichan(peer->p_cnxctx))) {
     942                        fd_psm_change_state(peer, STATE_OPEN_NEW );
     943                        /* send DWR */
     944                        CHECK_FCT( fd_p_dw_timeout(peer) );
     945                } else {
     946
     947                        fd_psm_change_state(peer, STATE_OPEN );
     948                        fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
     949                }
    895950        }
    896951       
     
    898953
    899954error_abort:
    900         if (ec) {
    901                 /* Create the error message */
    902                 CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, MSGFL_ANSW_ERROR ) );
    903 
    904                 /* Set the error code */
    905                 CHECK_FCT( fd_msg_rescode_set(msg, ec, NULL, NULL, 1 ) );
    906 
    907                 /* msg now contains an answer message to send back */
    908                 CHECK_FCT_DO( fd_out_send(&msg, peer->p_cnxctx, peer, FD_CNX_ORDERED), /* In case of error the message has already been dumped */ );
     955        if (pei.pei_errcode) {
     956                /* Send the error */
     957                receiver_reject(&peer->p_cnxctx, &msg, &pei);
    909958        }
    910959       
     
    925974int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid)
    926975{
    927         fd_cpu_flush_cache();
    928         switch (peer->p_hdr.info.runtime.pir_state) {
     976        struct fd_pei pei;
     977        int cur_state = fd_peer_getstate(peer);
     978        memset(&pei, 0, sizeof(pei));
     979       
     980        switch (cur_state) {
    929981                case STATE_CLOSED:
    930982                        peer->p_receiver = *cnx;
     
    9601012
    9611013                                /* Answer an ELECTION LOST to the receiver side and continue */
    962                                 receiver_reject(*cnx, msg, "ELECTION_LOST", "Please answer my CER instead, you won the election.");
    963                                 *cnx = NULL;
     1014                                pei.pei_errcode = "ELECTION_LOST";
     1015                                pei.pei_message = "Please answer my CER instead, you won the election.";
     1016                                receiver_reject(cnx, msg, &pei);
    9641017                        }
    9651018                        break;
    9661019
    9671020                default:
    968                         receiver_reject(*cnx, msg, "DIAMETER_UNABLE_TO_COMPLY", "Invalid state to receive a new connection attempt");
    969                         *cnx = NULL;
     1021                        pei.pei_errcode = "DIAMETER_UNABLE_TO_COMPLY"; /* INVALID COMMAND? in case of Capabilities-Updates? */
     1022                        pei.pei_message = "Invalid state to receive a new connection attempt.";
     1023                        receiver_reject(cnx, msg, &pei);
    9701024        }
    9711025                               
  • libfdcore/p_cnx.c

    r691 r706  
    3636#include "fdcore-internal.h"
    3737
     38
     39/* TODO: change the behavior to handle properly forced ordering at beginning & end of OPEN state */
     40
    3841/* This file contains code used by a peer state machine to initiate a connection to remote peer */
    3942
     
    8790                ret = getaddrinfo(peer->p_hdr.info.pi_diamid, NULL, &hints, &ai);
    8891                if (ret) {
    89                         fd_log_debug("Unable to resolve address for peer '%s' (%s), aborting\n", peer->p_hdr.info.pi_diamid, gai_strerror(ret));
     92                        TRACE_DEBUG(INFO, "Unable to resolve address for peer '%s' (%s), aborting\n", peer->p_hdr.info.pi_diamid, gai_strerror(ret));
    9093                        if (ret != EAI_AGAIN)
    9194                                fd_psm_terminate( peer, NULL );
     
    123126        /* Now check we have at least one address to attempt */
    124127        if (FD_IS_LIST_EMPTY(&peer->p_hdr.info.pi_endpoints)) {
    125                 fd_log_debug("No address %savailable to connect to peer '%s', aborting\n", peer->p_hdr.info.config.pic_flags.pro3 ? "in the configured family " : "", peer->p_hdr.info.pi_diamid);
     128                TRACE_DEBUG(INFO, "No address %savailable to connect to peer '%s', aborting\n",
     129                                        peer->p_hdr.info.config.pic_flags.pro3 ? "in the configured family " : "", peer->p_hdr.info.pi_diamid);
    126130                fd_psm_terminate( peer, NULL );
    127131                return 0;
     
    219223        {
    220224                char buf[48];
    221                 sprintf(buf, "ConnTo:%.*s", (int)(sizeof(buf)) - 8, peer->p_hdr.info.pi_diamid);
     225                snprintf(buf, sizeof(buf), "ConnTo:%s", peer->p_hdr.info.pi_diamid);
    222226                fd_log_threadname ( buf );
    223227        }
     
    247251#ifndef DISABLE_SCTP                   
    248252                        case IPPROTO_SCTP:
    249                                 cnx = fd_cnx_cli_connect_sctp((peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ?: fd_g_config->cnf_flags.no_ip6, nc->port, &peer->p_hdr.info.pi_endpoints);
     253                                cnx = fd_cnx_cli_connect_sctp((peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ?: fd_g_config->cnf_flags.no_ip6,
     254                                                        nc->port, &peer->p_hdr.info.pi_endpoints);
    250255                                break;
    251256#endif /* DISABLE_SCTP */
     
    260265                pthread_testcancel();
    261266               
    262         } while (!cnx); /* and until cancellation */
     267        } while (!cnx); /* and until cancellation or all addresses attempted without success */
    263268       
    264269        /* Now, we have an established connection in cnx */
     
    274279                        {
    275280                                /* Handshake failed ...  */
    276                                 fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
     281                                TRACE_DEBUG(INFO, "TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
    277282                                fd_cnx_destroy(cnx);
    278283                                empty_connection_list(peer);
  • libfdcore/p_dp.c

    r662 r706  
    3838/* This file contains code to handle Disconnect Peer messages (DPR and DPA) */
    3939
     40/* Delay to use before next reconnect attempt */
     41int fd_p_dp_newdelay(struct fd_peer * peer)
     42{
     43        int delay = peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc;
     44       
     45        switch (peer->p_hdr.info.runtime.pir_lastDC) {
     46                case ACV_DC_REBOOTING:
     47                default:
     48                        /* We use TcTimer to attempt reconnection */
     49                        break;
     50                case ACV_DC_BUSY:
     51                        /* No need to hammer the overloaded peer */
     52                        delay *= 10;
     53                        break;
     54                case ACV_DC_NOT_FRIEND:
     55                        /* He does not want to speak to us... let's retry a *lot* later maybe */
     56                        delay *= 200;
     57                        break;
     58        }
     59        return delay;
     60}
     61
    4062/* Handle a received message */
    4163int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer)
     
    4466       
    4567        if (req) {
    46                 /* We received a DPR, save the Disconnect-Cause and terminate the connection */
     68                /* We received a DPR, save the Disconnect-Cause and go to CLOSING_GRACE or terminate the connection */
    4769                struct avp * dc;
    48                 int delay = peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc;
    4970               
    5071                CHECK_FCT( fd_msg_search_avp ( *msg, fd_dict_avp_DC, &dc ));
    5172                if (dc) {
    52                         /* Check the value is consistent with the saved one */
    5373                        struct avp_hdr * hdr;
    5474                        CHECK_FCT(  fd_msg_avp_hdr( dc, &hdr )  );
     
    6080                        }
    6181
     82                        /* save the cause */
    6283                        peer->p_hdr.info.runtime.pir_lastDC = hdr->avp_value->u32;
    63                        
    64                         switch (hdr->avp_value->u32) {
    65                                 case ACV_DC_REBOOTING:
    66                                 default:
    67                                         /* We use TcTimer to attempt reconnection */
    68                                         break;
    69                                 case ACV_DC_BUSY:
    70                                         /* No need to hammer the overloaded peer */
    71                                         delay *= 10;
    72                                         break;
    73                                 case ACV_DC_NOT_FRIEND:
    74                                         /* He does not want to speak to us... let's retry a lot later maybe */
    75                                         delay *= 200;
    76                                         break;
    77                         }
    7884                }
    7985                if (TRACE_BOOL(INFO)) {
    8086                        if (dc) {
    81                                 struct dict_object * dictobj = NULL;
     87                                struct dict_object * dictobj;
    8288                                struct dict_enumval_request er;
    8389                                memset(&er, 0, sizeof(er));
     90                               
     91                                /* prepare the request */
    8492                                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT )  );
    8593                                er.search.enum_value.u32 = peer->p_hdr.info.runtime.pir_lastDC;
     94                               
     95                                /* Search the enum value */
    8696                                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, 0 )  );
    8797                                if (dictobj) {
     
    100110                CHECK_FCT( fd_msg_rescode_set( *msg, "DIAMETER_SUCCESS", NULL, NULL, 1 ) );
    101111               
    102                 /* Move to CLOSING state to failover outgoing messages (and avoid failing the DPA...) */
     112                /* Move to CLOSING state to failover outgoing messages (and avoid failing over the DPA...) */
    103113                CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING) );
    104114               
     
    106116                CHECK_FCT( fd_out_send( msg, NULL, peer, FD_CNX_ORDERED) );
    107117               
    108                 /* Move to CLOSED state */
    109                 fd_psm_cleanup(peer, 0);
    110                
    111                 /* Reset the timer for next connection attempt -- we'll retry sooner or later depending on the disconnection cause */
    112                 fd_psm_next_timeout(peer, 1, delay);
    113                
     118                if (fd_cnx_isMultichan(peer->p_cnxctx)) {
     119                        /* There is a possibililty that messages are still in the pipe coming here, so let's grace for 1 second */
     120                        CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING_GRACE) );
     121                        fd_psm_next_timeout(peer, 0, 1);
     122                       
     123                } else {
     124                        /* Move to CLOSED state */
     125                        fd_psm_cleanup(peer, 0);
     126
     127                        /* Reset the timer for next connection attempt -- we'll retry sooner or later depending on the disconnection cause */
     128                        fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
     129                }
    114130        } else {
    115131                /* We received a DPA */
    116                 fd_cpu_flush_cache();
    117                 if (peer->p_hdr.info.runtime.pir_state != STATE_CLOSING) {
    118                         TRACE_DEBUG(INFO, "Ignoring DPA received in state %s", STATE_STR(peer->p_hdr.info.runtime.pir_state));
     132                int curstate = fd_peer_getstate(peer);
     133                if (curstate != STATE_CLOSING) {
     134                        TRACE_DEBUG(INFO, "Ignoring DPA received in state %s", STATE_STR(curstate));
    119135                }
    120136                       
    121137                /* In theory, we should control the Result-Code AVP. But since we will not go back to OPEN state here anyway, let's skip it */
     138               
     139                /* TODO("Control Result-Code in the DPA") */
    122140                CHECK_FCT_DO( fd_msg_free( *msg ), /* continue */ );
    123141                *msg = NULL;
    124142               
    125                 /* The calling function handles cleaning the PSM and terminating the peer since we return in CLOSING state */
     143                if (fd_cnx_isMultichan(peer->p_cnxctx)) {
     144                        CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING_GRACE) );
     145                        fd_psm_next_timeout(peer, 0, 1);
     146                        peer->p_flags.pf_localterm = 1;
     147                }
     148                /* otherwise, return in CLOSING state, the psm will handle it */
    126149        }
    127150       
     
    153176        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT )  );
    154177        er.search.enum_name = reason ?: "REBOOTING";
    155         CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, ENOENT )  );
     178        CHECK_FCT_DO( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, ENOENT ), { ASSERT(0); /* internal error: unknown reason */ }  );
    156179        CHECK_FCT( fd_dict_getval( dictobj, &er.search ) );
    157180       
  • libfdcore/p_dw.c

    r662 r706  
    3838/* This file contains code to handle Device Watchdog messages (DWR and DWA) */
    3939
    40 /* Check the value of Origin-State-Id is consistent in a DWR or  DWA -- we just log if it is not the case */
    41 static void check_state_id(struct msg * msg, struct fd_peer * peer)
     40/* Check the value of Origin-State-Id is consistent in a DWR or DWA -- we return an error otherwise */
     41static int check_state_id(struct msg * msg, struct fd_peer * peer)
    4242{
    4343        struct avp * osi;
     44       
    4445        /* Check if the request contains the Origin-State-Id */
    45         CHECK_FCT_DO( fd_msg_search_avp ( msg, fd_dict_avp_OSI, &osi ), return );
     46        CHECK_FCT( fd_msg_search_avp ( msg, fd_dict_avp_OSI, &osi ) );
    4647        if (osi) {
    4748                /* Check the value is consistent with the saved one */
    4849                struct avp_hdr * hdr;
    49                 CHECK_FCT_DO(  fd_msg_avp_hdr( osi, &hdr ), return  );
     50                CHECK_FCT(  fd_msg_avp_hdr( osi, &hdr )  );
    5051                if (hdr->avp_value == NULL) {
    5152                        /* This is a sanity check */
     
    5657
    5758                if (peer->p_hdr.info.runtime.pir_orstate != hdr->avp_value->u32) {
    58                         fd_log_debug("Received a new Origin-State-Id from peer %s! (%x / %x)\n",
     59                        TRACE_DEBUG(INFO, "Received a new Origin-State-Id from peer '%s'! (%x -> %x); resetting the connection.\n",
    5960                                peer->p_hdr.info.pi_diamid,
    60                                 hdr->avp_value->u32,
    61                                 peer->p_hdr.info.runtime.pir_orstate );
     61                                peer->p_hdr.info.runtime.pir_orstate,
     62                                hdr->avp_value->u32 );
     63                        return EINVAL;
    6264                }
    6365        }
     66        return 0;
    6467}
    6568
     
    9295       
    9396        /* Check the value of OSI for information */
    94         check_state_id(*msg, peer);
     97        CHECK_FCT( check_state_id(*msg, peer) );
    9598       
    9699        if (req) {
     
    102105               
    103106        } else {
    104                 /* Just discard the DWA */
     107                /* Discard the DWA */
    105108                CHECK_FCT_DO( fd_msg_free(*msg), /* continue */ );
    106109                *msg = NULL;
     
    123126       
    124127        /* If we are in REOPEN state, increment the counter */
    125         fd_cpu_flush_cache();
    126         if (peer->p_hdr.info.runtime.pir_state == STATE_REOPEN) {
     128        if (fd_peer_getstate(peer) == STATE_REOPEN) {
    127129                peer->p_flags.pf_reopen_cnt += 1;
    128130               
  • libfdcore/p_expiry.c

    r691 r706  
    5959               
    6060                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    61                         struct fd_peer * peer = (struct fd_peer *)li;
    62                        
    63                         fd_cpu_flush_cache();
    64                         if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE)
     61                        struct fd_peer * peer = (struct fd_peer *)li->o;
     62                       
     63                        if (fd_peer_getstate(peer) != STATE_ZOMBIE)
    6564                                continue;
    6665                       
     
    7877                /* Now delete peers that are in the purge list */
    7978                while (!FD_IS_LIST_EMPTY(&purge)) {
    80                         struct fd_peer * peer = (struct fd_peer *)(purge.next);
     79                        struct fd_peer * peer = (struct fd_peer *)(purge.next->o);
    8180                        fd_list_unlink(&peer->p_hdr.chain);
    8281                        TRACE_DEBUG(INFO, "Garbage Collect: delete zombie peer '%s'", peer->p_hdr.info.pi_diamid);
     
    105104                struct fd_peer * first;
    106105               
    107                 /* Check if there are expiring sessions available */
     106                /* Check if there are expiring peers available */
    108107                if (FD_IS_LIST_EMPTY(&exp_list)) {
    109108                        /* Just wait for a change or cancelation */
     
    183182               
    184183                /* update the p_exp_timer value */
    185                 CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &peer->p_exp_timer)  );
     184                CHECK_SYS_DO(  clock_gettime(CLOCK_REALTIME, &peer->p_exp_timer), { ASSERT(0); }  );
    186185                peer->p_exp_timer.tv_sec += peer->p_hdr.info.config.pic_lft;
    187186               
  • libfdcore/p_out.c

    r691 r706  
    109109        {
    110110                char buf[48];
    111                 sprintf(buf, "OUT/%.*s", (int)sizeof(buf) - 5, peer->p_hdr.info.pi_diamid);
     111                snprintf(buf, sizeof(buf), "OUT/%s", peer->p_hdr.info.pi_diamid);
    112112                fd_log_threadname ( buf );
    113113        }
     
    149149        CHECK_PARAMS( msg && *msg && (cnx || (peer && peer->p_cnxctx)));
    150150       
    151         fd_cpu_flush_cache();
    152         if (peer && (peer->p_hdr.info.runtime.pir_state == STATE_OPEN)) {
     151        if (fd_peer_getstate(peer) == STATE_OPEN) {
    153152                /* Normal case: just queue for the out thread to pick it up */
    154153                CHECK_FCT( fd_fifo_post(peer->p_tosend, msg) );
  • libfdcore/p_psm.c

    r691 r706  
    3636#include "fdcore-internal.h"
    3737
     38/*
     39This file implement a Peer State Machine which is a mix of:
     40 - the state machine described in rfc3588bis
     41 - the state machine described in rfc3539#section-3.4
     42 - the following observations.
     43 
     44The delivery of Diameter messages must not always be unordered: order is important at
     45begining and end of a connection lifetime. It means we need agility to
     46switch between "ordering enforced" and "ordering not enforced to counter
     47HotLB" modes of operation.
     48
     49The connection state machine represented in RFC3588 (and rfc3588bis) is
     50incomplete, because it lacks the SUSPECT state and the 3 DWR/DWA
     51exchanges (section 5.1) when the peer recovers from this state.
     52Personnally I don't see the rationale for exchanging 3 messages (why 3?)
     53but, if we require at least 1 DWR/DWA exchange to be always performed
     54after the CER/CEA exchange (and initiated by the peer that sent the
     55CEA), we have a simple way to deal with our ordering problem, as resumed
     56bellow. Peers are: [i]nitiator, [r]esponder.
     57 (1) [i] SCTP connection attempt.
     58 (2) [r] accept the connection.
     59 (3) [i,r] (if secure port) DTLS handshake, close on failure.
     60 (4) [i] Send CER
     61 (5) [r] Receive CER, send CEA using stream 0, flag "unordered" cleared.
     62       [r] Immediately send a DWR after the CEA, also using stream 0,
     63flag "unordered" cleared.
     64       [r] Move to STATE_OPEN_NEW state -- equivalent to OPEN except
     65that all messages are sent ordered at the moment.
     66 (6) [i] receive CEA, move to OPEN state. All messages can be sent
     67unordered in OPEN state.
     68       [i] As per normal operation, reply with DWA to the DWR.
     69 (7) [r] Upon reception of the DWA, move to OPEN state, messages can be
     70sent unordered from this point.
     71
     72Note about (5) and (6): if the Diameter Identity received in CER or CEA
     73does not match the credentials from the certificate presented during
     74DTLS handshake, we may need to specify a path of clean disconnection
     75(not blocking the remote peer waiting for something).
     76
     77This proposed mechanism removes the problem of application messages
     78received before the CEA by the initiator. Note that if the "old" inband
     79TLS handshake is used, this handshake plays the same synchronization
     80role than the new DWR/DWA, which becomes useless.
     81
     82
     83The other time where ordering is important is by the end of connection
     84lifetime, when one peer is shutting down the link for some reason
     85(reboot, overload, no activity, etc...). In case of unordered delivery,
     86we may have:
     87- peer A sends an application message followed by a DPR. Peer B receives
     88the DPR first and tears down the connection. Application message is lost.
     89- Peer B sends an application message, then receives a DPR and answers a
     90DPA. Peer A receives the DPA before the application message. The
     91application message is lost.
     92
     93This situation is actually quite possible because DPR/DPA messages are
     94very short, while application messages can be quite large. Therefore,
     95they require much more time to deliver.
     96
     97I really cannot see a way to counter this effect by using the ordering
     98of the messages, except by applying a timer (state STATE_CLOSING_GRACE).
     99
     100However, this problem must be balanced with the fact that the message
     101that is lost will be in many cases sent again as the failover mechanism
     102specifies.
     103*/
     104
    38105/* The actual declaration of peer_state_str */
    39106DECLARE_STATE_STR();
     
    101168                return 0;
    102169        }
     170       
    103171        /* Insert in the active peers list */
    104172        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_activ_peers_rw) );
    105173        for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) {
    106174                struct fd_peer * next_p = (struct fd_peer *)li->o;
    107                 int cmp = strcmp(peer->p_hdr.info.pi_diamid, next_p->p_hdr.info.pi_diamid);
     175                int cmp = fd_os_cmp(peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen,
     176                                        next_p->p_hdr.info.pi_diamid, next_p->p_hdr.info.pi_diamidlen);
    108177                if (cmp < 0)
    109178                        break;
     
    115184        if (peer->p_cb) {
    116185                TRACE_DEBUG(FULL, "Calling add callback for peer %s", peer->p_hdr.info.pi_diamid);
    117                 (*peer->p_cb)(&peer->p_hdr.info, peer->p_cb_data);
     186                (*peer->p_cb)(&peer->p_hdr.info, peer->p_cb_data); /* TODO: do this in a separate detached thread? */
    118187                peer->p_cb = NULL;
    119188                peer->p_cb_data = NULL;
     
    178247}
    179248
     249/* Read state */
     250int fd_peer_get_state(struct peer_hdr *peer)
     251{
     252        int ret;
     253       
     254        struct fd_peer * p = (struct fd_peer *)peer;
     255       
     256        if (!CHECK_PEER(p))
     257                return -1;
     258       
     259        CHECK_POSIX_DO( pthread_mutex_lock(&p->p_state_mtx), return -1 );
     260        ret = p->p_state;
     261        CHECK_POSIX_DO( pthread_mutex_unlock(&p->p_state_mtx), return -1 );
     262       
     263        return ret;
     264}
     265
    180266
    181267/* Change state */
     
    186272        TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state));
    187273        CHECK_PARAMS( CHECK_PEER(peer) );
    188         fd_cpu_flush_cache();
    189         old = peer->p_hdr.info.runtime.pir_state;
     274       
     275        old = fd_peer_getstate(peer);
    190276        if (old == new_state)
    191277                return 0;
     
    196282                        peer->p_hdr.info.pi_diamid);
    197283       
    198         peer->p_hdr.info.runtime.pir_state = new_state;
    199         fd_cpu_flush_cache();
     284       
     285        CHECK_POSIX( pthread_mutex_lock(&peer->p_state_mtx) );
     286        peer->p_state = new_state;
     287        CHECK_POSIX( pthread_mutex_unlock(&peer->p_state_mtx) );
    200288       
    201289        if (old == STATE_OPEN) {
     
    255343{
    256344        /* Move to CLOSED state: failover messages, stop OUT thread, unlink peer from active list */
    257         fd_cpu_flush_cache();
    258         if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
     345        if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
    259346                CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ );
    260347        }
     
    285372        struct fd_peer * peer = (struct fd_peer *)arg;
    286373        CHECK_PARAMS_DO( CHECK_PEER(peer), return );
    287         peer->p_hdr.info.runtime.pir_state = STATE_ZOMBIE;
    288         fd_cpu_flush_cache();
     374        CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), );
     375        peer->p_state = STATE_ZOMBIE;
     376        CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), );
    289377        return;
    290378}
     
    298386        size_t ev_sz;
    299387        void * ev_data;
     388        int cur_state;
    300389       
    301390        CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) );
     
    306395        {
    307396                char buf[48];
    308                 sprintf(buf, "PSM/%.*s", (int)sizeof(buf) - 5, peer->p_hdr.info.pi_diamid);
     397                snprintf(buf, sizeof(buf), "PSM/%s", peer->p_hdr.info.pi_diamid);
    309398                fd_log_threadname ( buf );
    310399        }
    311400       
    312401        /* The state machine starts in CLOSED state */
    313         peer->p_hdr.info.runtime.pir_state = STATE_CLOSED;
     402        CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), goto psm_end );
     403        peer->p_state = STATE_CLOSED;
     404        CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), goto psm_end );
    314405
    315406        /* Wait that the PSM are authorized to start in the daemon */
     
    326417        /* Get next event */
    327418        TRACE_DEBUG(FULL, "'%s' in state '%s' waiting for next event.",
    328                         peer->p_hdr.info.pi_diamid, STATE_STR(peer->p_hdr.info.runtime.pir_state));
     419                        peer->p_hdr.info.pi_diamid, STATE_STR(fd_peer_getstate(peer)));
    329420        CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );
     421       
     422        cur_state = fd_peer_getstate(peer);
     423        if (cur_state == -1)
     424                goto psm_end;
     425       
    330426        TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%zd)\t'%s'",
    331                         STATE_STR(peer->p_hdr.info.runtime.pir_state),
     427                        STATE_STR(cur_state),
    332428                        fd_pev_str(event), ev_data, ev_sz,
    333429                        peer->p_hdr.info.pi_diamid);
     
    336432
    337433        /* The following states are impossible */
    338         ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_NEW );
    339         ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE );
    340         ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_OPEN_HANDSHAKE ); /* because it should exist only between two loops */
     434        ASSERT( cur_state != STATE_NEW );
     435        ASSERT( cur_state != STATE_ZOMBIE );
     436        ASSERT( cur_state != STATE_OPEN_HANDSHAKE ); /* because it should exist only between two loops */
    341437
    342438        /* Purge invalid events */
    343439        if (!CHECK_PEVENT(event)) {
    344440                TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event);
     441                ASSERT(0); /* we should investigate this situation */
    345442                goto psm_loop;
    346443        }
     
    354451        /* Requests to terminate the peer object */
    355452        if (event == FDEVP_TERMINATE) {
    356                 switch (peer->p_hdr.info.runtime.pir_state) {
     453                switch (cur_state) {
    357454                        case STATE_OPEN:
     455                        case STATE_OPEN_NEW:
    358456                        case STATE_REOPEN:
    359                                 /* We cannot just close the conenction, we have to send a DPR first */
     457                                /* We cannot just close the connection, we have to send a DPR first */
    360458                                CHECK_FCT_DO( fd_p_dp_initiate(peer, ev_data), goto psm_end );
    361459                                goto psm_loop;
     
    363461                        /*     
    364462                        case STATE_CLOSING:
     463                        case STATE_CLOSING_GRACE:
    365464                        case STATE_WAITCNXACK:
    366465                        case STATE_WAITCNXACK_ELEC:
     
    380479                struct msg_hdr * hdr;
    381480               
    382                 /* If the current state does not allow receiving messages, just drop it */
    383                 if (peer->p_hdr.info.runtime.pir_state == STATE_CLOSED) {
    384                         TRACE_DEBUG(FULL, "Purging message in queue while in CLOSED state (%zdb)", ev_sz);
    385                         free(ev_data);
    386                         goto psm_loop;
    387                 }
    388                
    389481                /* Parse the received buffer */
    390482                CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg),
     
    396488                        } );
    397489               
     490                /* If the current state does not allow receiving messages, just drop it */
     491                if (cur_state == STATE_CLOSED) {
     492                        /* In such case, just discard the message */
     493                        fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Purged from peer '%s''s queue (CLOSED state).", peer->p_hdr.info.pi_diamid );
     494                        fd_msg_free(msg);
     495                        goto psm_loop;
     496                }
     497               
    398498                /* Log incoming message */
    399                 fd_msg_log( FD_MSG_LOG_RECEIVED, msg, "Received %zdb from '%s'", ev_sz, peer->p_hdr.info.pi_diamid );
     499                fd_msg_log( FD_MSG_LOG_RECEIVED, msg, "Received %zdb from '%s' (%s)", ev_sz, peer->p_hdr.info.pi_diamid, STATE_STR(cur_state) );
    400500       
    401501                /* Extract the header */
     
    417517                }
    418518               
     519                if (cur_state == STATE_OPEN_NEW) {
     520                        /* OK, we have received something, so the connection is supposedly now in OPEN state at the remote site */
     521                        fd_psm_change_state(peer, STATE_OPEN );
     522                }
     523               
    419524                /* Now handle non-link-local messages */
    420525                if (fd_msg_is_routable(msg)) {
    421                         switch (peer->p_hdr.info.runtime.pir_state) {
     526                        switch (cur_state) {
    422527                                /* To maximize compatibility -- should not be a security issue here */
    423528                                case STATE_REOPEN:
    424529                                case STATE_SUSPECT:
    425530                                case STATE_CLOSING:
     531                                case STATE_CLOSING_GRACE:
    426532                                        TRACE_DEBUG(FULL, "Accepted a message while not in OPEN state... ");
    427533                                /* The standard situation : */
     534                                case STATE_OPEN_NEW:
    428535                                case STATE_OPEN:
    429536                                        /* We received a valid routable message, update the expiry timer */
     
    431538
    432539                                        /* Set the message source and add the Route-Record */
    433                                         CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, 1, fd_g_config->cnf_dict ), goto psm_end);
     540                                        CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen, 1, fd_g_config->cnf_dict ), goto psm_end);
    434541
    435542                                        /* Requeue to the global incoming queue */
     
    437544
    438545                                        /* Update the peer timer (only in OPEN state) */
    439                                         if ((peer->p_hdr.info.runtime.pir_state == STATE_OPEN) && (!peer->p_flags.pf_dw_pending)) {
     546                                        if ((cur_state == STATE_OPEN) && (!peer->p_flags.pf_dw_pending)) {
    440547                                                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
    441548                                        }
     
    449556                                default:
    450557                                        /* In such case, just discard the message */
    451                                         fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received from peer '%s' while connection was not in OPEN state.", peer->p_hdr.info.pi_diamid );
     558                                        fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received from peer '%s' while connection was not in state %s.", peer->p_hdr.info.pi_diamid, STATE_STR(cur_state) );
    452559                                        fd_msg_free(msg);
    453560                        }
     
    485592                        case CC_DISCONNECT_PEER:
    486593                                CHECK_FCT_DO( fd_p_dp_handle(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), goto psm_reset );
    487                                 if (peer->p_hdr.info.runtime.pir_state == STATE_CLOSING)
     594                                if (fd_peer_getstate(peer) == STATE_CLOSING)
    488595                                        goto psm_end;
     596
    489597                                break;
    490598                       
     
    494602                       
    495603                        default:
    496                                 /* Unknown / unexpected / invalid message */
     604                                /* Unknown / unexpected / invalid message -- but validated by our dictionary */
    497605                                TRACE_DEBUG(INFO, "Invalid non-routable command received: %u.", hdr->msg_code);
    498606                                if (hdr->msg_flags & CMD_FLAG_REQUEST) {
     
    502610
    503611                                                /* Set the error code */
    504                                                 CHECK_FCT_DO( fd_msg_rescode_set(msg, "DIAMETER_INVALID_HDR_BITS", NULL, NULL, 1 ), break );
     612                                                CHECK_FCT_DO( fd_msg_rescode_set(msg, "DIAMETER_COMMAND_UNSUPPORTED", "Or maybe the P-bit or application Id are erroneous.", NULL, 1 ), break );
    505613
    506614                                                /* Send the answer */
     
    509617                                } else {
    510618                                        /* We did ASK for it ??? */
    511                                         fd_log_debug("Invalid PXY flag in answer header ?\n");
     619                                        TRACE_DEBUG(INFO, "Received answer with erroneous 'is_routable' result...");
    512620                                }
    513621                               
     
    531639        /* The connection object is broken */
    532640        if (event == FDEVP_CNX_ERROR) {
    533                 switch (peer->p_hdr.info.runtime.pir_state) {
     641                switch (cur_state) {
    534642                        case STATE_WAITCNXACK_ELEC:
    535643                                /* Abort the initiating side */
     
    541649                        case STATE_WAITCEA:
    542650                        case STATE_OPEN:
     651                        case STATE_OPEN_NEW:
    543652                        case STATE_REOPEN:
    544653                        case STATE_WAITCNXACK:
     
    558667                                goto psm_end;
    559668                               
     669                        case STATE_CLOSING_GRACE:
     670                                if (peer->p_flags.pf_localterm) /* initiated here */
     671                                        goto psm_end;
     672                               
     673                                fd_psm_cleanup(peer, 0);
     674                               
     675                                /* Reset the timer for next connection attempt */
     676                                fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
     677                                goto psm_loop;
    560678                }
    561679                goto psm_loop;
     
    616734                peer->p_ini_thr = (pthread_t)NULL;
    617735               
    618                 switch (peer->p_hdr.info.runtime.pir_state) {
     736                switch (cur_state) {
    619737                        case STATE_WAITCNXACK_ELEC:
    620738                        case STATE_WAITCNXACK:
     
    624742                        default:
    625743                                /* Just abort the attempt and continue */
    626                                 TRACE_DEBUG(FULL, "Connection attempt successful but current state is %s, closing...", STATE_STR(peer->p_hdr.info.runtime.pir_state));
     744                                TRACE_DEBUG(FULL, "Connection attempt successful but current state is %s, closing... (too slow?)", STATE_STR(cur_state));
    627745                                fd_cnx_destroy(cnx);
    628746                }
     
    638756                peer->p_ini_thr = (pthread_t)NULL;
    639757               
    640                 switch (peer->p_hdr.info.runtime.pir_state) {
     758                switch (cur_state) {
    641759                        case STATE_WAITCNXACK_ELEC:
    642760                                /* Abort the initiating side */
     
    653771                        default:
    654772                                /* Just ignore */
    655                                 TRACE_DEBUG(FULL, "Connection attempt failed but current state is %s, ignoring...", STATE_STR(peer->p_hdr.info.runtime.pir_state));
     773                                TRACE_DEBUG(FULL, "Connection attempt failed but current state is %s, ignoring...", STATE_STR(cur_state));
    656774                }
    657775               
     
    661779        /* The timeout for the current state has been reached */
    662780        if (event == FDEVP_PSM_TIMEOUT) {
    663                 switch (peer->p_hdr.info.runtime.pir_state) {
     781                switch (cur_state) {
    664782                        case STATE_OPEN:
    665783                        case STATE_REOPEN:
     784                        case STATE_OPEN_NEW:
    666785                                CHECK_FCT_DO( fd_p_dw_timeout(peer), goto psm_end );
    667786                                goto psm_loop;
     
    676795                                /* Mark the connection problem */
    677796                                peer->p_flags.pf_cnx_pb = 1;
    678                                
    679797                        case STATE_CLOSING:
    680798                        case STATE_WAITCNXACK:
     
    683801                                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
    684802                                goto psm_reset;
     803                               
     804                        case STATE_CLOSING_GRACE:
     805                                /* The grace period is completed, now close */
     806                                if (peer->p_flags.pf_localterm)
     807                                        goto psm_end;
     808                               
     809                                fd_psm_cleanup(peer, 0);
     810                                /* Reset the timer for next connection attempt */
     811                                fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
     812                                goto psm_loop;
    685813                               
    686814                        case STATE_WAITCNXACK_ELEC:
     
    697825       
    698826        /* Default action : the handling has not yet been implemented. [for debug only] */
    699         TRACE_DEBUG(INFO, "Missing handler in PSM for '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.runtime.pir_state), fd_pev_str(event));
     827        TRACE_DEBUG(INFO, "Missing handler in PSM for '%s'\t<-- '%s'", STATE_STR(cur_state), fd_pev_str(event));
    700828psm_reset:
    701829        if (peer->p_flags.pf_delete)
     
    707835        fd_psm_cleanup(peer, 1);
    708836        TRACE_DEBUG(INFO, "'%s'\t-> STATE_ZOMBIE (terminated)\t'%s'",
    709                         STATE_STR(peer->p_hdr.info.runtime.pir_state),
     837                        STATE_STR(fd_peer_getstate(peer)),
    710838                        peer->p_hdr.info.pi_diamid);
    711839        pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
    712         fd_cpu_flush_cache();
    713840        peer->p_psm = (pthread_t)NULL;
    714841        pthread_detach(pthread_self());
     
    726853       
    727854        /* Check the peer and state are OK */
    728         CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_hdr.info.runtime.pir_state == STATE_NEW) );
     855        CHECK_PARAMS( fd_peer_getstate(peer) == STATE_NEW );
    729856       
    730857        /* Create the FIFO for events */
     
    744871        CHECK_PARAMS( CHECK_PEER(peer) );
    745872       
    746         fd_cpu_flush_cache();
    747         if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
     873        if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
    748874                CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, reason) );
    749875        } else {
  • libfdcore/p_sr.c

    r691 r706  
    3636#include "fdcore-internal.h"
    3737
    38 #ifndef SR_DEBUG_LVL
    39 #define SR_DEBUG_LVL ANNOYING
    40 #endif /* SR_DEBUG_LVL */
    41 
    4238/* Structure to store a sent request */
    4339struct sentreq {
     
    6965        struct fd_list * li;
    7066        struct timespec now;
    71         if (!TRACE_BOOL(SR_DEBUG_LVL))
     67       
     68        if (!TRACE_BOOL(ANNOYING))
    7269                return;
     70       
     71        fd_log_debug("%sSentReq list @%p:\n", text, srlist);
     72       
    7373        CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), );
    74         fd_log_debug("%sSentReq list @%p:\n", text, srlist);
     74       
    7575        for (li = srlist->next; li != srlist; li = li->next) {
    7676                struct sentreq * sr = (struct sentreq *)li;
    7777                uint32_t * nexthbh = li->o;
    78                 fd_log_debug(" - Next req (%x): [since %ld.%06ld sec]\n", *nexthbh,
     78               
     79                fd_log_debug(" - Next req (hbh:%x): [since %ld.%06ld sec]\n", *nexthbh,
    7980                        (now.tv_nsec >= sr->added_on.tv_nsec) ? (now.tv_sec - sr->added_on.tv_sec) : (now.tv_sec - sr->added_on.tv_sec - 1),
    8081                        (now.tv_nsec >= sr->added_on.tv_nsec) ? (now.tv_nsec - sr->added_on.tv_nsec) / 1000 : (now.tv_nsec - sr->added_on.tv_nsec + 1000000000) / 1000);
    81                 fd_msg_dump_one(SR_DEBUG_LVL + 1, sr->req);
     82               
     83                fd_msg_dump_one(ANNOYING + 1, sr->req);
    8284        }
    8385}
     
    117119}
    118120
    119 /* thread that handles messages expiring. The thread is started / cancelled only when needed */
     121/* thread that handles messages expiring. The thread is started only when needed */
    120122static void * sr_expiry_th(void * arg) {
    121123        struct sr_list * srlist = arg;
     
    129131        {
    130132                char buf[48];
    131                 sprintf(buf, "ReqExp/%.*s", (int)sizeof(buf) - 8, ((struct fd_peer *)(srlist->exp.o))->p_hdr.info.pi_diamid);
     133                snprintf(buf, sizeof(buf), "ReqExp/%s", ((struct fd_peer *)(srlist->exp.o))->p_hdr.info.pi_diamid);
    132134                fd_log_threadname ( buf );
    133135        }
     
    313315                } else {
    314316                        /* Just free the request. */
    315                         fd_msg_log( FD_MSG_LOG_DROPPED, sr->req, "Local message discarded during failover" );
     317                        fd_msg_log( FD_MSG_LOG_DROPPED, sr->req, "Sent & unanswered local message discarded during failover." );
    316318                        CHECK_FCT_DO(fd_msg_free(sr->req), /* Ignore */);
    317319                }
  • libfdcore/peers.c

    r691 r706  
    7373       
    7474        p->p_eyec = EYEC_PEER;
     75        CHECK_POSIX( pthread_mutex_init(&p->p_state_mtx, NULL) );
     76       
    7577        fd_list_init(&p->p_actives, p);
    7678        fd_list_init(&p->p_expiry, p);
     
    9496        struct fd_list * li;
    9597        int ret = 0;
     98       
    9699        TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data);
    97100        CHECK_PARAMS(info && info->pi_diamid);
    98101       
     102        if (info->config.pic_realm) {
     103                if (!fd_os_is_valid_DiameterIdentity((os0_t)info->config.pic_realm, strlen(info->config.pic_realm))) {
     104                        TRACE_DEBUG(INFO, "'%s' is not a valid DiameterIdentity.", info->config.pic_realm);
     105                        return EINVAL;
     106                }
     107        }
     108       
    99109        /* Create a structure to contain the new peer information */
    100110        CHECK_FCT( fd_peer_alloc(&p) );
    101111       
    102112        /* Copy the informations from the parameters received */
    103         CHECK_MALLOC( p->p_hdr.info.pi_diamid = strdup(info->pi_diamid) );
     113        p->p_hdr.info.pi_diamid = info->pi_diamid;
     114        CHECK_FCT( fd_os_validate_DiameterIdentity(&p->p_hdr.info.pi_diamid, &p->p_hdr.info.pi_diamidlen, 1) );
    104115       
    105116        memcpy( &p->p_hdr.info.config, &info->config, sizeof(p->p_hdr.info.config) );
     117       
    106118        /* Duplicate the strings if provided */
    107119        if (info->config.pic_realm) {
     
    109121        }
    110122        if (info->config.pic_priority) {
    111                 CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_priority) );
     123                CHECK_MALLOC( p->p_hdr.info.config.pic_priority = strdup(info->config.pic_priority) );
    112124        }
    113125       
     
    124136                CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) );
    125137        } else {
    126                 CHECK_MALLOC( p->p_dbgorig = strdup("unknown") );
     138                CHECK_MALLOC( p->p_dbgorig = strdup("unspecified") );
    127139        }
    128140        p->p_cb = cb;
     
    134146        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    135147                struct fd_peer * next = (struct fd_peer *)li;
    136                 int cmp = strcasecmp( p->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamid );
     148                int cmp = fd_os_almostcasecmp( p->p_hdr.info.pi_diamid, p->p_hdr.info.pi_diamidlen,
     149                                                next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
    137150                if (cmp > 0)
    138151                        continue;
     
    162175
    163176/* Search for a peer */
    164 int fd_peer_getbyid( char * diamid, struct peer_hdr ** peer )
     177int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer )
    165178{
    166179        struct fd_list * li;
    167        
    168         TRACE_ENTRY("%p %p", diamid, peer);
    169         CHECK_PARAMS( diamid && peer );
     180        TRACE_ENTRY("%p %zd %d %p", diamid, diamidlen, igncase, peer);
     181        CHECK_PARAMS( diamid && diamidlen && peer );
    170182       
    171183        *peer = NULL;
     
    175187        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    176188                struct fd_peer * next = (struct fd_peer *)li;
    177                 int cmp = strcasecmp( diamid, next->p_hdr.info.pi_diamid );
     189                int cmp;
     190                if (igncase)
     191                        cmp = fd_os_almostcasecmp( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
     192                else
     193                        cmp = fd_os_cmp( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
    178194                if (cmp > 0)
    179195                        continue;
     
    255271       
    256272        CHECK_FCT_DO( fd_fifo_del(&p->p_tosend), /* continue */ );
     273        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_state_mtx), /* continue */);
    257274        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_sr.mtx), /* continue */);
    258275        CHECK_POSIX_DO( pthread_cond_destroy(&p->p_sr.cnd), /* continue */);
     
    283300        CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
    284301        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    285                 struct fd_peer * peer = (struct fd_peer *)li;
    286                
    287                 fd_cpu_flush_cache();
    288                 if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
     302                struct fd_peer * peer = (struct fd_peer *)li->o;
     303               
     304                if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
    289305                        CHECK_FCT_DO( fd_psm_terminate(peer, "REBOOTING"), /* continue */ );
    290306                } else {
     
    307323               
    308324                /* Allow the PSM(s) to execute */
    309                 sched_yield();
     325                usleep(100000);
    310326               
    311327                /* Remove zombie peers */
    312328                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
    313329                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    314                         struct fd_peer * peer = (struct fd_peer *)li;
    315                         fd_cpu_flush_cache();
    316                         if (peer->p_hdr.info.runtime.pir_state == STATE_ZOMBIE) {
     330                        struct fd_peer * peer = (struct fd_peer *)li->o;
     331                        if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
    317332                                li = li->prev; /* to avoid breaking the loop */
    318333                                fd_list_unlink(&peer->p_hdr.chain);
     
    329344                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
    330345                while (!FD_IS_LIST_EMPTY(&fd_g_peers)) {
    331                         struct fd_peer * peer = (struct fd_peer *)(fd_g_peers.next);
     346                        struct fd_peer * peer = (struct fd_peer *)(fd_g_peers.next->o);
    332347                        fd_psm_abord(peer);
    333348                        fd_list_unlink(&peer->p_hdr.chain);
     
    339354        /* Free memory objects of all peers */
    340355        while (!FD_IS_LIST_EMPTY(&purge)) {
    341                 struct fd_peer * peer = (struct fd_peer *)(purge.next);
     356                struct fd_peer * peer = (struct fd_peer *)(purge.next->o);
    342357                fd_list_unlink(&peer->p_hdr.chain);
    343358                fd_peer_free(&peer);
     
    364379        }
    365380
    366         fd_log_debug(">  %s\t%s", STATE_STR(peer->p_hdr.info.runtime.pir_state), peer->p_hdr.info.pi_diamid);
     381        fd_log_debug(">  %s\t%s", STATE_STR(fd_peer_getstate(peer)), peer->p_hdr.info.pi_diamid);
    367382        if (details > INFO) {
    368                 fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "(unknown)");
     383                fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "<unknown>");
    369384                if (peer->p_hdr.info.runtime.pir_prodname)
    370385                        fd_log_debug("\t['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev);
     
    398413       
    399414        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    400                 struct fd_peer * np = (struct fd_peer *)li;
     415                struct fd_peer * np = (struct fd_peer *)li->o;
    401416                fd_peer_dump(np, details);
    402417        }
     
    404419        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
    405420}
     421
     422static struct dict_object *avp_oh_model = NULL;
     423static pthread_mutex_t cache_avp_lock = PTHREAD_MUTEX_INITIALIZER;
    406424
    407425/* Handle an incoming CER request on a new connection */
     
    409427{
    410428        struct msg * msg;
    411         struct dict_object *avp_oh_model;
    412         avp_code_t code = AC_ORIGIN_HOST;
    413429        struct avp *avp_oh;
    414430        struct avp_hdr * avp_hdr;
     
    424440        msg = *cer;
    425441       
     442        /* If needed, resolve the dictioanry model for Origin-Host */
     443        CHECK_POSIX( pthread_mutex_lock(&cache_avp_lock) );
     444        if (!avp_oh_model) {
     445                avp_code_t code = AC_ORIGIN_HOST;
     446                int ret;
     447                CHECK_FCT_DO( ret = fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT),
     448                        { CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) ); return ret; } );
     449        }
     450        CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) );
     451       
    426452        /* Find the Diameter Identity of the remote peer in the message */
    427         CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT) );
    428453        CHECK_FCT( fd_msg_search_avp ( msg, avp_oh_model, &avp_oh ) );
     454        ASSERT(avp_oh); /* otherwise it should not have passed rules validation, right? */
    429455        CHECK_FCT( fd_msg_avp_hdr ( avp_oh, &avp_hdr ) );
     456       
     457        /* First, check if the Origin-Host value  */
     458        if (!fd_os_is_valid_DiameterIdentity(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len)) {
     459                TRACE_DEBUG(INFO, "Received new CER with invalid \\0 in its Origin-Host");
     460                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ) );
     461                CHECK_FCT( fd_msg_rescode_set(*cer, "ER_DIAMETER_INVALID_AVP_VALUE",
     462                                                        "Your Origin-Host contains invalid characters.", avp_oh, 1 ) );
     463                CHECK_FCT( fd_out_send(cer, *cnx, NULL, FD_CNX_ORDERED) );
     464                return EINVAL;
     465        }
    430466       
    431467        /* Search if we already have this peer id in our list. We take directly the write lock so that we don't need to upgrade if it is a new peer.
     
    435471       
    436472        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    437                 peer = (struct fd_peer *)li;
    438                 /* It is probably unwise to use strcasecmp on UTF8 data... To be improved! */
    439                 int cmp = strncasecmp( (char *)avp_hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid, avp_hdr->avp_value->os.len );
     473                int cmp;
     474                peer = (struct fd_peer *)li->o;
     475                cmp = fd_os_almostcasecmp( avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen );
    440476                if (cmp > 0)
    441477                        continue;
     
    451487               
    452488                /* Set the peer Diameter Id and the responder flag parameters */
    453                 CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = malloc(avp_hdr->avp_value->os.len + 1), { ret = ENOMEM; goto out; } );
    454                 memcpy(peer->p_hdr.info.pi_diamid, avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len);
    455                 peer->p_hdr.info.pi_diamid[avp_hdr->avp_value->os.len] = '\0';
     489                CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = os0dup(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len),
     490                        { ret = ENOMEM; goto out; } );
     491                peer->p_hdr.info.pi_diamidlen = avp_hdr->avp_value->os.len;
    456492                CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } );
    457493                peer->p_flags.pf_responder = 1;
     
    470506        } else {
    471507                /* Check if the peer is in zombie state */
    472                 fd_cpu_flush_cache();
    473                 if (peer->p_hdr.info.runtime.pir_state == STATE_ZOMBIE) {
     508                if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
    474509                        /* Re-activate the peer */
    475510                        if (peer->p_hdr.info.config.pic_flags.exp)
    476511                                peer->p_flags.pf_responder = 1;
    477                         peer->p_hdr.info.runtime.pir_state = STATE_NEW;
     512                        CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), );
     513                        peer->p_state = STATE_NEW;
     514                        CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), );
     515                        peer->p_flags.pf_localterm = 0;
    478516                        CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
    479517                }
    480518        }
    481                
     519       
    482520        /* Send the new connection event to the PSM */
    483521        CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } );
  • libfdcore/routing_dispatch.c

    r691 r706  
    208208                struct fd_peer * peer;
    209209                struct fd_app *found;
    210                 CHECK_FCT( fd_peer_getbyid( c->diamid, (void *)&peer ) );
    211                 if (peer && (peer->p_hdr.info.runtime.pir_relay == 0)) {
     210                CHECK_FCT( fd_peer_getbyid( c->diamid, c->diamidlen, 0, (void *)&peer ) );
     211                if (peer && !peer->p_hdr.info.runtime.pir_relay) {
    212212                        /* Check if the remote peer advertised the message's appli */
    213213                        CHECK_FCT( fd_app_check(&peer->p_hdr.info.runtime.pir_apps, hdr->msg_appl, &found) );
     
    264264        for (li = candidates->next; li != candidates; li = li->next) {
    265265                struct rtd_candidate *c = (struct rtd_candidate *) li;
     266               
     267            #if 0 /* this is actually useless since the sending process will also ensure that the peer is still available */
    266268                struct fd_peer * peer;
    267                 CHECK_FCT( fd_peer_getbyid( c->diamid, (void *)&peer ) );
    268                 if (peer) {
    269                         if (dh
    270                                 && (dh->os.len == strlen(peer->p_hdr.info.pi_diamid))
    271                                 /* Here again we use strncasecmp on UTF8 data... This should probably be changed. */
    272                                 && (strncasecmp(peer->p_hdr.info.pi_diamid, (char *)dh->os.data, dh->os.len) == 0)) {
    273                                 /* The candidate is the Destination-Host */
    274                                 c->score += FD_SCORE_FINALDEST;
    275                         } else {
    276                                 if (dr  && peer->p_hdr.info.runtime.pir_realm
    277                                         && (dr->os.len == strlen(peer->p_hdr.info.runtime.pir_realm))
    278                                         /* Yet another case where we use strncasecmp on UTF8 data... Hmmm :-( */
    279                                         && (strncasecmp(peer->p_hdr.info.runtime.pir_realm, (char *)dr->os.data, dr->os.len) == 0)) {
    280                                         /* The candidate's realm matchs the Destination-Realm */
    281                                         c->score += FD_SCORE_REALM;
    282                                 }
     269                /* Since the candidates list comes from the peers list, we do not have any issue with upper/lower case to find the peer object */
     270                CHECK_FCT( fd_peer_getbyid( c->diamid, c->diamidlen, 0, (void *)&peer ) );
     271                if (!peer)
     272                        continue; /* it has been deleted since the candidate list was generated; avoid sending to this one in that case. */
     273            #endif /* 0 */
     274               
     275                /* In the AVPs, the value comes from the network, so let's be case permissive */
     276                if (dh && !fd_os_almostcasecmp(dh->os.data, dh->os.len, c->diamid, c->diamidlen) ) {
     277                        /* The candidate is the Destination-Host */
     278                        c->score += FD_SCORE_FINALDEST;
     279                } else {
     280                        if (dr && !fd_os_almostcasecmp(dr->os.data, dr->os.len, c->realm, c->realmlen) ) {
     281                                /* The candidate's realm matchs the Destination-Realm */
     282                                c->score += FD_SCORE_REALM;
    283283                        }
    284284                }
     
    298298       
    299299        TRACE_ENTRY("%p %p %p", un, excl_idx, at_idx);
    300         CHECK_PARAMS_DO( un && excl_idx, return );
     300        CHECK_PARAMS_DO( un && excl_idx && at_idx, return );
     301       
    301302        *excl_idx = 0;
     303        *at_idx = 0;
    302304       
    303305        /* Search if there is a '!' before any '@' -- do we need to check it contains a '.' ? */
     
    307309                        if (!*excl_idx)
    308310                                *excl_idx = i;
    309                         if (!at_idx)
    310                                 return;
     311                        continue;
    311312                }
    312313                /* If we reach the realm part, we can stop */
    313314                if ( un->os.data[i] == (unsigned char) '@' ) {
    314                         if (at_idx)
    315                                 *at_idx = i;
     315                        *at_idx = i;
    316316                        break;
     317                }
     318                /* Stop if we find a \0 in the middle */
     319                if ( un->os.data[i] == 0 ) {
     320                        return;
    317321                }
    318322                /* Skip escaped characters */
     
    321325                        continue;
    322326                }
    323                 /* Skip UTF-8 characters spanning on several bytes */
    324                 if ( (un->os.data[i] & 0xF8) == 0xF0 ) { /* 11110zzz */
    325                         i += 3;
    326                         continue;
    327                 }
    328                 if ( (un->os.data[i] & 0xF0) == 0xE0 ) { /* 1110yyyy */
    329                         i += 2;
    330                         continue;
    331                 }
    332                 if ( (un->os.data[i] & 0xE0) == 0xC0 ) { /* 110yyyxx */
    333                         i += 1;
    334                         continue;
    335                 }
    336327        }
    337328