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