Ignore:
Timestamp:
Jun 6, 2008 10:52:48 PM (16 years ago)
Author:
bennylp
Message:

Ticket #418 Protect client registration session with mutex

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c

    r1981 r1992  
    2828#include <pj/assert.h> 
    2929#include <pj/guid.h> 
     30#include <pj/lock.h> 
    3031#include <pj/os.h> 
    3132#include <pj/pool.h> 
     
    6465    pj_pool_t                   *pool; 
    6566    pjsip_endpoint              *endpt; 
     67    pj_lock_t                   *lock; 
    6668    pj_bool_t                    _delete_flag; 
    6769    pj_bool_t                    has_tsx; 
    68     pj_int32_t                   busy; 
     70    pj_atomic_t                 *busy_ctr; 
    6971    enum regc_op                 current_op; 
    7072 
     
    130132    regc->add_xuid_param = pjsip_cfg()->regc.add_xuid_param; 
    131133 
     134    status = pj_lock_create_recursive_mutex(pool, pool->obj_name,  
     135                                            &regc->lock); 
     136    if (status != PJ_SUCCESS) { 
     137        pj_pool_release(pool); 
     138        return status; 
     139    } 
     140 
     141    status = pj_atomic_create(pool, 0, &regc->busy_ctr); 
     142    if (status != PJ_SUCCESS) { 
     143        pj_lock_destroy(regc->lock); 
     144        pj_pool_release(pool); 
     145        return status; 
     146    } 
     147 
    132148    status = pjsip_auth_clt_init(&regc->auth_sess, endpt, regc->pool, 0); 
    133149    if (status != PJ_SUCCESS) 
     
    149165    PJ_ASSERT_RETURN(regc, PJ_EINVAL); 
    150166 
    151     if (regc->has_tsx || regc->busy) { 
     167    pj_lock_acquire(regc->lock); 
     168    if (regc->has_tsx || pj_atomic_get(regc->busy_ctr) != 0) { 
    152169        regc->_delete_flag = 1; 
    153170        regc->cb = NULL; 
     171        pj_lock_release(regc->lock); 
    154172    } else { 
    155173        pjsip_tpselector_dec_ref(&regc->tp_sel); 
     
    162180            regc->timer.id = 0; 
    163181        } 
     182        pj_atomic_destroy(regc->busy_ctr); 
     183        pj_lock_release(regc->lock); 
     184        pj_lock_destroy(regc->lock); 
     185        regc->lock = NULL; 
    164186        pjsip_endpt_release_pool(regc->endpt, regc->pool); 
    165187    } 
     
    174196    PJ_ASSERT_RETURN(regc && info, PJ_EINVAL); 
    175197 
     198    pj_lock_acquire(regc->lock); 
     199 
    176200    info->server_uri = regc->str_srv_url; 
    177201    info->client_uri = regc->from_uri; 
    178     info->is_busy = (regc->busy || regc->has_tsx); 
     202    info->is_busy = (pj_atomic_get(regc->busy_ctr) || regc->has_tsx); 
    179203    info->auto_reg = regc->auto_reg; 
    180204    info->interval = regc->expires; 
     
    194218        info->next_reg = next_reg.sec; 
    195219    } 
     220 
     221    pj_lock_release(regc->lock); 
    196222 
    197223    return PJ_SUCCESS; 
     
    505531    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL); 
    506532 
     533    pj_lock_acquire(regc->lock); 
     534 
    507535    status = create_request(regc, &tdata); 
    508     if (status != PJ_SUCCESS) 
     536    if (status != PJ_SUCCESS) { 
     537        pj_lock_release(regc->lock); 
    509538        return status; 
     539    } 
    510540 
    511541    msg = tdata->msg; 
     
    540570    regc->auto_reg = autoreg; 
    541571 
     572    pj_lock_release(regc->lock); 
     573 
    542574    /* Done */ 
    543575    *p_tdata = tdata; 
     
    556588    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL); 
    557589 
     590    pj_lock_acquire(regc->lock); 
     591 
    558592    if (regc->timer.id != 0) { 
    559593        pjsip_endpt_cancel_timer(regc->endpt, &regc->timer); 
     
    562596 
    563597    status = create_request(regc, &tdata); 
    564     if (status != PJ_SUCCESS) 
     598    if (status != PJ_SUCCESS) { 
     599        pj_lock_release(regc->lock); 
    565600        return status; 
     601    } 
    566602 
    567603    msg = tdata->msg; 
     
    587623    pjsip_msg_add_hdr(msg, hdr); 
    588624 
     625    pj_lock_release(regc->lock); 
     626 
    589627    *p_tdata = tdata; 
    590628    return PJ_SUCCESS; 
     
    602640    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL); 
    603641 
     642    pj_lock_acquire(regc->lock); 
     643 
    604644    if (regc->timer.id != 0) { 
    605645        pjsip_endpt_cancel_timer(regc->endpt, &regc->timer); 
     
    608648 
    609649    status = create_request(regc, &tdata); 
    610     if (status != PJ_SUCCESS) 
     650    if (status != PJ_SUCCESS) { 
     651        pj_lock_release(regc->lock); 
    611652        return status; 
     653    } 
    612654 
    613655    msg = tdata->msg; 
     
    625667    pjsip_msg_add_hdr(msg, hdr); 
    626668 
     669    pj_lock_release(regc->lock); 
     670 
    627671    *p_tdata = tdata; 
    628672    return PJ_SUCCESS; 
     
    634678                                                const pj_str_t contact[] ) 
    635679{ 
     680    pj_status_t status; 
     681 
    636682    PJ_ASSERT_RETURN(regc, PJ_EINVAL); 
    637     return set_contact( regc, contact_cnt, contact ); 
     683 
     684    pj_lock_acquire(regc->lock); 
     685    status = set_contact( regc, contact_cnt, contact ); 
     686    pj_lock_release(regc->lock); 
     687 
     688    return status; 
    638689} 
    639690 
     
    643694{ 
    644695    PJ_ASSERT_RETURN(regc, PJ_EINVAL); 
     696 
     697    pj_lock_acquire(regc->lock); 
    645698    set_expires( regc, expires ); 
     699    pj_lock_release(regc->lock); 
     700 
    646701    return PJ_SUCCESS; 
    647702} 
     
    685740 
    686741    /* Temporarily increase busy flag to prevent regc from being deleted 
    687      * in pjsip_regc_send() 
     742     * in pjsip_regc_send() or in the callback 
    688743     */ 
    689     regc->busy++; 
     744    pj_atomic_inc(regc->busy_ctr); 
    690745 
    691746    entry->id = 0; 
     
    701756    } 
    702757 
    703     regc->busy--; 
    704  
    705758    /* Delete the record if user destroy regc during the callback. */ 
    706     if (regc->_delete_flag && regc->busy==0) { 
     759    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) { 
    707760        pjsip_regc_destroy(regc); 
    708761    } 
     
    881934    pjsip_regc *regc = (pjsip_regc*) token; 
    882935    pjsip_transaction *tsx = event->body.tsx_state.tsx; 
    883      
     936 
     937    pj_atomic_inc(regc->busy_ctr); 
     938    pj_lock_acquire(regc->lock); 
     939 
    884940    /* Decrement pending transaction counter. */ 
    885941    pj_assert(regc->has_tsx); 
     
    915971 
    916972        if (status == PJ_SUCCESS) { 
    917             ++regc->busy; 
    918973            status = pjsip_regc_send(regc, tdata); 
    919             --regc->busy; 
    920974        } 
    921975         
     
    926980             */ 
    927981            if (regc->_delete_flag == 0) { 
    928                 /* Increment busy flag temporarily to prevent regc from 
    929                  * being destroyed. 
     982                /* Should be safe to release the lock temporarily. 
     983                 * We do this to avoid deadlock.  
    930984                 */ 
    931                 ++regc->busy; 
    932  
     985                pj_lock_release(regc->lock); 
    933986                call_callback(regc, status, tsx->status_code,  
    934987                              &rdata->msg_info.msg->line.status.reason, 
    935988                              rdata, -1, 0, NULL); 
    936  
    937                 /* Decrement busy flag */ 
    938                 --regc->busy; 
     989                pj_lock_acquire(regc->lock); 
    939990            } 
    940991        } 
     
    9941045        } 
    9951046 
    996         /* Increment busy flag temporarily to prevent regc from 
    997          * being destroyed. 
    998          */ 
    999         ++regc->busy; 
    1000  
    10011047        /* Update registration */ 
    10021048        if (expiration==NOEXP) expiration=-1; 
     
    10041050 
    10051051        /* Call callback. */ 
     1052        /* Should be safe to release the lock temporarily. 
     1053         * We do this to avoid deadlock.  
     1054         */ 
     1055        pj_lock_release(regc->lock); 
    10061056        call_callback(regc, PJ_SUCCESS, tsx->status_code,  
    10071057                      (rdata ? &rdata->msg_info.msg->line.status.reason  
     
    10091059                      rdata, expiration,  
    10101060                      contact_cnt, contact); 
    1011  
    1012         /* Decrement busy flag */ 
    1013         --regc->busy; 
    1014     } 
     1061        pj_lock_acquire(regc->lock); 
     1062    } 
     1063 
     1064    pj_lock_release(regc->lock); 
    10151065 
    10161066    /* Delete the record if user destroy regc during the callback. */ 
    1017     if (regc->_delete_flag && regc->busy==0) { 
     1067    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) { 
    10181068        pjsip_regc_destroy(regc); 
    10191069    } 
     
    10261076    pjsip_expires_hdr *expires_hdr; 
    10271077    pj_uint32_t cseq; 
     1078 
     1079    pj_atomic_inc(regc->busy_ctr); 
     1080    pj_lock_acquire(regc->lock); 
    10281081 
    10291082    /* Make sure we don't have pending transaction. */ 
     
    10321085                             "transaction pending")); 
    10331086        pjsip_tx_data_dec_ref( tdata ); 
     1087        pj_lock_release(regc->lock); 
     1088        pj_atomic_dec(regc->busy_ctr); 
    10341089        return PJSIP_EBUSY; 
    10351090    } 
     
    10531108    pjsip_tx_data_set_transport(tdata, &regc->tp_sel); 
    10541109 
    1055     /* Increment pending transaction first, since transaction callback 
    1056      * may be called even before send_request() returns! 
    1057      */ 
    10581110    regc->has_tsx = PJ_TRUE; 
    1059     ++regc->busy; 
    10601111 
    10611112    /* Set current operation based on the value of Expires header */ 
     
    10701121        PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status)); 
    10711122    } 
    1072     --regc->busy; 
     1123 
     1124    pj_lock_release(regc->lock); 
    10731125 
    10741126    /* Delete the record if user destroy regc during the callback. */ 
    1075     if (regc->_delete_flag && regc->busy==0) { 
     1127    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) { 
    10761128        pjsip_regc_destroy(regc); 
    10771129    } 
Note: See TracChangeset for help on using the changeset viewer.