diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-08-13 19:27:39 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-08-13 19:27:39 +0000 |
commit | f8b7aafee10e563344350ef1ae7b373ad881d230 (patch) | |
tree | d2d09738d485f542ea57c1db4ca5a215fdfd20ec | |
parent | c338e83712467731d7a9f46b53e5f2b164aac7a8 (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
-rw-r--r-- | channels/chan_iax2.c | 30 |
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 */ |