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