commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mt...@apache.org
Subject svn commit: r1165189 - in /commons/sandbox/runtime/trunk: ./ src/main/java/org/apache/commons/runtime/net/ src/main/native/ src/main/native/os/unix/ src/main/native/os/win32/ src/main/test/org/apache/commons/runtime/
Date Mon, 05 Sep 2011 07:08:56 GMT
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



Mime
View raw message