diff options
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2010-03-06 14:16:20 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2010-03-06 14:16:20 +0000
commit5e8a340e01fa2bf47fb3f07aac63d59207b8965c (patch)
parent77cb4d4a4c4cf6221ec7a73ad16d5da5a4dc0ce2 (diff)
Fix a crash in SIP blind transfer handling found by an automated external test.
The first real test added to the external test suite found a pretty nasty crash that occurred in Asterisk trunk. The crash was due to a race condition between the REFER handling and channel destruction in the channel thread. After the transfer has been completed, we go back to the transferrer channel and try to lock it so we can fire off a CEL event. However, there was no guarantee that the channel was still around at that point since it's racing against the channel thread. Since ast_channel is a reference counted object, the fix is simple. The code unlocks the transferrer channel before finally completing the transfer with an async goto. At this point the channel thread is going to start call tear down and the channel will eventually be destroyed. To ensure that the channel is valid when we want to fire off the CEL event, increase the channel's reference count. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@251137 f38db490-d61c-443f-a65b-d21fe96a405b
1 files changed, 9 insertions, 0 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 793a31b3c..b8f93b583 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -20089,6 +20089,11 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
/* Must release lock now, because it will not longer
be accessible after the transfer! */
*nounlock = 1;
+ /*
+ * Increase ref count so that we can delay channel destruction until after
+ * we get a chance to fire off some events.
+ */
+ ast_channel_ref(current.chan1);
/* Connect the call */
@@ -20113,6 +20118,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
transmit_notify_with_sipfrag(p, seqno, "503 Service Unavailable (can't handle one-legged xfers)", TRUE);
ast_clear_flag(&p->flags[0], SIP_GOTREFER);
append_history(p, "Xfer", "Refer failed (only bridged calls).");
+ ast_channel_unref(current.chan1);
return -1;
ast_set_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */
@@ -20163,6 +20169,9 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
ast_clear_flag(&p->flags[0], SIP_GOTREFER);
res = -1;
+ ast_channel_unref(current.chan1);
return res;