diff options
author | Riza Sulistyo <riza@teluu.com> | 2016-08-30 08:40:18 +0000 |
---|---|---|
committer | Riza Sulistyo <riza@teluu.com> | 2016-08-30 08:40:18 +0000 |
commit | a097c5c02918f7813e107d2365f1cc70055fc551 (patch) | |
tree | 932b1896503acea003e17bfaf83900b082ad018c | |
parent | 5dab3c71aadd09ccd6c242856068571dd30380bc (diff) |
Re #1959: Add reference counter to pjsip_inv_session to avoid race condition.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5435 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r-- | pjsip/include/pjsip-ua/sip_inv.h | 30 | ||||
-rw-r--r-- | pjsip/src/pjsip-ua/sip_inv.c | 95 |
2 files changed, 104 insertions, 21 deletions
diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h index 4f9777ca..8e458bca 100644 --- a/pjsip/include/pjsip-ua/sip_inv.h +++ b/pjsip/include/pjsip-ua/sip_inv.h @@ -383,6 +383,11 @@ struct pjsip_timer; * Other applications that want to use these pools must understand * that the flip-flop pool's lifetimes are synchronized to the * SDP offer-answer negotiation. + * + * The lifetime of this session is controlled by the reference counter in this + * structure, which is manipulated by calling #pjsip_inv_add_ref and + * #pjsip_inv_dec_ref. When the reference counter has reached zero, then + * this session will be destroyed. */ struct pjsip_inv_session { @@ -412,6 +417,7 @@ struct pjsip_inv_session struct pjsip_timer *timer; /**< Session Timers. */ pj_bool_t following_fork; /**< Internal, following forked media? */ + pj_atomic_t *ref_cnt; /**< Reference counter. */ }; @@ -631,6 +637,30 @@ PJ_DECL(pj_status_t) pjsip_inv_create_uas(pjsip_dialog *dlg, /** + * Add reference counter to the INVITE session. The reference counter controls + * the life time of the session, ie. when the counter reaches zero, then it + * will be destroyed. + * + * @param inv The INVITE session. + * @return PJ_SUCCESS if the INVITE session reference counter + * was increased. + */ +PJ_DECL(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv ); + +/** + * Decrement reference counter of the INVITE session. + * When the session is no longer used, it will be destroyed and + * caller is informed with PJ_EGONE return status. + * + * @param inv The INVITE session. + * @return PJ_SUCCESS if the INVITE session reference counter + * was decreased. A status PJ_EGONE will be returned to + * inform that session is destroyed. + */ +PJ_DECL(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv ); + + +/** * Forcefully terminate and destroy INVITE session, regardless of * the state of the session. Note that this function should only be used * when there is failure in the INVITE session creation. After the diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c index a8882b55..fbc8ebed 100644 --- a/pjsip/src/pjsip-ua/sip_inv.c +++ b/pjsip/src/pjsip-ua/sip_inv.c @@ -195,6 +195,65 @@ static pj_status_t mod_inv_unload(void) } /* + * Add reference to INVITE session. + */ +PJ_DEF(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv ) +{ + PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL); + + pj_atomic_inc(inv->ref_cnt); + + return PJ_SUCCESS; +} + +static void inv_session_destroy(pjsip_inv_session *inv) +{ + if (inv->last_ack) { + pjsip_tx_data_dec_ref(inv->last_ack); + inv->last_ack = NULL; + } + if (inv->invite_req) { + pjsip_tx_data_dec_ref(inv->invite_req); + inv->invite_req = NULL; + } + if (inv->pending_bye) { + pjsip_tx_data_dec_ref(inv->pending_bye); + inv->pending_bye = NULL; + } + pjsip_100rel_end_session(inv); + pjsip_timer_end_session(inv); + pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); + + /* Release the flip-flop pools */ + pj_pool_release(inv->pool_prov); + inv->pool_prov = NULL; + pj_pool_release(inv->pool_active); + inv->pool_active = NULL; + + pj_atomic_destroy(inv->ref_cnt); + inv->ref_cnt = NULL; +} + +/* + * Decrease INVITE session reference, destroy it when the reference count + * reaches zero. + */ +PJ_DEF(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv ) +{ + pj_atomic_value_t ref_cnt; + + PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL); + + ref_cnt = pj_atomic_dec_and_get(inv->ref_cnt); + pj_assert( ref_cnt >= 0); + if (ref_cnt == 0) { + inv_session_destroy(inv); + return PJ_EGONE; + } + return PJ_SUCCESS; +} + +/* * Set session state. */ static void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state, @@ -261,27 +320,7 @@ static void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state, if (inv->state == PJSIP_INV_STATE_DISCONNECTED && prev_state != PJSIP_INV_STATE_DISCONNECTED) { - if (inv->last_ack) { - pjsip_tx_data_dec_ref(inv->last_ack); - inv->last_ack = NULL; - } - if (inv->invite_req) { - pjsip_tx_data_dec_ref(inv->invite_req); - inv->invite_req = NULL; - } - if (inv->pending_bye) { - pjsip_tx_data_dec_ref(inv->pending_bye); - inv->pending_bye = NULL; - } - pjsip_100rel_end_session(inv); - pjsip_timer_end_session(inv); - pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); - - /* Release the flip-flop pools */ - pj_pool_release(inv->pool_prov); - inv->pool_prov = NULL; - pj_pool_release(inv->pool_active); - inv->pool_active = NULL; + pjsip_inv_dec_ref(inv); } } @@ -838,6 +877,12 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg, inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session); pj_assert(inv != NULL); + status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt); + if (status != PJ_SUCCESS) { + pjsip_dlg_dec_lock(dlg); + return status; + } + inv->pool = dlg->pool; inv->role = PJSIP_ROLE_UAC; inv->state = PJSIP_INV_STATE_NULL; @@ -881,6 +926,7 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg, pjsip_100rel_attach(inv); /* Done */ + pjsip_inv_add_ref(inv); *p_inv = inv; pjsip_dlg_dec_lock(dlg); @@ -1471,6 +1517,12 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg, inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session); pj_assert(inv != NULL); + status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt); + if (status != PJ_SUCCESS) { + pjsip_dlg_dec_lock(dlg); + return status; + } + inv->pool = dlg->pool; inv->role = PJSIP_ROLE_UAS; inv->state = PJSIP_INV_STATE_NULL; @@ -1540,6 +1592,7 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg, } /* Done */ + pjsip_inv_add_ref(inv); pjsip_dlg_dec_lock(dlg); *p_inv = inv; |