Merged revisions 82929 via svnmerge from
authorRussell Bryant <russell@russellbryant.com>
Tue, 18 Sep 2007 22:46:05 +0000 (22:46 +0000)
committerRussell Bryant <russell@russellbryant.com>
Tue, 18 Sep 2007 22:46:05 +0000 (22:46 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r82929 | russell | 2007-09-18 17:42:27 -0500 (Tue, 18 Sep 2007) | 11 lines

Add a new patch to handle interrupting the fgets() call when using FastAGI.
This version of the patch maintains the original behavior of the code when
not using FastAGI.
(closes issue #10553)
Reported by: juggie
Patches:
      res_agi_fgets-4.patch uploaded by juggie (license 24)
      res_agi_fgets_1.4svn.patch uploaded by juggie (license 24)
  Slight mods by me
Tested by: juggie, festr

........

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@82931 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/agi.h
res/res_agi.c

index 4be6565..25bad67 100644 (file)
@@ -31,6 +31,7 @@ typedef struct agi_state {
        int fd;         /* FD for general output */
        int audio;      /* FD for audio output */
        int ctrl;               /* FD for input control */
+       unsigned int fast:1; /* flag for fast agi or not */
 } AGI;
 
 typedef struct agi_command {
index 8bc3295..9e92616 100644 (file)
@@ -110,6 +110,7 @@ static int agidebug = 0;
 
 enum agi_result {
        AGI_RESULT_SUCCESS,
+       AGI_RESULT_SUCCESS_FAST,
        AGI_RESULT_FAILURE,
        AGI_RESULT_NOTFOUND,
        AGI_RESULT_HANGUP,
@@ -231,7 +232,7 @@ static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, in
        fds[0] = s;
        fds[1] = s;
        *opid = -1;
-       return AGI_RESULT_SUCCESS;
+       return AGI_RESULT_SUCCESS_FAST;
 }
 
 static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
@@ -1869,6 +1870,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
        enum agi_result returnstatus = AGI_RESULT_SUCCESS;
        struct ast_frame *f;
        char buf[AGI_BUF_LEN];
+       char *res = NULL;
        FILE *readf;
        /* how many times we'll retry if ast_waitfor_nandfs will return without either 
          channel or file descriptor in case select is interrupted by a system call (EINTR) */
@@ -1909,10 +1911,27 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
                                ast_frfree(f);
                        }
                } else if (outfd > -1) {
+                       size_t len = sizeof(buf);
+                       size_t buflen = 0;
+
                        retry = AGI_NANDFS_RETRY;
                        buf[0] = '\0';
 
-                       if (!fgets(buf, sizeof(buf), readf)) {
+                       while (buflen < (len - 1)) {
+                               res = fgets(buf + buflen, len, readf);
+                               if (feof(readf)) 
+                                       break;
+                               if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 
+                                       break;
+                               if (res != NULL && !agi->fast)
+                                       break;
+                               buflen = strlen(buf);
+                               len -= buflen;
+                               if (agidebug)
+                                       ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
+                       }
+
+                       if (!buf[0]) {
                                /* Program terminated */
                                if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
                                        returnstatus = -1;
@@ -2122,14 +2141,15 @@ static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int
        }
 #endif
        res = launch_script(args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
-       if (res == AGI_RESULT_SUCCESS) {
+       if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
                int status = 0;
                agi.fd = fds[1];
                agi.ctrl = fds[0];
                agi.audio = efd;
+               agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
                res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
                /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
-               if (res == AGI_RESULT_SUCCESS && status)
+               if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
                        res = AGI_RESULT_FAILURE;
                if (fds[1] != fds[0])
                        close(fds[1]);
@@ -2141,6 +2161,7 @@ static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int
 
        switch (res) {
        case AGI_RESULT_SUCCESS:
+       case AGI_RESULT_SUCCESS_FAST:
                pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
                break;
        case AGI_RESULT_FAILURE: