Navigation


Changeset 706:4ffbc9f1e922 in freeDiameter for libfdcore/peers.c


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

Large UNTESTED commit with the following changes:

  • Improved DiameterIdentity? handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7)
  • Cleanup in the session module to free only unreferenced sessions (#16)
  • Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
  • Improved peer state machine algorithm to counter SCTP multistream race condition.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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; } );
Note: See TracChangeset for help on using the changeset viewer.