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