aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_sip.c
diff options
context:
space:
mode:
authordvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b>2010-02-23 16:37:48 +0000
committerdvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b>2010-02-23 16:37:48 +0000
commit96f3e06cd488eb56d482e9230d68240618fc0c63 (patch)
tree70f0864c2430792d2e92b14f04ade1099845c144 /channels/chan_sip.c
parenteb48370f32bb7f8119df965e4362f7ef24c91db8 (diff)
Merged revisions 248397 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk ................ r248397 | dvossel | 2010-02-23 10:34:39 -0600 (Tue, 23 Feb 2010) | 15 lines Merged revisions 248396 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r248396 | dvossel | 2010-02-23 10:26:05 -0600 (Tue, 23 Feb 2010) | 9 lines fixes invite with replaces deadlock (closes issue #16862) Reported by: pwalker Patches: replaces_deadlock_1.4 uploaded by dvossel (license 671) Tested by: pwalker, dvossel ........ ................ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.2@248398 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r--channels/chan_sip.c72
1 files changed, 53 insertions, 19 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index e99a67a03..6ebd8b5bd 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -19641,6 +19641,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
int gotdest;
const char *p_replaces;
char *replace_id = NULL;
+ int refer_locked = 0;
const char *required;
unsigned int required_profile = 0;
struct ast_channel *c = NULL; /* New channel */
@@ -19681,7 +19682,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
p->invitestate = INV_COMPLETED;
if (!p->lastinvite)
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
}
@@ -19708,7 +19710,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
transmit_response(p, "482 Loop Detected", req);
p->invitestate = INV_COMPLETED;
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return 0;
+ res = 0;
+ goto request_invite_cleanup;
} else {
/*! This is a spiral. What we need to do is to just change the outgoing INVITE
* so that it now routes to the new Request URI. Since we created the INVITE ourselves
@@ -19734,7 +19737,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
*/
ast_string_field_set(p->owner, call_forward, peerorhost);
ast_queue_control(p->owner, AST_CONTROL_BUSY);
- return 0;
+ res = 0;
+ goto request_invite_cleanup;
}
}
@@ -19772,7 +19776,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
transmit_response_reliable(p, "491 Request Pending", req);
ast_debug(1, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
/* Don't destroy dialog here */
- return 0;
+ res = 0;
+ goto request_invite_cleanup;
}
}
@@ -19789,7 +19794,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
ast_debug(3, "INVITE w Replaces on existing call? Refusing action. [%s]\n", p->callid);
transmit_response_reliable(p, "400 Bad request", req); /* The best way to not not accept the transfer */
/* Do not destroy existing call */
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
if (sipdebug)
@@ -19803,7 +19809,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
append_history(p, "Xfer", "INVITE/Replace Failed. Out of memory.");
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
p->invitestate = INV_COMPLETED;
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
/* Todo: (When we find phones that support this)
@@ -19862,6 +19869,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existent call id (%s)!\n", replace_id);
transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req);
error = 1;
+ } else {
+ refer_locked = 1;
}
/* The matched call is the call from the transferer to Asterisk .
@@ -19899,8 +19908,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
ast_channel_unlock(p->refer->refer_call->owner);
}
}
+ refer_locked = 0;
p->invitestate = INV_COMPLETED;
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
}
@@ -19933,7 +19944,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
transmit_response_reliable(p, "488 Not acceptable here", req);
if (!p->lastinvite)
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
ast_queue_control(p->owner, AST_CONTROL_SRCUPDATE);
} else {
@@ -19952,7 +19964,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
res = check_user(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin);
if (res == AUTH_CHALLENGE_SENT) {
p->invitestate = INV_COMPLETED; /* Needs to restart in another INVITE transaction */
- return 0;
+ res = 0;
+ goto request_invite_cleanup;
}
if (res < 0) { /* Something failed in authentication */
if (res == AUTH_FAKE_AUTH) {
@@ -19965,7 +19978,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
p->invitestate = INV_COMPLETED;
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
ast_string_field_set(p, theirtag, NULL);
- return 0;
+ res = 0;
+ goto request_invite_cleanup;
}
/* If T38 is needed but not present, then make it magically appear */
@@ -19982,7 +19996,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
p->invitestate = INV_COMPLETED;
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
ast_debug(1, "No compatible codecs for this SIP call.\n");
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
if (ast_test_flag(&p->flags[1], SIP_PAGE2_CONSTANT_SSRC)) {
if (p->rtp) {
@@ -20017,7 +20032,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
p->invitestate = INV_COMPLETED;
}
- return 0;
+ res = 0;
+ goto request_invite_cleanup;
}
gotdest = get_destination(p, NULL); /* Get destination right away */
get_rdnis(p, NULL); /* Get redirect information */
@@ -20044,7 +20060,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
p->invitestate = INV_COMPLETED;
update_call_counter(p, DEC_CALL_LIMIT);
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return 0;
+ res = 0;
+ goto request_invite_cleanup;
} else {
/* If no extension was specified, use the s one */
@@ -20098,7 +20115,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
if (!p->lastinvite) {
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
}
@@ -20112,7 +20130,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
if (!p->lastinvite) {
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
}
@@ -20126,7 +20145,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
if (!p->lastinvite) {
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
p->stimer->st_active_peer_ua = TRUE;
@@ -20156,7 +20176,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
if (!p->lastinvite) {
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
- return -1;
+ res = -1;
+ goto request_invite_cleanup;
}
break;
@@ -20230,12 +20251,15 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
ast_hangup(c);
sip_pvt_lock(p);
- return 0;
+ res = 0;
+ goto request_invite_cleanup;
} else {
/* Go and take over the target call */
if (sipdebug)
ast_debug(4, "Sending this call to the invite/replcaes handler %s\n", p->callid);
- return handle_invite_replaces(p, req, debug, seqno, sin, nounlock);
+ res = handle_invite_replaces(p, req, debug, seqno, sin, nounlock);
+ refer_locked = 0;
+ goto request_invite_cleanup;
}
}
@@ -20360,6 +20384,16 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
}
+
+request_invite_cleanup:
+
+ if (refer_locked && p->refer && p->refer->refer_call) {
+ sip_pvt_unlock(p->refer->refer_call);
+ if (p->refer->refer_call->owner) {
+ ast_channel_unlock(p->refer->refer_call->owner);
+ }
+ }
+
return res;
}