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 //#include "rdma_ch_RdmaPollArrayWrapper.h" 46 47 #ifndef IP_MULTICAST_ALL 48 #define IP_MULTICAST_ALL 49 49 #endif 50 51 #define COPY_INET6_ADDRESS(env, source, target) \ 52 (*env)->GetByteArrayRegion(env, source, 0, 16, target) 53 54 static jfieldID fd_fdID; 55 56 JNIEXPORT jboolean JNICALL 57 Java_rdma_ch_RdmaNet_isRdmaAvailable0(JNIEnv *env, jclass cls) { 58 return rdma_supported(); 59 } 60 61 static int 62 configureBlocking(int fd, jboolean blocking) 63 { 64 int flags = rfcntl(fd, F_GETFL); 65 int newflags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); 66 67 return (flags == newflags) ? 0 : rfcntl(fd, F_SETFL, newflags); 68 } 69 70 JNIEXPORT void JNICALL 71 Java_rdma_ch_RdmaNet_configureBlocking(JNIEnv *env, jclass clazz, 72 jobject fdo, jboolean blocking) 73 { 74 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 75 if (configureBlocking(fd, blocking) < 0) 76 JNU_ThrowIOExceptionWithLastError(env, "Configure blocking failed"); 77 } 78 79 JNIEXPORT void JNICALL 80 Java_rdma_ch_RdmaNet_initIDs(JNIEnv *env, jclass clazz) 81 { 82 CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor")); 83 CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, clazz, "fd", "I")); 84 initInetAddressIDs(env); 85 } 86 87 JNIEXPORT jboolean JNICALL 88 Java_rdma_ch_RdmaNet_isIPv6Available0(JNIEnv* env, jclass cl) 89 { 90 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; 91 } 92 93 JNIEXPORT jboolean JNICALL 94 Java_rdma_ch_RdmaNet_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) 95 { 96 return JNI_TRUE; 97 } 98 99 JNIEXPORT jboolean JNICALL 100 Java_rdma_ch_RdmaNet_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) 101 { 102 return JNI_FALSE; 103 } 104 105 JNIEXPORT jint JNICALL 106 Java_rdma_ch_RdmaNet_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, 107 jboolean stream, jboolean reuse, jboolean ignored) 108 { 109 int fd; 110 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 111 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; 112 113 fd = rsocket(domain, type, 0); 114 if (fd < 0) { 115 return handleSocketError(env, errno); 116 } 117 118 /* Disable IPV6_V6ONLY to ensure dual-socket support */ 119 if (domain == AF_INET6) { 120 int arg = 0; 121 if (rsetsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 122 sizeof(int)) < 0) { 123 JNU_ThrowByNameWithLastError(env, 124 JNU_JAVANETPKG "SocketException", 125 "Unable to set IPV6_V6ONLY"); 126 rclose(fd); 127 return -1; 128 } 129 } 130 131 if (reuse) { 132 int arg = 1; 133 if (rsetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 134 sizeof(arg)) < 0) { 135 JNU_ThrowByNameWithLastError(env, 136 JNU_JAVANETPKG "SocketException", 137 "Unable to set SO_REUSEADDR"); 138 rclose(fd); 139 return -1; 140 } 141 } 142 143 if (type == SOCK_DGRAM) { 144 int arg = 0; 145 int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP; 146 if ((rsetsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) && 147 (errno != ENOPROTOOPT)) { 148 JNU_ThrowByNameWithLastError(env, 149 JNU_JAVANETPKG "SocketException", 150 "Unable to set IP_MULTICAST_ALL"); 151 rclose(fd); 152 return -1; 153 } 154 } 155 156 /* By default, Linux uses the route default */ 157 if (domain == AF_INET6 && type == SOCK_DGRAM) { 158 int arg = 1; 159 if (rsetsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, 160 sizeof(arg)) < 0) { 161 JNU_ThrowByNameWithLastError(env, 162 JNU_JAVANETPKG "SocketException", 163 "Unable to set IPV6_MULTICAST_HOPS"); 164 rclose(fd); 165 return -1; 166 } 167 } 168 return fd; 169 } 170 171 JNIEXPORT void JNICALL 172 Java_rdma_ch_RdmaNet_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6, 173 jboolean useExclBind, jobject iao, int port) 174 { 175 SOCKETADDRESS sa; 176 int sa_len = 0; 177 int rv = 0; 178 179 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, 180 preferIPv6) != 0) { 181 return; 182 } 183 184 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 185 rv = RDMA_Bind(fd, &sa, sa_len); 186 if (rv != 0) { 187 handleSocketError(env, errno); 188 } 189 } 190 191 JNIEXPORT void JNICALL 192 Java_rdma_ch_RdmaNet_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) 193 { 194 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 195 if (rlisten(fd, backlog) < 0) 196 handleSocketError(env, errno); 197 } 198 199 JNIEXPORT jint JNICALL 200 Java_rdma_ch_RdmaNet_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, 201 jobject fdo, jobject iao, jint port) 202 { 203 SOCKETADDRESS sa; 204 int sa_len = 0; 205 int rv; 206 207 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, 208 preferIPv6) != 0) { 209 return IOS_THROWN; 210 } 211 212 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 213 rv = rconnect(fd, &sa.sa, sa_len); 214 if (rv != 0) { 215 if (errno == EINPROGRESS) { 216 return IOS_UNAVAILABLE; 217 } else if (errno == EINTR) { 218 return IOS_INTERRUPTED; 219 } 220 return handleSocketError(env, errno); 221 } 222 return 1; 223 } 224 225 JNIEXPORT jint JNICALL 226 Java_rdma_ch_RdmaNet_localPort(JNIEnv *env, jclass clazz, jobject fdo) 227 { 228 SOCKETADDRESS sa; 229 socklen_t sa_len = sizeof(SOCKETADDRESS); 230 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 231 if (rgetsockname(fd, &sa.sa, &sa_len) < 0) { 232 handleSocketError(env, errno); 233 return -1; 234 } 235 return NET_GetPortFromSockaddr(&sa); 236 } 237 238 JNIEXPORT jobject JNICALL 239 Java_rdma_ch_RdmaNet_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) 240 { 241 SOCKETADDRESS sa; 242 socklen_t sa_len = sizeof(SOCKETADDRESS); 243 int port; 244 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 245 if (rgetsockname(fd, &sa.sa, &sa_len) < 0) { 246 handleSocketError(env, errno); 247 return NULL; 248 } 249 return NET_SockaddrToInetAddress(env, &sa, &port); 250 } 251 252 JNIEXPORT jint JNICALL 253 Java_rdma_ch_RdmaNet_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 254 jboolean mayNeedConversion, jint level, jint opt) 255 { 256 int result; 257 u_char carg; 258 void *arg; 259 socklen_t arglen; 260 int n; 261 262 arg = (void *)&result; 263 arglen = sizeof(result); 264 265 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 266 if (mayNeedConversion) { 267 n = RDMA_GetSockOpt(fd, level, opt, arg, (int*)&arglen); 268 } else { 269 n = rgetsockopt(fd, level, opt, arg, &arglen); 270 } 271 if (n < 0) { 272 JNU_ThrowByNameWithLastError(env, 273 JNU_JAVANETPKG "SocketException", 274 "rdma.ch.RdmaNet.getIntOption"); 275 return -1; 276 } 277 278 return (jint)result; 279 } 280 281 JNIEXPORT void JNICALL 282 Java_rdma_ch_RdmaNet_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, 283 jboolean mayNeedConversion, jint level, 284 jint opt, jint arg, jboolean isIPv6) 285 { 286 int result; 287 u_char carg; 288 void *parg; 289 socklen_t arglen; 290 int n; 291 292 parg = (void*)&arg; 293 arglen = sizeof(arg); 294 295 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 296 if (mayNeedConversion) { 297 n = RDMA_SetSockOpt(fd, level, opt, parg, arglen); 298 } else { 299 n = rsetsockopt(fd, level, opt, parg, arglen); 300 } 301 if (n < 0) { 302 JNU_ThrowByNameWithLastError(env, 303 JNU_JAVANETPKG "SocketException", 304 "rdma.ch.RdmaNet.setIntOption"); 305 } 306 } 307 308 JNIEXPORT void JNICALL 309 Java_rdma_ch_RdmaNet_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) 310 { 311 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : 312 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; 313 int fd = (*env)->GetIntField(env, fdo, fd_fdID); 314 if ((rshutdown(fd, how) < 0) && (errno != ENOTCONN)) 315 handleSocketError(env, errno); 316 } 317 318 JNIEXPORT jint JNICALL 319 Java_rdma_ch_RdmaNet_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout) 320 { 321 struct pollfd pfd; 322 int rv; 323 pfd.fd = (*env)->GetIntField(env, fdo, fd_fdID); 324 pfd.events = events; 325 if (timeout < -1) { 326 timeout = -1; 327 } else if (timeout > INT_MAX) { 328 timeout = INT_MAX; 329 } 330 rv = rpoll(&pfd, 1, (int)timeout); 331 332 if (rv >= 0) { 333 return pfd.revents; 334 } else if (errno == EINTR) { 335 return IOS_INTERRUPTED; 336 } else { 337 handleSocketError(env, errno); 338 return IOS_THROWN; 339 } 340 } 341 342 /* 343 JNIEXPORT jshort JNICALL 344 Java_rdma_ch_RdmaNet_pollinValue(JNIEnv *env, jclass this) 345 { 346 return (jshort)POLLIN; 347 } 348 349 JNIEXPORT jshort JNICALL 350 Java_rdma_ch_RdmaNet_polloutValue(JNIEnv *env, jclass this) 351 { 352 return (jshort)POLLOUT; 353 } 354 355 JNIEXPORT jshort JNICALL 356 Java_rdma_ch_RdmaNet_pollerrValue(JNIEnv *env, jclass this) 357 { 358 return (jshort)POLLERR; 359 } 360 361 JNIEXPORT jshort JNICALL 362 Java_rdma_ch_RdmaNet_pollhupValue(JNIEnv *env, jclass this) 363 { 364 return (jshort)POLLHUP; 365 } 366 367 JNIEXPORT jshort JNICALL 368 Java_rdma_ch_RdmaNet_pollnvalValue(JNIEnv *env, jclass this) 369 { 370 return (jshort)POLLNVAL; 371 } 372 373 JNIEXPORT jshort JNICALL 374 Java_rdma_ch_RdmaNet_pollconnValue(JNIEnv *env, jclass this) 375 { 376 return (jshort)POLLOUT; 377 } 378 */