[Asterisk-code-review] res pjsip refer/session: Calls dropped during transfer (asterisk[certified/13.13])

Jenkins2 asteriskteam at digium.com
Fri Jun 16 17:20:04 CDT 2017


Jenkins2 has submitted this change and it was merged. ( https://gerrit.asterisk.org/5821 )

Change subject: res_pjsip_refer/session: Calls dropped during transfer
......................................................................

res_pjsip_refer/session: Calls dropped during transfer

When doing an attended transfer it's possible for the transferer, after
receiving an accepted response from Asterisk, to send a BYE to Asterisk,
which can then be processed before Asterisk has time to start and/or
complete the transfer process. This of course causes the transfer to not
complete successfully, thus dropping the call.

This patch makes it so any BYEs received from the transferer, after the REFER,
that initiate a session end are deferred until the transfer is complete. This
allows the channel that would have otherwise been hung up by Asterisk to
remain available throughout the transfer process.

ASTERISK-27053 #close

Change-Id: I43586db79079457d92d71f1fd993be9a3b409d5a
---
M include/asterisk/res_pjsip_session.h
M res/res_pjsip_refer.c
M res/res_pjsip_session.c
M res/res_pjsip_session.exports.in
4 files changed, 48 insertions(+), 0 deletions(-)

Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved
  Jenkins2: Approved for Submit



diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
index 7e65e6d..c9a41f8 100644
--- a/include/asterisk/res_pjsip_session.h
+++ b/include/asterisk/res_pjsip_session.h
@@ -151,6 +151,10 @@
 	struct ast_sip_aor *aor;
 	/*! From header saved at invite creation */
 	pjsip_fromto_hdr *saved_from_hdr;
+	/*! Whether the end of the session should be deferred */
+	unsigned int defer_end:1;
+	/*! Session end (remote hangup) requested while termination deferred */
+	unsigned int ended_while_deferred:1;
 };
 
 typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
@@ -476,6 +480,13 @@
 void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session);
 
 /*!
+ * \brief End the session if it had been previously deferred
+ *
+ * \param session The session to end if it had been deferred
+ */
+void ast_sip_session_end_if_deferred(struct ast_sip_session *session);
+
+/*!
  * \brief Register an SDP handler
  *
  * An SDP handler is responsible for parsing incoming SDP streams and ensuring that
diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c
index 99295d5..06f709e 100644
--- a/res/res_pjsip_refer.c
+++ b/res/res_pjsip_refer.c
@@ -539,6 +539,7 @@
 		}
 	}
 
+	ast_sip_session_end_if_deferred(attended->transferer);
 	if (response != 200) {
 		if (!ast_sip_push_task(attended->transferer->serializer,
 			defer_termination_cancel, attended->transferer)) {
@@ -757,6 +758,7 @@
 
 		/* Push it to the other session, which will have both channels with minimal locking */
 		if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {
+			ast_sip_session_end_if_deferred(session);
 			ast_sip_session_defer_termination_cancel(session);
 			ao2_cleanup(attended);
 			return 500;
@@ -794,9 +796,12 @@
 
 		response = xfer_response_code2sip(ast_bridge_transfer_blind(1, session->channel,
 			"external_replaces", context, refer_blind_callback, &refer));
+
+		ast_sip_session_end_if_deferred(session);
 		if (response != 200) {
 			ast_sip_session_defer_termination_cancel(session);
 		}
+
 		return response;
 	}
 }
@@ -841,9 +846,12 @@
 
 	response = xfer_response_code2sip(ast_bridge_transfer_blind(1, session->channel,
 		exten, context, refer_blind_callback, &refer));
+
+	ast_sip_session_end_if_deferred(session);
 	if (response != 200) {
 		ast_sip_session_defer_termination_cancel(session);
 	}
+
 	return response;
 }
 
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 60850f0..0954a85 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1849,6 +1849,8 @@
 	}
 }
 
+static int session_end(void *vsession);
+
 static int session_termination_task(void *data)
 {
 	struct ast_sip_session *session = data;
@@ -1882,6 +1884,9 @@
 	ast_assert(!session->defer_terminate);
 
 	session->defer_terminate = 1;
+
+	session->defer_end = 1;
+	session->ended_while_deferred = 0;
 
 	session->scheduled_termination.id = 0;
 	ao2_ref(session, +1);
@@ -1920,6 +1925,7 @@
 		/* Already canceled or timer fired. */
 		return;
 	}
+
 	session->defer_terminate = 0;
 
 	if (session->terminate_while_deferred) {
@@ -1929,6 +1935,22 @@
 
 	/* Stop the termination timer if it is still running. */
 	sip_session_defer_termination_stop_timer(session);
+}
+
+void ast_sip_session_end_if_deferred(struct ast_sip_session *session)
+{
+	if (!session->defer_end) {
+		return;
+	}
+
+	session->defer_end = 0;
+
+	if (session->ended_while_deferred) {
+		/* Complete the session end started by the remote hangup. */
+		ast_debug(3, "Ending session (%p) after being deferred\n", session);
+		session->ended_while_deferred = 0;
+		session_end(session);
+	}
 }
 
 struct ast_sip_session *ast_sip_dialog_get_session(pjsip_dialog *dlg)
@@ -2620,6 +2642,12 @@
 	}
 
 	if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
+		if (session->defer_end) {
+			ast_debug(3, "Deferring session (%p) end\n", session);
+			session->ended_while_deferred = 1;
+			return;
+		}
+
 		if (ast_sip_push_task(session->serializer, session_end, session)) {
 			/* Do it anyway even though this is not the right thread. */
 			session_end(session);
diff --git a/res/res_pjsip_session.exports.in b/res/res_pjsip_session.exports.in
index a39485e..fdfc5fb 100644
--- a/res/res_pjsip_session.exports.in
+++ b/res/res_pjsip_session.exports.in
@@ -3,6 +3,7 @@
 		LINKER_SYMBOL_PREFIXast_sip_session_terminate;
 		LINKER_SYMBOL_PREFIXast_sip_session_defer_termination;
 		LINKER_SYMBOL_PREFIXast_sip_session_defer_termination_cancel;
+		LINKER_SYMBOL_PREFIXast_sip_session_end_if_deferred;
 		LINKER_SYMBOL_PREFIXast_sip_session_register_sdp_handler;
 		LINKER_SYMBOL_PREFIXast_sip_session_unregister_sdp_handler;
 		LINKER_SYMBOL_PREFIXast_sip_session_register_supplement;

-- 
To view, visit https://gerrit.asterisk.org/5821
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: certified/13.13
Gerrit-MessageType: merged
Gerrit-Change-Id: I43586db79079457d92d71f1fd993be9a3b409d5a
Gerrit-Change-Number: 5821
Gerrit-PatchSet: 2
Gerrit-Owner: Kevin Harwell <kharwell at digium.com>
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Jenkins2
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20170616/c1eeb98c/attachment.html>


More information about the asterisk-code-review mailing list