diff options
author | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-02-23 16:34:39 +0000 |
---|---|---|
committer | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-02-23 16:34:39 +0000 |
commit | bae3ac487bdf8b3a3f2ea2bcaeab6a016f357dde (patch) | |
tree | 23dfad2ac965adea89eef28d89eb9600d20abe5b | |
parent | f18ebf7f35cde5a65f0e0c96758d58c2e65beeeb (diff) |
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/trunk@248397 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | channels/chan_sip.c | 72 |
1 files changed, 53 insertions, 19 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 5b089dd1e..a60bc0e2f 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -18816,6 +18816,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 */ @@ -18856,7 +18857,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; } } @@ -18883,7 +18885,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 @@ -18909,7 +18912,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; } } @@ -18947,7 +18951,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; } } @@ -18964,7 +18969,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) @@ -18977,7 +18983,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) @@ -19040,6 +19047,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 . @@ -19077,8 +19086,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; } } @@ -19121,7 +19132,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 { @@ -19142,7 +19154,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) { @@ -19155,7 +19168,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 */ @@ -19172,7 +19186,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 (p->rtp) { ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_CONSTANT_SSRC, ast_test_flag(&p->flags[1], SIP_PAGE2_CONSTANT_SSRC)); @@ -19205,7 +19220,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 */ change_redirecting_information(p, req, &redirecting, FALSE); /*Will return immediately if no Diversion header is present */ @@ -19232,7 +19248,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 */ @@ -19292,7 +19309,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; } } @@ -19306,7 +19324,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; } } @@ -19320,7 +19339,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; @@ -19350,7 +19370,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; @@ -19429,12 +19450,15 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int ast_hangup(c); sip_pvt_lock(p); /* pvt is expected to remain locked on return, so re-lock it */ - 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; } } @@ -19558,6 +19582,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; } |