From 0066ea5ae4142299d6e8e35dfe438e745f625f8f Mon Sep 17 00:00:00 2001 From: jpeeler Date: Thu, 13 Mar 2008 18:59:04 +0000 Subject: (closes issue #11827) 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: http://svn.digium.com/svn/asterisk/trunk@108404 f38db490-d61c-443f-a65b-d21fe96a405b --- apps/app_externalivr.c | 228 ++++++++++++++++++++++++++++++------------------- 1 file changed, 142 insertions(+), 86 deletions(-) (limited to 'apps/app_externalivr.c') diff --git a/apps/app_externalivr.c b/apps/app_externalivr.c index eb1989c62..49f900c6c 100644 --- a/apps/app_externalivr.c +++ b/apps/app_externalivr.c @@ -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) { -- cgit v1.2.3