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