[asterisk-dev] asterisk 1.4 rtp port exhaustion fix
Paul Albrecht
albrecht at glccom.com
Mon May 16 13:02:18 CDT 2011
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
More information about the asterisk-dev
mailing list