chan_iax2: Prevent deadlock due to duplicate autoservice.

If a switch is invoked using chan_iax2, deadlock can result
because the PBX core is autoservicing the channel while chan_iax2
also then attempts to service it while waiting for the result
of the switch. This removes servicing of the channel to prevent
any conflicts.

ASTERISK-30064 #close

Change-Id: Ie92f206d32f9a36924af734ddde652b21106af22
This commit is contained in:
Naveen Albert
2022-05-16 13:01:48 +00:00
committed by Kevin Harwell
parent 3b7bcbb6d5
commit 82cebaa023

View File

@@ -14219,9 +14219,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
{ {
struct iax2_dpcache *dp = NULL; struct iax2_dpcache *dp = NULL;
struct timeval now = ast_tvnow(); struct timeval now = ast_tvnow();
int x, com[2], timeout, old = 0, outfd, doabort, callno; int x, com[2], timeout, doabort, callno;
struct ast_channel *c = NULL;
struct ast_frame *f = NULL;
AST_LIST_TRAVERSE_SAFE_BEGIN(&dpcache, dp, cache_list) { AST_LIST_TRAVERSE_SAFE_BEGIN(&dpcache, dp, cache_list) {
if (ast_tvcmp(now, dp->expiry) > 0) { if (ast_tvcmp(now, dp->expiry) > 0) {
@@ -14268,8 +14266,8 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
/* By here we must have a dp */ /* By here we must have a dp */
if (dp->flags & CACHE_FLAG_PENDING) { if (dp->flags & CACHE_FLAG_PENDING) {
struct timeval start; int res;
int ms; struct pollfd pfd;
/* Okay, here it starts to get nasty. We need a pipe now to wait /* Okay, here it starts to get nasty. We need a pipe now to wait
for a reply to come back so long as it's pending */ for a reply to come back so long as it's pending */
for (x = 0; x < ARRAY_LEN(dp->waiters); x++) { for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
@@ -14290,35 +14288,31 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
timeout = iaxdefaulttimeout * 1000; timeout = iaxdefaulttimeout * 1000;
/* Temporarily unlock */ /* Temporarily unlock */
AST_LIST_UNLOCK(&dpcache); AST_LIST_UNLOCK(&dpcache);
/* Defer any dtmf */
if (chan)
old = ast_channel_defer_dtmf(chan);
doabort = 0; doabort = 0;
start = ast_tvnow();
while ((ms = ast_remaining_ms(start, timeout))) { /* chan is in autoservice here, so do NOT service it here! */
c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &ms); pfd.fd = com[0];
if (outfd > -1) pfd.events = POLLIN;
break; pfd.revents = 0;
if (!c) /* Wait for pipe activity... if the channel hangs up, we'll catch it on the way out. */
continue; res = ast_poll(&pfd, 1, timeout);
if (!(f = ast_read(c))) { if (res < 0) {
doabort = 1; ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
break; return NULL;
} } else if (!pfd.revents) {
ast_frfree(f);
}
if (!ms) {
ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten); ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten);
} }
if (ast_check_hangup(chan)) {
doabort = 1;
}
AST_LIST_LOCK(&dpcache); AST_LIST_LOCK(&dpcache);
dp->waiters[x] = -1; dp->waiters[x] = -1;
close(com[1]); close(com[1]);
close(com[0]); close(com[0]);
if (doabort) { if (doabort) {
/* Don't interpret anything, just abort. Not sure what th epoint /* Don't interpret anything, just abort. */
of undeferring dtmf on a hung up channel is but hey whatever */
if (!old && chan)
ast_channel_undefer_dtmf(chan);
return NULL; return NULL;
} }
if (!(dp->flags & CACHE_FLAG_TIMEOUT)) { if (!(dp->flags & CACHE_FLAG_TIMEOUT)) {
@@ -14341,8 +14335,6 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
} }
} }
/* Our caller will obtain the rest */ /* Our caller will obtain the rest */
if (!old && chan)
ast_channel_undefer_dtmf(chan);
} }
return dp; return dp;
} }