]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merged revisions 248397 via svnmerge from
authorDavid Vossel <dvossel@digium.com>
Tue, 23 Feb 2010 16:51:23 +0000 (16:51 +0000)
committerDavid Vossel <dvossel@digium.com>
Tue, 23 Feb 2010 16:51:23 +0000 (16:51 +0000)
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: https://origsvn.digium.com/svn/asterisk/branches/1.6.0@248400 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index 975211816596004e5f2161e44410421ff2e3236b..68d3c497627efc5563ba3fefd192aa44ab03848b 100644 (file)
@@ -17839,6 +17839,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 */
@@ -17873,7 +17874,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;
                }
        }
 
@@ -17898,7 +17900,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
@@ -17921,7 +17924,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;
                }
        }
 
@@ -17959,7 +17963,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;
                }
        }
 
@@ -17976,7 +17981,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)
@@ -17990,7 +17996,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)
@@ -18026,6 +18033,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;
                }
 
                /* At this point, bot the pvt and the owner of the call to be replaced is locked */
@@ -18065,8 +18074,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;
                }
        }
 
@@ -18099,7 +18110,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 {
@@ -18119,7 +18131,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) {
@@ -18132,7 +18145,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 */
@@ -18148,7 +18162,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) {
@@ -18183,7 +18198,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 */
@@ -18210,7 +18226,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 */
@@ -18264,7 +18281,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;
                        }
                }
 
@@ -18278,7 +18296,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;
                        }
                }
 
@@ -18292,7 +18311,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;
@@ -18322,7 +18342,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;
 
@@ -18382,7 +18403,10 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                /* 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;
+
        }
 
 
@@ -18506,6 +18530,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;
 }