diff options
Diffstat (limited to 'pjnath/src/pjnath/stun_session.c')
-rw-r--r-- | pjnath/src/pjnath/stun_session.c | 377 |
1 files changed, 214 insertions, 163 deletions
diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c index 45d5313..4018b93 100644 --- a/pjnath/src/pjnath/stun_session.c +++ b/pjnath/src/pjnath/stun_session.c @@ -1,4 +1,4 @@ -/* $Id: stun_session.c 3843 2011-10-24 14:13:35Z bennylp $ */ +/* $Id: stun_session.c 4360 2013-02-21 11:26:35Z bennylp $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> @@ -25,13 +25,10 @@ struct pj_stun_session { pj_stun_config *cfg; pj_pool_t *pool; - pj_lock_t *lock; - pj_bool_t delete_lock; + pj_grp_lock_t *grp_lock; pj_stun_session_cb cb; void *user_data; - - pj_atomic_t *busy; - pj_bool_t destroy_request; + pj_bool_t is_destroying; pj_bool_t use_fingerprint; @@ -55,14 +52,15 @@ struct pj_stun_session }; #define SNAME(s_) ((s_)->pool->obj_name) +#define THIS_FILE "stun_session.c" -#if PJ_LOG_MAX_LEVEL >= 5 +#if 1 # define TRACE_(expr) PJ_LOG(5,expr) #else # define TRACE_(expr) #endif -#define LOG_ERR_(sess,title,rc) pjnath_perror(sess->pool->obj_name,title,rc) +#define LOG_ERR_(sess,title,rc) PJ_PERROR(3,(sess->pool->obj_name,rc,title)) #define TDATA_POOL_SIZE PJNATH_POOL_LEN_STUN_TDATA #define TDATA_POOL_INC PJNATH_POOL_INC_STUN_TDATA @@ -77,6 +75,7 @@ static pj_status_t stun_tsx_on_send_msg(pj_stun_client_tsx *tsx, const void *stun_pkt, pj_size_t pkt_size); static void stun_tsx_on_destroy(pj_stun_client_tsx *tsx); +static void stun_sess_on_destroy(void *comp); static pj_stun_tsx_cb tsx_cb = { @@ -148,31 +147,38 @@ static void stun_tsx_on_destroy(pj_stun_client_tsx *tsx) pj_stun_tx_data *tdata; tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); - tsx_erase(tdata->sess, tdata); + pj_stun_client_tsx_stop(tsx); + if (tdata) { + tsx_erase(tdata->sess, tdata); + pj_pool_release(tdata->pool); + } - pj_stun_client_tsx_destroy(tsx); - pj_pool_release(tdata->pool); + TRACE_((THIS_FILE, "STUN transaction %p destroyed", tsx)); } static void destroy_tdata(pj_stun_tx_data *tdata, pj_bool_t force) { + TRACE_((THIS_FILE, "tdata %p destroy request, force=%d, tsx=%p", tdata, + force, tdata->client_tsx)); + if (tdata->res_timer.id != PJ_FALSE) { - pj_timer_heap_cancel(tdata->sess->cfg->timer_heap, - &tdata->res_timer); - tdata->res_timer.id = PJ_FALSE; + pj_timer_heap_cancel_if_active(tdata->sess->cfg->timer_heap, + &tdata->res_timer, PJ_FALSE); pj_list_erase(tdata); } if (force) { + pj_list_erase(tdata); if (tdata->client_tsx) { - tsx_erase(tdata->sess, tdata); - pj_stun_client_tsx_destroy(tdata->client_tsx); + pj_stun_client_tsx_stop(tdata->client_tsx); + pj_stun_client_tsx_set_data(tdata->client_tsx, NULL); } pj_pool_release(tdata->pool); } else { if (tdata->client_tsx) { - pj_time_val delay = {2, 0}; + /* "Probably" this is to absorb retransmission */ + pj_time_val delay = {0, 300}; pj_stun_client_tsx_schedule_destroy(tdata->client_tsx, &delay); } else { @@ -206,7 +212,7 @@ static void on_cache_timeout(pj_timer_heap_t *timer_heap, PJ_LOG(5,(SNAME(tdata->sess), "Response cache deleted")); pj_list_erase(tdata); - pj_stun_msg_destroy_tdata(tdata->sess, tdata); + destroy_tdata(tdata, PJ_FALSE); } static pj_status_t apply_msg_options(pj_stun_session *sess, @@ -419,8 +425,12 @@ static void stun_tsx_on_complete(pj_stun_client_tsx *tsx, sess = tdata->sess; /* Lock the session and prevent user from destroying us in the callback */ - pj_atomic_inc(sess->busy); - pj_lock_acquire(sess->lock); + pj_grp_lock_acquire(sess->grp_lock); + if (sess->is_destroying) { + pj_stun_msg_destroy_tdata(sess, tdata); + pj_grp_lock_release(sess->grp_lock); + return; + } /* Handle authentication challenge */ handle_auth_challenge(sess, tdata, response, src_addr, @@ -434,15 +444,13 @@ static void stun_tsx_on_complete(pj_stun_client_tsx *tsx, /* Destroy the transmit data. This will remove the transaction * from the pending list too. */ - pj_stun_msg_destroy_tdata(sess, tdata); + if (status == PJNATH_ESTUNTIMEDOUT) + destroy_tdata(tdata, PJ_TRUE); + else + destroy_tdata(tdata, PJ_FALSE); tdata = NULL; - pj_lock_release(sess->lock); - - if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { - pj_stun_session_destroy(sess); - return; - } + pj_grp_lock_release(sess->grp_lock); } static pj_status_t stun_tsx_on_send_msg(pj_stun_client_tsx *tsx, @@ -457,20 +465,21 @@ static pj_status_t stun_tsx_on_send_msg(pj_stun_client_tsx *tsx, sess = tdata->sess; /* Lock the session and prevent user from destroying us in the callback */ - pj_atomic_inc(sess->busy); - pj_lock_acquire(sess->lock); + pj_grp_lock_acquire(sess->grp_lock); + if (sess->is_destroying) { + /* Stray timer */ + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } + status = sess->cb.on_send_msg(tdata->sess, tdata->token, stun_pkt, pkt_size, tdata->dst_addr, tdata->addr_len); - pj_lock_release(sess->lock); + if (pj_grp_lock_release(sess->grp_lock)) + return PJ_EGONE; - if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { - pj_stun_session_destroy(sess); - return PJNATH_ESTUNDESTROYED; - } else { - return status; - } + return status; } /* **************************************************************************/ @@ -479,6 +488,7 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_config *cfg, const char *name, const pj_stun_session_cb *cb, pj_bool_t fingerprint, + pj_grp_lock_t *grp_lock, pj_stun_session **p_sess) { pj_pool_t *pool; @@ -500,49 +510,38 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_config *cfg, pj_memcpy(&sess->cb, cb, sizeof(*cb)); sess->use_fingerprint = fingerprint; sess->log_flag = 0xFFFF; - - sess->srv_name.ptr = (char*) pj_pool_alloc(pool, 32); - sess->srv_name.slen = pj_ansi_snprintf(sess->srv_name.ptr, 32, - "pjnath-%s", pj_get_version()); - sess->rx_pool = pj_pool_create(sess->cfg->pf, name, - PJNATH_POOL_LEN_STUN_TDATA, + if (grp_lock) { + sess->grp_lock = grp_lock; + } else { + status = pj_grp_lock_create(pool, NULL, &sess->grp_lock); + if (status != PJ_SUCCESS) { + pj_pool_release(pool); + return status; + } + } + + pj_grp_lock_add_ref(sess->grp_lock); + pj_grp_lock_add_handler(sess->grp_lock, pool, sess, + &stun_sess_on_destroy); + + pj_stun_session_set_software_name(sess, &cfg->software_name); + + sess->rx_pool = pj_pool_create(sess->cfg->pf, name, + PJNATH_POOL_LEN_STUN_TDATA, PJNATH_POOL_INC_STUN_TDATA, NULL); pj_list_init(&sess->pending_request_list); pj_list_init(&sess->cached_response_list); - status = pj_lock_create_recursive_mutex(pool, name, &sess->lock); - if (status != PJ_SUCCESS) { - pj_pool_release(pool); - return status; - } - sess->delete_lock = PJ_TRUE; - - status = pj_atomic_create(pool, 0, &sess->busy); - if (status != PJ_SUCCESS) { - pj_lock_destroy(sess->lock); - pj_pool_release(pool); - return status; - } - *p_sess = sess; return PJ_SUCCESS; } -PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) +static void stun_sess_on_destroy(void *comp) { - PJ_ASSERT_RETURN(sess, PJ_EINVAL); - - pj_lock_acquire(sess->lock); - - /* Can't destroy if we're in a callback */ - sess->destroy_request = PJ_TRUE; - if (pj_atomic_get(sess->busy)) { - pj_lock_release(sess->lock); - return PJ_EPENDING; - } + pj_stun_session *sess = (pj_stun_session*)comp; while (!pj_list_empty(&sess->pending_request_list)) { pj_stun_tx_data *tdata = sess->pending_request_list.next; @@ -553,11 +552,6 @@ PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) pj_stun_tx_data *tdata = sess->cached_response_list.next; destroy_tdata(tdata, PJ_TRUE); } - pj_lock_release(sess->lock); - - if (sess->delete_lock) { - pj_lock_destroy(sess->lock); - } if (sess->rx_pool) { pj_pool_release(sess->rx_pool); @@ -566,6 +560,47 @@ PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) pj_pool_release(sess->pool); + TRACE_((THIS_FILE, "STUN session %p destroyed", sess)); +} + +PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) +{ + pj_stun_tx_data *tdata; + + PJ_ASSERT_RETURN(sess, PJ_EINVAL); + + TRACE_((SNAME(sess), "STUN session %p destroy request, ref_cnt=%d", + sess, pj_grp_lock_get_ref(sess->grp_lock))); + + pj_grp_lock_acquire(sess->grp_lock); + + if (sess->is_destroying) { + /* Prevent from decrementing the ref counter more than once */ + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } + + sess->is_destroying = PJ_TRUE; + + /* We need to stop transactions and cached response because they are + * holding the group lock's reference counter while retransmitting. + */ + tdata = sess->pending_request_list.next; + while (tdata != &sess->pending_request_list) { + if (tdata->client_tsx) + pj_stun_client_tsx_stop(tdata->client_tsx); + tdata = tdata->next; + } + + tdata = sess->cached_response_list.next; + while (tdata != &sess->cached_response_list) { + pj_timer_heap_cancel_if_active(tdata->sess->cfg->timer_heap, + &tdata->res_timer, PJ_FALSE); + tdata = tdata->next; + } + + pj_grp_lock_dec_ref(sess->grp_lock); + pj_grp_lock_release(sess->grp_lock); return PJ_SUCCESS; } @@ -574,9 +609,9 @@ PJ_DEF(pj_status_t) pj_stun_session_set_user_data( pj_stun_session *sess, void *user_data) { PJ_ASSERT_RETURN(sess, PJ_EINVAL); - pj_lock_acquire(sess->lock); + pj_grp_lock_acquire(sess->grp_lock); sess->user_data = user_data; - pj_lock_release(sess->lock); + pj_grp_lock_release(sess->grp_lock); return PJ_SUCCESS; } @@ -586,35 +621,16 @@ PJ_DEF(void*) pj_stun_session_get_user_data(pj_stun_session *sess) return sess->user_data; } -PJ_DEF(pj_status_t) pj_stun_session_set_lock( pj_stun_session *sess, - pj_lock_t *lock, - pj_bool_t auto_del) -{ - pj_lock_t *old_lock = sess->lock; - pj_bool_t old_del; - - PJ_ASSERT_RETURN(sess && lock, PJ_EINVAL); - - pj_lock_acquire(old_lock); - sess->lock = lock; - old_del = sess->delete_lock; - sess->delete_lock = auto_del; - pj_lock_release(old_lock); - - if (old_lock) - pj_lock_destroy(old_lock); - - return PJ_SUCCESS; -} - PJ_DEF(pj_status_t) pj_stun_session_set_software_name(pj_stun_session *sess, const pj_str_t *sw) { PJ_ASSERT_RETURN(sess, PJ_EINVAL); + pj_grp_lock_acquire(sess->grp_lock); if (sw && sw->slen) pj_strdup(sess->pool, &sess->srv_name, sw); else sess->srv_name.slen = 0; + pj_grp_lock_release(sess->grp_lock); return PJ_SUCCESS; } @@ -624,6 +640,7 @@ PJ_DEF(pj_status_t) pj_stun_session_set_credential(pj_stun_session *sess, { PJ_ASSERT_RETURN(sess, PJ_EINVAL); + pj_grp_lock_acquire(sess->grp_lock); sess->auth_type = auth_type; if (cred) { pj_stun_auth_cred_dup(sess->pool, &sess->cred, cred); @@ -631,6 +648,7 @@ PJ_DEF(pj_status_t) pj_stun_session_set_credential(pj_stun_session *sess, sess->auth_type = PJ_STUN_AUTH_NONE; pj_bzero(&sess->cred, sizeof(sess->cred)); } + pj_grp_lock_release(sess->grp_lock); return PJ_SUCCESS; } @@ -707,17 +725,21 @@ PJ_DEF(pj_status_t) pj_stun_session_create_req(pj_stun_session *sess, PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); + pj_grp_lock_acquire(sess->grp_lock); + if (sess->is_destroying) { + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } + status = create_tdata(sess, &tdata); if (status != PJ_SUCCESS) - return status; + goto on_error; /* Create STUN message */ status = pj_stun_msg_create(tdata->pool, method, magic, tsx_id, &tdata->msg); - if (status != PJ_SUCCESS) { - pj_pool_release(tdata->pool); - return status; - } + if (status != PJ_SUCCESS) + goto on_error; /* copy the request's transaction ID as the transaction key. */ pj_assert(sizeof(tdata->msg_key)==sizeof(tdata->msg->hdr.tsx_id)); @@ -733,10 +755,8 @@ PJ_DEF(pj_status_t) pj_stun_session_create_req(pj_stun_session *sess, } else if (sess->auth_type == PJ_STUN_AUTH_SHORT_TERM) { /* MUST put authentication in request */ status = get_auth(sess, tdata); - if (status != PJ_SUCCESS) { - pj_pool_release(tdata->pool); - return status; - } + if (status != PJ_SUCCESS) + goto on_error; } else if (sess->auth_type == PJ_STUN_AUTH_LONG_TERM) { /* Only put authentication information if we've received @@ -744,22 +764,27 @@ PJ_DEF(pj_status_t) pj_stun_session_create_req(pj_stun_session *sess, */ if (sess->next_nonce.slen != 0) { status = get_auth(sess, tdata); - if (status != PJ_SUCCESS) { - pj_pool_release(tdata->pool); - return status; - } + if (status != PJ_SUCCESS) + goto on_error; tdata->auth_info.nonce = sess->next_nonce; tdata->auth_info.realm = sess->server_realm; } } else { pj_assert(!"Invalid authentication type"); - pj_pool_release(tdata->pool); - return PJ_EBUG; + status = PJ_EBUG; + goto on_error; } *p_tdata = tdata; + pj_grp_lock_release(sess->grp_lock); return PJ_SUCCESS; + +on_error: + if (tdata) + pj_pool_release(tdata->pool); + pj_grp_lock_release(sess->grp_lock); + return status; } PJ_DEF(pj_status_t) pj_stun_session_create_ind(pj_stun_session *sess, @@ -771,9 +796,17 @@ PJ_DEF(pj_status_t) pj_stun_session_create_ind(pj_stun_session *sess, PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); + pj_grp_lock_acquire(sess->grp_lock); + if (sess->is_destroying) { + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } + status = create_tdata(sess, &tdata); - if (status != PJ_SUCCESS) + if (status != PJ_SUCCESS) { + pj_grp_lock_release(sess->grp_lock); return status; + } /* Create STUN message */ msg_type |= PJ_STUN_INDICATION_BIT; @@ -781,10 +814,13 @@ PJ_DEF(pj_status_t) pj_stun_session_create_ind(pj_stun_session *sess, NULL, &tdata->msg); if (status != PJ_SUCCESS) { pj_pool_release(tdata->pool); + pj_grp_lock_release(sess->grp_lock); return status; } *p_tdata = tdata; + + pj_grp_lock_release(sess->grp_lock); return PJ_SUCCESS; } @@ -800,15 +836,24 @@ PJ_DEF(pj_status_t) pj_stun_session_create_res( pj_stun_session *sess, pj_status_t status; pj_stun_tx_data *tdata = NULL; + pj_grp_lock_acquire(sess->grp_lock); + if (sess->is_destroying) { + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } + status = create_tdata(sess, &tdata); - if (status != PJ_SUCCESS) + if (status != PJ_SUCCESS) { + pj_grp_lock_release(sess->grp_lock); return status; + } /* Create STUN response message */ status = pj_stun_msg_create_response(tdata->pool, rdata->msg, err_code, err_msg, &tdata->msg); if (status != PJ_SUCCESS) { pj_pool_release(tdata->pool); + pj_grp_lock_release(sess->grp_lock); return status; } @@ -823,6 +868,8 @@ PJ_DEF(pj_status_t) pj_stun_session_create_res( pj_stun_session *sess, *p_tdata = tdata; + pj_grp_lock_release(sess->grp_lock); + return PJ_SUCCESS; } @@ -869,6 +916,13 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); + /* Lock the session and prevent user from destroying us in the callback */ + pj_grp_lock_acquire(sess->grp_lock); + if (sess->is_destroying) { + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } + pj_log_push_indent(); /* Allocate packet */ @@ -878,10 +932,6 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, tdata->token = token; tdata->retransmit = retransmit; - /* Lock the session and prevent user from destroying us in the callback */ - pj_atomic_inc(sess->busy); - pj_lock_acquire(sess->lock); - /* Apply options */ status = apply_msg_options(sess, tdata->pool, &tdata->auth_info, tdata->msg); @@ -911,7 +961,8 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, if (PJ_STUN_IS_REQUEST(tdata->msg->hdr.type)) { /* Create STUN client transaction */ - status = pj_stun_client_tsx_create(sess->cfg, tdata->pool, + status = pj_stun_client_tsx_create(sess->cfg, tdata->pool, + sess->grp_lock, &tsx_cb, &tdata->client_tsx); PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); pj_stun_client_tsx_set_data(tdata->client_tsx, (void*)tdata); @@ -941,17 +992,17 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, pj_time_val timeout; pj_memset(&tdata->res_timer, 0, sizeof(tdata->res_timer)); - pj_timer_entry_init(&tdata->res_timer, PJ_TRUE, tdata, + pj_timer_entry_init(&tdata->res_timer, PJ_FALSE, tdata, &on_cache_timeout); timeout.sec = sess->cfg->res_cache_msec / 1000; timeout.msec = sess->cfg->res_cache_msec % 1000; - status = pj_timer_heap_schedule(sess->cfg->timer_heap, - &tdata->res_timer, - &timeout); + status = pj_timer_heap_schedule_w_grp_lock(sess->cfg->timer_heap, + &tdata->res_timer, + &timeout, PJ_TRUE, + sess->grp_lock); if (status != PJ_SUCCESS) { - tdata->res_timer.id = PJ_FALSE; pj_stun_msg_destroy_tdata(sess, tdata); LOG_ERR_(sess, "Error scheduling response timer", status); goto on_return; @@ -977,15 +1028,10 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, } on_return: - pj_lock_release(sess->lock); - pj_log_pop_indent(); - /* Check if application has called destroy() in the callback */ - if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { - pj_stun_session_destroy(sess); - return PJNATH_ESTUNDESTROYED; - } + if (pj_grp_lock_release(sess->grp_lock)) + return PJ_EGONE; return status; } @@ -1007,14 +1053,25 @@ PJ_DEF(pj_status_t) pj_stun_session_respond( pj_stun_session *sess, pj_str_t reason; pj_stun_tx_data *tdata; + pj_grp_lock_acquire(sess->grp_lock); + if (sess->is_destroying) { + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } + status = pj_stun_session_create_res(sess, rdata, code, (errmsg?pj_cstr(&reason,errmsg):NULL), &tdata); - if (status != PJ_SUCCESS) + if (status != PJ_SUCCESS) { + pj_grp_lock_release(sess->grp_lock); return status; + } - return pj_stun_session_send_msg(sess, token, cache, PJ_FALSE, - dst_addr, addr_len, tdata); + status = pj_stun_session_send_msg(sess, token, cache, PJ_FALSE, + dst_addr, addr_len, tdata); + + pj_grp_lock_release(sess->grp_lock); + return status; } @@ -1031,8 +1088,11 @@ PJ_DEF(pj_status_t) pj_stun_session_cancel_req( pj_stun_session *sess, PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(tdata->msg->hdr.type), PJ_EINVAL); /* Lock the session and prevent user from destroying us in the callback */ - pj_atomic_inc(sess->busy); - pj_lock_acquire(sess->lock); + pj_grp_lock_acquire(sess->grp_lock); + if (sess->is_destroying) { + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } if (notify) { (sess->cb.on_request_complete)(sess, notify_status, tdata->token, @@ -1042,12 +1102,7 @@ PJ_DEF(pj_status_t) pj_stun_session_cancel_req( pj_stun_session *sess, /* Just destroy tdata. This will destroy the transaction as well */ pj_stun_msg_destroy_tdata(sess, tdata); - pj_lock_release(sess->lock); - - if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { - pj_stun_session_destroy(sess); - return PJNATH_ESTUNDESTROYED; - } + pj_grp_lock_release(sess->grp_lock); return PJ_SUCCESS; } @@ -1056,7 +1111,8 @@ PJ_DEF(pj_status_t) pj_stun_session_cancel_req( pj_stun_session *sess, * Explicitly request retransmission of the request. */ PJ_DEF(pj_status_t) pj_stun_session_retransmit_req(pj_stun_session *sess, - pj_stun_tx_data *tdata) + pj_stun_tx_data *tdata, + pj_bool_t mod_count) { pj_status_t status; @@ -1064,17 +1120,15 @@ PJ_DEF(pj_status_t) pj_stun_session_retransmit_req(pj_stun_session *sess, PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(tdata->msg->hdr.type), PJ_EINVAL); /* Lock the session and prevent user from destroying us in the callback */ - pj_atomic_inc(sess->busy); - pj_lock_acquire(sess->lock); - - status = pj_stun_client_tsx_retransmit(tdata->client_tsx); + pj_grp_lock_acquire(sess->grp_lock); + if (sess->is_destroying) { + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } - pj_lock_release(sess->lock); + status = pj_stun_client_tsx_retransmit(tdata->client_tsx, mod_count); - if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { - pj_stun_session_destroy(sess); - return PJNATH_ESTUNDESTROYED; - } + pj_grp_lock_release(sess->grp_lock); return status; } @@ -1362,11 +1416,15 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL); - pj_log_push_indent(); - /* Lock the session and prevent user from destroying us in the callback */ - pj_atomic_inc(sess->busy); - pj_lock_acquire(sess->lock); + pj_grp_lock_acquire(sess->grp_lock); + + if (sess->is_destroying) { + pj_grp_lock_release(sess->grp_lock); + return PJ_EINVALIDOP; + } + + pj_log_push_indent(); /* Reset pool */ pj_pool_reset(sess->rx_pool); @@ -1419,17 +1477,10 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, } on_return: - pj_lock_release(sess->lock); - pj_log_pop_indent(); - /* If we've received destroy request while we're on the callback, - * destroy the session now. - */ - if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { - pj_stun_session_destroy(sess); - return PJNATH_ESTUNDESTROYED; - } + if (pj_grp_lock_release(sess->grp_lock)) + return PJ_EGONE; return status; } |