1 /* 2 * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <poll.h> 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <rdma/rsocket.h> 30 #include <string.h> 31 #include <netinet/in.h> 32 #include <netinet/tcp.h> 33 #include <limits.h> 34 35 #include "jni.h" 36 #include "jni_util.h" 37 #include "jvm.h" 38 #include "jlong.h" 39 #include "sun_nio_ch_Net.h" 40 #include "net_util.h" 41 #include "net_util_md.h" 42 #include "nio_util.h" 43 #include "nio.h" 44 #include "rdma_util_md.h" 45 46 #ifndef IP_MULTICAST_ALL 47 #define IP_MULTICAST_ALL 49 48 #endif 49 50 #define COPY_INET6_ADDRESS(env, source, target) \ 51 (*env)->GetByteArrayRegion(env, source, 0, 16, target) 52 53 static jfieldID fd_fdID; 54 55 JNIEXPORT jboolean JNICALL 56 Java_rdma_ch_RdmaNet_isRdmaAvailable0(JNIEnv *env, jclass cls) { 57 return rdma_supported(); 58 } 59 60 static int 61 configureBlocking(int fd, jboolean blocking) 62 { 63 int flags = rfcntl(fd, F_GETFL); 64 int newflags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); 65 66 return (flags == newflags) ? 0 : rfcntl(fd, F_SETFL, newflags); 67 } 68 69 JNIEXPORT void JNICALL 70 Java_rdma_ch_RdmaNet_configureBlocking(JNIEnv *env, jclass clazz, 71 jobject fdo, jboolean blocking) 72 { 73 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 74 if (configureBlocking(fd, blocking) < 0) 75 JNU_ThrowIOExceptionWithLastError(env, "Configure blocking failed"); 76 } 77 78 JNIEXPORT void JNICALL 79 Java_rdma_ch_RdmaNet_initIDs(JNIEnv *env, jclass clazz) 80 { 81 CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor")); 82 CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, clazz, "fd", "I")); 83 initInetAddressIDs(env); 84 } 85 86 JNIEXPORT jboolean JNICALL 87 Java_rdma_ch_RdmaNet_isIPv6Available0(JNIEnv* env, jclass cl) 88 { 89 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; 90 } 91 92 JNIEXPORT jboolean JNICALL 93 Java_rdma_ch_RdmaNet_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) 94 { 95 return JNI_TRUE; 96 } 97 98 JNIEXPORT jboolean JNICALL 99 Java_rdma_ch_RdmaNet_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) 100 { 101 return JNI_FALSE; 102 } 103 104 JNIEXPORT jint JNICALL 105 Java_rdma_ch_RdmaNet_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, 106 jboolean stream, jboolean reuse, jboolean ignored) 107 { 108 int fd; 109 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 110 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; 111 112 fd = rsocket(domain, type, 0); 113 if (fd < 0) { 114 return handleSocketError(env, errno); 115 } 116 117 if (reuse) { 118 int arg = 1; 119 if (rsetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 120 sizeof(arg)) < 0) { 121 JNU_ThrowByNameWithLastError(env, 122 JNU_JAVANETPKG "SocketException", 123 "Unable to set SO_REUSEADDR"); 124 rclose(fd); 125 return -1; 126 } 127 } 128 129 return fd; 130 } 131 132 JNIEXPORT void JNICALL 133 Java_rdma_ch_RdmaNet_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, 134 jboolean useExclBind, jobject iao, int port) 135 { 136 SOCKETADDRESS sa; 137 int sa_len = 0; 138 int rv = 0; 139 140 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, 141 preferIPv6) != 0) { 142 return; 143 } 144 145 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 146 rv = RDMA_Bind(fd, &sa, sa_len); 147 if (rv != 0) { 148 handleSocketError(env, errno); 149 } 150 } 151 152 JNIEXPORT void JNICALL 153 Java_rdma_ch_RdmaNet_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 154 { 155 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 156 if (rlisten(fd, backlog) < 0) 157 handleSocketError(env, errno); 158 } 159 160 JNIEXPORT jint JNICALL 161 Java_rdma_ch_RdmaNet_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 162 jobject fdo, jobject iao, jint port) 163 { 164 SOCKETADDRESS sa; 165 int sa_len = 0; 166 int rv; 167 168 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, 169 preferIPv6) != 0) { 170 return IOS_THROWN; 171 } 172 173 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 174 175 rv = rconnect(fd, &sa.sa, sa_len); 176 if (rv != 0) { 177 if (errno == EINPROGRESS) { 178 return IOS_UNAVAILABLE; 179 } else if (errno == EINTR) { 180 return IOS_INTERRUPTED; 181 } 182 return handleSocketError(env, errno); 183 } 184 return 1; 185 } 186 187 JNIEXPORT jint JNICALL 188 Java_rdma_ch_RdmaNet_localPort(JNIEnv *env, jclass clazz, jobject fdo) 189 { 190 SOCKETADDRESS sa; 191 socklen_t sa_len = sizeof(SOCKETADDRESS); 192 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 193 if (rgetsockname(fd, &sa.sa, &sa_len) < 0) { 194 handleSocketError(env, errno); 195 return -1; 196 } 197 return NET_GetPortFromSockaddr(&sa); 198 } 199 200 JNIEXPORT jobject JNICALL 201 Java_rdma_ch_RdmaNet_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 202 { 203 SOCKETADDRESS sa; 204 socklen_t sa_len = sizeof(SOCKETADDRESS); 205 int port; 206 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 207 if (rgetsockname(fd, &sa.sa, &sa_len) < 0) { 208 handleSocketError(env, errno); 209 return NULL; 210 } 211 return NET_SockaddrToInetAddress(env, &sa, &port); 212 } 213 214 JNIEXPORT jint JNICALL 215 Java_rdma_ch_RdmaNet_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 216 jboolean mayNeedConversion, jint level, jint opt) 217 { 218 int result; 219 struct linger linger; 220 u_char carg; 221 void *arg; 222 socklen_t arglen; 223 int n; 224 225 arg = (void *)&result; 226 arglen = sizeof(result); 227 228 if (level == SOL_SOCKET && opt == SO_LINGER) { 229 arg = (void *)&linger; 230 arglen = sizeof(linger); 231 } 232 233 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 234 if (mayNeedConversion) { 235 n = RDMA_GetSockOpt(fd, level, opt, arg, (int*)&arglen); 236 } else { 237 n = rgetsockopt(fd, level, opt, arg, &arglen); 238 } 239 if (n < 0) { 240 JNU_ThrowByNameWithLastError(env, 241 JNU_JAVANETPKG "SocketException", 242 "rdma.ch.RdmaNet.getIntOption"); 243 return -1; 244 } 245 246 if (level == SOL_SOCKET && opt == SO_LINGER) 247 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; 248 249 return (jint)result; 250 } 251 252 JNIEXPORT void JNICALL 253 Java_rdma_ch_RdmaNet_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 254 jboolean mayNeedConversion, jint level, 255 jint opt, jint arg, jboolean isIPv6) 256 { 257 int result; 258 struct linger linger; 259 u_char carg; 260 void *parg; 261 socklen_t arglen; 262 int n; 263 264 parg = (void*)&arg; 265 arglen = sizeof(arg); 266 267 if (level == SOL_SOCKET && opt == SO_LINGER) { 268 parg = (void *)&linger; 269 arglen = sizeof(linger); 270 if (arg >= 0) { 271 linger.l_onoff = 1; 272 linger.l_linger = arg; 273 } else { 274 linger.l_onoff = 0; 275 linger.l_linger = 0; 276 } 277 } 278 279 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 280 if (mayNeedConversion) { 281 n = RDMA_SetSockOpt(fd, level, opt, parg, arglen); 282 } else { 283 n = rsetsockopt(fd, level, opt, parg, arglen); 284 } 285 if (n < 0) { 286 JNU_ThrowByNameWithLastError(env, 287 JNU_JAVANETPKG "SocketException", 288 "rdma.ch.RdmaNet.setIntOption"); 289 } 290 } 291 292 JNIEXPORT void JNICALL 293 Java_rdma_ch_RdmaNet_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) 294 { 295 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : 296 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; 297 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 298 if ((rshutdown(fd, how) < 0) && (errno != ENOTCONN)) 299 handleSocketError(env, errno); 300 } 301 302 JNIEXPORT jint JNICALL 303 Java_rdma_ch_RdmaNet_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout) 304 { 305 struct pollfd pfd; 306 int rv; 307 pfd.fd = (*env)->GetIntField(env, fdo, fd_fdID); 308 pfd.events = events; 309 if (timeout < -1) { 310 timeout = -1; 311 } else if (timeout > INT_MAX) { 312 timeout = INT_MAX; 313 } 314 rv = rpoll(&pfd, 1, (int)timeout); 315 316 if (rv >= 0) { 317 return pfd.revents; 318 } else if (errno == EINTR) { 319 return IOS_INTERRUPTED; 320 } else { 321 handleSocketError(env, errno); 322 return IOS_THROWN; 323 } 324 }