diff options
author | Richard Mudgett <rmudgett@digium.com> | 2011-04-13 16:37:06 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2011-04-13 16:37:06 +0000 |
commit | c16d39ea8359a212998e494627853fb4b5da9932 (patch) | |
tree | c1a803d2891e7a423269b1a161d8aed83469ce35 | |
parent | b8b1d085db3c741adf2500161ee869f4f0f910cf (diff) |
Merged revisions 313588 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.8
................
r313588 | rmudgett | 2011-04-13 11:31:50 -0500 (Wed, 13 Apr 2011) | 55 lines
Merged revisions 313579 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.6.2
................
r313579 | rmudgett | 2011-04-13 11:29:49 -0500 (Wed, 13 Apr 2011) | 48 lines
Merged revisions 313545 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r313545 | rmudgett | 2011-04-13 11:21:24 -0500 (Wed, 13 Apr 2011) | 41 lines
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/trunk@313606 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r-- | main/channel.c | 34 | ||||
-rw-r--r-- | res/res_agi.c | 55 |
2 files changed, 55 insertions, 34 deletions
diff --git a/main/channel.c b/main/channel.c index c3b3981f1..6a422673a 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3722,23 +3722,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() on chan '%s' called with no recorded file descriptor.\n", - chan->name); - } + /* + * 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; diff --git a/res/res_agi.c b/res/res_agi.c index 0c25c99a2..5a95d1c6e 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -1178,7 +1178,7 @@ static int action_add_agi_cmd(struct mansession *s, const struct message *m) return 0; } -static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead); +static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead); static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]); static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd) { @@ -2181,12 +2181,14 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); - return -1; + ast_agi_send(agi->fd, chan, "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; + ast_agi_send(agi->fd, chan, "200 result=-1\n"); + return RESULT_FAILURE; } ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE)); } @@ -3257,7 +3259,7 @@ normal: return 0; } -static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead) +static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead) { const char *argv[MAX_ARGS]; int argc = MAX_ARGS, res; @@ -3308,9 +3310,10 @@ static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int } 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 if ((c = find_command(argv, 0))) { ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n"); @@ -3331,7 +3334,7 @@ static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int "ResultCode: 510\r\n" "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd); } - 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, int argc, char *argv[]) { @@ -3376,16 +3379,27 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi } } 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 + * switch to dead mode. + */ + c = chan; + } if (c) { retry = AGI_NANDFS_RETRY; /* Idle the channel until we get a command */ f = ast_read(c); if (!f) { ast_debug(1, "%s hungup\n", chan->name); - returnstatus = AGI_RESULT_HANGUP; needhup = 1; - continue; + if (!returnstatus) { + returnstatus = AGI_RESULT_HANGUP; + } } else { /* If it's voice, write it to the audio pipe */ if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) { @@ -3398,6 +3412,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'; @@ -3420,9 +3435,6 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi if (!buf[0]) { /* Program terminated */ - if (returnstatus) { - returnstatus = -1; - } ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus); if (pid > 0) waitpid(pid, status, 0); @@ -3442,11 +3454,16 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi buf[strlen(buf) - 1] = 0; if (agidebug) ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf); - returnstatus |= agi_handle_command(chan, agi, buf, dead); - /* If the handle_command returns -1, we need to stop */ - if (returnstatus < 0) { - needhup = 1; - continue; + cmd_status = agi_handle_command(chan, agi, buf, dead); + switch (cmd_status) { + case AGI_RESULT_FAILURE: + if (dead || !ast_check_hangup(chan)) { + /* The failure was not because of a hangup. */ + returnstatus = AGI_RESULT_FAILURE; + } + break; + default: + break; } } else { if (--retry <= 0) { |