<p>Kevin Harwell has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/5822">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, 73 insertions(+), 2 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/22/5822/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 7fbeddc..9d0c915 100644<br>--- a/include/asterisk/res_pjsip_session.h<br>+++ b/include/asterisk/res_pjsip_session.h<br>@@ -145,6 +145,10 @@<br> pjsip_rx_data *deferred_reinvite;<br> /*! Current T.38 state */<br> enum ast_sip_session_t38state t38state;<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>@@ -459,6 +463,20 @@<br> void ast_sip_session_defer_termination(struct ast_sip_session *session);<br> <br> /*!<br>+ * \brief Defer the end of a session<br>+ *<br>+ * \param session The session to defer<br>+ */<br>+void ast_sip_session_defer_end(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 13ca01a..59a38ad 100644<br>--- a/res/res_pjsip_refer.c<br>+++ b/res/res_pjsip_refer.c<br>@@ -488,6 +488,8 @@<br> }<br> }<br> <br>+ ast_sip_session_end_if_deferred(attended->transferer);<br>+<br> return 0;<br> }<br> <br>@@ -656,8 +658,11 @@<br> return 500;<br> }<br> <br>+ ast_sip_session_defer_end(session);<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, attended)) {<br>+ ast_sip_session_end_if_deferred(session);<br> ao2_cleanup(attended);<br> return 500;<br> }<br>@@ -669,6 +674,7 @@<br> } else {<br> const char *context = pbx_builtin_getvar_helper(session->channel, "TRANSFER_CONTEXT");<br> struct refer_blind refer = { 0, };<br>+ enum ast_transfer_result transfer_result;<br> <br> if (ast_strlen_zero(context)) {<br> context = session->endpoint->context;<br>@@ -686,7 +692,12 @@<br> refer.replaces = replaces;<br> refer.refer_to = target_uri;<br> <br>- switch (ast_bridge_transfer_blind(1, session->channel, "external_replaces", context, refer_blind_callback, &refer)) {<br>+ ast_sip_session_defer_end(session);<br>+ transfer_result = ast_bridge_transfer_blind(1, session->channel,<br>+ "external_replaces", context, refer_blind_callback, &refer);<br>+ ast_sip_session_end_if_deferred(session);<br>+<br>+ switch (transfer_result) {<br> case AST_BRIDGE_TRANSFER_INVALID:<br> return 400;<br> case AST_BRIDGE_TRANSFER_NOT_PERMITTED:<br>@@ -697,6 +708,8 @@<br> ast_sip_session_defer_termination(session);<br> return 200;<br> }<br>+<br>+ ast_sip_session_end_if_deferred(session);<br> <br> return 503;<br> }<br>@@ -710,6 +723,7 @@<br> const char *context;<br> char exten[AST_MAX_EXTENSION];<br> struct refer_blind refer = { 0, };<br>+ enum ast_transfer_result transfer_result;<br> <br> /* If no explicit transfer context has been provided use their configured context */<br> context = pbx_builtin_getvar_helper(session->channel, "TRANSFER_CONTEXT");<br>@@ -730,7 +744,12 @@<br> refer.rdata = rdata;<br> refer.refer_to = target;<br> <br>- switch (ast_bridge_transfer_blind(1, session->channel, exten, context, refer_blind_callback, &refer)) {<br>+ ast_sip_session_defer_end(session);<br>+ transfer_result = ast_bridge_transfer_blind(1, session->channel, exten,<br>+ context, refer_blind_callback, &refer);<br>+ ast_sip_session_end_if_deferred(session);<br>+<br>+ switch (transfer_result) {<br> case AST_BRIDGE_TRANSFER_INVALID:<br> return 400;<br> case AST_BRIDGE_TRANSFER_NOT_PERMITTED:<br>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c<br>index a2b30a1..2832b36 100644<br>--- a/res/res_pjsip_session.c<br>+++ b/res/res_pjsip_session.c<br>@@ -1653,6 +1653,8 @@<br> return session;<br> }<br> <br>+static int session_end(struct ast_sip_session *session);<br>+<br> void ast_sip_session_terminate(struct ast_sip_session *session, int response)<br> {<br> pj_status_t status;<br>@@ -1730,6 +1732,30 @@<br> <br> if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &session->scheduled_termination, &delay) != PJ_SUCCESS) {<br> ao2_ref(session, -1);<br>+ }<br>+}<br>+<br>+void ast_sip_session_defer_end(struct ast_sip_session *session)<br>+{<br>+ ast_assert(!session->defer_end);<br>+<br>+ session->defer_end = 1;<br>+ session->ended_while_deferred = 0;<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>@@ -2349,6 +2375,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> session_end(session);<br> }<br> }<br>diff --git a/res/res_pjsip_session.exports.in b/res/res_pjsip_session.exports.in<br>index 5a21b1d..4af9933 100644<br>--- a/res/res_pjsip_session.exports.in<br>+++ b/res/res_pjsip_session.exports.in<br>@@ -2,6 +2,8 @@<br> global:<br> LINKER_SYMBOL_PREFIXast_sip_session_terminate;<br> LINKER_SYMBOL_PREFIXast_sip_session_defer_termination;<br>+ LINKER_SYMBOL_PREFIXast_sip_session_defer_end;<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/5822">change 5822</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/5822"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: certified/13.1 </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: 5822 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Kevin Harwell <kharwell@digium.com> </div>