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