[Pkg-voip-commits] [pjproject] 05/14: asterisk/0002-r5435-add-pjsip_inv_session-ref_cnt

Bernhard Schmidt berni at moszumanska.debian.org
Thu Nov 10 09:32:01 UTC 2016


This is an automated email from the git hooks/post-receive script.

berni pushed a commit to branch master
in repository pjproject.

commit cb55bebea5f2a6b1153d70e141b0674541324553
Author: Bernhard Schmidt <berni at debian.org>
Date:   Thu Nov 10 09:45:56 2016 +0100

    asterisk/0002-r5435-add-pjsip_inv_session-ref_cnt
    
    When a transport error occured on an INVITE session
    the stack calls on_tsx_state_changed with new state
    PJSIP_INV_STATE_DISCONNECTED and immediately destroys
    the INVITE session.
    At the same time this INVITE session could being processed
    on another thread. This thread could use the session's
    memory pools which were already freed, so we get segfault.
    
    This patch adds a reference counter and new functions:
    pjsip_inv_add_ref and pjsip_inv_dec_ref.
    The INVITE session is destroyed only when the reference
    counter has reached zero.
    
    To avoid race condition an application should call
    pjsip_inv_add_ref/pjsip_inv_dec_ref.
    
    Patch-Category: asterisk
---
 pjsip/include/pjsip-ua/sip_inv.h | 30 +++++++++++++
 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 c4fa97f..8915fe0 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 2ab0715..4bb6f33 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,
@@ -260,27 +319,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);
     }
 }
 
@@ -837,6 +876,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;
@@ -880,6 +925,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);
@@ -1470,6 +1516,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;
@@ -1539,6 +1591,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;
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/pjproject.git



More information about the Pkg-voip-commits mailing list