Ignore:
Timestamp:
Feb 21, 2013 11:26:35 AM (11 years ago)
Author:
bennylp
Message:

Fixed #1617: major synchronization fixes in PJNATH with incorporation of group lock to avoid deadlock and crashes due to race conditions

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/src/pjnath/stun_session.c

    r4352 r4360  
    2626    pj_stun_config      *cfg; 
    2727    pj_pool_t           *pool; 
    28     pj_lock_t           *lock; 
    29     pj_bool_t            delete_lock; 
     28    pj_grp_lock_t       *grp_lock; 
    3029    pj_stun_session_cb   cb; 
    3130    void                *user_data; 
    32  
    33     pj_atomic_t         *busy; 
    34     pj_bool_t            destroy_request; 
     31    pj_bool_t            is_destroying; 
    3532 
    3633    pj_bool_t            use_fingerprint; 
     
    5653 
    5754#define SNAME(s_)                   ((s_)->pool->obj_name) 
    58  
    59 #if PJ_LOG_MAX_LEVEL >= 5 
     55#define THIS_FILE                   "stun_session.c" 
     56 
     57#if 1 
    6058#   define TRACE_(expr)             PJ_LOG(5,expr) 
    6159#else 
     
    6361#endif 
    6462 
    65 #define LOG_ERR_(sess,title,rc) pjnath_perror(sess->pool->obj_name,title,rc) 
     63#define LOG_ERR_(sess,title,rc) PJ_PERROR(3,(sess->pool->obj_name,rc,title)) 
    6664 
    6765#define TDATA_POOL_SIZE             PJNATH_POOL_LEN_STUN_TDATA 
     
    7876                                        pj_size_t pkt_size); 
    7977static void stun_tsx_on_destroy(pj_stun_client_tsx *tsx); 
     78static void stun_sess_on_destroy(void *comp); 
    8079 
    8180static pj_stun_tsx_cb tsx_cb =  
     
    149148 
    150149    tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); 
    151     tsx_erase(tdata->sess, tdata); 
    152  
    153     pj_stun_client_tsx_destroy(tsx); 
    154     pj_pool_release(tdata->pool); 
     150    pj_stun_client_tsx_stop(tsx); 
     151    if (tdata) { 
     152        tsx_erase(tdata->sess, tdata); 
     153        pj_pool_release(tdata->pool); 
     154    } 
     155 
     156    TRACE_((THIS_FILE, "STUN transaction %p destroyed", tsx)); 
    155157} 
    156158 
    157159static void destroy_tdata(pj_stun_tx_data *tdata, pj_bool_t force) 
    158160{ 
     161    TRACE_((THIS_FILE, "tdata %p destroy request, force=%d, tsx=%p", tdata, 
     162            force, tdata->client_tsx)); 
     163 
    159164    if (tdata->res_timer.id != PJ_FALSE) { 
    160         pj_timer_heap_cancel(tdata->sess->cfg->timer_heap,  
    161                              &tdata->res_timer); 
    162         tdata->res_timer.id = PJ_FALSE; 
     165        pj_timer_heap_cancel_if_active(tdata->sess->cfg->timer_heap, 
     166                                       &tdata->res_timer, PJ_FALSE); 
    163167        pj_list_erase(tdata); 
    164168    } 
    165169 
    166170    if (force) { 
     171        pj_list_erase(tdata); 
    167172        if (tdata->client_tsx) { 
    168             tsx_erase(tdata->sess, tdata); 
    169             pj_stun_client_tsx_destroy(tdata->client_tsx); 
     173            pj_stun_client_tsx_stop(tdata->client_tsx); 
     174            pj_stun_client_tsx_set_data(tdata->client_tsx, NULL); 
    170175        } 
    171176        pj_pool_release(tdata->pool); 
     
    173178    } else { 
    174179        if (tdata->client_tsx) { 
    175             pj_time_val delay = {2, 0}; 
     180            /* "Probably" this is to absorb retransmission */ 
     181            pj_time_val delay = {0, 300}; 
    176182            pj_stun_client_tsx_schedule_destroy(tdata->client_tsx, &delay); 
    177183 
     
    207213 
    208214    pj_list_erase(tdata); 
    209     pj_stun_msg_destroy_tdata(tdata->sess, tdata); 
     215    destroy_tdata(tdata, PJ_FALSE); 
    210216} 
    211217 
     
    420426 
    421427    /* Lock the session and prevent user from destroying us in the callback */ 
    422     pj_atomic_inc(sess->busy); 
    423     pj_lock_acquire(sess->lock); 
     428    pj_grp_lock_acquire(sess->grp_lock); 
     429    if (sess->is_destroying) { 
     430        pj_stun_msg_destroy_tdata(sess, tdata); 
     431        pj_grp_lock_release(sess->grp_lock); 
     432        return; 
     433    } 
    424434 
    425435    /* Handle authentication challenge */ 
     
    435445     * from the pending list too.  
    436446     */ 
    437     pj_stun_msg_destroy_tdata(sess, tdata); 
     447    if (status == PJNATH_ESTUNTIMEDOUT) 
     448        destroy_tdata(tdata, PJ_TRUE); 
     449    else 
     450        destroy_tdata(tdata, PJ_FALSE); 
    438451    tdata = NULL; 
    439452 
    440     pj_lock_release(sess->lock); 
    441  
    442     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    443         pj_stun_session_destroy(sess); 
    444         return; 
    445     } 
     453    pj_grp_lock_release(sess->grp_lock); 
    446454} 
    447455 
     
    458466 
    459467    /* Lock the session and prevent user from destroying us in the callback */ 
    460     pj_atomic_inc(sess->busy); 
    461     pj_lock_acquire(sess->lock); 
     468    pj_grp_lock_acquire(sess->grp_lock); 
    462469     
     470    if (sess->is_destroying) { 
     471        /* Stray timer */ 
     472        pj_grp_lock_release(sess->grp_lock); 
     473        return PJ_EINVALIDOP; 
     474    } 
     475 
    463476    status = sess->cb.on_send_msg(tdata->sess, tdata->token, stun_pkt,  
    464477                                  pkt_size, tdata->dst_addr,  
    465478                                  tdata->addr_len); 
    466     pj_lock_release(sess->lock); 
    467  
    468     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    469         pj_stun_session_destroy(sess); 
    470         return PJNATH_ESTUNDESTROYED; 
    471     } else { 
    472         return status; 
    473     } 
     479    if (pj_grp_lock_release(sess->grp_lock)) 
     480        return PJ_EGONE; 
     481 
     482    return status; 
    474483} 
    475484 
     
    480489                                            const pj_stun_session_cb *cb, 
    481490                                            pj_bool_t fingerprint, 
     491                                            pj_grp_lock_t *grp_lock, 
    482492                                            pj_stun_session **p_sess) 
    483493{ 
     
    502512    sess->log_flag = 0xFFFF; 
    503513 
     514    if (grp_lock) { 
     515        sess->grp_lock = grp_lock; 
     516    } else { 
     517        status = pj_grp_lock_create(pool, NULL, &sess->grp_lock); 
     518        if (status != PJ_SUCCESS) { 
     519            pj_pool_release(pool); 
     520            return status; 
     521        } 
     522    } 
     523 
     524    pj_grp_lock_add_ref(sess->grp_lock); 
     525    pj_grp_lock_add_handler(sess->grp_lock, pool, sess, 
     526                            &stun_sess_on_destroy); 
     527 
    504528    pj_stun_session_set_software_name(sess, &cfg->software_name); 
    505529 
    506     sess->rx_pool = pj_pool_create(sess->cfg->pf, name,  
    507                                    PJNATH_POOL_LEN_STUN_TDATA,  
     530    sess->rx_pool = pj_pool_create(sess->cfg->pf, name, 
     531                                   PJNATH_POOL_LEN_STUN_TDATA, 
    508532                                   PJNATH_POOL_INC_STUN_TDATA, NULL); 
    509533 
     
    511535    pj_list_init(&sess->cached_response_list); 
    512536 
    513     status = pj_lock_create_recursive_mutex(pool, name, &sess->lock); 
    514     if (status != PJ_SUCCESS) { 
    515         pj_pool_release(pool); 
    516         return status; 
    517     } 
    518     sess->delete_lock = PJ_TRUE; 
    519  
    520     status = pj_atomic_create(pool, 0, &sess->busy); 
    521     if (status != PJ_SUCCESS) { 
    522         pj_lock_destroy(sess->lock); 
    523         pj_pool_release(pool); 
    524         return status; 
    525     } 
    526  
    527537    *p_sess = sess; 
    528538 
     
    530540} 
    531541 
    532 PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) 
    533 { 
    534     PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    535  
    536     pj_lock_acquire(sess->lock); 
    537  
    538     /* Can't destroy if we're in a callback */ 
    539     sess->destroy_request = PJ_TRUE; 
    540     if (pj_atomic_get(sess->busy)) { 
    541         pj_lock_release(sess->lock); 
    542         return PJ_EPENDING; 
    543     } 
     542static void stun_sess_on_destroy(void *comp) 
     543{ 
     544    pj_stun_session *sess = (pj_stun_session*)comp; 
    544545 
    545546    while (!pj_list_empty(&sess->pending_request_list)) { 
     
    552553        destroy_tdata(tdata, PJ_TRUE); 
    553554    } 
    554     pj_lock_release(sess->lock); 
    555  
    556     if (sess->delete_lock) { 
    557         pj_lock_destroy(sess->lock); 
    558     } 
    559555 
    560556    if (sess->rx_pool) { 
     
    565561    pj_pool_release(sess->pool); 
    566562 
     563    TRACE_((THIS_FILE, "STUN session %p destroyed", sess)); 
     564} 
     565 
     566PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) 
     567{ 
     568    pj_stun_tx_data *tdata; 
     569 
     570    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     571 
     572    TRACE_((SNAME(sess), "STUN session %p destroy request, ref_cnt=%d", 
     573             sess, pj_grp_lock_get_ref(sess->grp_lock))); 
     574 
     575    pj_grp_lock_acquire(sess->grp_lock); 
     576 
     577    if (sess->is_destroying) { 
     578        /* Prevent from decrementing the ref counter more than once */ 
     579        pj_grp_lock_release(sess->grp_lock); 
     580        return PJ_EINVALIDOP; 
     581    } 
     582 
     583    sess->is_destroying = PJ_TRUE; 
     584 
     585    /* We need to stop transactions and cached response because they are 
     586     * holding the group lock's reference counter while retransmitting. 
     587     */ 
     588    tdata = sess->pending_request_list.next; 
     589    while (tdata != &sess->pending_request_list) { 
     590        if (tdata->client_tsx) 
     591            pj_stun_client_tsx_stop(tdata->client_tsx); 
     592        tdata = tdata->next; 
     593    } 
     594 
     595    tdata = sess->cached_response_list.next; 
     596    while (tdata != &sess->cached_response_list) { 
     597        pj_timer_heap_cancel_if_active(tdata->sess->cfg->timer_heap, 
     598                                       &tdata->res_timer, PJ_FALSE); 
     599        tdata = tdata->next; 
     600    } 
     601 
     602    pj_grp_lock_dec_ref(sess->grp_lock); 
     603    pj_grp_lock_release(sess->grp_lock); 
    567604    return PJ_SUCCESS; 
    568605} 
     
    573610{ 
    574611    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    575     pj_lock_acquire(sess->lock); 
     612    pj_grp_lock_acquire(sess->grp_lock); 
    576613    sess->user_data = user_data; 
    577     pj_lock_release(sess->lock); 
     614    pj_grp_lock_release(sess->grp_lock); 
    578615    return PJ_SUCCESS; 
    579616} 
     
    585622} 
    586623 
    587 PJ_DEF(pj_status_t) pj_stun_session_set_lock( pj_stun_session *sess, 
    588                                               pj_lock_t *lock, 
    589                                               pj_bool_t auto_del) 
    590 { 
    591     pj_lock_t *old_lock = sess->lock; 
    592     pj_bool_t old_del; 
    593  
    594     PJ_ASSERT_RETURN(sess && lock, PJ_EINVAL); 
    595  
    596     pj_lock_acquire(old_lock); 
    597     sess->lock = lock; 
    598     old_del = sess->delete_lock; 
    599     sess->delete_lock = auto_del; 
    600     pj_lock_release(old_lock); 
    601  
    602     if (old_lock) 
    603         pj_lock_destroy(old_lock); 
    604  
    605     return PJ_SUCCESS; 
    606 } 
    607  
    608624PJ_DEF(pj_status_t) pj_stun_session_set_software_name(pj_stun_session *sess, 
    609625                                                      const pj_str_t *sw) 
    610626{ 
    611627    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     628    pj_grp_lock_acquire(sess->grp_lock); 
    612629    if (sw && sw->slen) 
    613630        pj_strdup(sess->pool, &sess->srv_name, sw); 
    614631    else 
    615632        sess->srv_name.slen = 0; 
     633    pj_grp_lock_release(sess->grp_lock); 
    616634    return PJ_SUCCESS; 
    617635} 
     
    623641    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    624642 
     643    pj_grp_lock_acquire(sess->grp_lock); 
    625644    sess->auth_type = auth_type; 
    626645    if (cred) { 
     
    630649        pj_bzero(&sess->cred, sizeof(sess->cred)); 
    631650    } 
     651    pj_grp_lock_release(sess->grp_lock); 
    632652 
    633653    return PJ_SUCCESS; 
     
    706726    PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); 
    707727 
     728    pj_grp_lock_acquire(sess->grp_lock); 
     729    if (sess->is_destroying) { 
     730        pj_grp_lock_release(sess->grp_lock); 
     731        return PJ_EINVALIDOP; 
     732    } 
     733 
    708734    status = create_tdata(sess, &tdata); 
    709735    if (status != PJ_SUCCESS) 
    710         return status; 
     736        goto on_error; 
    711737 
    712738    /* Create STUN message */ 
    713739    status = pj_stun_msg_create(tdata->pool, method,  magic,  
    714740                                tsx_id, &tdata->msg); 
    715     if (status != PJ_SUCCESS) { 
    716         pj_pool_release(tdata->pool); 
    717         return status; 
    718     } 
     741    if (status != PJ_SUCCESS) 
     742        goto on_error; 
    719743 
    720744    /* copy the request's transaction ID as the transaction key. */ 
     
    732756        /* MUST put authentication in request */ 
    733757        status = get_auth(sess, tdata); 
    734         if (status != PJ_SUCCESS) { 
    735             pj_pool_release(tdata->pool); 
    736             return status; 
    737         } 
     758        if (status != PJ_SUCCESS) 
     759            goto on_error; 
    738760 
    739761    } else if (sess->auth_type == PJ_STUN_AUTH_LONG_TERM) { 
     
    743765        if (sess->next_nonce.slen != 0) { 
    744766            status = get_auth(sess, tdata); 
    745             if (status != PJ_SUCCESS) { 
    746                 pj_pool_release(tdata->pool); 
    747                 return status; 
    748             } 
     767            if (status != PJ_SUCCESS) 
     768                goto on_error; 
    749769            tdata->auth_info.nonce = sess->next_nonce; 
    750770            tdata->auth_info.realm = sess->server_realm; 
     
    753773    } else { 
    754774        pj_assert(!"Invalid authentication type"); 
     775        status = PJ_EBUG; 
     776        goto on_error; 
     777    } 
     778 
     779    *p_tdata = tdata; 
     780    pj_grp_lock_release(sess->grp_lock); 
     781    return PJ_SUCCESS; 
     782 
     783on_error: 
     784    if (tdata) 
    755785        pj_pool_release(tdata->pool); 
    756         return PJ_EBUG; 
    757     } 
    758  
    759     *p_tdata = tdata; 
    760     return PJ_SUCCESS; 
     786    pj_grp_lock_release(sess->grp_lock); 
     787    return status; 
    761788} 
    762789 
     
    770797    PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); 
    771798 
     799    pj_grp_lock_acquire(sess->grp_lock); 
     800    if (sess->is_destroying) { 
     801        pj_grp_lock_release(sess->grp_lock); 
     802        return PJ_EINVALIDOP; 
     803    } 
     804 
    772805    status = create_tdata(sess, &tdata); 
    773     if (status != PJ_SUCCESS) 
     806    if (status != PJ_SUCCESS) { 
     807        pj_grp_lock_release(sess->grp_lock); 
    774808        return status; 
     809    } 
    775810 
    776811    /* Create STUN message */ 
     
    780815    if (status != PJ_SUCCESS) { 
    781816        pj_pool_release(tdata->pool); 
     817        pj_grp_lock_release(sess->grp_lock); 
    782818        return status; 
    783819    } 
    784820 
    785821    *p_tdata = tdata; 
     822 
     823    pj_grp_lock_release(sess->grp_lock); 
    786824    return PJ_SUCCESS; 
    787825} 
     
    799837    pj_stun_tx_data *tdata = NULL; 
    800838 
     839    pj_grp_lock_acquire(sess->grp_lock); 
     840    if (sess->is_destroying) { 
     841        pj_grp_lock_release(sess->grp_lock); 
     842        return PJ_EINVALIDOP; 
     843    } 
     844 
    801845    status = create_tdata(sess, &tdata); 
    802     if (status != PJ_SUCCESS) 
     846    if (status != PJ_SUCCESS) { 
     847        pj_grp_lock_release(sess->grp_lock); 
    803848        return status; 
     849    } 
    804850 
    805851    /* Create STUN response message */ 
     
    808854    if (status != PJ_SUCCESS) { 
    809855        pj_pool_release(tdata->pool); 
     856        pj_grp_lock_release(sess->grp_lock); 
    810857        return status; 
    811858    } 
     
    821868 
    822869    *p_tdata = tdata; 
     870 
     871    pj_grp_lock_release(sess->grp_lock); 
    823872 
    824873    return PJ_SUCCESS; 
     
    868917    PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); 
    869918 
     919    /* Lock the session and prevent user from destroying us in the callback */ 
     920    pj_grp_lock_acquire(sess->grp_lock); 
     921    if (sess->is_destroying) { 
     922        pj_grp_lock_release(sess->grp_lock); 
     923        return PJ_EINVALIDOP; 
     924    } 
     925 
    870926    pj_log_push_indent(); 
    871927 
     
    876932    tdata->token = token; 
    877933    tdata->retransmit = retransmit; 
    878  
    879     /* Lock the session and prevent user from destroying us in the callback */ 
    880     pj_atomic_inc(sess->busy); 
    881     pj_lock_acquire(sess->lock); 
    882934 
    883935    /* Apply options */ 
     
    910962 
    911963        /* Create STUN client transaction */ 
    912         status = pj_stun_client_tsx_create(sess->cfg, tdata->pool,  
     964        status = pj_stun_client_tsx_create(sess->cfg, tdata->pool, 
     965                                           sess->grp_lock, 
    913966                                           &tsx_cb, &tdata->client_tsx); 
    914967        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     
    940993             
    941994            pj_memset(&tdata->res_timer, 0, sizeof(tdata->res_timer)); 
    942             pj_timer_entry_init(&tdata->res_timer, PJ_TRUE, tdata,  
     995            pj_timer_entry_init(&tdata->res_timer, PJ_FALSE, tdata, 
    943996                                &on_cache_timeout); 
    944997 
     
    946999            timeout.msec = sess->cfg->res_cache_msec % 1000; 
    9471000 
    948             status = pj_timer_heap_schedule(sess->cfg->timer_heap,  
    949                                             &tdata->res_timer, 
    950                                             &timeout); 
     1001            status = pj_timer_heap_schedule_w_grp_lock(sess->cfg->timer_heap, 
     1002                                                       &tdata->res_timer, 
     1003                                                       &timeout, PJ_TRUE, 
     1004                                                       sess->grp_lock); 
    9511005            if (status != PJ_SUCCESS) { 
    952                 tdata->res_timer.id = PJ_FALSE; 
    9531006                pj_stun_msg_destroy_tdata(sess, tdata); 
    9541007                LOG_ERR_(sess, "Error scheduling response timer", status); 
     
    9761029 
    9771030on_return: 
    978     pj_lock_release(sess->lock); 
    979  
    9801031    pj_log_pop_indent(); 
    9811032 
    982     /* Check if application has called destroy() in the callback */ 
    983     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    984         pj_stun_session_destroy(sess); 
    985         return PJNATH_ESTUNDESTROYED; 
    986     } 
     1033    if (pj_grp_lock_release(sess->grp_lock)) 
     1034        return PJ_EGONE; 
    9871035 
    9881036    return status; 
     
    10061054    pj_stun_tx_data *tdata; 
    10071055 
     1056    pj_grp_lock_acquire(sess->grp_lock); 
     1057    if (sess->is_destroying) { 
     1058        pj_grp_lock_release(sess->grp_lock); 
     1059        return PJ_EINVALIDOP; 
     1060    } 
     1061 
    10081062    status = pj_stun_session_create_res(sess, rdata, code,  
    10091063                                        (errmsg?pj_cstr(&reason,errmsg):NULL),  
    10101064                                        &tdata); 
    1011     if (status != PJ_SUCCESS) 
     1065    if (status != PJ_SUCCESS) { 
     1066        pj_grp_lock_release(sess->grp_lock); 
    10121067        return status; 
    1013  
    1014     return pj_stun_session_send_msg(sess, token, cache, PJ_FALSE, 
    1015                                     dst_addr,  addr_len, tdata); 
     1068    } 
     1069 
     1070    status = pj_stun_session_send_msg(sess, token, cache, PJ_FALSE, 
     1071                                      dst_addr,  addr_len, tdata); 
     1072 
     1073    pj_grp_lock_release(sess->grp_lock); 
     1074    return status; 
    10161075} 
    10171076 
     
    10301089 
    10311090    /* Lock the session and prevent user from destroying us in the callback */ 
    1032     pj_atomic_inc(sess->busy); 
    1033     pj_lock_acquire(sess->lock); 
     1091    pj_grp_lock_acquire(sess->grp_lock); 
     1092    if (sess->is_destroying) { 
     1093        pj_grp_lock_release(sess->grp_lock); 
     1094        return PJ_EINVALIDOP; 
     1095    } 
    10341096 
    10351097    if (notify) { 
     
    10411103    pj_stun_msg_destroy_tdata(sess, tdata); 
    10421104 
    1043     pj_lock_release(sess->lock); 
    1044  
    1045     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    1046         pj_stun_session_destroy(sess); 
    1047         return PJNATH_ESTUNDESTROYED; 
    1048     } 
     1105    pj_grp_lock_release(sess->grp_lock); 
    10491106 
    10501107    return PJ_SUCCESS; 
     
    10641121 
    10651122    /* Lock the session and prevent user from destroying us in the callback */ 
    1066     pj_atomic_inc(sess->busy); 
    1067     pj_lock_acquire(sess->lock); 
     1123    pj_grp_lock_acquire(sess->grp_lock); 
     1124    if (sess->is_destroying) { 
     1125        pj_grp_lock_release(sess->grp_lock); 
     1126        return PJ_EINVALIDOP; 
     1127    } 
    10681128 
    10691129    status = pj_stun_client_tsx_retransmit(tdata->client_tsx, mod_count); 
    10701130 
    1071     pj_lock_release(sess->lock); 
    1072  
    1073     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    1074         pj_stun_session_destroy(sess); 
    1075         return PJNATH_ESTUNDESTROYED; 
    1076     } 
     1131    pj_grp_lock_release(sess->grp_lock); 
    10771132 
    10781133    return status; 
     
    13621417    PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL); 
    13631418 
     1419    /* Lock the session and prevent user from destroying us in the callback */ 
     1420    pj_grp_lock_acquire(sess->grp_lock); 
     1421 
     1422    if (sess->is_destroying) { 
     1423        pj_grp_lock_release(sess->grp_lock); 
     1424        return PJ_EINVALIDOP; 
     1425    } 
     1426 
    13641427    pj_log_push_indent(); 
    1365  
    1366     /* Lock the session and prevent user from destroying us in the callback */ 
    1367     pj_atomic_inc(sess->busy); 
    1368     pj_lock_acquire(sess->lock); 
    13691428 
    13701429    /* Reset pool */ 
     
    14191478 
    14201479on_return: 
    1421     pj_lock_release(sess->lock); 
    1422  
    14231480    pj_log_pop_indent(); 
    14241481 
    1425     /* If we've received destroy request while we're on the callback, 
    1426      * destroy the session now. 
    1427      */ 
    1428     if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 
    1429         pj_stun_session_destroy(sess); 
    1430         return PJNATH_ESTUNDESTROYED; 
    1431     } 
     1482    if (pj_grp_lock_release(sess->grp_lock)) 
     1483        return PJ_EGONE; 
    14321484 
    14331485    return status; 
Note: See TracChangeset for help on using the changeset viewer.