(closes issue #11827)
authorJeff Peeler <jpeeler@digium.com>
Thu, 13 Mar 2008 18:59:04 +0000 (18:59 +0000)
committerJeff Peeler <jpeeler@digium.com>
Thu, 13 Mar 2008 18:59:04 +0000 (18:59 +0000)
Reported by: ctooley
Patches:
      eivr_tcp_generic.patch uploaded by jpeeler (license 325)
This change adds the ability to communicate over a TCP socket instead of forking a child process.

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

apps/app_externalivr.c

index eb1989c..49f900c 100644 (file)
@@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/linkedlists.h"
 #include "asterisk/app.h"
 #include "asterisk/utils.h"
+#include "asterisk/tcptls.h"
 
 static const char *app = "ExternalIVR";
 
@@ -89,6 +90,8 @@ static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
               int eivr_events_fd, int eivr_commands_fd, int eivr_errors_fd, 
               const char *args);
 
+int eivr_connect_socket(struct ast_channel *chan, const char *host, int port);
+
 static void send_eivr_event(FILE *handle, const char event, const char *data,
        const struct ast_channel *chan)
 {
@@ -305,6 +308,12 @@ static int app_exec(struct ast_channel *chan, void *data)
        int gen_active = 0;
        int pid;
        char *buf, *pipe_delim_argbuf, *pdargbuf_ptr;
+
+       char hostname[1024];
+       char *port_str = NULL;
+       int port = 0;
+       struct ast_tcptls_session_instance *ser;
+
        struct ivr_localuser foo = {
                .playlist = AST_LIST_HEAD_INIT_VALUE,
                .finishlist = AST_LIST_HEAD_INIT_VALUE,
@@ -333,90 +342,137 @@ static int app_exec(struct ast_channel *chan, void *data)
        pipe_delim_argbuf = ast_strdupa(data);
        while((pdargbuf_ptr = strchr(pipe_delim_argbuf, ',')) != NULL)
                pdargbuf_ptr[0] = '|';
-       
-       if (pipe(child_stdin)) {
-               ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
-               goto exit;
-       }
-       if (pipe(child_stdout)) {
-               ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
-               goto exit;
-       }
-       if (pipe(child_stderr)) {
-               ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
-               goto exit;
-       }
-       if (chan->_state != AST_STATE_UP) {
-               ast_answer(chan);
-       }
-       if (ast_activate_generator(chan, &gen, u) < 0) {
-               ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
-               goto exit;
-       } else
-               gen_active = 1;
-
-       pid = fork();
-       if (pid < 0) {
-               ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
-               goto exit;
-       }
-
-       if (!pid) {
-               /* child process */
-               int i;
 
-               signal(SIGPIPE, SIG_DFL);
-               pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
+       if(!strncmp(args.cmd[0], "ivr://", 6)) {
+               struct server_args ivr_desc = {
+                       .accept_fd = -1,
+                       .name = "IVR",
+               };
+               struct ast_hostent hp;
 
-               if (ast_opt_high_priority)
-                       ast_set_priority(0);
+               /*communicate through socket to server*/
+               if (chan->_state != AST_STATE_UP) {
+                       ast_answer(chan);
+               }
+               if (ast_activate_generator(chan, &gen, u) < 0) {
+                       ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
+                       goto exit;
+               } else {
+                       gen_active = 1;
+               }
 
-               dup2(child_stdin[0], STDIN_FILENO);
-               dup2(child_stdout[1], STDOUT_FILENO);
-               dup2(child_stderr[1], STDERR_FILENO);
-               for (i = STDERR_FILENO + 1; i < 1024; i++)
-                       close(i);
-               execv(args.cmd[0], args.cmd);
-               fprintf(stderr, "Failed to execute '%s': %s\n", args.cmd[0], strerror(errno));
-               _exit(1);
+               ast_chan_log(LOG_DEBUG, chan, "Parsing hostname:port for socket connect from \"%s\"\n", args.cmd[0]);           
+               strncpy(hostname, args.cmd[0] + 6, sizeof(hostname));
+               if((port_str = strchr(hostname, ':')) != NULL) {
+                       port_str[0] = 0;
+                       port_str += 1;
+                       port = atoi(port_str);
+               }
+               if(!port)
+                       port = 2949;  /*default port, if one is not provided*/
+
+               ast_gethostbyname(hostname, &hp);
+               ivr_desc.sin.sin_family = AF_INET;
+               ivr_desc.sin.sin_port = htons(port);
+               memmove(&ivr_desc.sin.sin_addr.s_addr, hp.hp.h_addr, hp.hp.h_length);
+               ser = ast_tcptls_client_start(&ivr_desc);
+
+               if (!ser) {
+                       goto exit;
+               } 
+               res = eivr_comm(chan, u, ser->fd, ser->fd, 0, pipe_delim_argbuf);
        } else {
-               /* parent process */
+       
+               if (pipe(child_stdin)) {
+                       ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
+                       goto exit;
+               }
+               if (pipe(child_stdout)) {
+                       ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
+                       goto exit;
+               }
+               if (pipe(child_stderr)) {
+                       ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
+                       goto exit;
+               }
+               if (chan->_state != AST_STATE_UP) {
+                       ast_answer(chan);
+               }
+               if (ast_activate_generator(chan, &gen, u) < 0) {
+                       ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
+                       goto exit;
+               } else {
+                       gen_active = 1;
+               }
+       
+               pid = fork();
+               if (pid < 0) {
+                       ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
+                       goto exit;
+               }
+       
+               if (!pid) {
+                       /* child process */
+                       int i;
+       
+                       signal(SIGPIPE, SIG_DFL);
+                       pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
+       
+                       if (ast_opt_high_priority)
+                               ast_set_priority(0);
+       
+                       dup2(child_stdin[0], STDIN_FILENO);
+                       dup2(child_stdout[1], STDOUT_FILENO);
+                       dup2(child_stderr[1], STDERR_FILENO);
+                       for (i = STDERR_FILENO + 1; i < 1024; i++)
+                               close(i);
+                       execv(args.cmd[0], args.cmd);
+                       fprintf(stderr, "Failed to execute '%s': %s\n", args.cmd[0], strerror(errno));
+                       _exit(1);
+               } else {
+                       /* parent process */
+       
+                       close(child_stdin[0]);
+                       child_stdin[0] = 0;
+                       close(child_stdout[1]);
+                       child_stdout[1] = 0;
+                       close(child_stderr[1]);
+                       child_stderr[1] = 0;
+                       res = eivr_comm(chan, u, child_stdin[1], child_stdout[0], child_stderr[0], pipe_delim_argbuf);
+               }
+       }
 
-               close(child_stdin[0]);
-               child_stdin[0] = 0;
-               close(child_stdout[1]);
-               child_stdout[1] = 0;
-               close(child_stderr[1]);
-               child_stderr[1] = 0;
-               res = eivr_comm(chan, u, child_stdin[1], child_stdout[0], child_stderr[0], pipe_delim_argbuf);
+       exit:
+       if (gen_active)
+               ast_deactivate_generator(chan);
 
-               exit:
-               if (gen_active)
-                       ast_deactivate_generator(chan);
+       if (child_stdin[0])
+               close(child_stdin[0]);
 
-               if (child_stdin[0])
-                       close(child_stdin[0]);
+       if (child_stdin[1])
+               close(child_stdin[1]);
 
-               if (child_stdin[1])
-                       close(child_stdin[1]);
+       if (child_stdout[0])
+               close(child_stdout[0]);
 
-               if (child_stdout[0])
-                       close(child_stdout[0]);
+       if (child_stdout[1])
+               close(child_stdout[1]);
 
-               if (child_stdout[1])
-                       close(child_stdout[1]);
+       if (child_stderr[0])
+               close(child_stderr[0]);
 
-               if (child_stderr[0])
-                       close(child_stderr[0]);
+       if (child_stderr[1])
+               close(child_stderr[1]);
 
-               if (child_stderr[1])
-                       close(child_stderr[1]);
+       if (ser) {
+               fclose(ser->f);
+               ast_tcptls_session_instance_destroy(ser);
+       }
 
-               while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
-                       ast_free(entry);
+       while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
+               ast_free(entry);
 
-               return res;
-       }
+       return res;
 }
 
 static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, 
@@ -436,21 +492,21 @@ static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
        FILE *eivr_commands = NULL;
        FILE *eivr_errors = NULL;
        FILE *eivr_events = NULL;
-       if (!(eivr_events = fdopen(eivr_events_fd, "w"))) {
-               ast_chan_log(LOG_WARNING, chan, "Could not open stream to send events\n");
-               goto exit;
-       }
-       if (!(eivr_commands = fdopen(eivr_commands_fd, "r"))) {
-               ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive commands\n");
-               goto exit;
-       }
-       if(eivr_errors_fd) {  /*if opening a socket connection, error stream will not be used*/
+
+       if (!(eivr_events = fdopen(eivr_events_fd, "w"))) {
+               ast_chan_log(LOG_WARNING, chan, "Could not open stream to send events\n");
+               goto exit;
+       }
+       if (!(eivr_commands = fdopen(eivr_commands_fd, "r"))) {
+               ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive commands\n");
+               goto exit;
+       }
+       if(eivr_errors_fd) {  /* if opening a socket connection, error stream will not be used */
                if (!(eivr_errors = fdopen(eivr_errors_fd, "r"))) {
                        ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive errors\n");
                        goto exit;
                }
-       }
+       }
  
        setvbuf(eivr_events, NULL, _IONBF, 0);
        setvbuf(eivr_commands, NULL, _IONBF, 0);
@@ -633,18 +689,18 @@ static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
  
 exit:
  
-       if (eivr_events)
+       if (eivr_events)
                fclose(eivr_events);
  
-       if (eivr_commands)
+       if (eivr_commands)
                fclose(eivr_commands);
 
-       if (eivr_errors)
-               fclose(eivr_errors);
+       if (eivr_errors)
+               fclose(eivr_errors);
   
        return res;
  
-  }
+}
 
 static int unload_module(void)
 {