summaryrefslogtreecommitdiff
path: root/res/res_pjsip_session.c
diff options
context:
space:
mode:
authorKevin Harwell <kharwell@digium.com>2017-06-13 14:17:29 -0500
committerKevin Harwell <kharwell@digium.com>2017-06-13 14:28:11 -0500
commit3a8cb4986d1d7dfb73248c042782e0aea5c2a2c1 (patch)
tree0b4ab91f1df42a03c15a0d743c0ad73ea820e4a4 /res/res_pjsip_session.c
parent7994914c882874593eb17fdd8c910ee418f44a1b (diff)
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
Diffstat (limited to 'res/res_pjsip_session.c')
-rw-r--r--res/res_pjsip_session.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index eb0d1f054..2949d5b2a 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1903,6 +1903,9 @@ int ast_sip_session_defer_termination(struct ast_sip_session *session)
session->defer_terminate = 1;
+ session->defer_end = 1;
+ session->ended_while_deferred = 0;
+
session->scheduled_termination.id = 0;
ao2_ref(session, +1);
session->scheduled_termination.user_data = session;
@@ -1940,6 +1943,7 @@ void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session)
/* Already canceled or timer fired. */
return;
}
+
session->defer_terminate = 0;
if (session->terminate_while_deferred) {
@@ -1951,6 +1955,22 @@ void ast_sip_session_defer_termination_cancel(struct ast_sip_session *session)
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)
{
pjsip_inv_session *inv_session = pjsip_dlg_get_inv_session(dlg);
@@ -2668,6 +2688,12 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
}
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);