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 }