[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