Author: mturk
Date: Mon Sep 5 07:08:56 2011
New Revision: 1165189
URL: http://svn.apache.org/viewvc?rev=1165189&view=rev
Log:
Add send socket api for sending the sockets between processes
Added:
commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfd.c (with
props)
commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestSendSocket.java
(with props)
Modified:
commons/sandbox/runtime/trunk/build.xml
commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Utils.java
commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in
commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_defs.h
commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h
commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c
commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_defs.h
Modified: commons/sandbox/runtime/trunk/build.xml
URL:
http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/build.xml?rev=1165189&r1=1165188&r2=1165189&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/build.xml (original)
+++ commons/sandbox/runtime/trunk/build.xml Mon Sep 5 07:08:56 2011
@@ -408,6 +408,17 @@ The Apache Software Foundation (http://w
</sequential>
</parallel>
</target>
+ <target name="testsendsockets" depends="tests">
+ <parallel>
+ <sequential>
+ <runtest groups="init,sendsd.parent" name="sendsd.parent"/>
+ </sequential>
+ <sequential>
+ <sleep milliseconds="100" />
+ <runtest groups="init,sendsd.child" name="sendsd.child"/>
+ </sequential>
+ </parallel>
+ </target>
<target name="testmutex" depends="tests">
<parallel>
<sequential>
Modified:
commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Utils.java
URL:
http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Utils.java?rev=1165189&r1=1165188&r2=1165189&view=diff
==============================================================================
---
commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Utils.java
(original)
+++
commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Utils.java
Mon Sep 5 07:08:56 2011
@@ -19,12 +19,50 @@
package org.apache.commons.runtime.net;
import java.io.IOException;
+import org.apache.commons.runtime.Status;
public final class Utils
{
+
+ private static native int sendfd0(String name, long[] fds,
+ int off, int len);
+ private static native long[] recvfd0(String name)
+ throws NetworkException;
+
private Utils()
{
// No instance.
}
+ /**
+ * Gets the name for the ipc socket used to send files
+ * between processes.
+ *
+ * @param pid id of the child process.
+ * @return name for the ipc socket
+ */
+ public static native String sendSocketName(int childPid)
+ throws NetworkException;
+
+ public static void sendSockets(String ipcName, long[] fds, int off, int
len)
+ throws NetworkException
+ {
+
+ if (ipcName == null)
+ throw new NullPointerException();
+ int rc = sendfd0(ipcName, fds, off, len);
+ if (rc != 0) {
+ throw new NetworkException(Status.describe(rc));
+ }
+ }
+
+
+ public static long[] recvSockets(String ipcName)
+ throws NetworkException
+ {
+ if (ipcName == null)
+ throw new NullPointerException();
+ return recvfd0(ipcName);
+ }
+
}
Modified: commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in
URL:
http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in?rev=1165189&r1=1165188&r2=1165189&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in (original)
+++ commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in Mon Sep 5
07:08:56 2011
@@ -75,6 +75,7 @@ UNIX_SOURCES=\
$(TOPDIR)/os/unix/shmem.c \
$(TOPDIR)/os/unix/selectset.c \
$(TOPDIR)/os/unix/semaphore.c \
+ $(TOPDIR)/os/unix/sendfd.c \
$(TOPDIR)/os/unix/sendfile.c \
$(TOPDIR)/os/unix/sockopts.c \
$(TOPDIR)/os/unix/sockstream.c \
Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_defs.h
URL:
http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_defs.h?rev=1165189&r1=1165188&r2=1165189&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_defs.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_defs.h Mon Sep
5 07:08:56 2011
@@ -156,4 +156,11 @@ typedef struct stat struct_stat_
#else
#endif
+#define ACR_NO_END_SLASHA(P) \
+ if (*(P) != '\0') { \
+ size_t _s = strlen((P)) - 1; \
+ if ((P)[_s] == '/') \
+ (P)[_s] = '\0'; \
+ } else (void)0
+
#endif /* _ACR_ARCH_DEFS_H_ */
Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h
URL:
http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h?rev=1165189&r1=1165188&r2=1165189&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h Mon Sep
5 07:08:56 2011
@@ -164,6 +164,6 @@ int AcrSocketPair(int pd[2], int fla
int AcrSigIgnore(int signo);
int AcrSigDefault(int signo);
void AcrDrainPipe(int fd);
-
+const char *AcrTempPathGet(const char *srch);
#endif /* _ACR_ARCH_OPTS_H_ */
Added: commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfd.c
URL:
http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfd.c?rev=1165189&view=auto
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfd.c (added)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfd.c Mon Sep 5
07:08:56 2011
@@ -0,0 +1,252 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "acr/jnitypes.h"
+#include "acr/error.h"
+#include "acr/debug.h"
+#include "acr/memory.h"
+#include "acr/netapi.h"
+#include "acr/string.h"
+#include "acr/port.h"
+#include "arch_opts.h"
+#include "arch_sync.h"
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#define MAX_SEND_FDS 512
+#define CONTROLLEN_BSIZE(N) (sizeof(struct cmsghdr) + (sizeof(int) * (N)))
+
+static char _nobuf = '?';
+static struct iovec _noiov = { &_nobuf , 1};
+
+static int
+send_fds(int sock, const int *fds, int nfd)
+{
+ struct msghdr hdr;
+ struct cmsghdr *cmsg;
+ int i, rc = 0;
+
+ hdr.msg_name = 0;
+ hdr.msg_namelen = 0;
+ hdr.msg_iov = &_noiov;
+ hdr.msg_iovlen = 1;
+ hdr.msg_flags = 0;
+ hdr.msg_controllen = CONTROLLEN_BSIZE(nfd);
+ hdr.msg_control = malloc(hdr.msg_controllen);
+ if (hdr.msg_control == 0)
+ return ENOMEM;
+
+ cmsg = CMSG_FIRSTHDR(&hdr);
+ cmsg->cmsg_len = hdr.msg_controllen;
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+
+ for(i = 0; i < nfd; i++)
+ ((int *)CMSG_DATA(cmsg))[i] = fds[i];
+ if (sendmsg(sock, &hdr, 0) == -1)
+ rc = errno;
+ free(hdr.msg_control);
+ return rc;
+}
+
+static int
+recv_fds(int sock, int *fds, int nfd)
+{
+ struct msghdr hdr;
+ char unused;
+ ssize_t r;
+ struct iovec iov = { &unused, 1 };
+ struct cmsghdr *cmsg;
+ int i;
+
+ hdr.msg_name = 0;
+ hdr.msg_namelen = 0;
+ hdr.msg_iov = &iov;
+ hdr.msg_iovlen = 1;
+ hdr.msg_flags = 0;
+ hdr.msg_controllen = CONTROLLEN_BSIZE(nfd);
+ hdr.msg_control = malloc(hdr.msg_controllen);
+ if (hdr.msg_control == 0)
+ return -1;
+
+ cmsg = CMSG_FIRSTHDR(&hdr);
+ cmsg->cmsg_len = hdr.msg_controllen;
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ for(i = 0; i < nfd; i++)
+ ((int *)CMSG_DATA(cmsg))[i] = -1;
+
+ do {
+ r = recvmsg(sock, &hdr, 0);
+ } while (r == -1 && errno == EINTR);
+
+ if (r == -1) {
+ free(hdr.msg_control);
+ return -1;
+ }
+ for(i = 0; i < nfd; i++)
+ fds[i] = ((int *)CMSG_DATA(cmsg))[i];
+ nfd = (cmsg->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int);
+ free(hdr.msg_control);
+ return nfd;
+}
+
+static int sendfd_sock(const char *name, int parent)
+{
+ int sd, rc = 0;
+ socklen_t salen;
+ struct sockaddr_un sa;
+
+ sa.sun_family = AF_LOCAL;
+ strlcpy(sa.sun_path, name, sizeof(sa.sun_path));
+ sd = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (sd == -1)
+ return -1;
+ salen = strlen(sa.sun_path) + ISIZEOF(sa.sun_family);
+ if (parent) {
+ if (bind(sd, (struct sockaddr *)&sa, salen) == -1) {
+ rc = errno;
+ goto failed;
+ }
+ if (listen(sd, 1) == -1) {
+ rc = errno;
+ goto failed;
+ }
+ }
+ else {
+ if (connect(sd, (struct sockaddr *)&sa, salen) == -1) {
+ rc = errno;
+ goto failed;
+ }
+ }
+ return sd;
+failed:
+ if (parent)
+ unlink(sa.sun_path);
+ close(sd);
+ errno = rc;
+ return -1;
+}
+
+ACR_NET_EXPORT(jstring, Utils, sendSocketName)(JNI_STDARGS, jint pid)
+{
+ char buf[1024];
+ const char *tmp;
+
+ if ((tmp = AcrTempPathGet(0)) == 0) {
+ ACR_THROW_NET_ERRNO();
+ return 0;
+ }
+ snprintf(buf, sizeof(buf), "%s/sendsock.%u", tmp, pid);
+ return AcrNewJavaStringA(env, buf);
+}
+
+ACR_NET_EXPORT(jint, Utils, sendfd0)(JNI_STDARGS, jstring name,
+ jlongArray fda,
+ jint off, jint len)
+{
+ int rc = 0;
+ jlong *fds = 0;
+ int i, fd[MAX_SEND_FDS];
+
+ if (len > MAX_SEND_FDS)
+ return ACR_EOVERFLOW;
+ WITH_CSTR(name) {
+ struct sockaddr_un ra;
+ socklen_t salen;
+ int sd = -1;
+ int cs = -1;
+
+ unlink(J2S(name));
+ if ((sd = sendfd_sock(J2S(name), 1)) == -1) {
+ rc = ACR_GET_OS_ERROR();
+ goto cleanup;
+ }
+ salen = ISIZEOF(ra);
+ if ((cs = accept(sd, (struct sockaddr *)&ra, &salen)) == -1) {
+ rc = errno;
+ goto cleanup;
+ }
+ fds = (*env)->GetLongArrayElements(env, fda, 0);
+ if (fds == 0) {
+ rc = ACR_EINVAL;
+ goto cleanup;
+ }
+ for (i = 0; i < len; i++) {
+ acr_sd_t *sp = J2P(fds[i + off], acr_sd_t *);
+ if (sp != 0) {
+ fd[i] = sp->s;
+ }
+ }
+ rc = send_fds(cs, fd, len);
+ (*env)->ReleaseLongArrayElements(env, fda, fds, JNI_ABORT);
+cleanup:
+ s_close(cs);
+ s_close(sd);
+ unlink(J2S(name));
+ } DONE_WITH_STR(name);
+ return rc;
+}
+
+ACR_NET_EXPORT(jlongArray, Utils, recvfd0)(JNI_STDARGS, jstring name)
+{
+ int rc = 0;
+ jlongArray fds = 0;
+ jint fda[MAX_SEND_FDS];
+ jlong sda[MAX_SEND_FDS];
+
+ WITH_CSTR(name) {
+ int sd;
+ if ((sd = sendfd_sock(J2S(name), 0)) == -1) {
+ rc = ACR_GET_OS_ERROR();
+ }
+ else {
+ int i, nfd = recv_fds(sd, fda, MAX_SEND_FDS);
+ if (nfd == - 1) {
+ rc = ACR_GET_OS_ERROR();
+ goto cleanup;
+ }
+ fds = (*env)->NewLongArray(env, nfd);
+ if (fds != 0) {
+ for (i = 0; i < nfd; i++) {
+ acr_sd_t *sp = ACR_TALLOC(acr_sd_t);
+ if (sp == 0) {
+ rc = ACR_ENOMEM;
+ break;
+ }
+ sp->type = ACR_DT_SOCKET;
+ sp->refs = 1;
+ sp->s = fda[i];
+ sp->timeout = -1;
+ sda[i] = P2J(sp);
+ }
+ (*env)->SetLongArrayRegion(env, fds, 0, nfd, sda);
+ }
+cleanup:
+ s_close(sd);
+ }
+ } DONE_WITH_STR(name);
+ if (rc != 0)
+ ACR_THROW_NET_ERROR(rc);
+ return fds;
+}
Propchange: commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfd.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c
URL:
http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c?rev=1165189&r1=1165188&r2=1165189&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c Mon Sep 5
07:08:56 2011
@@ -22,6 +22,21 @@
#include "arch_opts.h"
#include <poll.h>
+#define TMP_PATH_MAX (PATH_MAX - 12)
+static const char *_try_dirs[] = {
+ "/tmp",
+ "/usr/tmp",
+ "/var/tmp",
+ 0
+};
+
+static const char *_try_envs[] = {
+ "TMPDIR",
+ "TEMP",
+ "TMP",
+ 0
+};
+
#if HAVE_FDWALK
int AcrFdwalk(int (*func)(void *data , int fd), void *cd)
{
@@ -455,3 +470,102 @@ int AcrSigDefault(int signo)
else
return 0;
}
+
+static int _temp_test(const char *path)
+{
+ char tp[PATH_MAX];
+ int f;
+
+ strlcpy(tp, path, PATH_MAX);
+ ACR_NO_END_SLASHA(tp);
+ strlcat(tp, "/.acrXXXXXX", PATH_MAX);
+ f = mkstemp(tp);
+ if (f != -1) {
+ unlink(tp);
+ r_close(f);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+const char *AcrTempPathGet(const char *srch)
+{
+ static char _temp_path[TMP_PATH_MAX] = "";
+ int i = 0;
+
+ if (srch) {
+ char *p = strchr(srch, ':');
+ if (p == 0)
+ p = (char *)(srch + strlen(srch));
+ while (p) {
+ size_t part = p - srch + 1;
+ if (part >= TMP_PATH_MAX)
+ break;
+ strlcpy(_temp_path, srch, part);
+ if (_temp_path[0] && _temp_test(_temp_path)) {
+ ACR_NO_END_SLASHA(_temp_path);
+ break;
+ }
+ _temp_path[0] = '\0';
+ if (*p != ':') {
+ /* No more path components */
+ break;
+ }
+ else {
+ srch = p + 1;
+ p = strchr(srch, ':');
+ if (p == 0)
+ p = (char *)(srch + strlen(srch));
+ }
+ }
+ }
+ if (_temp_path[0] != '\0')
+ return _temp_path;
+ while (_try_envs[i]) {
+ char *val = getenv(_try_envs[i]);
+ if (val != 0 && *val != '\0') {
+ if (strlen(val) < TMP_PATH_MAX) {
+ if (_temp_test(val)) {
+ strlcpy(_temp_path, val, TMP_PATH_MAX);
+ break;
+ }
+ }
+ }
+ i++;
+ }
+ if (_temp_path[0] != '\0') {
+ ACR_NO_END_SLASHA(_temp_path);
+ return _temp_path;
+ }
+ i = 0;
+ while (_try_dirs[i]) {
+ if (strlen(_try_dirs[i]) < TMP_PATH_MAX) {
+ if (_temp_test(_try_dirs[i])) {
+ strlcpy(_temp_path, _try_dirs[i], TMP_PATH_MAX);
+ break;
+ }
+ }
+ i++;
+ }
+ if (_temp_path[0] != '\0') {
+ ACR_NO_END_SLASHA(_temp_path);
+ return _temp_path;
+ }
+ else {
+ /* Finally try the users $HOME */
+ char *val = getenv("HOME");
+ if (val != 0 && *val != '\0') {
+ if (strlen(val) < TMP_PATH_MAX) {
+ if (_temp_test(val))
+ strlcpy(_temp_path, val, TMP_PATH_MAX);
+ }
+ }
+ }
+ if (_temp_path[0] != '\0') {
+ ACR_NO_END_SLASHA(_temp_path);
+ return _temp_path;
+ }
+ else
+ return 0;
+}
Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_defs.h
URL:
http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_defs.h?rev=1165189&r1=1165188&r2=1165189&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_defs.h
(original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_defs.h Mon Sep
5 07:08:56 2011
@@ -180,4 +180,18 @@ static __inline int isblank(int c)
#define ACR_KEY_WOW64_32KEY 0x0400
#define ACR_KEY_WRITE 0x0800
+#define ACR_NO_END_SLASHA(P) \
+ if (*(P) != '\0') { \
+ size_t _s = strlen((P)) - 1; \
+ if ((P)[_s] == '/' || (P)[_s] == '\\') \
+ (P)[_s] = '\0'; \
+ } else (void)0
+
+#define ACR_NO_END_SLASHW(P) \
+ if (*(P) != L'\0') { \
+ size_t _s = wcslen((P)) - 1; \
+ if ((P)[_s] == L'/' || (P)[_s] == L'\\') \
+ (P)[_s] = L'\0'; \
+ } else (void)0
+
#endif /* _ACR_ARCH_DEFS_H_ */
Added:
commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestSendSocket.java
URL:
http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestSendSocket.java?rev=1165189&view=auto
==============================================================================
---
commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestSendSocket.java
(added)
+++
commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestSendSocket.java
Mon Sep 5 07:08:56 2011
@@ -0,0 +1,57 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.runtime.net;
+
+import java.io.IOException;
+import java.io.File;
+import org.testng.annotations.*;
+import org.testng.Assert;
+
+public class TestSendSocket extends Assert
+{
+
+ // TODO: How can we get a process id from the testng
+ // and use it here?
+ private static final String ipcname = "acrSendSockets23";
+
+ @Test(groups = { "sendsd.parent" })
+ public void sendSocket()
+ throws Exception
+ {
+ SocketServerEndpoint ss = new SocketServerEndpoint();
+ InetSocketAddress sa = new InetSocketAddress("127.0.0.1", 0);
+ ss.bind(sa);
+ long fds[] = new long[1];
+ fds[0] = ss.descriptor().fd();
+ Utils.sendSockets(ipcname, fds, 0, 1);
+ System.out.println("[parent] Done.");
+ System.out.flush();
+ }
+
+ @Test(groups = { "sendsd.child" })
+ public void recvSocket()
+ throws Exception
+ {
+ System.out.println("[child] Geting sockets");
+ System.out.flush();
+ long[] fds = Utils.recvSockets(ipcname);
+ assertEquals(fds.length, 1);
+ System.out.println("[child] Done.");
+ System.out.flush();
+ }
+
+}
Propchange:
commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestSendSocket.java
------------------------------------------------------------------------------
svn:eol-style = native