--- /dev/null 2018-06-04 09:38:58.268495706 -0700 +++ new/src/jdk.net/linux/native/libextnet/RdmaNet.c 2018-06-04 11:02:27.964275349 -0700 @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2001, 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 +#include +#include +#include +#include +#include +#include +#include + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "sun_nio_ch_Net.h" +#include "net_util.h" +#include "net_util_md.h" +#include "nio_util.h" +#include "nio.h" +#include "rdma_util_md.h" +//#include "rdma_ch_RdmaPollArrayWrapper.h" + +#ifndef IP_MULTICAST_ALL + #define IP_MULTICAST_ALL 49 +#endif + +#define COPY_INET6_ADDRESS(env, source, target) \ + (*env)->GetByteArrayRegion(env, source, 0, 16, target) + +static jfieldID fd_fdID; + +JNIEXPORT jboolean JNICALL +Java_rdma_ch_RdmaNet_isRdmaAvailable0(JNIEnv *env, jclass cls) { + return rdma_supported(); +} + +static int +configureBlocking(int fd, jboolean blocking) +{ + int flags = rfcntl(fd, F_GETFL); + int newflags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); + + return (flags == newflags) ? 0 : rfcntl(fd, F_SETFL, newflags); +} + +JNIEXPORT void JNICALL +Java_rdma_ch_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_rdma_ch_RdmaNet_initIDs(JNIEnv *env, jclass clazz) +{ + CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor")); + CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, clazz, "fd", "I")); + initInetAddressIDs(env); +} + +JNIEXPORT jboolean JNICALL +Java_rdma_ch_RdmaNet_isIPv6Available0(JNIEnv* env, jclass cl) +{ + return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_rdma_ch_RdmaNet_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) +{ + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL +Java_rdma_ch_RdmaNet_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) +{ + return JNI_FALSE; +} + +JNIEXPORT jint JNICALL +Java_rdma_ch_RdmaNet_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, + jboolean stream, jboolean reuse, jboolean ignored) +{ + int fd; + int type = (stream ? SOCK_STREAM : SOCK_DGRAM); + int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; + + fd = rsocket(domain, type, 0); + if (fd < 0) { + return handleSocketError(env, errno); + } + + /* Disable IPV6_V6ONLY to ensure dual-socket support */ + if (domain == AF_INET6) { + int arg = 0; + if (rsetsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, + sizeof(int)) < 0) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "Unable to set IPV6_V6ONLY"); + rclose(fd); + return -1; + } + } + + if (reuse) { + int arg = 1; + if (rsetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, + sizeof(arg)) < 0) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "Unable to set SO_REUSEADDR"); + rclose(fd); + return -1; + } + } + + if (type == SOCK_DGRAM) { + int arg = 0; + int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP; + if ((rsetsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && + (errno != ENOPROTOOPT)) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "Unable to set IP_MULTICAST_ALL"); + rclose(fd); + return -1; + } + } + + /* By default, Linux uses the route default */ + if (domain == AF_INET6 && type == SOCK_DGRAM) { + int arg = 1; + if (rsetsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, + sizeof(arg)) < 0) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "Unable to set IPV6_MULTICAST_HOPS"); + rclose(fd); + return -1; + } + } + return fd; +} + +JNIEXPORT void JNICALL +Java_rdma_ch_RdmaNet_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, + jboolean useExclBind, 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_rdma_ch_RdmaNet_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) +{ + int fd = (*env)->GetIntField(env, fdo, fd_fdID); + if (rlisten(fd, backlog) < 0) + handleSocketError(env, errno); +} + +JNIEXPORT jint JNICALL +Java_rdma_ch_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 = rconnect(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_rdma_ch_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 (rgetsockname(fd, &sa.sa, &sa_len) < 0) { + handleSocketError(env, errno); + return -1; + } + return NET_GetPortFromSockaddr(&sa); +} + +JNIEXPORT jobject JNICALL +Java_rdma_ch_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 (rgetsockname(fd, &sa.sa, &sa_len) < 0) { + handleSocketError(env, errno); + return NULL; + } + return NET_SockaddrToInetAddress(env, &sa, &port); +} + +JNIEXPORT jint JNICALL +Java_rdma_ch_RdmaNet_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt) +{ + int result; + u_char carg; + 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 = rgetsockopt(fd, level, opt, arg, &arglen); + } + if (n < 0) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "rdma.ch.RdmaNet.getIntOption"); + return -1; + } + + return (jint)result; +} + +JNIEXPORT void JNICALL +Java_rdma_ch_RdmaNet_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, + jint opt, jint arg, jboolean isIPv6) +{ + int result; + u_char carg; + 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 = rsetsockopt(fd, level, opt, parg, arglen); + } + if (n < 0) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "rdma.ch.RdmaNet.setIntOption"); + } +} + +JNIEXPORT void JNICALL +Java_rdma_ch_RdmaNet_shutdown(JNIEnv *env, jclass cl, 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 ((rshutdown(fd, how) < 0) && (errno != ENOTCONN)) + handleSocketError(env, errno); +} + +JNIEXPORT jint JNICALL +Java_rdma_ch_RdmaNet_poll(JNIEnv* env, jclass this, 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 = rpoll(&pfd, 1, (int)timeout); + + if (rv >= 0) { + return pfd.revents; + } else if (errno == EINTR) { + return IOS_INTERRUPTED; + } else { + handleSocketError(env, errno); + return IOS_THROWN; + } +} + +/* +JNIEXPORT jshort JNICALL +Java_rdma_ch_RdmaNet_pollinValue(JNIEnv *env, jclass this) +{ + return (jshort)POLLIN; +} + +JNIEXPORT jshort JNICALL +Java_rdma_ch_RdmaNet_polloutValue(JNIEnv *env, jclass this) +{ + return (jshort)POLLOUT; +} + +JNIEXPORT jshort JNICALL +Java_rdma_ch_RdmaNet_pollerrValue(JNIEnv *env, jclass this) +{ + return (jshort)POLLERR; +} + +JNIEXPORT jshort JNICALL +Java_rdma_ch_RdmaNet_pollhupValue(JNIEnv *env, jclass this) +{ + return (jshort)POLLHUP; +} + +JNIEXPORT jshort JNICALL +Java_rdma_ch_RdmaNet_pollnvalValue(JNIEnv *env, jclass this) +{ + return (jshort)POLLNVAL; +} + +JNIEXPORT jshort JNICALL +Java_rdma_ch_RdmaNet_pollconnValue(JNIEnv *env, jclass this) +{ + return (jshort)POLLOUT; +} +*/