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 266 connect_rv = RDMA_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC); 267 268 if (connect_rv >= 0) { 269 break; 270 } 271 if (errno != EINTR) { 272 break; 273 } 274 275 newNanoTime = JVM_NanoTime(env, 0); 276 nanoTimeout -= (newNanoTime - prevNanoTime); 277 if (nanoTimeout < NET_NSEC_PER_MSEC) { 278 connect_rv = 0; 279 break; 280 } 281 prevNanoTime = newNanoTime; 282 283 } 284 285 if (connect_rv == 0) { 286 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 287 "connect timed out"); 288 289 SET_BLOCKING(fd); 290 rshutdown(fd, 2); 291 return; 292 } 293 294 optlen = sizeof(connect_rv); 295 if (rgetsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, 296 &optlen) <0) { 297 connect_rv = errno; 298 } 299 } 300 301 SET_BLOCKING(fd); 302 303 if (connect_rv != 0) { 304 errno = connect_rv; 305 connect_rv = -1; 306 } 307 } 308 309 if (connect_rv < 0) { 310 if (connect_rv == -1 && errno == EINVAL) { 311 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 312 "Invalid argument or cannot assign requested address"); 313 return; 314 } 315 #if defined(EPROTO) 316 if (errno == EPROTO) { 317 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "ProtocolException", 318 "Protocol error"); 319 return; 320 } 321 #endif 322 if (errno == ECONNREFUSED) { 323 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "ConnectException", 324 "Connection refused"); 325 } else if (errno == ETIMEDOUT) { 326 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "ConnectException", 327 "Connection timed out"); 328 } else if (errno == EHOSTUNREACH) { 329 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "NoRouteToHostException", 330 "Host unreachable"); 331 } else if (errno == EADDRNOTAVAIL) { 332 JNU_ThrowByNameWithMessageAndLastError(env, 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 339 (env, 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 (rgetsockname(fd, &sa.sa, &slen) == -1) { 352 JNU_ThrowByNameWithMessageAndLastError 353 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 354 } else { 355 localport = NET_GetPortFromSockaddr(&sa); 356 (*env)->SetIntField(env, impl, psi_localportID, localport); 357 } 358 } 359 } 360 361 JNIEXPORT void JNICALL 362 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketBind(JNIEnv *env, jobject this, jobject impl, 363 jobject iaObj, jint localport) { 364 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 365 int fd; 366 int len = 0; 367 SOCKETADDRESS sa; 368 369 if (IS_NULL(fdObj)) { 370 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 371 "Socket closed"); 372 return; 373 } else { 374 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 375 } 376 if (IS_NULL(iaObj)) { 377 JNU_ThrowNullPointerException(env, "iaObj is null."); 378 return; 379 } 380 381 if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, 382 &len, JNI_TRUE) != 0) { 383 return; 384 } 385 386 if (RDMA_Bind(fd, &sa, len) < 0) { 387 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL || 388 errno == EPERM || errno == EACCES) { 389 JNU_ThrowByNameWithMessageAndLastError(env, JNU_JAVANETPKG "BindException", 390 "Bind failed"); 391 } else { 392 JNU_ThrowByNameWithMessageAndLastError 393 (env, JNU_JAVANETPKG "SocketException", "Bind failed"); 394 } 395 return; 396 } 397 (*env)->SetObjectField(env, impl, psi_addressID, iaObj); 398 399 if (localport == 0) { 400 socklen_t slen = sizeof(SOCKETADDRESS); 401 if (rgetsockname(fd, &sa.sa, &slen) == -1) { 402 JNU_ThrowByNameWithMessageAndLastError 403 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 404 return; 405 } 406 localport = NET_GetPortFromSockaddr(&sa); 407 (*env)->SetIntField(env, impl, psi_localportID, localport); 408 } else { 409 (*env)->SetIntField(env, impl, psi_localportID, localport); 410 } 411 } 412 413 JNIEXPORT void JNICALL 414 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketListen(JNIEnv *env, jobject this, jobject impl, 415 jint count) 416 { 417 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 418 int fd; 419 420 if (IS_NULL(fdObj)) { 421 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 422 "Socket closed"); 423 return; 424 } else { 425 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 426 } 427 428 if (count == 0x7fffffff) 429 count -= 1; 430 431 int rv = rlisten(fd, count); 432 if (rv == -1) { 433 JNU_ThrowByNameWithMessageAndLastError 434 (env, JNU_JAVANETPKG "SocketException", "Listen failed"); 435 } 436 } 437 438 JNIEXPORT void JNICALL 439 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketAccept(JNIEnv *env, jobject this, jobject socket, jobject impl) 440 { 441 int port; 442 jint timeout = (*env)->GetIntField(env, impl, psi_timeoutID); 443 jlong prevNanoTime = 0; 444 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; 445 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 446 447 jobject socketFdObj; 448 jobject socketAddressObj; 449 450 jint fd; 451 452 jint newfd; 453 454 SOCKETADDRESS sa; 455 socklen_t slen = sizeof(SOCKETADDRESS); 456 457 if (IS_NULL(fdObj)) { 458 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 459 "Socket closed"); 460 return; 461 } else { 462 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 463 } 464 if (IS_NULL(socket)) { 465 JNU_ThrowNullPointerException(env, "socket is null"); 466 return; 467 } 468 469 for (;;) { 470 int ret; 471 jlong currNanoTime; 472 473 if (prevNanoTime == 0 && nanoTimeout > 0) { 474 prevNanoTime = JVM_NanoTime(env, 0); 475 } 476 477 if (timeout <= 0) { 478 ret = RDMA_Timeout(env, fd, -1, 0); 479 } else { 480 ret = RDMA_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, prevNanoTime); 481 } 482 483 if (ret == 0) { 484 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 485 "Accept timed out"); 486 return; 487 } else if (ret == -1) { 488 if (errno == EBADF) { 489 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 490 } else if (errno == ENOMEM) { 491 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed"); 492 } else { 493 JNU_ThrowByNameWithMessageAndLastError 494 (env, JNU_JAVANETPKG "SocketException", "Accept failed"); 495 } 496 return; 497 } 498 499 newfd = RDMA_Accept(fd, &sa.sa, &slen); 500 501 if (newfd >= 0) { 502 SET_BLOCKING(newfd); 503 break; 504 } 505 506 if (!(errno == ECONNABORTED || errno == EWOULDBLOCK)) { 507 break; 508 } 509 510 if (nanoTimeout >= NET_NSEC_PER_MSEC) { 511 currNanoTime = JVM_NanoTime(env, 0); 512 nanoTimeout -= (currNanoTime - prevNanoTime); 513 if (nanoTimeout < NET_NSEC_PER_MSEC) { 514 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", 515 "Accept timed out"); 516 return; 517 } 518 prevNanoTime = currNanoTime; 519 } 520 } 521 522 if (newfd < 0) { 523 if (newfd == -2) { 524 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 525 "operation interrupted"); 526 } else { 527 if (errno == EINVAL) { 528 errno = EBADF; 529 } 530 if (errno == EBADF) { 531 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); 532 } else { 533 JNU_ThrowByNameWithMessageAndLastError 534 (env, JNU_JAVANETPKG "SocketException", "Accept failed"); 535 } 536 } 537 return; 538 } 539 540 socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port); 541 if (socketAddressObj == NULL) { 542 rclose(newfd); 543 return; 544 } 545 546 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID); 547 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd); 548 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); 549 (*env)->SetIntField(env, socket, psi_portID, port); 550 port = (*env)->GetIntField(env, impl, psi_localportID); 551 (*env)->SetIntField(env, socket, psi_localportID, port); 552 } 553 554 555 JNIEXPORT jint JNICALL 556 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketAvailable(JNIEnv *env, jobject this, jobject impl) { 557 jint ret = -1; 558 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 559 jint fd; 560 561 if (IS_NULL(fdObj)) { 562 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 563 "Socket closed"); 564 return -1; 565 } else { 566 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 567 } 568 if (RDMA_SocketAvailable(fd, &ret) == 0){ 569 if (errno == ECONNRESET) { 570 JNU_ThrowByName(env, "sun/net/ConnectionResetException", ""); 571 } else { 572 JNU_ThrowByNameWithMessageAndLastError 573 (env, JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed"); 574 } 575 } 576 return ret; 577 } 578 579 JNIEXPORT void JNICALL 580 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketClose(JNIEnv *env, jobject this, 581 jboolean useDeferredClose, jobject impl) { 582 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 583 jint fd; 584 585 if (IS_NULL(fdObj)) { 586 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 587 "socket already closed"); 588 return; 589 } else { 590 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 591 } 592 if (fd != -1) { 593 if (useDeferredClose && marker_fd >= 0) { 594 RDMA_Dup2(marker_fd, fd); 595 } else { 596 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1); 597 RDMA_SocketClose(fd); 598 } 599 } 600 } 601 602 JNIEXPORT void JNICALL 603 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketShutdown(JNIEnv *env, jobject this, 604 jint howto, jobject impl) 605 { 606 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 607 jint fd; 608 609 if (IS_NULL(fdObj)) { 610 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 611 "socket already closed"); 612 return; 613 } else { 614 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 615 } 616 rshutdown(fd, howto); 617 } 618 619 620 JNIEXPORT void JNICALL 621 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketSetOption 622 (JNIEnv *env, jobject this, jobject impl, jint cmd, jboolean on, jobject value) 623 { 624 int fd; 625 int level, optname, optlen; 626 union { 627 int i; 628 struct linger ling; 629 } optval; 630 631 fd = getFD(env, impl); 632 if (fd < 0) { 633 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 634 "Socket closed"); 635 return; 636 } 637 638 if (cmd == java_net_SocketOptions_SO_TIMEOUT) { 639 return; 640 } 641 642 if (RDMA_MapSocketOption(cmd, &level, &optname)) { 643 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 644 return; 645 } 646 647 switch (cmd) { 648 case java_net_SocketOptions_SO_SNDBUF : 649 case java_net_SocketOptions_SO_RCVBUF : 650 case java_net_SocketOptions_SO_LINGER : 651 { 652 jclass cls; 653 jfieldID fid; 654 655 cls = (*env)->FindClass(env, "java/lang/Integer"); 656 CHECK_NULL(cls); 657 fid = (*env)->GetFieldID(env, cls, "value", "I"); 658 CHECK_NULL(fid); 659 660 if (cmd == java_net_SocketOptions_SO_LINGER) { 661 if (on) { 662 optval.ling.l_onoff = 1; 663 optval.ling.l_linger = (*env)->GetIntField(env, value, fid); 664 } else { 665 optval.ling.l_onoff = 0; 666 optval.ling.l_linger = 0; 667 } 668 optlen = sizeof(optval.ling); 669 } else { 670 optval.i = (*env)->GetIntField(env, value, fid); 671 optlen = sizeof(optval.i); 672 } 673 674 break; 675 } 676 677 default : 678 optval.i = (on ? 1 : 0); 679 optlen = sizeof(optval.i); 680 681 } 682 if (RDMA_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) { 683 JNU_ThrowByNameWithMessageAndLastError 684 (env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); 685 } 686 } 687 688 JNIEXPORT jint JNICALL 689 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketGetOption 690 (JNIEnv *env, jobject this, jobject impl, jint cmd, jobject iaContainerObj) 691 { 692 int fd; 693 int level, optname, optlen; 694 union { 695 int i; 696 struct linger ling; 697 } optval; 698 699 fd = getFD(env, impl); 700 if (fd < 0) { 701 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 702 "Socket closed"); 703 return -1; 704 } 705 706 if (cmd == java_net_SocketOptions_SO_BINDADDR) { 707 SOCKETADDRESS sa; 708 socklen_t len = sizeof(SOCKETADDRESS); 709 int port; 710 jobject iaObj; 711 jclass iaCntrClass; 712 jfieldID iaFieldID; 713 714 if (rgetsockname(fd, &sa.sa, &len) < 0) { 715 JNU_ThrowByNameWithMessageAndLastError 716 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name"); 717 return -1; 718 } 719 iaObj = NET_SockaddrToInetAddress(env, &sa, &port); 720 CHECK_NULL_RETURN(iaObj, -1); 721 722 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj); 723 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;"); 724 CHECK_NULL_RETURN(iaFieldID, -1); 725 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj); 726 return 0; 727 } 728 729 if (RDMA_MapSocketOption(cmd, &level, &optname)) { 730 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option"); 731 return -1; 732 } 733 734 /* 735 * Args are int except for SO_LINGER 736 */ 737 if (cmd == java_net_SocketOptions_SO_LINGER) { 738 optlen = sizeof(optval.ling); 739 } else { 740 optlen = sizeof(optval.i); 741 } 742 743 if (RDMA_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) { 744 JNU_ThrowByNameWithMessageAndLastError 745 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option"); 746 return -1; 747 } 748 749 switch (cmd) { 750 case java_net_SocketOptions_SO_LINGER: 751 return (optval.ling.l_onoff ? optval.ling.l_linger: -1); 752 753 case java_net_SocketOptions_SO_SNDBUF: 754 case java_net_SocketOptions_SO_RCVBUF: 755 return optval.i; 756 757 default : 758 return (optval.i == 0) ? -1 : 1; 759 } 760 } 761 762 JNIEXPORT void JNICALL 763 Java_rdma_ch_LinuxRdmaSocketImpl_rdmaSocketSendUrgentData(JNIEnv *env, jobject this, jobject impl, 764 jint data) { 765 jobject fdObj = (*env)->GetObjectField(env, impl, psi_fdID); 766 int n, fd; 767 unsigned char d = data & 0xFF; 768 769 if (IS_NULL(fdObj)) { 770 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 771 return; 772 } else { 773 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 774 if (fd == -1) { 775 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 776 return; 777 } 778 779 } 780 n = RDMA_Send(fd, (char *)&d, 1, MSG_OOB); 781 if (n == -1) { 782 JNU_ThrowIOExceptionWithLastError(env, "Write failed"); 783 } 784 }