} 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;
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);
}
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;
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)
{
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 */
} 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';
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)
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 {