[asterisk-commits] rmudgett: trunk r313606 - in /trunk: ./ main/channel.c res/res_agi.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 13 11:37:15 CDT 2011


Author: rmudgett
Date: Wed Apr 13 11:37:06 2011
New Revision: 313606

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=313606
Log:
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/
    ........
  ................
................

Modified:
    trunk/   (props changed)
    trunk/main/channel.c
    trunk/res/res_agi.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.

Modified: trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/channel.c?view=diff&rev=313606&r1=313605&r2=313606
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Wed Apr 13 11:37:06 2011
@@ -3722,23 +3722,27 @@
 		} 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;
 

Modified: trunk/res/res_agi.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_agi.c?view=diff&rev=313606&r1=313605&r2=313606
==============================================================================
--- trunk/res/res_agi.c (original)
+++ trunk/res/res_agi.c Wed Apr 13 11:37:06 2011
@@ -1178,7 +1178,7 @@
 	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 @@
 		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 @@
 	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 @@
 			}
 			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 @@
 				"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 @@
 			}
 		}
 		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 @@
 		} 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 @@
 
 			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 @@
 				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) {




More information about the asterisk-commits mailing list