summaryrefslogtreecommitdiff
path: root/channels/chan_sip.c
diff options
context:
space:
mode:
authorAlec L Davis <sivad.a@paradise.net.nz>2011-02-25 18:58:10 +0000
committerAlec L Davis <sivad.a@paradise.net.nz>2011-02-25 18:58:10 +0000
commitb6e37118c9220f65e9bcb77bf88ccb46796906a2 (patch)
tree05b4cd119d2d4b9cd137ef9b72ab07da4fad9af7 /channels/chan_sip.c
parent642d6c306c8e9146bf85c3080ec9af4bef3fd011 (diff)
Merged revisions 308945 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r308945 | alecdavis | 2011-02-26 07:52:53 +1300 (Sat, 26 Feb 2011) | 21 lines Fix Deadlock with attended transfer of SIP call Call path sip_set_rtp_peer (locks chan then pvt) transmit_reinvite_with_sdp try_suggested_sip_codec pbx_builtin_getvar_helper (locks p->owner) But by the time p->owner lock was attempted, seems as though chan and p->owner were different. So in sip_set_rtp_peer, lock pvt first then lock p->owner using deadlocking methods. (closes issue #18837) Reported by: alecdavis Patches: bug18837-trunk.diff3.txt uploaded by alecdavis (license 585) Tested by: alecdavis, Irontec, ZX81, cmaj Review: [https://reviewboard.asterisk.org/r/1126/] ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@308946 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r--channels/chan_sip.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index e9ef2d695..79e570b39 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -27966,7 +27966,20 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
if (!p) {
return -1;
}
+ /*
+ * Lock both the pvt and it's owner safely.
+ */
sip_pvt_lock(p);
+ while (p->owner && ast_channel_trylock(p->owner)) {
+ sip_pvt_unlock(p);
+ usleep(1);
+ sip_pvt_lock(p);
+ }
+
+ if (!p->owner) {
+ sip_pvt_unlock(p);
+ return 0;
+ }
if (udptl) {
ast_udptl_get_peer(udptl, &p->udptlredirip);
} else {
@@ -27985,6 +27998,7 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
}
/* Reset lastrtprx timer */
p->lastrtprx = p->lastrtptx = time(NULL);
+ ast_channel_unlock(p->owner);
sip_pvt_unlock(p);
return 0;
}
@@ -28102,12 +28116,25 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
return 0;
}
- ast_channel_lock(chan);
+ /*
+ * Lock both the pvt and it's owner safely.
+ */
sip_pvt_lock(p);
+ while (p->owner && ast_channel_trylock(p->owner)) {
+ sip_pvt_unlock(p);
+ usleep(1);
+ sip_pvt_lock(p);
+ }
+
+ if (!p->owner) {
+ sip_pvt_unlock(p);
+ return 0;
+ }
+
if (p->alreadygone) {
/* If we're destroyed, don't bother */
+ ast_channel_unlock(p->owner);
sip_pvt_unlock(p);
- ast_channel_unlock(chan);
return 0;
}
@@ -28115,8 +28142,8 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
that are known to be behind a NAT, then stop the process now
*/
if (nat_active && !ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) {
+ ast_channel_unlock(p->owner);
sip_pvt_unlock(p);
- ast_channel_unlock(chan);
return 0;
}
@@ -28158,8 +28185,8 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i
}
/* Reset lastrtprx timer */
p->lastrtprx = p->lastrtptx = time(NULL);
+ ast_channel_unlock(p->owner);
sip_pvt_unlock(p);
- ast_channel_unlock(chan);
return 0;
}