1 /*
   2  * Copyright (c) 1997, 2019, 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 "net_util.h"
  29 
  30 #include "java_net_SocketOptions.h"
  31 #include "java_net_PlainSocketImpl.h"
  32 
  33 /************************************************************************
  34  * PlainSocketImpl
  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 extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him);
  51 
  52 /*
  53  * file descriptor used for dup2
  54  */
  55 static int marker_fd = -1;
  56 
  57 
  58 #define SET_NONBLOCKING(fd) {           \
  59         int flags = fcntl(fd, F_GETFL); \
  60         flags |= O_NONBLOCK;            \
  61         fcntl(fd, F_SETFL, flags);      \
  62 }
  63 
  64 #define SET_BLOCKING(fd) {              \
  65         int flags = fcntl(fd, F_GETFL); \
  66         flags &= ~O_NONBLOCK;           \
  67         fcntl(fd, F_SETFL, flags);      \
  68 }
  69 
  70 /*
  71  * Create the marker file descriptor by establishing a loopback connection
  72  * which we shutdown but do not close the fd. The result is an fd that
  73  * can be used for read/write.
  74  */
  75 static int getMarkerFD()
  76 {
  77     int sv[2];
  78 
  79 #ifdef AF_UNIX
  80     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
  81         return -1;
  82     }
  83 #else
  84     return -1;
  85 #endif
  86 
  87     /*
  88      * Finally shutdown sv[0] (any reads to this fd will get
  89      * EOF; any writes will get an error).
  90      */
  91     shutdown(sv[0], 2);
  92     close(sv[1]);
  93 
  94     return sv[0];
  95 }
  96 
  97 /*
  98  * Return the file descriptor given a PlainSocketImpl
  99  */
 100 static int getFD(JNIEnv *env, jobject this) {
 101     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 102     CHECK_NULL_RETURN(fdObj, -1);
 103     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 104 }
 105 
 106 /*
 107  * The initroto function is called whenever PlainSocketImpl is
 108  * loaded, to cache field IDs for efficiency. This is called every time
 109  * the Java class is loaded.
 110  *
 111  * Class:     java_net_PlainSocketImpl
 112  * Method:    initProto
 113  * Signature: ()V
 114  */
 115 JNIEXPORT void JNICALL
 116 Java_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) {
 117     psi_fdID = (*env)->GetFieldID(env, cls , "fd",
 118                                   "Ljava/io/FileDescriptor;");
 119     CHECK_NULL(psi_fdID);
 120     psi_addressID = (*env)->GetFieldID(env, cls, "address",
 121                                           "Ljava/net/InetAddress;");
 122     CHECK_NULL(psi_addressID);
 123     psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
 124     CHECK_NULL(psi_portID);
 125     psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
 126     CHECK_NULL(psi_localportID);
 127     psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
 128     CHECK_NULL(psi_timeoutID);
 129     psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
 130     CHECK_NULL(psi_trafficClassID);
 131     psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",
 132                         "Ljava/net/ServerSocket;");
 133     CHECK_NULL(psi_serverSocketID);
 134     psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock",
 135                                       "Ljava/lang/Object;");
 136     CHECK_NULL(psi_fdLockID);
 137     psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z");
 138     CHECK_NULL(psi_closePendingID);
 139     IO_fd_fdID = NET_GetFileDescriptorID(env);
 140     CHECK_NULL(IO_fd_fdID);
 141 
 142     initInetAddressIDs(env);
 143     JNU_CHECK_EXCEPTION(env);
 144 
 145     /* Create the marker fd used for dup2 */
 146     marker_fd = getMarkerFD();
 147 }
 148 
 149 /* a global reference to the java.net.SocketException class. In
 150  * socketCreate, we ensure that this is initialized. This is to
 151  * prevent the problem where socketCreate runs out of file
 152  * descriptors, and is then unable to load the exception class.
 153  */
 154 static jclass socketExceptionCls;
 155 
 156 /*
 157  * Class:     java_net_PlainSocketImpl
 158  * Method:    socketCreate
 159  * Signature: (Z)V */
 160 JNIEXPORT void JNICALL
 161 Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
 162                                            jboolean stream) {
 163     jobject fdObj, ssObj;
 164     int fd;
 165     int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
 166     int domain = ipv6_available() ? AF_INET6 : AF_INET;
 167 
 168     if (socketExceptionCls == NULL) {
 169         jclass c = (*env)->FindClass(env, "java/net/SocketException");
 170         CHECK_NULL(c);
 171         socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c);
 172         CHECK_NULL(socketExceptionCls);
 173     }
 174     fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 175 
 176     if (fdObj == NULL) {
 177         (*env)->ThrowNew(env, socketExceptionCls, "null fd object");
 178         return;
 179     }
 180 
 181     if ((fd = socket(domain, type, 0)) == -1) {
 182         /* note: if you run out of fds, you may not be able to load
 183          * the exception class, and get a NoClassDefFoundError
 184          * instead.
 185          */
 186         NET_ThrowNew(env, errno, "can't create socket");
 187         return;
 188     }
 189 
 190     /* Disable IPV6_V6ONLY to ensure dual-socket support */
 191     if (domain == AF_INET6) {
 192         int arg = 0;
 193         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
 194                        sizeof(int)) < 0) {
 195             NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
 196             close(fd);
 197             return;
 198         }
 199     }
 200 
 201     /*
 202      * If this is a server socket then enable SO_REUSEADDR
 203      * automatically and set to non blocking.
 204      */
 205     ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);
 206     if (ssObj != NULL) {
 207         int arg = 1;
 208         SET_NONBLOCKING(fd);
 209         if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
 210                        sizeof(arg)) < 0) {
 211             NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
 212             close(fd);
 213             return;
 214         }
 215     }
 216 
 217     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
 218 }
 219 
 220 /*
 221  * inetAddress is the address object passed to the socket connect
 222  * call.
 223  *
 224  * Class:     java_net_PlainSocketImpl
 225  * Method:    socketConnect
 226  * Signature: (Ljava/net/InetAddress;I)V
 227  */
 228 JNIEXPORT void JNICALL
 229 Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
 230                                             jobject iaObj, jint port,
 231                                             jint timeout)
 232 {
 233     jint localport = (*env)->GetIntField(env, this, psi_localportID);
 234     int len = 0;
 235     /* fdObj is the FileDescriptor field on this */
 236     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 237 
 238     jclass clazz = (*env)->GetObjectClass(env, this);
 239 
 240     jobject fdLock;
 241 
 242     jint trafficClass = (*env)->GetIntField(env, this, psi_trafficClassID);
 243 
 244     /* fd is an int field on iaObj */
 245     jint fd;
 246 
 247     SOCKETADDRESS sa;
 248     /* The result of the connection */
 249     int connect_rv = -1;
 250 
 251     if (IS_NULL(fdObj)) {
 252         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 253         return;
 254     } else {
 255         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 256     }
 257     if (IS_NULL(iaObj)) {
 258         JNU_ThrowNullPointerException(env, "inet address argument null.");
 259         return;
 260     }
 261 
 262     /* connect */
 263     if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len,
 264                                   JNI_TRUE) != 0) {
 265         return;
 266     }
 267     setDefaultScopeID(env, &sa.sa);
 268 
 269     if (trafficClass != 0 && ipv6_available()) {
 270         NET_SetTrafficClass(&sa, trafficClass);
 271     }
 272 
 273     if (timeout <= 0) {
 274         connect_rv = NET_Connect(fd, &sa.sa, len);
 275 #ifdef __solaris__
 276         if (connect_rv == -1 && errno == EINPROGRESS ) {
 277 
 278             /* This can happen if a blocking connect is interrupted by a signal.
 279              * See 6343810.
 280              */
 281             while (1) {
 282                 struct pollfd pfd;
 283                 pfd.fd = fd;
 284                 pfd.events = POLLOUT;
 285 
 286                 connect_rv = NET_Poll(&pfd, 1, -1);
 287 
 288                 if (connect_rv == -1) {
 289                     if (errno == EINTR) {
 290                         continue;
 291                     } else {
 292                         break;
 293                     }
 294                 }
 295                 if (connect_rv > 0) {
 296                     socklen_t optlen;
 297                     /* has connection been established */
 298                     optlen = sizeof(connect_rv);
 299                     if (getsockopt(fd, SOL_SOCKET, SO_ERROR,
 300                                    (void*)&connect_rv, &optlen) <0) {
 301                         connect_rv = errno;
 302                     }
 303 
 304                     if (connect_rv != 0) {
 305                         /* restore errno */
 306                         errno = connect_rv;
 307                         connect_rv = -1;
 308                     }
 309                     break;
 310                 }
 311             }
 312         }
 313 #endif
 314     } else {
 315         /*
 316          * A timeout was specified. We put the socket into non-blocking
 317          * mode, connect, and then wait for the connection to be
 318          * established, fail, or timeout.
 319          */
 320         SET_NONBLOCKING(fd);
 321 
 322         /* no need to use NET_Connect as non-blocking */
 323         connect_rv = connect(fd, &sa.sa, len);
 324 
 325         /* connection not established immediately */
 326         if (connect_rv != 0) {
 327             socklen_t optlen;
 328             jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
 329             jlong prevNanoTime = JVM_NanoTime(env, 0);
 330 
 331             if (errno != EINPROGRESS) {
 332                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 333                              "connect failed");
 334                 SET_BLOCKING(fd);
 335                 return;
 336             }
 337 
 338             /*
 339              * Wait for the connection to be established or a
 340              * timeout occurs. poll needs to handle EINTR in
 341              * case lwp sig handler redirects any process signals to
 342              * this thread.
 343              */
 344             while (1) {
 345                 jlong newNanoTime;
 346                 struct pollfd pfd;
 347                 pfd.fd = fd;
 348                 pfd.events = POLLOUT;
 349 
 350                 errno = 0;
 351                 connect_rv = NET_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC);
 352 
 353                 if (connect_rv >= 0) {
 354                     break;
 355                 }
 356                 if (errno != EINTR) {
 357                     break;
 358                 }
 359 
 360                 /*
 361                  * The poll was interrupted so adjust timeout and
 362                  * restart
 363                  */
 364                 newNanoTime = JVM_NanoTime(env, 0);
 365                 nanoTimeout -= (newNanoTime - prevNanoTime);
 366                 if (nanoTimeout < NET_NSEC_PER_MSEC) {
 367                     connect_rv = 0;
 368                     break;
 369                 }
 370                 prevNanoTime = newNanoTime;
 371 
 372             } /* while */
 373 
 374             if (connect_rv == 0) {
 375                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 376                             "connect timed out");
 377 
 378                 /*
 379                  * Timeout out but connection may still be established.
 380                  * At the high level it should be closed immediately but
 381                  * just in case we make the socket blocking again and
 382                  * shutdown input & output.
 383                  */
 384                 SET_BLOCKING(fd);
 385                 shutdown(fd, 2);
 386                 return;
 387             }
 388 
 389             /* has connection been established */
 390             optlen = sizeof(connect_rv);
 391             if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
 392                            &optlen) <0) {
 393                 connect_rv = errno;
 394             }
 395         }
 396 
 397         /* make socket blocking again */
 398         SET_BLOCKING(fd);
 399 
 400         /* restore errno */
 401         if (connect_rv != 0) {
 402             errno = connect_rv;
 403             connect_rv = -1;
 404         }
 405     }
 406 
 407     /* report the appropriate exception */
 408     if (connect_rv < 0) {
 409 
 410 #ifdef __linux__
 411         /*
 412          * Linux/GNU distribution setup /etc/hosts so that
 413          * InetAddress.getLocalHost gets back the loopback address
 414          * rather than the host address. Thus a socket can be
 415          * bound to the loopback address and the connect will
 416          * fail with EADDRNOTAVAIL. In addition the Linux kernel
 417          * returns the wrong error in this case - it returns EINVAL
 418          * instead of EADDRNOTAVAIL. We handle this here so that
 419          * a more descriptive exception text is used.
 420          */
 421         if (connect_rv == -1 && errno == EINVAL) {
 422             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 423                 "Invalid argument or cannot assign requested address");
 424             return;
 425         }
 426 #endif
 427 #if defined(EPROTO)
 428         if (errno == EPROTO) {
 429             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ProtocolException",
 430                            "Protocol error");
 431             return;
 432         }
 433 #endif
 434         if (errno == ECONNREFUSED) {
 435             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 436                            "Connection refused");
 437         } else if (errno == ETIMEDOUT) {
 438             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 439                            "Connection timed out");
 440         } else if (errno == EHOSTUNREACH) {
 441             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
 442                            "Host unreachable");
 443         } else if (errno == EADDRNOTAVAIL) {
 444             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
 445                              "Address not available");
 446         } else if ((errno == EISCONN) || (errno == EBADF)) {
 447             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 448                             "Socket closed");
 449         } else {
 450             JNU_ThrowByNameWithMessageAndLastError
 451                 (env, JNU_JAVANETPKG "SocketException", "connect failed");
 452         }
 453         return;
 454     }
 455 
 456     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
 457 
 458     /* set the remote peer address and port */
 459     (*env)->SetObjectField(env, this, psi_addressID, iaObj);
 460     (*env)->SetIntField(env, this, psi_portID, port);
 461 
 462     /*
 463      * we need to initialize the local port field if bind was called
 464      * previously to the connect (by the client) then localport field
 465      * will already be initialized
 466      */
 467     if (localport == 0) {
 468         /* Now that we're a connected socket, let's extract the port number
 469          * that the system chose for us and store it in the Socket object.
 470          */
 471         socklen_t slen = sizeof(SOCKETADDRESS);
 472         if (getsockname(fd, &sa.sa, &slen) == -1) {
 473             JNU_ThrowByNameWithMessageAndLastError
 474                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
 475         } else {
 476             localport = NET_GetPortFromSockaddr(&sa);
 477             (*env)->SetIntField(env, this, psi_localportID, localport);
 478         }
 479     }
 480 }
 481 
 482 /*
 483  * Class:     java_net_PlainSocketImpl
 484  * Method:    socketBind
 485  * Signature: (Ljava/net/InetAddress;I)V
 486  */
 487 JNIEXPORT void JNICALL
 488 Java_java_net_PlainSocketImpl_socketBind(JNIEnv *env, jobject this,
 489                                          jobject iaObj, jint localport) {
 490 
 491     /* fdObj is the FileDescriptor field on this */
 492     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 493     /* fd is an int field on fdObj */
 494     int fd;
 495     int len = 0;
 496     SOCKETADDRESS sa;
 497 
 498     if (IS_NULL(fdObj)) {
 499         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 500                         "Socket closed");
 501         return;
 502     } else {
 503         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 504     }
 505     if (IS_NULL(iaObj)) {
 506         JNU_ThrowNullPointerException(env, "iaObj is null.");
 507         return;
 508     }
 509 
 510     /* bind */
 511     if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa,
 512                                   &len, JNI_TRUE) != 0) {
 513         return;
 514     }
 515     setDefaultScopeID(env, &sa.sa);
 516 
 517     if (NET_Bind(fd, &sa, len) < 0) {
 518         if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
 519             errno == EPERM || errno == EACCES) {
 520             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
 521                            "Bind failed");
 522         } else {
 523             JNU_ThrowByNameWithMessageAndLastError
 524                 (env, JNU_JAVANETPKG "SocketException", "Bind failed");
 525         }
 526         return;
 527     }
 528 
 529     /* set the address */
 530     (*env)->SetObjectField(env, this, psi_addressID, iaObj);
 531 
 532     /* initialize the local port */
 533     if (localport == 0) {
 534         socklen_t slen = sizeof(SOCKETADDRESS);
 535         /* Now that we're a connected socket, let's extract the port number
 536          * that the system chose for us and store it in the Socket object.
 537          */
 538         if (getsockname(fd, &sa.sa, &slen) == -1) {
 539             JNU_ThrowByNameWithMessageAndLastError
 540                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
 541             return;
 542         }
 543         localport = NET_GetPortFromSockaddr(&sa);
 544         (*env)->SetIntField(env, this, psi_localportID, localport);
 545     } else {
 546         (*env)->SetIntField(env, this, psi_localportID, localport);
 547     }
 548 }
 549 
 550 /*
 551  * Class:     java_net_PlainSocketImpl
 552  * Method:    socketListen
 553  * Signature: (I)V
 554  */
 555 JNIEXPORT void JNICALL
 556 Java_java_net_PlainSocketImpl_socketListen(JNIEnv *env, jobject this,
 557                                            jint count)
 558 {
 559     /* this FileDescriptor fd field */
 560     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 561     /* fdObj's int fd field */
 562     int fd;
 563 
 564     if (IS_NULL(fdObj)) {
 565         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 566                         "Socket closed");
 567         return;
 568     } else {
 569         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 570     }
 571 
 572     /*
 573      * Workaround for bugid 4101691 in Solaris 2.6. See 4106600.
 574      * If listen backlog is Integer.MAX_VALUE then subtract 1.
 575      */
 576     if (count == 0x7fffffff)
 577         count -= 1;
 578 
 579     if (listen(fd, count) == -1) {
 580         JNU_ThrowByNameWithMessageAndLastError
 581             (env, JNU_JAVANETPKG "SocketException", "Listen failed");
 582     }
 583 }
 584 
 585 /*
 586  * Class:     java_net_PlainSocketImpl
 587  * Method:    socketAccept
 588  * Signature: (Ljava/net/SocketImpl;)V
 589  */
 590 JNIEXPORT void JNICALL
 591 Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
 592                                            jobject socket)
 593 {
 594     /* fields on this */
 595     int port;
 596     jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
 597     jlong prevNanoTime = 0;
 598     jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
 599     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 600 
 601     /* the FileDescriptor field on socket */
 602     jobject socketFdObj;
 603     /* the InetAddress field on socket */
 604     jobject socketAddressObj;
 605 
 606     /* the ServerSocket fd int field on fdObj */
 607     jint fd;
 608 
 609     /* accepted fd */
 610     jint newfd;
 611 
 612     SOCKETADDRESS sa;
 613     socklen_t slen = sizeof(SOCKETADDRESS);
 614 
 615     if (IS_NULL(fdObj)) {
 616         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 617                         "Socket closed");
 618         return;
 619     } else {
 620         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 621     }
 622     if (IS_NULL(socket)) {
 623         JNU_ThrowNullPointerException(env, "socket is null");
 624         return;
 625     }
 626 
 627     /*
 628      * accept connection but ignore ECONNABORTED indicating that
 629      * connection was eagerly accepted by the OS but was reset
 630      * before accept() was called.
 631      *
 632      * If accept timeout in place and timeout is adjusted with
 633      * each ECONNABORTED or EWOULDBLOCK or EAGAIN to ensure that
 634      * semantics of timeout are preserved.
 635      */
 636     for (;;) {
 637         int ret;
 638         jlong currNanoTime;
 639 
 640         /* first usage pick up current time */
 641         if (prevNanoTime == 0 && nanoTimeout > 0) {
 642             prevNanoTime = JVM_NanoTime(env, 0);
 643         }
 644 
 645         /* passing a timeout of 0 to poll will return immediately,
 646            but in the case of ServerSocket 0 means infinite. */
 647         if (timeout <= 0) {
 648             ret = NET_Timeout(env, fd, -1, 0);
 649         } else {
 650             ret = NET_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, prevNanoTime);
 651         }
 652         if (ret == 0) {
 653             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 654                             "Accept timed out");
 655             return;
 656         } else if (ret == -1) {
 657             if (errno == EBADF) {
 658                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 659             } else if (errno == ENOMEM) {
 660                JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
 661             } else {
 662                JNU_ThrowByNameWithMessageAndLastError
 663                    (env, JNU_JAVANETPKG "SocketException", "Accept failed");
 664             }
 665             return;
 666         }
 667 
 668         newfd = NET_Accept(fd, &sa.sa, &slen);
 669 
 670         /* connection accepted */
 671         if (newfd >= 0) {
 672             SET_BLOCKING(newfd);
 673             break;
 674         }
 675 
 676         /* non (ECONNABORTED or EWOULDBLOCK or EAGAIN) error */
 677         if (!(errno == ECONNABORTED || errno == EWOULDBLOCK || errno == EAGAIN)) {
 678             break;
 679         }
 680 
 681         /* ECONNABORTED or EWOULDBLOCK or EAGAIN error so adjust timeout if there is one. */
 682         if (nanoTimeout >= NET_NSEC_PER_MSEC) {
 683             currNanoTime = JVM_NanoTime(env, 0);
 684             nanoTimeout -= (currNanoTime - prevNanoTime);
 685             if (nanoTimeout < NET_NSEC_PER_MSEC) {
 686                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 687                         "Accept timed out");
 688                 return;
 689             }
 690             prevNanoTime = currNanoTime;
 691         }
 692     }
 693 
 694     if (newfd < 0) {
 695         if (newfd == -2) {
 696             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 697                             "operation interrupted");
 698         } else {
 699             if (errno == EINVAL) {
 700                 errno = EBADF;
 701             }
 702             if (errno == EBADF) {
 703                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 704             } else {
 705                 JNU_ThrowByNameWithMessageAndLastError
 706                     (env, JNU_JAVANETPKG "SocketException", "Accept failed");
 707             }
 708         }
 709         return;
 710     }
 711 
 712     /*
 713      * fill up the remote peer port and address in the new socket structure.
 714      */
 715     socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port);
 716     if (socketAddressObj == NULL) {
 717         /* should be pending exception */
 718         close(newfd);
 719         return;
 720     }
 721 
 722     /*
 723      * Populate SocketImpl.fd.fd
 724      */
 725     socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
 726     (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd);
 727 
 728     (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
 729     (*env)->SetIntField(env, socket, psi_portID, port);
 730     /* also fill up the local port information */
 731      port = (*env)->GetIntField(env, this, psi_localportID);
 732     (*env)->SetIntField(env, socket, psi_localportID, port);
 733 }
 734 
 735 
 736 /*
 737  * Class:     java_net_PlainSocketImpl
 738  * Method:    socketAvailable
 739  * Signature: ()I
 740  */
 741 JNIEXPORT jint JNICALL
 742 Java_java_net_PlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
 743     int count = 0;
 744     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 745     jint fd;
 746 
 747     if (IS_NULL(fdObj)) {
 748         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 749                         "Socket closed");
 750         return -1;
 751     } else {
 752         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 753     }
 754     if (NET_SocketAvailable(fd, &count) != 0) {
 755         if (errno == ECONNRESET) {
 756             JNU_ThrowByName(env, "sun/net/ConnectionResetException", "");
 757         } else {
 758             JNU_ThrowByNameWithMessageAndLastError
 759                 (env, JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed");
 760         }
 761     }
 762     return (jint) count;
 763 }
 764 
 765 /*
 766  * Class:     java_net_PlainSocketImpl
 767  * Method:    socketClose0
 768  * Signature: (Z)V
 769  */
 770 JNIEXPORT void JNICALL
 771 Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
 772                                           jboolean useDeferredClose) {
 773 
 774     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 775     jint fd;
 776 
 777     if (IS_NULL(fdObj)) {
 778         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 779                         "socket already closed");
 780         return;
 781     } else {
 782         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 783     }
 784     if (fd != -1) {
 785         if (useDeferredClose && marker_fd >= 0) {
 786             NET_Dup2(marker_fd, fd);
 787         } else {
 788             (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
 789             NET_SocketClose(fd);
 790         }
 791     }
 792 }
 793 
 794 /*
 795  * Class:     java_net_PlainSocketImpl
 796  * Method:    socketShutdown
 797  * Signature: (I)V
 798  */
 799 JNIEXPORT void JNICALL
 800 Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
 801                                              jint howto)
 802 {
 803 
 804     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 805     jint fd;
 806 
 807     /*
 808      * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
 809      * -1 already?
 810      */
 811     if (IS_NULL(fdObj)) {
 812         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 813                         "socket already closed");
 814         return;
 815     } else {
 816         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 817     }
 818     shutdown(fd, howto);
 819 }
 820 
 821 
 822 /*
 823  * Class:     java_net_PlainSocketImpl
 824  * Method:    socketSetOption0
 825  * Signature: (IZLjava/lang/Object;)V
 826  */
 827 JNIEXPORT void JNICALL
 828 Java_java_net_PlainSocketImpl_socketSetOption0
 829   (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value)
 830 {
 831     int fd;
 832     int level, optname, optlen;
 833     union {
 834         int i;
 835         struct linger ling;
 836     } optval;
 837 
 838     /*
 839      * Check that socket hasn't been closed
 840      */
 841     fd = getFD(env, this);
 842     if (fd < 0) {
 843         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 844                         "Socket closed");
 845         return;
 846     }
 847 
 848     /*
 849      * SO_TIMEOUT is a NOOP on Solaris/Linux
 850      */
 851     if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
 852         return;
 853     }
 854 
 855     /*
 856      * Map the Java level socket option to the platform specific
 857      * level and option name.
 858      */
 859     if (NET_MapSocketOption(cmd, &level, &optname)) {
 860         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 861         return;
 862     }
 863 
 864     switch (cmd) {
 865         case java_net_SocketOptions_SO_SNDBUF :
 866         case java_net_SocketOptions_SO_RCVBUF :
 867         case java_net_SocketOptions_SO_LINGER :
 868         case java_net_SocketOptions_IP_TOS :
 869             {
 870                 jclass cls;
 871                 jfieldID fid;
 872 
 873                 cls = (*env)->FindClass(env, "java/lang/Integer");
 874                 CHECK_NULL(cls);
 875                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 876                 CHECK_NULL(fid);
 877 
 878                 if (cmd == java_net_SocketOptions_SO_LINGER) {
 879                     if (on) {
 880                         optval.ling.l_onoff = 1;
 881                         optval.ling.l_linger = (*env)->GetIntField(env, value, fid);
 882                     } else {
 883                         optval.ling.l_onoff = 0;
 884                         optval.ling.l_linger = 0;
 885                     }
 886                     optlen = sizeof(optval.ling);
 887                 } else {
 888                     optval.i = (*env)->GetIntField(env, value, fid);
 889                     optlen = sizeof(optval.i);
 890                 }
 891 
 892                 break;
 893             }
 894 
 895         /* Boolean -> int */
 896         default :
 897             optval.i = (on ? 1 : 0);
 898             optlen = sizeof(optval.i);
 899 
 900     }
 901 
 902     if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
 903 #if defined(__solaris__) || defined(_AIX)
 904         if (errno == EINVAL) {
 905             // On Solaris setsockopt will set errno to EINVAL if the socket
 906             // is closed. The default error message is then confusing
 907             char fullMsg[128];
 908             jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer");
 909             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
 910             return;
 911         }
 912 #endif /* __solaris__ */
 913         JNU_ThrowByNameWithMessageAndLastError
 914             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
 915     }
 916 }
 917 
 918 /*
 919  * Class:     java_net_PlainSocketImpl
 920  * Method:    socketGetOption
 921  * Signature: (ILjava/lang/Object;)I
 922  */
 923 JNIEXPORT jint JNICALL
 924 Java_java_net_PlainSocketImpl_socketGetOption
 925   (JNIEnv *env, jobject this, jint cmd, jobject iaContainerObj)
 926 {
 927     int fd;
 928     int level, optname, optlen;
 929     union {
 930         int i;
 931         struct linger ling;
 932     } optval;
 933 
 934     /*
 935      * Check that socket hasn't been closed
 936      */
 937     fd = getFD(env, this);
 938     if (fd < 0) {
 939         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 940                         "Socket closed");
 941         return -1;
 942     }
 943 
 944     /*
 945      * SO_BINDADDR isn't a socket option
 946      */
 947     if (cmd == java_net_SocketOptions_SO_BINDADDR) {
 948         SOCKETADDRESS sa;
 949         socklen_t len = sizeof(SOCKETADDRESS);
 950         int port;
 951         jobject iaObj;
 952         jclass iaCntrClass;
 953         jfieldID iaFieldID;
 954 
 955         if (getsockname(fd, &sa.sa, &len) < 0) {
 956             JNU_ThrowByNameWithMessageAndLastError
 957                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
 958             return -1;
 959         }
 960         iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
 961         CHECK_NULL_RETURN(iaObj, -1);
 962 
 963         iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
 964         iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
 965         CHECK_NULL_RETURN(iaFieldID, -1);
 966         (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
 967         return 0; /* notice change from before */
 968     }
 969 
 970     /*
 971      * Map the Java level socket option to the platform specific
 972      * level and option name.
 973      */
 974     if (NET_MapSocketOption(cmd, &level, &optname)) {
 975         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 976         return -1;
 977     }
 978 
 979     /*
 980      * Args are int except for SO_LINGER
 981      */
 982     if (cmd == java_net_SocketOptions_SO_LINGER) {
 983         optlen = sizeof(optval.ling);
 984     } else {
 985         optlen = sizeof(optval.i);
 986     }
 987 
 988     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
 989         JNU_ThrowByNameWithMessageAndLastError
 990             (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
 991         return -1;
 992     }
 993 
 994     switch (cmd) {
 995         case java_net_SocketOptions_SO_LINGER:
 996             return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
 997 
 998         case java_net_SocketOptions_SO_SNDBUF:
 999         case java_net_SocketOptions_SO_RCVBUF:
1000         case java_net_SocketOptions_IP_TOS:
1001             return optval.i;
1002 
1003         default :
1004             return (optval.i == 0) ? -1 : 1;
1005     }
1006 }
1007 
1008 
1009 /*
1010  * Class:     java_net_PlainSocketImpl
1011  * Method:    socketSendUrgentData
1012  * Signature: (B)V
1013  */
1014 JNIEXPORT void JNICALL
1015 Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
1016                                              jint data) {
1017     /* The fd field */
1018     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1019     int n, fd;
1020     unsigned char d = data & 0xFF;
1021 
1022     if (IS_NULL(fdObj)) {
1023         JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1024         return;
1025     } else {
1026         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1027         /* Bug 4086704 - If the Socket associated with this file descriptor
1028          * was closed (sysCloseFD), the file descriptor is set to -1.
1029          */
1030         if (fd == -1) {
1031             JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1032             return;
1033         }
1034 
1035     }
1036     n = NET_Send(fd, (char *)&d, 1, MSG_OOB);
1037     if (n == -1) {
1038         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
1039     }
1040 }