aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_iax2.c
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-08-13 19:27:39 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-08-13 19:27:39 +0000
commitf8b7aafee10e563344350ef1ae7b373ad881d230 (patch)
treed2d09738d485f542ea57c1db4ca5a215fdfd20ec /channels/chan_iax2.c
parentc338e83712467731d7a9f46b53e5f2b164aac7a8 (diff)
I am fighting deadlocks in chan_iax2. I have tracked them down to a single
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: http://svn.digium.com/svn/asterisk/branches/1.4@79272 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_iax2.c')
-rw-r--r--channels/chan_iax2.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index e8f78cf06..d6b55dd89 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -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 */