/* * 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; } */