[asterisk-dev] asterisk 1.4 rtp port exhaustion fix
CDR
venefax at gmail.com
Mon May 16 13:42:43 CDT 2011
Please somebody evaluate this fix for 1.6.X and 1.8?
On Mon, May 16, 2011 at 2:02 PM, Paul Albrecht <albrecht at glccom.com> wrote:
> Hi,
>
> When I run the mp3 application I sometimes run out of rtp ports because
> asterisk doesn't close open files and sockets before exec'ing the mpg123
> process. Here's a fix:
>
> diff -Naur asterisk-1.4.30/apps/app_mp3.c asterisk-1.4.30-hacked/apps/app_mp3.c
> --- asterisk-1.4.30/apps/app_mp3.c 2010-01-06 09:18:22.000000000 -0600
> +++ asterisk-1.4.30-hacked/apps/app_mp3.c 2011-05-12 13:28:28.000000000 -0500
> @@ -39,6 +39,9 @@
> #include <stdlib.h>
> #include <unistd.h>
> #include <fcntl.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <errno.h>
> #include <sys/time.h>
> #ifdef HAVE_CAP
> #include <sys/capability.h>
> @@ -67,10 +70,9 @@
> "any key on the dialpad, or by hanging up.";
>
>
> -static int mp3play(char *filename, int fd)
> +static int mp3play(char *filename, struct sockaddr_un ast_address)
> {
> int res;
> - int x;
> sigset_t fullset, oldset;
> #ifdef HAVE_CAP
> cap_t cap;
> @@ -100,18 +102,68 @@
> signal(SIGPIPE, SIG_DFL);
> pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
>
> - dup2(fd, STDOUT_FILENO);
> - for (x=STDERR_FILENO + 1;x<256;x++) {
> - close(x);
> + //
> + // create and connect unix socket file descriptors
> + //
> +
> + int mp3_sock;
> + if ((mp3_sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
> + ast_log(LOG_ERROR, "unable to create mp3 socket: %s\n", strerror(errno));
> + _exit(1);
> + }
> +
> + if((res = connect(mp3_sock, (const struct sockaddr *) &ast_address, sizeof(struct sockaddr_un))) != 0) {
> + ast_log(LOG_ERROR, "unable to connect mp3 socket: %s\n", strerror(errno));
> + _exit(1);
> + }
> +
> + //
> + // create pipe for mp3 program
> + //
> +
> + int mp3_fds[2] = { 0, };
> + if (pipe2(mp3_fds,O_CLOEXEC)) {
> + ast_log(LOG_ERROR, "unable to create mp3 pipe: %s\n", strerror(errno));
> + _exit(1);
> + }
> +
> + //
> + // send mp3 file descriptors to asterisk
> + //
> +
> + char mp3_data[1] = { '*' };
> + struct iovec mp3_iov[1] = { { .iov_base = mp3_data, .iov_len = 1 } };
> +
> + char mp3_buf[CMSG_SPACE(2 * sizeof(int))] = { 0, };
> +
> + struct msghdr mp3_message = { .msg_iov = mp3_iov, .msg_iovlen = 1, .msg_control = mp3_buf, .msg_controllen = sizeof mp3_buf };
> +
> + struct cmsghdr *mp3_cmsg = CMSG_FIRSTHDR(&mp3_message);
> + mp3_cmsg->cmsg_level = SOL_SOCKET;
> + mp3_cmsg->cmsg_type = SCM_RIGHTS;
> + mp3_cmsg->cmsg_len = CMSG_LEN(2 * sizeof(int));
> +
> + int *mp3_cmsg_fds_ptr = (int *)CMSG_DATA(mp3_cmsg);
> + memcpy(mp3_cmsg_fds_ptr, mp3_fds, 2 * sizeof(int));
> + mp3_message.msg_controllen = mp3_cmsg->cmsg_len;
> +
> + if ((res = sendmsg(mp3_sock, &mp3_message, 0)) < 0) {
> + ast_log(LOG_ERROR, "mp3 fds sendmsg failed: %s\n", strerror(errno));
> + _exit(1);
> }
> +
> + close(mp3_sock);
> +
> + dup2(mp3_fds[1], STDOUT_FILENO);
> +
> /* Execute mpg123, but buffer if it's a net connection */
> - if (!strncasecmp(filename, "http://", 7)) {
> + if (!strncasecmp(filename, "http://", 7) || !strncasecmp(filename, "- at http://", 9)) {
> /* Most commonly installed in /usr/local/bin */
> - execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
> + execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "128", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
> /* But many places has it in /usr/bin */
> - execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
> + execl(MPG_123, "mpg123", "-q", "-s", "-b", "128","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
> /* As a last-ditch effort, try to use PATH */
> - execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
> + execlp("mpg123", "mpg123", "-q", "-s", "-b", "128", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
> }
> else {
> /* Most commonly installed in /usr/local/bin */
> @@ -166,12 +218,6 @@
>
> u = ast_module_user_add(chan);
>
> - if (pipe(fds)) {
> - ast_log(LOG_WARNING, "Unable to create pipe\n");
> - ast_module_user_remove(u);
> - return -1;
> - }
> -
> ast_stopstream(chan);
>
> owriteformat = chan->writeformat;
> @@ -181,10 +227,62 @@
> ast_module_user_remove(u);
> return -1;
> }
> +
> + //
> + // create and bind unix socket for file descriptors
> + //
> +
> + int ast_sock;
> + if ((ast_sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) {
> + ast_log(LOG_ERROR, "unable to create ast socket: %s\n", strerror(errno));
> + ast_module_user_remove(u);
> + return -1;
> + }
> +
> + struct sockaddr_un ast_address;
> + ast_address.sun_family = AF_UNIX;
> + sprintf(ast_address.sun_path, "/tmp/asterisk-%s",chan->uniqueid);
> +
> + if((res = bind(ast_sock, (const struct sockaddr *) &ast_address, sizeof(struct sockaddr_un))) != 0) {
> + ast_log(LOG_ERROR, "ast_sock bind failed, %s\n", strerror(errno));
> + ast_module_user_remove(u);
> + return -1;
> + }
>
> - res = mp3play((char *)data, fds[1]);
> - if (!strncasecmp((char *)data, "http://", 7)) {
> - timeout = 10000;
> + if ((res = mp3play((char *)data, ast_address) < 0)) {
> + ast_log(LOG_WARNING, "Unable to fork child process\n");
> + ast_module_user_remove(u);
> + return -1;
> + }
> +
> + //
> + // receive file descriptors from mp3 process
> + //
> +
> + char ast_data[1] = { 0, };
> + struct iovec ast_iov[1] = { { .iov_base = ast_data, .iov_len = 1 } };
> +
> + char ast_buf[CMSG_SPACE(2 * sizeof(int))] = { 0, };
> +
> + struct msghdr ast_message = { .msg_iov = ast_iov, .msg_iovlen = 1, .msg_control = ast_buf, .msg_controllen = CMSG_LEN(2 * sizeof(int)) };
> +
> + if ((res = recvmsg(ast_sock, &ast_message, MSG_CMSG_CLOEXEC)) < 0) {
> + ast_log(LOG_ERROR, "ast fds recvmsg failed: %s\n", strerror(errno));
> + ast_module_user_remove(u);
> + return -1;
> + }
> +
> + struct cmsghdr *ast_cmsg = CMSG_FIRSTHDR(&ast_message);
> + memcpy(fds,CMSG_DATA(ast_cmsg),2 * sizeof(int));
> +
> + //ast_log(LOG_NOTICE, "recvmsg: fds = %d,%d\n", fds[0], fds[1]);
> +
> + close(ast_sock);
> +
> + unlink(ast_address.sun_path);
> +
> + if (!strncasecmp((char *)data, "http://", 7) || !strncasecmp((char *)data, "- at http://", 9)) {
> + timeout = 40000;
> }
> /* Wait 1000 ms first */
> next = ast_tvnow();
> @@ -245,7 +343,7 @@
> }
> close(fds[0]);
> close(fds[1]);
> -
> +
> if (pid > -1)
> kill(pid, SIGKILL);
> if (!res && owriteformat)
> diff -Naur asterisk-1.4.30/channels/chan_sip.c asterisk-1.4.30-hacked/channels/chan_sip.c
> --- asterisk-1.4.30/channels/chan_sip.c 2010-02-26 11:04:29.000000000 -0600
> +++ asterisk-1.4.30-hacked/channels/chan_sip.c 2011-05-05 13:24:51.000000000 -0500
> @@ -18796,7 +18796,7 @@
> sipsock = -1;
> }
> if (sipsock < 0) {
> - sipsock = socket(AF_INET, SOCK_DGRAM, 0);
> + sipsock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
> if (sipsock < 0) {
> ast_log(LOG_WARNING, "Unable to create SIP socket: %s\n", strerror(errno));
> ast_config_destroy(cfg);
> diff -Naur asterisk-1.4.30/contrib/scripts/safe_asterisk asterisk-1.4.30-hacked/contrib/scripts/safe_asterisk
> --- asterisk-1.4.30/contrib/scripts/safe_asterisk 2010-01-11 21:18:36.000000000 -0600
> +++ asterisk-1.4.30-hacked/contrib/scripts/safe_asterisk 2011-05-05 10:38:04.000000000 -0500
> @@ -131,6 +131,9 @@
> if test "x$EXITSTATUS" = "x0" ; then
> # Properly shutdown....
> echo "Asterisk shutdown normally."
> + if test "0$KILLALLMPG123" -gt "0" ; then
> + killall -9 mpg123
> + fi
> exit 0
> elif test "0$EXITSTATUS" -gt "128" ; then
> EXITSIGNAL=$(($EXITSTATUS - 128))
> diff -Naur asterisk-1.4.30/funcs/func_curl.c asterisk-1.4.30-hacked/funcs/func_curl.c
> --- asterisk-1.4.30/funcs/func_curl.c 2008-10-06 15:52:04.000000000 -0500
> +++ asterisk-1.4.30-hacked/funcs/func_curl.c 2011-04-25 14:10:19.000000000 -0500
> @@ -82,6 +82,11 @@
> return realsize;
> }
>
> +int mySocketOpen(void *clientp, curlsocktype purpose, struct curl_sockaddr *address)
> +{
> + return socket(address->family, address->socktype | SOCK_CLOEXEC, address->protocol);
> +}
> +
> static const char *global_useragent = "asterisk-libcurl-agent/1.0";
>
> static void curl_instance_cleanup(void *data)
> @@ -110,6 +115,8 @@
> curl_easy_setopt(*curl, CURLOPT_TIMEOUT, 180);
> curl_easy_setopt(*curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
> curl_easy_setopt(*curl, CURLOPT_USERAGENT, global_useragent);
> + curl_easy_setopt(*curl, CURLOPT_FORBID_REUSE, 1);
> + curl_easy_setopt(*curl, CURLOPT_OPENSOCKETFUNCTION, mySocketOpen);
> }
>
> curl_easy_setopt(*curl, CURLOPT_URL, url);
> diff -Naur asterisk-1.4.30/main/asterisk.c asterisk-1.4.30-hacked/main/asterisk.c
> --- asterisk-1.4.30/main/asterisk.c 2010-02-25 15:21:05.000000000 -0600
> +++ asterisk-1.4.30-hacked/main/asterisk.c 2011-05-09 13:06:57.000000000 -0500
> @@ -1015,14 +1015,14 @@
> continue;
> }
> len = sizeof(sunaddr);
> - s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
> + s = accept4(ast_socket, (struct sockaddr *)&sunaddr, &len, SOCK_CLOEXEC);
> if (s < 0) {
> if (errno != EINTR)
> ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
> } else {
> for (x = 0; x < AST_MAX_CONNECTS; x++) {
> if (consoles[x].fd < 0) {
> - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
> + if (socketpair(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0, consoles[x].p)) {
> ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
> consoles[x].fd = -1;
> fdprint(s, "Server failed to create pipe\n");
> @@ -1068,7 +1068,7 @@
> for (x = 0; x < AST_MAX_CONNECTS; x++)
> consoles[x].fd = -1;
> unlink(ast_config_AST_SOCKET);
> - ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
> + ast_socket = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
> if (ast_socket < 0) {
> ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
> return -1;
> @@ -1130,7 +1130,7 @@
> {
> struct sockaddr_un sunaddr;
> int res;
> - ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
> + ast_consock = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
> if (ast_consock < 0) {
> ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
> return 0;
> @@ -3188,7 +3188,7 @@
> if (ast_opt_no_fork)
> consolethread = pthread_self();
>
> - if (pipe(sig_alert_pipe))
> + if (pipe2(sig_alert_pipe, O_CLOEXEC))
> sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
>
> ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
> diff -Naur asterisk-1.4.30/main/channel.c asterisk-1.4.30-hacked/main/channel.c
> --- asterisk-1.4.30/main/channel.c 2010-02-12 17:30:17.000000000 -0600
> +++ asterisk-1.4.30-hacked/main/channel.c 2011-04-25 14:15:54.000000000 -0500
> @@ -758,7 +758,7 @@
> #endif
>
> if (needqueue) {
> - if (pipe(tmp->alertpipe)) {
> + if (pipe2(tmp->alertpipe,O_CLOEXEC)) {
> ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe! Try increasing max file descriptors with ulimit -n\n");
> alertpipe_failed:
> #ifdef HAVE_DAHDI
> @@ -1591,7 +1591,8 @@
> }
>
> ast_channel_unlock(chan);
> - manager_event(EVENT_FLAG_CALL, "Hangup",
> + //manager_event(EVENT_FLAG_CALL, "Hangup",
> + manager_event(EVENT_FLAG_USER, "Hangup",
> "Channel: %s\r\n"
> "Uniqueid: %s\r\n"
> "Cause: %d\r\n"
> diff -Naur asterisk-1.4.30/main/file.c asterisk-1.4.30-hacked/main/file.c
> --- asterisk-1.4.30/main/file.c 2010-01-08 13:20:44.000000000 -0600
> +++ asterisk-1.4.30-hacked/main/file.c 2011-04-20 13:45:03.000000000 -0500
> @@ -457,6 +457,7 @@
> */
> if (action == ACTION_OPEN) {
> struct ast_channel *chan = (struct ast_channel *)arg2;
> + int fd;
> FILE *bfile;
> struct ast_filestream *s;
>
> @@ -465,7 +466,14 @@
> free(fn);
> continue; /* not a supported format */
> }
> - if ( (bfile = fopen(fn, "r")) == NULL) {
> + fd = open(fn, O_RDONLY|O_CLOEXEC);
> + if (fd > -1) {
> + if ( (bfile = fdopen(fd, "r")) == NULL) {
> + free(fn);
> + close(fd);
> + continue; /* cannot open file */
> + }
> + } else {
> free(fn);
> continue; /* cannot open file */
> }
> @@ -1080,7 +1088,7 @@
> format_found = 1;
>
> fn = build_filename(filename, type);
> - fd = open(fn, flags | myflags, mode);
> + fd = open(fn, flags | myflags | O_CLOEXEC, mode);
> if (fd > -1) {
> /* fdopen() the resulting file stream */
> bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
> diff -Naur asterisk-1.4.30/main/logger.c asterisk-1.4.30-hacked/main/logger.c
> --- asterisk-1.4.30/main/logger.c 2010-02-24 15:02:18.000000000 -0600
> +++ asterisk-1.4.30-hacked/main/logger.c 2011-05-12 13:35:42.000000000 -0500
> @@ -38,6 +38,7 @@
> #include <stdlib.h>
> #include <errno.h>
> #include <sys/stat.h>
> +#include <fcntl.h>
> #if ((defined(AST_DEVMODE)) && (defined(linux)))
> #include <execinfo.h>
> #define MAX_BACKTRACE_FRAMES 20
> @@ -264,7 +265,8 @@
> snprintf(chan->filename, sizeof(chan->filename), "%s/%s",
> channel[0] != '/' ? ast_config_AST_LOG_DIR : "", channel);
> }
> - chan->fileptr = fopen(chan->filename, "a");
> + int fd = open((char *)(chan->filename), O_CREAT | O_APPEND | O_WRONLY | O_CLOEXEC, 0644);
> + chan->fileptr = fdopen(fd, "a");
> if (!chan->fileptr) {
> /* Can't log here, since we're called with a lock */
> fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
> @@ -432,7 +434,8 @@
> ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
> }
>
> - eventlog = fopen(old, "a");
> + int efd = open((char *)old, O_CREAT | O_APPEND | O_WRONLY | O_CLOEXEC, 0644);
> + eventlog = fdopen(efd, "a");
> if (eventlog) {
> ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
> if (option_verbose)
> @@ -460,7 +463,8 @@
> ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
> }
>
> - qlog = fopen(old, "a");
> + int qfd = open((char *)old, O_CREAT | O_APPEND | O_WRONLY | O_CLOEXEC, 0644);
> + qlog = fdopen(qfd, "a");
> if (qlog) {
> ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
> ast_log(LOG_EVENT, "Restarted Asterisk Queue Logger\n");
> @@ -600,7 +604,8 @@
> if (logfiles.event_log) {
> mkdir((char *)ast_config_AST_LOG_DIR, 0755);
> snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
> - eventlog = fopen((char *)tmp, "a");
> + int efd = open((char *)tmp, O_CREAT | O_APPEND | O_WRONLY | O_CLOEXEC, 0644);
> + eventlog = fdopen(efd, "a");
> if (eventlog) {
> ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
> if (option_verbose)
> @@ -613,7 +618,8 @@
>
> if (logfiles.queue_log) {
> snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
> - qlog = fopen(tmp, "a");
> + int qfd = open((char *)tmp, O_CREAT | O_APPEND | O_WRONLY | O_CLOEXEC, 0644);
> + qlog = fdopen(qfd, "a");
> ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
> }
> return res;
> diff -Naur asterisk-1.4.30/main/manager.c asterisk-1.4.30-hacked/main/manager.c
> --- asterisk-1.4.30/main/manager.c 2010-01-25 14:08:32.000000000 -0600
> +++ asterisk-1.4.30-hacked/main/manager.c 2011-04-25 13:33:42.000000000 -0500
> @@ -2493,7 +2493,7 @@
> we can ditch any old manager sessions */
> if (ast_poll(pfds, 1, 5000) < 1)
> continue;
> - as = accept(asock, (struct sockaddr *)&sin, &sinlen);
> + as = accept4(asock, (struct sockaddr *)&sin, &sinlen,SOCK_CLOEXEC);
> if (as < 0) {
> ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
> continue;
> @@ -3289,7 +3289,7 @@
> return 0;
>
> if (asock < 0) {
> - asock = socket(AF_INET, SOCK_STREAM, 0);
> + asock = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
> if (asock < 0) {
> ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
> return -1;
> diff -Naur asterisk-1.4.30/main/rtp.c asterisk-1.4.30-hacked/main/rtp.c
> --- asterisk-1.4.30/main/rtp.c 2010-02-20 16:25:42.000000000 -0600
> +++ asterisk-1.4.30-hacked/main/rtp.c 2011-04-18 14:33:09.000000000 -0500
> @@ -1905,7 +1905,7 @@
> {
> int s;
> long flags;
> - s = socket(AF_INET, SOCK_DGRAM, 0);
> + s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
> if (s > -1) {
> flags = fcntl(s, F_GETFL);
> fcntl(s, F_SETFL, flags | O_NONBLOCK);
> diff -Naur asterisk-1.4.30/res/res_agi.c asterisk-1.4.30-hacked/res/res_agi.c
> --- asterisk-1.4.30/res/res_agi.c 2010-01-04 12:19:00.000000000 -0600
> +++ asterisk-1.4.30-hacked/res/res_agi.c 2011-05-12 09:29:22.000000000 -0500
> @@ -34,6 +34,9 @@
> #include <sys/types.h>
> #include <netdb.h>
> #include <sys/socket.h>
> +
> +#include <sys/un.h>
> +
> #include <netinet/in.h>
> #include <netinet/tcp.h>
> #include <arpa/inet.h>
> @@ -253,12 +256,10 @@
> return AGI_RESULT_SUCCESS_FAST;
> }
>
> -static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
> +static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
> {
> char tmp[256];
> int pid;
> - int toast[2];
> - int fromast[2];
> int audio[2];
> int x;
> int res;
> @@ -271,23 +272,9 @@
> snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
> script = tmp;
> }
> - if (pipe(toast)) {
> - ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
> - return AGI_RESULT_FAILURE;
> - }
> - if (pipe(fromast)) {
> - ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
> - close(toast[0]);
> - close(toast[1]);
> - return AGI_RESULT_FAILURE;
> - }
> if (efd) {
> if (pipe(audio)) {
> ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
> - close(fromast[0]);
> - close(fromast[1]);
> - close(toast[0]);
> - close(toast[1]);
> return AGI_RESULT_FAILURE;
> }
> res = fcntl(audio[1], F_GETFL);
> @@ -295,16 +282,31 @@
> res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
> if (res < 0) {
> ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
> - close(fromast[0]);
> - close(fromast[1]);
> - close(toast[0]);
> - close(toast[1]);
> close(audio[0]);
> close(audio[1]);
> return AGI_RESULT_FAILURE;
> }
> }
>
> + //
> + // create and bind unix socket for file descriptors
> + //
> +
> + int ast_sock;
> + if ((ast_sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) {
> + ast_log(LOG_ERROR, "unable to create ast socket: %s\n", strerror(errno));
> + return AGI_RESULT_FAILURE;
> + }
> +
> + struct sockaddr_un ast_address;
> + ast_address.sun_family = AF_UNIX;
> + sprintf(ast_address.sun_path, "/tmp/asterisk-%s",chan->uniqueid);
> +
> + if((res = bind(ast_sock, (const struct sockaddr *) &ast_address, sizeof(struct sockaddr_un))) != 0) {
> + ast_log(LOG_ERROR, "ast_sock bind failed, %s\n", strerror(errno));
> + return AGI_RESULT_FAILURE;
> + }
> +
> /* Block SIGHUP during the fork - prevents a race */
> sigfillset(&signal_set);
> pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
> @@ -312,9 +314,72 @@
> if (pid < 0) {
> ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
> pthread_sigmask(SIG_SETMASK, &old_set, NULL);
> +
> + close(ast_sock);
> +
> return AGI_RESULT_FAILURE;
> }
> if (!pid) {
> +
> + //
> + // create and connect unix socket for file descriptors
> + //
> +
> + int agi_sock;
> + if ((agi_sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
> + ast_log(LOG_ERROR, "unable to create agi socket: %s\n", strerror(errno));
> + _exit(1);
> + }
> +
> + if((res = connect(agi_sock, (const struct sockaddr *) &ast_address, sizeof(struct sockaddr_un))) != 0) {
> + ast_log(LOG_ERROR, "agi_sock unable to connect agi sock: %s\n", strerror(errno));
> + _exit(1);
> + }
> +
> + //
> + // send toast/fromast file descriptors to asterisk
> + //
> +
> + int agi_fds[2] = { 0, };
> + int toast[2] = { 0, };
> + int fromast[2] = { 0, };
> +
> + if (!pipe2(toast,O_CLOEXEC)) {
> + agi_fds[0] = toast[0];
> + } else {
> + ast_log(LOG_ERROR, "Unable to create toast pipe: %s\n",strerror(errno));
> + _exit(1);
> + }
> + if (!pipe2(fromast,O_CLOEXEC)) {
> + agi_fds[1] = fromast[1];
> + } else {
> + ast_log(LOG_ERROR, "unable to create fromast pipe: %s\n", strerror(errno));
> + _exit(1);
> + }
> +
> + char agi_data[1] = { '*' };
> + struct iovec agi_iov[1] = { { .iov_base = agi_data, .iov_len = 1 } };
> +
> + char agi_buf[CMSG_SPACE(2 * sizeof(int))] = { 0, };
> +
> + struct msghdr agi_message = { .msg_iov = agi_iov, .msg_iovlen = 1, .msg_control = agi_buf, .msg_controllen = sizeof agi_buf };
> +
> + struct cmsghdr *agi_cmsg = CMSG_FIRSTHDR(&agi_message);
> + agi_cmsg->cmsg_level = SOL_SOCKET;
> + agi_cmsg->cmsg_type = SCM_RIGHTS;
> + agi_cmsg->cmsg_len = CMSG_LEN(2 * sizeof(int));
> +
> + int *agi_cmsg_fds_ptr = (int *)CMSG_DATA(agi_cmsg);
> + memcpy(agi_cmsg_fds_ptr, agi_fds, 2 * sizeof(int));
> + agi_message.msg_controllen = agi_cmsg->cmsg_len;
> +
> + if ((res = sendmsg(agi_sock, &agi_message, 0)) < 0) {
> + ast_log(LOG_ERROR, "agi fds sendmsg failed: %s\n", strerror(errno));
> + _exit(1);
> + }
> +
> + close(agi_sock);
> +
> #ifdef HAVE_CAP
> cap_t cap = cap_from_text("cap_net_admin-eip");
>
> @@ -366,9 +431,10 @@
> }
>
> /* Close everything but stdin/out/error */
> + /*
> for (x=STDERR_FILENO + 2;x<1024;x++)
> close(x);
> -
> + */
> /* Execute script */
> execv(script, argv);
> /* Can't use ast_log since FD's are closed */
> @@ -379,16 +445,35 @@
> _exit(1);
> }
> pthread_sigmask(SIG_SETMASK, &old_set, NULL);
> +
> + //
> + //receive toast/fromast file descriptors from agi process
> + //
> +
> + char ast_data[1] = { 0, };
> + struct iovec ast_iov[1] = { { .iov_base = ast_data, .iov_len = 1 } };
> +
> + char ast_buf[CMSG_SPACE(2 * sizeof(int))] = { 0, };
> +
> + struct msghdr ast_message = { .msg_iov = ast_iov, .msg_iovlen = 1, .msg_control = ast_buf, .msg_controllen = CMSG_LEN(2 * sizeof(int)) };
> +
> + if ((res = recvmsg(ast_sock, &ast_message, MSG_CMSG_CLOEXEC)) < 0) {
> + ast_log(LOG_ERROR, "ast fds recvmsg failed: %s\n", strerror(errno));
> + return AGI_RESULT_FAILURE;
> + }
> +
> + struct cmsghdr *ast_cmsg = CMSG_FIRSTHDR(&ast_message);
> + memcpy(fds,CMSG_DATA(ast_cmsg),2 * sizeof(int));
> +
> + close(ast_sock);
> +
> + unlink(ast_address.sun_path);
> +
> if (option_verbose > 2)
> ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
> - fds[0] = toast[0];
> - fds[1] = fromast[1];
> if (efd) {
> *efd = audio[1];
> }
> - /* close what we're not using in the parent */
> - close(toast[1]);
> - close(fromast[0]);
>
> if (efd)
> close(audio[0]);
> @@ -2143,7 +2228,7 @@
> }
> #endif
> ast_replace_sigchld();
> - res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
> + res = launch_script(chan, argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
> if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
> int status = 0;
> agi.fd = fds[1];
>
>
> --
> Paul Albrecht
>
>
> --
> _____________________________________________________________________
> -- Bandwidth and Colocation Provided by http://www.api-digital.com --
>
> asterisk-dev mailing list
> To UNSUBSCRIBE or update options visit:
> http://lists.digium.com/mailman/listinfo/asterisk-dev
>
More information about the asterisk-dev
mailing list