8231187: SelectorProvider.inheritedChannel() returns TCP socket channel for Unix domain socket
Reviewed-by: alanb, chegar
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java Tue Sep 24 17:08:19 2019 +0200
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorProvider.java Tue Sep 24 16:19:11 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
import java.io.IOException;
import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.*;
public class KQueueSelectorProvider
extends SelectorProviderImpl
@@ -34,4 +35,8 @@
public AbstractSelector openSelector() throws IOException {
return new KQueueSelectorImpl(this);
}
+
+ public Channel inheritedChannel() throws IOException {
+ return InheritedChannel.getChannel();
+ }
}
--- a/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java Tue Sep 24 17:08:19 2019 +0200
+++ b/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java Tue Sep 24 16:19:11 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,12 @@
private static final int SOCK_STREAM = 1;
private static final int SOCK_DGRAM = 2;
+ // socket address type
+ private static final int AF_UNKNOWN = -1;
+ private static final int AF_INET = 1;
+ private static final int AF_INET6 = 2;
+ private static final int AF_UNIX = 3;
+
// oflag values when opening a file
private static final int O_RDONLY = 0;
private static final int O_WRONLY = 1;
@@ -89,6 +95,20 @@
}
}
+ public static class InheritedUnixChannelImpl extends UnixDomainSocketChannelImpl {
+
+ InheritedUnixChannelImpl(FileDescriptor fd)
+ throws IOException
+ {
+ super(fd);
+ }
+
+ protected void implCloseSelectableChannel() throws IOException {
+ super.implCloseChannel();
+ detachIOStreams();
+ }
+ }
+
public static class InheritedServerSocketChannelImpl extends
ServerSocketChannelImpl {
@@ -160,7 +180,6 @@
return null;
}
-
// Next we create a FileDescriptor for the dup'ed file descriptor
// Have to use reflection and also make assumption on how FD
// is implemented.
@@ -182,6 +201,17 @@
Channel c;
if (st == SOCK_STREAM) {
+ int family = addressFamily(fdVal);
+ if (family == AF_UNKNOWN)
+ return null;
+ if (family == AF_UNIX) {
+ if (isConnected(fdVal)) {
+ return new InheritedUnixChannelImpl(fd);
+ } else {
+ // listener. unsupported.
+ return null;
+ }
+ }
InetAddress ia = peerAddress0(fdVal);
if (ia == null) {
c = new InheritedServerSocketChannelImpl(provider, fd);
@@ -232,9 +262,13 @@
private static native int open0(String path, int oflag) throws IOException;
private static native void close0(int fd) throws IOException;
private static native int soType0(int fd);
+ private static native int addressFamily(int fd);
private static native InetAddress peerAddress0(int fd);
private static native int peerPort0(int fd);
+ // return true if socket is connected to a peer
+ private static native boolean isConnected(int fd);
+
static {
IOUtil.load();
initIDs();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java Tue Sep 24 16:19:11 2019 +0100
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ByteChannel;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.spi.AbstractInterruptibleChannel;
+import java.util.Objects;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+class UnixDomainSocketChannelImpl
+ extends AbstractInterruptibleChannel
+ implements ByteChannel
+{
+ // Used to make native read and write calls
+ private static final NativeDispatcher nd = new SocketDispatcher();
+
+ // Our file descriptor object
+ private final FileDescriptor fd;
+ // Lock held by current reading or connecting thread
+ private final ReentrantLock readLock = new ReentrantLock();
+
+ // Lock held by current writing or connecting thread
+ private final ReentrantLock writeLock = new ReentrantLock();
+
+ // Lock for managing close state
+ private final Object stateLock = new Object();
+
+ // Channel state
+ private static final int ST_INUSE = 0;
+ private static final int ST_CLOSING = 1;
+ private static final int ST_CLOSED = 2;
+ private int state;
+
+ // IDs of native threads doing reads and writes, for signalling
+ private long readerThread;
+ private long writerThread;
+
+ UnixDomainSocketChannelImpl(FileDescriptor fd)
+ throws IOException
+ {
+ this.fd = fd;
+ }
+
+ /**
+ * Checks that the channel is open.
+ *
+ * @throws ClosedChannelException if channel is closed (or closing)
+ */
+ private void ensureOpen() throws ClosedChannelException {
+ if (!isOpen())
+ throw new ClosedChannelException();
+ }
+
+ /**
+ * Closes the socket if there are no I/O operations in progress
+ */
+ private boolean tryClose() throws IOException {
+ assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
+ if (readerThread == 0 && writerThread == 0) {
+ state = ST_CLOSED;
+ nd.close(fd);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Complete closure of pre-closed socket (release the file descriptor)
+ */
+ private void tryFinishClose() {
+ try {
+ tryClose();
+ } catch (IOException ignore) { }
+ }
+
+ /**
+ * Marks the beginning of a read operation
+ *
+ * @throws ClosedChannelException if the channel is closed
+ * @throws NotYetConnectedException if the channel is not yet connected
+ */
+ private void beginRead() throws ClosedChannelException {
+ // set hook for Thread.interrupt
+ begin();
+ synchronized (stateLock) {
+ ensureOpen();
+ readerThread = NativeThread.current();
+ }
+ }
+
+ /**
+ * Marks the end of a read operation that may have blocked.
+ *
+ * @throws AsynchronousCloseException if the channel was closed due to this
+ * thread being interrupted on a blocking read operation.
+ */
+ private void endRead(boolean completed)
+ throws AsynchronousCloseException
+ {
+ synchronized (stateLock) {
+ readerThread = 0;
+ if (state == ST_CLOSING) {
+ tryFinishClose();
+ }
+ }
+ end(completed);
+ }
+
+ @Override
+ public int read(ByteBuffer buf) throws IOException {
+ Objects.requireNonNull(buf);
+
+ readLock.lock();
+ try {
+ int n = 0;
+ try {
+ beginRead();
+ n = IOUtil.read(fd, buf, -1, nd);
+ while (IOStatus.okayToRetry(n) && isOpen()) {
+ park(Net.POLLIN, 0L);
+ n = IOUtil.read(fd, buf, -1, nd);
+ }
+ } finally {
+ endRead(n > 0);
+ }
+ return n;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * Marks the beginning of a write operation that might block.
+ *
+ * @throws ClosedChannelException if the channel is closed
+ * @throws NotYetConnectedException if the channel is not yet connected
+ */
+ private void beginWrite() throws ClosedChannelException {
+ begin();
+ synchronized (stateLock) {
+ // set hook for Thread.interrupt
+ ensureOpen();
+ writerThread = NativeThread.current();
+ }
+ }
+
+ /**
+ * Marks the end of a write operation that may have blocked.
+ *
+ * @throws AsynchronousCloseException if the channel was closed due to this
+ * thread being interrupted on a blocking write operation.
+ */
+ private void endWrite(boolean completed)
+ throws AsynchronousCloseException
+ {
+ synchronized (stateLock) {
+ writerThread = 0;
+ if (state == ST_CLOSING) {
+ tryFinishClose();
+ }
+ }
+ end(completed);
+ }
+
+ void park(int event, long nanos) throws IOException {
+ long millis;
+ if (nanos <= 0) {
+ millis = -1;
+ } else {
+ millis = NANOSECONDS.toMillis(nanos);
+ }
+ Net.poll(fd, event, millis);
+ }
+
+ @Override
+ public int write(ByteBuffer buf) throws IOException {
+ Objects.requireNonNull(buf);
+
+ writeLock.lock();
+ try {
+ int n = 0;
+ try {
+ beginWrite();
+ n = IOUtil.write(fd, buf, -1, nd);
+ while (IOStatus.okayToRetry(n) && isOpen()) {
+ park(Net.POLLOUT, 0L);
+ n = IOUtil.write(fd, buf, -1, nd);
+ }
+ } finally {
+ endWrite(n > 0);
+ }
+ return n;
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * Closes this channel
+ *
+ * If there is an I/O operation in progress then the socket is pre-closed
+ * and the I/O threads signalled, in which case the final close is deferred
+ * until all I/O operations complete.
+ */
+ @Override
+ protected void implCloseChannel() throws IOException {
+ synchronized (stateLock) {
+ assert state == ST_INUSE;
+ state = ST_CLOSING;
+ if (!tryClose()) {
+ long reader = readerThread;
+ long writer = writerThread;
+ if (reader != 0 || writer != 0) {
+ nd.preClose(fd);
+ if (reader != 0)
+ NativeThread.signal(reader);
+ if (writer != 0)
+ NativeThread.signal(writer);
+ }
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getSuperclass().getName());
+ sb.append('[');
+ if (!isOpen())
+ sb.append("closed");
+ sb.append(']');
+ return sb.toString();
+ }
+}
--- a/src/java.base/unix/native/libnio/ch/InheritedChannel.c Tue Sep 24 17:08:19 2019 +0200
+++ b/src/java.base/unix/native/libnio/ch/InheritedChannel.c Tue Sep 24 16:19:11 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -82,6 +82,39 @@
}
JNIEXPORT jint JNICALL
+Java_sun_nio_ch_InheritedChannel_addressFamily(JNIEnv *env, jclass cla, jint fd)
+{
+ SOCKETADDRESS addr;
+ socklen_t addrlen = sizeof(addr);
+
+ if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) < 0) {
+ return sun_nio_ch_InheritedChannel_AF_UNKNOWN;
+ }
+ if (addr.sa.sa_family == AF_INET) {
+ return sun_nio_ch_InheritedChannel_AF_INET;
+ }
+ if (addr.sa.sa_family == AF_INET6) {
+ return sun_nio_ch_InheritedChannel_AF_INET6;
+ }
+ if (addr.sa.sa_family == AF_UNIX) {
+ return sun_nio_ch_InheritedChannel_AF_UNIX;
+ }
+ return sun_nio_ch_InheritedChannel_AF_UNKNOWN;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_InheritedChannel_isConnected(JNIEnv *env, jclass cla, jint fd)
+{
+ SOCKETADDRESS addr;
+ socklen_t addrlen = sizeof(addr);
+
+ if (getpeername(fd, (struct sockaddr *)&addr, &addrlen) < 0) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+JNIEXPORT jint JNICALL
Java_sun_nio_ch_InheritedChannel_soType0(JNIEnv *env, jclass cla, jint fd)
{
int sotype;
--- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java Tue Sep 24 17:08:19 2019 +0200
+++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java Tue Sep 24 16:19:11 2019 +0100
@@ -25,7 +25,7 @@
* @test
* @bug 4673940 4930794 8211842
* @summary Unit tests for inetd feature
- * @requires (os.family == "linux" | os.family == "solaris")
+ * @requires (os.family == "linux" | os.family == "solaris" | os.family == "mac")
* @library /test/lib
* @build jdk.test.lib.Utils
* jdk.test.lib.Asserts
@@ -33,7 +33,8 @@
* jdk.test.lib.JDKToolLauncher
* jdk.test.lib.Platform
* jdk.test.lib.process.*
- * UnixSocketTest StateTest StateTestService EchoTest EchoService CloseTest Launcher Util
+ * UnixSocketTest StateTest StateTestService EchoTest EchoService
+ * UnixDomainChannelTest CloseTest Launcher Util
* @run testng/othervm/native InheritedChannelTest
* @key intermittent
*/
@@ -73,7 +74,8 @@
@DataProvider
public Object[][] testCases() {
- return new Object[][]{
+ return new Object[][] {
+ { "UnixDomainChannelTest", List.of(UnixDomainChannelTest.class.getName())},
{ "UnixSocketTest", List.of(UnixSocketTest.class.getName())},
{ "StateTest", List.of(StateTest.class.getName()) },
{ "EchoTest", List.of(EchoTest.class.getName()) },
@@ -83,6 +85,7 @@
// Note that the system properties are arguments to StateTest and not options.
// These system properties are passed to the launched service as options:
// java [-options] class [args...]
+
{ "StateTest run with " + POLICY_PASS, List.of(StateTest.class.getName(),
"-Djava.security.manager",
"-Djava.security.policy="
@@ -97,7 +100,7 @@
};
}
- @Test(dataProvider = "testCases")
+ @Test(dataProvider = "testCases", timeOut=30000)
public void test(String desc, List<String> opts) throws Throwable {
String pathVar = Platform.sharedLibraryPathVariableName();
System.out.println(pathVar + "=" + libraryPath);
--- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/Launcher.java Tue Sep 24 17:08:19 2019 +0200
+++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/Launcher.java Tue Sep 24 16:19:11 2019 +0100
@@ -1,5 +1,4 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -75,6 +74,15 @@
return socks[1];
}
+ /**
+ * Launch specified class with an AF_UNIX socket created externally, and one String arg to child VM
+ */
+ public static void launchWithUnixDomainSocket(String className, UnixDomainSocket socket, String arg) throws IOException {
+ String[] args = new String[1];
+ args[0] = arg;
+ launch(className, null, args, socket.fd());
+ }
+
/*
* Launch 'java' with specified class with the specified arguments (may be null).
* The launched process will inherit a connected TCP socket. The remote endpoint
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainChannelTest.java Tue Sep 24 16:19:11 2019 +0100
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.channels.*;
+import java.nio.ByteBuffer;
+import java.io.IOException;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
+/*
+ * Make sure that System.inheritedChannel returns null when given a UNIX domain socket
+ */
+
+public class UnixDomainChannelTest {
+
+ public static class Child {
+ public static void main(String[] args) throws Exception {
+ // we just want to make sure that System.inheritedChannel either
+ // returns a connected channel, or null if it is given a listener
+ Channel channel = System.inheritedChannel();
+ String result = channel == null ? "N" : "Y";
+ if (args[0].equals("test1") || args[0].equals("test2")) {
+ // socket is writeable
+ ByteChannel bc = (ByteChannel)channel;
+ ByteBuffer buf = ByteBuffer.wrap(result.getBytes(ISO_8859_1));
+ bc.write(buf);
+ } else { // test3
+ // in this case the socket is a listener
+ // we can't write to it. So, use UnixDatagramSocket
+ // to accept a writeable socket
+ UnixDomainSocket listener = new UnixDomainSocket(0); // fd 0
+ UnixDomainSocket sock = listener.accept();
+ sock.write((int)result.charAt(0));
+ }
+ }
+ }
+
+ static boolean passed = true;
+
+ public static void main(String args[]) throws Exception {
+ test1();
+ test2();
+ test3();
+ if (!passed)
+ throw new RuntimeException();
+ }
+
+ private static void closeAll(UnixDomainSocket... sockets) {
+ for (UnixDomainSocket sock : sockets) {
+ sock.close();
+ }
+ }
+
+ // Test with a named connected socket
+ private static void test1() throws Exception {
+ UnixDomainSocket listener = new UnixDomainSocket();
+ listener.bind("foo.socket");
+ UnixDomainSocket sock1 = new UnixDomainSocket();
+ sock1.connect("foo.socket");
+ UnixDomainSocket sock2 = listener.accept();
+
+ Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", sock2, "test1");
+ int c = sock1.read();
+ if (c != 'Y') {
+ System.err.printf("test1: failed %d d\n", c );
+ passed = false;
+ }
+ closeAll(listener, sock1, sock2);
+ }
+
+ // Test with unnamed socketpair
+ private static void test2() throws Exception {
+ UnixDomainSocket[] pair = UnixDomainSocket.socketpair();
+ System.out.println("test2: launching child");
+ Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", pair[0], "test2");
+ if (pair[1].read() != 'Y') {
+ System.err.println("test2: failed");
+ passed = false;
+ }
+ closeAll(pair[0], pair[1]);
+ }
+
+ // Test with a named listener
+ private static void test3() throws Exception {
+ UnixDomainSocket listener = new UnixDomainSocket();
+ listener.bind("foo.socket");
+ UnixDomainSocket sock1 = new UnixDomainSocket();
+ System.out.println("test3: launching child");
+ Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", listener, "test3");
+ sock1.connect("foo.socket");
+ if (sock1.read() != 'N') {
+ System.err.println("test3: failed");
+ passed = false;
+ }
+ closeAll(listener, sock1);
+ }
+
+}
--- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainSocket.java Tue Sep 24 17:08:19 2019 +0200
+++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainSocket.java Tue Sep 24 16:19:11 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,21 +37,44 @@
}
private final int fd;
+ private volatile String name;
+
+ public UnixDomainSocket() throws IOException {
+ this.fd = create();
+ }
+
+ public void bind(String name) throws IOException {
+ bind0(fd, name);
+ this.name = name;
+ }
+
+ public UnixDomainSocket accept() throws IOException {
+ int newsock = accept0(fd);
+ return new UnixDomainSocket(newsock);
+ }
public UnixDomainSocket(int fd) {
this.fd = fd;
}
+ public void connect(String dest) throws IOException {
+ connect0(fd, dest);
+ }
+
public int read() throws IOException {
return read0(fd);
}
+ public String name() {
+ return name;
+ }
+
public void write(int w) throws IOException {
write0(fd, w);
}
public void close() {
- close0(fd);
+ close0(fd, name); // close0 will unlink name if non-null
}
public int fd() {
@@ -62,11 +85,16 @@
return "UnixDomainSocket: fd=" + Integer.toString(fd);
}
+ private static native int create() throws IOException;
+ private static native void bind0(int fd, String name) throws IOException;
+ private static native int accept0(int fd) throws IOException;
+ private static native int connect0(int fd, String name) throws IOException;
+
/* read and write bytes with UNIX domain sockets */
private static native int read0(int fd) throws IOException;
private static native void write0(int fd, int w) throws IOException;
- private static native void close0(int fd);
+ private static native void close0(int fd, String name);
private static native void init();
public static native UnixDomainSocket[] socketpair();
}
--- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/libInheritedChannel.c Tue Sep 24 17:08:19 2019 +0200
+++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/libInheritedChannel.c Tue Sep 24 16:19:11 2019 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,10 @@
*/
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
@@ -147,19 +149,18 @@
/*
* We need to close all file descriptors except for serviceFd. To
- * get the list of open file descriptos we read through /proc/self/fd
+ * get the list of open file descriptos we read through /proc/self/fd (/dev/fd)
* but to open this requires a file descriptor. We could use a specific
* file descriptor and fdopendir but Linux doesn't seem to support
* fdopendir. Instead we use opendir and make an assumption on the
* file descriptor that is used (by opening & closing a file).
*/
- thisFd = open("/dev/null", O_RDONLY);
+ thisFd = open("/dev/fd", O_RDONLY);
if (thisFd < 0) {
_exit(-1);
}
- close(thisFd);
- if ((dp = opendir("/proc/self/fd")) == NULL) {
+ if ((dp = fdopendir(thisFd)) == NULL) {
_exit(-1);
}
@@ -216,6 +217,65 @@
return result;
}
+JNIEXPORT jint JNICALL Java_UnixDomainSocket_create
+ (JNIEnv *env, jclass cls)
+{
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock == -1) {
+ ThrowException(env, "java/io/IOException", "socket create error");
+ }
+ return sock;
+}
+
+JNIEXPORT void JNICALL Java_UnixDomainSocket_bind0
+ (JNIEnv *env, jclass cls, jint sock, jstring name)
+{
+ struct sockaddr_un addr;
+ const char *nameUtf = (*env)->GetStringUTFChars(env, name, NULL);
+ int ret = -1;
+ unlink(nameUtf);
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, nameUtf, strlen(nameUtf));
+ ret = bind(sock, (const struct sockaddr*)&addr, sizeof(addr));
+ if (ret == -1) {
+ ThrowException(env, "java/io/IOException", "socket bind error");
+ }
+ ret = listen(sock, 5);
+ if (ret == -1) {
+ ThrowException(env, "java/io/IOException", "socket bind error");
+ }
+ (*env)->ReleaseStringUTFChars(env, name, nameUtf);
+}
+
+JNIEXPORT jint JNICALL Java_UnixDomainSocket_accept0
+ (JNIEnv *env, jclass cls, jint sock)
+{
+ struct sockaddr_storage addr;
+ socklen_t len = sizeof(addr);
+ int ret = accept(sock, (struct sockaddr *)&addr, &len);
+ if (ret == -1)
+ ThrowException(env, "java/io/IOException", "socket accept error");
+ return ret;
+}
+
+JNIEXPORT void JNICALL Java_UnixDomainSocket_connect0
+ (JNIEnv *env, jclass cls, jint fd, jstring name)
+{
+ struct sockaddr_un addr;
+ const char *nameUtf = (*env)->GetStringUTFChars(env, name, NULL);
+ int ret = -1;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, nameUtf, strlen(nameUtf));
+ ret = connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
+ if (ret == -1) {
+ ThrowException(env, "java/io/IOException", "socket connect error");
+ }
+ (*env)->ReleaseStringUTFChars(env, name, nameUtf);
+}
+
+
JNIEXPORT jint JNICALL Java_UnixDomainSocket_read0
(JNIEnv *env, jclass cls, jint fd)
{
@@ -243,7 +303,12 @@
}
JNIEXPORT void JNICALL Java_UnixDomainSocket_close0
- (JNIEnv *env, jclass cls, jint fd)
+ (JNIEnv *env, jclass cls, jint fd, jstring name)
{
close(fd);
+ if (name != NULL) {
+ const char *nameUtf = (*env)->GetStringUTFChars(env, name, NULL);
+ unlink(nameUtf);
+ (*env)->ReleaseStringUTFChars(env, name, nameUtf);
+ }
}