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