1 /*
   2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 #include <errno.h>
  26 
  27 #include "jvm.h"
  28 #include "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 
 744     jint ret = -1;
 745     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 746     jint fd;
 747 
 748     if (IS_NULL(fdObj)) {
 749         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 750                         "Socket closed");
 751         return -1;
 752     } else {
 753         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 754     }
 755     /* NET_SocketAvailable returns 0 for failure, 1 for success */
 756     if (NET_SocketAvailable(fd, &ret) == 0){
 757         if (errno == ECONNRESET) {
 758             JNU_ThrowByName(env, "sun/net/ConnectionResetException", "");
 759         } else {
 760             JNU_ThrowByNameWithMessageAndLastError
 761                 (env, JNU_JAVANETPKG "SocketException", "ioctl FIONREAD failed");
 762         }
 763     }
 764     return ret;
 765 }
 766 
 767 /*
 768  * Class:     java_net_PlainSocketImpl
 769  * Method:    socketClose0
 770  * Signature: (Z)V
 771  */
 772 JNIEXPORT void JNICALL
 773 Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
 774                                           jboolean useDeferredClose) {
 775 
 776     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 777     jint fd;
 778 
 779     if (IS_NULL(fdObj)) {
 780         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 781                         "socket already closed");
 782         return;
 783     } else {
 784         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 785     }
 786     if (fd != -1) {
 787         if (useDeferredClose && marker_fd >= 0) {
 788             NET_Dup2(marker_fd, fd);
 789         } else {
 790             (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
 791             NET_SocketClose(fd);
 792         }
 793     }
 794 }
 795 
 796 /*
 797  * Class:     java_net_PlainSocketImpl
 798  * Method:    socketShutdown
 799  * Signature: (I)V
 800  */
 801 JNIEXPORT void JNICALL
 802 Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
 803                                              jint howto)
 804 {
 805 
 806     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 807     jint fd;
 808 
 809     /*
 810      * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
 811      * -1 already?
 812      */
 813     if (IS_NULL(fdObj)) {
 814         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 815                         "socket already closed");
 816         return;
 817     } else {
 818         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 819     }
 820     shutdown(fd, howto);
 821 }
 822 
 823 
 824 /*
 825  * Class:     java_net_PlainSocketImpl
 826  * Method:    socketSetOption0
 827  * Signature: (IZLjava/lang/Object;)V
 828  */
 829 JNIEXPORT void JNICALL
 830 Java_java_net_PlainSocketImpl_socketSetOption0
 831   (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value)
 832 {
 833     int fd;
 834     int level, optname, optlen;
 835     union {
 836         int i;
 837         struct linger ling;
 838     } optval;
 839 
 840     /*
 841      * Check that socket hasn't been closed
 842      */
 843     fd = getFD(env, this);
 844     if (fd < 0) {
 845         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 846                         "Socket closed");
 847         return;
 848     }
 849 
 850     /*
 851      * SO_TIMEOUT is a NOOP on Solaris/Linux
 852      */
 853     if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
 854         return;
 855     }
 856 
 857     /*
 858      * Map the Java level socket option to the platform specific
 859      * level and option name.
 860      */
 861     if (NET_MapSocketOption(cmd, &level, &optname)) {
 862         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 863         return;
 864     }
 865 
 866     switch (cmd) {
 867         case java_net_SocketOptions_SO_SNDBUF :
 868         case java_net_SocketOptions_SO_RCVBUF :
 869         case java_net_SocketOptions_SO_LINGER :
 870         case java_net_SocketOptions_IP_TOS :
 871             {
 872                 jclass cls;
 873                 jfieldID fid;
 874 
 875                 cls = (*env)->FindClass(env, "java/lang/Integer");
 876                 CHECK_NULL(cls);
 877                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 878                 CHECK_NULL(fid);
 879 
 880                 if (cmd == java_net_SocketOptions_SO_LINGER) {
 881                     if (on) {
 882                         optval.ling.l_onoff = 1;
 883                         optval.ling.l_linger = (*env)->GetIntField(env, value, fid);
 884                     } else {
 885                         optval.ling.l_onoff = 0;
 886                         optval.ling.l_linger = 0;
 887                     }
 888                     optlen = sizeof(optval.ling);
 889                 } else {
 890                     optval.i = (*env)->GetIntField(env, value, fid);
 891                     optlen = sizeof(optval.i);
 892                 }
 893 
 894                 break;
 895             }
 896 
 897         /* Boolean -> int */
 898         default :
 899             optval.i = (on ? 1 : 0);
 900             optlen = sizeof(optval.i);
 901 
 902     }
 903 
 904     if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
 905 #if defined(__solaris__) || defined(_AIX)
 906         if (errno == EINVAL) {
 907             // On Solaris setsockopt will set errno to EINVAL if the socket
 908             // is closed. The default error message is then confusing
 909             char fullMsg[128];
 910             jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer");
 911             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
 912             return;
 913         }
 914 #endif /* __solaris__ */
 915         JNU_ThrowByNameWithMessageAndLastError
 916             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
 917     }
 918 }
 919 
 920 /*
 921  * Class:     java_net_PlainSocketImpl
 922  * Method:    socketGetOption
 923  * Signature: (ILjava/lang/Object;)I
 924  */
 925 JNIEXPORT jint JNICALL
 926 Java_java_net_PlainSocketImpl_socketGetOption
 927   (JNIEnv *env, jobject this, jint cmd, jobject iaContainerObj)
 928 {
 929     int fd;
 930     int level, optname, optlen;
 931     union {
 932         int i;
 933         struct linger ling;
 934     } optval;
 935 
 936     /*
 937      * Check that socket hasn't been closed
 938      */
 939     fd = getFD(env, this);
 940     if (fd < 0) {
 941         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 942                         "Socket closed");
 943         return -1;
 944     }
 945 
 946     /*
 947      * SO_BINDADDR isn't a socket option
 948      */
 949     if (cmd == java_net_SocketOptions_SO_BINDADDR) {
 950         SOCKETADDRESS sa;
 951         socklen_t len = sizeof(SOCKETADDRESS);
 952         int port;
 953         jobject iaObj;
 954         jclass iaCntrClass;
 955         jfieldID iaFieldID;
 956 
 957         if (getsockname(fd, &sa.sa, &len) < 0) {
 958             JNU_ThrowByNameWithMessageAndLastError
 959                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
 960             return -1;
 961         }
 962         iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
 963         CHECK_NULL_RETURN(iaObj, -1);
 964 
 965         iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
 966         iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
 967         CHECK_NULL_RETURN(iaFieldID, -1);
 968         (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
 969         return 0; /* notice change from before */
 970     }
 971 
 972     /*
 973      * Map the Java level socket option to the platform specific
 974      * level and option name.
 975      */
 976     if (NET_MapSocketOption(cmd, &level, &optname)) {
 977         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 978         return -1;
 979     }
 980 
 981     /*
 982      * Args are int except for SO_LINGER
 983      */
 984     if (cmd == java_net_SocketOptions_SO_LINGER) {
 985         optlen = sizeof(optval.ling);
 986     } else {
 987         optlen = sizeof(optval.i);
 988     }
 989 
 990     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
 991         JNU_ThrowByNameWithMessageAndLastError
 992             (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
 993         return -1;
 994     }
 995 
 996     switch (cmd) {
 997         case java_net_SocketOptions_SO_LINGER:
 998             return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
 999 
1000         case java_net_SocketOptions_SO_SNDBUF:
1001         case java_net_SocketOptions_SO_RCVBUF:
1002         case java_net_SocketOptions_IP_TOS:
1003             return optval.i;
1004 
1005         default :
1006             return (optval.i == 0) ? -1 : 1;
1007     }
1008 }
1009 
1010 
1011 /*
1012  * Class:     java_net_PlainSocketImpl
1013  * Method:    socketSendUrgentData
1014  * Signature: (B)V
1015  */
1016 JNIEXPORT void JNICALL
1017 Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
1018                                              jint data) {
1019     /* The fd field */
1020     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1021     int n, fd;
1022     unsigned char d = data & 0xFF;
1023 
1024     if (IS_NULL(fdObj)) {
1025         JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1026         return;
1027     } else {
1028         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1029         /* Bug 4086704 - If the Socket associated with this file descriptor
1030          * was closed (sysCloseFD), the file descriptor is set to -1.
1031          */
1032         if (fd == -1) {
1033             JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1034             return;
1035         }
1036 
1037     }
1038     n = NET_Send(fd, (char *)&d, 1, MSG_OOB);
1039     if (n == -1) {
1040         JNU_ThrowIOExceptionWithLastError(env, "Write failed");
1041     }
1042 }