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 }