Asterisk does not hangup a channel after endpoint hangs up.

If the call that the dialplan started an AGI script for is hungup while
the AGI script is in the middle of a command then the AGI script is not
notified of the hangup.  There are many AGI Exec commands that this can
happen with.  The reported applications have been: Background, Wait, Read,
and Dial.  Also the AGI Get Data command.

* Don't wait on the Asterisk channel after it has hung up.  The channel is
likely to never need servicing again.

* Restored the AGI script's ability to return the AGI_RESULT_HANGUP value
in run_agi().  It previously only could return AGI_RESULT_SUCCESS or
AGI_RESULT_FAILURE after the DeadAGI and AGI applications were merged.

(closes issue #17954)
Reported by: mn3250
Patches:
      issue17954_v1.8.patch uploaded by rmudgett (license 664)
      issue17954_v1.6.2.patch uploaded by rmudgett (license 664)
      issue17954_v1.4.patch uploaded by rmudgett (license 664)
Tested by: rmudgett
JIRA SWP-2171

(closes issue #18492)
Reported by: devmod
Tested by: rmudgett
JIRA SWP-2761

(closes issue #18935)
Reported by: nvitaly
Tested by: astmiv, rmudgett
JIRA SWP-3216

(closes issue #17393)
Reported by: siby
Tested by: rmudgett
JIRA SWP-2727

Review: https://reviewboard.asterisk.org/r/1165/


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@313545 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Richard Mudgett 16 years ago
parent 453275054e
commit fa67a98ccc

@ -2253,21 +2253,27 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
} else {
goto done;
}
}
} else {
#ifdef AST_DEVMODE
/*
* The ast_waitfor() code records which of the channel's file descriptors reported that
* data is available. In theory, ast_read() should only be called after ast_waitfor()
* reports that a channel has data available for reading. However, there still may be
* some edge cases throughout the code where ast_read() is called improperly. This can
* potentially cause problems, so if this is a developer build, make a lot of noise if
* this happens so that it can be addressed.
*/
if (chan->fdno == -1) {
ast_log(LOG_ERROR, "ast_read() called with no recorded file descriptor.\n");
}
/*
* The ast_waitfor() code records which of the channel's file
* descriptors reported that data is available. In theory,
* ast_read() should only be called after ast_waitfor() reports
* that a channel has data available for reading. However,
* there still may be some edge cases throughout the code where
* ast_read() is called improperly. This can potentially cause
* problems, so if this is a developer build, make a lot of
* noise if this happens so that it can be addressed.
*
* One of the potential problems is blocking on a dead channel.
*/
if (chan->fdno == -1) {
ast_log(LOG_ERROR,
"ast_read() on chan '%s' called with no recorded file descriptor.\n",
chan->name);
}
#endif
}
prestate = chan->_state;

@ -952,12 +952,14 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
return -1;
fdprintf(agi->fd, "200 result=%d\n", res);
return RESULT_FAILURE;
}
sildet = ast_dsp_new();
if (!sildet) {
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
return -1;
fdprintf(agi->fd, "200 result=-1\n");
return RESULT_FAILURE;
}
ast_dsp_set_threshold(sildet, 256);
}
@ -1855,7 +1857,7 @@ normal:
return 0;
}
static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
{
char *argv[MAX_ARGS];
int argc = MAX_ARGS;
@ -1882,14 +1884,15 @@ static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
return AST_PBX_KEEPALIVE;
break;
case RESULT_FAILURE:
/* They've already given the failure. We've been hung up on so handle this
appropriately */
return -1;
/* The RESULT_FAILURE code is usually because the channel hungup. */
return AGI_RESULT_FAILURE;
default:
break;
}
} else {
fdprintf(agi->fd, "510 Invalid or unknown command\n");
}
return 0;
return AGI_RESULT_SUCCESS;
}
static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead)
{
@ -1916,7 +1919,17 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
setup_env(chan, request, agi->fd, (agi->audio > -1));
for (;;) {
ms = -1;
c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
if (dead) {
c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
} else if (!ast_check_hangup(chan)) {
c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
} else {
/*
* Read the channel control queue until it is dry so we can
* quit.
*/
c = chan;
}
if (c) {
retry = AGI_NANDFS_RETRY;
/* Idle the channel until we get a command */
@ -1937,6 +1950,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
} else if (outfd > -1) {
size_t len = sizeof(buf);
size_t buflen = 0;
enum agi_result cmd_status;
retry = AGI_NANDFS_RETRY;
buf[0] = '\0';
@ -1959,8 +1973,6 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
if (!buf[0]) {
/* Program terminated */
if (returnstatus)
returnstatus = -1;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
if (pid > 0)
@ -1981,9 +1993,15 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
buf[strlen(buf) - 1] = 0;
if (agidebug)
ast_verbose("AGI Rx << %s\n", buf);
returnstatus |= agi_handle_command(chan, agi, buf);
/* If the handle_command returns -1, we need to stop */
if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
cmd_status = agi_handle_command(chan, agi, buf);
if (cmd_status == AGI_RESULT_FAILURE) {
if (dead || !ast_check_hangup(chan)) {
/* The failure was not because of a hangup. */
returnstatus = AGI_RESULT_FAILURE;
break;
}
} else if (cmd_status == AST_PBX_KEEPALIVE) {
returnstatus = AST_PBX_KEEPALIVE;
break;
}
} else {

Loading…
Cancel
Save