diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-08-13 19:29:30 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-08-13 19:29:30 +0000 |
commit | 633a42b7b5d059e300bdbc5a1317cdb69558054e (patch) | |
tree | 47245c3e4b71e0419643137c6a6c0568dd1aefed | |
parent | 782319a0da02f539aa72812594938b2bacea04d8 (diff) |
Merged revisions 79272 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r79272 | russell | 2007-08-13 14:27:39 -0500 (Mon, 13 Aug 2007) | 9 lines
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/trunk@79273 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | channels/chan_iax2.c | 29 |
1 files changed, 27 insertions, 2 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 8eff5ca1a..228e6ca41 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -1397,6 +1397,8 @@ static int make_trunk(unsigned short callno, int locked) * However, it's too late to change that now. Instead, we need to come up with * a better way of indexing active calls so that these frequent lookups are not * so expensive. + * + * \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) { @@ -2674,6 +2676,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; @@ -5496,6 +5502,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; @@ -5503,7 +5513,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) @@ -5540,11 +5551,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) @@ -7846,6 +7867,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 */ |