--- a/make/gensrc/GensrcMisc.gmk Fri Jan 25 11:15:00 2019 +0100
+++ b/make/gensrc/GensrcMisc.gmk Sat Jan 26 14:02:35 2019 +0000
@@ -87,6 +87,17 @@
GENSRC_JAVA_BASE += $(GENSRC_SOR_FILE)
+ifeq ($(OPENJDK_TARGET_OS), linux)
+ GENSRC_RSOR_FILE += $(SUPPORT_OUTPUTDIR)/gensrc/jdk.net/jdk/internal/net/rdma/RdmaSocketOptionRegistry.java
+
+ $(GENSRC_RSOR_FILE): \
+ $(TOPDIR)/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketOptionRegistry.java.template
+ $(generate-preproc-src)
+
+ GENSRC_JAVA_BASE += $(GENSRC_RSOR_FILE)
+
+endif
+
################################################################################
ifneq ($(OPENJDK_TARGET_OS), windows)
--- a/make/lib/Lib-jdk.net.gmk Fri Jan 25 11:15:00 2019 +0100
+++ b/make/lib/Lib-jdk.net.gmk Sat Jan 26 14:02:35 2019 +0000
@@ -32,12 +32,17 @@
$(eval $(call SetupJdkLibrary, BUILD_LIBEXTNET, \
NAME := extnet, \
OPTIMIZATION := LOW, \
- CFLAGS := $(CFLAGS_JDKLIB), \
+ CFLAGS := $(CFLAGS_JDKLIB) \
+ -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
+ -I$(TOPDIR)/src/java.base/share/native/libnet \
+ -I$(TOPDIR)/src/java.base/unix/native/libnet \
+ -I$(TOPDIR)/src/java.base/share/native/libnio/ch \
+ -I$(TOPDIR)/src/java.base/unix/native/libnio/ch, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := -ljava, \
LIBS_solaris := -lsocket, \
- LIBS_linux := -ljvm, \
+ LIBS_linux := -ljvm -lnet -lnio -lpthread -ldl, \
))
$(BUILD_LIBEXTNET): $(call FindLib, java.base, java)
--- a/make/test/JtregNativeJdk.gmk Fri Jan 25 11:15:00 2019 +0100
+++ b/make/test/JtregNativeJdk.gmk Sat Jan 26 14:02:35 2019 +0000
@@ -66,6 +66,7 @@
BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava
ifeq ($(OPENJDK_TARGET_OS), linux)
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava
+ BUILD_JDK_JTREG_LIBRARIES_LIBS_libRsocketTest := -ljava -ldl
else ifeq ($(OPENJDK_TARGET_OS), solaris)
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava -lsocket -lnsl
endif
--- a/src/java.base/share/classes/module-info.java Fri Jan 25 11:15:00 2019 +0100
+++ b/src/java.base/share/classes/module-info.java Sat Jan 26 14:02:35 2019 +0000
@@ -230,7 +230,8 @@
jdk.jfr;
exports sun.net to
java.net.http,
- jdk.naming.dns;
+ jdk.naming.dns,
+ jdk.net;
exports sun.net.ext to
jdk.net;
exports sun.net.dns to
@@ -265,7 +266,8 @@
java.sql.rowset;
exports sun.security.action to
java.desktop,
- java.security.jgss;
+ java.security.jgss,
+ jdk.net;
exports sun.security.internal.interfaces to
jdk.crypto.cryptoki;
exports sun.security.internal.spec to
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/net/ext/RdmaSocketOptions.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 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
+ * 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.net.ext;
+
+import java.io.FileDescriptor;
+import java.net.SocketException;
+import java.net.SocketOption;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Defines the infrastructure to support RDMA socket options.
+ *
+ * RDMA socket options are accessed through the jdk.net API, which is in
+ * the jdk.net module.
+ */
+public abstract class RdmaSocketOptions {
+
+ private final Set<SocketOption<?>> options;
+
+ /** Tells whether or not the option is supported. */
+ public final boolean isOptionSupported(SocketOption<?> option) {
+ return options().contains(option);
+ }
+
+ /** Return the, possibly empty, set of RDMA socket options available. */
+ public final Set<SocketOption<?>> options() { return options; }
+
+ /** Sets the value of a socket option, for the given socket. */
+ public abstract void setOption(FileDescriptor fd, SocketOption<?> option,
+ Object value) throws SocketException;
+
+ /** Returns the value of a socket option, for the given socket. */
+ public abstract Object getOption(FileDescriptor fd, SocketOption<?> option)
+ throws SocketException;
+
+ protected RdmaSocketOptions(Set<SocketOption<?>> options) {
+ this.options = options;
+ }
+
+ private static volatile RdmaSocketOptions instance;
+
+ public static final RdmaSocketOptions getInstance() { return instance; }
+
+ /** Registers support for RDMA socket options. Invoked by the jdk.net module. */
+ public static final void register(RdmaSocketOptions rdmaOptions) {
+ if (instance != null)
+ throw new InternalError("Attempting to reregister RDMA options");
+
+ instance = rdmaOptions;
+ }
+
+ static {
+ try {
+ // If the class is present, it will be initialized which
+ // triggers registration of the RDMA socket options.
+ Class<?> c = Class.forName("jdk.net.RdmaSocketOptions");
+ } catch (ClassNotFoundException e) {
+ // the jdk.net module is not present => no RDMA socket options
+ instance = new NoRdmaSocketOptions();
+ }
+ }
+
+ static final class NoRdmaSocketOptions extends RdmaSocketOptions {
+
+ NoRdmaSocketOptions() {
+ super(Collections.<SocketOption<?>>emptySet());
+ }
+
+ @Override
+ public void setOption(FileDescriptor fd, SocketOption<?> option,
+ Object value) throws SocketException
+ {
+ throw new UnsupportedOperationException(
+ "no RDMA options: " + option.name());
+ }
+
+ @Override
+ public Object getOption(FileDescriptor fd, SocketOption<?> option)
+ throws SocketException
+ {
+ throw new UnsupportedOperationException(
+ "no RDMA options: " + option.name());
+ }
+ }
+}
--- a/src/java.base/share/classes/sun/nio/ch/IOUtil.java Fri Jan 25 11:15:00 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/IOUtil.java Sat Jan 26 14:02:35 2019 +0000
@@ -43,7 +43,7 @@
private IOUtil() { } // No instantiation
- static int write(FileDescriptor fd, ByteBuffer src, long position,
+ public static int write(FileDescriptor fd, ByteBuffer src, long position,
NativeDispatcher nd)
throws IOException
{
@@ -123,8 +123,8 @@
return write(fd, bufs, 0, bufs.length, false, -1, nd);
}
- static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
- NativeDispatcher nd)
+ public static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset,
+ int length, NativeDispatcher nd)
throws IOException
{
return write(fd, bufs, offset, length, false, -1, nd);
@@ -216,7 +216,7 @@
}
}
- static int read(FileDescriptor fd, ByteBuffer dst, long position,
+ public static int read(FileDescriptor fd, ByteBuffer dst, long position,
NativeDispatcher nd)
throws IOException
{
@@ -286,8 +286,8 @@
return read(fd, bufs, 0, bufs.length, false, -1, nd);
}
- static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
- NativeDispatcher nd)
+ public static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset,
+ int length, NativeDispatcher nd)
throws IOException
{
return read(fd, bufs, offset, length, false, -1, nd);
--- a/src/java.base/share/classes/sun/nio/ch/Net.java Fri Jan 25 11:15:00 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/Net.java Sat Jan 26 14:02:35 2019 +0000
@@ -79,7 +79,7 @@
/**
* Tells whether dual-IPv4/IPv6 sockets should be used.
*/
- static boolean isIPv6Available() {
+ public static boolean isIPv6Available() {
if (!checkedIPv6) {
isIPv6Available = isIPv6Available0();
checkedIPv6 = true;
@@ -150,7 +150,7 @@
return (InetSocketAddress)sa;
}
- static void translateToSocketException(Exception x)
+ public static void translateToSocketException(Exception x)
throws SocketException
{
if (x instanceof SocketException)
@@ -180,7 +180,7 @@
throw new Error("Untranslated exception", nx);
}
- static void translateException(Exception x,
+ public static void translateException(Exception x,
boolean unknownHostForUnresolved)
throws IOException
{
@@ -196,7 +196,7 @@
translateToSocketException(x);
}
- static void translateException(Exception x)
+ public static void translateException(Exception x)
throws IOException
{
translateException(x, false);
@@ -205,7 +205,7 @@
/**
* Returns the local address after performing a SecurityManager#checkConnect.
*/
- static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) {
+ public static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) {
SecurityManager sm = System.getSecurityManager();
if (addr == null || sm == null)
return addr;
@@ -220,7 +220,7 @@
return addr;
}
- static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
+ public static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
return System.getSecurityManager() == null ? addr.toString() :
getLoopbackAddress(addr.getPort()).toString();
}
--- a/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java Fri Jan 25 11:15:00 2019 +0100
+++ b/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java Sat Jan 26 14:02:35 2019 +0000
@@ -42,7 +42,7 @@
* Selector implementation based on poll
*/
-class PollSelectorImpl extends SelectorImpl {
+public class PollSelectorImpl extends SelectorImpl {
// initial capacity of poll array
private static final int INITIAL_CAPACITY = 16;
@@ -67,7 +67,7 @@
private final Object interruptLock = new Object();
private boolean interruptTriggered;
- PollSelectorImpl(SelectorProvider sp) throws IOException {
+ protected PollSelectorImpl(SelectorProvider sp) throws IOException {
super(sp);
int size = pollArrayCapacity * SIZE_POLLFD;
@@ -133,6 +133,14 @@
}
/**
+ * Protected poll method allows different platform-specific
+ * native implementations
+ */
+ protected int poll(long pollAddress, int numfds, int timeout) {
+ return poll0(pollAddress, numfds, timeout);
+ }
+
+ /**
* Process changes to the interest ops.
*/
private void processUpdateQueue() {
@@ -377,7 +385,7 @@
return pollArray.getShort(offset);
}
- private static native int poll(long pollAddress, int numfds, int timeout);
+ private static native int poll0(long pollAddress, int numfds, int timeout);
static {
IOUtil.load();
--- a/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java Fri Jan 25 11:15:00 2019 +0100
+++ b/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java Sat Jan 26 14:02:35 2019 +0000
@@ -33,29 +33,33 @@
* for read and write operations.
*/
-class SocketDispatcher extends NativeDispatcher {
+public class SocketDispatcher extends NativeDispatcher {
- int read(FileDescriptor fd, long address, int len) throws IOException {
+ protected int read(FileDescriptor fd, long address, int len)
+ throws IOException {
return FileDispatcherImpl.read0(fd, address, len);
}
- long readv(FileDescriptor fd, long address, int len) throws IOException {
+ protected long readv(FileDescriptor fd, long address, int len)
+ throws IOException {
return FileDispatcherImpl.readv0(fd, address, len);
}
- int write(FileDescriptor fd, long address, int len) throws IOException {
+ protected int write(FileDescriptor fd, long address, int len)
+ throws IOException {
return FileDispatcherImpl.write0(fd, address, len);
}
- long writev(FileDescriptor fd, long address, int len) throws IOException {
+ protected long writev(FileDescriptor fd, long address, int len)
+ throws IOException {
return FileDispatcherImpl.writev0(fd, address, len);
}
- void close(FileDescriptor fd) throws IOException {
+ protected void close(FileDescriptor fd) throws IOException {
FileDispatcherImpl.close0(fd);
}
- void preClose(FileDescriptor fd) throws IOException {
+ public void preClose(FileDescriptor fd) throws IOException {
FileDispatcherImpl.preClose0(fd);
}
}
--- a/src/java.base/unix/native/libnio/ch/PollSelectorImpl.c Fri Jan 25 11:15:00 2019 +0100
+++ b/src/java.base/unix/native/libnio/ch/PollSelectorImpl.c Sat Jan 26 14:02:35 2019 +0000
@@ -33,9 +33,9 @@
#include "sun_nio_ch_PollSelectorImpl.h"
JNIEXPORT jint JNICALL
-Java_sun_nio_ch_PollSelectorImpl_poll(JNIEnv *env, jclass clazz,
- jlong address, jint numfds,
- jint timeout)
+Java_sun_nio_ch_PollSelectorImpl_poll0(JNIEnv *env, jclass clazz,
+ jlong address, jint numfds,
+ jint timeout)
{
struct pollfd *a;
int res;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/LinuxRdmaSocketDispatcherImpl.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import sun.nio.ch.IOUtil;
+
+public class LinuxRdmaSocketDispatcherImpl {
+
+ static {
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Void>() {
+ public Void run() {
+ System.loadLibrary("extnet");
+ return null;
+ }
+ });
+ IOUtil.load();
+ init();
+ }
+
+ LinuxRdmaSocketDispatcherImpl() { }
+
+
+ // -- Native methods --
+
+ static native int read0(FileDescriptor fd, long address, int len)
+ throws IOException;
+
+ static native long readv0(FileDescriptor fd, long address, int len)
+ throws IOException;
+
+ static native int write0(FileDescriptor fd, long address, int len)
+ throws IOException;
+
+ static native long writev0(FileDescriptor fd, long address, int len)
+ throws IOException;
+
+ static native void close0(FileDescriptor fd) throws IOException;
+
+ static native void init();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaInetAddressContainer.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.net.InetAddress;
+class RdmaInetAddressContainer {
+ InetAddress addr;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaNet.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ProtocolFamily;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.net.StandardProtocolFamily;
+import java.net.StandardSocketOptions;
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import sun.net.ext.RdmaSocketOptions;
+import sun.nio.ch.IOUtil;
+import sun.nio.ch.Net;
+
+public class RdmaNet {
+ private RdmaNet() { }
+
+ static final ProtocolFamily UNSPEC = new ProtocolFamily() {
+ public String name() {
+ return "UNSPEC";
+ }
+ };
+
+ static boolean isReusePortAvailable() {
+ return false;
+ }
+
+ private static volatile boolean checkedRdma;
+ private static volatile boolean isRdmaAvailable;
+
+ static boolean isRdmaAvailable() {
+ if (!checkedRdma) {
+ isRdmaAvailable = isRdmaAvailable0();
+ checkedRdma = true;
+ }
+ return isRdmaAvailable;
+ }
+
+ private static native boolean isRdmaAvailable0();
+
+ static InetSocketAddress checkAddress(SocketAddress sa, ProtocolFamily family) {
+ InetSocketAddress isa = Net.checkAddress(sa);
+ if (family == StandardProtocolFamily.INET) {
+ InetAddress addr = isa.getAddress();
+ if (!(addr instanceof Inet4Address))
+ throw new UnsupportedAddressTypeException();
+ }
+ if (family == StandardProtocolFamily.INET6) {
+ InetAddress addr = isa.getAddress();
+ if (!(addr instanceof Inet6Address))
+ throw new UnsupportedAddressTypeException();
+ }
+ return isa;
+ }
+
+ // -- Socket options
+
+ static final RdmaSocketOptions rdmaOptions =
+ RdmaSocketOptions.getInstance();
+
+ static void setSocketOption(FileDescriptor fd, ProtocolFamily family,
+ SocketOption<?> name, Object value) throws IOException
+ {
+ if (value == null)
+ throw new IllegalArgumentException("Invalid option value");
+
+ Class<?> type = name.type();
+
+ if (rdmaOptions.isOptionSupported(name)) {
+ rdmaOptions.setOption(fd, name, value);
+ return;
+ }
+
+ if (type != Integer.class && type != Boolean.class)
+ throw new AssertionError("Should not reach here");
+
+ if (name == StandardSocketOptions.SO_RCVBUF ||
+ name == StandardSocketOptions.SO_SNDBUF)
+ {
+ int i = ((Integer)value).intValue();
+ if (i < 0)
+ throw new IllegalArgumentException(
+ "Invalid send/receive buffer size");
+ }
+
+ RdmaOptionKey key = RdmaSocketOptionRegistry.findOption(name, family);
+ if (key == null)
+ throw new AssertionError("Option not found");
+
+ int arg;
+ int maxValue = 1024 * 1024 * 1024 - 1;
+ if (type == Integer.class) {
+ arg = ((Integer)value).intValue();
+ if (arg > maxValue)
+ arg = maxValue;
+ } else {
+ boolean b = ((Boolean)value).booleanValue();
+ arg = (b) ? 1 : 0;
+ }
+
+ boolean mayNeedConversion = (family == UNSPEC);
+ setIntOption0(fd, mayNeedConversion, key.level(),
+ key.name(), arg);
+ }
+
+ static Object getSocketOption(FileDescriptor fd, ProtocolFamily family,
+ SocketOption<?> name) throws IOException
+ {
+ Class<?> type = name.type();
+
+ if (rdmaOptions.isOptionSupported(name)) {
+ return rdmaOptions.getOption(fd, name);
+ }
+
+ if (type != Integer.class && type != Boolean.class)
+ throw new AssertionError("Should not reach here");
+
+ RdmaOptionKey key = RdmaSocketOptionRegistry.findOption(name, family);
+ if (key == null)
+ throw new AssertionError("Option not found");
+
+ boolean mayNeedConversion = (family == UNSPEC);
+ int value = getIntOption0(fd, mayNeedConversion, key.level(),
+ key.name());
+
+ if (type == Integer.class) {
+ return Integer.valueOf(value);
+ } else {
+ return (value == 0) ? Boolean.FALSE : Boolean.TRUE;
+ }
+ }
+
+ // -- Socket operations --
+ static FileDescriptor socket(ProtocolFamily family, boolean stream)
+ throws IOException {
+ boolean preferIPv6 = Net.isIPv6Available() &&
+ (family != StandardProtocolFamily.INET);
+ return IOUtil.newFD(socket0(preferIPv6, stream, false));
+ }
+
+ static FileDescriptor serverSocket(ProtocolFamily family, boolean stream)
+ throws IOException {
+ boolean preferIPv6 = Net.isIPv6Available() &&
+ (family != StandardProtocolFamily.INET);
+ return IOUtil.newFD(socket0(preferIPv6, stream, true));
+ }
+
+ private static native int socket0(boolean preferIPv6, boolean stream,
+ boolean reuse);
+ static void bind(ProtocolFamily family, FileDescriptor fd,
+ InetAddress addr, int port) throws IOException
+ {
+ boolean preferIPv6 = Net.isIPv6Available() &&
+ (family != StandardProtocolFamily.INET);
+ bind0(fd, preferIPv6, addr, port);
+ }
+
+ private static native void bind0(FileDescriptor fd, boolean preferIPv6,
+ InetAddress addr, int port) throws IOException;
+
+ static native void listen(FileDescriptor fd, int backlog)
+ throws IOException;
+
+ static int connect(FileDescriptor fd, InetAddress remote, int remotePort)
+ throws IOException
+ {
+ return connect(UNSPEC, fd, remote, remotePort);
+ }
+
+ static int connect(ProtocolFamily family, FileDescriptor fd,
+ InetAddress remote, int remotePort) throws IOException
+ {
+ boolean preferIPv6 = Net.isIPv6Available() &&
+ (family != StandardProtocolFamily.INET);
+ return connect0(preferIPv6, fd, remote, remotePort);
+ }
+
+ public static InetSocketAddress localAddress(FileDescriptor fd)
+ throws IOException
+ {
+ return new InetSocketAddress(localInetAddress(fd), localPort(fd));
+ }
+
+ private static native int connect0(boolean preferIPv6, FileDescriptor fd,
+ InetAddress remote, int remotePort) throws IOException;
+
+ static native void shutdown(FileDescriptor fd, int how) throws IOException;
+
+ private static native int localPort(FileDescriptor fd)
+ throws IOException;
+
+ private static native InetAddress localInetAddress(FileDescriptor fd)
+ throws IOException;
+
+ private static native int getIntOption0(FileDescriptor fd,
+ boolean mayNeedConversion, int level, int opt) throws IOException;
+
+ private static native void setIntOption0(FileDescriptor fd,
+ boolean mayNeedConversion, int level, int opt, int arg)
+ throws IOException;
+
+ static native int poll(FileDescriptor fd, int events, long timeout)
+ throws IOException;
+
+ public static native void configureBlocking(FileDescriptor fd,
+ boolean blocking);
+
+ private static native void initIDs();
+
+ static {
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<>() {
+ public Void run() {
+ System.loadLibrary("extnet");
+ return null;
+ }
+ });
+ IOUtil.load();
+ initIDs();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaOptionKey.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+/**
+ * Represents the level/name of a RDMA socket option
+ */
+
+class RdmaOptionKey {
+ private int level;
+ private int name;
+
+ RdmaOptionKey(int level, int name) {
+ this.level = level;
+ this.name = name;
+ }
+
+ int level() {
+ return level;
+ }
+
+ int name() {
+ return name;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaPollSelectorImpl.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.IOException;
+import java.nio.channels.spi.SelectorProvider;
+import sun.nio.ch.PollSelectorImpl;
+import sun.nio.ch.IOUtil;
+
+/**
+ * Selector implementation based on poll
+ */
+
+public class RdmaPollSelectorImpl extends PollSelectorImpl {
+
+ private static final UnsupportedOperationException unsupported;
+
+ private static final SelectorProvider checkSupported(SelectorProvider sp) {
+ if (unsupported != null)
+ throw new UnsupportedOperationException(unsupported.getMessage(),
+ unsupported);
+ else
+ return sp;
+ }
+
+ protected RdmaPollSelectorImpl(SelectorProvider sp) throws IOException {
+ super(checkSupported(sp));
+ }
+
+ protected int poll(long pollAddress, int numfds, int timeout) {
+ return poll0(pollAddress, numfds, timeout);
+ }
+
+ private static native int poll0(long pollAddress, int numfds, int timeout);
+
+ static {
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<>() {
+ public Void run() {
+ System.loadLibrary("extnet");
+ return null;
+ }
+ });
+ IOUtil.load();
+ UnsupportedOperationException uoe = null;
+ try {
+ init();
+ } catch (UnsupportedOperationException e) {
+ uoe = e;
+ }
+ unsupported = uoe;
+ }
+
+ private static native void init() throws UnsupportedOperationException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaPollSelectorProvider.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.IOException;
+import java.net.ProtocolFamily;
+import java.nio.channels.DatagramChannel;
+import java.nio.channels.Pipe;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+import sun.nio.ch.SelectorProviderImpl;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+public class RdmaPollSelectorProvider
+ extends SelectorProvider
+{
+ private static final Object lock = new Object();
+ private static SelectorProvider provider = null;
+
+ public static SelectorProvider provider() {
+ synchronized (lock) {
+ if (provider != null)
+ return provider;
+ return AccessController.doPrivileged(
+ new PrivilegedAction<>() {
+ public SelectorProvider run() {
+ provider = new RdmaPollSelectorProvider();
+ return provider;
+ }
+ });
+ }
+ }
+
+ public AbstractSelector openSelector() throws IOException {
+ return new RdmaPollSelectorImpl(this);
+ }
+
+ public SocketChannel openSocketChannel()
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public SocketChannel openSocketChannel(ProtocolFamily family)
+ throws IOException {
+ return new RdmaSocketChannelImpl(this, family);
+ }
+
+ public ServerSocketChannel openServerSocketChannel()
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public ServerSocketChannel openServerSocketChannel(ProtocolFamily family)
+ throws IOException {
+ return new RdmaServerSocketChannelImpl(this, family);
+ }
+
+ public DatagramChannel openDatagramChannel()
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public DatagramChannel openDatagramChannel(ProtocolFamily family)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Pipe openPipe() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaServerSocketAdaptor.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.net.StandardSocketOptions;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import sun.nio.ch.Net;
+
+class RdmaServerSocketAdaptor
+ extends ServerSocket
+{
+ private final RdmaServerSocketChannelImpl ssc;
+
+ private volatile int timeout;
+
+ public static ServerSocket create(RdmaServerSocketChannelImpl ssc) {
+ try {
+ return new RdmaServerSocketAdaptor(ssc);
+ } catch (IOException x) {
+ throw new Error(x);
+ }
+ }
+
+ private RdmaServerSocketAdaptor(RdmaServerSocketChannelImpl ssc)
+ throws IOException {
+ this.ssc = ssc;
+ }
+
+ public void bind(SocketAddress local) throws IOException {
+ bind(local, 50);
+ }
+
+ public void bind(SocketAddress local, int backlog) throws IOException {
+ if (local == null)
+ local = new InetSocketAddress(0);
+ try {
+ ssc.bind(local, backlog);
+ } catch (Exception x) {
+ Net.translateException(x);
+ }
+ }
+
+ public InetAddress getInetAddress() {
+ InetSocketAddress local = ssc.localAddress();
+ if (local == null) {
+ return null;
+ } else {
+ return Net.getRevealedLocalAddress(local).getAddress();
+ }
+ }
+
+ public int getLocalPort() {
+ InetSocketAddress local = ssc.localAddress();
+ if (local == null) {
+ return -1;
+ } else {
+ return local.getPort();
+ }
+ }
+
+ public Socket accept() throws IOException {
+ synchronized (ssc.blockingLock()) {
+ try {
+ if (!ssc.isBound())
+ throw new NotYetBoundException();
+
+ long to = this.timeout;
+ if (to == 0) {
+ // for compatibility reasons: accept connection if available
+ // when configured non-blocking
+ SocketChannel sc = ssc.accept();
+ if (sc == null && !ssc.isBlocking())
+ throw new IllegalBlockingModeException();
+ return sc.socket();
+ }
+
+ if (!ssc.isBlocking())
+ throw new IllegalBlockingModeException();
+ for (;;) {
+ long st = System.currentTimeMillis();
+ if (ssc.pollAccept(to))
+ return ssc.accept().socket();
+ to -= System.currentTimeMillis() - st;
+ if (to <= 0)
+ throw new SocketTimeoutException();
+ }
+
+ } catch (Exception x) {
+ Net.translateException(x);
+ assert false;
+ return null; // Never happens
+ }
+ }
+ }
+
+ public void close() throws IOException {
+ ssc.close();
+ }
+
+ public ServerSocketChannel getChannel() {
+ return ssc;
+ }
+
+ public boolean isBound() {
+ return ssc.isBound();
+ }
+
+ public boolean isClosed() {
+ return !ssc.isOpen();
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ this.timeout = timeout;
+ }
+
+ public int getSoTimeout() throws SocketException {
+ return timeout;
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ try {
+ ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ try {
+ return ssc.getOption(StandardSocketOptions.SO_REUSEADDR)
+ .booleanValue();
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return false; // Never happens
+ }
+ }
+
+ public String toString() {
+ if (!isBound())
+ return "RdmaServerSocket[unbound]";
+ return "RdmaServerSocket[addr=" + getInetAddress() +
+ ",localport=" + getLocalPort() + "]";
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ // size 0 valid for ServerSocketChannel, invalid for ServerSocket
+ if (size <= 0)
+ throw new IllegalArgumentException("size cannot be 0 or negative");
+ try {
+ ssc.setOption(StandardSocketOptions.SO_RCVBUF, size);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ try {
+ return ssc.getOption(StandardSocketOptions.SO_RCVBUF).intValue();
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return -1; // Never happens
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaServerSocketChannelImpl.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ProtocolFamily;
+import java.net.ServerSocket;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
+import java.net.StandardProtocolFamily;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+import sun.nio.ch.IOStatus;
+import sun.nio.ch.IOUtil;
+import sun.nio.ch.NativeThread;
+import sun.nio.ch.Net;
+import sun.nio.ch.SelChImpl;
+import sun.nio.ch.SelectionKeyImpl;
+import sun.net.ext.RdmaSocketOptions;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+
+public class RdmaServerSocketChannelImpl
+ extends ServerSocketChannel
+ implements SelChImpl
+{
+ //The protocol family of the socket
+ private final ProtocolFamily family;
+
+ private static RdmaSocketDispatcher nd;
+
+ private final FileDescriptor fd;
+ private final int fdVal;
+
+ private final ReentrantLock acceptLock = new ReentrantLock();
+
+ private final Object stateLock = new Object();
+
+ private static final int ST_INUSE = 0;
+ private static final int ST_CLOSING = 1;
+ private static final int ST_KILLPENDING = 2;
+ private static final int ST_KILLED = 3;
+ private int state;
+
+ private long thread;
+
+ private InetSocketAddress localAddress;
+
+ private boolean isReuseAddress;
+
+ private ServerSocket socket;
+
+ private static final UnsupportedOperationException unsupported;
+
+ private static final SelectorProvider checkSupported(SelectorProvider sp) {
+ if (unsupported != null)
+ throw new UnsupportedOperationException(unsupported.getMessage(), unsupported);
+ else
+ return sp;
+ }
+
+ RdmaServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family)
+ throws IOException {
+ super(checkSupported(sp));
+ Objects.requireNonNull(family, "'family' is null");
+ if (!(family == INET || family == INET6)) {
+ throw new UnsupportedOperationException(
+ "Protocol family not supported");
+ }
+ if (family == INET6) {
+ if (!Net.isIPv6Available()) {
+ throw new UnsupportedOperationException(
+ "IPv6 not available");
+ }
+ }
+ this.family = family;
+ this.fd = RdmaNet.serverSocket(family, true);
+ this.fdVal = IOUtil.fdVal(fd);
+ }
+
+ private void ensureOpen() throws ClosedChannelException {
+ if (!isOpen())
+ throw new ClosedChannelException();
+ }
+
+ @Override
+ public ServerSocket socket() {
+ synchronized (stateLock) {
+ if (socket == null)
+ socket = RdmaServerSocketAdaptor.create(this);
+ return socket;
+ }
+ }
+
+ @Override
+ public SocketAddress getLocalAddress() throws IOException {
+ synchronized (stateLock) {
+ ensureOpen();
+ return (localAddress == null)
+ ? null
+ : Net.getRevealedLocalAddress(localAddress);
+ }
+ }
+
+ @Override
+ public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
+ throws IOException
+ {
+ Objects.requireNonNull(name);
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name
+ + "' not supported");
+ synchronized (stateLock) {
+ ensureOpen();
+ if (isBound() && (name == StandardSocketOptions.SO_REUSEADDR))
+ throw new UnsupportedOperationException(
+ "RDMA server socket channel cannot set the socket option "
+ + name.toString() + " after bind.");
+
+ RdmaNet.setSocketOption(fd, RdmaNet.UNSPEC, name, value);
+ return this;
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getOption(SocketOption<T> name)
+ throws IOException
+ {
+ Objects.requireNonNull(name);
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name
+ + "' not supported");
+
+ synchronized (stateLock) {
+ ensureOpen();
+ return (T) RdmaNet.getSocketOption(fd, RdmaNet.UNSPEC, name);
+ }
+ }
+
+ private static class DefaultOptionsHolder {
+ static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+ private static Set<SocketOption<?>> defaultOptions() {
+ HashSet<SocketOption<?>> set = new HashSet<>(2);
+ set.add(StandardSocketOptions.SO_RCVBUF);
+ set.add(StandardSocketOptions.SO_REUSEADDR);
+ if (RdmaNet.isRdmaAvailable()) {
+ RdmaSocketOptions rdmaOptions =
+ RdmaSocketOptions.getInstance();
+ set.addAll(rdmaOptions.options());
+ }
+ return Collections.unmodifiableSet(set);
+ }
+ }
+
+ public final Set<SocketOption<?>> supportedOptions() {
+ return DefaultOptionsHolder.defaultOptions;
+ }
+
+ private final InetSocketAddress anyLocalAddress() throws IOException {
+ if (family == INET)
+ return new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0);
+ else if (family == INET6)
+ return new InetSocketAddress(InetAddress.getByName("::"), 0);
+ else
+ throw new UnsupportedAddressTypeException();
+ }
+
+ @Override
+ public ServerSocketChannel bind(SocketAddress local, int backlog)
+ throws IOException {
+ synchronized (stateLock) {
+ ensureOpen();
+ if (localAddress != null)
+ throw new AlreadyBoundException();
+ InetSocketAddress isa = (local == null)
+ ? anyLocalAddress()
+ : RdmaNet.checkAddress(local, family);
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkListen(isa.getPort());
+ RdmaNet.bind(family, fd, isa.getAddress(), isa.getPort());
+ RdmaNet.listen(fd, backlog < 1 ? 50 : backlog);
+ localAddress = RdmaNet.localAddress(fd);
+ }
+ return this;
+ }
+
+ private void begin(boolean blocking) throws ClosedChannelException {
+ if (blocking)
+ begin();
+ synchronized (stateLock) {
+ ensureOpen();
+ if (localAddress == null)
+ throw new NotYetBoundException();
+ if (blocking)
+ thread = NativeThread.current();
+ }
+ }
+
+ private void end(boolean blocking, boolean completed)
+ throws AsynchronousCloseException {
+ if (blocking) {
+ synchronized (stateLock) {
+ thread = 0;
+ if (state == ST_CLOSING) {
+ stateLock.notifyAll();
+ }
+ }
+ end(completed);
+ }
+ }
+
+ @Override
+ public SocketChannel accept() throws IOException {
+ acceptLock.lock();
+ try {
+ int n = 0;
+ FileDescriptor newfd = new FileDescriptor();
+ InetSocketAddress[] isaa = new InetSocketAddress[1];
+
+ boolean blocking = isBlocking();
+ try {
+ begin(blocking);
+ do {
+ if (blocking) {
+ do {
+ n = checkAccept(this.fd);
+ } while ((n == 0 || n == IOStatus.INTERRUPTED)
+ && isOpen());
+ }
+ n = accept(this.fd, newfd, isaa);
+ } while (n == IOStatus.INTERRUPTED && isOpen());
+ } finally {
+ end(blocking, n > 0);
+ assert IOStatus.check(n);
+ }
+
+ if (n < 1)
+ return null;
+
+ // newly accepted socket is initially in blocking mode
+ RdmaNet.configureBlocking(newfd, true);
+
+ InetSocketAddress isa = isaa[0];
+ SocketChannel sc = new RdmaSocketChannelImpl(provider(),
+ newfd, isa);
+
+ // check permitted to accept connections from the remote address
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ try {
+ sm.checkAccept(isa.getAddress().getHostAddress(),
+ isa.getPort());
+ } catch (SecurityException x) {
+ sc.close();
+ throw x;
+ }
+ }
+ return sc;
+
+ } finally {
+ acceptLock.unlock();
+ }
+ }
+
+ @Override
+ protected void implConfigureBlocking(boolean block) throws IOException {
+ acceptLock.lock();
+ try {
+ synchronized (stateLock) {
+ ensureOpen();
+ RdmaNet.configureBlocking(fd, block);
+ }
+ } finally {
+ acceptLock.unlock();
+ }
+ }
+
+ @Override
+ protected void implCloseSelectableChannel() throws IOException {
+ assert !isOpen();
+
+ boolean interrupted = false;
+ boolean blocking;
+
+ // set state to ST_CLOSING
+ synchronized (stateLock) {
+ assert state < ST_CLOSING;
+ state = ST_CLOSING;
+ blocking = isBlocking();
+ }
+
+ // wait for any outstanding accept to complete
+ if (blocking) {
+ synchronized (stateLock) {
+ assert state == ST_CLOSING;
+ long th = thread;
+ if (th != 0) {
+ nd.preClose(fd);
+ NativeThread.signal(th);
+
+ // wait for accept operation to end
+ while (thread != 0) {
+ try {
+ stateLock.wait();
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ }
+ }
+ } else {
+ // non-blocking mode: wait for accept to complete
+ acceptLock.lock();
+ acceptLock.unlock();
+ }
+
+ // set state to ST_KILLPENDING
+ synchronized (stateLock) {
+ assert state == ST_CLOSING;
+ state = ST_KILLPENDING;
+ }
+
+ // close socket if not registered with Selector
+ if (!isRegistered())
+ kill();
+
+ // restore interrupt status
+ if (interrupted)
+ Thread.currentThread().interrupt();
+ }
+
+ @Override
+ public void kill() throws IOException {
+ synchronized (stateLock) {
+ if (state == ST_KILLPENDING) {
+ state = ST_KILLED;
+ nd.close(fd);
+ }
+ }
+ }
+
+ boolean isBound() {
+ synchronized (stateLock) {
+ return localAddress != null;
+ }
+ }
+
+ InetSocketAddress localAddress() {
+ synchronized (stateLock) {
+ return localAddress;
+ }
+ }
+
+ /**
+ * Poll this channel's socket for a new connection up to the given timeout.
+ * @return {@code true} if there is a connection to accept
+ */
+ boolean pollAccept(long timeout) throws IOException {
+ assert Thread.holdsLock(blockingLock()) && isBlocking();
+ acceptLock.lock();
+ try {
+ boolean polled = false;
+ try {
+ begin(true);
+ int events = RdmaNet.poll(fd, Net.POLLIN, timeout);
+ polled = (events != 0);
+ } finally {
+ end(true, polled);
+ }
+ return polled;
+ } finally {
+ acceptLock.unlock();
+ }
+ }
+
+ public boolean translateReadyOps(int ops, int initialOps,
+ SelectionKeyImpl ski) {
+ int intOps = ski.nioInterestOps();
+ int oldOps = ski.nioReadyOps();
+ int newOps = initialOps;
+
+ if ((ops & Net.POLLNVAL) != 0) {
+ return false;
+ }
+
+ if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
+ newOps = intOps;
+ ski.nioReadyOps(newOps);
+ return (newOps & ~oldOps) != 0;
+ }
+
+ if (((ops & Net.POLLIN) != 0) &&
+ ((intOps & SelectionKey.OP_ACCEPT) != 0))
+ newOps |= SelectionKey.OP_ACCEPT;
+
+ ski.nioReadyOps(newOps);
+ return (newOps & ~oldOps) != 0;
+ }
+
+ public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
+ return translateReadyOps(ops, ski.nioReadyOps(), ski);
+ }
+
+ public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
+ return translateReadyOps(ops, 0, ski);
+ }
+
+ public int translateInterestOps(int ops) {
+ int newOps = 0;
+ if ((ops & SelectionKey.OP_ACCEPT) != 0)
+ newOps |= Net.POLLIN;
+ return newOps;
+ }
+
+ public FileDescriptor getFD() {
+ return fd;
+ }
+
+ public int getFDVal() {
+ return fdVal;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getName());
+ sb.append('[');
+ if (!isOpen()) {
+ sb.append("closed");
+ } else {
+ synchronized (stateLock) {
+ InetSocketAddress addr = localAddress;
+ if (addr == null) {
+ sb.append("unbound");
+ } else {
+ sb.append(Net.getRevealedLocalAddressAsString(addr));
+ }
+ }
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ private int accept(FileDescriptor ssfd, FileDescriptor newfd,
+ InetSocketAddress[] isaa) throws IOException {
+ return accept0(ssfd, newfd, isaa);
+ }
+
+ // -- Native methods --
+ private static native int checkAccept(FileDescriptor fd)
+ throws IOException;
+
+ private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
+ InetSocketAddress[] isaa) throws IOException;
+
+ private static native void initIDs()throws UnsupportedOperationException;
+
+ static {
+ IOUtil.load();
+ System.loadLibrary("extnet");
+ UnsupportedOperationException uoe = null;
+ try {
+ initIDs();
+ } catch (UnsupportedOperationException e) {
+ uoe = e;
+ }
+ unsupported = uoe;
+ nd = new RdmaSocketDispatcher();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketAdaptor.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketOption;
+import java.net.SocketTimeoutException;
+import java.net.StandardSocketOptions;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.SocketChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import sun.nio.ch.ChannelInputStream;
+import sun.nio.ch.Net;
+
+import static java.util.concurrent.TimeUnit.*;
+
+class RdmaSocketAdaptor
+ extends Socket
+{
+ // The channel being adapted
+ private final RdmaSocketChannelImpl sc;
+
+ // Timeout "option" value for reads
+ private volatile int timeout;
+
+ private RdmaSocketAdaptor(RdmaSocketChannelImpl sc) throws SocketException {
+ super((RdmaSocketImpl) null);
+ this.sc = sc;
+ }
+
+ public static Socket create(RdmaSocketChannelImpl sc) {
+ try {
+ return new RdmaSocketAdaptor(sc);
+ } catch (SocketException e) {
+ throw new InternalError("Should not reach here");
+ }
+ }
+
+ public SocketChannel getChannel() {
+ return sc;
+ }
+
+ // Override this method just to protect against changes in the superclass
+ //
+ public void connect(SocketAddress remote) throws IOException {
+ connect(remote, 0);
+ }
+
+ public void connect(SocketAddress remote, int timeout) throws IOException {
+ if (remote == null)
+ throw new IllegalArgumentException(
+ "connect: The address can't be null");
+ if (timeout < 0)
+ throw new IllegalArgumentException(
+ "connect: timeout can't be negative");
+
+ synchronized (sc.blockingLock()) {
+ if (!sc.isBlocking())
+ throw new IllegalBlockingModeException();
+
+ try {
+ if (timeout == 0) {
+ sc.connect(remote);
+ return;
+ }
+
+ sc.configureBlocking(false);
+ try {
+ if (sc.connect(remote))
+ return;
+ } finally {
+ try {
+ sc.configureBlocking(true);
+ } catch (ClosedChannelException e) { }
+ }
+
+ long timeoutNanos = NANOSECONDS.convert(timeout, MILLISECONDS);
+ long to = timeout;
+ for (;;) {
+ long startTime = System.nanoTime();
+ if (sc.pollConnected(to)) {
+ boolean connected = sc.finishConnect();
+ assert connected;
+ break;
+ }
+ timeoutNanos -= System.nanoTime() - startTime;
+ if (timeoutNanos <= 0) {
+ try {
+ sc.close();
+ } catch (IOException x) { }
+ throw new SocketTimeoutException();
+ }
+ to = MILLISECONDS.convert(timeoutNanos, NANOSECONDS);
+ }
+
+ } catch (Exception x) {
+ Net.translateException(x, true);
+ }
+ }
+
+ }
+
+ public void bind(SocketAddress local) throws IOException {
+ try {
+ sc.bind(local);
+ } catch (Exception x) {
+ Net.translateException(x);
+ }
+ }
+
+ public InetAddress getInetAddress() {
+ InetSocketAddress remote = sc.remoteAddress();
+ if (remote == null) {
+ return null;
+ } else {
+ return remote.getAddress();
+ }
+ }
+
+ public InetAddress getLocalAddress() {
+ if (sc.isOpen()) {
+ InetSocketAddress local = sc.localAddress();
+ if (local != null) {
+ return Net.getRevealedLocalAddress(local).getAddress();
+ }
+ }
+ return new InetSocketAddress(0).getAddress();
+ }
+
+ public int getPort() {
+ InetSocketAddress remote = sc.remoteAddress();
+ if (remote == null) {
+ return 0;
+ } else {
+ return remote.getPort();
+ }
+ }
+
+ public int getLocalPort() {
+ InetSocketAddress local = sc.localAddress();
+ if (local == null) {
+ return -1;
+ } else {
+ return local.getPort();
+ }
+ }
+
+ private class SocketInputStream
+ extends ChannelInputStream
+ {
+ private SocketInputStream() {
+ super(sc);
+ }
+
+ protected int read(ByteBuffer bb)
+ throws IOException {
+ synchronized (sc.blockingLock()) {
+ if (!sc.isBlocking())
+ throw new IllegalBlockingModeException();
+
+ // no timeout
+ long to = RdmaSocketAdaptor.this.timeout;
+ if (to == 0)
+ return sc.read(bb);
+
+ // timed read
+ long timeoutNanos = NANOSECONDS.convert(to, MILLISECONDS);
+ for (;;) {
+ long startTime = System.nanoTime();
+ if (sc.pollRead(to)) {
+ return sc.read(bb);
+ }
+ timeoutNanos -= System.nanoTime() - startTime;
+ if (timeoutNanos <= 0)
+ throw new SocketTimeoutException();
+ to = MILLISECONDS.convert(timeoutNanos, NANOSECONDS);
+ }
+ }
+ }
+ }
+
+ private InputStream socketInputStream = null;
+
+ public InputStream getInputStream() throws IOException {
+ if (!sc.isOpen())
+ throw new SocketException("Socket is closed");
+ if (!sc.isConnected())
+ throw new SocketException("Socket is not connected");
+ if (!sc.isInputOpen())
+ throw new SocketException("Socket input is shutdown");
+ if (socketInputStream == null) {
+ try {
+ socketInputStream = AccessController.doPrivileged(
+ new PrivilegedExceptionAction<InputStream>() {
+ public InputStream run() throws IOException {
+ return new SocketInputStream();
+ }
+ });
+ } catch (java.security.PrivilegedActionException e) {
+ throw (IOException)e.getException();
+ }
+ }
+ return socketInputStream;
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ if (!sc.isOpen())
+ throw new SocketException("Socket is closed");
+ if (!sc.isConnected())
+ throw new SocketException("Socket is not connected");
+ if (!sc.isOutputOpen())
+ throw new SocketException("Socket output is shutdown");
+ OutputStream os = null;
+ try {
+ os = AccessController.doPrivileged(
+ new PrivilegedExceptionAction<OutputStream>() {
+ public OutputStream run() throws IOException {
+ return Channels.newOutputStream(sc);
+ }
+ });
+ } catch (java.security.PrivilegedActionException e) {
+ throw (IOException)e.getException();
+ }
+ return os;
+ }
+
+ private void setBooleanOption(SocketOption<Boolean> name, boolean value)
+ throws SocketException {
+ try {
+ sc.setOption(name, value);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ private void setIntOption(SocketOption<Integer> name, int value)
+ throws SocketException {
+ try {
+ sc.setOption(name, value);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ private boolean getBooleanOption(SocketOption<Boolean> name)
+ throws SocketException {
+ try {
+ return sc.getOption(name).booleanValue();
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return false; // keep compiler happy
+ }
+ }
+
+ private int getIntOption(SocketOption<Integer> name)
+ throws SocketException {
+ try {
+ return sc.getOption(name).intValue();
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return -1; // keep compiler happy
+ }
+ }
+
+ public void setTcpNoDelay(boolean on) throws SocketException {
+ setBooleanOption(StandardSocketOptions.TCP_NODELAY, on);
+ }
+
+ public boolean getTcpNoDelay() throws SocketException {
+ return getBooleanOption(StandardSocketOptions.TCP_NODELAY);
+ }
+
+ public void sendUrgentData(int data) throws IOException {
+ int n = sc.sendOutOfBandData((byte) data);
+ if (n == 0)
+ throw new IOException("Socket buffer full");
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ if (timeout < 0)
+ throw new IllegalArgumentException("timeout can't be negative");
+ this.timeout = timeout;
+ }
+
+ public int getSoTimeout() throws SocketException {
+ return timeout;
+ }
+
+ public void setSendBufferSize(int size) throws SocketException {
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid send size");
+ setIntOption(StandardSocketOptions.SO_SNDBUF, size);
+ }
+
+ public int getSendBufferSize() throws SocketException {
+ return getIntOption(StandardSocketOptions.SO_SNDBUF);
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid receive size");
+ setIntOption(StandardSocketOptions.SO_RCVBUF, size);
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ return getIntOption(StandardSocketOptions.SO_RCVBUF);
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
+ }
+
+ public void close() throws IOException {
+ sc.close();
+ }
+
+ public void shutdownInput() throws IOException {
+ try {
+ sc.shutdownInput();
+ } catch (Exception x) {
+ Net.translateException(x);
+ }
+ }
+
+ public void shutdownOutput() throws IOException {
+ try {
+ sc.shutdownOutput();
+ } catch (Exception x) {
+ Net.translateException(x);
+ }
+ }
+
+ public String toString() {
+ if (sc.isConnected())
+ return "RdmaSocket[addr=" + getInetAddress() +
+ ",port=" + getPort() +
+ ",localport=" + getLocalPort() + "]";
+ return "RdmaSocket[unconnected]";
+ }
+
+ public boolean isConnected() {
+ return sc.isConnected();
+ }
+
+ public boolean isBound() {
+ return sc.localAddress() != null;
+ }
+
+ public boolean isClosed() {
+ return !sc.isOpen();
+ }
+
+ public boolean isInputShutdown() {
+ return !sc.isInputOpen();
+ }
+
+ public boolean isOutputShutdown() {
+ return !sc.isOutputOpen();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketChannelImpl.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,988 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ProtocolFamily;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
+import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ConnectionPendingException;
+import java.nio.channels.NoConnectionPendingException;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+import sun.net.ext.RdmaSocketOptions;
+import sun.nio.ch.IOStatus;
+import sun.nio.ch.IOUtil;
+import sun.nio.ch.NativeThread;
+import sun.nio.ch.Net;
+import sun.nio.ch.SelChImpl;
+import sun.nio.ch.SelectionKeyImpl;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+
+public class RdmaSocketChannelImpl
+ extends SocketChannel
+ implements SelChImpl
+{
+ // The protocol family of the socket
+ private final ProtocolFamily family;
+
+ private static RdmaSocketDispatcher nd;
+ private final FileDescriptor fd;
+ private final int fdVal;
+
+ private final ReentrantLock readLock = new ReentrantLock();
+ private final ReentrantLock writeLock = new ReentrantLock();
+
+ private final Object stateLock = new Object();
+
+ private volatile boolean isInputClosed;
+ private volatile boolean isOutputClosed;
+
+ private boolean isReuseAddress;
+
+ private static final int ST_UNCONNECTED = 0;
+ private static final int ST_CONNECTIONPENDING = 1;
+ private static final int ST_CONNECTED = 2;
+ private static final int ST_CLOSING = 3;
+ private static final int ST_KILLPENDING = 4;
+ private static final int ST_KILLED = 5;
+ private volatile int state; // need stateLock to change
+
+ private long readerThread;
+ private long writerThread;
+
+ private InetSocketAddress localAddress;
+ private InetSocketAddress remoteAddress;
+
+ private Socket socket;
+
+ private static final UnsupportedOperationException unsupported;
+
+ private static final SelectorProvider checkSupported(SelectorProvider sp) {
+ if (unsupported != null)
+ throw new UnsupportedOperationException(unsupported.getMessage(),
+ unsupported);
+ else
+ return sp;
+ }
+
+ protected RdmaSocketChannelImpl(SelectorProvider sp, ProtocolFamily family)
+ throws IOException {
+ super(checkSupported(sp));
+
+ Objects.requireNonNull(family, "null family");
+ if (!(family == INET || family == INET6)) {
+ throw new UnsupportedOperationException("Protocol family not supported");
+ }
+ if (family == INET6) {
+ if (!Net.isIPv6Available()) {
+ throw new UnsupportedOperationException("IPv6 not available");
+ }
+ }
+
+ this.family = family;
+ this.fd = RdmaNet.socket(family, true);
+ IOUtil.configureBlocking(fd, false);
+ this.fdVal = IOUtil.fdVal(fd);
+ }
+
+ RdmaSocketChannelImpl(SelectorProvider sp,
+ FileDescriptor fd,
+ InetSocketAddress isa) throws IOException {
+ super(checkSupported(sp));
+ this.family = Net.isIPv6Available() ? INET6 : INET;
+ this.fd = fd;
+ this.fdVal = IOUtil.fdVal(fd);
+ IOUtil.configureBlocking(fd, false);
+ synchronized (stateLock) {
+ this.localAddress = RdmaNet.localAddress(fd);
+ this.remoteAddress = isa;
+ this.state = ST_CONNECTED;
+ }
+ }
+
+ private void ensureOpen() throws ClosedChannelException {
+ if (!isOpen())
+ throw new ClosedChannelException();
+ }
+
+ private void ensureOpenAndConnected() throws ClosedChannelException {
+ int state = this.state;
+ if (state < ST_CONNECTED) {
+ throw new NotYetConnectedException();
+ } else if (state > ST_CONNECTED) {
+ throw new ClosedChannelException();
+ }
+ }
+
+ @Override
+ public Socket socket() {
+ synchronized (stateLock) {
+ if (socket == null)
+ socket = RdmaSocketAdaptor.create(this);
+ return socket;
+ }
+ }
+
+ @Override
+ public SocketAddress getLocalAddress() throws IOException {
+ synchronized (stateLock) {
+ ensureOpen();
+ return Net.getRevealedLocalAddress(localAddress);
+ }
+ }
+
+ @Override
+ public SocketAddress getRemoteAddress() throws IOException {
+ synchronized (stateLock) {
+ ensureOpen();
+ return remoteAddress;
+ }
+ }
+
+ @Override
+ public <T> SocketChannel setOption(SocketOption<T> name, T value)
+ throws IOException {
+ Objects.requireNonNull(name);
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name
+ + "' not supported");
+
+ synchronized (stateLock) {
+ ensureOpen();
+ RdmaNet.setSocketOption(fd, RdmaNet.UNSPEC, name, value);
+ return this;
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getOption(SocketOption<T> name)
+ throws IOException {
+ Objects.requireNonNull(name);
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name
+ + "' not supported");
+
+ synchronized (stateLock) {
+ ensureOpen();
+ return (T) RdmaNet.getSocketOption(fd, RdmaNet.UNSPEC, name);
+ }
+ }
+
+ private static class DefaultOptionsHolder {
+ static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+ private static Set<SocketOption<?>> defaultOptions() {
+ HashSet<SocketOption<?>> set = new HashSet<>();
+ set.add(StandardSocketOptions.SO_SNDBUF);
+ set.add(StandardSocketOptions.SO_RCVBUF);
+ set.add(StandardSocketOptions.SO_REUSEADDR);
+ set.add(StandardSocketOptions.TCP_NODELAY);
+ RdmaSocketOptions rdmaOptions =
+ RdmaSocketOptions.getInstance();
+ set.addAll(rdmaOptions.options());
+ return Collections.unmodifiableSet(set);
+ }
+ }
+
+ public Set<SocketOption<?>> supportedOptions() {
+ return DefaultOptionsHolder.defaultOptions;
+ }
+
+ private void beginRead(boolean blocking) throws ClosedChannelException {
+ if (blocking) {
+ // set hook for Thread.interrupt
+ begin();
+
+ synchronized (stateLock) {
+ ensureOpenAndConnected();
+ // record thread so it can be signalled if needed
+ readerThread = NativeThread.current();
+ }
+ } else {
+ ensureOpenAndConnected();
+ }
+ }
+ private void endRead(boolean blocking, boolean completed)
+ throws AsynchronousCloseException
+ {
+ if (blocking) {
+ synchronized (stateLock) {
+ readerThread = 0;
+ // notify any thread waiting in implCloseSelectableChannel
+ if (state == ST_CLOSING) {
+ stateLock.notifyAll();
+ }
+ }
+ // remove hook for Thread.interrupt
+ end(completed);
+ }
+ }
+
+ @Override
+ public int read(ByteBuffer buf) throws IOException {
+ Objects.requireNonNull(buf);
+
+ readLock.lock();
+ try {
+ boolean blocking = isBlocking();
+ int n = 0;
+ try {
+ beginRead(blocking);
+
+ // check if input is shutdown
+ if (isInputClosed)
+ return IOStatus.EOF;
+
+ n = IOUtil.read(fd, buf, -1, nd);
+ if (n == IOStatus.UNAVAILABLE && blocking) {
+ do {
+ RdmaNet.poll(fd, Net.POLLIN, -1);
+ n = IOUtil.read(fd, buf, -1, nd);
+ } while (n == IOStatus.UNAVAILABLE && isOpen());
+ }
+ } finally {
+ endRead(blocking, n > 0);
+ if (n <= 0 && isInputClosed)
+ return IOStatus.EOF;
+ }
+ return IOStatus.normalize(n);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public long read(ByteBuffer[] dsts, int offset, int length)
+ throws IOException
+ {
+ Objects.checkFromIndexSize(offset, length, dsts.length);
+
+ readLock.lock();
+ try {
+ boolean blocking = isBlocking();
+ long n = 0;
+ try {
+ beginRead(blocking);
+
+ // check if input is shutdown
+ if (isInputClosed)
+ return IOStatus.EOF;
+
+ n = IOUtil.read(fd, dsts, offset, length, nd);
+ if (n == IOStatus.UNAVAILABLE && blocking) {
+ do {
+ RdmaNet.poll(fd, Net.POLLIN, -1);
+ n = IOUtil.read(fd, dsts, offset, length, nd);
+ } while (n == IOStatus.UNAVAILABLE && isOpen());
+ }
+ } finally {
+ endRead(blocking, n > 0);
+ if (n <= 0 && isInputClosed)
+ return IOStatus.EOF;
+ }
+ return IOStatus.normalize(n);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ private void beginWrite(boolean blocking) throws ClosedChannelException {
+ if (blocking) {
+ // set hook for Thread.interrupt
+ begin();
+
+ synchronized (stateLock) {
+ ensureOpenAndConnected();
+ if (isOutputClosed)
+ throw new ClosedChannelException();
+ // record thread so it can be signalled if needed
+ writerThread = NativeThread.current();
+ }
+ } else {
+ ensureOpenAndConnected();
+ }
+ }
+
+ private void endWrite(boolean blocking, boolean completed)
+ throws AsynchronousCloseException {
+ if (blocking) {
+ synchronized (stateLock) {
+ writerThread = 0;
+ // notify any thread waiting in implCloseSelectableChannel
+ if (state == ST_CLOSING) {
+ stateLock.notifyAll();
+ }
+ }
+ // remove hook for Thread.interrupt
+ end(completed);
+ }
+ }
+
+ @Override
+ public int write(ByteBuffer buf) throws IOException {
+ Objects.requireNonNull(buf);
+
+ writeLock.lock();
+ try {
+ boolean blocking = isBlocking();
+ int n = 0;
+ try {
+ beginWrite(blocking);
+ n = IOUtil.write(fd, buf, -1, nd);
+ if (n == IOStatus.UNAVAILABLE && blocking) {
+ do {
+ RdmaNet.poll(fd, Net.POLLOUT, -1);
+ n = IOUtil.write(fd, buf, -1, nd);
+ } while (n == IOStatus.UNAVAILABLE && isOpen());
+ }
+ } finally {
+ endWrite(blocking, n > 0);
+ if (n <= 0 && isOutputClosed)
+ throw new AsynchronousCloseException();
+ }
+ return IOStatus.normalize(n);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ public long write(ByteBuffer[] srcs, int offset, int length)
+ throws IOException {
+ Objects.checkFromIndexSize(offset, length, srcs.length);
+
+ writeLock.lock();
+ try {
+ boolean blocking = isBlocking();
+ long n = 0;
+ try {
+ beginWrite(blocking);
+ n = IOUtil.write(fd, srcs, offset, length, nd);
+ if (n == IOStatus.UNAVAILABLE && blocking) {
+ do {
+ RdmaNet.poll(fd, Net.POLLOUT, -1);
+ n = IOUtil.write(fd, srcs, offset, length, nd);
+ } while (n == IOStatus.UNAVAILABLE && isOpen());
+ }
+ } finally {
+ endWrite(blocking, n > 0);
+ if (n <= 0 && isOutputClosed)
+ throw new AsynchronousCloseException();
+ }
+ return IOStatus.normalize(n);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ int sendOutOfBandData(byte b) throws IOException {
+ writeLock.lock();
+ try {
+ boolean blocking = isBlocking();
+ int n = 0;
+ try {
+ beginWrite(blocking);
+ n = sendOutOfBandData(fd, b);
+ if (n == IOStatus.UNAVAILABLE && blocking) {
+ do {
+ RdmaNet.poll(fd, Net.POLLOUT, -1);
+ n = sendOutOfBandData(fd, b);
+ } while (n == IOStatus.INTERRUPTED && isOpen());
+ }
+ } finally {
+ endWrite(blocking, n > 0);
+ if (n <= 0 && isOutputClosed)
+ throw new AsynchronousCloseException();
+ }
+ return IOStatus.normalize(n);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ protected void implConfigureBlocking(boolean block) throws IOException {
+ readLock.lock();
+ try {
+ writeLock.lock();
+ try {
+ synchronized (stateLock) {
+ ensureOpen();
+ // do nothing
+ }
+ } finally {
+ writeLock.unlock();
+ }
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ InetSocketAddress localAddress() {
+ synchronized (stateLock) {
+ return localAddress;
+ }
+ }
+
+ InetSocketAddress remoteAddress() {
+ synchronized (stateLock) {
+ return remoteAddress;
+ }
+ }
+
+ private final InetSocketAddress anyLocalAddress() throws IOException {
+ if (family == INET)
+ return new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0);
+ else if (family == INET6)
+ return new InetSocketAddress(InetAddress.getByName("::"), 0);
+ else
+ throw new UnsupportedAddressTypeException();
+ }
+
+ @Override
+ public SocketChannel bind(SocketAddress local) throws IOException {
+ readLock.lock();
+ try {
+ writeLock.lock();
+ try {
+ synchronized (stateLock) {
+ ensureOpen();
+ if (state == ST_CONNECTIONPENDING)
+ throw new ConnectionPendingException();
+ if (localAddress != null)
+ throw new AlreadyBoundException();
+ InetSocketAddress isa = (local == null)
+ ? anyLocalAddress()
+ : RdmaNet.checkAddress(local, family);
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkListen(isa.getPort());
+ }
+ RdmaNet.bind(family, fd, isa.getAddress(), isa.getPort());
+ localAddress = RdmaNet.localAddress(fd);
+ }
+ } finally {
+ writeLock.unlock();
+ }
+ } finally {
+ readLock.unlock();
+ }
+ return this;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return (state == ST_CONNECTED);
+ }
+
+ @Override
+ public boolean isConnectionPending() {
+ return (state == ST_CONNECTIONPENDING);
+ }
+
+ private void beginConnect(boolean blocking, InetSocketAddress isa)
+ throws IOException {
+ if (blocking) {
+ // set hook for Thread.interrupt
+ begin();
+ }
+ synchronized (stateLock) {
+ ensureOpen();
+ int state = this.state;
+ if (state == ST_CONNECTED)
+ throw new AlreadyConnectedException();
+ if (state == ST_CONNECTIONPENDING)
+ throw new ConnectionPendingException();
+ assert state == ST_UNCONNECTED;
+ this.state = ST_CONNECTIONPENDING;
+
+ remoteAddress = isa;
+
+ if (blocking) {
+ // record thread so it can be signalled if needed
+ readerThread = NativeThread.current();
+ }
+ }
+ }
+
+ private void endConnect(boolean blocking, boolean completed)
+ throws IOException {
+ endRead(blocking, completed);
+
+ if (completed) {
+ synchronized (stateLock) {
+ if (state == ST_CONNECTIONPENDING) {
+ localAddress = RdmaNet.localAddress(fd);
+ state = ST_CONNECTED;
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean connect(SocketAddress sa) throws IOException {
+ InetSocketAddress isa = RdmaNet.checkAddress(sa, family);
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
+
+ InetAddress ia = isa.getAddress();
+ if (ia.isAnyLocalAddress())
+ ia = InetAddress.getLocalHost();
+
+ try {
+ readLock.lock();
+ try {
+ writeLock.lock();
+ try {
+ boolean blocking = isBlocking();
+ boolean connected = false;
+ try {
+ beginConnect(blocking, isa);
+ int n = RdmaNet.connect(family, fd, ia, isa.getPort());
+ if (n == IOStatus.UNAVAILABLE && blocking) {
+ do {
+ RdmaNet.poll(fd, Net.POLLOUT, -1);
+ n = checkConnect(fd, false);
+ } while (n == IOStatus.INTERRUPTED && isOpen());
+ }
+ connected = (n > 0) && isOpen();
+ } finally {
+ endConnect(blocking, connected);
+ }
+ return connected;
+ } finally {
+ writeLock.unlock();
+ }
+ } finally {
+ readLock.unlock();
+ }
+ } catch (IOException ioe) {
+ // connect failed, close the channel
+ close();
+ throw ioe;
+ }
+ }
+
+ private void beginFinishConnect(boolean blocking)
+ throws ClosedChannelException {
+ if (blocking) {
+ // set hook for Thread.interrupt
+ begin();
+ }
+ synchronized (stateLock) {
+ ensureOpen();
+ if (state != ST_CONNECTIONPENDING)
+ throw new NoConnectionPendingException();
+ if (blocking) {
+ // record thread so it can be signalled if needed
+ readerThread = NativeThread.current();
+ }
+ }
+ }
+
+ private void endFinishConnect(boolean blocking, boolean completed)
+ throws IOException
+ {
+ endRead(blocking, completed);
+
+ if (completed) {
+ synchronized (stateLock) {
+ if (state == ST_CONNECTIONPENDING) {
+ localAddress = RdmaNet.localAddress(fd);
+ state = ST_CONNECTED;
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean finishConnect() throws IOException {
+ try {
+ readLock.lock();
+ try {
+ writeLock.lock();
+ try {
+ // no-op if already connected
+ if (isConnected())
+ return true;
+
+ boolean blocking = isBlocking();
+ boolean connected = false;
+ try {
+ beginFinishConnect(blocking);
+ int n = checkConnect(fd, false);
+ if (n == IOStatus.UNAVAILABLE && blocking) {
+ do {
+ RdmaNet.poll(fd, Net.POLLOUT, -1);
+ n = checkConnect(fd, false);
+ } while (n == IOStatus.UNAVAILABLE && isOpen());
+ }
+ connected = (n > 0) && isOpen();
+ } finally {
+ endFinishConnect(blocking, connected);
+ }
+ assert (blocking && connected) ^ !blocking;
+ return connected;
+ } finally {
+ writeLock.unlock();
+ }
+ } finally {
+ readLock.unlock();
+ }
+ } catch (IOException ioe) {
+ // connect failed, close the channel
+ close();
+ throw ioe;
+ }
+ }
+
+ @Override
+ protected void implCloseSelectableChannel() throws IOException {
+ assert !isOpen();
+ boolean blocking;
+ boolean connected;
+ boolean interrupted = false;
+
+ // set state to ST_CLOSING
+ synchronized (stateLock) {
+ assert state < ST_CLOSING;
+ blocking = isBlocking();
+ connected = (state == ST_CONNECTED);
+ state = ST_CLOSING;
+ }
+
+ // wait for any outstanding I/O operations to complete
+ if (blocking) {
+ synchronized (stateLock) {
+ assert state == ST_CLOSING;
+ long reader = readerThread;
+ long writer = writerThread;
+ if (reader != 0 || writer != 0) {
+ nd.preClose(fd);
+ connected = false; // fd is no longer connected socket
+
+ if (reader != 0)
+ NativeThread.signal(reader);
+ if (writer != 0)
+ NativeThread.signal(writer);
+
+ // wait for blocking I/O operations to end
+ while (readerThread != 0 || writerThread != 0) {
+ try {
+ stateLock.wait();
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ }
+ }
+ } else {
+ // non-blocking mode: wait for read/write to complete
+ readLock.lock();
+ try {
+ writeLock.lock();
+ writeLock.unlock();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ // set state to ST_KILLPENDING
+ synchronized (stateLock) {
+ assert state == ST_CLOSING;
+ // if connected and the channel is registered with a Selector then
+ // shutdown the output if possible so that the peer reads EOF.
+ if (connected && isRegistered()) {
+ try {
+ RdmaNet.shutdown(fd, Net.SHUT_WR);
+ } catch (IOException ignore) { }
+ }
+ state = ST_KILLPENDING;
+ }
+
+ // close socket if not registered with Selector
+ if (!isRegistered())
+ kill();
+
+ // restore interrupt status
+ if (interrupted)
+ Thread.currentThread().interrupt();
+ }
+
+ @Override
+ public void kill() throws IOException {
+ synchronized (stateLock) {
+ if (state == ST_KILLPENDING) {
+ state = ST_KILLED;
+ nd.close(fd);
+ }
+ }
+ }
+
+ @Override
+ public SocketChannel shutdownInput() throws IOException {
+ synchronized (stateLock) {
+ ensureOpen();
+ if (!isConnected())
+ throw new NotYetConnectedException();
+ if (!isInputClosed) {
+ RdmaNet.shutdown(fd, Net.SHUT_RD);
+ long thread = readerThread;
+ if (thread != 0)
+ NativeThread.signal(thread);
+ isInputClosed = true;
+ }
+ return this;
+ }
+ }
+
+ @Override
+ public SocketChannel shutdownOutput() throws IOException {
+ synchronized (stateLock) {
+ ensureOpen();
+ if (!isConnected())
+ throw new NotYetConnectedException();
+ if (!isOutputClosed) {
+ RdmaNet.shutdown(fd, Net.SHUT_WR);
+ long thread = writerThread;
+ if (thread != 0)
+ NativeThread.signal(thread);
+ isOutputClosed = true;
+ }
+ return this;
+ }
+ }
+
+ boolean isInputOpen() {
+ return !isInputClosed;
+ }
+
+ boolean isOutputOpen() {
+ return !isOutputClosed;
+ }
+
+ /**
+ * Poll this channel's socket for reading up to the given timeout.
+ * @return {@code true} if the socket is polled
+ */
+ boolean pollRead(long timeout) throws IOException {
+ boolean blocking = isBlocking();
+ assert Thread.holdsLock(blockingLock()) && blocking;
+
+ readLock.lock();
+ try {
+ boolean polled = false;
+ try {
+ beginRead(blocking);
+ int events = RdmaNet.poll(fd, Net.POLLIN, timeout);
+ polled = (events != 0);
+ } finally {
+ endRead(blocking, polled);
+ }
+ return polled;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * Poll this channel's socket for a connection, up to the given timeout.
+ * @return {@code true} if the socket is polled
+ */
+ boolean pollConnected(long timeout) throws IOException {
+ boolean blocking = isBlocking();
+ assert Thread.holdsLock(blockingLock()) && blocking;
+
+ readLock.lock();
+ try {
+ writeLock.lock();
+ try {
+ boolean polled = false;
+ try {
+ beginFinishConnect(blocking);
+ int events = RdmaNet.poll(fd, Net.POLLCONN, timeout);
+ polled = (events != 0);
+ } finally {
+ // invoke endFinishConnect with completed = false so that
+ // the state is not changed to ST_CONNECTED. The socket
+ // adaptor will use finishConnect to finish.
+ endFinishConnect(blocking, /*completed*/false);
+ }
+ return polled;
+ } finally {
+ writeLock.unlock();
+ }
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ public boolean translateReadyOps(int ops, int initialOps,
+ SelectionKeyImpl ski) {
+ int intOps = ski.nioInterestOps();
+ int oldOps = ski.nioReadyOps();
+ int newOps = initialOps;
+
+ if ((ops & Net.POLLNVAL) != 0) {
+ return false;
+ }
+
+ if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
+ newOps = intOps;
+ ski.nioReadyOps(newOps);
+ return (newOps & ~oldOps) != 0;
+ }
+
+ boolean connected = isConnected();
+ if (((ops & Net.POLLIN) != 0) &&
+ ((intOps & SelectionKey.OP_READ) != 0) && connected)
+ newOps |= SelectionKey.OP_READ;
+
+ if (((ops & Net.POLLCONN) != 0) &&
+ ((intOps & SelectionKey.OP_CONNECT) != 0) && isConnectionPending())
+ newOps |= SelectionKey.OP_CONNECT;
+
+ if (((ops & Net.POLLOUT) != 0) &&
+ ((intOps & SelectionKey.OP_WRITE) != 0) && connected)
+ newOps |= SelectionKey.OP_WRITE;
+
+ ski.nioReadyOps(newOps);
+ return (newOps & ~oldOps) != 0;
+ }
+
+ public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
+ return translateReadyOps(ops, ski.nioReadyOps(), ski);
+ }
+
+ public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
+ return translateReadyOps(ops, 0, ski);
+ }
+
+ public int translateInterestOps(int ops) {
+ int newOps = 0;
+ if ((ops & SelectionKey.OP_READ) != 0)
+ newOps |= Net.POLLIN;
+ if ((ops & SelectionKey.OP_WRITE) != 0)
+ newOps |= Net.POLLOUT;
+ if ((ops & SelectionKey.OP_CONNECT) != 0)
+ newOps |= Net.POLLCONN;
+ return newOps;
+ }
+
+ public FileDescriptor getFD() {
+ return fd;
+ }
+
+ public int getFDVal() {
+ return fdVal;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getSuperclass().getName());
+ sb.append('[');
+ if (!isOpen())
+ sb.append("closed");
+ else {
+ synchronized (stateLock) {
+ switch (state) {
+ case ST_UNCONNECTED:
+ sb.append("unconnected");
+ break;
+ case ST_CONNECTIONPENDING:
+ sb.append("connection-pending");
+ break;
+ case ST_CONNECTED:
+ sb.append("connected");
+ if (isInputClosed)
+ sb.append(" ishut");
+ if (isOutputClosed)
+ sb.append(" oshut");
+ break;
+ }
+ InetSocketAddress addr = localAddress();
+ if (addr != null) {
+ sb.append(" local=");
+ sb.append(Net.getRevealedLocalAddressAsString(addr));
+ }
+ if (remoteAddress() != null) {
+ sb.append(" remote=");
+ sb.append(remoteAddress().toString());
+ }
+ }
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ // -- Native methods --
+
+ private static native void initIDs() throws UnsupportedOperationException;
+
+ private static native int checkConnect(FileDescriptor fd, boolean block)
+ throws IOException;
+
+ private static native int sendOutOfBandData(FileDescriptor fd, byte data)
+ throws IOException;
+
+ static {
+ IOUtil.load();
+ System.loadLibrary("extnet");
+ UnsupportedOperationException uoe = null;
+ try {
+ initIDs();
+ } catch (UnsupportedOperationException e) {
+ uoe = e;
+ }
+ unsupported = uoe;
+ nd = new RdmaSocketDispatcher();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketDispatcher.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.nio.ch.SocketDispatcher;
+
+/**
+ * Allows different platforms to call different native methods
+ * for read and write operations.
+ */
+
+public class RdmaSocketDispatcher extends SocketDispatcher
+{
+ protected int read(FileDescriptor fd, long address, int len)
+ throws IOException {
+ return LinuxRdmaSocketDispatcherImpl.read0(fd, address, len);
+ }
+
+ protected long readv(FileDescriptor fd, long address, int len)
+ throws IOException {
+ return LinuxRdmaSocketDispatcherImpl.readv0(fd, address, len);
+ }
+
+ protected int write(FileDescriptor fd, long address, int len)
+ throws IOException {
+ return LinuxRdmaSocketDispatcherImpl.write0(fd, address, len);
+ }
+
+ protected long writev(FileDescriptor fd, long address, int len)
+ throws IOException {
+ return LinuxRdmaSocketDispatcherImpl.writev0(fd, address, len);
+ }
+
+ protected void close(FileDescriptor fd) throws IOException {
+ LinuxRdmaSocketDispatcherImpl.close0(fd);
+ }
+
+ public void preClose(FileDescriptor fd) throws IOException {
+ /* With RDMA socket channels, no need to do preClose */
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketImpl.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ProtocolFamily;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketImpl;
+import java.net.SocketOption;
+import java.net.SocketOptions;
+import java.net.StandardSocketOptions;
+import java.net.UnknownHostException;
+import java.util.Objects;
+import java.util.Set;
+import sun.nio.ch.Net;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+
+public abstract class RdmaSocketImpl extends SocketImpl
+{
+ private ProtocolFamily family;
+
+ Socket socket = null;
+ ServerSocket serverSocket = null;
+
+ int timeout; // timeout in millisec
+
+ int trafficClass;
+
+ InputStream socketInputStream;
+ OutputStream socketOutputStream;
+
+ private boolean shut_rd = false;
+ private boolean shut_wr = false;
+
+ /* number of threads using the FileDescriptor */
+ protected int fdUseCount = 0;
+
+ /* lock when increment/decrementing fdUseCount */
+ protected final Object fdLock = new Object();
+
+ /* indicates a close is pending on the file descriptor */
+ protected boolean closePending = false;
+
+ /* indicates connection reset state */
+ private int CONNECTION_NOT_RESET = 0;
+ private int CONNECTION_RESET_PENDING = 1;
+ private int CONNECTION_RESET = 2;
+ private int resetState;
+ private final Object resetLock = new Object();
+
+ protected boolean stream;
+
+ private static UnsupportedOperationException unsupported;
+
+ static final sun.net.ext.RdmaSocketOptions rdmaOptions =
+ sun.net.ext.RdmaSocketOptions.getInstance();
+
+ static {
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<>() {
+ public Void run() {
+ System.loadLibrary("net");
+ System.loadLibrary("extnet");
+ return null;
+ }
+ });
+ UnsupportedOperationException uoe = null;
+ try {
+ initProto();
+ } catch (UnsupportedOperationException e) {
+ uoe = e;
+ }
+ unsupported = uoe;
+ }
+
+ private static final Void checkSupported() {
+ if (unsupported != null) {
+ Exception e = unsupported;
+ throw new UnsupportedOperationException(e.getMessage(), e);
+ } else {
+ return null;
+ }
+ }
+
+ public RdmaSocketImpl(ProtocolFamily family) {
+ this(checkSupported(), family);
+ }
+
+ private RdmaSocketImpl(Void unused, ProtocolFamily family) {
+ Objects.requireNonNull(family, "null family");
+ if (!(family == INET || family == INET6)) {
+ throw new UnsupportedOperationException("Protocol family not supported");
+ }
+ if (family == INET6) {
+ if (!Net.isIPv6Available()) {
+ throw new UnsupportedOperationException(
+ "IPv6 not available");
+ }
+ }
+ this.family = family;
+ }
+
+ private static volatile boolean checkedRdma;
+ private static volatile boolean isRdmaAvailable;
+
+ boolean isRdmaAvailable() {
+ if (!checkedRdma) {
+ isRdmaAvailable = isRdmaAvailable0();
+ checkedRdma = true;
+ }
+ return isRdmaAvailable;
+ }
+
+ void setSocket(Socket soc) {
+ this.socket = soc;
+ }
+
+ Socket getSocket() {
+ return socket;
+ }
+
+ void setServerSocket(ServerSocket soc) {
+ this.serverSocket = soc;
+ }
+
+ ServerSocket getServerSocket() {
+ return serverSocket;
+ }
+
+ @Override
+ protected abstract Set<SocketOption<?>> supportedOptions();
+
+ protected synchronized void create(boolean stream) throws IOException {
+ this.stream = stream;
+ if (stream) {
+ fd = new FileDescriptor();
+
+ boolean preferIPv6 = Net.isIPv6Available() && (family != INET);
+ rdmaSocketCreate(preferIPv6, true);
+ }
+ }
+
+ protected void connect(String host, int port)
+ throws UnknownHostException, IOException {
+ boolean connected = false;
+ try {
+ InetAddress address = InetAddress.getByName(host);
+ this.port = port;
+ this.address = address;
+
+ connectToAddress(address, port, timeout);
+ connected = true;
+ } finally {
+ if (!connected) {
+ try {
+ close();
+ } catch (IOException ioe) {
+ }
+ }
+ }
+ }
+
+ protected void connect(InetAddress address, int port) throws IOException {
+ if (family == INET && !(address instanceof Inet4Address))
+ throw new IllegalArgumentException("address type mismatch");
+ if (family == INET6 && !(address instanceof Inet6Address))
+ throw new IllegalArgumentException("address type mismatch");
+
+ this.port = port;
+ this.address = address;
+ try {
+ connectToAddress(address, port, timeout);
+ return;
+ } catch (IOException e) {
+ close();
+ throw e;
+ }
+ }
+
+ protected void connect(SocketAddress address, int timeout)
+ throws IOException {
+ boolean connected = false;
+ try {
+ if (address == null || !(address instanceof InetSocketAddress))
+ throw new IllegalArgumentException("unsupported address type");
+ InetSocketAddress addr = (InetSocketAddress) address;
+ InetAddress ia = addr.getAddress();
+ if (family == INET && !(ia instanceof Inet4Address))
+ throw new IllegalArgumentException("address type mismatch");
+ if (family == INET6 && !(ia instanceof Inet6Address))
+ throw new IllegalArgumentException("address type mismatch");
+ if (addr.isUnresolved())
+ throw new UnknownHostException(addr.getHostName());
+ this.port = addr.getPort();
+ this.address = addr.getAddress();
+
+ connectToAddress(this.address, port, timeout);
+ connected = true;
+ } finally {
+ if (!connected) {
+ try {
+ close();
+ } catch (IOException ioe) {
+ }
+ }
+ }
+ }
+
+ private void connectToAddress(InetAddress address, int port, int timeout)
+ throws IOException {
+ if (address.isAnyLocalAddress()) {
+ doConnect(InetAddress.getLocalHost(), port, timeout);
+ } else {
+ doConnect(address, port, timeout);
+ }
+ }
+
+ @Override
+ protected abstract <T> void setOption(SocketOption<T> name, T value)
+ throws IOException;
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected abstract <T> T getOption(SocketOption<T> name)
+ throws IOException;
+
+ public void setOption(int opt, Object val) throws SocketException {
+ if (isClosedOrPending()) {
+ throw new SocketException("Socket Closed");
+ }
+ boolean on = true;
+ switch (opt) {
+ case SO_TIMEOUT:
+ if (val == null || (!(val instanceof Integer)))
+ throw new SocketException("Bad parameter for SO_TIMEOUT");
+ int tmp = ((Integer) val).intValue();
+ if (tmp < 0)
+ throw new IllegalArgumentException("timeout < 0");
+ timeout = tmp;
+ break;
+ case SO_BINDADDR:
+ throw new SocketException("Cannot re-bind socket");
+ case TCP_NODELAY:
+ if (val == null || !(val instanceof Boolean))
+ throw new SocketException("bad parameter for TCP_NODELAY");
+ on = ((Boolean)val).booleanValue();
+ break;
+ case SO_SNDBUF:
+ case SO_RCVBUF:
+ int value = ((Integer)val).intValue();
+ int maxValue = 1024 * 1024 * 1024 - 1; //maximum value for the buffer
+ if (val == null || !(val instanceof Integer) ||
+ !(value > 0)) {
+ throw new SocketException("bad parameter for SO_SNDBUF " +
+ "or SO_RCVBUF");
+ }
+ if (value >= maxValue)
+ value = maxValue;
+ break;
+ case SO_REUSEADDR:
+ if (val == null || !(val instanceof Boolean))
+ throw new SocketException("bad parameter for SO_REUSEADDR");
+ on = ((Boolean)val).booleanValue();
+ if (serverSocket != null && serverSocket.isBound())
+ throw new UnsupportedOperationException(
+ "RDMA server socket cannot set " +
+ "SO_REUSEADDR after bind.");
+ if (socket != null && socket.isConnected())
+ throw new UnsupportedOperationException(
+ "RDMA socket cannot set " +
+ "SO_REUSEADDR after connect.");
+ break;
+ default:
+ throw new SocketException("unrecognized TCP option: " + opt);
+ }
+ socketSetOption(opt, on, val);
+ }
+
+ public Object getOption(int opt) throws SocketException {
+ if (isClosedOrPending()) {
+ throw new SocketException("Socket Closed");
+ }
+ if (opt == SO_TIMEOUT) {
+ return timeout;
+ }
+ int ret = 0;
+
+ switch (opt) {
+ case TCP_NODELAY:
+ ret = rdmaSocketGetOption(opt, null);
+ return Boolean.valueOf(ret != -1);
+ case SO_REUSEADDR:
+ ret = rdmaSocketGetOption(opt, null);
+ return Boolean.valueOf(ret != -1);
+ case SO_BINDADDR:
+ RdmaInetAddressContainer in = new RdmaInetAddressContainer();
+ ret = rdmaSocketGetOption(opt, in);
+ return in.addr;
+ case SO_SNDBUF:
+ case SO_RCVBUF:
+ ret = rdmaSocketGetOption(opt, null);
+ return ret;
+ default:
+ return null;
+ }
+ }
+
+ protected void socketSetOption(int opt, boolean b, Object val)
+ throws SocketException {
+ if (opt == SocketOptions.SO_REUSEPORT &&
+ !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+ throw new UnsupportedOperationException("unsupported option");
+ }
+ try {
+ rdmaSocketSetOption(opt, b, val);
+ } catch (SocketException se) {
+ if (socket == null || !socket.isConnected())
+ throw se;
+ }
+ }
+
+ synchronized void doConnect(InetAddress address, int port, int timeout)
+ throws IOException {
+ try {
+ acquireFD();
+ boolean preferIPv6 = Net.isIPv6Available() && (family != INET);
+ try {
+ rdmaSocketConnect(preferIPv6, address, port, timeout);
+ synchronized (fdLock) {
+ if (closePending) {
+ throw new SocketException ("Socket closed");
+ }
+ }
+ } finally {
+ releaseFD();
+ }
+ } catch (IOException e) {
+ close();
+ throw e;
+ }
+ }
+
+ private final InetAddress anyLocalAddress() throws IOException {
+ if (family == INET)
+ return InetAddress.getByName("0.0.0.0");
+ else if (family == INET6)
+ return InetAddress.getByName("::");
+ else
+ throw new IllegalArgumentException("Unsupported address type " + family);
+ }
+
+ protected synchronized void bind(InetAddress address, int lport)
+ throws IOException {
+ if (address == null)
+ throw new IllegalArgumentException("address is null");
+
+ if (address.isAnyLocalAddress())
+ address = anyLocalAddress();
+
+ if (family == INET && !(address instanceof Inet4Address))
+ throw new IllegalArgumentException("address type mismatch");
+ if (family == INET6 && !(address instanceof Inet6Address))
+ throw new IllegalArgumentException("address type mismatch");
+ boolean preferIPv6 = Net.isIPv6Available() && (family != INET);
+ rdmaSocketBind(preferIPv6, address, lport);
+ }
+
+ protected synchronized void listen(int count) throws IOException {
+ rdmaSocketListen(count);
+ }
+
+ protected void accept(SocketImpl s) throws IOException {
+ acquireFD();
+ try {
+ rdmaSocketAccept(s);
+ } finally {
+ releaseFD();
+ }
+ }
+
+ protected synchronized InputStream getInputStream() throws IOException {
+ synchronized (fdLock) {
+ if (isClosedOrPending())
+ throw new IOException("Socket Closed");
+ if (shut_rd)
+ throw new IOException("Socket input is shutdown");
+ if (socketInputStream == null)
+ socketInputStream = new RdmaSocketInputStream(this);
+ }
+ return socketInputStream;
+ }
+
+ protected synchronized OutputStream getOutputStream() throws IOException {
+ synchronized (fdLock) {
+ if (isClosedOrPending())
+ throw new IOException("Socket Closed");
+ if (shut_wr)
+ throw new IOException("Socket output is shutdown");
+ if (socketOutputStream == null)
+ socketOutputStream = new RdmaSocketOutputStream(this);
+ }
+ return socketOutputStream;
+ }
+
+ protected FileDescriptor getFileDescriptor() {
+ return fd;
+ }
+
+ protected void setFileDescriptor(FileDescriptor fd) {
+ this.fd = fd;
+ }
+
+ protected void setAddress(InetAddress address) {
+ this.address = address;
+ }
+
+ void setPort(int port) {
+ this.port = port;
+ }
+
+ void setLocalPort(int localport) {
+ this.localport = localport;
+ }
+
+ protected synchronized int available() throws IOException {
+ throw new UnsupportedOperationException(
+ "unsupported socket operation");
+ }
+
+ protected void close() throws IOException {
+ synchronized(fdLock) {
+ if (fd != null) {
+ if (fdUseCount == 0) {
+ if (closePending) {
+ return;
+ }
+ closePending = true;
+ rdmaSocketClose();
+ fd = null;
+ return;
+ } else {
+ if (!closePending) {
+ closePending = true;
+ fdUseCount--;
+ rdmaSocketClose();
+ }
+ }
+ }
+ }
+ }
+
+ void reset() throws IOException {
+ if (fd != null) {
+ rdmaSocketClose();
+ }
+ fd = null;
+ postReset();
+ }
+
+ void postReset() throws IOException {
+ address = null;
+ port = 0;
+ localport = 0;
+ }
+
+ protected void shutdownInput() throws IOException {
+ if (fd != null) {
+ rdmaSocketShutdown(SHUT_RD);
+ if (socketInputStream != null) {
+ ((RdmaSocketInputStream)socketInputStream).setEOF(true);
+ }
+ shut_rd = true;
+ }
+ }
+
+ protected void shutdownOutput() throws IOException {
+ if (fd != null) {
+ rdmaSocketShutdown(SHUT_WR);
+ shut_wr = true;
+ }
+ }
+
+ protected boolean supportsUrgentData () {
+ return true;
+ }
+
+ protected void sendUrgentData (int data) throws IOException {
+ if (fd == null) {
+ throw new IOException("Socket Closed");
+ }
+ rdmaSocketSendUrgentData(data);
+ }
+
+ FileDescriptor acquireFD() {
+ synchronized (fdLock) {
+ fdUseCount++;
+ return fd;
+ }
+ }
+
+ void releaseFD() {
+ synchronized (fdLock) {
+ fdUseCount--;
+ if (fdUseCount == -1) {
+ if (fd != null) {
+ try {
+ rdmaSocketClose();
+ } catch (IOException e) {
+ } finally {
+ fd = null;
+ }
+ }
+ }
+ }
+ }
+
+ public boolean isConnectionReset() {
+ synchronized (resetLock) {
+ return (resetState == CONNECTION_RESET);
+ }
+ }
+
+ public boolean isConnectionResetPending() {
+ synchronized (resetLock) {
+ return (resetState == CONNECTION_RESET_PENDING);
+ }
+ }
+
+ public void setConnectionReset() {
+ synchronized (resetLock) {
+ resetState = CONNECTION_RESET;
+ }
+ }
+
+ public void setConnectionResetPending() {
+ synchronized (resetLock) {
+ if (resetState == CONNECTION_NOT_RESET) {
+ resetState = CONNECTION_RESET_PENDING;
+ }
+ }
+
+ }
+
+ public boolean isClosedOrPending() {
+ synchronized (fdLock) {
+ if (closePending || (fd == null)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public int getTimeout() {
+ return timeout;
+ }
+
+ protected InetAddress getInetAddress() {
+ return address;
+ }
+
+ protected int getPort() {
+ return port;
+ }
+
+ protected int getLocalPort() {
+ return localport;
+ }
+
+ public static final int SHUT_RD = 0;
+ public static final int SHUT_WR = 1;
+
+ static native void initProto() throws UnsupportedOperationException;
+
+ private static native boolean isRdmaAvailable0();
+
+ native void rdmaSocketCreate(boolean preferIPv6, boolean isServer)
+ throws IOException;
+
+ native void rdmaSocketConnect(boolean preferIPv6, InetAddress address,
+ int port, int timeout) throws IOException;
+
+ native void rdmaSocketBind(boolean preferIPv6, InetAddress address,
+ int port) throws IOException;
+
+ native void rdmaSocketListen(int count) throws IOException;
+
+ native void rdmaSocketAccept(SocketImpl s) throws IOException;
+
+ native void rdmaSocketClose() throws IOException;
+
+ native void rdmaSocketShutdown(int howto) throws IOException;
+
+ native void rdmaSocketSetOption(int cmd, boolean on, Object value)
+ throws SocketException;
+
+ native int rdmaSocketGetOption(int opt, Object iaContainerObj)
+ throws SocketException;
+
+ native void rdmaSocketSendUrgentData(int data) throws IOException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketInputStream.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.net.Socket;
+import java.net.SocketException;
+
+import sun.net.ConnectionResetException;
+
+class RdmaSocketInputStream extends FileInputStream
+{
+ static {
+ init();
+ }
+
+ private boolean eof;
+ private RdmaSocketImpl impl = null;
+ private byte temp[];
+ private Socket socket = null;
+
+ RdmaSocketInputStream(RdmaSocketImpl impl) throws IOException {
+ super(impl.getFileDescriptor());
+ this.impl = impl;
+ socket = impl.getSocket();
+ }
+
+ public final FileChannel getChannel() {
+ return null;
+ }
+
+ private native int rdmaSocketRead0(FileDescriptor fd, byte b[],
+ int off, int len, int timeout) throws IOException;
+
+ private int rdmaSocketRead(FileDescriptor fd, byte b[],
+ int off, int len, int timeout) throws IOException {
+ return rdmaSocketRead0(fd, b, off, len, timeout);
+ }
+
+ public int read(byte b[]) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte b[], int off, int length) throws IOException {
+ return read(b, off, length, impl.getTimeout());
+ }
+
+ int read(byte b[], int off, int length, int timeout) throws IOException {
+ int n;
+
+ if (eof) {
+ return -1;
+ }
+
+ if (impl.isConnectionReset()) {
+ throw new SocketException("Connection reset");
+ }
+
+ if (length <= 0 || off < 0 || length > b.length - off) {
+ if (length == 0) {
+ return 0;
+ }
+ throw new ArrayIndexOutOfBoundsException("length == " + length
+ + " off == " + off + " buffer length == " + b.length);
+ }
+
+ boolean gotReset = false;
+
+ FileDescriptor fd = impl.acquireFD();
+ try {
+ n = rdmaSocketRead(fd, b, off, length, timeout);
+ if (n > 0) {
+ return n;
+ }
+ } catch (ConnectionResetException rstExc) {
+ gotReset = true;
+ } finally {
+ impl.releaseFD();
+ }
+
+ if (gotReset) {
+ impl.setConnectionResetPending();
+ impl.acquireFD();
+ try {
+ n = rdmaSocketRead(fd, b, off, length, timeout);
+ if (n > 0) {
+ return n;
+ }
+ } catch (ConnectionResetException rstExc) {
+ } finally {
+ impl.releaseFD();
+ }
+ }
+
+ if (impl.isClosedOrPending()) {
+ throw new SocketException("Socket closed");
+ }
+ if (impl.isConnectionResetPending()) {
+ impl.setConnectionReset();
+ }
+ if (impl.isConnectionReset()) {
+ throw new SocketException("Connection reset");
+ }
+ eof = true;
+ return -1;
+ }
+
+ /**
+ * Reads a single byte from the socket.
+ */
+ public int read() throws IOException {
+ if (eof) {
+ return -1;
+ }
+ temp = new byte[1];
+ int n = read(temp, 0, 1);
+ if (n <= 0) {
+ return -1;
+ }
+ return temp[0] & 0xff;
+ }
+
+ /**
+ * Skips n bytes of input.
+ * @param numbytes the number of bytes to skip
+ * @return the actual number of bytes skipped.
+ * @exception IOException If an I/O error has occurred.
+ */
+ public long skip(long numbytes) throws IOException {
+ if (numbytes <= 0) {
+ return 0;
+ }
+ long n = numbytes;
+ int buflen = (int) Math.min(1024, n);
+ byte data[] = new byte[buflen];
+ while (n > 0) {
+ int r = read(data, 0, (int) Math.min((long) buflen, n));
+ if (r < 0) {
+ break;
+ }
+ n -= r;
+ }
+ return numbytes - n;
+ }
+
+ public int available() throws IOException {
+ throw new UnsupportedOperationException(
+ "unsupported socket operation");
+ }
+
+ /**
+ * Closes the stream.
+ */
+ private boolean closing = false;
+ public void close() throws IOException {
+ if (closing)
+ return;
+ closing = true;
+ if (socket != null) {
+ if (!socket.isClosed())
+ socket.close();
+ } else
+ impl.close();
+ closing = false;
+ }
+
+ void setEOF(boolean eof) {
+ this.eof = eof;
+ }
+
+ /**
+ * Perform class load-time initializations.
+ */
+ private static native void init();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketOptionRegistry.java.template Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ *
+ */
+@@END_COPYRIGHT@@
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+/* To be able to name the Java constants the same as the C constants without
+ having the preprocessor rewrite those identifiers, add PREFIX_ to all
+ identifiers matching a C constant. The PREFIX_ is filtered out in the
+ makefile. */
+
+@@START_HERE@@
+
+package jdk.internal.net.rdma;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
+import java.net.ProtocolFamily;
+import java.util.Map;
+import java.util.HashMap;
+
+class RdmaSocketOptionRegistry {
+
+ private RdmaSocketOptionRegistry() { }
+
+ private static class RegistryKey {
+ private final SocketOption<?> name;
+ private final ProtocolFamily family;
+ RegistryKey(SocketOption<?> name, ProtocolFamily family) {
+ this.name = name;
+ this.family = family;
+ }
+ public int hashCode() {
+ return name.hashCode() + family.hashCode();
+ }
+ public boolean equals(Object ob) {
+ if (ob == null) return false;
+ if (!(ob instanceof RegistryKey)) return false;
+ RegistryKey other = (RegistryKey)ob;
+ if (this.name != other.name) return false;
+ if (this.family != other.family) return false;
+ return true;
+ }
+ }
+
+ private static class LazyInitialization {
+
+ static final Map<RegistryKey,RdmaOptionKey> options = options();
+
+ private static Map<RegistryKey,RdmaOptionKey> options() {
+ Map<RegistryKey,RdmaOptionKey> map =
+ new HashMap<RegistryKey,RdmaOptionKey>();
+ map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_SNDBUF,
+ RdmaNet.UNSPEC), new RdmaOptionKey(SOL_SOCKET, SO_SNDBUF));
+ map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_RCVBUF,
+ RdmaNet.UNSPEC), new RdmaOptionKey(SOL_SOCKET, SO_RCVBUF));
+ map.put(new RegistryKey(StandardSocketOptions.PREFIX_SO_REUSEADDR,
+ RdmaNet.UNSPEC), new RdmaOptionKey(SOL_SOCKET, SO_REUSEADDR));
+ // IPPROTO_TCP is 6
+ map.put(new RegistryKey(StandardSocketOptions.PREFIX_TCP_NODELAY,
+ RdmaNet.UNSPEC), new RdmaOptionKey(6, TCP_NODELAY));
+ return map;
+ }
+ }
+
+ public static RdmaOptionKey findOption(SocketOption<?> name,
+ ProtocolFamily family) {
+ RegistryKey key = new RegistryKey(name, family);
+ return LazyInitialization.options.get(key);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketOutputStream.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.net.Socket;
+import java.net.SocketException;
+
+class RdmaSocketOutputStream extends FileOutputStream
+{
+ static {
+ init();
+ }
+
+ private RdmaSocketImpl impl = null;
+ private byte temp[] = new byte[1];
+ private Socket socket = null;
+
+ RdmaSocketOutputStream(RdmaSocketImpl impl) throws IOException {
+ super(impl.getFileDescriptor());
+ this.impl = impl;
+ socket = impl.getSocket();
+ }
+
+ public final FileChannel getChannel() {
+ return null;
+ }
+
+ /**
+ * Writes to the socket.
+ * @param fd the FileDescriptor
+ * @param b the data to be written
+ * @param off the start offset in the data
+ * @param len the number of bytes that are written
+ * @exception IOException If an I/O error has occurred.
+ */
+ private native void rdmaSocketWrite0(FileDescriptor fd, byte[] b,
+ int off, int len) throws IOException;
+
+ /**
+ * Writes to the socket with appropriate locking of the
+ * FileDescriptor.
+ * @param b the data to be written
+ * @param off the start offset in the data
+ * @param len the number of bytes that are written
+ * @exception IOException If an I/O error has occurred.
+ */
+ private void rdmaSocketWrite(byte b[], int off, int len)
+ throws IOException {
+ if (len <= 0 || off < 0 || len > b.length - off) {
+ if (len == 0) {
+ return;
+ }
+ throw new ArrayIndexOutOfBoundsException("len == " + len
+ + " off == " + off + " buffer length == " + b.length);
+ }
+
+ FileDescriptor fd = impl.acquireFD();
+ try {
+ rdmaSocketWrite0(fd, b, off, len);
+ } catch (SocketException se) {
+ if (se instanceof sun.net.ConnectionResetException) {
+ impl.setConnectionResetPending();
+ se = new SocketException("Connection reset");
+ }
+ if (impl.isClosedOrPending()) {
+ throw new SocketException("Socket closed");
+ } else {
+ throw se;
+ }
+ } finally {
+ impl.releaseFD();
+ }
+ }
+
+ /**
+ * Writes a byte to the socket.
+ * @param b the data to be written
+ * @exception IOException If an I/O error has occurred.
+ */
+ public void write(int b) throws IOException {
+ temp[0] = (byte)b;
+ rdmaSocketWrite(temp, 0, 1);
+ }
+
+ /**
+ * Writes the contents of the buffer <i>b</i> to the socket.
+ * @param b the data to be written
+ * @exception SocketException If an I/O error has occurred.
+ */
+ public void write(byte b[]) throws IOException {
+ rdmaSocketWrite(b, 0, b.length);
+ }
+
+ /**
+ * Writes <i>length</i> bytes from buffer <i>b</i> starting at
+ * offset <i>len</i>.
+ * @param b the data to be written
+ * @param off the start offset in the data
+ * @param len the number of bytes that are written
+ * @exception SocketException If an I/O error has occurred.
+ */
+ public void write(byte b[], int off, int len) throws IOException {
+ rdmaSocketWrite(b, off, len);
+ }
+
+ /**
+ * Closes the stream.
+ */
+ private boolean closing = false;
+ public void close() throws IOException {
+ if (closing)
+ return;
+ closing = true;
+ if (socket != null) {
+ if (!socket.isClosed())
+ socket.close();
+ } else
+ impl.close();
+ closing = false;
+ }
+
+ /**
+ * Perform class load-time initializations.
+ */
+ private static native void init();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketProvider.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.IOException;
+import java.net.ProtocolFamily;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketImpl;
+import java.net.SocketOption;
+import java.net.SocketOptions;
+import java.net.StandardSocketOptions;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import jdk.net.RdmaSocketOptions;
+
+public class RdmaSocketProvider {
+
+ static class RdmaClientSocketImpl extends RdmaSocketImpl {
+
+ private final Set<SocketOption<?>> options =
+ Set.of(StandardSocketOptions.SO_SNDBUF,
+ StandardSocketOptions.SO_RCVBUF,
+ StandardSocketOptions.SO_REUSEADDR,
+ StandardSocketOptions.TCP_NODELAY,
+ RdmaSocketOptions.RDMA_SQSIZE,
+ RdmaSocketOptions.RDMA_RQSIZE,
+ RdmaSocketOptions.RDMA_INLINE);
+
+ RdmaClientSocketImpl(ProtocolFamily family) {
+ super(family);
+ }
+
+ @Override
+ public Set<SocketOption<?>> supportedOptions() {
+ return options;
+ }
+
+ @Override
+ protected <T> void setOption(SocketOption<T> name, T value)
+ throws IOException {
+ if (!rdmaOptions.isOptionSupported(name)) {
+ int opt;
+ if (name == StandardSocketOptions.SO_SNDBUF) {
+ opt = SocketOptions.SO_SNDBUF;
+ } else if (name == StandardSocketOptions.SO_RCVBUF) {
+ opt = SocketOptions.SO_RCVBUF;
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ opt = SocketOptions.SO_REUSEADDR;
+ } else if (name == StandardSocketOptions.TCP_NODELAY) {
+ opt = SocketOptions.TCP_NODELAY;
+ } else {
+ throw new UnsupportedOperationException(
+ "unsupported option: " + name);
+ }
+ setOption(opt, value);
+ } else {
+ rdmaOptions.setOption(fd, name, value);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected <T> T getOption(SocketOption<T> name) throws IOException {
+ Object value;
+ if (!rdmaOptions.isOptionSupported(name)) {
+ int opt;
+ if (name == StandardSocketOptions.SO_SNDBUF) {
+ opt = SocketOptions.SO_SNDBUF;
+ } else if (name == StandardSocketOptions.SO_RCVBUF) {
+ opt = SocketOptions.SO_RCVBUF;
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ opt = SocketOptions.SO_REUSEADDR;
+ } else if (name == StandardSocketOptions.TCP_NODELAY) {
+ opt = SocketOptions.TCP_NODELAY;
+ } else {
+ throw new UnsupportedOperationException(
+ "unsupported option: " + name);
+ }
+ value = getOption(opt);
+ } else {
+ value = rdmaOptions.getOption(fd, name);
+ }
+ return (T) value;
+ }
+ }
+
+ static class RdmaServerSocketImpl extends RdmaSocketImpl {
+ private final Set<SocketOption<?>> options =
+ Set.of(StandardSocketOptions.SO_RCVBUF,
+ StandardSocketOptions.SO_REUSEADDR,
+ RdmaSocketOptions.RDMA_SQSIZE,
+ RdmaSocketOptions.RDMA_RQSIZE,
+ RdmaSocketOptions.RDMA_INLINE);
+
+ RdmaServerSocketImpl(ProtocolFamily family) {
+ super(family);
+ }
+
+ @Override
+ public Set<SocketOption<?>> supportedOptions() {
+ return options;
+ }
+
+ @Override
+ protected <T> void setOption(SocketOption<T> name, T value)
+ throws IOException {
+ if (!rdmaOptions.isOptionSupported(name)) {
+ int opt;
+ if (name == StandardSocketOptions.SO_RCVBUF) {
+ opt = SocketOptions.SO_RCVBUF;
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ opt = SocketOptions.SO_REUSEADDR;
+ } else {
+ throw new UnsupportedOperationException(
+ "unsupported option: " + name);
+ }
+ setOption(opt, value);
+ } else {
+ rdmaOptions.setOption(fd, name, value);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected <T> T getOption(SocketOption<T> name) throws IOException {
+ Object value;
+ if (!rdmaOptions.isOptionSupported(name)) {
+ int opt;
+ if (name == StandardSocketOptions.SO_RCVBUF) {
+ opt = SocketOptions.SO_RCVBUF;
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ opt = SocketOptions.SO_REUSEADDR;
+ } else {
+ throw new UnsupportedOperationException(
+ "unsupported option: " + name);
+ }
+ value = getOption(opt);
+ } else {
+ value = rdmaOptions.getOption(fd, name);
+ }
+ return (T) value;
+ }
+ }
+
+ public static Socket openSocket(ProtocolFamily family) throws IOException {
+ return new Socket(new RdmaClientSocketImpl(family)) { };
+ }
+
+ public static ServerSocket openServerSocket(ProtocolFamily family)
+ throws IOException {
+ return new ServerSocket(new RdmaServerSocketImpl(family)) {
+ public Socket accept() throws IOException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ if (!isBound())
+ throw new SocketException("Socket is not bound yet");
+
+ Socket s = openSocket(family);
+ implAccept(s);
+ return s;
+ }
+ };
+ }
+
+ private RdmaSocketProvider() {}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/classes/jdk/net/LinuxRdmaSocketOptions.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.net;
+
+import java.net.SocketException;
+import jdk.net.RdmaSocketOptions.PlatformRdmaSocketOptions;
+
+class LinuxRdmaSocketOptions extends PlatformRdmaSocketOptions {
+
+ private static final UnsupportedOperationException unsupported;
+
+ private static final Void checkSupported() {
+ if (unsupported != null)
+ throw new UnsupportedOperationException(unsupported.getMessage(), unsupported);
+ else
+ return null;
+ }
+
+ public LinuxRdmaSocketOptions() {
+ this(checkSupported());
+ }
+
+ private LinuxRdmaSocketOptions(Void unused) { }
+
+ @Override native void setSockOpt(int fd, int opt, int value)
+ throws SocketException;
+
+ @Override native int getSockOpt(int fd, int opt)
+ throws SocketException;
+
+ @Override native boolean rdmaSocketSupported();
+
+ static {
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<>() {
+ public Void run() {
+ System.loadLibrary("extnet");
+ return null;
+ }
+ });
+ UnsupportedOperationException uoe = null;
+ try {
+ init();
+ } catch (UnsupportedOperationException e) {
+ uoe = e;
+ }
+ unsupported = uoe;
+ }
+
+ private static native void init() throws UnsupportedOperationException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/LinuxRdmaSocketDispatcherImpl.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include "jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl.h"
+#include "nio.h"
+#include "nio_util.h"
+#include <Rsocket.h>
+
+static jfieldID fd_fdID;
+
+jint
+convertReturnVal(JNIEnv *env, jint n, jboolean reading) {
+ if (n > 0)
+ return n;
+ else if (n == 0) {
+ if (reading) {
+ return IOS_EOF;
+ } else {
+ return 0;
+ }
+ }
+ else if (errno == EAGAIN)
+ return IOS_UNAVAILABLE;
+ else if (errno == EINTR)
+ return IOS_INTERRUPTED;
+ else {
+ const char *msg = reading ? "Read failed" : "Write failed";
+ JNU_ThrowIOExceptionWithLastError(env, msg);
+ return IOS_THROWN;
+ }
+}
+
+jlong
+convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading) {
+ if (n > 0)
+ return n;
+ else if (n == 0) {
+ if (reading) {
+ return IOS_EOF;
+ } else {
+ return 0;
+ }
+ }
+ else if (errno == EAGAIN)
+ return IOS_UNAVAILABLE;
+ else if (errno == EINTR)
+ return IOS_INTERRUPTED;
+ else {
+ const char *msg = reading ? "Read failed" : "Write failed";
+ JNU_ThrowIOExceptionWithLastError(env, msg);
+ return IOS_THROWN;
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_init(JNIEnv *env,
+ jclass cl) {
+ loadRdmaFuncs(env);
+ CHECK_NULL(cl = (*env)->FindClass(env, "java/io/FileDescriptor"));
+ CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, cl, "fd", "I"));
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_read0(JNIEnv *env,
+ jclass clazz, jobject fdo, jlong address, jint len) {
+ jint fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ void *buf = (void *)jlong_to_ptr(address);
+ jint result = convertReturnVal(env, rs_read(fd, buf, len), JNI_TRUE);
+/*
+ if (result == IOS_UNAVAILABLE
+ && (rs_fcntl(fd, F_GETFL, 0) & O_NONBLOCK) == 0) { // blocking
+ struct pollfd pfd[1];
+ pfd[0].fd = fd;
+ pfd[0].events = POLLIN;
+ rs_poll(pfd, 1, -1);
+ if (pfd[0].revents & POLLIN)
+ result = convertReturnVal(env, rs_read(fd, buf, len), JNI_TRUE);
+ else {
+ JNU_ThrowIOExceptionWithLastError(env, "Read failed");
+ return IOS_THROWN;
+ }
+ }
+*/
+ return result;
+}
+
+JNIEXPORT jlong JNICALL
+Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_readv0(JNIEnv *env,
+ jclass clazz, jobject fdo, jlong address, jint len) {
+ jint fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
+ jlong result = convertLongReturnVal(env, rs_readv(fd, iov, len), JNI_TRUE);
+/*
+ if (result == IOS_UNAVAILABLE
+ && (rs_fcntl(fd, F_GETFL, 0) & O_NONBLOCK) == 0) { // blocking
+ struct pollfd pfd[1];
+ pfd[0].fd = fd;
+ pfd[0].events = POLLIN;
+ rs_poll(pfd, 1, -1);
+ if (pfd[0].revents & POLLIN)
+ result = convertLongReturnVal(env, rs_readv(fd, iov, len), JNI_TRUE);
+ else {
+ JNU_ThrowIOExceptionWithLastError(env, "Read failed");
+ return IOS_THROWN;
+ }
+ }
+*/
+ return result;
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_write0(JNIEnv *env,
+ jclass clazz, jobject fdo, jlong address, jint len) {
+ jint fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ void *buf = (void *)jlong_to_ptr(address);
+ jint result = convertReturnVal(env, rs_write(fd, buf, len), JNI_FALSE);
+/*
+ if (result == IOS_UNAVAILABLE
+ && (rs_fcntl(fd, F_GETFL, 0) & O_NONBLOCK) == 0) { // blocking
+ struct pollfd pfd[1];
+ pfd[0].fd = fd;
+ pfd[0].events = POLLOUT;
+ rs_poll(pfd, 1, -1);
+ if (pfd[0].revents & POLLOUT)
+ result = convertReturnVal(env, rs_write(fd, buf, len), JNI_FALSE);
+ else {
+ JNU_ThrowIOExceptionWithLastError(env, "Write failed");
+ return IOS_THROWN;
+ }
+ }
+*/
+ return result;
+}
+
+JNIEXPORT jlong JNICALL
+Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_writev0(JNIEnv *env,
+ jclass clazz, jobject fdo, jlong address, jint len) {
+ jint fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
+ jlong result = convertLongReturnVal(env, rs_writev(fd, iov, len),
+ JNI_FALSE);
+/*
+ if (result == IOS_UNAVAILABLE
+ && (rs_fcntl(fd, F_GETFL, 0) & O_NONBLOCK) == 0) { // blocking
+ struct pollfd pfd[1];
+ pfd[0].fd = fd;
+ pfd[0].events = POLLOUT;
+ rs_poll(pfd, 1, -1);
+ if (pfd[0].revents & POLLOUT)
+ result = convertLongReturnVal(env, rs_writev(fd, iov, len), JNI_FALSE);
+ else {
+ JNU_ThrowIOExceptionWithLastError(env, "Write failed");
+ return IOS_THROWN;
+ }
+ }
+*/
+ return result;
+}
+
+static void closeFileDescriptor(JNIEnv *env, int fd) {
+ if (fd != -1) {
+ int result = rs_close(fd);
+ if (result < 0)
+ JNU_ThrowIOExceptionWithLastError(env, "Close failed");
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_close0(JNIEnv *env,
+ jclass clazz, jobject fdo) {
+ jint fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ closeFileDescriptor(env, fd);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/LinuxRdmaSocketOptions.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+
+#include "jdk_net_LinuxRdmaSocketOptions.h"
+#include "rdma_util_md.h"
+#include "Rsocket.h"
+#include "jni_util.h"
+
+void throwByNameWithLastError(JNIEnv *env, const char *name,
+ const char *defaultDetail) {
+ char defaultMsg[255];
+ sprintf(defaultMsg, "errno: %d, %s", errno, defaultDetail);
+ JNU_ThrowByNameWithLastError(env, name, defaultMsg);
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_net_LinuxRdmaSocketOptions_init(JNIEnv *env, jclass c) {
+ loadRdmaFuncs(env);
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_net_LinuxRdmaSocketOptions_setSockOpt(JNIEnv *env,
+ jobject unused, jint fd, jint opt, jint value) {
+ int optname;
+ int level = SOL_RDMA;
+ RDMA_MapSocketOption(opt, &level, &optname);
+ int len = sizeof(value);
+ int rv = RDMA_SetSockOpt(fd, level, optname, (char*)&value, len);
+ if (rv < 0) {
+ if (errno == ENOPROTOOPT) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ "unsupported RDMA socket option");
+ } else if (errno == EACCES || errno == EPERM) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Permission denied");
+ } else {
+ throwByNameWithLastError(env, "java/net/SocketException",
+ "set RDMA option failed");
+ }
+ }
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_net_LinuxRdmaSocketOptions_getSockOpt(JNIEnv *env,
+ jobject unused, jint fd, jint opt) {
+ int optname;
+ int level = SOL_RDMA;
+ RDMA_MapSocketOption(opt, &level, &optname);
+ int value;
+ int len = sizeof(value);
+ int rv = RDMA_GetSockOpt(fd, level, optname, (char*)&value, &len);
+
+ if (rv < 0) {
+ if (errno == ENOPROTOOPT) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ "unsupported RDMA socket option");
+ } else if (errno == EACCES || errno == EPERM) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Permission denied");
+ } else {
+ throwByNameWithLastError(env, "java/net/SocketException",
+ "get RDMA option failed");
+ }
+ return -1;
+ }
+ return value;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_jdk_net_LinuxRdmaSocketOptions_rdmaSocketSupported(JNIEnv *env,
+ jobject unused) {
+ int rv, s;
+
+ s = rs_socket(PF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ return JNI_FALSE;
+ }
+ rs_close(s);
+ return JNI_TRUE;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/RdmaNet.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include "net_util.h"
+#include "nio.h"
+#include "nio_util.h"
+#include "rdma_util_md.h"
+#include "Rsocket.h"
+#include "sun_nio_ch_Net.h"
+
+static jfieldID fd_fdID;
+
+JNIEXPORT jboolean JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_isRdmaAvailable0(JNIEnv *env,
+ jclass clazz) {
+ return rdma_supported();
+}
+
+static int
+configureBlocking(int fd, jboolean blocking) {
+ int flags = rs_fcntl(fd, F_GETFL);
+ int newflags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
+
+ return (flags == newflags) ? 0 : rs_fcntl(fd, F_SETFL, newflags);
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_configureBlocking(JNIEnv *env, jclass clazz,
+ jobject fdo, jboolean blocking) {
+ int fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ if (configureBlocking(fd, blocking) < 0)
+ JNU_ThrowIOExceptionWithLastError(env, "Configure blocking failed");
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_initIDs(JNIEnv *env, jclass clazz) {
+ loadRdmaFuncs(env);
+ CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor"));
+ CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, clazz, "fd", "I"));
+ initInetAddressIDs(env);
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_socket0(JNIEnv *env, jclass clazz,
+ jboolean preferIPv6, jboolean stream, jboolean reuse) {
+ int fd;
+ int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
+ int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
+
+ fd = rs_socket(domain, type, 0);
+
+ rs_fcntl(fd, F_SETFL, rs_fcntl(fd, F_GETFL) | O_NONBLOCK);
+
+ if (fd < 0) {
+ return handleSocketError(env, errno);
+ }
+
+ if (reuse) {
+ int arg = 1;
+ if (rs_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
+ sizeof(arg)) < 0) {
+ JNU_ThrowByNameWithLastError(env,
+ JNU_JAVANETPKG "SocketException",
+ "Unable to set SO_REUSEADDR");
+ rs_close(fd);
+ return -1;
+ }
+ }
+ return fd;
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_bind0(JNIEnv *env, jclass clazz,
+ jobject fdo, jboolean preferIPv6, jobject iao, int port) {
+ SOCKETADDRESS sa;
+ int sa_len = 0;
+ int rv = 0;
+
+ if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
+ preferIPv6) != 0) {
+ return;
+ }
+
+ int fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ rv = RDMA_Bind(fd, &sa, sa_len);
+ if (rv != 0) {
+ handleSocketError(env, errno);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_listen(JNIEnv *env, jclass clazz,
+ jobject fdo, jint backlog) {
+ int fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ if (rs_listen(fd, backlog) < 0)
+ handleSocketError(env, errno);
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_connect0(JNIEnv *env, jclass clazz,
+ jboolean preferIPv6, jobject fdo, jobject iao, jint port) {
+ SOCKETADDRESS sa;
+ int sa_len = 0;
+ int rv;
+
+ if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
+ preferIPv6) != 0) {
+ return IOS_THROWN;
+ }
+
+ int fd = (*env)->GetIntField(env, fdo, fd_fdID);
+
+ rv = rs_connect(fd, &sa.sa, sa_len);
+
+ if (rv != 0) {
+ if (errno == EINPROGRESS) {
+ return IOS_UNAVAILABLE;
+ } else if (errno == EINTR) {
+ return IOS_INTERRUPTED;
+ }
+ return handleSocketError(env, errno);
+ }
+ return 1;
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_localPort(JNIEnv *env, jclass clazz,
+ jobject fdo) {
+ SOCKETADDRESS sa;
+ socklen_t sa_len = sizeof(SOCKETADDRESS);
+ int fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ if (rs_getsockname(fd, &sa.sa, &sa_len) < 0) {
+ handleSocketError(env, errno);
+ return -1;
+ }
+ return NET_GetPortFromSockaddr(&sa);
+}
+
+JNIEXPORT jobject JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_localInetAddress(JNIEnv *env, jclass clazz,
+ jobject fdo) {
+ SOCKETADDRESS sa;
+ socklen_t sa_len = sizeof(SOCKETADDRESS);
+ int port;
+ int fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ if (rs_getsockname(fd, &sa.sa, &sa_len) < 0) {
+ handleSocketError(env, errno);
+ return NULL;
+ }
+ return NET_SockaddrToInetAddress(env, &sa, &port);
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_getIntOption0(JNIEnv *env, jclass clazz,
+ jobject fdo, jboolean mayNeedConversion, jint level, jint opt) {
+ int result;
+ void *arg;
+ socklen_t arglen;
+ int n;
+
+ arg = (void *)&result;
+ arglen = sizeof(result);
+
+ int fd = (*env)->GetIntField(env, fdo, fd_fdID);
+
+ if (mayNeedConversion) {
+ n = RDMA_GetSockOpt(fd, level, opt, arg, (int*)&arglen);
+ } else {
+ n = rs_getsockopt(fd, level, opt, arg, &arglen);
+ }
+
+ if (n < 0) {
+ JNU_ThrowByNameWithLastError(env,
+ JNU_JAVANETPKG "SocketException",
+ "jdk.internal.net.rdma.RdmaNet.getIntOption");
+ return -1;
+ }
+
+ return (jint)result;
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_setIntOption0(JNIEnv *env, jclass clazz,
+ jobject fdo, jboolean mayNeedConversion, jint level, jint opt,
+ jint arg) {
+ int result;
+ void *parg;
+ socklen_t arglen;
+ int n;
+
+ parg = (void*)&arg;
+ arglen = sizeof(arg);
+
+ int fd = (*env)->GetIntField(env, fdo, fd_fdID);
+
+ if (mayNeedConversion) {
+ n = RDMA_SetSockOpt(fd, level, opt, parg, arglen);
+ } else {
+ n = rs_setsockopt(fd, level, opt, parg, arglen);
+ }
+ if (n < 0) {
+ JNU_ThrowByNameWithLastError(env,
+ JNU_JAVANETPKG "SocketException",
+ "jdk.internal.net.rdma.RdmaNet.setIntOption");
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_shutdown(JNIEnv *env, jclass clazz,
+ jobject fdo, jint jhow) {
+ int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
+ (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
+ int fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ if ((rs_shutdown(fd, how) < 0) && (errno != ENOTCONN))
+ handleSocketError(env, errno);
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaNet_poll(JNIEnv* env, jclass clazz,
+ jobject fdo, jint events, jlong timeout) {
+ struct pollfd pfd;
+ int rv;
+ pfd.fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ pfd.events = events;
+ if (timeout < -1) {
+ timeout = -1;
+ } else if (timeout > INT_MAX) {
+ timeout = INT_MAX;
+ }
+ rv = rs_poll(&pfd, 1, (int)timeout);
+
+ if (rv >= 0) {
+ return pfd.revents;
+ } else if (errno == EINTR) {
+ // interrupted, no events to return
+ return 0;
+ } else {
+ handleSocketError(env, errno);
+ return IOS_THROWN;
+ }
+}
+
+jint handleSocketError(JNIEnv *env, jint errorValue) {
+ char *xn;
+ switch (errorValue) {
+ case EINPROGRESS: /* Non-blocking connect */
+ return 0;
+#ifdef EPROTO
+ case EPROTO:
+ xn = JNU_JAVANETPKG "ProtocolException";
+ break;
+#endif
+ case ECONNREFUSED:
+ case ETIMEDOUT:
+ case ENOTCONN:
+ xn = JNU_JAVANETPKG "ConnectException";
+ break;
+
+ case EHOSTUNREACH:
+ xn = JNU_JAVANETPKG "NoRouteToHostException";
+ break;
+ case EADDRINUSE: /* Fall through */
+ case EADDRNOTAVAIL:
+ xn = JNU_JAVANETPKG "BindException";
+ break;
+ default:
+ xn = JNU_JAVANETPKG "SocketException";
+ break;
+ }
+ errno = errorValue;
+ JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
+ return IOS_THROWN;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/RdmaPollSelectorImpl.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include <Rsocket.h>
+#include "jni_util.h"
+#include "jvm.h"
+#include "nio.h"
+#include "jdk_internal_net_rdma_RdmaPollSelectorImpl.h"
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaPollSelectorImpl_init(JNIEnv *env,
+ jclass clazz) {
+ loadRdmaFuncs(env);
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaPollSelectorImpl_poll0(JNIEnv *env,
+ jclass clazz, jlong address, jint numfds, jint timeout) {
+ struct pollfd *a;
+ int res;
+
+ a = (struct pollfd *) jlong_to_ptr(address);
+ res = rs_poll(a, numfds, timeout);
+ if (res < 0) {
+ if (errno == EINTR) {
+ return IOS_INTERRUPTED;
+ } else {
+ JNU_ThrowIOExceptionWithLastError(env, "poll failed");
+ return IOS_THROWN;
+ }
+ }
+ return (jint) res;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/RdmaServerSocketChannelImpl.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include "jdk_internal_net_rdma_RdmaServerSocketChannelImpl.h"
+#include "net_util.h"
+#include "nio.h"
+#include <Rsocket.h>
+
+static jfieldID fd_fdID; /* java.io.FileDescriptor.fd */
+static jclass isa_class; /* java.net.InetSocketAddress */
+static jmethodID isa_ctorID; /* .InetSocketAddress(InetAddress, int) */
+
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaServerSocketChannelImpl_initIDs(JNIEnv *env,
+ jclass c) {
+ loadRdmaFuncs(env);
+
+ jclass cls;
+
+ cls = (*env)->FindClass(env, "java/io/FileDescriptor");
+ CHECK_NULL(cls);
+ fd_fdID = (*env)->GetFieldID(env, cls, "fd", "I");
+ CHECK_NULL(fd_fdID);
+
+ cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
+ CHECK_NULL(cls);
+ isa_class = (*env)->NewGlobalRef(env, cls);
+ if (isa_class == NULL) {
+ JNU_ThrowOutOfMemoryError(env, NULL);
+ return;
+ }
+ isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
+ "(Ljava/net/InetAddress;I)V");
+ CHECK_NULL(isa_ctorID);
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaServerSocketChannelImpl_checkAccept(JNIEnv *env,
+ jobject this, jobject fdo) {
+ jint fd = (*env)->GetIntField(env, fdo, fd_fdID);
+ int result = 0;
+ struct pollfd poller;
+
+ poller.fd = fd;
+ poller.events = POLLIN;
+ poller.revents = 0;
+
+ result = rs_poll(&poller, 1, -1);
+
+ if (result < 0) {
+ if (errno == EINTR) {
+ return IOS_INTERRUPTED;
+ } else {
+ JNU_ThrowIOExceptionWithLastError(env, "rpoll failed");
+ return IOS_THROWN;
+ }
+ }
+
+ if (poller.revents & poller.events) {
+ return 1;
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaServerSocketChannelImpl_accept0(JNIEnv *env,
+ jobject this, jobject ssfdo, jobject newfdo, jobjectArray isaa) {
+ jint ssfd = (*env)->GetIntField(env, ssfdo, fd_fdID);
+ jint newfd;
+ SOCKETADDRESS sa;
+ socklen_t sa_len = sizeof(SOCKETADDRESS);
+ jobject remote_ia = 0;
+ jobject isa;
+ jint remote_port = 0;
+
+ /*
+ * accept connection but ignore ECONNABORTED indicating that
+ * a connection was eagerly accepted but was reset before
+ * accept() was called.
+ */
+ for (;;) {
+ newfd = rs_accept(ssfd, &sa.sa, &sa_len);
+ if (newfd >= 0) {
+ break;
+ }
+ if (errno != ECONNABORTED) {
+ break;
+ }
+ /* ECONNABORTED => restart accept */
+ }
+
+ if (newfd < 0) {
+ if (errno == EAGAIN)
+ return IOS_UNAVAILABLE;
+ if (errno == EINTR)
+ return IOS_INTERRUPTED;
+ JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
+ return IOS_THROWN;
+ }
+
+ (*env)->SetIntField(env, newfdo, fd_fdID, newfd);
+ remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
+ CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
+ isa = (*env)->NewObject(env, isa_class, isa_ctorID,
+ remote_ia, remote_port);
+ CHECK_NULL_RETURN(isa, IOS_THROWN);
+ (*env)->SetObjectArrayElement(env, isaa, 0, isa);
+ return 1;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/RdmaSocketChannelImpl.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include "jdk_internal_net_rdma_RdmaSocketChannelImpl.h"
+#include "nio_util.h"
+#include "nio.h"
+#include <Rsocket.h>
+
+static jfieldID fd_fdID;
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketChannelImpl_initIDs(JNIEnv *env,
+ jclass clazz) {
+ loadRdmaFuncs(env);
+ CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor"));
+ CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, clazz, "fd", "I"));
+}
+
+jint fdVal(JNIEnv *env, jobject fdo) {
+ return (*env)->GetIntField(env, fdo, fd_fdID);
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketChannelImpl_checkConnect(JNIEnv *env,
+ jobject this, jobject fdo, jboolean block) {
+ int error = 0;
+ socklen_t n = sizeof(int);
+ jint fd = fdVal(env, fdo);
+ int result = 0;
+ struct pollfd poller;
+
+ poller.fd = fd;
+ poller.events = POLLOUT;
+ poller.revents = 0;
+
+ result = rs_poll(&poller, 1, block ? -1 : 0);
+
+ if (result < 0) {
+ if (errno == EINTR) {
+ return IOS_INTERRUPTED;
+ } else {
+ JNU_ThrowIOExceptionWithLastError(env, "rpoll failed");
+ return IOS_THROWN;
+ }
+ }
+ if (!block && (result == 0))
+ return IOS_UNAVAILABLE;
+
+ if (result > 0) {
+ errno = 0;
+ result = rs_getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n);
+ if (result < 0) {
+ return handleSocketError(env, errno);
+ } else if (error) {
+ return handleSocketError(env, error);
+ } else if ((poller.revents & POLLHUP) != 0) {
+ return handleSocketError(env, ENOTCONN);
+ }
+ // connected
+ return 1;
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketChannelImpl_sendOutOfBandData(JNIEnv* env,
+ jclass this, jobject fdo, jbyte b) {
+ int n = rs_send(fdVal(env, fdo), (const void*)&b, 1, MSG_OOB);
+ return convertReturnVal(env, n, JNI_FALSE);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/RdmaSocketImpl.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,711 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include "java_net_SocketOptions.h"
+#include "jdk_internal_net_rdma_RdmaSocketImpl.h"
+#include "jvm.h"
+#include "net_util.h"
+#include "rdma_util_md.h"
+#include "Rsocket.h"
+
+/************************************************************************
+ * RdmaSocketImpl
+ */
+
+static jfieldID IO_fd_fdID;
+
+jfieldID psi_fdID;
+jfieldID psi_addressID;
+jfieldID psi_ipaddressID;
+jfieldID psi_portID;
+jfieldID psi_localportID;
+jfieldID psi_timeoutID;
+jfieldID psi_trafficClassID;
+jfieldID psi_serverSocketID;
+jfieldID psi_fdLockID;
+jfieldID psi_closePendingID;
+
+#define SET_NONBLOCKING(fd) { \
+ int flags = rs_fcntl(fd, F_GETFL); \
+ flags |= O_NONBLOCK; \
+ rs_fcntl(fd, F_SETFL, flags); \
+}
+
+#define SET_BLOCKING(fd) { \
+ int flags = rs_fcntl(fd, F_GETFL); \
+ flags &= ~O_NONBLOCK; \
+ rs_fcntl(fd, F_SETFL, flags); \
+}
+
+static jclass socketExceptionCls;
+
+static int getFD(JNIEnv *env, jobject this) {
+ jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
+ CHECK_NULL_RETURN(fdObj, -1);
+ return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+}
+
+
+jfieldID
+NET_GetFileDescriptorID(JNIEnv *env) {
+ jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor");
+ CHECK_NULL_RETURN(cls, NULL);
+ return (*env)->GetFieldID(env, cls, "fd", "I");
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_initProto(JNIEnv *env,
+ jclass cls) {
+ loadRdmaFuncs(env);
+
+ jclass clazz = (*env)->FindClass(env,
+ "jdk/internal/net/rdma/RdmaSocketImpl");
+ psi_fdID = (*env)->GetFieldID(env, clazz , "fd",
+ "Ljava/io/FileDescriptor;");
+ CHECK_NULL(psi_fdID);
+ psi_addressID = (*env)->GetFieldID(env, clazz, "address",
+ "Ljava/net/InetAddress;");
+ CHECK_NULL(psi_addressID);
+ psi_timeoutID = (*env)->GetFieldID(env, clazz, "timeout", "I");
+ CHECK_NULL(psi_timeoutID);
+ psi_trafficClassID = (*env)->GetFieldID(env, clazz, "trafficClass", "I");
+ CHECK_NULL(psi_trafficClassID);
+ psi_portID = (*env)->GetFieldID(env, clazz, "port", "I");
+ CHECK_NULL(psi_portID);
+ psi_localportID = (*env)->GetFieldID(env, clazz, "localport", "I");
+ CHECK_NULL(psi_localportID);
+ psi_serverSocketID = (*env)->GetFieldID(env, clazz, "serverSocket",
+ "Ljava/net/ServerSocket;");
+ CHECK_NULL(psi_serverSocketID);
+
+ IO_fd_fdID = NET_GetFileDescriptorID(env);
+ CHECK_NULL(IO_fd_fdID);
+
+ initInetAddressIDs(env);
+ JNU_CHECK_EXCEPTION(env);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_isRdmaAvailable0(JNIEnv *env,
+ jclass cls) {
+ return rdma_supported();
+}
+
+void
+NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass) {
+ if (sa->sa.sa_family == AF_INET6) {
+ sa->sa6.sin6_flowinfo = htonl((trafficClass & 0xff) << 20);
+ }
+}
+
+/*
+ * Class: jdk_net_RdmaSocketImpl
+ * Method: rdmaSocketCreate
+ * Signature: (Z)V */
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketCreate(JNIEnv *env,
+ jclass cls, jboolean preferIPv6, jboolean stream) {
+ jobject fdObj, ssObj;
+ int fd;
+ int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
+ int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
+
+ if (socketExceptionCls == NULL) {
+ jclass c = (*env)->FindClass(env, "java/net/SocketException");
+ CHECK_NULL(c);
+ socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c);
+ CHECK_NULL(socketExceptionCls);
+ }
+
+ fdObj = (*env)->GetObjectField(env, cls, psi_fdID);
+
+ if (fdObj == NULL) {
+ (*env)->ThrowNew(env, socketExceptionCls, "null fd object");
+ return;
+ }
+
+ if ((fd = rs_socket(domain, type, 0)) == -1) {
+ NET_ThrowNew(env, errno, "can't create socket");
+ return;
+ }
+ if (domain == AF_INET6) {
+ int arg = 0;
+ if (rs_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
+ sizeof(int)) < 0) {
+ NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
+ rs_close(fd);
+ return;
+ }
+ }
+
+ ssObj = (*env)->GetObjectField(env, cls, psi_serverSocketID);
+ if (ssObj != NULL) {
+ int arg = 1;
+ SET_NONBLOCKING(fd);
+ if (RDMA_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
+ sizeof(arg)) < 0) {
+ NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
+ rs_close(fd);
+ return;
+ }
+ }
+ (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketConnect(JNIEnv *env,
+ jclass cls, jboolean preferIPv6, jobject iaObj, jint port,
+ jint timeout) {
+ jint localport = (*env)->GetIntField(env, cls, psi_localportID);
+ int len = 0;
+ jobject fdObj = (*env)->GetObjectField(env, cls, psi_fdID);
+
+ jobject fdLock;
+
+ jint trafficClass = (*env)->GetIntField(env, cls, psi_trafficClassID);
+
+ jint fd;
+
+ SOCKETADDRESS sa;
+ int connect_rv = -1;
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
+ return;
+ } else {
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ }
+ if (IS_NULL(iaObj)) {
+ JNU_ThrowNullPointerException(env, "inet address argument null.");
+ return;
+ }
+
+ if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len,
+ preferIPv6) != 0) {
+ return;
+ }
+
+ if (trafficClass != 0 && ipv6_available()) {
+ NET_SetTrafficClass(&sa, trafficClass);
+ }
+
+ if (timeout <= 0) {
+ connect_rv = RDMA_Connect(fd, &sa.sa, len);
+ } else {
+ SET_NONBLOCKING(fd);
+
+ connect_rv = rs_connect(fd, &sa.sa, len);
+
+ if (connect_rv != 0) {
+ socklen_t optlen;
+ jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
+ jlong prevNanoTime = JVM_NanoTime(env, 0);
+
+ if (errno != EINPROGRESS) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "ConnectException", "connect failed");
+ SET_BLOCKING(fd);
+ return;
+ }
+
+ while (1) {
+ jlong newNanoTime;
+ struct pollfd pfd;
+ pfd.fd = fd;
+ pfd.events = POLLOUT;
+
+ errno = 0;
+
+ connect_rv = RDMA_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC);
+
+ if (connect_rv >= 0) {
+ break;
+ }
+ if (errno != EINTR) {
+ break;
+ }
+
+ newNanoTime = JVM_NanoTime(env, 0);
+ nanoTimeout -= (newNanoTime - prevNanoTime);
+ if (nanoTimeout < NET_NSEC_PER_MSEC) {
+ connect_rv = 0;
+ break;
+ }
+ prevNanoTime = newNanoTime;
+
+ }
+
+ if (connect_rv == 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+ "connect timed out");
+
+ SET_BLOCKING(fd);
+ rs_shutdown(fd, 2);
+ return;
+ }
+
+ optlen = sizeof(connect_rv);
+ if (rs_getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
+ &optlen) <0) {
+ connect_rv = errno;
+ }
+ }
+
+ SET_BLOCKING(fd);
+
+ if (connect_rv != 0) {
+ errno = connect_rv;
+ connect_rv = -1;
+ }
+ }
+
+ if (connect_rv < 0) {
+ if (connect_rv == -1 && errno == EINVAL) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Invalid argument or cannot assign requested address");
+ return;
+ }
+#if defined(EPROTO)
+ if (errno == EPROTO) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "ProtocolException", "Protocol error");
+ return;
+ }
+#endif
+ if (errno == ECONNREFUSED) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "ConnectException", "Connection refused");
+ } else if (errno == ETIMEDOUT) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "ConnectException", "Connection timed out");
+ } else if (errno == EHOSTUNREACH) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "NoRouteToHostException", "Host unreachable");
+ } else if (errno == EADDRNOTAVAIL) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "NoRouteToHostException",
+ "Address not available");
+ } else if ((errno == EISCONN) || (errno == EBADF)) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ } else {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException", "connect failed");
+ }
+ return;
+ }
+
+ (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
+
+ (*env)->SetObjectField(env, cls, psi_addressID, iaObj);
+ (*env)->SetIntField(env, cls, psi_portID, port);
+
+ if (localport == 0) {
+ socklen_t slen = sizeof(SOCKETADDRESS);
+ if (rs_getsockname(fd, &sa.sa, &slen) == -1) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException",
+ "Error getting socket name");
+ } else {
+ localport = NET_GetPortFromSockaddr(&sa);
+ (*env)->SetIntField(env, cls, psi_localportID, localport);
+ }
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketBind(JNIEnv *env,
+ jclass cls, jboolean preferIPv6, jobject iaObj, jint localport) {
+ jobject fdObj = (*env)->GetObjectField(env, cls, psi_fdID);
+ int fd;
+ int len = 0;
+ SOCKETADDRESS sa;
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ return;
+ } else {
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ }
+ if (IS_NULL(iaObj)) {
+ JNU_ThrowNullPointerException(env, "iaObj is null.");
+ return;
+ }
+
+ if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa,
+ &len, preferIPv6) != 0) {
+ return;
+ }
+
+ if (RDMA_Bind(fd, &sa, len) < 0) {
+ if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
+ errno == EPERM || errno == EACCES) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "BindException", "Bind failed");
+ } else {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException", "Bind failed");
+ }
+ return;
+ }
+ (*env)->SetObjectField(env, cls, psi_addressID, iaObj);
+
+ if (localport == 0) {
+ socklen_t slen = sizeof(SOCKETADDRESS);
+ if (rs_getsockname(fd, &sa.sa, &slen) == -1) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException",
+ "Error getting socket name");
+ return;
+ }
+ localport = NET_GetPortFromSockaddr(&sa);
+ (*env)->SetIntField(env, cls, psi_localportID, localport);
+ } else {
+ (*env)->SetIntField(env, cls, psi_localportID, localport);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketListen(JNIEnv *env,
+ jclass cls, jint count) {
+ jobject fdObj = (*env)->GetObjectField(env, cls, psi_fdID);
+ int fd;
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ return;
+ } else {
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ }
+
+ if (count == 0x7fffffff)
+ count -= 1;
+
+ int rv = rs_listen(fd, count);
+ if (rv == -1) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException", "Listen failed");
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketAccept(JNIEnv *env,
+ jclass cls, jobject socket) {
+ int port;
+ jint timeout = (*env)->GetIntField(env, cls, psi_timeoutID);
+ jlong prevNanoTime = 0;
+ jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
+ jobject fdObj = (*env)->GetObjectField(env, cls, psi_fdID);
+
+ jobject socketFdObj;
+ jobject socketAddressObj;
+
+ jint fd;
+
+ jint newfd;
+
+ SOCKETADDRESS sa;
+ socklen_t slen = sizeof(SOCKETADDRESS);
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ return;
+ } else {
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ }
+ if (IS_NULL(socket)) {
+ JNU_ThrowNullPointerException(env, "socket is null");
+ return;
+ }
+
+ for (;;) {
+ int ret;
+ jlong currNanoTime;
+
+ if (prevNanoTime == 0 && nanoTimeout > 0) {
+ prevNanoTime = JVM_NanoTime(env, 0);
+ }
+
+ if (timeout <= 0) {
+ ret = RDMA_Timeout(env, fd, -1, 0);
+ } else {
+ ret = RDMA_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC,
+ prevNanoTime);
+ }
+
+ if (ret == 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+ "Accept timed out");
+ return;
+ } else if (ret == -1) {
+ if (errno == EBADF) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ } else if (errno == ENOMEM) {
+ JNU_ThrowOutOfMemoryError(env,
+ "NET_Timeout native heap allocation failed");
+ } else {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException", "Accept failed");
+ }
+ return;
+ }
+
+ newfd = RDMA_Accept(fd, &sa.sa, &slen);
+
+ if (newfd >= 0) {
+ SET_BLOCKING(newfd);
+ break;
+ }
+
+ if (!(errno == ECONNABORTED || errno == EWOULDBLOCK)) {
+ break;
+ }
+
+ if (nanoTimeout >= NET_NSEC_PER_MSEC) {
+ currNanoTime = JVM_NanoTime(env, 0);
+ nanoTimeout -= (currNanoTime - prevNanoTime);
+ if (nanoTimeout < NET_NSEC_PER_MSEC) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+ "Accept timed out");
+ return;
+ }
+ prevNanoTime = currNanoTime;
+ }
+ }
+
+ if (newfd < 0) {
+ if (newfd == -2) {
+ JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
+ "operation interrupted");
+ } else {
+ if (errno == EINVAL) {
+ errno = EBADF;
+ }
+ if (errno == EBADF) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ } else {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException", "Accept failed");
+ }
+ }
+ return;
+ }
+
+ socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port);
+ if (socketAddressObj == NULL) {
+ rs_close(newfd);
+ return;
+ }
+
+ socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
+ (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd);
+ (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
+ (*env)->SetIntField(env, socket, psi_portID, port);
+ port = (*env)->GetIntField(env, cls, psi_localportID);
+ (*env)->SetIntField(env, socket, psi_localportID, port);
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketClose(JNIEnv *env,
+ jclass cls) {
+ jobject fdObj = (*env)->GetObjectField(env, cls, psi_fdID);
+ jint fd;
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "socket already closed");
+ return;
+ } else {
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ }
+ if (fd != -1) {
+ (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
+ RDMA_SocketClose(fd);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketShutdown(JNIEnv *env,
+ jclass cls, jint howto) {
+ jobject fdObj = (*env)->GetObjectField(env, cls, psi_fdID);
+ jint fd;
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "socket already closed");
+ return;
+ } else {
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ }
+ rs_shutdown(fd, howto);
+}
+
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketSetOption(JNIEnv *env,
+ jclass cls, jint cmd, jboolean on, jobject value) {
+ int fd;
+ int level, optname, optlen;
+ union {
+ int i;
+ struct linger ling;
+ } optval;
+
+ fd = getFD(env, cls);
+ if (fd < 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ return;
+ }
+
+ if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
+ return;
+ }
+
+ if (RDMA_MapSocketOption(cmd, &level, &optname)) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
+ return;
+ }
+
+ switch (cmd) {
+ case java_net_SocketOptions_SO_SNDBUF :
+ case java_net_SocketOptions_SO_RCVBUF :
+ {
+ jclass cls;
+ jfieldID fid;
+
+ cls = (*env)->FindClass(env, "java/lang/Integer");
+ CHECK_NULL(cls);
+ fid = (*env)->GetFieldID(env, cls, "value", "I");
+ CHECK_NULL(fid);
+
+ optval.i = (*env)->GetIntField(env, value, fid);
+ optlen = sizeof(optval.i);
+ break;
+ }
+ default :
+ optval.i = (on ? 1 : 0);
+ optlen = sizeof(optval.i);
+
+ }
+ if (RDMA_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException", "Error setting socket option");
+ }
+}
+
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketGetOption(JNIEnv *env,
+ jclass cls, jint cmd, jobject iaContainerObj) {
+ int fd;
+ int level, optname, optlen;
+ union {
+ int i;
+ struct linger ling;
+ } optval;
+
+ fd = getFD(env, cls);
+ if (fd < 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ return -1;
+ }
+
+ if (cmd == java_net_SocketOptions_SO_BINDADDR) {
+ SOCKETADDRESS sa;
+ socklen_t len = sizeof(SOCKETADDRESS);
+ int port;
+ jobject iaObj;
+ jclass iaCntrClass;
+ jfieldID iaFieldID;
+
+ if (rs_getsockname(fd, &sa.sa, &len) < 0) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException",
+ "Error getting socket name");
+ return -1;
+ }
+ iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
+ CHECK_NULL_RETURN(iaObj, -1);
+
+ iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
+ iaFieldID = (*env)->GetFieldID(env, iaCntrClass,
+ "addr", "Ljava/net/InetAddress;");
+ CHECK_NULL_RETURN(iaFieldID, -1);
+ (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
+ return 0;
+ }
+
+ if (RDMA_MapSocketOption(cmd, &level, &optname)) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
+ return -1;
+ }
+
+ optlen = sizeof(optval.i);
+
+ if (RDMA_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
+ JNU_ThrowByNameWithMessageAndLastError(env,
+ JNU_JAVANETPKG "SocketException", "Error getting socket option");
+ return -1;
+ }
+
+ switch (cmd) {
+ case java_net_SocketOptions_SO_SNDBUF:
+ case java_net_SocketOptions_SO_RCVBUF:
+ return optval.i;
+
+ default :
+ return (optval.i == 0) ? -1 : 1;
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketImpl_rdmaSocketSendUrgentData(
+ JNIEnv *env, jclass cls, jint data) {
+ jobject fdObj = (*env)->GetObjectField(env, cls, psi_fdID);
+ int n, fd;
+ unsigned char d = data & 0xFF;
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
+ return;
+ } else {
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ if (fd == -1) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
+ return;
+ }
+
+ }
+ n = RDMA_Send(fd, (char *)&d, 1, MSG_OOB);
+ if (n == -1) {
+ JNU_ThrowIOExceptionWithLastError(env, "Write failed");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/RdmaSocketInputStream.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+#include <stdlib.h>
+#include "jvm.h"
+#include "net_util.h"
+#include "rdma_util_md.h"
+#include "jdk_internal_net_rdma_RdmaSocketInputStream.h"
+
+static jfieldID IO_fd_fdID;
+
+/*
+ * Class: jdk_net_RdmaSocketInputStream
+ * Method: init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketInputStream_init(JNIEnv *env, jclass cls) {
+ IO_fd_fdID = NET_GetFileDescriptorID(env);
+}
+
+static int RDMA_ReadWithTimeout(JNIEnv *env, int fd, char *bufP, int len,
+ long timeout) {
+ int result = 0;
+ jlong prevNanoTime = JVM_NanoTime(env, 0);
+ jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
+ while (nanoTimeout >= NET_NSEC_PER_MSEC) {
+ result = RDMA_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC,
+ prevNanoTime);
+ if (result <= 0) {
+ if (result == 0) {
+ JNU_ThrowByName(env, "java/net/SocketTimeoutException",
+ "Read timed out");
+ } else if (result == -1) {
+ if (errno == EBADF) {
+ JNU_ThrowByName(env, "java/net/SocketException",
+ "Socket closed");
+ } else if (errno == ENOMEM) {
+ JNU_ThrowOutOfMemoryError
+ (env, "NET_Timeout native heap allocation failed");
+ } else {
+ JNU_ThrowByNameWithMessageAndLastError
+ (env, "java/net/SocketException", "select/poll failed");
+ }
+ }
+ return -1;
+ }
+ result = RDMA_NonBlockingRead(fd, bufP, len);
+ if (result == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
+ jlong newtNanoTime = JVM_NanoTime(env, 0);
+ nanoTimeout -= newtNanoTime - prevNanoTime;
+ if (nanoTimeout >= NET_NSEC_PER_MSEC) {
+ prevNanoTime = newtNanoTime;
+ }
+ } else {
+ break;
+ }
+ }
+ return result;
+}
+
+/*
+ * Class: jdk_net_RdmaSocketInputStream
+ * Method: rdmaSocketRead0
+ * Signature: (Ljava/io/FileDescriptor;[BIII)I
+ */
+JNIEXPORT jint JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketInputStream_rdmaSocketRead0(JNIEnv *env,
+ jobject this, jobject fdObj, jbyteArray data,
+ jint off, jint len, jint timeout) {
+ char BUF[MAX_BUFFER_LEN];
+ char *bufP;
+ jint fd, nread;
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, "java/net/SocketException",
+ "Socket closed");
+ return -1;
+ }
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ if (fd == -1) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
+ return -1;
+ }
+
+ if (len > MAX_BUFFER_LEN) {
+ if (len > MAX_HEAP_BUFFER_LEN) {
+ len = MAX_HEAP_BUFFER_LEN;
+ }
+ bufP = (char *)malloc((size_t)len);
+ if (bufP == NULL) {
+ bufP = BUF;
+ len = MAX_BUFFER_LEN;
+ }
+ } else {
+ bufP = BUF;
+ }
+ if (timeout) {
+ nread = RDMA_ReadWithTimeout(env, fd, bufP, len, timeout);
+ if ((*env)->ExceptionCheck(env)) {
+ if (bufP != BUF) {
+ free(bufP);
+ }
+ return nread;
+ }
+ } else {
+ nread = RDMA_Read(fd, bufP, len);
+ }
+
+ if (nread <= 0) {
+ if (nread < 0) {
+
+ switch (errno) {
+ case ECONNRESET:
+ case EPIPE:
+ JNU_ThrowByName(env, "sun/net/ConnectionResetException",
+ "Connection reset");
+ break;
+
+ case EBADF:
+ JNU_ThrowByName(env, "java/net/SocketException",
+ "Socket closed");
+ break;
+
+ case EINTR:
+ JNU_ThrowByName(env, "java/io/InterruptedIOException",
+ "Operation interrupted");
+ break;
+ default:
+ JNU_ThrowByNameWithMessageAndLastError
+ (env, "java/net/SocketException", "Read failed");
+ }
+ }
+ } else {
+ (*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP);
+ }
+
+ if (bufP != BUF) {
+ free(bufP);
+ }
+ return nread;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/RdmaSocketOutputStream.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+#include <stdlib.h>
+#include "net_util.h"
+#include "rdma_util_md.h"
+#include "jdk_internal_net_rdma_RdmaSocketOutputStream.h"
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static jfieldID IO_fd_fdID;
+
+/*
+ * Class: jdk_net_SocketOutputStream
+ * Method: init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketOutputStream_init(JNIEnv *env,
+ jclass cls) {
+ IO_fd_fdID = NET_GetFileDescriptorID(env);
+}
+
+/*
+ * Class: jdk_net_RdmaSocketOutputStream
+ * Method: rdmaSocketWrite0
+ * Signature: (Ljava/io/FileDescriptor;[BII)V
+ */
+JNIEXPORT void JNICALL
+Java_jdk_internal_net_rdma_RdmaSocketOutputStream_rdmaSocketWrite0(JNIEnv *env,
+ jobject this, jobject fdObj, jbyteArray data, jint off, jint len) {
+ char *bufP;
+ char BUF[MAX_BUFFER_LEN];
+ int buflen;
+ int fd;
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
+ return;
+ } else {
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ if (fd == -1) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
+ return;
+ }
+ }
+
+ if (len <= MAX_BUFFER_LEN) {
+ bufP = BUF;
+ buflen = MAX_BUFFER_LEN;
+ } else {
+ buflen = min(MAX_HEAP_BUFFER_LEN, len);
+ bufP = (char *)malloc((size_t)buflen);
+
+ if (bufP == NULL) {
+ bufP = BUF;
+ buflen = MAX_BUFFER_LEN;
+ }
+ }
+
+ while(len > 0) {
+ int loff = 0;
+ int chunkLen = min(buflen, len);
+ int llen = chunkLen;
+ (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
+
+ if ((*env)->ExceptionCheck(env)) {
+ break;
+ } else {
+ while(llen > 0) {
+ int n = RDMA_Send(fd, bufP + loff, llen, 0);
+ if (n > 0) {
+ llen -= n;
+ loff += n;
+ continue;
+ }
+ if (errno == ECONNRESET) {
+ JNU_ThrowByName(env, "sun/net/ConnectionResetException",
+ "Connection reset");
+ } else {
+ JNU_ThrowByNameWithMessageAndLastError
+ (env, "java/net/SocketException", "Write failed");
+ }
+ if (bufP != BUF) {
+ free(bufP);
+ }
+ return;
+ }
+ len -= chunkLen;
+ off += chunkLen;
+ }
+ }
+
+ if (bufP != BUF) {
+ free(bufP);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/Rsocket.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include <Rsocket.h>
+#include <dlfcn.h>
+#include "jni_util.h"
+
+static const char* nativeRdmaLib = "librdmacm.so.1";
+static jboolean funcs_loaded = JNI_FALSE;
+
+jboolean loadRdmaFuncs(JNIEnv* env) {
+ if (funcs_loaded)
+ return JNI_TRUE;
+
+ if (dlopen(nativeRdmaLib, RTLD_GLOBAL | RTLD_LAZY) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_socket = (rs_rsocket_func*)
+ dlsym(RTLD_DEFAULT, "rsocket")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_fcntl = (rs_rfcntl_func*)
+ dlsym(RTLD_DEFAULT, "rfcntl")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_listen = (rs_rlisten_func*)
+ dlsym(RTLD_DEFAULT, "rlisten")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_bind = (rs_rbind_func*)
+ dlsym(RTLD_DEFAULT, "rbind")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_connect = (rs_rconnect_func*)
+ dlsym(RTLD_DEFAULT, "rconnect")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_getsockname = (rs_rgetsockname_func*)
+ dlsym(RTLD_DEFAULT, "rgetsockname")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_getsockopt = (rs_rgetsockopt_func*)
+ dlsym(RTLD_DEFAULT, "rgetsockopt")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_setsockopt = (rs_rsetsockopt_func*)
+ dlsym(RTLD_DEFAULT, "rsetsockopt")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_shutdown = (rs_rshutdown_func*)
+ dlsym(RTLD_DEFAULT, "rshutdown")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_poll = (rs_rpoll_func*)
+ dlsym(RTLD_DEFAULT, "rpoll")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_send = (rs_rsend_func*)
+ dlsym(RTLD_DEFAULT, "rsend")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_accept = (rs_raccept_func*)
+ dlsym(RTLD_DEFAULT, "raccept")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_close = (rs_rclose_func*)
+ dlsym(RTLD_DEFAULT, "rclose")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_read = (rs_rread_func*)
+ dlsym(RTLD_DEFAULT, "rread")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_readv = (rs_rreadv_func*)
+ dlsym(RTLD_DEFAULT, "rreadv")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_write = (rs_rwrite_func*)
+ dlsym(RTLD_DEFAULT, "rwrite")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_writev = (rs_rwritev_func*)
+ dlsym(RTLD_DEFAULT, "rwritev")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_recv = (rs_rrecv_func*)
+ dlsym(RTLD_DEFAULT, "rrecv")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_recvfrom = (rs_rrecvfrom_func*)
+ dlsym(RTLD_DEFAULT, "rrecvfrom")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ if ((rs_sendto = (rs_rsendto_func*)
+ dlsym(RTLD_DEFAULT, "rsendto")) == NULL) {
+ JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+ dlerror());
+ return JNI_FALSE;
+ }
+
+ funcs_loaded = JNI_TRUE;
+ return JNI_TRUE;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/Rsocket.h Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include <sys/socket.h>
+#include <poll.h>
+#include "jni.h"
+
+/* Function types to support dynamic linking of socket API extension functions
+ * for RDMA. This is so that there is no linkage depandancy during build or
+ * runtime for librdmacm.*/
+typedef int rs_rsocket_func(int domain, int type, int protocol);
+typedef int rs_rfcntl_func(int fd, int cmd, ... /* arg */ );
+typedef int rs_rlisten_func(int sockfd, int backlog);
+typedef int rs_rbind_func(int sockfd, const struct sockaddr *addr,
+ socklen_t addrlen);
+typedef int rs_rconnect_func(int sockfd, const struct sockaddr *addr,
+ socklen_t addlen);
+typedef int rs_rgetsockname_func(int sockfd, struct sockaddr *addr,
+ socklen_t *addrlen);
+typedef int rs_rgetsockopt_func(int sockfd, int level, int optname,
+ void *optval, socklen_t *optlen);
+typedef int rs_rsetsockopt_func(int sockfd, int level, int optname,
+ const void *optval, socklen_t optlen);
+typedef int rs_rshutdown_func(int sockfd, int how);
+typedef int rs_rpoll_func(struct pollfd *fds, nfds_t nfds, int timeout);
+typedef size_t rs_rsend_func(int sockfd, const void *buf, size_t len,
+ int flags);
+typedef int rs_raccept_func(int sockfd, struct sockaddr *addr,
+ socklen_t *addrlen);
+typedef int rs_rclose_func(int sockfd);
+typedef ssize_t rs_rread_func(int sockfd, void *buf, size_t count);
+typedef ssize_t rs_rreadv_func(int sockfd, const struct iovec *iov,
+ int iovcnt);
+typedef ssize_t rs_rwrite_func(int sockfd, const void *buf, size_t count);
+typedef ssize_t rs_rwritev_func(int sockfd, const struct iovec *iov,
+ int iovcnt);
+typedef ssize_t rs_rrecv_func(int sockfd, void *buf, size_t len, int flags);
+typedef ssize_t rs_rrecvfrom_func(int sockfd, void *buf, size_t len, int flags,
+ struct sockaddr *src_addr, socklen_t *addrlen);
+typedef ssize_t rs_rsendto_func(int sockfd, const void *buf, size_t len,
+ int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
+
+rs_rsocket_func* rs_socket;
+rs_rfcntl_func* rs_fcntl;
+rs_rlisten_func* rs_listen;
+rs_rbind_func* rs_bind;
+rs_rconnect_func* rs_connect;
+rs_rgetsockname_func* rs_getsockname;
+rs_rgetsockopt_func* rs_getsockopt;
+rs_rsetsockopt_func* rs_setsockopt;
+rs_rshutdown_func* rs_shutdown;
+rs_rpoll_func* rs_poll;
+rs_rsend_func* rs_send;
+rs_raccept_func* rs_accept;
+rs_rclose_func* rs_close;
+rs_rread_func* rs_read;
+rs_rreadv_func* rs_readv;
+rs_rwrite_func* rs_write;
+rs_rwritev_func* rs_writev;
+rs_rrecv_func* rs_recv;
+rs_rrecvfrom_func* rs_recvfrom;
+rs_rsendto_func* rs_sendto;
+
+jboolean loadRdmaFuncs(JNIEnv* env);
+
+/* Definitions taken from librdmacm/include/rdma/rsocket.h */
+#ifndef SOL_RDMA
+#define SOL_RDMA 0x10000
+#endif
+enum {
+ RDMA_SQSIZE,
+ RDMA_RQSIZE,
+ RDMA_INLINE,
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/rdma_util_md.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include <assert.h>
+#include "java_net_SocketOptions.h"
+#include "jdk_net_RdmaSocketOptions.h"
+#include "jvm.h"
+#include <netinet/tcp.h> // defines TCP_NODELAY
+#include "net_util.h"
+#include "rdma_util_md.h"
+#include "Rsocket.h"
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <pthread.h>
+
+#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \
+ int ret; \
+ threadEntry_t self; \
+ fdEntry_t *fdEntry = getFdEntry(FD); \
+ if (fdEntry == NULL) { \
+ errno = EBADF; \
+ return -1; \
+ } \
+ do { \
+ startOp(fdEntry, &self); \
+ ret = FUNC; \
+ endOp(fdEntry, &self); \
+ } while (ret == -1 && errno == EINTR); \
+ return ret; \
+}
+
+typedef struct threadEntry {
+ pthread_t thr; /* this thread */
+ struct threadEntry *next; /* next thread */
+ int intr; /* interrupted */
+} threadEntry_t;
+
+typedef struct {
+ pthread_mutex_t lock; /* fd lock */
+ threadEntry_t *threads; /* threads blocked on fd */
+} fdEntry_t;
+
+static int sigWakeup = (__SIGRTMAX - 2);
+
+static fdEntry_t* fdTable = NULL;
+
+static const int fdTableMaxSize = 0x1000; /* 4K */
+
+static int fdTableLen = 0;
+
+static int fdLimit = 0;
+
+static fdEntry_t** fdOverflowTable = NULL;
+
+static int fdOverflowTableLen = 0;
+
+static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
+
+pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
+
+static void sig_wakeup(int sig) {
+}
+
+static void __attribute((constructor)) init() {
+ struct rlimit nbr_files;
+ sigset_t sigset;
+ struct sigaction sa;
+ int i = 0;
+
+ if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
+ fprintf(stderr, "library initialization failed - "
+ "unable to get max # of allocated fds\n");
+ abort();
+ }
+ if (nbr_files.rlim_max != RLIM_INFINITY) {
+ fdLimit = nbr_files.rlim_max;
+ } else {
+ fdLimit = INT_MAX;
+ }
+
+ fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
+ fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
+ if (fdTable == NULL) {
+ fprintf(stderr, "library initialization failed - "
+ "unable to allocate file descriptor table - out of memory");
+ abort();
+ } else {
+ for (i = 0; i < fdTableLen; i ++) {
+ pthread_mutex_init(&fdTable[i].lock, NULL);
+ }
+ }
+
+ if (fdLimit > fdTableMaxSize) {
+ fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
+ fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));
+ if (fdOverflowTable == NULL) {
+ fprintf(stderr, "library initialization failed - "
+ "unable to allocate file descriptor overflow table - out of memory");
+ abort();
+ }
+ }
+
+ sa.sa_handler = sig_wakeup;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(sigWakeup, &sa, NULL);
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, sigWakeup);
+ sigprocmask(SIG_UNBLOCK, &sigset, NULL);
+}
+
+static inline fdEntry_t *getFdEntry(int fd) {
+ fdEntry_t* result = NULL;
+
+ if (fd < 0) {
+ return NULL;
+ }
+
+ assert(fd < fdLimit);
+
+ if (fd < fdTableMaxSize) {
+ assert(fd < fdTableLen);
+ result = &fdTable[fd];
+ } else {
+ const int indexInOverflowTable = fd - fdTableMaxSize;
+ const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
+ const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
+ fdEntry_t* slab = NULL;
+ assert(rootindex < fdOverflowTableLen);
+ assert(slabindex < fdOverflowTableSlabSize);
+ pthread_mutex_lock(&fdOverflowTableLock);
+ if (fdOverflowTable[rootindex] == NULL) {
+ fdEntry_t* const newSlab =
+ (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));
+ if (newSlab == NULL) {
+ fprintf(stderr, "Unable to allocate file descriptor overflow"
+ " table slab - out of memory");
+ pthread_mutex_unlock(&fdOverflowTableLock);
+ abort();
+ } else {
+ int i;
+ for (i = 0; i < fdOverflowTableSlabSize; i ++) {
+ pthread_mutex_init(&newSlab[i].lock, NULL);
+ }
+ fdOverflowTable[rootindex] = newSlab;
+ }
+ }
+ pthread_mutex_unlock(&fdOverflowTableLock);
+ slab = fdOverflowTable[rootindex];
+ result = &slab[slabindex];
+ }
+ return result;
+}
+
+static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) {
+ self->thr = pthread_self();
+ self->intr = 0;
+
+ pthread_mutex_lock(&(fdEntry->lock));
+ {
+ self->next = fdEntry->threads;
+ fdEntry->threads = self;
+ }
+ pthread_mutex_unlock(&(fdEntry->lock));
+}
+
+static inline void endOp (fdEntry_t *fdEntry, threadEntry_t *self) {
+ int orig_errno = errno;
+ pthread_mutex_lock(&(fdEntry->lock));
+ {
+ threadEntry_t *curr, *prev=NULL;
+ curr = fdEntry->threads;
+ while (curr != NULL) {
+ if (curr == self) {
+ if (curr->intr) {
+ orig_errno = EBADF;
+ }
+ if (prev == NULL) {
+ fdEntry->threads = curr->next;
+ } else {
+ prev->next = curr->next;
+ }
+ break;
+ }
+ prev = curr;
+ curr = curr->next;
+ }
+ }
+ pthread_mutex_unlock(&(fdEntry->lock));
+ errno = orig_errno;
+}
+
+#define RESTARTABLE(_cmd, _result) do { \
+ do { \
+ _result = _cmd; \
+ } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+int rdma_supported() {
+ int one = 1;
+ int rv, s;
+ s = rs_socket(PF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+int RDMA_MapSocketOption(jint cmd, int *level, int *optname) {
+ static struct {
+ jint cmd;
+ int level;
+ int optname;
+ } const opts[] = {
+ { java_net_SocketOptions_TCP_NODELAY, IPPROTO_TCP, TCP_NODELAY },
+ { java_net_SocketOptions_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF },
+ { java_net_SocketOptions_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF },
+ { java_net_SocketOptions_SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR },
+ { jdk_net_RdmaSocketOptions_SQSIZE, SOL_RDMA, RDMA_SQSIZE },
+ { jdk_net_RdmaSocketOptions_RQSIZE, SOL_RDMA, RDMA_RQSIZE },
+ { jdk_net_RdmaSocketOptions_INLINE, SOL_RDMA, RDMA_INLINE },
+ };
+ int i;
+ for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
+ if (cmd == opts[i].cmd) {
+ *level = opts[i].level;
+ *optname = opts[i].optname;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int RDMA_GetSockOpt(int fd, int level, int opt, void *result, int *len) {
+ int rv;
+ socklen_t socklen = *len;
+
+ rv = rs_getsockopt(fd, level, opt, result, &socklen);
+ *len = socklen;
+
+ if (rv < 0) {
+ return rv;
+ }
+
+ if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
+ || (opt == SO_RCVBUF))) {
+ int n = *((int *)result);
+ n /= 2;
+ *((int *)result) = n;
+ }
+ return rv;
+}
+
+int RDMA_SetSockOpt(int fd, int level, int opt, const void *arg, int len) {
+ int *bufsize;
+ if (level == SOL_SOCKET && opt == SO_RCVBUF) {
+ int *bufsize = (int *)arg;
+ if (*bufsize < 1024) {
+ *bufsize = 1024;
+ }
+ }
+
+ return rs_setsockopt(fd, level, opt, arg, len);
+}
+
+int RDMA_Bind(int fd, SOCKETADDRESS *sa, int len) {
+ int rv;
+ int arg, alen;
+
+ if (sa->sa.sa_family == AF_INET) {
+ if ((ntohl(sa->sa4.sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
+ errno = EADDRNOTAVAIL;
+ return -1;
+ }
+ }
+ rv = rs_bind(fd, &sa->sa, len);
+ return rv;
+}
+
+jint RDMA_Wait(JNIEnv *env, jint fd, jint flags, jint timeout) {
+ jlong prevNanoTime = JVM_NanoTime(env, 0);
+ jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
+ jint read_rv;
+
+ while (1) {
+ jlong newNanoTime;
+ struct pollfd pfd;
+ pfd.fd = fd;
+ pfd.events = 0;
+ if (flags & NET_WAIT_READ)
+ pfd.events |= POLLIN;
+ if (flags & NET_WAIT_WRITE)
+ pfd.events |= POLLOUT;
+ if (flags & NET_WAIT_CONNECT)
+ pfd.events |= POLLOUT;
+
+ errno = 0;
+ read_rv = RDMA_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC);
+
+ newNanoTime = JVM_NanoTime(env, 0);
+ nanoTimeout -= (newNanoTime - prevNanoTime);
+ if (nanoTimeout < NET_NSEC_PER_MSEC) {
+ return read_rv > 0 ? 0 : -1;
+ }
+ prevNanoTime = newNanoTime;
+
+ if (read_rv > 0) {
+ break;
+ }
+ }
+ return (nanoTimeout / NET_NSEC_PER_MSEC);
+}
+
+static int rdma_closefd(int fd2) {
+ int rv, orig_errno;
+ fdEntry_t *fdEntry = getFdEntry(fd2);
+ if (fdEntry == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ pthread_mutex_lock(&(fdEntry->lock));
+ do {
+ rv = rs_close(fd2);
+ } while (rv == -1 && errno == EINTR);
+
+ threadEntry_t *curr = fdEntry->threads;
+ while (curr != NULL) {
+ curr->intr = 1;
+ pthread_kill( curr->thr, sigWakeup );
+ curr = curr->next;
+ }
+ orig_errno = errno;
+ pthread_mutex_unlock(&(fdEntry->lock));
+ errno = orig_errno;
+ return rv;
+}
+
+int RDMA_SocketClose(int fd) {
+ return rdma_closefd(fd);
+}
+
+int RDMA_Read(int s, void* buf, size_t len) {
+ BLOCKING_IO_RETURN_INT(s, rs_recv(s, buf, len, 0));
+}
+
+int RDMA_NonBlockingRead(int s, void* buf, size_t len) {
+ BLOCKING_IO_RETURN_INT(s, rs_recv(s, buf, len, MSG_DONTWAIT));
+}
+
+int RDMA_ReadV(int s, const struct iovec * vector, int count) {
+ BLOCKING_IO_RETURN_INT(s, rs_readv(s, vector, count) );
+}
+
+int RDMA_RecvFrom(int s, void *buf, int len, unsigned int flags,
+ struct sockaddr *from, socklen_t *fromlen) {
+ BLOCKING_IO_RETURN_INT(s, rs_recvfrom(s, buf, len, flags, from, fromlen));
+}
+
+int RDMA_Send(int s, void *msg, int len, unsigned int flags) {
+ BLOCKING_IO_RETURN_INT(s, rs_send(s, msg, len, flags));
+}
+
+int RDMA_WriteV(int s, const struct iovec * vector, int count) {
+ BLOCKING_IO_RETURN_INT(s, rs_writev(s, vector, count));
+}
+
+int NET_RSendTo(int s, const void *msg, int len, unsigned int
+ flags, const struct sockaddr *to, int tolen) {
+ BLOCKING_IO_RETURN_INT(s, rs_sendto(s, msg, len, flags, to, tolen));
+}
+
+int RDMA_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
+ BLOCKING_IO_RETURN_INT(s, rs_accept(s, addr, addrlen));
+}
+
+int RDMA_Connect(int s, struct sockaddr *addr, int addrlen) {
+ BLOCKING_IO_RETURN_INT(s, rs_connect(s, addr, addrlen));
+}
+
+int RDMA_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
+ BLOCKING_IO_RETURN_INT(ufds[0].fd, rs_poll(ufds, nfds, timeout));
+}
+
+int RDMA_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) {
+ jlong prevNanoTime = nanoTimeStamp;
+ jlong nanoTimeout = (jlong)timeout * NET_NSEC_PER_MSEC;
+ fdEntry_t *fdEntry = getFdEntry(s);
+
+ if (fdEntry == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ for(;;) {
+ struct pollfd pfd;
+ int rv;
+ threadEntry_t self;
+
+ pfd.fd = s;
+ pfd.events = POLLIN | POLLERR;
+
+ startOp(fdEntry, &self);
+ rv = rs_poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC);
+ endOp(fdEntry, &self);
+ if (rv < 0 && errno == EINTR) {
+ jlong newNanoTime = JVM_NanoTime(env, 0);
+ nanoTimeout -= newNanoTime - prevNanoTime;
+ if (nanoTimeout < NET_NSEC_PER_MSEC) {
+ return 0;
+ }
+ prevNanoTime = newNanoTime;
+ } else {
+ return rv;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/linux/native/libextnet/rdma_util_md.h Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+#include <poll.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <net_util_md.h>
+
+/************************************************************************
+ * Functions
+ */
+int rdma_supported();
+int RDMA_MapSocketOption(jint cmd, int *level, int *optname);
+int RDMA_Bind(int fd, SOCKETADDRESS *sa, int len);
+int RDMA_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp);
+int RDMA_Read(int s, void* buf, size_t len);
+int RDMA_NonBlockingRead(int s, void* buf, size_t len);
+int RDMA_RecvFrom(int s, void *buf, int len, unsigned int flags,
+ struct sockaddr *from, socklen_t *fromlen);
+int RDMA_ReadV(int s, const struct iovec * vector, int count);
+int RDMA_Send(int s, void *msg, int len, unsigned int flags);
+int RDMA_SendTo(int s, const void *msg, int len, unsigned int
+ flags, const struct sockaddr *to, int tolen);
+int RDMA_Writev(int s, const struct iovec * vector, int count);
+int RDMA_Connect(int s, struct sockaddr *addr, int addrlen);
+int RDMA_Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+int RDMA_SocketClose(int s);
+int RDMA_Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
+int RDMA_SetSockOpt(int fd, int level, int opt, const void *arg, int len);
+int RDMA_GetSockOpt(int fd, int level, int opt, void *result, int *len);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/share/classes/jdk/internal/net/rdma/RdmaPollSelectorProvider.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.IOException;
+import java.net.ProtocolFamily;
+import java.nio.channels.DatagramChannel;
+import java.nio.channels.Pipe;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+import sun.nio.ch.SelectorProviderImpl;
+
+public class RdmaPollSelectorProvider
+ extends SelectorProvider
+{
+ public static SelectorProvider provider() {
+ throw new UnsupportedOperationException();
+ }
+
+ public AbstractSelector openSelector() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public SocketChannel openSocketChannel()
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public SocketChannel openSocketChannel(ProtocolFamily family)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public ServerSocketChannel openServerSocketChannel()
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public ServerSocketChannel openServerSocketChannel(ProtocolFamily family)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public DatagramChannel openDatagramChannel()
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public DatagramChannel openDatagramChannel(ProtocolFamily family)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Pipe openPipe() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/share/classes/jdk/internal/net/rdma/RdmaSocketProvider.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.internal.net.rdma;
+
+import java.io.IOException;
+import java.net.ProtocolFamily;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+public class RdmaSocketProvider {
+ public static Socket openSocket(ProtocolFamily family)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public static ServerSocket openServerSocket(ProtocolFamily family)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ private RdmaSocketProvider() {}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/share/classes/jdk/net/RdmaSocketOptions.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.net;
+
+import java.io.FileDescriptor;
+import java.net.SocketException;
+import java.net.SocketOption;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Set;
+import jdk.internal.access.JavaIOFileDescriptorAccess;
+import jdk.internal.access.SharedSecrets;
+import java.lang.annotation.Native;
+
+/**
+ * Defines socket options specific to RDMA-based TCP sockets and channels.
+ *
+ * @since 12
+ */
+public final class RdmaSocketOptions {
+
+ private static class RdmaSocketOption<T> implements SocketOption<T> {
+ private final String name;
+ private final Class<T> type;
+ RdmaSocketOption(String name, Class<T> type) {
+ this.name = name;
+ this.type = type;
+ }
+ @Override public String name() { return name; }
+ @Override public Class<T> type() { return type; }
+ @Override public String toString() { return name; }
+ }
+
+ private RdmaSocketOptions() { }
+
+ /**
+ * The integer size of the underlying RDMA send queue used by the
+ * platform for network I/O.
+ *
+ * The initial/default size of the RDMA send queue and the range of
+ * allowable values is system and device dependent although a negative
+ * size is not allowed.
+ *
+ * <p> An implementation allows this socket option to be set before the
+ * socket is bound or connected. Changing the value of this socket option
+ * after the socket is bound or connected has no effect.
+ *
+ * Valid for RDMA-based TCP sockets.
+ */
+ public static final SocketOption<Integer> RDMA_SQSIZE = new
+ RdmaSocketOption<Integer>("RDMA_SQSIZE", Integer.class);
+
+ /**
+ * The integer size of the underlying RDMA receive queue used by the
+ * platform for network I/O.
+ *
+ * The initial/default size of the RDMA receive queue and the range of
+ * allowable values is system and device dependent although a negative
+ * size is not allowed.
+ *
+ * <p> An implementation allows this socket option to be set before the
+ * socket is bound or connected. Changing the value of this socket option
+ * after the socket is bound or connected has no effect.
+ *
+ * Valid for RDMA-based TCP sockets.
+ */
+ public static final SocketOption<Integer> RDMA_RQSIZE = new
+ RdmaSocketOption<Integer>("RDMA_RQSIZE", Integer.class);
+
+ /**
+ * The integer size of the underlying RDMA inline data used by the
+ * platform for network I/O.
+ *
+ * The initial/default size of the RDMA inline data and the range of
+ * allowable values is system and device dependent although a negative
+ * size is not allowed.
+ *
+ * <p> An implementation allows this socket option to be set before the
+ * socket is bound or connected. Changing the value of this socket option
+ * after the socket is bound or connected has no effect.
+ *
+ * Valid for RDMA-based TCP sockets.
+ */
+ public static final SocketOption<Integer> RDMA_INLINE = new
+ RdmaSocketOption<Integer>("RDMA_INLINE", Integer.class);
+
+ @Native private static final int SQSIZE = 0x3001;
+
+ @Native private static final int RQSIZE = 0x3002;
+
+ @Native private static final int INLINE = 0x3003;
+
+ private static final PlatformRdmaSocketOptions platformRdmaSocketOptions =
+ PlatformRdmaSocketOptions.get();
+
+ private static final boolean rdmaSocketSupported =
+ platformRdmaSocketOptions.rdmaSocketSupported();
+
+ private static final Set<SocketOption<?>> rdmaOptions = options();
+
+ static Set<SocketOption<?>> options() {
+ if (rdmaSocketSupported)
+ return Set.of(RDMA_SQSIZE, RDMA_RQSIZE, RDMA_INLINE);
+ else
+ return Collections.<SocketOption<?>>emptySet();
+ }
+
+ static {
+ sun.net.ext.RdmaSocketOptions.register(
+ new sun.net.ext.RdmaSocketOptions(rdmaOptions) {
+
+ @Override
+ public void setOption(FileDescriptor fd,
+ SocketOption<?> option, Object value)
+ throws SocketException {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new NetworkPermission("setOption."
+ + option.name()));
+
+ if (fd == null || !fd.valid())
+ throw new SocketException("socket closed");
+
+ if ((option == RDMA_SQSIZE) || (option == RDMA_RQSIZE)
+ || (option == RDMA_INLINE)) {
+ assert rdmaSocketSupported;
+
+ int val;
+ int opt;
+ if (option == RDMA_SQSIZE) {
+ if (value == null || (!(value instanceof Integer)))
+ throw new SocketException(
+ "Bad parameter for RDMA_SQSIZE");
+ val = ((Integer) value).intValue();
+ opt = SQSIZE;
+ if (val < 0)
+ throw new IllegalArgumentException(
+ "send queue size < 0");
+ } else if (option == RDMA_RQSIZE) {
+ if (value == null || (!(value instanceof Integer)))
+ throw new SocketException(
+ "Bad parameter for RDMA_RQSIZE");
+ val = ((Integer) value).intValue();
+ opt = RQSIZE;
+ if (val < 0)
+ throw new IllegalArgumentException(
+ "receive queue size < 0");
+ } else if (option == RDMA_INLINE) {
+ if (value == null || (!(value instanceof Integer)))
+ throw new SocketException(
+ "Bad parameter for RDMA_INLINE");
+ val = ((Integer) value).intValue();
+ opt = INLINE;
+ if (val < 0)
+ throw new IllegalArgumentException(
+ "inline size < 0");
+ } else {
+ throw new SocketException(
+ "unrecognized RDMA socket option: " + option);
+ }
+
+ setSockOpt(fd, opt, val);
+
+ } else {
+ throw new InternalError("Unexpected option " + option);
+ }
+ }
+
+ @Override
+ public Object getOption(FileDescriptor fd,
+ SocketOption<?> option) throws SocketException {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new NetworkPermission("getOption."
+ + option.name()));
+
+ if (fd == null || !fd.valid())
+ throw new SocketException("socket closed");
+
+ if ((option == RDMA_SQSIZE) || (option == RDMA_RQSIZE)
+ || (option == RDMA_INLINE)) {
+ assert rdmaSocketSupported;
+ int opt;
+ if (option == RDMA_SQSIZE) {
+ opt = SQSIZE;
+ } else if (option == RDMA_RQSIZE) {
+ opt = RQSIZE;
+ } else {
+ opt = INLINE;
+ }
+ return getSockOpt(fd, opt);
+ } else {
+ throw new InternalError("Unexpected option " + option);
+ }
+ }
+ });
+ }
+
+ private static final JavaIOFileDescriptorAccess fdAccess =
+ SharedSecrets.getJavaIOFileDescriptorAccess();
+
+ private static void setSockOpt(FileDescriptor fd, int opt, int val)
+ throws SocketException {
+ platformRdmaSocketOptions.setSockOpt(fdAccess.get(fd), opt, val);
+ }
+
+ private static int getSockOpt(FileDescriptor fd, int opt)
+ throws SocketException {
+ return platformRdmaSocketOptions.getSockOpt(fdAccess.get(fd), opt);
+ }
+
+ static class PlatformRdmaSocketOptions {
+
+ protected PlatformRdmaSocketOptions() {}
+
+ @SuppressWarnings("unchecked")
+ private static PlatformRdmaSocketOptions newInstance(String cn) {
+ Class<PlatformRdmaSocketOptions> c;
+ try {
+ c = (Class<PlatformRdmaSocketOptions>)Class.forName(cn);
+ return c.getConstructor(new Class<?>[] { }).newInstance();
+ } catch (ReflectiveOperationException x) {
+ if (x.getCause() instanceof UnsupportedOperationException)
+ throw (UnsupportedOperationException)x.getCause();
+ throw new AssertionError(x);
+ }
+ }
+
+ private static PlatformRdmaSocketOptions create() {
+ String osname = AccessController.doPrivileged(
+ new PrivilegedAction<String>() {
+ public String run() {
+ return System.getProperty("os.name");
+ }
+ });
+ if ("Linux".equals(osname)) {
+ try {
+ return newInstance("jdk.net.LinuxRdmaSocketOptions");
+ } catch (UnsupportedOperationException uoe) {
+ return new PlatformRdmaSocketOptions();
+ }
+ }
+ return new PlatformRdmaSocketOptions();
+ }
+
+ private static final PlatformRdmaSocketOptions instance = create();
+
+ static PlatformRdmaSocketOptions get() {
+ return instance;
+ }
+
+ void setSockOpt(int fd, int opt, int value) throws SocketException {
+ throw new UnsupportedOperationException(
+ "unsupported socket option");
+ }
+
+ int getSockOpt(int fd, int opt) throws SocketException {
+ throw new UnsupportedOperationException(
+ "unsupported socket option");
+ }
+
+ boolean rdmaSocketSupported() {
+ return false;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.net/share/classes/jdk/net/RdmaSockets.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 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
+ * 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 jdk.net;
+
+import java.net.ProtocolFamily;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.io.IOException;
+import java.util.Objects;
+import jdk.internal.net.rdma.RdmaPollSelectorProvider;
+import jdk.internal.net.rdma.RdmaSocketProvider;
+
+/**
+ * Factory methods for creating RDMA-based TCP sockets and channels.
+ *
+ * <p>The {@link #openSocket(ProtocolFamily family) openSocket} and {@link
+ * #openServerSocket(ProtocolFamily family) openServerSocket} methods
+ * create RDMA-based TCP sockets.
+ *
+ * <p>The {@link #openSelector() openSelector}, {@link
+ * #openSocketChannel(ProtocolFamily family) openSocketChannel}, and {@link
+ * #openServerSocketChannel(ProtocolFamily family) openServerSocketChannel}
+ * methods create selectors and selectable channels for use with RDMA sockets.
+ * These objects are created by a {@link java.nio.channels.spi.SelectorProvider
+ * SelectorProvider} that is not the default {@code SelectorProvider}.
+ * Consequently, selectable channels to RDMA sockets may not be multiplexed
+ * with selectable channels created by the default selector provider. Its
+ * selector provider does not support datagram channels and pipes.
+ * The {@link java.nio.channels.spi.SelectorProvider#openDatagramChannel
+ * openDatagramChannel} and
+ * {@link java.nio.channels.spi.SelectorProvider#openPipe openPipe} methods
+ * throw {@link java.lang.UnsupportedOperationException
+ * UnsupportedOperationException}.
+ *
+ * @since 12
+ */
+public class RdmaSockets {
+
+ private RdmaSockets() {}
+
+ /**
+ * Creates an unbound and unconnected RDMA socket.
+ *
+ * <p> An RDMA socket supports the same socket options that {@link
+ * java.net.Socket java.net.Socket} defines. In addition, it supports the
+ * socket options specified by {@link RdmaSocketOptions}.
+ *
+ * <p> When binding the socket to a local address, or invoking {@code
+ * connect} to connect the socket, the socket address specified to those
+ * methods must correspond to the protocol family specified here.
+ *
+ * @param family
+ * The protocol family
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws NullPointerException
+ * If name is {@code null}
+ * @throws UnsupportedOperationException
+ * If RDMA sockets are not supported on this platform or if the
+ * specified protocol family is not supported. For example, if
+ * the parameter is {@link java.net.StandardProtocolFamily#INET6
+ * StandardProtocolFamily.INET6} but IPv6 is not enabled on the
+ * platform.
+ */
+ public static Socket openSocket(ProtocolFamily family) throws IOException {
+ Objects.requireNonNull("protocol family is null");
+ return RdmaSocketProvider.openSocket(family);
+ }
+
+ /**
+ * Creates an unbound RDMA server socket.
+ *
+ * <p> An RDMA socket supports the same socket options that {@link
+ * java.net.ServerSocket java.net.ServerSocket} defines.
+ *
+ * <p> When binding the socket to an address, the socket address specified
+ * to the {@code bind} method must correspond to the protocol family
+ * specified here.
+ *
+ * @param family
+ * The protocol family
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws NullPointerException
+ * If name is {@code null}
+ * @throws UnsupportedOperationException
+ * If RDMA sockets are not supported on this platform or if the
+ * specified protocol family is not supported. For example, if
+ * the parameter is {@link java.net.StandardProtocolFamily#INET6
+ * StandardProtocolFamily.INET6} but IPv6 is not enabled on the
+ * platform.
+ */
+ public static ServerSocket openServerSocket(ProtocolFamily family)
+ throws IOException {
+ Objects.requireNonNull("protocol family is null");
+ return RdmaSocketProvider.openServerSocket(family);
+ }
+
+ /**
+ * Opens a socket channel to an RDMA socket. A newly created socket channel
+ * is {@link SocketChannel#isOpen() open}, not yet bound to a {@link
+ * SocketChannel#getLocalAddress() local address}, and not yet
+ * {@link SocketChannel#isConnected() connected}.
+ *
+ * <p> A socket channel to an RDMA socket supports all of the socket options
+ * specified by {@code SocketChannel}. In addition, it supports the
+ * socket options specified by {@link RdmaSocketOptions}.
+ *
+ * <p> When binding the channel's socket to a local address, or invoking
+ * {@code connect} to connect channel's socket, the socket address specified
+ * to those methods must correspond to the protocol family specified here.
+ *
+ * @param family
+ * The protocol family
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws NullPointerException
+ * If name is {@code null}
+ * @throws UnsupportedOperationException
+ * If RDMA sockets are not supported on this platform or if the
+ * specified protocol family is not supported. For example, if
+ * the parameter is {@link java.net.StandardProtocolFamily#INET6
+ * StandardProtocolFamily.INET6} but IPv6 is not enabled on the
+ * platform.
+ */
+ public static SocketChannel openSocketChannel(ProtocolFamily family)
+ throws IOException {
+ Objects.requireNonNull("protocol family is null");
+ SelectorProvider provider = RdmaPollSelectorProvider.provider();
+ return ((RdmaPollSelectorProvider)provider).openSocketChannel(family);
+ }
+
+ /**
+ * Opens a server socket channel to an RDMA socket. A newly created socket
+ * channel is {@link SocketChannel#isOpen() open} but not yet bound to a
+ * {@link SocketChannel#getLocalAddress() local address}.
+ *
+ * <p> When binding the channel's socket to an address, the socket address
+ * specified to the {@code bind} method must correspond to the protocol
+ * family specified here.
+ *
+ * @param family
+ * The protocol family
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws NullPointerException
+ * If name is {@code null}
+ * @throws UnsupportedOperationException
+ * If RDMA sockets are not supported on this platform or if the
+ * specified protocol family is not supported. For example, if
+ * the parameter is {@link java.net.StandardProtocolFamily#INET6
+ * StandardProtocolFamily.INET6} but IPv6 is not enabled on the
+ * platform.
+ */
+ public static ServerSocketChannel openServerSocketChannel(
+ ProtocolFamily family) throws IOException {
+ Objects.requireNonNull("protocol family is null");
+ SelectorProvider provider = RdmaPollSelectorProvider.provider();
+ return ((RdmaPollSelectorProvider)provider)
+ .openServerSocketChannel(family);
+ }
+
+ /**
+ * Opens a selector to multiplex selectable channels to RDMA sockets.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws UnsupportedOperationException
+ * If RDMA sockets are not supported on this platform
+ */
+ public static Selector openSelector() throws IOException {
+ SelectorProvider provider = RdmaPollSelectorProvider.provider();
+ return provider.openSelector();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/Exceptions.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8195160
+ * @summary RdmaSockets API Exceptions
+ * @run testng Exceptions
+ */
+
+import java.net.ProtocolFamily;
+import org.testng.annotations.Test;
+import static jdk.net.RdmaSockets.*;
+import static org.testng.Assert.*;
+
+public class Exceptions {
+
+ static final Class<NullPointerException> NPE = NullPointerException.class;
+ static final Class<UnsupportedOperationException> UOE = UnsupportedOperationException.class;
+
+ @Test
+ public void testNull() {
+ assertThrows(NPE, () -> openSocket(null));
+ assertThrows(NPE, () -> openServerSocket(null));
+ assertThrows(NPE, () -> openSocketChannel(null));
+ assertThrows(NPE, () -> openServerSocketChannel(null));
+ }
+
+ static class UnsupportedFamily implements ProtocolFamily {
+ @Override public String name() { return null; }
+ }
+
+ @Test
+ public void testBadFamily() {
+ assertThrows(UOE, () -> openSocket(new UnsupportedFamily()));
+ assertThrows(UOE, () -> openServerSocket(new UnsupportedFamily()));
+ assertThrows(UOE, () -> openSocketChannel(new UnsupportedFamily()));
+ assertThrows(UOE, () -> openServerSocketChannel(new UnsupportedFamily()));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/NullBind.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8195160
+ * @summary Tests binding with null ( automatically assigned address )
+ * @requires (os.family == "linux")
+ * @library /test/lib
+ * @build RsocketTest
+ * @run testng/othervm NullBind
+ * @run testng/othervm -Djava.net.preferIPv6Addresses=true NullBind
+ */
+
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ProtocolFamily;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static java.lang.String.format;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+import static jdk.net.RdmaSockets.*;
+import static org.testng.Assert.assertTrue;
+
+public class NullBind {
+
+ @BeforeTest
+ public void setup() throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkipException("rsocket is not available");
+ }
+
+ @DataProvider(name = "families")
+ public Object[][] families() {
+ return new Object[][] {
+ { INET, Inet4Address.class },
+ { INET6, Inet6Address.class }
+ };
+ }
+
+ @Test(dataProvider = "families")
+ public void testSocket(ProtocolFamily family,
+ Class<? extends InetAddress> expectedClass)
+ throws IOException
+ {
+ try (Socket s = openSocket(family)) {
+ s.bind(null);
+ InetAddress addr = s.getLocalAddress();
+ //TODO: Argh! still a family issue in Socket.getLocalAddress
+ //assertTrue(expectedClass.isAssignableFrom(addr.getClass()),
+ // format("Excepted %s got: %s", expectedClass, addr));
+ assertTrue(addr.isAnyLocalAddress(),
+ format("Expected any local address, got: %s", addr));
+ }
+ }
+
+ @Test(dataProvider = "families")
+ public void testServerSocket(ProtocolFamily family,
+ Class<? extends InetAddress> expectedClass)
+ throws IOException
+ {
+ try (ServerSocket ss = openServerSocket(family)) {
+ ss.bind(null);
+ InetAddress addr = ss.getInetAddress();
+ assertTrue(expectedClass.isAssignableFrom(addr.getClass()),
+ format("Excepted %s got: %s", expectedClass, addr));
+ assertTrue(addr.isAnyLocalAddress(),
+ format("Expected any local address, got: %s", addr));
+ }
+ }
+
+ @Test(dataProvider = "families")
+ public void testSocketChannel(ProtocolFamily family,
+ Class<? extends InetAddress> expectedClass)
+ throws IOException
+ {
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.bind(null);
+ InetAddress addr = ((InetSocketAddress)sc.getLocalAddress()).getAddress();
+ assertTrue(expectedClass.isAssignableFrom(addr.getClass()),
+ format("Excepted %s got: %s", expectedClass, addr));
+ assertTrue(addr.isAnyLocalAddress(),
+ format("Expected any local address, got: %s", addr));
+ }
+ }
+
+ @Test(dataProvider = "families")
+ public void testServerSocketChannel(ProtocolFamily family,
+ Class<? extends InetAddress> expectedClass)
+ throws IOException
+ {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(null);
+ InetAddress addr = ((InetSocketAddress)ssc.getLocalAddress()).getAddress();
+ assertTrue(expectedClass.isAssignableFrom(addr.getClass()),
+ format("Excepted %s got: %s", expectedClass, addr));
+ assertTrue(addr.isAnyLocalAddress(),
+ format("Expected any local address, got: %s", addr));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/RsocketTest.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8195160
+ * @summary Test to check if rsocket is available
+ * @requires (os.family == "linux")
+ * @library /test/lib
+ * @build jdk.test.lib.Platform
+ * @run main/native RsocketTest
+ */
+
+import java.io.IOException;
+import java.net.SocketException;
+import java.net.StandardProtocolFamily;
+
+public class RsocketTest {
+ private static boolean libInstalled;
+ private static boolean supported;
+ private static boolean checked;
+
+ static {
+ System.loadLibrary("RsocketTest");
+ }
+
+ public static boolean isRsocketAvailable()
+ throws IOException {
+ if (!checked) {
+ checked = true;
+ supported = isRsocketAvailable0();
+ }
+ if (!supported) {
+ checkUnsupportedWithParameter();
+ checkUnsupportedNoParameter();
+ }
+ return supported;
+ }
+
+ static void checkUnsupportedWithParameter() throws IOException {
+ checkThrowsUOEWithParameter(jdk.net.RdmaSockets::openSocket);
+ checkThrowsUOEWithParameter(jdk.net.RdmaSockets::openServerSocket);
+ checkThrowsUOEWithParameter(jdk.net.RdmaSockets::openSocketChannel);
+ checkThrowsUOEWithParameter(
+ jdk.net.RdmaSockets::openServerSocketChannel);
+ }
+
+ static void checkUnsupportedNoParameter() throws IOException {
+ checkThrowsUOENoParameter(jdk.net.RdmaSockets::openSelector);
+ }
+
+ static void checkThrowsUOEWithParameter(
+ ThrowingRunnableWithParameter runnable) throws IOException {
+ try {
+ runnable.run(StandardProtocolFamily.INET);
+ runnable.run(StandardProtocolFamily.INET6);
+ if (!libInstalled)
+ throw new RuntimeException("Unexpected creation");
+ }
+ catch (UnsupportedOperationException | SocketException expected) { }
+ }
+
+ static void checkThrowsUOENoParameter(ThrowingRunnableNoParameter runnable)
+ throws IOException {
+ try {
+ runnable.run();
+ if (!libInstalled)
+ throw new RuntimeException("Unexpected creation");
+ }
+ catch (UnsupportedOperationException expected) { }
+ }
+
+ interface ThrowingRunnableWithParameter {
+ void run(StandardProtocolFamily family) throws IOException;
+ }
+
+ interface ThrowingRunnableNoParameter { void run() throws IOException; }
+
+ private static native boolean isRsocketAvailable0();
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("testing rsocket!");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/Selector/BasicAccept.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8195160
+ * @summary Test RdmaSelector with RdmaServerSocketChannels
+ * @requires (os.family == "linux")
+ * @library .. /test/lib /test/jdk/java/nio/channels
+ * @build RsocketTest
+ * @run main/othervm BasicAccept
+ */
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Iterator;
+import java.util.Set;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+public class BasicAccept {
+
+ static void server(ServerSocketChannel ssc) throws Exception {
+ Selector acceptSelector = RdmaSockets.openSelector();
+ try {
+ ssc.configureBlocking(false);
+ SelectionKey acceptKey
+ = ssc.register(acceptSelector, SelectionKey.OP_ACCEPT);
+ for (;;) {
+ int n = acceptSelector.select();
+ if (Thread.interrupted())
+ break;
+ if (n == 0)
+ continue;
+ Set<SelectionKey> readyKeys = acceptSelector.selectedKeys();
+ Iterator<SelectionKey> i = readyKeys.iterator();
+ while (i.hasNext()) {
+ SelectionKey sk = i.next();
+ i.remove();
+ ServerSocketChannel nextReady
+ = (ServerSocketChannel)sk.channel();
+ SocketChannel sc = nextReady.accept();
+ ByteBuffer bb = ByteBuffer.wrap(new byte[] { 42 });
+ sc.write(bb);
+ sc.close();
+ }
+ }
+ } finally {
+ acceptSelector.close();
+ }
+ }
+
+ private static class Server extends TestThread {
+ final ServerSocketChannel ssc;
+ Server() throws IOException {
+ super("Server", System.err);
+ this.ssc = RdmaSockets.openServerSocketChannel(
+ StandardProtocolFamily.INET)
+ .bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
+ }
+ int port() {
+ return ssc.socket().getLocalPort();
+ }
+ void go() throws Exception {
+ try {
+ server(ssc);
+ } finally {
+ ssc.close();
+ }
+ }
+ }
+
+ static void client(int port) throws Exception {
+ // Get a connection from the server
+ InetAddress lh = InetAddress.getLocalHost();
+ InetSocketAddress isa
+ = new InetSocketAddress(lh, port);
+ int connectFailures = 0;
+ boolean result = false;
+ SocketChannel sc = RdmaSockets.openSocketChannel(
+ StandardProtocolFamily.INET);
+ for (;;) {
+ try {
+ result = sc.connect(isa);
+ break;
+ } catch (java.net.ConnectException e) {
+ connectFailures++;
+ if (connectFailures > 30)
+ throw new RuntimeException("Cannot connect");
+ Thread.currentThread().sleep(100);
+ sc = RdmaSockets.openSocketChannel(StandardProtocolFamily.INET);
+ }
+ }
+ if (result) {
+ System.err.println("Connected");
+ } else {
+ // Only happens when server and client are on separate machines
+ System.err.println("Connection pending...");
+ connectFailures = 0;
+ while (!result) {
+ try {
+ result = sc.finishConnect();
+ if (!result)
+ System.err.println("Not finished");
+ Thread.sleep(50);
+ } catch (java.net.ConnectException e) {
+ Thread.sleep(100);
+ connectFailures++;
+ if (connectFailures > 30)
+ throw new RuntimeException("Cannot finish connecting");
+ }
+ }
+ System.err.println("Finished connecting");
+ }
+
+ ByteBuffer bb = ByteBuffer.allocateDirect(1024);
+ if (sc.read(bb) < 0)
+ throw new RuntimeException("Failed to read from server");
+ if (bb.get(0) != 42)
+ throw new RuntimeException("Read wrong byte from server");
+ System.err.println("Read from server");
+ sc.close();
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ Server server = new Server();
+ server.start();
+ try {
+ client(server.port());
+ } finally {
+ server.interrupt();
+ server.finish(2000);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/Selector/BasicConnect.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Test for nonblocking connect and finishConnect
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build jdk.test.lib.Utils TestServers
+ * @build RsocketTest
+ * @run main/othervm BasicConnect
+ */
+
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Iterator;
+import java.util.Set;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+/**
+ * Typically there would be more than one channel registered to select
+ * on, this test is just a very simple version with only one channel
+ * registered for the connectSelector.
+ */
+
+public class BasicConnect {
+
+ public static void main(String[] args) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ Selector connectSelector =
+ RdmaSockets.openSelector();
+ try {
+ TestServers.EchoServer echoServer
+ = TestServers.EchoServer.startNewServer(100);
+ InetSocketAddress isa
+ = new InetSocketAddress(echoServer.getAddress(),
+ echoServer.getPort());
+ SocketChannel sc = RdmaSockets.openSocketChannel(
+ StandardProtocolFamily.INET);
+ sc.configureBlocking(false);
+ boolean result = sc.connect(isa);
+ if (result) {
+ System.out.println("Socket immediately connected on "
+ + System.getProperty("os.name")
+ + ": " + sc);
+ }
+ while (!result) {
+ SelectionKey connectKey = sc.register(connectSelector,
+ SelectionKey.OP_CONNECT);
+ int keysAdded = connectSelector.select();
+ if (keysAdded > 0) {
+ Set readyKeys = connectSelector.selectedKeys();
+ Iterator i = readyKeys.iterator();
+ while (i.hasNext()) {
+ SelectionKey sk = (SelectionKey)i.next();
+ i.remove();
+ SocketChannel nextReady = (SocketChannel)sk.channel();
+ result = nextReady.finishConnect();
+ if (result)
+ sk.cancel();
+ }
+ }
+ }
+
+ byte[] bs = new byte[] { (byte)0xca, (byte)0xfe,
+ (byte)0xba, (byte)0xbe };
+ ByteBuffer bb = ByteBuffer.wrap(bs);
+ sc.configureBlocking(true);
+ sc.write(bb);
+ bb.rewind();
+
+ ByteBuffer bb2 = ByteBuffer.allocateDirect(100);
+ int n = sc.read(bb2);
+ bb2.flip();
+
+ sc.close();
+ connectSelector.close();
+
+ if (!bb.equals(bb2))
+ throw new Exception("Echoed bytes incorrect: Sent "
+ + bb + ", got " + bb2);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Test Failed!");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/Selector/Connect.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Test making lots of Selectors
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build jdk.test.lib.Utils TestServers
+ * @build RsocketTest
+ * @run main/othervm Connect
+ */
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
+import java.util.Set;
+import jdk.net.RdmaSockets;
+import jtreg.SkippedException;
+import static java.net.StandardProtocolFamily.INET;
+
+public class Connect {
+
+ static int success = 0;
+ static final int LIMIT = 30;
+
+ public static void main(String[] args) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ try (TestServers.DayTimeServer daytimeServer
+ = TestServers.DayTimeServer.startNewServer(50)) {
+ scaleTest(daytimeServer);
+ }
+ }
+
+ static void scaleTest(TestServers.DayTimeServer daytimeServer)
+ throws Exception
+ {
+ InetAddress myAddress = daytimeServer.getAddress();
+ InetSocketAddress isa = new InetSocketAddress(myAddress, daytimeServer.getPort());
+
+ for (int j=0; j<LIMIT; j++) {
+ SocketChannel sc = RdmaSockets.openSocketChannel(INET);
+ sc.configureBlocking(false);
+ boolean connected = sc.connect(isa);
+ System.out.println("connected = " + connected);
+
+ if (!connected) {
+ Selector selector = RdmaSockets.openSelector();
+ sc.register(selector, SelectionKey.OP_CONNECT);
+ while (!connected) {
+ int keysAdded = selector.select(100);
+ if (keysAdded > 0) {
+ Set<SelectionKey> readyKeys = selector.selectedKeys();
+ Iterator<SelectionKey> i = readyKeys.iterator();
+ while (i.hasNext()) {
+ SelectionKey sk = i.next();
+ SocketChannel nextReady = (SocketChannel)sk.channel();
+ connected = nextReady.finishConnect();
+ }
+ readyKeys.clear();
+ }
+ }
+ selector.close();
+ }
+ readAndClose(sc);
+ }
+ }
+
+ static void readAndClose(SocketChannel sc) throws Exception {
+ ByteBuffer bb = ByteBuffer.allocateDirect(100);
+ int n = 0;
+ while (n == 0) // Note this is not a rigorous check for done reading
+ n = sc.read(bb);
+ sc.close();
+ success++;
+ System.out.println("success count = " + success);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/Selector/SelectorTest.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Test RdmaSelector with RdmaServerSocketChannels
+ * @requires (os.family == "linux")
+ * @library .. /test/lib /test/jdk/java/nio/channels
+ * @build RsocketTest
+ * @run main/othervm BasicAccept
+ */
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.ByteBuffer;
+import java.nio.channels.Selector;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Iterator;
+import java.util.Set;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+public class SelectorTest {
+ private static List clientList = new LinkedList();
+ private static Random rnd = new Random();
+ public static int NUM_CLIENTS = 5;
+ public static int TEST_PORT = 31452;
+ static PrintStream log = System.err;
+ private static int FINISH_TIME = 30000;
+
+ /*
+ * Usage note
+ *
+ * java SelectorTest [server] [client <host>] [<port>]
+ *
+ * No arguments runs both client and server in separate threads
+ * using the default port of 31452.
+ *
+ * client runs the client on this machine and connects to server
+ * at the given IP address.
+ *
+ * server runs the server on localhost.
+ */
+ public static void main(String[] args) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ if (args.length == 0) {
+ Server server = new Server(0);
+ server.start();
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) { }
+ InetSocketAddress isa
+ = new InetSocketAddress(InetAddress.getLocalHost(), server.port());
+ Client client = new Client(isa);
+ client.start();
+ if ((server.finish(FINISH_TIME) & client.finish(FINISH_TIME)) == 0)
+ throw new Exception("Failure");
+ log.println();
+
+ } else if (args[0].equals("server")) {
+
+ if (args.length > 1)
+ TEST_PORT = Integer.parseInt(args[1]);
+ Server server = new Server(TEST_PORT);
+ server.start();
+ if (server.finish(FINISH_TIME) == 0)
+ throw new Exception("Failure");
+ log.println();
+
+ } else if (args[0].equals("client")) {
+
+ if (args.length < 2) {
+ log.println("No host specified: terminating.");
+ return;
+ }
+ String ip = args[1];
+ if (args.length > 2)
+ TEST_PORT = Integer.parseInt(args[2]);
+ InetAddress ia = InetAddress.getByName(ip);
+ InetSocketAddress isa = new InetSocketAddress(ia, TEST_PORT);
+ Client client = new Client(isa);
+ client.start();
+ if (client.finish(FINISH_TIME) == 0)
+ throw new Exception("Failure");
+ log.println();
+
+ } else {
+ System.out.println("Usage note:");
+ System.out.println("java SelectorTest [server] [client <host>] [<port>]");
+ System.out.println("No arguments runs both client and server in separate threads using the default port of 31452.");
+ System.out.println("client runs the client on this machine and connects to the server specified.");
+ System.out.println("server runs the server on localhost.");
+ }
+ }
+
+ static class Client extends TestThread {
+ InetSocketAddress isa;
+ Client(InetSocketAddress isa) {
+ super("Client", SelectorTest.log);
+ this.isa = isa;
+ }
+
+ public void go() throws Exception {
+ log.println("starting client...");
+ for (int i=0; i<NUM_CLIENTS; i++)
+ clientList.add(new RemoteEntity(i, isa, log));
+
+ Collections.shuffle(clientList);
+
+ log.println("created "+NUM_CLIENTS+" clients");
+ do {
+ for (Iterator i = clientList.iterator(); i.hasNext(); ) {
+ RemoteEntity re = (RemoteEntity) i.next();
+ if (re.cycle()) {
+ i.remove();
+ }
+ }
+ Collections.shuffle(clientList);
+ } while (clientList.size() > 0);
+ }
+ }
+
+ static class Server extends TestThread {
+ private final ServerSocketChannel ssc;
+ private List socketList = new ArrayList();
+ private ServerSocket ss;
+ private int connectionsAccepted = 0;
+ private Selector pollSelector;
+ private Selector acceptSelector;
+ private Set pkeys;
+ private Set pskeys;
+
+ Server(int port) throws IOException {
+ super("Server", SelectorTest.log);
+ this.ssc = RdmaSockets.openServerSocketChannel(
+ StandardProtocolFamily.INET);
+ ssc.bind(new InetSocketAddress(InetAddress.getLocalHost(), port));
+ }
+
+ int port() {
+ return ssc.socket().getLocalPort();
+ }
+
+ public void go() throws Exception {
+ log.println("starting server...");
+ acceptSelector = RdmaSockets.openSelector();
+ pollSelector = RdmaSockets.openSelector();
+ pkeys = pollSelector.keys();
+ pskeys = pollSelector.selectedKeys();
+ Set readyKeys = acceptSelector.selectedKeys();
+ RequestHandler rh = new RequestHandler(pollSelector, log);
+ Thread requestThread = new Thread(rh);
+
+ requestThread.start();
+
+ ssc.configureBlocking(false);
+ SelectionKey acceptKey = ssc.register(acceptSelector,
+ SelectionKey.OP_ACCEPT);
+ while(connectionsAccepted < SelectorTest.NUM_CLIENTS) {
+ int keysAdded = acceptSelector.select(100);
+ if (keysAdded > 0) {
+ Iterator i = readyKeys.iterator();
+ while(i.hasNext()) {
+ SelectionKey sk = (SelectionKey)i.next();
+ i.remove();
+ ServerSocketChannel nextReady =
+ (ServerSocketChannel)sk.channel();
+ SocketChannel sc = nextReady.accept();
+ connectionsAccepted++;
+ if (sc != null) {
+ sc.configureBlocking(false);
+ synchronized (pkeys) {
+ sc.register(pollSelector, SelectionKey.OP_READ);
+ }
+ } else {
+ throw new RuntimeException(
+ "Socket does not support Channels");
+ }
+ }
+ }
+ }
+ acceptKey.cancel();
+ requestThread.join();
+ acceptSelector.close();
+ pollSelector.close();
+ }
+ }
+}
+
+class RemoteEntity {
+ private static Random rnd = new Random();
+ int id;
+ ByteBuffer data;
+ int dataWrittenIndex;
+ int totalDataLength;
+ boolean initiated = false;
+ boolean connected = false;
+ boolean written = false;
+ boolean acked = false;
+ boolean closed = false;
+ private SocketChannel sc;
+ ByteBuffer ackBuffer;
+ PrintStream log;
+ InetSocketAddress server;
+
+ RemoteEntity(int id, InetSocketAddress server, PrintStream log)
+ throws Exception
+ {
+ int connectFailures = 0;
+ this.id = id;
+ this.log = log;
+ this.server = server;
+
+ sc = RdmaSockets.openSocketChannel(StandardProtocolFamily.INET);
+ sc.configureBlocking(false);
+
+ // Prepare the data buffer to write out from this entity
+ // Let's use both slow and fast buffers
+ if (rnd.nextBoolean())
+ data = ByteBuffer.allocateDirect(100);
+ else
+ data = ByteBuffer.allocate(100);
+ String number = Integer.toString(id);
+ if (number.length() == 1)
+ number = "0"+number;
+ String source = "Testing from " + number;
+ data.put(source.getBytes("8859_1"));
+ data.flip();
+ totalDataLength = source.length();
+
+ // Allocate an ack buffer
+ ackBuffer = ByteBuffer.allocateDirect(10);
+ }
+
+ private void reset() throws Exception {
+ sc.close();
+ sc = RdmaSockets.openSocketChannel(StandardProtocolFamily.INET);
+ sc.configureBlocking(false);
+ }
+
+ private void connect() throws Exception {
+ try {
+ connected = sc.connect(server);
+ initiated = true;
+ } catch (ConnectException e) {
+ initiated = false;
+ reset();
+ }
+ }
+
+ private void finishConnect() throws Exception {
+ try {
+ connected = sc.finishConnect();
+ } catch (IOException e) {
+ initiated = false;
+ reset();
+ }
+ }
+
+ int id() {
+ return id;
+ }
+
+ boolean cycle() throws Exception {
+ if (!initiated)
+ connect();
+ else if (!connected)
+ finishConnect();
+ else if (!written)
+ writeCycle();
+ else if (!acked)
+ ackCycle();
+ else if (!closed)
+ close();
+ return closed;
+ }
+
+ private void ackCycle() throws Exception {
+ //log.println("acking from "+id);
+ int bytesRead = sc.read(ackBuffer);
+ if (bytesRead > 0) {
+ acked = true;
+ }
+ }
+
+ private void close() throws Exception {
+ sc.close();
+ closed = true;
+ }
+
+ private void writeCycle() throws Exception {
+ log.println("writing from "+id);
+ int numBytesToWrite = rnd.nextInt(10)+1;
+ int newWriteTarget = dataWrittenIndex + numBytesToWrite;
+ if (newWriteTarget > totalDataLength)
+ newWriteTarget = totalDataLength;
+ data.limit(newWriteTarget);
+ int bytesWritten = sc.write(data);
+ if (bytesWritten > 0)
+ dataWrittenIndex += bytesWritten;
+ if (dataWrittenIndex == totalDataLength) {
+ written = true;
+ sc.socket().shutdownOutput();
+ }
+ }
+
+}
+
+
+class RequestHandler implements Runnable {
+ private static Random rnd = new Random();
+ private Selector selector;
+ private int connectionsHandled = 0;
+ private HashMap dataBin = new HashMap();
+ PrintStream log;
+
+ public RequestHandler(Selector selector, PrintStream log) {
+ this.selector = selector;
+ this.log = log;
+ }
+
+ public void run() {
+ log.println("starting request handler...");
+ int connectionsAccepted = 0;
+
+ Set nKeys = selector.keys();
+ Set readyKeys = selector.selectedKeys();
+
+ try {
+ while(connectionsHandled < SelectorTest.NUM_CLIENTS) {
+ int numKeys = selector.select(100);
+
+ // Process channels with data
+ synchronized (nKeys) {
+ if (readyKeys.size() > 0) {
+ Iterator i = readyKeys.iterator();
+ while(i.hasNext()) {
+ SelectionKey sk = (SelectionKey)i.next();
+ i.remove();
+ SocketChannel sc = (SocketChannel)sk.channel();
+ if (sc.isOpen())
+ read(sk, sc);
+ }
+ }
+ }
+
+ // Give other threads a chance to run
+ if (numKeys == 0) {
+ try {
+ Thread.sleep(1);
+ } catch (Exception x) {}
+ }
+ }
+ } catch (Exception e) {
+ log.println("Unexpected error 1: "+e);
+ e.printStackTrace();
+ }
+ }
+
+ private void read(SelectionKey sk, SocketChannel sc) throws Exception {
+ ByteBuffer bin = (ByteBuffer)dataBin.get(sc);
+ if (bin == null) {
+ if (rnd.nextBoolean())
+ bin = ByteBuffer.allocateDirect(100);
+ else
+ bin = ByteBuffer.allocate(100);
+ dataBin.put(sc, bin);
+ }
+
+ int bytesRead = 0;
+ do {
+ bytesRead = sc.read(bin);
+ } while(bytesRead > 0);
+
+ if (bytesRead == -1) {
+ sk.interestOps(0);
+ bin.flip();
+ int size = bin.limit();
+ byte[] data = new byte[size];
+ for(int j=0; j<size; j++)
+ data[j] = bin.get();
+ String message = new String(data, "8859_1");
+ connectionsHandled++;
+ acknowledge(sc);
+ log.println("Received >>>"+message + "<<<");
+ log.println("Handled: "+connectionsHandled);
+ }
+ }
+
+ private void acknowledge(SocketChannel sc) throws Exception {
+ ByteBuffer ackBuffer = ByteBuffer.allocateDirect(10);
+ String s = "ack";
+ ackBuffer.put(s.getBytes("8859_1"));
+ ackBuffer.flip();
+ int bytesWritten = 0;
+ while(bytesWritten == 0) {
+ bytesWritten += sc.write(ackBuffer);
+ }
+ sc.close();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/ServerSocketChannel/Basic.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Unit test for server-socket channels
+ * @requires (os.family == "linux")
+ * @library .. /test/lib /test/jdk/java/nio/channels
+ * @build RsocketTest
+ * @run main/othervm Basic
+ */
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.ByteBuffer;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Random;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+public class Basic {
+
+ static PrintStream log = System.err;
+
+ static class Server
+ extends TestThread
+ {
+ ServerSocketChannel ssc;
+ boolean block;
+
+ Server(ServerSocketChannel ssc, boolean block) {
+ super("Server", Basic.log);
+ this.ssc = ssc;
+ this.block = block;
+ }
+
+ void go() throws Exception {
+ log.println("Server: Listening "
+ + (block ? "(blocking)" : "(non-blocking)"));
+ if (!block)
+ ssc.configureBlocking(false);
+ log.println(" " + ssc);
+ SocketChannel sc = null;
+ for (;;) {
+ sc = ssc.accept();
+ if (sc != null) {
+ break;
+ }
+ log.println("Server: Sleeping...");
+ Thread.sleep(50);
+ }
+ log.println("Server: Accepted " + sc);
+ ByteBuffer bb = ByteBuffer.allocateDirect(100);
+ if (sc.read(bb) != 1)
+ throw new Exception("Read failed");
+ bb.flip();
+ byte b = bb.get();
+ log.println("Server: Read " + b + ", writing " + (b + 1));
+ bb.clear();
+ bb.put((byte)43);
+ bb.flip();
+ if (sc.write(bb) != 1)
+ throw new Exception("Write failed");
+ sc.close();
+ ssc.close();
+ log.println("Server: Finished");
+ }
+
+ }
+
+ static class Client
+ extends TestThread
+ {
+ int port;
+ boolean dally;
+
+ Client(int port, boolean block) {
+ super("Client", Basic.log);
+ this.port = port;
+ this.dally = !block;
+ }
+
+ public void go() throws Exception {
+ if (dally)
+ Thread.sleep(200);
+ InetSocketAddress isa
+ = new InetSocketAddress(InetAddress.getLocalHost(), port);
+ log.println("Client: Connecting to " + isa);
+ SocketChannel sc = RdmaSockets.openSocketChannel(
+ StandardProtocolFamily.INET);
+ sc.connect(isa);
+ log.println("Client: Connected");
+ ByteBuffer bb = ByteBuffer.allocateDirect(512);
+ bb.put((byte)42).flip();
+ log.println("Client: Writing " + bb.get(0));
+ if (sc.write(bb) != 1)
+ throw new Exception("Write failed");
+ bb.clear();
+ if (sc.read(bb) != 1)
+ throw new Exception("Read failed");
+ bb.flip();
+ if (bb.get() != 43)
+ throw new Exception("Read " + bb.get(bb.position() - 1));
+ log.println("Client: Read " + bb.get(0));
+ sc.close();
+ log.println("Client: Finished");
+ }
+
+ }
+
+ static void test(boolean block) throws Exception {
+ ServerSocketChannel ssc = RdmaSockets.openServerSocketChannel(
+ StandardProtocolFamily.INET);
+ ssc.socket().setReuseAddress(true);
+ InetAddress lh = InetAddress.getLocalHost();
+ int port;
+ Random r = new Random();
+ for (;;) {
+ port = r.nextInt((1 << 16) - 1024) + 1024;
+ InetSocketAddress isa = new InetSocketAddress(lh, port);
+ try {
+ ssc.socket().bind(isa);
+ } catch (IOException x) {
+ continue;
+ }
+ break;
+ }
+
+ Server server = new Server(ssc, block);
+ Client client = new Client(port, block);
+ server.start();
+ client.start();
+ if ((server.finish(0) & client.finish(0)) == 0)
+ throw new Exception("Failure");
+ log.println();
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ log.println();
+ test(true);
+ test(false);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/ServerSocketChannel/SSCConfigureBlocking.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8195160
+ * @summary Tests blocking configuration of server socket channels
+ * @requires (os.family == "linux")
+ * @library ../ /test/lib
+ * @build RsocketTest
+ * @run testng/othervm SSCConfigureBlocking
+ */
+
+import java.io.IOException;
+import java.net.ProtocolFamily;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+import static java.nio.channels.SelectionKey.OP_ACCEPT;
+import static jdk.net.RdmaSockets.*;
+import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.assertTrue;
+
+public class SSCConfigureBlocking {
+
+ @BeforeTest
+ public void setup() throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkipException("rsocket is not available");
+ }
+
+ @DataProvider(name = "families")
+ public Object[][] families() {
+ return new Object[][] { { INET }, { INET6 } };
+ }
+
+ // Newly-created selectable channels are always in blocking mode.
+
+ @Test(dataProvider = "families")
+ public void testServerSocketChannel(ProtocolFamily family)
+ throws IOException
+ {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ assertTrue(ssc.isBlocking(), "Newly created channel is not blocking");
+ ssc.configureBlocking(false);
+ assertTrue(!ssc.isBlocking(), "Expected non-blocking");
+ ssc.configureBlocking(true);
+ assertTrue(ssc.isBlocking(), "Expected blocking");
+ }
+ }
+
+ static final Class<IllegalBlockingModeException> IBME = IllegalBlockingModeException.class;
+
+ @Test(dataProvider = "families")
+ public void testServerSocketChannelRegister(ProtocolFamily family)
+ throws IOException
+ {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family);
+ Selector selector = Selector.open()) {
+ assertThrows(IBME, () -> ssc.register(selector, OP_ACCEPT));
+ assertThrows(IBME, () -> ssc.register(selector, OP_ACCEPT, new Object()));
+ ssc.configureBlocking(false);
+ ssc.register(selector, OP_ACCEPT);
+ assertThrows(IBME, () -> ssc.configureBlocking(true));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/ServerSocketChannel/SocketOptionTests.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Unit test for ServerSocketChannel setOption/getOption/options
+ * methods.
+ * @modules jdk.net
+ * @requires !vm.graal.enabled
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build RsocketTest
+ * @run main/othervm SocketOptionTests
+ */
+
+import java.io.IOException;
+import java.net.StandardProtocolFamily;
+import java.net.SocketOption;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ServerSocketChannel;
+import java.util.Set;
+import jdk.net.RdmaSockets;
+import static java.net.StandardSocketOptions.*;
+import static jdk.net.RdmaSocketOptions.*;
+
+import jtreg.SkippedException;
+
+public class SocketOptionTests {
+
+ static void checkOption(ServerSocketChannel ssc, SocketOption name, Object expectedValue)
+ throws IOException
+ {
+ Object value = ssc.getOption(name);
+ if (!value.equals(expectedValue))
+ throw new RuntimeException("value not as expected");
+ }
+
+ public static void main(String[] args) throws IOException {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ ServerSocketChannel ssc = RdmaSockets.openServerSocketChannel(
+ StandardProtocolFamily.INET);
+
+ // check supported options
+ Set<SocketOption<?>> options = ssc.supportedOptions();
+ if (!options.contains(SO_REUSEADDR))
+ throw new RuntimeException("SO_REUSEADDR should be supported");
+ if (!options.contains(SO_RCVBUF))
+ throw new RuntimeException("SO_RCVBUF should be supported");
+ if (!options.contains(RDMA_SQSIZE))
+ throw new RuntimeException("RDMA_SQSIZE should be supported");
+ if (!options.contains(RDMA_RQSIZE))
+ throw new RuntimeException("RDMA_RQSIZE should be supported");
+ if (!options.contains(RDMA_INLINE))
+ throw new RuntimeException("RDMA_INLINE should be supported");
+
+ // allowed to change when not bound
+ ssc.setOption(SO_RCVBUF, 256*1024); // can't check
+ int before = ssc.getOption(SO_RCVBUF);
+ int after = ssc.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
+ ssc.setOption(SO_REUSEADDR, true);
+ checkOption(ssc, SO_REUSEADDR, true);
+ ssc.setOption(SO_REUSEADDR, false);
+ checkOption(ssc, SO_REUSEADDR, false);
+
+ // NullPointerException
+ try {
+ ssc.setOption(null, "value");
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+ try {
+ ssc.getOption(null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+
+ // ClosedChannelException
+ ssc.close();
+ try {
+ ssc.setOption(SO_REUSEADDR, true);
+ throw new RuntimeException("ClosedChannelException not thrown");
+ } catch (ClosedChannelException x) {
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/Socket/BasicSocketTest.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8195160
+ * @summary Test for basic functionality for RdmaSocket and RdmaServerSocket
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build RsocketTest
+ * @run main/othervm BasicSocketTest
+ */
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+public class BasicSocketTest implements Runnable {
+ static ServerSocket ss;
+ static Socket s1, s2;
+ static InetAddress iaddr;
+ static int port = 0;
+ static ServerSocketChannel ssc;
+ static SocketChannel sc1, sc2;
+ static String message = "This is a message!";
+ static int length = -1;
+
+ public static void main(String args[]) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ iaddr = InetAddress.getLocalHost();
+
+ try {
+ ss = RdmaSockets.openServerSocket(StandardProtocolFamily.INET);
+ s1 = RdmaSockets.openSocket(StandardProtocolFamily.INET);
+ ss.bind(new InetSocketAddress(iaddr, port));
+
+ Thread t = new Thread(new BasicSocketTest());
+ t.start();
+ s2 = ss.accept();
+
+ InputStream is = s2.getInputStream();
+ length = message.length();
+
+ int num = 0;
+ byte[] buf = new byte[length];
+ while (num < length) {
+ int l = is.read(buf);
+ num += l;
+ }
+
+ String result = new String(buf);
+ if(!result.equals(message))
+ throw new RuntimeException("Test Failed!");
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Test Failed!");
+ } finally {
+ ss.close();
+ s1.close();
+ s2.close();
+ }
+ }
+
+ public void run() {
+ try {
+ s1.connect(new InetSocketAddress(iaddr, ss.getLocalPort()));
+
+ OutputStream os = s1.getOutputStream();
+ os.write(message.getBytes());
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Test Failed!");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/Socket/GetLocalAddress.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Test the java.net.socket.GetLocalAddress method
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build RsocketTest
+ * @run main/othervm GetLocalAddress
+ */
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.net.ServerSocket;
+import java.net.Socket;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+public class GetLocalAddress implements Runnable {
+ static Socket s;
+ static ServerSocket ss;
+ static InetAddress addr;
+ static int port;
+
+ public static void main(String args[]) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ testBindNull();
+
+ boolean error = true;
+ int value = 0;
+ addr = InetAddress.getLocalHost();
+
+ ss = RdmaSockets.openServerSocket(StandardProtocolFamily.INET);
+ s = RdmaSockets.openSocket(StandardProtocolFamily.INET);
+ addr = InetAddress.getLocalHost();
+ ss.bind(new InetSocketAddress(addr, 0));
+
+ port = ss.getLocalPort();
+
+ Thread t = new Thread(new GetLocalAddress());
+ t.start();
+
+ Socket soc = ss.accept();
+
+ if(addr.equals(soc.getLocalAddress())) {
+ error = false;
+ }
+ if (error)
+ throw new RuntimeException("Socket.GetLocalAddress failed.");
+ soc.close();
+ }
+
+ public void run() {
+ try {
+ s.connect(new InetSocketAddress(addr, port));
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Socket.GetLocalAddress failed.");
+ }
+ }
+
+ static void testBindNull() throws Exception {
+ try {
+ Socket soc = RdmaSockets.openSocket(StandardProtocolFamily.INET);
+ soc.bind(null);
+ if (!soc.isBound())
+ throw new RuntimeException(
+ "should be bound after bind(null)");
+ if (soc.getLocalPort() <= 0)
+ throw new RuntimeException(
+ "bind(null) failed, local port: " + soc.getLocalPort());
+ if (soc.getLocalAddress() == null)
+ throw new RuntimeException(
+ "bind(null) failed, local address is null");
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Socket.GetLocalAddress failed.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketChannel/BasicSocketChannelTest.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8195160
+ * @summary Test for basic functionality for RdmaSocketChannel
+ * and RdmaServerSocketChannel
+ * @requires (os.family == "linux")
+ * @library ../ /test/lib
+ * @build RsocketTest
+ * @run main/othervm BasicSocketChannelTest
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.net.*;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.ByteBuffer;
+import jdk.net.RdmaSockets;
+import jtreg.SkippedException;
+import static java.lang.String.format;
+import static java.lang.System.out;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+public class BasicSocketChannelTest {
+
+ static final String MESSAGE = "This is a MESSAGE!";
+ static final int MESSAGE_LENGTH = MESSAGE.length();
+
+ public static void main(String args[]) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ InetAddress iaddr = InetAddress.getLocalHost();
+ ProtocolFamily family = iaddr instanceof Inet6Address ? INET6 : INET;
+ out.printf("local address: %s%n", iaddr);
+
+ testChannel(iaddr, family);
+ testSocket(iaddr, family);
+ }
+
+ // Tests SocketChannel and ServerSocketChannel
+ static void testChannel(InetAddress iaddr, ProtocolFamily family) throws Exception {
+ out.printf("--- testChannel iaddr:%s, family:%s%n", iaddr, family);
+
+ try (ServerSocketChannel ssc = RdmaSockets.openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(iaddr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ Thread t = new Thread("Channel") {
+ public void run() {
+ try (SocketChannel sc1 = RdmaSockets.openSocketChannel(family)) {
+ sc1.connect(new InetSocketAddress(iaddr, port));
+ if (!sc1.isConnected())
+ throw new RuntimeException("Unconnected channel:" + sc1);
+ ByteBuffer input = ByteBuffer.allocate(MESSAGE_LENGTH);
+ input.put(MESSAGE.getBytes(UTF_8));
+ input.flip();
+ int inputNum = 0;
+ while (inputNum < MESSAGE_LENGTH) {
+ inputNum += sc1.write(input);
+ }
+ sc1.shutdownInput();
+ assertInputShutdown(sc1);
+ sc1.shutdownOutput();
+ assertOutputShutdown(sc1);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ };
+ t.start();
+
+ try (SocketChannel sc2 = ssc.accept()) {
+ ByteBuffer output = ByteBuffer.allocate(MESSAGE_LENGTH + 1);
+ while (sc2.read(output) != -1);
+ output.flip();
+
+ String result = UTF_8.decode(output).toString();
+ if (!result.equals(MESSAGE)) {
+ String msg = format("Expected [%s], received [%s]", MESSAGE, result);
+ throw new RuntimeException("Test Failed! " + msg);
+ }
+ sc2.shutdownInput();
+ assertInputShutdown(sc2);
+ sc2.shutdownOutput();
+ assertOutputShutdown(sc2);
+ }
+ t.join();
+ out.printf("passed%n");
+ }
+ }
+
+ // Tests SocketChannel.socket() and ServerSocketChannel.socket()
+ static void testSocket(InetAddress iaddr, ProtocolFamily family) throws Exception {
+ out.printf("--- testSocket iaddr:%s, family:%s%n", iaddr, family);
+
+ try (ServerSocketChannel ssc = RdmaSockets.openServerSocketChannel(family)) {
+ ssc.socket().bind(new InetSocketAddress(iaddr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ Thread t = new Thread("Socket") {
+ public void run() {
+ try (SocketChannel sc1 = RdmaSockets.openSocketChannel(family);
+ Socket client = sc1.socket()) {
+ client.connect(new InetSocketAddress(iaddr, port));
+ if (!client.isConnected())
+ throw new RuntimeException("Test Failed!");
+ InputStream is = client.getInputStream();
+ OutputStream os = client.getOutputStream();
+ os.write(MESSAGE.getBytes(UTF_8));
+
+ client.shutdownInput();
+ assertInputShutdown(sc1);
+ assertInputShutdown(client, is);
+ client.shutdownOutput();
+ assertOutputShutdown(sc1);
+ assertOutputShutdown(client, os);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ };
+ t.start();
+
+ try (Socket conn = ssc.socket().accept()) {
+ InputStream is = conn.getInputStream();
+ OutputStream os = conn.getOutputStream();
+ byte[] buf = is.readAllBytes();
+
+ String result = new String(buf, UTF_8);
+ if (!result.equals(MESSAGE)) {
+ String msg = format("Expected [%s], received [%s]", MESSAGE, result);
+ throw new RuntimeException("Test Failed! " + msg);
+ }
+ conn.shutdownInput();
+ assertInputShutdown(conn, is);
+ conn.shutdownOutput();
+ assertOutputShutdown(conn, os);
+ }
+ t.join();
+ out.printf("passed%n");
+ }
+ }
+
+ static void assertInputShutdown(SocketChannel sc) throws IOException {
+ ByteBuffer bb = ByteBuffer.allocate(1);
+ int r = sc.read(bb);
+ if (r != -1)
+ throw new RuntimeException(format("Unexpected read of %d bytes", r));
+
+ try {
+ sc.socket().getInputStream();
+ } catch (IOException expected) {
+ String msg = expected.getMessage();
+ if (!msg.contains("input"))
+ throw new RuntimeException("Expected to find \"input\" in " + expected);
+ if (!msg.contains("shutdown"))
+ throw new RuntimeException("Expected to find \"shutdown\" in " + expected);
+ }
+ }
+
+ static void assertOutputShutdown(SocketChannel sc) throws IOException {
+ ByteBuffer bb = ByteBuffer.allocate(1);
+ bb.put((byte)0x05);
+ bb.flip();
+ try {
+ sc.write(bb);
+ throw new RuntimeException("Unexpected write of bytes");
+ } catch (ClosedChannelException expected) { }
+
+ try {
+ sc.socket().getOutputStream();
+ } catch (IOException expected) {
+ String msg = expected.getMessage();
+ if (!msg.contains("output"))
+ throw new RuntimeException("Expected to find \"output\" in " + expected);
+ if (!msg.contains("shutdown"))
+ throw new RuntimeException("Expected to find \"shutdown\" in " + expected);
+ }
+ }
+
+ static void assertInputShutdown(Socket s, InputStream is) throws IOException {
+ if (!s.isInputShutdown()) {
+ throw new RuntimeException("Unexpected open input: " + s);
+ }
+ int r;
+ if ((r = is.read()) != -1)
+ throw new RuntimeException(format("Unexpected read of %d", r));
+
+ try {
+ s.getInputStream();
+ } catch (IOException expected) {
+ String msg = expected.getMessage();
+ if (!msg.contains("input"))
+ throw new RuntimeException("Expected to find \"input\" in " + expected);
+ if (!msg.contains("shutdown"))
+ throw new RuntimeException("Expected to find \"shutdown\" in " + expected);
+ }
+ }
+
+ static void assertOutputShutdown(Socket s, OutputStream os) throws IOException {
+ if (!s.isOutputShutdown()) {
+ throw new RuntimeException("Unexpected open output: " + s);
+ }
+ try {
+ os.write((byte)0x07);
+ throw new RuntimeException("Unexpected write of bytes");
+ } catch (ClosedChannelException expected) { }
+
+ try {
+ s.getOutputStream();
+ } catch (IOException expected) {
+ String msg = expected.getMessage();
+ if (!msg.contains("output"))
+ throw new RuntimeException("Expected to find \"output\" in " + expected);
+ if (!msg.contains("shutdown"))
+ throw new RuntimeException("Expected to find \"shutdown\" in " + expected);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketChannel/CloseDuringWrite.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Test asynchronous close during a blocking write
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build RsocketTest
+ * @run main/othervm CloseDuringWrite
+ * @key randomness
+ */
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ProtocolFamily;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.Random;
+import jdk.net.RdmaSockets;
+import jtreg.SkippedException;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+
+public class CloseDuringWrite {
+
+ static final Random rand = new Random();
+
+ /**
+ * A task that closes a Closeable
+ */
+ static class Closer implements Callable<Void> {
+ final Closeable c;
+ Closer(Closeable c) {
+ this.c = c;
+ }
+ public Void call() throws IOException {
+ c.close();
+ return null;
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ InetAddress lh = InetAddress.getLocalHost();
+ ProtocolFamily family = lh instanceof Inet6Address ? INET6 : INET;
+ System.out.printf("local address: %s%n", lh);
+
+ ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();
+ try (ServerSocketChannel ssc = RdmaSockets.openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(lh, 0));
+ int port = ssc.socket().getLocalPort();
+ SocketAddress sa = new InetSocketAddress(lh, port);
+
+ ByteBuffer bb = ByteBuffer.allocate(2 * 1024 * 1024);
+
+ for (int i = 0; i < 20; i++) {
+ System.out.println(i);
+ try (SocketChannel source = RdmaSockets.openSocketChannel(family)) {
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ System.out.println("connecting ...");
+ source.connect(sa);
+ System.out.println("connected");
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Test Failed");
+ }
+ }
+ };
+
+ Thread t = new Thread(runnable);
+ t.start();
+ try (SocketChannel sink = ssc.accept()) {
+ System.out.println("accepted new connection");
+ // schedule channel to be closed
+ Closer c = new Closer(source);
+ int when = 1000 + rand.nextInt(2000);
+ Future<Void> result = pool.schedule(c, when, TimeUnit.MILLISECONDS);
+
+ // the write should either succeed or else throw a
+ // ClosedChannelException (more likely an
+ // AsynchronousCloseException)
+ try {
+ for (;;) {
+ int limit = rand.nextInt(bb.capacity());
+ bb.position(0);
+ bb.limit(limit);
+ int n = source.write(bb);
+ System.out.format("wrote %d, expected %d%n", n, limit);
+ }
+ } catch (ClosedChannelException expected) {
+ System.out.println(expected + " (expected)");
+ } finally {
+ result.get();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Test Failed");
+ }
+ }
+ } finally {
+ pool.shutdown();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketChannel/Connect.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Unit test for socket channels
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build jdk.test.lib.Utils TestServers
+ * @build RsocketTest
+ * @run main/othervm Connect
+ */
+
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.ByteBuffer;
+import java.nio.channels.Selector;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.util.Set;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+public class Connect {
+
+ private static final long INCREMENTAL_DELAY = 30L * 1000L;
+
+ public static void main(String args[]) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ try (TestServers.EchoServer echoServer
+ = TestServers.EchoServer.startNewServer(1000)) {
+ test1(echoServer);
+ }
+ try {
+ test1(TestServers.RefusingServer.newRefusingServer());
+ throw new Exception("Refused connection throws no exception");
+ } catch (ConnectException ce) {
+ // Correct result
+ }
+ }
+
+ static void test1(TestServers.AbstractServer server) throws Exception {
+ Selector selector;
+ SocketChannel sc;
+ SelectionKey sk;
+ InetSocketAddress isa = new InetSocketAddress(
+ server.getAddress(), server.getPort());
+ sc = RdmaSockets.openSocketChannel(StandardProtocolFamily.INET);
+ sc.configureBlocking(false);
+
+ selector = RdmaSockets.openSelector();
+ sk = sc.register(selector, SelectionKey.OP_CONNECT);
+ if (sc.connect(isa)) {
+ System.err.println("Connected immediately!");
+ sc.close();
+ selector.close();
+ return;
+ } else {
+ ByteBuffer buf = ByteBuffer.allocateDirect(100);
+ buf.asCharBuffer().put(new String(
+ "The quick brown fox jumped over the lazy dog."
+ ).toCharArray());
+ buf.flip();
+ long startTime = System.currentTimeMillis();
+ while(true) {
+ selector.select(INCREMENTAL_DELAY);
+ Set selectedKeys = selector.selectedKeys();
+
+ if(selectedKeys.isEmpty()) {
+ System.err.println("Elapsed time without response: " +
+ (System.currentTimeMillis() -
+ startTime) / 1000L + " seconds.");
+ }
+ else if(!selectedKeys.contains(sk))
+ {
+ System.err.println("Got wrong event about selection key.");
+ } else {
+ System.err.println("Got event for our selection key.");
+ if(sk.isConnectable()) {
+ if(sc.finishConnect()) {
+ if(sc.isConnected()) {
+ System.err.println("Successful connect.");
+ sk.interestOps(SelectionKey.OP_WRITE);
+ sc.write(buf);
+ } else {
+ System.err.println(
+ "Finish connect completed incorrectly.");
+ }
+ } else {
+ System.err.println(
+ "key incorrectly indicated socket channel connectable.");
+ }
+ }
+ if(sk.isWritable() && (buf.remaining() > 0)) {
+ sc.write(buf);
+ }
+ if(buf.remaining() == 0) {
+ System.err.println(
+ "SUCCESS! buffer contents were sent.");
+ sc.close();
+ selector.close();
+ return;
+ }
+ }
+ selectedKeys.clear();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketChannel/FinishConnect.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Test RDMA SocketChannel.finishConnect
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build jdk.test.lib.Utils TestServers
+ * @build RsocketTest
+ * @run main/othervm FinishConnect
+ */
+
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.Selector;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.Set;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+public class FinishConnect {
+
+ public static void main(String[] args) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ try (TestServers.DayTimeServer dayTimeServer
+ = TestServers.DayTimeServer.startNewServer(100)) {
+ test1(dayTimeServer, true, true);
+ test1(dayTimeServer, true, false);
+ test1(dayTimeServer, false, true);
+ test1(dayTimeServer, false, false);
+ test2(dayTimeServer);
+ }
+ }
+
+ static void test1(TestServers.DayTimeServer daytimeServer,
+ boolean select,
+ boolean setBlocking)
+ throws Exception
+ {
+ InetSocketAddress isa
+ = new InetSocketAddress(daytimeServer.getAddress(),
+ daytimeServer.getPort());
+ SocketChannel sc = RdmaSockets.openSocketChannel(
+ StandardProtocolFamily.INET);
+ sc.configureBlocking(false);
+ boolean connected = sc.connect(isa);
+ int attempts = 0;
+
+ try {
+ sc.connect(isa);
+ throw new RuntimeException("Allowed another connect call");
+ } catch (IllegalStateException ise) {
+ // Correct behavior
+ }
+
+ if (setBlocking)
+ sc.configureBlocking(true);
+
+ if (!connected && select && !setBlocking) {
+ Selector selector = RdmaSockets.openSelector();
+ sc.register(selector, SelectionKey.OP_CONNECT);
+ while (!connected) {
+ int keysAdded = selector.select(100);
+ if (keysAdded > 0) {
+ Set readyKeys = selector.selectedKeys();
+ Iterator i = readyKeys.iterator();
+ while (i.hasNext()) {
+ SelectionKey sk = (SelectionKey)i.next();
+ SocketChannel nextReady =
+ (SocketChannel)sk.channel();
+ connected = sc.finishConnect();
+ }
+ }
+ }
+ selector.close();
+ }
+
+ while (!connected) {
+ if (attempts++ > 30)
+ throw new RuntimeException("Failed to connect");
+ Thread.sleep(100);
+ connected = sc.finishConnect();
+ }
+
+ ByteBuffer bb = ByteBuffer.allocateDirect(100);
+ int bytesRead = 0;
+ int totalRead = 0;
+ while (totalRead < 20) {
+ bytesRead = sc.read(bb);
+ if (bytesRead > 0)
+ totalRead += bytesRead;
+ if (bytesRead < 0)
+ throw new RuntimeException("Message shorter than expected");
+ }
+ bb.position(bb.position() - 2); // Drop CRLF
+ bb.flip();
+ CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb);
+ System.err.println(isa + " says: \"" + cb + "\"");
+ sc.close();
+ }
+
+ static void test2(TestServers.DayTimeServer daytimeServer) throws Exception {
+ InetSocketAddress isa
+ = new InetSocketAddress(daytimeServer.getAddress(),
+ daytimeServer.getPort());
+ boolean done = false;
+ int globalAttempts = 0;
+ int connectSuccess = 0;
+ while (!done) {
+ // When using a local daytime server it is not always possible
+ // to get a pending connection, as sc.connect(isa) may always
+ // return true.
+ // So we're going to throw the exception only if there was
+ // at least 1 case where we did not manage to connect.
+ if (globalAttempts++ > 50) {
+ if (globalAttempts == connectSuccess + 1) {
+ System.out.println("Can't fully test on "
+ + System.getProperty("os.name"));
+ break;
+ }
+ throw new RuntimeException("Failed to connect");
+ }
+ SocketChannel sc = RdmaSockets.openSocketChannel(
+ StandardProtocolFamily.INET);
+ sc.configureBlocking(false);
+ boolean connected = sc.connect(isa);
+ int localAttempts = 0;
+ while (!connected) {
+ if (localAttempts++ > 500)
+ throw new RuntimeException("Failed to connect");
+ connected = sc.finishConnect();
+ if (connected) {
+ done = true;
+ break;
+ }
+ Thread.sleep(10);
+ }
+ if (connected) {
+ connectSuccess++;
+ }
+ sc.close();
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketChannel/IOExchanges.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,1199 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8195160
+ * @summary Tests various combinations of blocking/nonblocking connections
+ * @requires (os.family == "linux")
+ * @library ../ /test/lib
+ * @build RsocketTest
+ * @run testng/othervm IOExchanges
+ * @author chegar
+ */
+
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ProtocolFamily;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.ByteBuffer;
+import jdk.net.RdmaSockets;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static java.lang.System.out;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+import static java.nio.channels.SelectionKey.OP_ACCEPT;
+import static java.nio.channels.SelectionKey.OP_READ;
+import static java.nio.channels.SelectionKey.OP_WRITE;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class IOExchanges {
+
+ // Whether, or not, to use RDMA channels or regular socket channels.
+ // For test assertion purposes during development.
+ static final boolean useRDMA = true;
+
+ static InetAddress addr;
+ static ProtocolFamily family;
+
+ @BeforeTest
+ public void setup() throws Exception {
+ if (useRDMA && !RsocketTest.isRsocketAvailable())
+ throw new SkipException("rsocket is not available");
+
+ addr = InetAddress.getLocalHost();
+ family = addr instanceof Inet6Address ? INET6 : INET;
+ out.printf("local address: %s%n", addr);
+ out.printf("useRDMA: %b%n", useRDMA);
+ }
+
+ static SocketChannel openSocketChannel(ProtocolFamily family)
+ throws IOException
+ {
+ return useRDMA ? RdmaSockets.openSocketChannel(family)
+ : SocketChannel.open();
+ }
+ static ServerSocketChannel openServerSocketChannel(ProtocolFamily family)
+ throws IOException
+ {
+ return useRDMA ? RdmaSockets.openServerSocketChannel(family)
+ : ServerSocketChannel.open();
+ }
+ static Selector openSelector( ) throws IOException {
+ return useRDMA ? RdmaSockets.openSelector() : Selector.open();
+ }
+
+ /*
+ The following, non-exhaustive set, of tests exercise different combinations
+ of blocking and non-blocking accept/connect calls along with I/O
+ operations, that exchange a single byte. The intent it to test a reasonable
+ set of blocking and non-blocking scenarios.
+
+ The individual test method names follow their test scenario.
+ [BAccep|SELNBAccep|SPINNBAccep] - Accept either:
+ blocking, select-non-blocking, spinning-non-blocking
+ [BConn|NBConn] - blocking connect / non-blocking connect
+ [BIO|NBIO] - blocking / non-blocking I/O operations (read/write)
+ [WR|RW] - connecting thread write/accepting thread reads first, and vice-versa
+ [Id] - unique test Id
+
+ BAccep_BConn_BIO_WR_1
+ BAccep_BConn_BIO_RW_2
+ SELNBAccep_BConn_BIO_WR_3
+ SELNBAccep_BConn_BIO_RW_4
+ SPINNBAccep_BConn_BIO_WR_5
+ SPINNBAccep_BConn_BIO_RW_6
+ BAccep_NBConn_BIO_WR_7
+ BAccep_NBConn_BIO_RW_8
+ SELNBAccep_NBConn_BIO_WR_9
+ SELNBAccep_NBConn_BIO_RW_10
+ SPINNBAccep_NBConn_BIO_WR_11
+ SPINNBAccep_NBConn_BIO_RW_12
+
+ BAccep_BConn_NBIO_WR_1a << Non-Blocking I/O
+ BAccep_BConn_NBIO_RW_2a
+ SELNBAccep_BConn_NBIO_WR_3a
+ SELNBAccep_BConn_NBIO_RW_4a
+ SPINNBAccep_BConn_NBIO_WR_5a
+ SPINNBAccep_BConn_NBIO_RW_6a
+ BAccep_NBConn_NBIO_WR_7a
+ BAccep_NBConn_NBIO_RW_8a
+ SELNBAccep_NBConn_NBIO_WR_9a
+ SELNBAccep_NBConn_NBIO_RW_10a
+ SPINBAccep_NBConn_NBIO_WR_11a
+ SPINBAccep_NBConn_NBIO_RW_12a
+ */
+
+
+ @Test
+ public void BAccep_BConn_BIO_WR_1() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t1", () -> {
+ try (SocketChannel sc = openSocketChannel(family)) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x01).flip();
+ assertEquals(sc.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc.read(bb.clear()), -1);
+ }
+ });
+ t.start();
+
+ try (SocketChannel sc = ssc.accept()) {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x01);
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void BAccep_BConn_BIO_RW_2() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t2", () -> {
+ try (SocketChannel sc = openSocketChannel(family)) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x02);
+ }
+ });
+ t.start();
+
+ try (SocketChannel sc = ssc.accept()) {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x02).flip();
+ assertEquals(sc.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc.read(bb.clear()), -1);
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void SELNBAccep_BConn_BIO_WR_3() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family);
+ Selector selector = openSelector()) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t3", () -> {
+ try (SocketChannel sc = openSocketChannel(family)) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x03).flip();
+ assertEquals(sc.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc.read(bb.clear()), -1);
+ }
+ });
+ t.start();
+
+ ssc.configureBlocking(false).register(selector, OP_ACCEPT);
+ assertEquals(selector.select(), 1);
+
+ try (SocketChannel sc = ssc.accept()) {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x03);
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void SELNBAccep_BConn_BIO_RW_4() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family);
+ Selector selector = openSelector()) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t4", () -> {
+ try (SocketChannel sc = openSocketChannel(family)) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x04);
+ }
+ });
+ t.start();
+
+ ssc.configureBlocking(false).register(selector, OP_ACCEPT);
+ assertEquals(selector.select(), 1);
+
+ try (SocketChannel sc = ssc.accept()) {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x04).flip();
+ assertEquals(sc.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc.read(bb.clear()), -1);
+
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void SPINNBAccep_BConn_BIO_WR_5() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t5", () -> {
+ try (SocketChannel sc = openSocketChannel(family)) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x05).flip();
+ assertEquals(sc.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc.read(bb.clear()), -1);
+ }
+ });
+ t.start();
+
+ SocketChannel accepted;
+ for (;;) {
+ accepted = ssc.accept();
+ if (accepted != null) {
+ out.println("accepted new connection");
+ break;
+ }
+ Thread.onSpinWait();
+ }
+
+ try (SocketChannel sc = accepted) {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x05);
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void SPINNBAccep_BConn_BIO_RW_6() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t6", () -> {
+ try (SocketChannel sc = openSocketChannel(family)) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x06);
+ }
+ });
+ t.start();
+
+ SocketChannel accepted;
+ for (;;) {
+ accepted = ssc.accept();
+ if (accepted != null) {
+ out.println("accepted new connection");
+ break;
+ }
+ Thread.onSpinWait();
+ }
+
+ try (SocketChannel sc = accepted) {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x06).flip();
+ assertEquals(sc.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc.read(bb.clear()), -1);
+
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ // Similar to the previous six scenarios, but with same-thread
+ // non-blocking connect.
+/*
+ @Test
+ public void BAccep_NBConn_BIO_WR_7() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ try (SocketChannel sc2 = ssc.accept()) {
+ assertTrue(sc.finishConnect());
+ sc.configureBlocking(true);
+ TestThread t = TestThread.of("t7", () -> {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x07).flip();
+ assertEquals(sc.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc.read(bb.clear()), -1);
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc2.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x07);
+ sc2.shutdownOutput();
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void BAccep_NBConn_BIO_RW_8() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ try (SocketChannel sc2 = ssc.accept()) {
+ assertTrue(sc.finishConnect());
+ sc.configureBlocking(true);
+ TestThread t = TestThread.of("t8", () -> {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x08);
+ sc.shutdownOutput();
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x08).flip();
+ assertEquals(sc2.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc2.read(bb.clear()), -1);
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void SELNBAccep_NBConn_BIO_WR_9() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family);
+ Selector selector = openSelector()) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ ssc.configureBlocking(false).register(selector, OP_ACCEPT);
+ assertEquals(selector.select(), 1);
+
+ try (SocketChannel sc2 = ssc.accept()) {
+ assertTrue(sc.finishConnect());
+ sc.configureBlocking(true);
+ TestThread t = TestThread.of("t9", () -> {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x09).flip();
+ assertEquals(sc.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc.read(bb.clear()), -1);
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc2.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x09);
+ sc2.shutdownOutput();
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void SELNBAccep_NBConn_BIO_RW_10() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family);
+ Selector selector = openSelector()) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ ssc.configureBlocking(false).register(selector, OP_ACCEPT);
+ assertEquals(selector.select(), 1);
+
+ try (SocketChannel sc2 = ssc.accept()) {
+ assertTrue(sc.finishConnect());
+ sc.configureBlocking(true);
+ TestThread t = TestThread.of("t10", () -> {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x10);
+ sc.shutdownOutput();
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x10).flip();
+ assertEquals(sc2.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc2.read(bb.clear()), -1);
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void SPINNBAccep_NBConn_BIO_WR_11() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ SocketChannel accepted;
+ for (;;) {
+ accepted = ssc.accept();
+ if (accepted != null) {
+ out.println("accepted new connection");
+ break;
+ }
+ Thread.onSpinWait();
+ }
+
+ try (SocketChannel sc2 = accepted) {
+ assertTrue(sc.finishConnect());
+ sc.configureBlocking(true);
+ TestThread t = TestThread.of("t11", () -> {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x11).flip();
+ assertEquals(sc.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc.read(bb.clear()), -1);
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc2.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x11);
+ sc2.shutdownOutput();
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void SPINNBAccep_NBConn_BIO_RW_12() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ SocketChannel accepted;
+ for (;;) {
+ accepted = ssc.accept();
+ if (accepted != null) {
+ out.println("accepted new connection");
+ break;
+ }
+ Thread.onSpinWait();
+ }
+
+ try (SocketChannel sc2 = accepted) {
+ assertTrue(sc.finishConnect());
+ sc.configureBlocking(true);
+ TestThread t = TestThread.of("t12", () -> {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ assertEquals(sc.read(bb), 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x12);
+ sc.shutdownOutput();
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x12).flip();
+ assertEquals(sc2.write(bb), 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ assertEquals(sc2.read(bb.clear()), -1);
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+*/
+ // ---
+ // Similar to the previous twelve scenarios but with non-blocking IO
+ // ---
+
+ @Test
+ public void BAccep_BConn_NBIO_WR_1a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t1a", () -> {
+ try (SocketChannel sc = openSocketChannel(family);
+ Selector selector = openSelector()) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x1A).flip();
+ sc.configureBlocking(false);
+ SelectionKey k = sc.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc.write(bb)) < 1);
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, -1);
+ }
+ });
+ t.start();
+
+ try (SocketChannel sc = ssc.accept();
+ Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc.configureBlocking(false);
+ sc.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc.read(bb)) == 0) ;
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x1A);
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void BAccep_BConn_NBIO_RW_2a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t2a", () -> {
+ try (SocketChannel sc = openSocketChannel(family);
+ Selector selector = openSelector()) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc.configureBlocking(false);
+ sc.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x2A);
+ }
+ });
+ t.start();
+
+ try (SocketChannel sc = ssc.accept();
+ Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x2A).flip();
+ sc.configureBlocking(false);
+ SelectionKey k = sc.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc.write(bb)) < 1);
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, -1);
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void SELNBAccep_BConn_NBIO_WR_3a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family);
+ Selector aselector = openSelector()) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t3a", () -> {
+ try (SocketChannel sc = openSocketChannel(family);
+ Selector selector = openSelector()) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x3A).flip();
+ sc.configureBlocking(false);
+ SelectionKey k = sc.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc.write(bb)) < 1);
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, -1);
+ }
+ });
+ t.start();
+
+ ssc.configureBlocking(false).register(aselector, OP_ACCEPT);
+ assertEquals(aselector.select(), 1);
+
+ try (SocketChannel sc = ssc.accept();
+ Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc.configureBlocking(false);
+ sc.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc.read(bb)) == 0) ;
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x3A);
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void SELNBAccep_BConn_NBIO_RW_4a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family);
+ Selector aselector = openSelector()) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t4a", () -> {
+ try (SocketChannel sc = openSocketChannel(family);
+ Selector selector = openSelector()) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc.configureBlocking(false);
+ sc.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x4A);
+ }
+ });
+ t.start();
+
+ ssc.configureBlocking(false).register(aselector, OP_ACCEPT);
+ assertEquals(aselector.select(), 1);
+
+ try (SocketChannel sc = ssc.accept();
+ Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x4A).flip();
+ sc.configureBlocking(false);
+ SelectionKey k = sc.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc.write(bb)) < 1);
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, -1);
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void SPINNBAccep_BConn_NBIO_WR_5a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t5a", () -> {
+ try (SocketChannel sc = openSocketChannel(family);
+ Selector selector = openSelector()) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x5A).flip();
+ sc.configureBlocking(false);
+ SelectionKey k = sc.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc.write(bb)) < 1);
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, -1);
+ }
+ });
+ t.start();
+
+ SocketChannel accepted;
+ for (;;) {
+ accepted = ssc.accept();
+ if (accepted != null) {
+ out.println("accepted new connection");
+ break;
+ }
+ Thread.onSpinWait();
+ }
+
+ try (SocketChannel sc = accepted;
+ Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc.configureBlocking(false);
+ sc.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc.read(bb)) == 0) ;
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x5A);
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ @Test
+ public void SPINNBAccep_BConn_NBIO_RW_6a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ TestThread t = TestThread.of("t6a", () -> {
+ try (SocketChannel sc = openSocketChannel(family);
+ Selector selector = openSelector()) {
+ assertTrue(sc.connect(new InetSocketAddress(addr, port)));
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc.configureBlocking(false);
+ sc.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x6A);
+ }
+ });
+ t.start();
+
+ SocketChannel accepted;
+ for (;;) {
+ accepted = ssc.accept();
+ if (accepted != null) {
+ out.println("accepted new connection");
+ break;
+ }
+ Thread.onSpinWait();
+ }
+
+ try (SocketChannel sc = accepted;
+ Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x6A).flip();
+ sc.configureBlocking(false);
+ SelectionKey k = sc.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc.write(bb)) < 1);
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, -1);
+
+ }
+ t.awaitCompletion();
+ }
+ }
+
+ // Similar to the previous six scenarios but with same-thread
+ // non-blocking connect.
+/*
+ @Test
+ public void BAccep_NBConn_NBIO_WR_7a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ try (SocketChannel sc2 = ssc.accept()) {
+ assertTrue(sc.finishConnect());
+ TestThread t = TestThread.of("t7a", () -> {
+ try (Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x7A).flip();
+ sc.configureBlocking(false);
+ SelectionKey k = sc.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc.write(bb)) < 1) ;
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc.read(bb)) == 0) ;
+ assertEquals(c, -1);
+ }
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc2.configureBlocking(false);
+ try (Selector selector = openSelector()) {
+ sc2.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc2.read(bb)) == 0) ;
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), 0x7A);
+ sc2.shutdownOutput();
+ }
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void BAccep_NBConn_NBIO_RW_8a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ try (SocketChannel sc2 = ssc.accept()) {
+ assertTrue(sc.finishConnect());
+ TestThread t = TestThread.of("t8a", () -> {
+ try (Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), (byte)0x8A);
+ sc.shutdownOutput();
+ }
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x8A).flip();
+ sc2.configureBlocking(false);
+ try (Selector selector = openSelector()) {
+ SelectionKey k = sc2.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc2.write(bb)) < 1) ;
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc2.read(bb)) == 0) ;
+ assertEquals(c, -1);
+ }
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void SELNBAccep_NBConn_NBIO_WR_9a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ Selector aselector = openSelector();
+ ssc.configureBlocking(false).register(aselector, OP_ACCEPT);
+ assertEquals(aselector.select(), 1);
+
+ try (SocketChannel sc2 = ssc.accept()) {
+ assertTrue(sc.finishConnect());
+ TestThread t = TestThread.of("t9a", () -> {
+ try (Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0x9A).flip();
+ sc.configureBlocking(false);
+ SelectionKey k = sc.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc.write(bb)) < 1) ;
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc.read(bb)) == 0) ;
+ assertEquals(c, -1);
+ }
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc2.configureBlocking(false);
+ try (Selector selector = openSelector()) {
+ sc2.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc2.read(bb)) == 0) ;
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), (byte)0x9A);
+ sc2.shutdownOutput();
+ }
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void SELNBAccep_NBConn_NBIO_RW_10a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ Selector aselector = openSelector();
+ ssc.configureBlocking(false).register(aselector, OP_ACCEPT);
+ assertEquals(aselector.select(), 1);
+
+ try (SocketChannel sc2 = ssc.accept()) {
+ assertTrue(sc.finishConnect());
+ TestThread t = TestThread.of("t10a", () -> {
+ try (Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), (byte)0xAA);
+ sc.shutdownOutput();
+ }
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0xAA).flip();
+ sc2.configureBlocking(false);
+ try (Selector selector = openSelector()) {
+ SelectionKey k = sc2.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc2.write(bb)) < 1) ;
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc2.read(bb)) == 0) ;
+ assertEquals(c, -1);
+ }
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void SPINBAccep_NBConn_NBIO_WR_11a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ SocketChannel accepted;
+ for (;;) {
+ accepted = ssc.accept();
+ if (accepted != null) {
+ out.println("accepted new connection");
+ break;
+ }
+ Thread.onSpinWait();
+ }
+
+ try (SocketChannel sc2 = accepted) {
+ assertTrue(sc.finishConnect());
+ TestThread t = TestThread.of("t11a", () -> {
+ try (Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0xBA).flip();
+ sc.configureBlocking(false);
+ SelectionKey k = sc.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc.write(bb)) < 1) ;
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc.read(bb)) == 0) ;
+ assertEquals(c, -1);
+ }
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc2.configureBlocking(false);
+ try (Selector selector = openSelector()) {
+ sc2.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc2.read(bb)) == 0) ;
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), (byte)0xBA);
+ sc2.shutdownOutput();
+ }
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void SPINBAccep_NBConn_NBIO_RW_12a() throws Throwable {
+ try (ServerSocketChannel ssc = openServerSocketChannel(family)) {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ final int port = ssc.socket().getLocalPort();
+
+ try (SocketChannel sc = openSocketChannel(family)) {
+ sc.configureBlocking(false);
+ sc.connect(new InetSocketAddress(addr, port));
+
+ SocketChannel accepted;
+ for (;;) {
+ accepted = ssc.accept();
+ if (accepted != null) {
+ out.println("accepted new connection");
+ break;
+ }
+ Thread.onSpinWait();
+ }
+
+ try (SocketChannel sc2 = accepted) {
+ assertTrue(sc.finishConnect());
+ TestThread t = TestThread.of("t10a", () -> {
+ try (Selector selector = openSelector()) {
+ ByteBuffer bb = ByteBuffer.allocate(10);
+ sc.register(selector, OP_READ);
+ selector.select();
+ int c;
+ while ((c = sc.read(bb)) == 0);
+ assertEquals(c, 1);
+ out.printf("read: 0x%x%n", bb.get(0));
+ assertEquals(bb.get(0), (byte)0xCA);
+ sc.shutdownOutput();
+ }
+ });
+ t.start();
+
+ ByteBuffer bb = ByteBuffer.allocate(10).put((byte)0xCA).flip();
+ sc2.configureBlocking(false);
+ try (Selector selector = openSelector()) {
+ SelectionKey k = sc2.register(selector, OP_WRITE);
+ selector.select();
+ int c;
+ while ((c = sc2.write(bb)) < 1) ;
+ assertEquals(c, 1);
+ out.printf("wrote: 0x%x%n", bb.get(0));
+ k.interestOps(OP_READ);
+ selector.select();
+ bb.clear();
+ while ((c = sc2.read(bb)) == 0) ;
+ assertEquals(c, -1);
+ }
+ t.awaitCompletion();
+ }
+ }
+ }
+ }
+*/
+ // --
+
+ static class TestThread extends Thread {
+ private final UncheckedRunnable runnable;
+ private volatile Throwable throwable;
+
+ TestThread(UncheckedRunnable runnable, String name) {
+ super(name);
+ this.runnable = runnable;
+ }
+
+ @Override
+ public void run() {
+ try {
+ runnable.run();
+ } catch (Throwable t) {
+ out.printf("[%s] caught unexpected: %s%n", getName(), t);
+ throwable = t;
+ }
+ }
+
+ interface UncheckedRunnable {
+ void run() throws Throwable;
+ }
+
+ static TestThread of(String name, UncheckedRunnable runnable) {
+ return new TestThread(runnable, name);
+ }
+
+ void awaitCompletion() throws Throwable {
+ this.join();
+ if (throwable != null)
+ throw throwable;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketChannel/SCConfigureBlocking.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8195160
+ * @summary Tests blocking configuration of socket channels
+ * @requires (os.family == "linux")
+ * @library ../ /test/lib
+ * @build RsocketTest
+ * @run testng/othervm SCConfigureBlocking
+ */
+
+import java.io.IOException;
+import java.net.ProtocolFamily;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static java.net.StandardProtocolFamily.INET;
+import static java.net.StandardProtocolFamily.INET6;
+import static java.nio.channels.SelectionKey.OP_READ;
+import static java.nio.channels.SelectionKey.OP_WRITE;
+import static jdk.net.RdmaSockets.*;
+import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.assertTrue;
+
+public class SCConfigureBlocking {
+
+ @BeforeTest
+ public void setup() throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkipException("rsocket is not available");
+ }
+
+ @DataProvider(name = "families")
+ public Object[][] families() {
+ return new Object[][] { { INET }, { INET6 } };
+ }
+
+ // Newly-created selectable channels are always in blocking mode.
+
+ @Test(dataProvider = "families")
+ public void testSocketChannel(ProtocolFamily family)
+ throws IOException
+ {
+ try (SocketChannel sc = openSocketChannel(family)) {
+ assertTrue(sc.isBlocking(), "Newly created channel is not blocking");
+ sc.configureBlocking(false);
+ assertTrue(!sc.isBlocking(), "Expected non-blocking");
+ sc.configureBlocking(true);
+ assertTrue(sc.isBlocking(), "Expected blocking");
+ }
+ }
+
+ static final Class<IllegalBlockingModeException> IBME = IllegalBlockingModeException.class;
+
+ @Test(dataProvider = "families")
+ public void testSocketChannelRegister(ProtocolFamily family)
+ throws IOException
+ {
+ try (SocketChannel sc = openSocketChannel(family);
+ Selector selector = Selector.open()) {
+ assertThrows(IBME, () -> sc.register(selector, OP_READ));
+ assertThrows(IBME, () -> sc.register(selector, OP_READ, new Object()));
+ sc.configureBlocking(false);
+ sc.register(selector, OP_READ | OP_WRITE);
+ assertThrows(IBME, () -> sc.configureBlocking(true));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketChannel/SocketOptionTests.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Unit test to check SocketChannel setOption/getOption/options
+ * methods.
+ * @requires !vm.graal.enabled
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build RsocketTest
+ * @run main/othervm SocketOptionTests
+ */
+
+import java.nio.channels.*;
+import java.net.*;
+import java.io.IOException;
+import java.util.*;
+import jdk.net.RdmaSockets;
+import static java.net.StandardSocketOptions.*;
+import static jdk.net.RdmaSocketOptions.*;
+
+import jtreg.SkippedException;
+
+public class SocketOptionTests {
+
+ static void checkOption(SocketChannel sc, SocketOption name, Object expectedValue)
+ throws IOException
+ {
+ Object value = sc.getOption(name);
+ if (!value.equals(expectedValue))
+ throw new RuntimeException("value not as expected");
+ }
+
+ public static void main(String[] args) throws IOException {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ SocketChannel sc = RdmaSockets.openSocketChannel(StandardProtocolFamily.INET);
+
+ // check supported options
+ Set<SocketOption<?>> options = sc.supportedOptions();
+
+ List<? extends SocketOption> rdmaOptions = List.of(RDMA_SQSIZE,
+ RDMA_RQSIZE, RDMA_INLINE);
+ List<? extends SocketOption> expected;
+ expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR,
+ TCP_NODELAY, RDMA_SQSIZE, RDMA_RQSIZE, RDMA_INLINE);
+ for (SocketOption opt: expected) {
+ if (!options.contains(opt))
+ throw new RuntimeException(opt.name() + " should be supported");
+ }
+
+ // check specified defaults
+ checkOption(sc, TCP_NODELAY, false);
+
+ // allowed to change when not bound
+ sc.setOption(SO_SNDBUF, 128*1024); // can't check
+ sc.setOption(SO_RCVBUF, 256*1024); // can't check
+ int before, after;
+ before = sc.getOption(SO_SNDBUF);
+ after = sc.setOption(SO_SNDBUF, Integer.MAX_VALUE).getOption(SO_SNDBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_SNDBUF to decrease");
+ before = sc.getOption(SO_RCVBUF);
+ after = sc.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
+ sc.setOption(SO_REUSEADDR, true);
+ checkOption(sc, SO_REUSEADDR, true);
+ sc.setOption(SO_REUSEADDR, false);
+ checkOption(sc, SO_REUSEADDR, false);
+ sc.setOption(TCP_NODELAY, true);
+ checkOption(sc, TCP_NODELAY, true);
+ sc.setOption(TCP_NODELAY, false); // can't check
+
+ sc.setOption(RDMA_SQSIZE, 1024);
+ checkOption(sc, RDMA_SQSIZE, 1024);
+
+ sc.setOption(RDMA_RQSIZE, 1024);
+ checkOption(sc, RDMA_RQSIZE, 1024);
+
+ sc.setOption(RDMA_INLINE, 512);
+ checkOption(sc, RDMA_INLINE, 512);
+
+ // bind socket
+ sc.bind(new InetSocketAddress(0));
+
+ sc.setOption(TCP_NODELAY, true); // can't check
+ sc.setOption(TCP_NODELAY, false); // can't check
+ // NullPointerException
+ try {
+ sc.setOption(null, "value");
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+ try {
+ sc.getOption(null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+
+ // ClosedChannelException
+ sc.close();
+ try {
+ sc.setOption(TCP_NODELAY, true);
+ throw new RuntimeException("ClosedChannelException not thrown");
+ } catch (ClosedChannelException x) {
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketChannel/Stream.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Test result of read on stream from nonblocking channel
+ * @requires (os.family == "linux")
+ * @library .. /test/lib
+ * @build jdk.test.lib.Utils TestServers
+ * @build RsocketTest
+ * @run main/othervm Stream
+ */
+
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.SocketChannel;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+public class Stream {
+
+ static void test(TestServers.DayTimeServer daytimeServer) throws Exception {
+ InetSocketAddress isa
+ = new InetSocketAddress(daytimeServer.getAddress(),
+ daytimeServer.getPort());
+ SocketChannel sc = RdmaSockets.openSocketChannel(StandardProtocolFamily.INET);
+ sc.connect(isa);
+ sc.configureBlocking(false);
+ InputStream is = sc.socket().getInputStream();
+ byte b[] = new byte[10];
+ try {
+ int n = is.read(b);
+ throw new RuntimeException("Exception expected; none thrown");
+ } catch (IllegalBlockingModeException e) {
+ // expected result
+ }
+ sc.close();
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ try (TestServers.DayTimeServer dayTimeServer
+ = TestServers.DayTimeServer.startNewServer(100)) {
+ test(dayTimeServer);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketChannel/VectorIO.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Test socketchannel vector IO (use -Dseed=X to set PRNG seed)
+ * @requires (os.family == "linux")
+ * @library .. /test/lib /test/jdk/java/nio/channels
+ * @build jdk.test.lib.RandomFactory
+ * @build RsocketTest
+ * @run main/othervm VectorIO
+ * @key randomness
+ */
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.ByteBuffer;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Random;
+import jdk.test.lib.RandomFactory;
+import jdk.net.RdmaSockets;
+
+import jtreg.SkippedException;
+
+public class VectorIO {
+
+ private static Random generator = RandomFactory.getRandom();
+
+ static int testSize;
+
+ // whether to use the write/read variant with a length parameter
+ static boolean setLength;
+
+ public static void main(String[] args) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ testSize = 1;
+ setLength = false;
+ runTest();
+ for(int i = 15; i < 18; i++) {
+ testSize = i;
+ setLength = !setLength;
+ runTest();
+ }
+ }
+
+ static void runTest() throws Exception {
+ System.err.println("Length " + testSize);
+ Server sv = new Server(testSize);
+ sv.start();
+ bufferTest(sv.port());
+ if (sv.finish(8000) == 0)
+ throw new Exception("Failed: Length = " + testSize);
+ }
+
+ static void bufferTest(int port) throws Exception {
+ ByteBuffer[] bufs = new ByteBuffer[testSize];
+ long total = 0L;
+ for(int i = 0; i < testSize; i++) {
+ String source = "buffer" + i;
+ if (generator.nextBoolean())
+ bufs[i] = ByteBuffer.allocateDirect(source.length());
+ else
+ bufs[i] = ByteBuffer.allocate(source.length());
+
+ bufs[i].put(source.getBytes("8859_1"));
+ bufs[i].flip();
+ total += bufs[i].remaining();
+ }
+
+ ByteBuffer[] bufsPlus1 = new ByteBuffer[bufs.length + 1];
+ System.arraycopy(bufs, 0, bufsPlus1, 0, bufs.length);
+
+ // Get a connection to the server
+ InetAddress lh = InetAddress.getLocalHost();
+ InetSocketAddress isa = new InetSocketAddress(lh, port);
+ SocketChannel sc = RdmaSockets.openSocketChannel(StandardProtocolFamily.INET);
+ sc.connect(isa);
+ sc.configureBlocking(generator.nextBoolean());
+
+ // Write the data out
+ long rem = total;
+ while (rem > 0L) {
+ long bytesWritten;
+ if (setLength) {
+ bytesWritten = sc.write(bufsPlus1, 0, bufs.length);
+ } else {
+ bytesWritten = sc.write(bufs);
+ }
+ if (bytesWritten == 0) {
+ if (sc.isBlocking()) {
+ throw new RuntimeException("write did not block");
+ } else {
+ System.err.println("Non-blocking write() wrote zero bytes");
+ }
+ Thread.sleep(50);
+ } else {
+ rem -= bytesWritten;
+ }
+ }
+
+ // Clean up
+ sc.close();
+ }
+
+ static class Server
+ extends TestThread
+ {
+ final int testSize;
+ final ServerSocketChannel ssc;
+
+ Server(int testSize) throws IOException {
+ super("Server " + testSize);
+ this.testSize = testSize;
+ this.ssc = RdmaSockets.openServerSocketChannel(
+ StandardProtocolFamily.INET).bind(new InetSocketAddress(0));
+ }
+
+ int port() {
+ return ssc.socket().getLocalPort();
+ }
+
+ void go() throws Exception {
+ bufferTest();
+ }
+
+ void bufferTest() throws Exception {
+ long total = 0L;
+ ByteBuffer[] bufs = new ByteBuffer[testSize];
+ for(int i=0; i<testSize; i++) {
+ String source = "buffer" + i;
+ if (generator.nextBoolean())
+ bufs[i] = ByteBuffer.allocateDirect(source.length());
+ else
+ bufs[i] = ByteBuffer.allocate(source.length());
+ total += bufs[i].capacity();
+ }
+
+ ByteBuffer[] bufsPlus1 = new ByteBuffer[bufs.length + 1];
+ System.arraycopy(bufs, 0, bufsPlus1, 0, bufs.length);
+
+ // Get a connection from client
+ SocketChannel sc = null;
+
+ try {
+
+ ssc.configureBlocking(false);
+
+ for (;;) {
+ sc = ssc.accept();
+ if (sc != null) {
+ System.err.println("accept() succeeded");
+ break;
+ }
+ Thread.sleep(50);
+ }
+
+ sc.configureBlocking(generator.nextBoolean());
+
+ // Read data into multiple buffers
+ long avail = total;
+ while (avail > 0) {
+ long bytesRead;
+ if (setLength) {
+ bytesRead = sc.read(bufsPlus1, 0, bufs.length);
+ } else {
+ bytesRead = sc.read(bufs);
+ }
+ if (bytesRead < 0)
+ break;
+ if (bytesRead == 0) {
+ if (sc.isBlocking()) {
+ throw new RuntimeException("read did not block");
+ } else {
+ System.err.println
+ ("Non-blocking read() read zero bytes");
+ }
+ Thread.sleep(50);
+ }
+ avail -= bytesRead;
+ }
+
+ // Check results
+ for(int i=0; i<testSize; i++) {
+ String expected = "buffer" + i;
+ bufs[i].flip();
+ int size = bufs[i].capacity();
+ byte[] data = new byte[size];
+ for(int j=0; j<size; j++)
+ data[j] = bufs[i].get();
+ String message = new String(data, "8859_1");
+ if (!message.equals(expected))
+ throw new Exception("Wrong data: Got "
+ + message + ", expected "
+ + expected);
+ }
+
+ } finally {
+ // Clean up
+ ssc.close();
+ if (sc != null)
+ sc.close();
+ }
+
+ }
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketOption/OptionsTest.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/* @test
+ * @bug 8195160
+ * @summary Unit test for SocketOption
+ * @requires (os.family == "linux")
+ * @requires !vm.graal.enabled
+ * @library .. /test/lib
+ * @build RsocketTest
+ * @run main/othervm OptionsTest
+ */
+
+import java.net.StandardProtocolFamily;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
+import java.util.Formatter;
+import java.util.Set;
+import jdk.net.RdmaSockets;
+import jdk.net.RdmaSocketOptions;
+
+import jtreg.SkippedException;
+
+public class OptionsTest {
+
+ static class Test {
+ Test(SocketOption<?> option, Object testValue) {
+ this.option = option;
+ this.testValue = testValue;
+ }
+ static Test create (SocketOption<?> option, Object testValue) {
+ return new Test(option, testValue);
+ }
+ Object option;
+ Object testValue;
+ }
+
+ // The tests set the option using the new API, read back the set value
+ // which could be diferent, and then use the legacy get API to check
+ // these values are the same
+
+ static Test[] socketTests = new Test[] {
+ Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)),
+ Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
+ Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+ };
+
+ static Test[] serverSocketTests = new Test[] {
+ Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
+ Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+ };
+
+ static Test[] rdmaSocketOptionTests = new Test[] {
+ Test.create(RdmaSocketOptions.RDMA_SQSIZE, Integer.valueOf(8 * 100)),
+ Test.create(RdmaSocketOptions.RDMA_RQSIZE, Integer.valueOf(10 * 100)),
+ Test.create(RdmaSocketOptions.RDMA_INLINE, Integer.valueOf(20 * 100)),
+ };
+
+ static void doSocketTests() throws Exception {
+ try {
+ Socket c = RdmaSockets.openSocket(StandardProtocolFamily.INET);
+
+ for (int i = 0; i < socketTests.length; i++) {
+ Test test = socketTests[i];
+ c.setOption((SocketOption)test.option, test.testValue);
+ Object getval = c.getOption((SocketOption)test.option);
+ Object legacyget = legacyGetOption(Socket.class, c, test.option);
+ if (!getval.equals(legacyget)) {
+ Formatter f = new Formatter();
+ f.format("S Err %d: %s/%s", i, getval, legacyget);
+ throw new RuntimeException(f.toString());
+ }
+ }
+
+ for (int i = 0; i < rdmaSocketOptionTests.length; i++) {
+ Test test = rdmaSocketOptionTests[i];
+ c.setOption((SocketOption)test.option, test.testValue);
+ Object getval = c.getOption((SocketOption)test.option);
+ if (((Integer)getval).intValue() !=
+ ((Integer)test.testValue).intValue())
+ throw new RuntimeException("Test Failed");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Test Failed");
+ }
+ }
+
+ static void doServerSocketTests() throws Exception {
+ try {
+ ServerSocket srv = RdmaSockets.openServerSocket(
+ StandardProtocolFamily.INET);
+ for (int i = 0; i < serverSocketTests.length; i++) {
+ Test test = serverSocketTests[i];
+ srv.setOption((SocketOption)test.option, test.testValue);
+ Object getval = srv.getOption((SocketOption)test.option);
+ Object legacyget = legacyGetOption(
+ ServerSocket.class, srv, test.option
+ );
+ if (!getval.equals(legacyget)) {
+ Formatter f = new Formatter();
+ f.format("SS Err %d: %s/%s", i, getval, legacyget);
+ throw new RuntimeException(f.toString());
+ }
+ }
+
+ for (int i = 0; i < rdmaSocketOptionTests.length; i++) {
+ Test test = rdmaSocketOptionTests[i];
+ srv.setOption((SocketOption)test.option, test.testValue);
+ Object getval = srv.getOption((SocketOption)test.option);
+ if (((Integer)getval).intValue() !=
+ ((Integer)test.testValue).intValue())
+ throw new RuntimeException("Test Failed");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Test Failed");
+ }
+ }
+
+ static Object legacyGetOption(
+ Class<?> type, Object s, Object option)
+
+ throws Exception
+ {
+ if (type.equals(Socket.class)) {
+ Socket socket = (Socket)s;
+ Set<SocketOption<?>> options = socket.supportedOptions();
+
+ if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
+ return Integer.valueOf(socket.getSendBufferSize());
+ } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
+ return Integer.valueOf(socket.getReceiveBufferSize());
+ } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
+ return Boolean.valueOf(socket.getReuseAddress());
+ } else if (option.equals(StandardSocketOptions.TCP_NODELAY)) {
+ return Boolean.valueOf(socket.getTcpNoDelay());
+ } else {
+ throw new RuntimeException("unexecpted socket option");
+ }
+ } else if (type.equals(ServerSocket.class)) {
+ ServerSocket socket = (ServerSocket)s;
+ Set<SocketOption<?>> options = socket.supportedOptions();
+
+ if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
+ return Integer.valueOf(socket.getReceiveBufferSize());
+ } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
+ return Boolean.valueOf(socket.getReuseAddress());
+ } else {
+ throw new RuntimeException("unexecpted socket option");
+ }
+ }
+ throw new RuntimeException("unexecpted socket type");
+ }
+
+ public static void main(String args[]) throws Exception {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ doSocketTests();
+ doServerSocketTests();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/SocketOption/UnsupportedOptionsTest.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 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
+ * 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.io.IOException;
+import java.net.StandardProtocolFamily;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
+import java.util.ArrayList;
+import java.util.List;
+import jdk.net.RdmaSockets;
+import jdk.net.RdmaSocketOptions;
+
+import jtreg.SkippedException;
+
+/* @test
+ * @bug 8195160
+ * @summary Test checks that UnsupportedOperationException for unsupported
+ * SOCKET_OPTIONS is thrown by both getOption() and setOption() methods.
+ * @requires (os.family == "linux")
+ * @requires !vm.graal.enabled
+ * @library .. /test/lib
+ * @build RsocketTest
+ * @run main/othervm UnsupportedOptionsTest
+ */
+public class UnsupportedOptionsTest {
+
+ private static final List<SocketOption<?>> socketOptions = new ArrayList<>();
+
+ static {
+ socketOptions.add(StandardSocketOptions.SO_RCVBUF);
+ socketOptions.add(StandardSocketOptions.SO_REUSEADDR);
+ socketOptions.add(StandardSocketOptions.SO_SNDBUF);
+ socketOptions.add(StandardSocketOptions.TCP_NODELAY);
+ socketOptions.add(RdmaSocketOptions.RDMA_SQSIZE);
+ socketOptions.add(RdmaSocketOptions.RDMA_RQSIZE);
+ socketOptions.add(RdmaSocketOptions.RDMA_INLINE);
+ }
+
+ public static void main(String[] args) throws IOException {
+ if (!RsocketTest.isRsocketAvailable())
+ throw new SkippedException("rsocket is not available");
+
+ Socket s = RdmaSockets.openSocket(StandardProtocolFamily.INET);
+ ServerSocket ss = RdmaSockets.openServerSocket(
+ StandardProtocolFamily.INET);
+
+ for (SocketOption option : socketOptions) {
+ if (!s.supportedOptions().contains(option)) {
+ testUnsupportedSocketOption(s, option);
+ }
+
+ if (!ss.supportedOptions().contains(option)) {
+ testUnsupportedSocketOption(ss, option);
+ }
+ }
+ }
+
+ /*
+ * Check that UnsupportedOperationException for unsupported option is
+ * thrown from both getOption() and setOption() methods.
+ */
+ private static void testUnsupportedSocketOption(Object socket,
+ SocketOption option) {
+ testSet(socket, option);
+ testGet(socket, option);
+ }
+
+ private static void testSet(Object socket, SocketOption option) {
+ try {
+ setOption(socket, option);
+ } catch (UnsupportedOperationException e) {
+ System.out.println("UnsupportedOperationException was throw " +
+ "as expected. Socket: " + socket + " Option: " + option);
+ return;
+ } catch (Exception e) {
+ throw new RuntimeException("FAIL. Unexpected exception.", e);
+ }
+ throw new RuntimeException("FAIL. UnsupportedOperationException " +
+ "hasn't been thrown. Socket: " + socket + " Option: " + option);
+ }
+
+ private static void testGet(Object socket, SocketOption option) {
+ try {
+ getOption(socket, option);
+ } catch (UnsupportedOperationException e) {
+ System.out.println("UnsupportedOperationException was throw " +
+ "as expected. Socket: " + socket + " Option: " + option);
+ return;
+ } catch (Exception e) {
+ throw new RuntimeException("FAIL. Unexpected exception.", e);
+ }
+ throw new RuntimeException("FAIL. UnsupportedOperationException " +
+ "hasn't been thrown. Socket: " + socket + " Option: " + option);
+ }
+
+ private static void getOption(Object socket,
+ SocketOption option) throws IOException {
+ if (socket instanceof Socket) {
+ ((Socket) socket).getOption(option);
+ } else if (socket instanceof ServerSocket) {
+ ((ServerSocket) socket).getOption(option);
+ } else {
+ throw new RuntimeException("Unsupported socket type");
+ }
+ }
+
+ private static void setOption(Object socket,
+ SocketOption option) throws IOException {
+ if (socket instanceof Socket) {
+ ((Socket) socket).setOption(option, null);
+ } else if (socket instanceof ServerSocket) {
+ ((ServerSocket) socket).setOption(option, null);
+ } else {
+ throw new RuntimeException("Unsupported socket type");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/TestServers.java Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 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
+ * 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.io.Closeable;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.StandardProtocolFamily;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import jdk.net.RdmaSockets;
+
+import jdk.test.lib.Utils;
+
+
+public class TestServers {
+
+ private TestServers() { }
+
+ /**
+ * An abstract server identifies a server which listens on a port on on a
+ * given machine.
+ */
+ static abstract class AbstractServer {
+
+ private AbstractServer() {
+ }
+
+ public abstract int getPort();
+
+ public abstract InetAddress getAddress();
+ }
+
+ /**
+ * A downgraded type of AbstractServer which will refuse connections. Note:
+ * use it once and throw it away - this implementation opens an anonymous
+ * socket and closes it, returning the address of the closed socket. If
+ * other servers are started afterwards, the address/port might get reused
+ * and become connectable again - so it's not a good idea to assume that
+ * connections using this address/port will always be refused. Connections
+ * will be refused as long as the address/port of the refusing server has
+ * not been reused.
+ */
+ static class RefusingServer extends AbstractServer {
+
+ final InetAddress address;
+ final int port;
+
+ private RefusingServer(InetAddress address, int port) {
+ this.address = address;
+ this.port = port;
+ }
+
+ @Override
+ public int getPort() {
+ return port;
+ }
+
+ @Override
+ public InetAddress getAddress() {
+ return address;
+ }
+
+ public static RefusingServer newRefusingServer() throws IOException {
+ return new RefusingServer(InetAddress.getLocalHost(),
+ Utils.refusingEndpoint().getPort());
+ }
+ }
+
+ /**
+ * An abstract class for implementing small TCP servers for the nio tests
+ * purposes. Disclaimer: This is a naive implementation that uses the old
+ * networking APIs (not those from {@code java.nio.*}) and shamelessly
+ * extends/creates Threads instead of using an executor service.
+ */
+ static abstract class AbstractTcpServer extends AbstractServer
+ implements Runnable, Closeable {
+
+ protected final long linger; // #of ms to wait before responding
+ private Thread acceptThread; // thread waiting for accept
+ // list of opened connections that should be closed on close.
+ private List<TcpConnectionThread> connections = new ArrayList<>();
+ private ServerSocket serverSocket; // the server socket
+ private boolean started = false; // whether the server is started
+ Throwable error = null;
+
+ /**
+ * Creates a new abstract TCP server.
+ *
+ * @param linger the amount of time the server should wait before
+ * responding to requests.
+ */
+ protected AbstractTcpServer(long linger) {
+ this.linger = linger;
+ }
+
+ /**
+ * The local port to which the server is bound.
+ *
+ * @return The local port to which the server is bound.
+ * @exception IllegalStateException is thrown if the server is not
+ * started.
+ */
+ @Override
+ public final synchronized int getPort() {
+ if (!started) {
+ throw new IllegalStateException("Not started");
+ }
+ return serverSocket.getLocalPort();
+ }
+
+ /**
+ * The local address to which the server is bound.
+ *
+ * @return The local address to which the server is bound.
+ * @exception IllegalStateException is thrown if the server is not
+ * started.
+ */
+ @Override
+ public final synchronized InetAddress getAddress() {
+ if (!started) {
+ throw new IllegalStateException("Not started");
+ }
+ return serverSocket.getInetAddress();
+ }
+
+ /**
+ * Tells whether the server is started.
+ *
+ * @return true if the server is started.
+ */
+ public final synchronized boolean isStarted() {
+ return started;
+ }
+
+ /**
+ * Creates a new server socket.
+ *
+ * @param port local port to bind to.
+ * @param backlog requested maximum length of the queue of incoming
+ * connections.
+ * @param address local address to bind to.
+ * @return a new bound server socket ready to accept connections.
+ * @throws IOException if the socket cannot be created or bound.
+ */
+ protected ServerSocket newServerSocket(int port, int backlog,
+ InetAddress address)
+ throws IOException {
+ ServerSocket ss = RdmaSockets.openServerSocket(StandardProtocolFamily.INET);
+ ss.bind(new InetSocketAddress(address, port), backlog);
+ return ss;
+ }
+
+ /**
+ * Starts listening for connections.
+ *
+ * @throws IOException if the server socket cannot be created or bound.
+ */
+ public final synchronized void start() throws IOException {
+ if (started) {
+ return;
+ }
+ final ServerSocket socket =
+ newServerSocket(0, 100, InetAddress.getLocalHost());
+ serverSocket = socket;
+ acceptThread = new Thread(this);
+ acceptThread.setDaemon(true);
+ acceptThread.start();
+ started = true;
+ }
+
+ /**
+ * Calls {@code Thread.sleep(linger);}
+ */
+ protected final void lingerIfRequired() {
+ if (linger > 0) {
+ try {
+ Thread.sleep(linger);
+ } catch (InterruptedException x) {
+ Thread.interrupted();
+ final ServerSocket socket = serverSocket();
+ if (socket != null && !socket.isClosed()) {
+ System.err.println("Thread interrupted...");
+ }
+ }
+ }
+ }
+
+ final synchronized ServerSocket serverSocket() {
+ return this.serverSocket;
+ }
+
+ /**
+ * The main accept loop.
+ */
+ @Override
+ public final void run() {
+ final ServerSocket sSocket = serverSocket();
+ try {
+ Socket s;
+ while (isStarted() && !Thread.interrupted()
+ && (s = sSocket.accept()) != null) {
+ lingerIfRequired();
+ listen(s);
+ }
+ } catch (Exception x) {
+ error = x;
+ } finally {
+ synchronized (this) {
+ if (!sSocket.isClosed()) {
+ try {
+ sSocket.close();
+ } catch (IOException x) {
+ System.err.println("Failed to close server socket");
+ }
+ }
+ if (started && this.serverSocket == sSocket) {
+ started = false;
+ this.serverSocket = null;
+ this.acceptThread = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Represents a connection accepted by the server.
+ */
+ protected abstract class TcpConnectionThread extends Thread {
+
+ protected final Socket socket;
+
+ protected TcpConnectionThread(Socket socket) {
+ this.socket = socket;
+ this.setDaemon(true);
+ }
+
+ public void close() throws IOException {
+ socket.close();
+ interrupt();
+ }
+ }
+
+ /**
+ * Creates a new TcpConnnectionThread to handle the connection through
+ * an accepted socket.
+ *
+ * @param s the socket returned by {@code serverSocket.accept()}.
+ * @return a new TcpConnnectionThread to handle the connection through
+ * an accepted socket.
+ */
+ protected abstract TcpConnectionThread createConnection(Socket s);
+
+ /**
+ * Creates and starts a new TcpConnectionThread to handle the accepted
+ * socket.
+ *
+ * @param s the socket returned by {@code serverSocket.accept()}.
+ */
+ private synchronized void listen(Socket s) {
+ TcpConnectionThread c = createConnection(s);
+ c.start();
+ addConnection(c);
+ }
+
+ /**
+ * Add the connection to the list of accepted connections.
+ *
+ * @param connection an accepted connection.
+ */
+ protected synchronized void addConnection(
+ TcpConnectionThread connection) {
+ connections.add(connection);
+ }
+
+ /**
+ * Remove the connection from the list of accepted connections.
+ *
+ * @param connection an accepted connection.
+ */
+ protected synchronized void removeConnection(
+ TcpConnectionThread connection) {
+ connections.remove(connection);
+ }
+
+ /**
+ * Close the server socket and all the connections present in the list
+ * of accepted connections.
+ *
+ * @throws IOException
+ */
+ @Override
+ public synchronized void close() throws IOException {
+ if (serverSocket != null && !serverSocket.isClosed()) {
+ serverSocket.close();
+ }
+ if (acceptThread != null) {
+ acceptThread.interrupt();
+ }
+ int failed = 0;
+ for (TcpConnectionThread c : connections) {
+ try {
+ c.close();
+ } catch (IOException x) {
+ // no matter - we're closing.
+ failed++;
+ }
+ }
+ connections.clear();
+ if (failed > 0) {
+ throw new IOException("Failed to close some connections");
+ }
+ }
+ }
+
+ /**
+ * A small TCP Server that emulates the echo service for tests purposes. See
+ * http://en.wikipedia.org/wiki/Echo_Protocol This server uses an anonymous
+ * port - NOT the standard port 7. We don't guarantee that its behavior
+ * exactly matches the RFC - the only purpose of this server is to have
+ * something that responds to nio tests...
+ */
+ static class EchoServer extends AbstractTcpServer {
+
+ public EchoServer() {
+ this(0L);
+ }
+
+ public EchoServer(long linger) {
+ super(linger);
+ }
+
+ @Override
+ protected TcpConnectionThread createConnection(Socket s) {
+ return new EchoConnection(s);
+ }
+
+ private final class EchoConnection extends TcpConnectionThread {
+
+ public EchoConnection(Socket socket) {
+ super(socket);
+ }
+
+ @Override
+ public void run() {
+ try {
+ final InputStream is = socket.getInputStream();
+ final OutputStream out = socket.getOutputStream();
+ byte[] b = new byte[255];
+ int n;
+ while ((n = is.read(b)) > 0) {
+ lingerIfRequired();
+ out.write(b, 0, n);
+ }
+ } catch (IOException io) {
+ // fall through to finally
+ } finally {
+ if (!socket.isClosed()) {
+ try {
+ socket.close();
+ } catch (IOException x) {
+ System.err.println(
+ "Failed to close echo connection socket");
+ }
+ }
+ removeConnection(this);
+ }
+ }
+ }
+
+ public static EchoServer startNewServer() throws IOException {
+ return startNewServer(0);
+ }
+
+ public static EchoServer startNewServer(long linger) throws IOException {
+ final EchoServer echoServer = new EchoServer(linger);
+ echoServer.start();
+ return echoServer;
+ }
+ }
+
+
+ /**
+ * A small TCP Server that accept connections but does not response to any input.
+ */
+ static final class NoResponseServer extends EchoServer {
+ public NoResponseServer() {
+ super(Long.MAX_VALUE);
+ }
+
+ public static NoResponseServer startNewServer() throws IOException {
+ final NoResponseServer noResponseServer = new NoResponseServer();
+ noResponseServer.start();
+ return noResponseServer;
+ }
+ }
+
+
+ /**
+ * A small TCP server that emulates the Day & Time service for tests
+ * purposes. See http://en.wikipedia.org/wiki/Daytime_Protocol This server
+ * uses an anonymous port - NOT the standard port 13. We don't guarantee
+ * that its behavior exactly matches the RFC - the only purpose of this
+ * server is to have something that responds to nio tests...
+ */
+ static final class DayTimeServer extends AbstractTcpServer {
+
+ public DayTimeServer() {
+ this(0L);
+ }
+
+ public DayTimeServer(long linger) {
+ super(linger);
+ }
+
+ @Override
+ protected TcpConnectionThread createConnection(Socket s) {
+ return new DayTimeServerConnection(s);
+ }
+
+ @Override
+ protected void addConnection(TcpConnectionThread connection) {
+ // do nothing - the connection just write the date and terminates.
+ }
+
+ @Override
+ protected void removeConnection(TcpConnectionThread connection) {
+ // do nothing - we're not adding connections to the list...
+ }
+
+ private final class DayTimeServerConnection extends TcpConnectionThread {
+
+ public DayTimeServerConnection(Socket socket) {
+ super(socket);
+ }
+
+ @Override
+ public void run() {
+ try {
+ final OutputStream out = socket.getOutputStream();
+ lingerIfRequired();
+ out.write(new Date(System.currentTimeMillis())
+ .toString().getBytes("US-ASCII"));
+ out.flush();
+ } catch (IOException io) {
+ // fall through to finally
+ } finally {
+ if (!socket.isClosed()) {
+ try {
+ socket.close();
+ } catch (IOException x) {
+ System.err.println(
+ "Failed to close echo connection socket");
+ }
+ }
+ }
+ }
+ }
+
+ public static DayTimeServer startNewServer()
+ throws IOException {
+ return startNewServer(0);
+ }
+
+ public static DayTimeServer startNewServer(long linger)
+ throws IOException {
+ final DayTimeServer daytimeServer = new DayTimeServer(linger);
+ daytimeServer.start();
+ return daytimeServer;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/RdmaSockets/rsocket/libRsocketTest.c Sat Jan 26 14:02:35 2019 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * Test if rsocket is available
+ */
+#include <stdlib.h>
+#ifdef __linux__
+#include <dlfcn.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <string.h>
+#endif
+#include "jni.h"
+
+jfieldID fid;
+
+/*
+ * Class: RsocketTest
+ * Method: isRsocketAvailable0
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean
+Java_RsocketTest_isRsocketAvailable0(JNIEnv *env, jclass cls) {
+ jboolean result = JNI_FALSE;
+#ifdef __linux__
+ void *handle;
+ int (*rs)(int, int, int);
+ char str[74];
+ strcpy(str, "librdmacm.so.1: cannot open shared object file: No such file or directory");
+ fid = (*env)->GetStaticFieldID(env, cls , "libInstalled", "Z");
+
+ handle = dlopen("librdmacm.so.1", RTLD_NOW);
+ if (!handle) {
+ int ret = strncmp(str, dlerror(), 74);
+ if (ret == 0) {
+ (*env)->SetStaticBooleanField(env, cls, fid, JNI_FALSE);
+ }
+ return JNI_FALSE;
+ } else {
+ (*env)->SetStaticBooleanField(env, cls, fid, JNI_TRUE);
+ }
+
+ rs = dlsym(handle, "rsocket");
+ if (!rs)
+ return JNI_FALSE;
+
+ if ((*rs)(AF_INET, SOCK_STREAM, 0) > 0)
+ result = JNI_TRUE;
+
+ dlclose(handle);
+#endif
+ return result;
+}