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