summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiza Sulistyo <riza@teluu.com>2016-08-30 08:40:18 +0000
committerRiza Sulistyo <riza@teluu.com>2016-08-30 08:40:18 +0000
commita097c5c02918f7813e107d2365f1cc70055fc551 (patch)
tree932b1896503acea003e17bfaf83900b082ad018c
parent5dab3c71aadd09ccd6c242856068571dd30380bc (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.h30
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c95
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;