From bc1e13dfc3f77c8a6bc07d50552638c1eb1563b3 Mon Sep 17 00:00:00 2001
From: Matthew Jordan <mjordan@digium.com>
Date: Mon, 9 Feb 2015 02:44:24 +0000
Subject: [PATCH] channels/chan_sip: Ensure that a BYE is sent during INVITE
 w/Replaces transfer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Consider a scenario where Alice and Bob have an established dialog with each
other external to Asterisk. Bob decides to perform an attended transfer of
Alice to Asterisk. In this case, Alice will send an INVITE with Replaces
to Asterisk, where the Replaces specifies Bob's dialog with Asterisk. In this
particular scenario, Asterisk will complete the transfer, but - since Bob's
channel has had Alice masqueraded into it and is now a Zombie - a BYE
request will not be sent.

This patch fixes that issue by adding a new flag to chan_sip that tracks
whether or not we have an INVITE with Replaces. If we do, the flag is used
on the sip_pvt to ensure that a BYE request is sent, even if the channel has
been masqueraded away.

Review: https://reviewboard.asterisk.org/r/4362/

ASTERISK-22436 #close
Reported by: Eelco Brolman
Tested by: Jeremiah Gowdy, Kristian Høgh
patches:
  asterisk-11-hangup-replaced-3.diff uploaded by Jeremiah Gowdy (License 6358)


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@431620 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 channels/chan_sip.c        | 10 +++++++++-
 channels/sip/include/sip.h |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 52874228d2..1feccba01f 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -7044,7 +7044,7 @@ static int sip_hangup(struct ast_channel *ast)
 				}
 
 				/* Send a hangup */
-				if (ast_channel_state(oldowner) == AST_STATE_UP) {
+				if (ast_channel_state(oldowner) == AST_STATE_UP || p->invitereplaces) {
 					transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
 				}
 
@@ -8591,6 +8591,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
 	make_our_tag(p);
 	p->ocseq = INITIAL_CSEQ;
 	p->allowed_methods = UINT_MAX;
+	p->invitereplaces = 0;
 
 	if (sip_methods[intended_method].need_rtp) {
 		p->maxcallbitrate = default_maxcallbitrate;
@@ -24917,6 +24918,8 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, st
 	struct ast_channel *replacecall = p->refer->refer_call->owner;	/* The channel we're about to take over */
 	struct ast_channel *targetcall;		/* The bridge to the take-over target */
 
+	p->refer->refer_call->invitereplaces = 1;
+
 	/* Check if we're in ring state */
 	if (ast_channel_state(replacecall) == AST_STATE_RING)
 		earlyreplace = 1;
@@ -25026,6 +25029,11 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, st
 		ast_channel_unlock(c);
 	}
 
+	/* Clear SIP_DEFER_BYE_ON_TRANSFER after the masq to avoid delay hanging up replaced channel */
+	sip_pvt_lock(p);
+	ast_clear_flag(&p->refer->refer_call->flags[0], SIP_DEFER_BYE_ON_TRANSFER);
+	sip_pvt_unlock(p);
+
 	/* c and c's tech pvt must be unlocked at this point for ast_hangup */
 	ast_hangup(c);
 	/* this indicates to handle_request_do that the owner channel has already been unlocked */
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index 6b448bf075..87a8c68e32 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -1100,6 +1100,7 @@ struct sip_pvt {
 	                                       */
 	unsigned short req_secure_signaling:1;/*!< Whether we are required to have secure signaling or not */
 	unsigned short natdetected:1;         /*!< Whether we detected a NAT when processing the Via */
+	unsigned short invitereplaces:1;      /*!< Whether we are doing an Invite: Replaces */
 	int timer_t1;                     /*!< SIP timer T1, ms rtt */
 	int timer_b;                      /*!< SIP timer B, ms */
 	unsigned int sipoptions;          /*!< Supported SIP options on the other end */
-- 
GitLab