mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-04 03:20:33 +00:00
213 lines
6.1 KiB
Diff
213 lines
6.1 KiB
Diff
![]() |
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.
|
||
|
|
||
|
Index: pjsip/include/pjsip-ua/sip_inv.h
|
||
|
===================================================================
|
||
|
--- a/pjsip/include/pjsip-ua/sip_inv.h (revision 5434)
|
||
|
+++ b/pjsip/include/pjsip-ua/sip_inv.h (revision 5435)
|
||
|
@@ -383,6 +383,11 @@
|
||
|
* 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_timer *timer; /**< Session Timers. */
|
||
|
pj_bool_t following_fork; /**< Internal, following
|
||
|
forked media? */
|
||
|
+ pj_atomic_t *ref_cnt; /**< Reference counter. */
|
||
|
};
|
||
|
|
||
|
|
||
|
@@ -631,6 +637,30 @@
|
||
|
|
||
|
|
||
|
/**
|
||
|
+ * 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
|
||
|
Index: pjsip/src/pjsip-ua/sip_inv.c
|
||
|
===================================================================
|
||
|
--- a/pjsip/src/pjsip-ua/sip_inv.c (revision 5434)
|
||
|
+++ b/pjsip/src/pjsip-ua/sip_inv.c (revision 5435)
|
||
|
@@ -195,6 +195,65 @@
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
+ * 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 @@
|
||
|
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 @@
|
||
|
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 @@
|
||
|
pjsip_100rel_attach(inv);
|
||
|
|
||
|
/* Done */
|
||
|
+ pjsip_inv_add_ref(inv);
|
||
|
*p_inv = inv;
|
||
|
|
||
|
pjsip_dlg_dec_lock(dlg);
|
||
|
@@ -1471,6 +1517,12 @@
|
||
|
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 @@
|
||
|
}
|
||
|
|
||
|
/* Done */
|
||
|
+ pjsip_inv_add_ref(inv);
|
||
|
pjsip_dlg_dec_lock(dlg);
|
||
|
*p_inv = inv;
|
||
|
|