diff --git a/libs/esl/ivrd.c b/libs/esl/ivrd.c index 3032a81cd3..2e2e6b2fa4 100644 --- a/libs/esl/ivrd.c +++ b/libs/esl/ivrd.c @@ -36,11 +36,56 @@ #include #include +static void my_forking_callback(esl_socket_t server_sock, esl_socket_t client_sock, struct sockaddr_in *addr) +{ + esl_handle_t handle = {{0}}; + char path_buffer[1024] = { 0 }; + const char *path; + char arg[64] = { 0 }; + + if (fork()) { + close(client_sock); + return; + } + + if (esl_attach_handle(&handle, client_sock, addr) != ESL_SUCCESS || !handle.info_event) { + esl_log(ESL_LOG_ERROR, "Socket Error\n"); + exit(0); + } + + if (!(path = esl_event_get_header(handle.info_event, "variable_ivr_path"))) { + esl_disconnect(&handle); + esl_log(ESL_LOG_ERROR, "Missing ivr_path param!\n"); + exit(0); + } + + snprintf(arg, sizeof(arg), "%d", client_sock); + + strncpy(path_buffer, path, sizeof(path_buffer) - 1); + + /* hotwire the socket to STDIN/STDOUT */ + /* hotwire the socket to STDIN/STDOUT */ + if (!(dup2(client_sock, STDIN_FILENO)) && !(dup2(client_sock, STDOUT_FILENO))){ + esl_disconnect(&handle); + esl_log(ESL_LOG_ERROR, "Socket Error hotwiring socket to STDIN/STDOUT!\n"); + return; + } + + /* close the handle but leak the socket on purpose cos the child will need it open */ + handle.sock = -1; + esl_disconnect(&handle); + + execl(path_buffer, path_buffer, arg, (char *)NULL); + close(client_sock); + exit(0); +} + static void mycallback(esl_socket_t server_sock, esl_socket_t client_sock, struct sockaddr_in *addr) { esl_handle_t handle = {{0}}; const char *path; - + char path_buffer[1024] = { 0 }; + if (esl_attach_handle(&handle, client_sock, addr) != ESL_SUCCESS || !handle.info_event) { close(client_sock); esl_log(ESL_LOG_ERROR, "Socket Error\n"); @@ -53,16 +98,13 @@ static void mycallback(esl_socket_t server_sock, esl_socket_t client_sock, struc return; } - /* hotwire the socket to STDIN/STDOUT */ - if (!(dup2(client_sock, STDIN_FILENO)) && !(dup2(client_sock, STDOUT_FILENO))){ - esl_disconnect(&handle); - esl_log(ESL_LOG_ERROR, "Socket Error hotwiring socket to STDIN/STDOUT!\n"); - return; - } + snprintf(path_buffer, sizeof(path_buffer), "%s %d", path, client_sock); - if(system(path)) { + + if (system(path_buffer)) { esl_log(ESL_LOG_ERROR, "System Call Failed! [%s]\n", strerror(errno)); } + esl_disconnect(&handle); } @@ -71,24 +113,43 @@ int main(int argc, char *argv[]) { int i; char *ip = NULL; - int port = 0; + int port = 0, thread = 0; - for (i = 1; i + 1 < argc; ) { - if (!strcasecmp(argv[i], "-h")) { - ip = argv[++i]; - } else if (!strcasecmp(argv[i], "-p")) { - port = atoi(argv[++i]); - } else { - i++; + for (i = 1; i < argc; ) { + int cont = 0; + + if (i + 1 < argc) { + if (!strcasecmp(argv[i], "-h")) { + ip = argv[++i]; cont++; + } else if (!strcasecmp(argv[i], "-p")) { + port = atoi(argv[++i]); cont++; + } } + + if (cont) { + i++; + continue; + } + + if (!strcasecmp(argv[i], "-t")) { + thread++; + } + + i++; } if (!(ip && port)) { - fprintf(stderr, "Usage %s -h -p \n", argv[0]); + fprintf(stderr, "Usage %s [-t] -h -p \n", argv[0]); return -1; } - esl_listen(ip, port, mycallback, 100000); + if (thread) { + printf("Starting threaded listener.\n"); + esl_listen_threaded(ip, port, mycallback, 100000); + } else { + printf("Starting forking listener.\n"); + esl_listen(ip, port, my_forking_callback); + } return 0; } diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index fb50c6d0da..22b27836fd 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -649,7 +649,64 @@ static void *client_thread(esl_thread_t *me, void *obj) } -ESL_DECLARE(esl_status_t) esl_listen(const char *host, esl_port_t port, esl_listen_callback_t callback, int max) +ESL_DECLARE(esl_status_t) esl_listen(const char *host, esl_port_t port, esl_listen_callback_t callback) +{ + esl_socket_t server_sock = ESL_SOCK_INVALID; + struct sockaddr_in addr; + esl_status_t status = ESL_SUCCESS; + + if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + return ESL_FAIL; + } + + esl_socket_reuseaddr(server_sock); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + status = ESL_FAIL; + goto end; + } + + if (listen(server_sock, 10000) < 0) { + status = ESL_FAIL; + goto end; + } + + for (;;) { + int client_sock; + struct sockaddr_in echoClntAddr; +#ifdef WIN32 + int clntLen; +#else + unsigned int clntLen; +#endif + + clntLen = sizeof(echoClntAddr); + + if ((client_sock = accept(server_sock, (struct sockaddr *) &echoClntAddr, &clntLen)) == ESL_SOCK_INVALID) { + status = ESL_FAIL; + goto end; + } + + callback(server_sock, client_sock, &echoClntAddr); + } + + end: + + if (server_sock != ESL_SOCK_INVALID) { + closesocket(server_sock); + server_sock = ESL_SOCK_INVALID; + } + + return status; + +} + +ESL_DECLARE(esl_status_t) esl_listen_threaded(const char *host, esl_port_t port, esl_listen_callback_t callback, int max) { esl_socket_t server_sock = ESL_SOCK_INVALID; struct sockaddr_in addr; diff --git a/libs/esl/src/include/esl.h b/libs/esl/src/include/esl.h index 7ba705359e..4296175f3a 100644 --- a/libs/esl/src/include/esl.h +++ b/libs/esl/src/include/esl.h @@ -391,7 +391,9 @@ ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t s \param port Port to bind to \param callback Callback that will be called upon data received */ -ESL_DECLARE(esl_status_t) esl_listen(const char *host, esl_port_t port, esl_listen_callback_t callback, int max); + +ESL_DECLARE(esl_status_t) esl_listen(const char *host, esl_port_t port, esl_listen_callback_t callback); +ESL_DECLARE(esl_status_t) esl_listen_threaded(const char *host, esl_port_t port, esl_listen_callback_t callback, int max); /*! \brief Executes application with sendmsg to a specific UUID. Used for outbound socket. \param handle Handle that the msg will be sent diff --git a/libs/esl/testserver.c b/libs/esl/testserver.c index cf60313fe7..1477d8d71e 100644 --- a/libs/esl/testserver.c +++ b/libs/esl/testserver.c @@ -48,7 +48,7 @@ static void mycallback(esl_socket_t server_sock, esl_socket_t client_sock, struc int main(void) { esl_global_set_default_logger(7); - esl_listen("localhost", 8084, mycallback, 100000); + esl_listen_threaded("localhost", 8084, mycallback, 100000); return 0; }