]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merged revisions 313545 via svnmerge from
authorRichard Mudgett <rmudgett@digium.com>
Wed, 13 Apr 2011 16:29:49 +0000 (16:29 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Wed, 13 Apr 2011 16:29:49 +0000 (16:29 +0000)
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/branches/1.6.2@313579 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/channel.c
res/res_agi.c

index 7718a7ff0a9bd096da65c264c15fb0432732b3e4..17aea6bbf3c20d11aa9c14146539726d7c58bd63 100644 (file)
@@ -2800,21 +2800,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;
 
index c3548906c306945389289248eebf49472508d019..7fd2aa006216c71ca150066af02b1b8326864521 100644 (file)
@@ -613,7 +613,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)
 {
@@ -1541,12 +1541,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;
+                       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));
        }
@@ -2775,7 +2777,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)
 {
        char *argv[MAX_ARGS];
        int argc = MAX_ARGS, res;
@@ -2826,9 +2828,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");
@@ -2849,7 +2852,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[])
 {
@@ -2894,16 +2897,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)) {
@@ -2916,6 +2930,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';
@@ -2938,9 +2953,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);
@@ -2960,11 +2972,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) {