1 /* 2 * Copyright (c) 1997, 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 #include <errno.h> 26 27 #include "jvm.h" 28 #include "rdma_util_md.h" 29 30 #include "java_net_SocketOptions.h" 31 32 #include "net_util.h" 33 #include "net_util_md.h" 34 #include "rdma_ch_LinuxRdmaSocketImpl.h" 35 36 /************************************************************************ 37 * RdmaSocketImpl 38 */ 39 40 static jfieldID IO_fd_fdID; 41 42 jfieldID psi_fdID; 43 jfieldID psi_addressID; 44 jfieldID psi_ipaddressID; 45 jfieldID psi_portID; 46 jfieldID psi_localportID; 47 jfieldID psi_timeoutID; 48 jfieldID psi_trafficClassID; 49 jfieldID psi_serverSocketID; 50 jfieldID psi_fdLockID; 51 jfieldID psi_closePendingID; 52 53 54 /* 55 * file descriptor used for dup2 56 */ 57 static int marker_fd = -1; 58 59 #define SET_NONBLOCKING(fd) { \ 60 int flags = rfcntl(fd, F_GETFL); \ 61 flags |= O_NONBLOCK; \ 62 rfcntl(fd, F_SETFL, flags); \ 63 } 64 65 #define SET_BLOCKING(fd) { \ 66 int flags = rfcntl(fd, F_GETFL); \ 67 flags &= ~O_NONBLOCK; \ 68 rfcntl(fd, F_SETFL, flags); \ 69 } 70 71 static jclass socketExceptionCls; 72 73 static int getMarkerFD() 74 { 75 int sv[2]; 76 77 #ifdef AF_UNIX 78 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { 79 return -1; 80 } 81 #else 82 return -1; 83 #endif 84 85 rshutdown(sv[0], 2); 86 rclose(sv[1]); 87 88 return sv[0]; 89 } 90 91 static int getFD(JNIEnv *env, jobject this) { 92 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID); 93 CHECK_NULL_RETURN(fdObj, -1); 94 return (*env)->GetIntField(env, fdObj, IO_fd_fdID); 95 } 96 97 98 jfieldID 99 NET_GetFileDescriptorID(JNIEnv *env) 100 { 101 jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor"); 102 CHECK_NULL_RETURN(cls, NULL); 103 return (*env)->GetFieldID(env, cls, "fd", "I"); 104 } 105 106 JNIEXPORT void JNICALL 107 Java_rdma_ch_LinuxRdmaSocketImpl_initProto(JNIEnv *env, jclass cls) { 108 jclass clazz = (*env)->FindClass(env, "rdma/ch/RdmaSocketImpl"); 109 psi_fdID = (*env)->GetFieldID(env, clazz , "fd", 110 "Ljava/io/FileDescriptor;"); 111 CHECK_NULL(psi_fdID); 112 psi_addressID = (*env)->GetFieldID(env, clazz, "address", 113 "Ljava/net/InetAddress;"); 114 CHECK_NULL(psi_addressID); 115 psi_timeoutID = (*env)->GetFieldID(env, clazz, "timeout", "I"); 116 CHECK_NULL(psi_timeoutID); 117 psi_trafficClassID = (*env)->GetFieldID(env, clazz, "trafficClass", "I"); 118 CHECK_NULL(psi_trafficClassID); 119 psi_portID = (*env)->GetFieldID(env, clazz, "port", "I"); 120 CHECK_NULL(psi_portID); 121 psi_localportID = (*env)->GetFieldID(env, clazz, "localport", "I"); 122 CHECK_NULL(psi_localportID); 123 psi_serverSocketID = (*env)->GetFieldID(env, clazz, "serverSocket", 124 "Ljava/net/ServerSocket;"); 125 CHECK_NULL(psi_serverSocketID); 126 127 IO_fd_fdID = NET_GetFileDescriptorID(env); 128 CHECK_NULL(IO_fd_fdID); 129 130 initInetAddressIDs(env); 131 JNU_CHECK_EXCEPTION(env); 132 marker_fd = getMarkerFD(); 133 } 134 135 JNIEXPORT jboolean JNICALL 136 Java_rdma_ch_LinuxRdmaSocketImpl_isRdmaAvailable0(JNIEnv *env, 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_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketCreate(JNIEnv *env, jobject this, 153 jboolean stream, jobject impl) { 154 jobject fdObj, ssObj; 155 int fd; 156 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); 157 int domain = ipv6_available() ? 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 = rsocket(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 (rsetsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, 180 sizeof(int)) < 0) { 181 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6"); 182 rclose(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 rclose(fd); 195 return; 196 } 197 } 198 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); 199 } 200 201 JNIEXPORT void JNICALL 202 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketConnect(JNIEnv *env, jobject this, jobject impl, 203 jobject iaObj, jint port, 204 jint timeout) 205 { 206 jint localport = (*env)->GetIntField(env, impl, psi_localportID); 207 int len = 0; 208 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 209 210 jobject fdLock; 211 212 jint trafficClass = (*env)->GetIntField(env, impl, psi_trafficClassID); 213 214 jint fd; 215 216 SOCKETADDRESS sa; 217 int connect_rv = -1; 218 219 if (IS_NULL(fdObj)) { 220 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 221 return; 222 } else { 223 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 224 } 225 if (IS_NULL(iaObj)) { 226 JNU_ThrowNullPointerException(env, "inet address argument null."); 227 return; 228 } 229 230 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len, 231 JNI_TRUE) != 0) { 232 return; 233 } 234 235 if (trafficClass != 0 && ipv6_available()) { 236 NET_SetTrafficClass(&sa, trafficClass); 237 } 238 239 if (timeout <= 0) { 240 connect_rv = RDMA_Connect(fd, &sa.sa, len); 241 } else { 242 SET_NONBLOCKING(fd); 243 244 connect_rv = rconnect(fd, &sa.sa, len); 245 246 if (connect_rv != 0) { 247 socklen_t optlen; 248 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; 249 jlong prevNanoTime = JVM_NanoTime(env, 0); 250 251 if (errno != EINPROGRESS) { 252 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "ConnectException", 253 "connect failed"); 254 SET_BLOCKING(fd); 255 return; 256 } 257 258 while (1) { 259 jlong newNanoTime; 260 struct pollfd pfd; 261 pfd.fd = fd; 262 pfd.events = POLLOUT; 263 264 errno = 0; 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 rshutdown(fd, 2); 290 return; 291 } 292 293 optlen = sizeof(connect_rv); 294 if (rgetsockopt(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 (rgetsockname(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_rdma_ch_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 (rgetsockname(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_rdma_ch_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 = rlisten(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_rdma_ch_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 rclose(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_rdma_ch_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_rdma_ch_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_rdma_ch_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 rshutdown(fd, howto); 616 } 617 618 619 JNIEXPORT void JNICALL 620 Java_rdma_ch_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 case java_net_SocketOptions_SO_LINGER : 650 { 651 jclass cls; 652 jfieldID fid; 653 654 cls = (*env)->FindClass(env, "java/lang/Integer"); 655 CHECK_NULL(cls); 656 fid = (*env)->GetFieldID(env, cls, "value", "I"); 657 CHECK_NULL(fid); 658 659 optval.i = (*env)->GetIntField(env, value, fid); 660 optlen = sizeof(optval.i); 661 662 break; 663 } 664 665 default : 666 optval.i = (on ? 1 : 0); 667 optlen = sizeof(optval.i); 668 669 } 670 if (RDMA_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) { 671 JNU_ThrowByNameWithMessageAndLastError 672 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); 673 } 674 } 675 676 JNIEXPORT jint JNICALL 677 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketGetOption 678 (JNIEnv *env, jobject this, jobject impl, jint cmd, jobject iaContainerObj) 679 { 680 int fd; 681 int level, optname, optlen; 682 union { 683 int i; 684 struct linger ling; 685 } optval; 686 687 fd = getFD(env, impl); 688 if (fd < 0) { 689 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 690 "Socket closed"); 691 return -1; 692 } 693 694 if (cmd == java_net_SocketOptions_SO_BINDADDR) { 695 SOCKETADDRESS sa; 696 socklen_t len = sizeof(SOCKETADDRESS); 697 int port; 698 jobject iaObj; 699 jclass iaCntrClass; 700 jfieldID iaFieldID; 701 702 if (rgetsockname(fd, &sa.sa, &len) < 0) { 703 JNU_ThrowByNameWithMessageAndLastError 704 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 705 return -1; 706 } 707 iaObj = NET_SockaddrToInetAddress(env, &sa, &port); 708 CHECK_NULL_RETURN(iaObj, -1); 709 710 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 711 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;"); 712 CHECK_NULL_RETURN(iaFieldID, -1); 713 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 714 return 0; 715 } 716 717 if (RDMA_MapSocketOption(cmd, &level, &optname)) { 718 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 719 return -1; 720 } 721 722 optlen = sizeof(optval.i); 723 724 if (RDMA_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 725 JNU_ThrowByNameWithMessageAndLastError 726 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option"); 727 return -1; 728 } 729 730 switch (cmd) { 731 case java_net_SocketOptions_SO_SNDBUF: 732 case java_net_SocketOptions_SO_RCVBUF: 733 return optval.i; 734 735 default : 736 return (optval.i == 0) ? -1 : 1; 737 } 738 } 739 740 JNIEXPORT void JNICALL 741 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketSendUrgentData(JNIEnv *env, jobject this, jobject impl, 742 jint data) { 743 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 744 int n, fd; 745 unsigned char d = data & 0xFF; 746 747 if (IS_NULL(fdObj)) { 748 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 749 return; 750 } else { 751 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 752 if (fd == -1) { 753 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 754 return; 755 } 756 757 } 758 n = RDMA_Send(fd, (char *)&d, 1, MSG_OOB); 759 if (n == -1) { 760 JNU_ThrowIOExceptionWithLastError(env, "Write failed"); 761 } 762 }