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