aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-08-13 20:02:57 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-08-13 20:02:57 +0000
commitf4f8dbcd026dfa68554ccd78ecc4072ad7763cf5 (patch)
tree2186f49ef2b7201b99e50d4ac13ea7d438f54cd8 /channels
parentf8b7aafee10e563344350ef1ae7b373ad881d230 (diff)
Don't call find_peer within update_registry with a pvt lock held. This can
cause a deadlock as the code will eventually call find_callno. git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@79274 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_iax2.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index d6b55dd89..0080384be 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -1042,6 +1042,10 @@ static int uncompress_subclass(unsigned char csub)
return csub;
}
+/*!
+ * \note This funtion calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
+ * so do not call it with a pvt lock held.
+ */
static struct iax2_peer *find_peer(const char *name, int realtime)
{
struct iax2_peer *peer = NULL;
@@ -5674,7 +5678,7 @@ static void reg_source_db(struct iax2_peer *p)
}
}
-static int update_registry(const char *name, struct sockaddr_in *sin, int callno, char *devtype, int fd, unsigned short refresh)
+static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, int fd, unsigned short refresh)
{
/* Called from IAX thread only, with proper iaxsl lock */
struct iax_ie_data ied;
@@ -5682,22 +5686,30 @@ static int update_registry(const char *name, struct sockaddr_in *sin, int callno
int msgcount;
char data[80];
int version;
+ const char *peer_name;
memset(&ied, 0, sizeof(ied));
+ peer_name = ast_strdupa(iaxs[callno]->peer);
+
/* SLD: Another find_peer call during registration - this time when we are really updating our registration */
- if (!(p = find_peer(name, 1))) {
- ast_log(LOG_WARNING, "No such peer '%s'\n", name);
+ ast_mutex_unlock(&iaxsl[callno]);
+ if (!(p = find_peer(peer_name, 1))) {
+ ast_mutex_lock(&iaxsl[callno]);
+ ast_log(LOG_WARNING, "No such peer '%s'\n", peer_name);
return -1;
}
+ ast_mutex_lock(&iaxsl[callno]);
+ if (!iaxs[callno])
+ return -1;
if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
if (sin->sin_addr.s_addr) {
time_t nowtime;
time(&nowtime);
- realtime_update_peer(name, sin, nowtime);
+ realtime_update_peer(peer_name, sin, nowtime);
} else {
- realtime_update_peer(name, sin, 0);
+ realtime_update_peer(peer_name, sin, 0);
}
}
if (inaddrcmp(&p->addr, sin)) {
@@ -7614,8 +7626,12 @@ retryowner2:
ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED | IAX_STATE_UNCHANGED)) {
if (f.subclass == IAX_COMMAND_REGREL)
memset(&sin, 0, sizeof(sin));
- if (update_registry(iaxs[fr->callno]->peer, &sin, fr->callno, ies.devicetype, fd, ies.refresh))
+ if (update_registry(&sin, fr->callno, ies.devicetype, fd, ies.refresh))
ast_log(LOG_WARNING, "Registry error\n");
+ if (!iaxs[fr->callno]) {
+ ast_mutex_unlock(&iaxsl[fr->callno]);
+ return 1;
+ }
if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
ast_mutex_unlock(&iaxsl[fr->callno]);
check_provisioning(&sin, fd, ies.serviceident, ies.provver);