1 /* 2 * Copyright (c) 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 "java_net_SocketOptions.h" 27 #include "jdk_internal_net_rdma_LinuxRdmaSocketImpl.h" 28 #include "jvm.h" 29 #include "net_util.h" 30 #include "rdma_util_md.h" 31 #include "Rsocket.h" 32 33 /************************************************************************ 34 * LinuxRdmaSocketImpl 35 */ 36 37 static jfieldID IO_fd_fdID; 38 39 jfieldID psi_fdID; 40 jfieldID psi_addressID; 41 jfieldID psi_ipaddressID; 42 jfieldID psi_portID; 43 jfieldID psi_localportID; 44 jfieldID psi_timeoutID; 45 jfieldID psi_trafficClassID; 46 jfieldID psi_serverSocketID; 47 jfieldID psi_fdLockID; 48 jfieldID psi_closePendingID; 49 50 51 /* 52 * file descriptor used for dup2 53 */ 54 static int marker_fd = -1; 55 56 #define SET_NONBLOCKING(fd) { \ 57 int flags = rs_fcntl(fd, F_GETFL); \ 58 flags |= O_NONBLOCK; \ 59 rs_fcntl(fd, F_SETFL, flags); \ 60 } 61 62 #define SET_BLOCKING(fd) { \ 63 int flags = rs_fcntl(fd, F_GETFL); \ 64 flags &= ~O_NONBLOCK; \ 65 rs_fcntl(fd, F_SETFL, flags); \ 66 } 67 68 static jclass socketExceptionCls; 69 70 static int getMarkerFD() { 71 int sv[2]; 72 73 #ifdef AF_UNIX 74 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { 75 return -1; 76 } 77 #else 78 return -1; 79 #endif 80 81 rs_shutdown(sv[0], 2); 82 rs_close(sv[1]); 83 84 return sv[0]; 85 } 86 87 static int getFD(JNIEnv *env, jobject this) { 88 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 89 CHECK_NULL_RETURN(fdObj, -1); 90 return (*env)->GetIntField(env, fdObj, IO_fd_fdID); 91 } 92 93 94 jfieldID 95 NET_GetFileDescriptorID(JNIEnv *env) { 96 jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor"); 97 CHECK_NULL_RETURN(cls, NULL); 98 return (*env)->GetFieldID(env, cls, "fd", "I"); 99 } 100 101 JNIEXPORT void JNICALL 102 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_initProto(JNIEnv *env, 103 jclass cls) { 104 loadRdmaFuncs(env); 105 106 jclass clazz = (*env)->FindClass(env, 107 "jdk/internal/net/rdma/RdmaSocketImpl"); 108 psi_fdID = (*env)->GetFieldID(env, clazz , "fd", 109 "Ljava/io/FileDescriptor;"); 110 CHECK_NULL(psi_fdID); 111 psi_addressID = (*env)->GetFieldID(env, clazz, "address", 112 "Ljava/net/InetAddress;"); 113 CHECK_NULL(psi_addressID); 114 psi_timeoutID = (*env)->GetFieldID(env, clazz, "timeout", "I"); 115 CHECK_NULL(psi_timeoutID); 116 psi_trafficClassID = (*env)->GetFieldID(env, clazz, "trafficClass", "I"); 117 CHECK_NULL(psi_trafficClassID); 118 psi_portID = (*env)->GetFieldID(env, clazz, "port", "I"); 119 CHECK_NULL(psi_portID); 120 psi_localportID = (*env)->GetFieldID(env, clazz, "localport", "I"); 121 CHECK_NULL(psi_localportID); 122 psi_serverSocketID = (*env)->GetFieldID(env, clazz, "serverSocket", 123 "Ljava/net/ServerSocket;"); 124 CHECK_NULL(psi_serverSocketID); 125 126 IO_fd_fdID = NET_GetFileDescriptorID(env); 127 CHECK_NULL(IO_fd_fdID); 128 129 initInetAddressIDs(env); 130 JNU_CHECK_EXCEPTION(env); 131 marker_fd = getMarkerFD(); 132 } 133 134 JNIEXPORT jboolean JNICALL 135 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_isRdmaAvailable0(JNIEnv *env, 136 jclass cls) { 137 return rdma_supported(); 138 } 139 140 void 141 NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass) { 142 if (sa->sa.sa_family == AF_INET6) { 143 sa->sa6.sin6_flowinfo = htonl((trafficClass & 0xff) << 20); 144 } 145 } 146 147 /* 148 * Class: jdk_net_LinuxRdmaSocketImpl 149 * Method: rdmaSocketCreate 150 * Signature: (Z)V */ 151 JNIEXPORT void JNICALL 152 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketCreate(JNIEnv *env, 153 jobject this, jobject impl, jboolean preferIPv6, jboolean stream) { 154 jobject fdObj, ssObj; 155 int fd; 156 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 157 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; 158 159 if (socketExceptionCls == NULL) { 160 jclass c = (*env)->FindClass(env, "java/net/SocketException"); 161 CHECK_NULL(c); 162 socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c); 163 CHECK_NULL(socketExceptionCls); 164 } 165 166 fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 167 168 if (fdObj == NULL) { 169 (*env)->ThrowNew(env, socketExceptionCls, "null fd object"); 170 return; 171 } 172 173 if ((fd = rs_socket(domain, type, 0)) == -1) { 174 NET_ThrowNew(env, errno, "can't create socket"); 175 return; 176 } 177 if (domain == AF_INET6) { 178 int arg = 0; 179 if (rs_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 180 sizeof(int)) < 0) { 181 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6"); 182 rs_close(fd); 183 return; 184 } 185 } 186 187 ssObj = (*env)->GetObjectField(env, impl, psi_serverSocketID); 188 if (ssObj != NULL) { 189 int arg = 1; 190 SET_NONBLOCKING(fd); 191 if (RDMA_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 192 sizeof(arg)) < 0) { 193 NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR"); 194 rs_close(fd); 195 return; 196 } 197 } 198 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 199 } 200 201 JNIEXPORT void JNICALL 202 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketConnect(JNIEnv *env, 203 jobject this, jobject impl, jboolean preferIPv6, jobject iaObj, 204 jint port, jint timeout) { 205 jint localport = (*env)->GetIntField(env, impl, psi_localportID); 206 int len = 0; 207 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 208 209 jobject fdLock; 210 211 jint trafficClass = (*env)->GetIntField(env, impl, psi_trafficClassID); 212 213 jint fd; 214 215 SOCKETADDRESS sa; 216 int connect_rv = -1; 217 218 if (IS_NULL(fdObj)) { 219 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 220 return; 221 } else { 222 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 223 } 224 if (IS_NULL(iaObj)) { 225 JNU_ThrowNullPointerException(env, "inet address argument null."); 226 return; 227 } 228 229 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len, 230 preferIPv6) != 0) { 231 return; 232 } 233 234 if (trafficClass != 0 && ipv6_available()) { 235 NET_SetTrafficClass(&sa, trafficClass); 236 } 237 238 if (timeout <= 0) { 239 connect_rv = RDMA_Connect(fd, &sa.sa, len); 240 } else { 241 SET_NONBLOCKING(fd); 242 243 connect_rv = rs_connect(fd, &sa.sa, len); 244 245 if (connect_rv != 0) { 246 socklen_t optlen; 247 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; 248 jlong prevNanoTime = JVM_NanoTime(env, 0); 249 250 if (errno != EINPROGRESS) { 251 JNU_ThrowByNameWithMessageAndLastError(env, 252 JNU_JAVANETPKG "ConnectException", "connect failed"); 253 SET_BLOCKING(fd); 254 return; 255 } 256 257 while (1) { 258 jlong newNanoTime; 259 struct pollfd pfd; 260 pfd.fd = fd; 261 pfd.events = POLLOUT; 262 263 errno = 0; 264 265 connect_rv = RDMA_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC); 266 267 if (connect_rv >= 0) { 268 break; 269 } 270 if (errno != EINTR) { 271 break; 272 } 273 274 newNanoTime = JVM_NanoTime(env, 0); 275 nanoTimeout -= (newNanoTime - prevNanoTime); 276 if (nanoTimeout < NET_NSEC_PER_MSEC) { 277 connect_rv = 0; 278 break; 279 } 280 prevNanoTime = newNanoTime; 281 282 } 283 284 if (connect_rv == 0) { 285 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 286 "connect timed out"); 287 288 SET_BLOCKING(fd); 289 rs_shutdown(fd, 2); 290 return; 291 } 292 293 optlen = sizeof(connect_rv); 294 if (rs_getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, 295 &optlen) <0) { 296 connect_rv = errno; 297 } 298 } 299 300 SET_BLOCKING(fd); 301 302 if (connect_rv != 0) { 303 errno = connect_rv; 304 connect_rv = -1; 305 } 306 } 307 308 if (connect_rv < 0) { 309 if (connect_rv == -1 && errno == EINVAL) { 310 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 311 "Invalid argument or cannot assign requested address"); 312 return; 313 } 314 #if defined(EPROTO) 315 if (errno == EPROTO) { 316 JNU_ThrowByNameWithMessageAndLastError(env, 317 JNU_JAVANETPKG "ProtocolException", "Protocol error"); 318 return; 319 } 320 #endif 321 if (errno == ECONNREFUSED) { 322 JNU_ThrowByNameWithMessageAndLastError(env, 323 JNU_JAVANETPKG "ConnectException", "Connection refused"); 324 } else if (errno == ETIMEDOUT) { 325 JNU_ThrowByNameWithMessageAndLastError(env, 326 JNU_JAVANETPKG "ConnectException", "Connection timed out"); 327 } else if (errno == EHOSTUNREACH) { 328 JNU_ThrowByNameWithMessageAndLastError(env, 329 JNU_JAVANETPKG "NoRouteToHostException", "Host unreachable"); 330 } else if (errno == EADDRNOTAVAIL) { 331 JNU_ThrowByNameWithMessageAndLastError(env, 332 JNU_JAVANETPKG "NoRouteToHostException", 333 "Address not available"); 334 } else if ((errno == EISCONN) || (errno == EBADF)) { 335 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 336 "Socket closed"); 337 } else { 338 JNU_ThrowByNameWithMessageAndLastError(env, 339 JNU_JAVANETPKG "SocketException", "connect failed"); 340 } 341 return; 342 } 343 344 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 345 346 (*env)->SetObjectField(env, impl, psi_addressID, iaObj); 347 (*env)->SetIntField(env, impl, psi_portID, port); 348 349 if (localport == 0) { 350 socklen_t slen = sizeof(SOCKETADDRESS); 351 if (rs_getsockname(fd, &sa.sa, &slen) == -1) { 352 JNU_ThrowByNameWithMessageAndLastError(env, 353 JNU_JAVANETPKG "SocketException", 354 "Error getting socket name"); 355 } else { 356 localport = NET_GetPortFromSockaddr(&sa); 357 (*env)->SetIntField(env, impl, psi_localportID, localport); 358 } 359 } 360 } 361 362 JNIEXPORT void JNICALL 363 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketBind(JNIEnv *env, 364 jobject this, jobject impl, jboolean preferIPv6, jobject iaObj, 365 jint localport) { 366 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 367 int fd; 368 int len = 0; 369 SOCKETADDRESS sa; 370 371 if (IS_NULL(fdObj)) { 372 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 373 "Socket closed"); 374 return; 375 } else { 376 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 377 } 378 if (IS_NULL(iaObj)) { 379 JNU_ThrowNullPointerException(env, "iaObj is null."); 380 return; 381 } 382 383 if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, 384 &len, preferIPv6) != 0) { 385 return; 386 } 387 388 if (RDMA_Bind(fd, &sa, len) < 0) { 389 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL || 390 errno == EPERM || errno == EACCES) { 391 JNU_ThrowByNameWithMessageAndLastError(env, 392 JNU_JAVANETPKG "BindException", "Bind failed"); 393 } else { 394 JNU_ThrowByNameWithMessageAndLastError(env, 395 JNU_JAVANETPKG "SocketException", "Bind failed"); 396 } 397 return; 398 } 399 (*env)->SetObjectField(env, impl, psi_addressID, iaObj); 400 401 if (localport == 0) { 402 socklen_t slen = sizeof(SOCKETADDRESS); 403 if (rs_getsockname(fd, &sa.sa, &slen) == -1) { 404 JNU_ThrowByNameWithMessageAndLastError(env, 405 JNU_JAVANETPKG "SocketException", 406 "Error getting socket name"); 407 return; 408 } 409 localport = NET_GetPortFromSockaddr(&sa); 410 (*env)->SetIntField(env, impl, psi_localportID, localport); 411 } else { 412 (*env)->SetIntField(env, impl, psi_localportID, localport); 413 } 414 } 415 416 JNIEXPORT void JNICALL 417 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketListen(JNIEnv *env, 418 jobject this, jobject impl, jint count) { 419 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 420 int fd; 421 422 if (IS_NULL(fdObj)) { 423 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 424 "Socket closed"); 425 return; 426 } else { 427 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 428 } 429 430 if (count == 0x7fffffff) 431 count -= 1; 432 433 int rv = rs_listen(fd, count); 434 if (rv == -1) { 435 JNU_ThrowByNameWithMessageAndLastError(env, 436 JNU_JAVANETPKG "SocketException", "Listen failed"); 437 } 438 } 439 440 JNIEXPORT void JNICALL 441 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketAccept(JNIEnv *env, 442 jobject this, jobject impl, jobject socket) { 443 int port; 444 jint timeout = (*env)->GetIntField(env, impl, psi_timeoutID); 445 jlong prevNanoTime = 0; 446 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; 447 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 448 449 jobject socketFdObj; 450 jobject socketAddressObj; 451 452 jint fd; 453 454 jint newfd; 455 456 SOCKETADDRESS sa; 457 socklen_t slen = sizeof(SOCKETADDRESS); 458 459 if (IS_NULL(fdObj)) { 460 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 461 "Socket closed"); 462 return; 463 } else { 464 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 465 } 466 if (IS_NULL(socket)) { 467 JNU_ThrowNullPointerException(env, "socket is null"); 468 return; 469 } 470 471 for (;;) { 472 int ret; 473 jlong currNanoTime; 474 475 if (prevNanoTime == 0 && nanoTimeout > 0) { 476 prevNanoTime = JVM_NanoTime(env, 0); 477 } 478 479 if (timeout <= 0) { 480 ret = RDMA_Timeout(env, fd, -1, 0); 481 } else { 482 ret = RDMA_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, 483 prevNanoTime); 484 } 485 486 if (ret == 0) { 487 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 488 "Accept timed out"); 489 return; 490 } else if (ret == -1) { 491 if (errno == EBADF) { 492 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 493 "Socket closed"); 494 } else if (errno == ENOMEM) { 495 JNU_ThrowOutOfMemoryError(env, 496 "NET_Timeout native heap allocation failed"); 497 } else { 498 JNU_ThrowByNameWithMessageAndLastError(env, 499 JNU_JAVANETPKG "SocketException", "Accept failed"); 500 } 501 return; 502 } 503 504 newfd = RDMA_Accept(fd, &sa.sa, &slen); 505 506 if (newfd >= 0) { 507 SET_BLOCKING(newfd); 508 break; 509 } 510 511 if (!(errno == ECONNABORTED || errno == EWOULDBLOCK)) { 512 break; 513 } 514 515 if (nanoTimeout >= NET_NSEC_PER_MSEC) { 516 currNanoTime = JVM_NanoTime(env, 0); 517 nanoTimeout -= (currNanoTime - prevNanoTime); 518 if (nanoTimeout < NET_NSEC_PER_MSEC) { 519 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 520 "Accept timed out"); 521 return; 522 } 523 prevNanoTime = currNanoTime; 524 } 525 } 526 527 if (newfd < 0) { 528 if (newfd == -2) { 529 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 530 "operation interrupted"); 531 } else { 532 if (errno == EINVAL) { 533 errno = EBADF; 534 } 535 if (errno == EBADF) { 536 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 537 "Socket closed"); 538 } else { 539 JNU_ThrowByNameWithMessageAndLastError(env, 540 JNU_JAVANETPKG "SocketException", "Accept failed"); 541 } 542 } 543 return; 544 } 545 546 socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port); 547 if (socketAddressObj == NULL) { 548 rs_close(newfd); 549 return; 550 } 551 552 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID); 553 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd); 554 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); 555 (*env)->SetIntField(env, socket, psi_portID, port); 556 port = (*env)->GetIntField(env, impl, psi_localportID); 557 (*env)->SetIntField(env, socket, psi_localportID, port); 558 } 559 560 561 JNIEXPORT jint JNICALL 562 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketAvailable(JNIEnv *env, 563 jobject this, jobject impl) { 564 jint ret = -1; 565 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 566 jint fd; 567 568 if (IS_NULL(fdObj)) { 569 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 570 "Socket closed"); 571 return -1; 572 } else { 573 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 574 } 575 if (RDMA_SocketAvailable(fd, &ret) == 0){ 576 if (errno == ECONNRESET) { 577 JNU_ThrowByName(env, "sun/net/ConnectionResetException", ""); 578 } else { 579 JNU_ThrowByNameWithMessageAndLastError(env, 580 JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed"); 581 } 582 } 583 return ret; 584 } 585 586 JNIEXPORT void JNICALL 587 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketClose(JNIEnv *env, 588 jobject this, jobject impl, jboolean useDeferredClose) { 589 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 590 jint fd; 591 592 if (IS_NULL(fdObj)) { 593 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 594 "socket already closed"); 595 return; 596 } else { 597 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 598 } 599 if (fd != -1) { 600 if (useDeferredClose && marker_fd >= 0) { 601 RDMA_Dup2(marker_fd, fd); 602 } else { 603 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 604 RDMA_SocketClose(fd); 605 } 606 } 607 } 608 609 JNIEXPORT void JNICALL 610 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketShutdown(JNIEnv *env, 611 jobject this, jobject impl, jint howto) { 612 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 613 jint fd; 614 615 if (IS_NULL(fdObj)) { 616 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 617 "socket already closed"); 618 return; 619 } else { 620 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 621 } 622 rs_shutdown(fd, howto); 623 } 624 625 626 JNIEXPORT void JNICALL 627 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketSetOption(JNIEnv *env, 628 jobject this, jobject impl, jint cmd, jboolean on, jobject value) { 629 int fd; 630 int level, optname, optlen; 631 union { 632 int i; 633 struct linger ling; 634 } optval; 635 636 fd = getFD(env, impl); 637 if (fd < 0) { 638 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 639 "Socket closed"); 640 return; 641 } 642 643 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 644 return; 645 } 646 647 if (RDMA_MapSocketOption(cmd, &level, &optname)) { 648 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 649 return; 650 } 651 652 switch (cmd) { 653 case java_net_SocketOptions_SO_SNDBUF : 654 case java_net_SocketOptions_SO_RCVBUF : 655 default : 656 optval.i = (on ? 1 : 0); 657 optlen = sizeof(optval.i); 658 659 } 660 if (RDMA_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) { 661 JNU_ThrowByNameWithMessageAndLastError(env, 662 JNU_JAVANETPKG "SocketException", "Error setting socket option"); 663 } 664 } 665 666 JNIEXPORT jint JNICALL 667 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketGetOption(JNIEnv *env, 668 jobject this, jobject impl, jint cmd, jobject iaContainerObj) { 669 int fd; 670 int level, optname, optlen; 671 union { 672 int i; 673 struct linger ling; 674 } optval; 675 676 fd = getFD(env, impl); 677 if (fd < 0) { 678 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 679 "Socket closed"); 680 return -1; 681 } 682 683 if (cmd == java_net_SocketOptions_SO_BINDADDR) { 684 SOCKETADDRESS sa; 685 socklen_t len = sizeof(SOCKETADDRESS); 686 int port; 687 jobject iaObj; 688 jclass iaCntrClass; 689 jfieldID iaFieldID; 690 691 if (rs_getsockname(fd, &sa.sa, &len) < 0) { 692 JNU_ThrowByNameWithMessageAndLastError(env, 693 JNU_JAVANETPKG "SocketException", 694 "Error getting socket name"); 695 return -1; 696 } 697 iaObj = NET_SockaddrToInetAddress(env, &sa, &port); 698 CHECK_NULL_RETURN(iaObj, -1); 699 700 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 701 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, 702 "addr", "Ljava/net/InetAddress;"); 703 CHECK_NULL_RETURN(iaFieldID, -1); 704 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 705 return 0; 706 } 707 708 if (RDMA_MapSocketOption(cmd, &level, &optname)) { 709 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 710 return -1; 711 } 712 713 optlen = sizeof(optval.i); 714 715 if (RDMA_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 716 JNU_ThrowByNameWithMessageAndLastError(env, 717 JNU_JAVANETPKG "SocketException", "Error getting socket option"); 718 return -1; 719 } 720 721 switch (cmd) { 722 case java_net_SocketOptions_SO_SNDBUF: 723 case java_net_SocketOptions_SO_RCVBUF: 724 return optval.i; 725 726 default : 727 return (optval.i == 0) ? -1 : 1; 728 } 729 } 730 731 JNIEXPORT void JNICALL 732 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketSendUrgentData( 733 JNIEnv *env, jobject this, jobject impl, jint data) { 734 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 735 int n, fd; 736 unsigned char d = data & 0xFF; 737 738 if (IS_NULL(fdObj)) { 739 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 740 return; 741 } else { 742 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 743 if (fd == -1) { 744 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 745 return; 746 } 747 748 } 749 n = RDMA_Send(fd, (char *)&d, 1, MSG_OOB); 750 if (n == -1) { 751 JNU_ThrowIOExceptionWithLastError(env, "Write failed"); 752 } 753 }