<p>Kevin Harwell has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/5813">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_refer/session: Calls dropped during transfer<br><br>When doing an attended transfer it's possible for the transferer, after<br>receiving an accepted response from Asterisk, to send a BYE to Asterisk,<br>which can then be processed before Asterisk has time to start and/or<br>complete the transfer process. This of course causes the transfer to not<br>complete successfully, thus dropping the call.<br><br>This patch makes it so any BYEs received from the transferer, after the REFER,<br>that initiate a session end are deferred until the transfer is complete. This<br>allows the channel that would have otherwise been hung up by Asterisk to<br>remain available throughout the transfer process.<br><br>ASTERISK-27053 #close<br><br>Change-Id: I43586db79079457d92d71f1fd993be9a3b409d5a<br>---<br>M include/asterisk/res_pjsip_session.h<br>M res/res_pjsip_refer.c<br>M res/res_pjsip_session.c<br>M res/res_pjsip_session.exports.in<br>4 files changed, 46 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/13/5813/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h<br>index 10e55f1..e2a9066 100644<br>--- a/include/asterisk/res_pjsip_session.h<br>+++ b/include/asterisk/res_pjsip_session.h<br>@@ -155,6 +155,10 @@<br> struct ast_sip_aor *aor;<br> /*! From header saved at invite creation */<br> pjsip_fromto_hdr *saved_from_hdr;<br>+ /*! Whether the end of the session should be deferred */<br>+ unsigned int defer_end:1;<br>+ /*! Session end (remote hangup) requested while termination deferred */<br>+ unsigned int ended_while_deferred:1;<br> };<br> <br> typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);<br>@@ -484,6 +488,13 @@<br> void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session);<br> <br> /*!<br>+ * \brief End the session if it had been previously deferred<br>+ *<br>+ * \param session The session to end if it had been deferred<br>+ */<br>+void ast_sip_session_end_if_deferred(struct ast_sip_session *session);<br>+<br>+/*!<br> * \brief Register an SDP handler<br> *<br> * An SDP handler is responsible for parsing incoming SDP streams and ensuring that<br>diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c<br>index 4629538..456e09d 100644<br>--- a/res/res_pjsip_refer.c<br>+++ b/res/res_pjsip_refer.c<br>@@ -543,6 +543,7 @@<br> }<br> }<br> <br>+ ast_sip_session_end_if_deferred(attended->transferer);<br> if (response != 200) {<br> if (!ast_sip_push_task(attended->transferer->serializer,<br> defer_termination_cancel, attended->transferer)) {<br>@@ -772,6 +773,7 @@<br> <br> /* Push it to the other session, which will have both channels with minimal locking */<br> if (ast_sip_push_task(other_session->serializer, refer_attended_task, attended)) {<br>+ ast_sip_session_end_if_deferred(session);<br> ast_sip_session_defer_termination_cancel(session);<br> ao2_cleanup(attended);<br> return 500;<br>@@ -810,9 +812,12 @@<br> <br> response = xfer_response_code2sip(ast_bridge_transfer_blind(1, session->channel,<br> "external_replaces", context, refer_blind_callback, &refer));<br>+<br>+ ast_sip_session_end_if_deferred(session);<br> if (response != 200) {<br> ast_sip_session_defer_termination_cancel(session);<br> }<br>+<br> return response;<br> }<br> }<br>@@ -865,9 +870,12 @@<br> <br> response = xfer_response_code2sip(ast_bridge_transfer_blind(1, session->channel,<br> exten, context, refer_blind_callback, &refer));<br>+<br>+ ast_sip_session_end_if_deferred(session);<br> if (response != 200) {<br> ast_sip_session_defer_termination_cancel(session);<br> }<br>+<br> return response;<br> }<br> <br>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c<br>index eb0d1f0..2949d5b 100644<br>--- a/res/res_pjsip_session.c<br>+++ b/res/res_pjsip_session.c<br>@@ -1903,6 +1903,9 @@<br> <br> session->defer_terminate = 1;<br> <br>+ session->defer_end = 1;<br>+ session->ended_while_deferred = 0;<br>+<br> session->scheduled_termination.id = 0;<br> ao2_ref(session, +1);<br> session->scheduled_termination.user_data = session;<br>@@ -1940,6 +1943,7 @@<br> /* Already canceled or timer fired. */<br> return;<br> }<br>+<br> session->defer_terminate = 0;<br> <br> if (session->terminate_while_deferred) {<br>@@ -1949,6 +1953,22 @@<br> <br> /* Stop the termination timer if it is still running. */<br> sip_session_defer_termination_stop_timer(session);<br>+}<br>+<br>+void ast_sip_session_end_if_deferred(struct ast_sip_session *session)<br>+{<br>+ if (!session->defer_end) {<br>+ return;<br>+ }<br>+<br>+ session->defer_end = 0;<br>+<br>+ if (session->ended_while_deferred) {<br>+ /* Complete the session end started by the remote hangup. */<br>+ ast_debug(3, "Ending session (%p) after being deferred\n", session);<br>+ session->ended_while_deferred = 0;<br>+ session_end(session);<br>+ }<br> }<br> <br> struct ast_sip_session *ast_sip_dialog_get_session(pjsip_dialog *dlg)<br>@@ -2668,6 +2688,12 @@<br> }<br> <br> if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {<br>+ if (session->defer_end) {<br>+ ast_debug(3, "Deferring session (%p) end\n", session);<br>+ session->ended_while_deferred = 1;<br>+ return;<br>+ }<br>+<br> if (ast_sip_push_task(session->serializer, session_end, session)) {<br> /* Do it anyway even though this is not the right thread. */<br> session_end(session);<br>diff --git a/res/res_pjsip_session.exports.in b/res/res_pjsip_session.exports.in<br>index a39485e..fdfc5fb 100644<br>--- a/res/res_pjsip_session.exports.in<br>+++ b/res/res_pjsip_session.exports.in<br>@@ -3,6 +3,7 @@<br> LINKER_SYMBOL_PREFIXast_sip_session_terminate;<br> LINKER_SYMBOL_PREFIXast_sip_session_defer_termination;<br> LINKER_SYMBOL_PREFIXast_sip_session_defer_termination_cancel;<br>+ LINKER_SYMBOL_PREFIXast_sip_session_end_if_deferred;<br> LINKER_SYMBOL_PREFIXast_sip_session_register_sdp_handler;<br> LINKER_SYMBOL_PREFIXast_sip_session_unregister_sdp_handler;<br> LINKER_SYMBOL_PREFIXast_sip_session_register_supplement;<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/5813">change 5813</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/5813"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 14 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I43586db79079457d92d71f1fd993be9a3b409d5a </div>
<div style="display:none"> Gerrit-Change-Number: 5813 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Kevin Harwell <kharwell@digium.com> </div>