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 * RdmaSocketImpl 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 { 72 int sv[2]; 73 74 #ifdef AF_UNIX 75 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { 76 return -1; 77 } 78 #else 79 return -1; 80 #endif 81 82 rs_shutdown(sv[0], 2); 83 rs_close(sv[1]); 84 85 return sv[0]; 86 } 87 88 static int getFD(JNIEnv *env, jobject this) { 89 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 90 CHECK_NULL_RETURN(fdObj, -1); 91 return (*env)->GetIntField(env, fdObj, IO_fd_fdID); 92 } 93 94 95 jfieldID 96 NET_GetFileDescriptorID(JNIEnv *env) 97 { 98 jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor"); 99 CHECK_NULL_RETURN(cls, NULL); 100 return (*env)->GetFieldID(env, cls, "fd", "I"); 101 } 102 103 JNIEXPORT void JNICALL 104 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_initProto(JNIEnv *env, jclass cls) { 105 loadRdmaFuncs(env); 106 107 jclass clazz = (*env)->FindClass(env, "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, jclass cls) { 136 return rdma_supported(); 137 } 138 139 void 140 NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass) { 141 if (sa->sa.sa_family == AF_INET6) { 142 sa->sa6.sin6_flowinfo = htonl((trafficClass & 0xff) << 20); 143 } 144 } 145 146 /* 147 * Class: jdk_net_LinuxRdmaSocketImpl 148 * Method: rdmaSocketCreate 149 * Signature: (Z)V */ 150 JNIEXPORT void JNICALL 151 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketCreate(JNIEnv *env, jobject this, 152 jboolean stream, jobject impl) { 153 jobject fdObj, ssObj; 154 int fd; 155 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 156 int domain = ipv6_available() ? AF_INET6 : AF_INET; 157 158 if (socketExceptionCls == NULL) { 159 jclass c = (*env)->FindClass(env, "java/net/SocketException"); 160 CHECK_NULL(c); 161 socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c); 162 CHECK_NULL(socketExceptionCls); 163 } 164 165 fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 166 167 if (fdObj == NULL) { 168 (*env)->ThrowNew(env, socketExceptionCls, "null fd object"); 169 return; 170 } 171 172 if ((fd = rs_socket(domain, type, 0)) == -1) { 173 NET_ThrowNew(env, errno, "can't create socket"); 174 return; 175 } 176 if (domain == AF_INET6) { 177 int arg = 0; 178 if (rs_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 179 sizeof(int)) < 0) { 180 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6"); 181 rs_close(fd); 182 return; 183 } 184 } 185 186 ssObj = (*env)->GetObjectField(env, impl, psi_serverSocketID); 187 if (ssObj != NULL) { 188 int arg = 1; 189 SET_NONBLOCKING(fd); 190 if (RDMA_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, 191 sizeof(arg)) < 0) { 192 NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR"); 193 rs_close(fd); 194 return; 195 } 196 } 197 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 198 } 199 200 JNIEXPORT void JNICALL 201 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketConnect(JNIEnv *env, jobject this, jobject impl, 202 jobject iaObj, jint port, 203 jint timeout) 204 { 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 JNI_TRUE) != 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, JNU_JAVANETPKG "ConnectException", 252 "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, JNU_JAVANETPKG "ProtocolException", 317 "Protocol error"); 318 return; 319 } 320 #endif 321 if (errno == ECONNREFUSED) { 322 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "ConnectException", 323 "Connection refused"); 324 } else if (errno == ETIMEDOUT) { 325 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "ConnectException", 326 "Connection timed out"); 327 } else if (errno == EHOSTUNREACH) { 328 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "NoRouteToHostException", 329 "Host unreachable"); 330 } else if (errno == EADDRNOTAVAIL) { 331 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "NoRouteToHostException", 332 "Address not available"); 333 } else if ((errno == EISCONN) || (errno == EBADF)) { 334 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 335 "Socket closed"); 336 } else { 337 JNU_ThrowByNameWithMessageAndLastError 338 (env, JNU_JAVANETPKG "SocketException", "connect failed"); 339 } 340 return; 341 } 342 343 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 344 345 (*env)->SetObjectField(env, impl, psi_addressID, iaObj); 346 (*env)->SetIntField(env, impl, psi_portID, port); 347 348 if (localport == 0) { 349 socklen_t slen = sizeof(SOCKETADDRESS); 350 if (rs_getsockname(fd, &sa.sa, &slen) == -1) { 351 JNU_ThrowByNameWithMessageAndLastError 352 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 353 } else { 354 localport = NET_GetPortFromSockaddr(&sa); 355 (*env)->SetIntField(env, impl, psi_localportID, localport); 356 } 357 } 358 } 359 360 JNIEXPORT void JNICALL 361 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketBind(JNIEnv *env, jobject this, jobject impl, 362 jobject iaObj, jint localport) { 363 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 364 int fd; 365 int len = 0; 366 SOCKETADDRESS sa; 367 368 if (IS_NULL(fdObj)) { 369 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 370 "Socket closed"); 371 return; 372 } else { 373 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 374 } 375 if (IS_NULL(iaObj)) { 376 JNU_ThrowNullPointerException(env, "iaObj is null."); 377 return; 378 } 379 380 if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, 381 &len, JNI_TRUE) != 0) { 382 return; 383 } 384 385 if (RDMA_Bind(fd, &sa, len) < 0) { 386 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL || 387 errno == EPERM || errno == EACCES) { 388 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "BindException", 389 "Bind failed"); 390 } else { 391 JNU_ThrowByNameWithMessageAndLastError 392 (env, JNU_JAVANETPKG "SocketException", "Bind failed"); 393 } 394 return; 395 } 396 (*env)->SetObjectField(env, impl, psi_addressID, iaObj); 397 398 if (localport == 0) { 399 socklen_t slen = sizeof(SOCKETADDRESS); 400 if (rs_getsockname(fd, &sa.sa, &slen) == -1) { 401 JNU_ThrowByNameWithMessageAndLastError 402 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 403 return; 404 } 405 localport = NET_GetPortFromSockaddr(&sa); 406 (*env)->SetIntField(env, impl, psi_localportID, localport); 407 } else { 408 (*env)->SetIntField(env, impl, psi_localportID, localport); 409 } 410 } 411 412 JNIEXPORT void JNICALL 413 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketListen(JNIEnv *env, jobject this, jobject impl, 414 jint count) 415 { 416 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 417 int fd; 418 419 if (IS_NULL(fdObj)) { 420 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 421 "Socket closed"); 422 return; 423 } else { 424 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 425 } 426 427 if (count == 0x7fffffff) 428 count -= 1; 429 430 int rv = rs_listen(fd, count); 431 if (rv == -1) { 432 JNU_ThrowByNameWithMessageAndLastError 433 (env, JNU_JAVANETPKG "SocketException", "Listen failed"); 434 } 435 } 436 437 JNIEXPORT void JNICALL 438 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketAccept(JNIEnv *env, jobject this, jobject socket, jobject impl) 439 { 440 int port; 441 jint timeout = (*env)->GetIntField(env, impl, psi_timeoutID); 442 jlong prevNanoTime = 0; 443 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; 444 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 445 446 jobject socketFdObj; 447 jobject socketAddressObj; 448 449 jint fd; 450 451 jint newfd; 452 453 SOCKETADDRESS sa; 454 socklen_t slen = sizeof(SOCKETADDRESS); 455 456 if (IS_NULL(fdObj)) { 457 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 458 "Socket closed"); 459 return; 460 } else { 461 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 462 } 463 if (IS_NULL(socket)) { 464 JNU_ThrowNullPointerException(env, "socket is null"); 465 return; 466 } 467 468 for (;;) { 469 int ret; 470 jlong currNanoTime; 471 472 if (prevNanoTime == 0 && nanoTimeout > 0) { 473 prevNanoTime = JVM_NanoTime(env, 0); 474 } 475 476 if (timeout <= 0) { 477 ret = RDMA_Timeout(env, fd, -1, 0); 478 } else { 479 ret = RDMA_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, prevNanoTime); 480 } 481 482 if (ret == 0) { 483 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 484 "Accept timed out"); 485 return; 486 } else if (ret == -1) { 487 if (errno == EBADF) { 488 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 489 } else if (errno == ENOMEM) { 490 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed"); 491 } else { 492 JNU_ThrowByNameWithMessageAndLastError 493 (env, JNU_JAVANETPKG "SocketException", "Accept failed"); 494 } 495 return; 496 } 497 498 newfd = RDMA_Accept(fd, &sa.sa, &slen); 499 500 if (newfd >= 0) { 501 SET_BLOCKING(newfd); 502 break; 503 } 504 505 if (!(errno == ECONNABORTED || errno == EWOULDBLOCK)) { 506 break; 507 } 508 509 if (nanoTimeout >= NET_NSEC_PER_MSEC) { 510 currNanoTime = JVM_NanoTime(env, 0); 511 nanoTimeout -= (currNanoTime - prevNanoTime); 512 if (nanoTimeout < NET_NSEC_PER_MSEC) { 513 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 514 "Accept timed out"); 515 return; 516 } 517 prevNanoTime = currNanoTime; 518 } 519 } 520 521 if (newfd < 0) { 522 if (newfd == -2) { 523 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 524 "operation interrupted"); 525 } else { 526 if (errno == EINVAL) { 527 errno = EBADF; 528 } 529 if (errno == EBADF) { 530 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 531 } else { 532 JNU_ThrowByNameWithMessageAndLastError 533 (env, JNU_JAVANETPKG "SocketException", "Accept failed"); 534 } 535 } 536 return; 537 } 538 539 socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port); 540 if (socketAddressObj == NULL) { 541 rs_close(newfd); 542 return; 543 } 544 545 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID); 546 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd); 547 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); 548 (*env)->SetIntField(env, socket, psi_portID, port); 549 port = (*env)->GetIntField(env, impl, psi_localportID); 550 (*env)->SetIntField(env, socket, psi_localportID, port); 551 } 552 553 554 JNIEXPORT jint JNICALL 555 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketAvailable(JNIEnv *env, jobject this, jobject impl) { 556 jint ret = -1; 557 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 558 jint fd; 559 560 if (IS_NULL(fdObj)) { 561 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 562 "Socket closed"); 563 return -1; 564 } else { 565 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 566 } 567 if (RDMA_SocketAvailable(fd, &ret) == 0){ 568 if (errno == ECONNRESET) { 569 JNU_ThrowByName(env, "sun/net/ConnectionResetException", ""); 570 } else { 571 JNU_ThrowByNameWithMessageAndLastError 572 (env, JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed"); 573 } 574 } 575 return ret; 576 } 577 578 JNIEXPORT void JNICALL 579 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketClose(JNIEnv *env, jobject this, 580 jboolean useDeferredClose, jobject impl) { 581 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 582 jint fd; 583 584 if (IS_NULL(fdObj)) { 585 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 586 "socket already closed"); 587 return; 588 } else { 589 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 590 } 591 if (fd != -1) { 592 if (useDeferredClose && marker_fd >= 0) { 593 RDMA_Dup2(marker_fd, fd); 594 } else { 595 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 596 RDMA_SocketClose(fd); 597 } 598 } 599 } 600 601 JNIEXPORT void JNICALL 602 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketShutdown(JNIEnv *env, jobject this, 603 jint howto, jobject impl) 604 { 605 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 606 jint fd; 607 608 if (IS_NULL(fdObj)) { 609 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 610 "socket already closed"); 611 return; 612 } else { 613 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 614 } 615 rs_shutdown(fd, howto); 616 } 617 618 619 JNIEXPORT void JNICALL 620 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketSetOption 621 (JNIEnv *env, jobject this, jobject impl, jint cmd, jboolean on, jobject value) 622 { 623 int fd; 624 int level, optname, optlen; 625 union { 626 int i; 627 struct linger ling; 628 } optval; 629 630 fd = getFD(env, impl); 631 if (fd < 0) { 632 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 633 "Socket closed"); 634 return; 635 } 636 637 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 638 return; 639 } 640 641 if (RDMA_MapSocketOption(cmd, &level, &optname)) { 642 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 643 return; 644 } 645 646 switch (cmd) { 647 case java_net_SocketOptions_SO_SNDBUF : 648 case java_net_SocketOptions_SO_RCVBUF : 649 default : 650 optval.i = (on ? 1 : 0); 651 optlen = sizeof(optval.i); 652 653 } 654 if (RDMA_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) { 655 JNU_ThrowByNameWithMessageAndLastError 656 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); 657 } 658 } 659 660 JNIEXPORT jint JNICALL 661 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketGetOption 662 (JNIEnv *env, jobject this, jobject impl, jint cmd, jobject iaContainerObj) 663 { 664 int fd; 665 int level, optname, optlen; 666 union { 667 int i; 668 struct linger ling; 669 } optval; 670 671 fd = getFD(env, impl); 672 if (fd < 0) { 673 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 674 "Socket closed"); 675 return -1; 676 } 677 678 if (cmd == java_net_SocketOptions_SO_BINDADDR) { 679 SOCKETADDRESS sa; 680 socklen_t len = sizeof(SOCKETADDRESS); 681 int port; 682 jobject iaObj; 683 jclass iaCntrClass; 684 jfieldID iaFieldID; 685 686 if (rs_getsockname(fd, &sa.sa, &len) < 0) { 687 JNU_ThrowByNameWithMessageAndLastError 688 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 689 return -1; 690 } 691 iaObj = NET_SockaddrToInetAddress(env, &sa, &port); 692 CHECK_NULL_RETURN(iaObj, -1); 693 694 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 695 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;"); 696 CHECK_NULL_RETURN(iaFieldID, -1); 697 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 698 return 0; 699 } 700 701 if (RDMA_MapSocketOption(cmd, &level, &optname)) { 702 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 703 return -1; 704 } 705 706 optlen = sizeof(optval.i); 707 708 if (RDMA_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 709 JNU_ThrowByNameWithMessageAndLastError 710 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option"); 711 return -1; 712 } 713 714 switch (cmd) { 715 case java_net_SocketOptions_SO_SNDBUF: 716 case java_net_SocketOptions_SO_RCVBUF: 717 return optval.i; 718 719 default : 720 return (optval.i == 0) ? -1 : 1; 721 } 722 } 723 724 JNIEXPORT void JNICALL 725 Java_jdk_internal_net_rdma_LinuxRdmaSocketImpl_rdmaSocketSendUrgentData(JNIEnv *env, jobject this, jobject impl, 726 jint data) { 727 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 728 int n, fd; 729 unsigned char d = data & 0xFF; 730 731 if (IS_NULL(fdObj)) { 732 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 733 return; 734 } else { 735 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 736 if (fd == -1) { 737 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 738 return; 739 } 740 741 } 742 n = RDMA_Send(fd, (char *)&d, 1, MSG_OOB); 743 if (n == -1) { 744 JNU_ThrowIOExceptionWithLastError(env, "Write failed"); 745 } 746 }