]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
I am fighting deadlocks in chan_iax2. I have tracked them down to a single
authorRussell Bryant <russell@russellbryant.com>
Mon, 13 Aug 2007 19:27:39 +0000 (19:27 +0000)
committerRussell Bryant <russell@russellbryant.com>
Mon, 13 Aug 2007 19:27:39 +0000 (19:27 +0000)
core issue.  You can not call find_callno() while holding a pvt lock as this
function has to lock another (every) other pvt lock.  Doing so can lead to a
classic deadlock.  So, I am tracking down all of the code paths where this
can happen and fixing them.

The fix I committed earlier today was along the same theme.  This patch fixes
some code down the path of authenticate_reply.

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@79272 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_iax2.c

index e8f78cf06f1914126b0e49d773c8e15812631bc3..d6b55dd89e2281bf40330ff2a84a8c46a0ae6aa3 100644 (file)
@@ -1244,6 +1244,9 @@ static int make_trunk(unsigned short callno, int locked)
        return res;
 }
 
+/*!
+ * \note Calling this function while holding another pvt lock can cause a deadlock.
+ */
 static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int lockpeer, int sockfd)
 {
        int res = 0;
@@ -2502,6 +2505,10 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
        return 0;
 }
 
+/*!
+ * \note This function calls reg_source_db -> iax2_poke_peer -> find_callno,
+ *       so do not call this with a pvt lock held.
+ */
 static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
 {
        struct ast_variable *var;
@@ -5219,6 +5226,10 @@ static int authenticate(const char *challenge, const char *secret, const char *k
        return res;
 }
 
+/*!
+ * \note This function calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
+ *       so do not call this function with a pvt lock held.
+ */
 static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin, struct iax_ies *ies, const char *override, const char *okey)
 {
        struct iax2_peer *peer = NULL;
@@ -5226,7 +5237,8 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
        int res = -1;
        int authmethods = 0;
        struct iax_ie_data ied;
-       
+       uint16_t callno = p->callno;
+
        memset(&ied, 0, sizeof(ied));
        
        if (ies->username)
@@ -5263,11 +5275,21 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
                if (!peer) {
                        /* We checked our list and didn't find one.  It's unlikely, but possible, 
                           that we're trying to authenticate *to* a realtime peer */
-                       if ((peer = realtime_peer(p->peer, NULL))) {
+                       const char *peer_name = ast_strdupa(p->peer);
+                       ast_mutex_unlock(&iaxsl[callno]);
+                       if ((peer = realtime_peer(peer_name, NULL))) {
+                               ast_mutex_lock(&iaxsl[callno]);
+                               if (!(p = iaxs[callno]))
+                                       return -1;
                                res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
                                if (ast_test_flag(peer, IAX_TEMPONLY))
                                        destroy_peer(peer);
                        }
+                       if (!peer) {
+                               ast_mutex_lock(&iaxsl[callno]);
+                               if (!(p = iaxs[callno]))
+                                       return -1;
+                       }
                }
        }
        if (ies->encmethods)
@@ -7384,6 +7406,10 @@ retryowner2:
                                                "I don't know how to authenticate %s to %s\n", 
                                                ies.username ? ies.username : "<unknown>", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr));
                                }
+                               if (!iaxs[fr->callno]) {
+                                       ast_mutex_unlock(&iaxsl[fr->callno]);
+                                       return 1;
+                               }
                                break;
                        case IAX_COMMAND_AUTHREP:
                                /* For security, always ack immediately */