1 /*
   2  * Copyright (c) 1997, 2011, 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 <windows.h>
  27 #include <winsock2.h>
  28 #include <ctype.h>
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <malloc.h>
  32 #include <sys/types.h>
  33 
  34 #include "java_net_SocketOptions.h"
  35 #include "java_net_TwoStacksPlainSocketImpl.h"
  36 #include "java_net_SocketImpl.h"
  37 #include "java_net_InetAddress.h"
  38 #include "java_io_FileDescriptor.h"
  39 #include "java_lang_Integer.h"
  40 
  41 #include "jvm.h"
  42 #include "net_util.h"
  43 #include "jni_util.h"
  44 
  45 /************************************************************************
  46  * TwoStacksPlainSocketImpl
  47  */
  48 
  49 static jfieldID IO_fd_fdID;
  50 
  51 jfieldID psi_fdID;
  52 jfieldID psi_fd1ID;
  53 jfieldID psi_addressID;
  54 jfieldID psi_portID;
  55 jfieldID psi_localportID;
  56 jfieldID psi_timeoutID;
  57 jfieldID psi_trafficClassID;
  58 jfieldID psi_serverSocketID;
  59 jfieldID psi_lastfdID;
  60 
  61 /*
  62  * the level of the TCP protocol for setsockopt and getsockopt
  63  * we only want to look this up once, from the static initializer
  64  * of TwoStacksPlainSocketImpl
  65  */
  66 static int tcp_level = -1;
  67 
  68 static int getFD(JNIEnv *env, jobject this) {
  69     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
  70 
  71     if (fdObj == NULL) {
  72         return -1;
  73     }
  74     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
  75 }
  76 
  77 static int getFD1(JNIEnv *env, jobject this) {
  78     jobject fdObj = (*env)->GetObjectField(env, this, psi_fd1ID);
  79 
  80     if (fdObj == NULL) {
  81         return -1;
  82     }
  83     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
  84 }
  85 
  86 
  87 /*
  88  * The initProto function is called whenever TwoStacksPlainSocketImpl is
  89  * loaded, to cache fieldIds for efficiency. This is called everytime
  90  * the Java class is loaded.
  91  *
  92  * Class:     java_net_TwoStacksPlainSocketImpl
  93  * Method:    initProto
  94 
  95  * Signature: ()V
  96  */
  97 JNIEXPORT void JNICALL
  98 Java_java_net_TwoStacksPlainSocketImpl_initProto(JNIEnv *env, jclass cls) {
  99 
 100     struct protoent *proto = getprotobyname("TCP");
 101     tcp_level = (proto == 0 ? IPPROTO_TCP: proto->p_proto);
 102 
 103     psi_fdID = (*env)->GetFieldID(env, cls , "fd", "Ljava/io/FileDescriptor;");
 104     CHECK_NULL(psi_fdID);
 105     psi_fd1ID =(*env)->GetFieldID(env, cls , "fd1", "Ljava/io/FileDescriptor;");
 106     CHECK_NULL(psi_fd1ID);
 107     psi_addressID = (*env)->GetFieldID(env, cls, "address",
 108                                           "Ljava/net/InetAddress;");
 109     CHECK_NULL(psi_addressID);
 110     psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
 111     CHECK_NULL(psi_portID);
 112     psi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I");
 113     CHECK_NULL(psi_portID);
 114     psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
 115     CHECK_NULL(psi_localportID);
 116     psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
 117     CHECK_NULL(psi_timeoutID);
 118     psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
 119     CHECK_NULL(psi_trafficClassID);
 120     psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",
 121                                             "Ljava/net/ServerSocket;");
 122     CHECK_NULL(psi_serverSocketID);
 123     IO_fd_fdID = NET_GetFileDescriptorID(env);
 124     CHECK_NULL(IO_fd_fdID);
 125 }
 126 
 127 /*
 128  * Class:     java_net_TwoStacksPlainSocketImpl
 129  * Method:    socketCreate
 130  * Signature: (Z)V
 131  */
 132 JNIEXPORT void JNICALL
 133 Java_java_net_TwoStacksPlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
 134                                            jboolean stream) {
 135     jobject fdObj, fd1Obj;
 136     int fd, fd1;
 137 
 138     fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 139 
 140     if (IS_NULL(fdObj)) {
 141         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 142                         "null fd object");
 143         return;
 144     }
 145     fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);
 146     if (fd == -1) {
 147         NET_ThrowCurrent(env, "create");
 148         return;
 149     } else {
 150         /* Set socket attribute so it is not passed to any child process */
 151         SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
 152         (*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd);
 153     }
 154     if (ipv6_available()) {
 155         fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 156 
 157         if (IS_NULL(fd1Obj)) {
 158             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 159                             "null fd1 object");
 160             (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
 161             NET_SocketClose(fd);
 162             return;
 163         }
 164         fd1 = socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);
 165         if (fd1 == -1) {
 166             NET_ThrowCurrent(env, "create");
 167             (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
 168             NET_SocketClose(fd);
 169             return;
 170         } else {
 171             /* Set socket attribute so it is not passed to any child process */
 172             SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
 173             (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
 174         }
 175     } else {
 176         (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
 177     }
 178 }
 179 
 180 /*
 181  * inetAddress is the address object passed to the socket connect
 182  * call.
 183  *
 184  * Class:     java_net_TwoStacksPlainSocketImpl
 185  * Method:    socketConnect
 186  * Signature: (Ljava/net/InetAddress;I)V
 187  */
 188 JNIEXPORT void JNICALL
 189 Java_java_net_TwoStacksPlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
 190                                             jobject iaObj, jint port,
 191                                             jint timeout)
 192 {
 193     jint localport = (*env)->GetIntField(env, this, psi_localportID);
 194 
 195     /* family and localport are int fields of iaObj */
 196     int family;
 197     jint fd, fd1=-1;
 198     jint len;
 199     int  ipv6_supported = ipv6_available();
 200 
 201     /* fd initially points to the IPv4 socket and fd1 to the IPv6 socket
 202      * If we want to connect to IPv6 then we swap the two sockets/objects
 203      * This way, fd is always the connected socket, and fd1 always gets closed.
 204      */
 205     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 206     jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 207 
 208     SOCKETADDRESS him;
 209 
 210     /* The result of the connection */
 211     int connect_res;
 212 
 213     if (!IS_NULL(fdObj)) {
 214         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 215     }
 216 
 217     if (ipv6_supported && !IS_NULL(fd1Obj)) {
 218         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 219     }
 220 
 221     if (IS_NULL(iaObj)) {
 222         JNU_ThrowNullPointerException(env, "inet address argument is null.");
 223         return;
 224     }
 225 
 226     if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&him, &len, JNI_FALSE) != 0) {
 227       return;
 228     }
 229 
 230     family = him.him.sa_family;
 231     if (family == AF_INET6) {
 232         if (!ipv6_supported) {
 233             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 234                             "Protocol family not supported");
 235             return;
 236         } else {
 237             if (fd1 == -1) {
 238                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 239                                 "Destination unreachable");
 240                 return;
 241             }
 242             /* close the v4 socket, and set fd to be the v6 socket */
 243             (*env)->SetObjectField(env, this, psi_fdID, fd1Obj);
 244             (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
 245             NET_SocketClose(fd);
 246             fd = fd1; fdObj = fd1Obj;
 247         }
 248     } else {
 249         if (fd1 != -1) {
 250             (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
 251             NET_SocketClose(fd1);
 252         }
 253         if (fd == -1) {
 254             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 255                             "Destination unreachable");
 256             return;
 257         }
 258     }
 259     (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
 260 
 261     if (timeout <= 0) {
 262         connect_res = connect(fd, (struct sockaddr *) &him, SOCKETADDRESS_LEN(&him));
 263         if (connect_res == SOCKET_ERROR) {
 264             connect_res = WSAGetLastError();
 265         }
 266     } else {
 267         int optval;
 268         int optlen = sizeof(optval);
 269 
 270         /* make socket non-blocking */
 271         optval = 1;
 272         ioctlsocket( fd, FIONBIO, &optval );
 273 
 274         /* initiate the connect */
 275         connect_res = connect(fd, (struct sockaddr *) &him, SOCKETADDRESS_LEN(&him));
 276         if (connect_res == SOCKET_ERROR) {
 277             if (WSAGetLastError() != WSAEWOULDBLOCK) {
 278                 connect_res = WSAGetLastError();
 279             } else {
 280                 fd_set wr, ex;
 281                 struct timeval t;
 282 
 283                 FD_ZERO(&wr);
 284                 FD_ZERO(&ex);
 285                 FD_SET(fd, &wr);
 286                 FD_SET(fd, &ex);
 287                 t.tv_sec = timeout / 1000;
 288                 t.tv_usec = (timeout % 1000) * 1000;
 289 
 290                 /*
 291                  * Wait for timout, connection established or
 292                  * connection failed.
 293                  */
 294                 connect_res = select(fd+1, 0, &wr, &ex, &t);
 295 
 296                 /*
 297                  * Timeout before connection is established/failed so
 298                  * we throw exception and shutdown input/output to prevent
 299                  * socket from being used.
 300                  * The socket should be closed immediately by the caller.
 301                  */
 302                 if (connect_res == 0) {
 303                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 304                                     "connect timed out");
 305                     shutdown( fd, SD_BOTH );
 306 
 307                      /* make socket blocking again - just in case */
 308                     optval = 0;
 309                     ioctlsocket( fd, FIONBIO, &optval );
 310                     return;
 311                 }
 312 
 313                 /*
 314                  * We must now determine if the connection has been established
 315                  * or if it has failed. The logic here is designed to work around
 316                  * bug on Windows NT whereby using getsockopt to obtain the
 317                  * last error (SO_ERROR) indicates there is no error. The workaround
 318                  * on NT is to allow winsock to be scheduled and this is done by
 319                  * yielding and retrying. As yielding is problematic in heavy
 320                  * load conditions we attempt up to 3 times to get the error reason.
 321                  */
 322                 if (!FD_ISSET(fd, &ex)) {
 323                     connect_res = 0;
 324                 } else {
 325                     int retry;
 326                     for (retry=0; retry<3; retry++) {
 327                         NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
 328                                        (char*)&connect_res, &optlen);
 329                         if (connect_res) {
 330                             break;
 331                         }
 332                         Sleep(0);
 333                     }
 334 
 335                     if (connect_res == 0) {
 336                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 337                                         "Unable to establish connection");
 338                         return;
 339                     }
 340                 }
 341             }
 342         }
 343 
 344         /* make socket blocking again */
 345         optval = 0;
 346         ioctlsocket(fd, FIONBIO, &optval);
 347     }
 348 
 349     if (connect_res) {
 350         if (connect_res == WSAEADDRNOTAVAIL) {
 351             JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
 352                 "connect: Address is invalid on local machine, or port is not valid on remote machine");
 353         } else {
 354             NET_ThrowNew(env, connect_res, "connect");
 355         }
 356         return;
 357     }
 358 
 359     (*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd);
 360 
 361     /* set the remote peer address and port */
 362     (*env)->SetObjectField(env, this, psi_addressID, iaObj);
 363     (*env)->SetIntField(env, this, psi_portID, port);
 364 
 365     /*
 366      * we need to initialize the local port field if bind was called
 367      * previously to the connect (by the client) then localport field
 368      * will already be initialized
 369      */
 370     if (localport == 0) {
 371         /* Now that we're a connected socket, let's extract the port number
 372          * that the system chose for us and store it in the Socket object.
 373          */
 374         u_short port;
 375         int len = SOCKETADDRESS_LEN(&him);
 376         if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
 377 
 378             if (WSAGetLastError() == WSAENOTSOCK) {
 379                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 380                         "Socket closed");
 381             } else {
 382                 NET_ThrowCurrent(env, "getsockname failed");
 383             }
 384             return;
 385         }
 386         port = ntohs ((u_short)GET_PORT(&him));
 387         (*env)->SetIntField(env, this, psi_localportID, (int) port);
 388     }
 389 }
 390 
 391 /*
 392  * Class:     java_net_TwoStacksPlainSocketImpl
 393  * Method:    socketBind
 394  * Signature: (Ljava/net/InetAddress;I)V
 395  */
 396 JNIEXPORT void JNICALL
 397 Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this,
 398                                          jobject iaObj, jint localport) {
 399 
 400     /* fdObj is the FileDescriptor field on this */
 401     jobject fdObj, fd1Obj;
 402     /* fd is an int field on fdObj */
 403     int fd, fd1, len;
 404     int ipv6_supported = ipv6_available();
 405 
 406     /* family is an int field of iaObj */
 407     int family;
 408     int rv;
 409 
 410     SOCKETADDRESS him;
 411 
 412     fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 413     fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 414 
 415     family = (*env)->GetIntField(env, iaObj, ia_familyID);
 416 
 417     if (family == IPv6 && !ipv6_supported) {
 418         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 419                         "Protocol family not supported");
 420         return;
 421     }
 422 
 423     if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
 424         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 425                         "Socket closed");
 426         return;
 427     } else {
 428         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 429         if (ipv6_supported) {
 430             fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 431         }
 432     }
 433     if (IS_NULL(iaObj)) {
 434         JNU_ThrowNullPointerException(env, "inet address argument");
 435         return;
 436     }
 437 
 438     if (NET_InetAddressToSockaddr(env, iaObj, localport,
 439                           (struct sockaddr *)&him, &len, JNI_FALSE) != 0) {
 440       return;
 441     }
 442 
 443     if (ipv6_supported) {
 444         struct ipv6bind v6bind;
 445         v6bind.addr = &him;
 446         v6bind.ipv4_fd = fd;
 447         v6bind.ipv6_fd = fd1;
 448         rv = NET_BindV6(&v6bind);
 449         if (rv != -1) {
 450             /* check if the fds have changed */
 451             if (v6bind.ipv4_fd != fd) {
 452                 fd = v6bind.ipv4_fd;
 453                 if (fd == -1) {
 454                     /* socket is closed. */
 455                     (*env)->SetObjectField(env, this, psi_fdID, NULL);
 456                 } else {
 457                     /* socket was re-created */
 458                     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
 459                 }
 460             }
 461             if (v6bind.ipv6_fd != fd1) {
 462                 fd1 = v6bind.ipv6_fd;
 463                 if (fd1 == -1) {
 464                     /* socket is closed. */
 465                     (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
 466                 } else {
 467                     /* socket was re-created */
 468                     (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
 469                 }
 470             }
 471         }
 472     } else {
 473         rv = NET_Bind(fd, (struct sockaddr *)&him, len);
 474     }
 475 
 476     if (rv == -1) {
 477         NET_ThrowCurrent(env, "JVM_Bind");
 478         return;
 479     }
 480 
 481     /* set the address */
 482     (*env)->SetObjectField(env, this, psi_addressID, iaObj);
 483 
 484     /* intialize the local port */
 485     if (localport == 0) {
 486         /* Now that we're a bound socket, let's extract the port number
 487          * that the system chose for us and store it in the Socket object.
 488          */
 489         int len = SOCKETADDRESS_LEN(&him);
 490         u_short port;
 491         fd = him.him.sa_family == AF_INET? fd: fd1;
 492 
 493         if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
 494             NET_ThrowCurrent(env, "getsockname in plain socketBind");
 495             return;
 496         }
 497         port = ntohs ((u_short) GET_PORT (&him));
 498 
 499         (*env)->SetIntField(env, this, psi_localportID, (int) port);
 500     } else {
 501         (*env)->SetIntField(env, this, psi_localportID, localport);
 502     }
 503 }
 504 
 505 /*
 506  * Class:     java_net_TwoStacksPlainSocketImpl
 507  * Method:    socketListen
 508  * Signature: (I)V
 509  */
 510 JNIEXPORT void JNICALL
 511 Java_java_net_TwoStacksPlainSocketImpl_socketListen (JNIEnv *env, jobject this,
 512                                             jint count)
 513 {
 514     /* this FileDescriptor fd field */
 515     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 516     jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 517     jobject address;
 518     /* fdObj's int fd field */
 519     int fd, fd1;
 520     SOCKETADDRESS addr; int addrlen;
 521 
 522     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 523         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 524                         "socket closed");
 525         return;
 526     }
 527 
 528     if (!IS_NULL(fdObj)) {
 529         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 530     }
 531     /* Listen on V4 if address type is v4 or if v6 and address is ::0.
 532      * Listen on V6 if address type is v6 or if v4 and address is 0.0.0.0.
 533      * In cases, where we listen on one space only, we close the other socket.
 534      */
 535     address = (*env)->GetObjectField(env, this, psi_addressID);
 536     if (IS_NULL(address)) {
 537         JNU_ThrowNullPointerException(env, "socket address");
 538         return;
 539     }
 540     if (NET_InetAddressToSockaddr(env, address, 0, (struct sockaddr *)&addr,
 541                                   &addrlen, JNI_FALSE) != 0) {
 542       return;
 543     }
 544 
 545     if (addr.him.sa_family == AF_INET || IN6ADDR_ISANY(&addr.him6)) {
 546         /* listen on v4 */
 547         if (listen(fd, count) == -1) {
 548             NET_ThrowCurrent(env, "listen failed");
 549         }
 550     } else {
 551         NET_SocketClose (fd);
 552         (*env)->SetObjectField(env, this, psi_fdID, NULL);
 553     }
 554     if (ipv6_available() && !IS_NULL(fd1Obj)) {
 555         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 556         if (addr.him.sa_family == AF_INET6 || addr.him4.sin_addr.s_addr == INADDR_ANY) {
 557             /* listen on v6 */
 558             if (listen(fd1, count) == -1) {
 559                 NET_ThrowCurrent(env, "listen failed");
 560             }
 561         } else {
 562             NET_SocketClose (fd1);
 563             (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
 564         }
 565     }
 566 }
 567 
 568 /*
 569  * Class:     java_net_TwoStacksPlainSocketImpl
 570  * Method:    socketAccept
 571  * Signature: (Ljava/net/SocketImpl;)V
 572  */
 573 JNIEXPORT void JNICALL
 574 Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
 575                                            jobject socket)
 576 {
 577     /* fields on this */
 578     jint port;
 579     jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
 580     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 581     jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 582 
 583     /* the FileDescriptor field on socket */
 584     jobject socketFdObj;
 585 
 586     /* cache the Inet4/6Address classes */
 587     static jclass inet4Cls;
 588     static jclass inet6Cls;
 589 
 590     /* the InetAddress field on socket */
 591     jobject socketAddressObj;
 592 
 593     /* the fd int field on fdObj */
 594     jint fd=-1, fd1=-1;
 595 
 596     SOCKETADDRESS him;
 597     jint len;
 598 
 599     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 600         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 601                         "Socket closed");
 602         return;
 603     }
 604     if (!IS_NULL(fdObj)) {
 605         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 606     }
 607     if (!IS_NULL(fd1Obj)) {
 608         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 609     }
 610     if (IS_NULL(socket)) {
 611         JNU_ThrowNullPointerException(env, "socket is null");
 612         return;
 613     } else {
 614         socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
 615         socketAddressObj = (*env)->GetObjectField(env, socket, psi_addressID);
 616     }
 617     if ((IS_NULL(socketAddressObj)) || (IS_NULL(socketFdObj))) {
 618         JNU_ThrowNullPointerException(env, "socket address or fd obj");
 619         return;
 620     }
 621     if (fd != -1 && fd1 != -1) {
 622         fd_set rfds;
 623         struct timeval t, *tP=&t;
 624         int lastfd, res, fd2;
 625         FD_ZERO(&rfds);
 626         FD_SET(fd,&rfds);
 627         FD_SET(fd1,&rfds);
 628         if (timeout) {
 629             t.tv_sec = timeout/1000;
 630             t.tv_usec = (timeout%1000)*1000;
 631         } else {
 632             tP = NULL;
 633         }
 634         res = select (fd, &rfds, NULL, NULL, tP);
 635         if (res == 0) {
 636             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 637                             "Accept timed out");
 638             return;
 639         } else if (res == 1) {
 640             fd2 = FD_ISSET(fd, &rfds)? fd: fd1;
 641         } else if (res == 2) {
 642             /* avoid starvation */
 643             lastfd = (*env)->GetIntField(env, this, psi_lastfdID);
 644             if (lastfd != -1) {
 645                 fd2 = lastfd==fd? fd1: fd;
 646             } else {
 647                 fd2 = fd;
 648             }
 649             (*env)->SetIntField(env, this, psi_lastfdID, fd2);
 650         } else {
 651             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 652                             "select failed");
 653             return;
 654         }
 655         if (fd2 == fd) { /* v4 */
 656             len = sizeof (struct sockaddr_in);
 657         } else {
 658             len = sizeof (struct SOCKADDR_IN6);
 659         }
 660         fd = fd2;
 661     } else {
 662         int ret;
 663         if (fd1 != -1) {
 664             fd = fd1;
 665             len = sizeof (struct SOCKADDR_IN6);
 666         } else {
 667             len = sizeof (struct sockaddr_in);
 668         }
 669         if (timeout) {
 670             ret = NET_Timeout(fd, timeout);
 671             if (ret == 0) {
 672                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 673                                 "Accept timed out");
 674                 return;
 675             } else if (ret == -1) {
 676                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 677             /* REMIND: SOCKET CLOSED PROBLEM */
 678     /*        NET_ThrowCurrent(env, "Accept failed"); */
 679                 return;
 680             } else if (ret == -2) {
 681                 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 682                                 "operation interrupted");
 683                 return;
 684             }
 685         }
 686     }
 687     fd = accept(fd, (struct sockaddr *)&him, &len);
 688     if (fd < 0) {
 689         /* REMIND: SOCKET CLOSED PROBLEM */
 690         if (fd == -2) {
 691             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 692                             "operation interrupted");
 693         } else {
 694             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 695                             "socket closed");
 696         }
 697         return;
 698     }
 699     (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd);
 700 
 701     if (him.him.sa_family == AF_INET) {
 702         if (inet4Cls == NULL) {
 703             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
 704             if (c != NULL) {
 705                 inet4Cls = (*env)->NewGlobalRef(env, c);
 706                 (*env)->DeleteLocalRef(env, c);
 707             }
 708         }
 709 
 710         /*
 711          * fill up the remote peer port and address in the new socket structure
 712          */
 713         if (inet4Cls != NULL) {
 714             socketAddressObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
 715         } else {
 716             socketAddressObj = NULL;
 717         }
 718         if (socketAddressObj == NULL) {
 719             /*
 720              * FindClass or NewObject failed so close connection and
 721              * exist (there will be a pending exception).
 722              */
 723             NET_SocketClose(fd);
 724             return;
 725         }
 726 
 727         (*env)->SetIntField(env, socketAddressObj, ia_addressID,
 728                             ntohl(him.him4.sin_addr.s_addr));
 729         (*env)->SetIntField(env, socketAddressObj, ia_familyID, IPv4);
 730         (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
 731     } else {
 732         jbyteArray addr;
 733         /* AF_INET6 -> Inet6Address */
 734         if (inet6Cls == 0) {
 735             jclass c = (*env)->FindClass(env, "java/net/Inet6Address");
 736             if (c != NULL) {
 737                 inet6Cls = (*env)->NewGlobalRef(env, c);
 738                 (*env)->DeleteLocalRef(env, c);
 739             }
 740         }
 741 
 742         if (inet6Cls != NULL) {
 743             socketAddressObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID);
 744         } else {
 745             socketAddressObj = NULL;
 746         }
 747         if (socketAddressObj == NULL) {
 748             /*
 749              * FindClass or NewObject failed so close connection and
 750              * exist (there will be a pending exception).
 751              */
 752             NET_SocketClose(fd);
 753             return;
 754         }
 755         addr = (*env)->GetObjectField (env, socketAddressObj, ia6_ipaddressID);
 756         (*env)->SetByteArrayRegion (env, addr, 0, 16, (const char *)&him.him6.sin6_addr);
 757         (*env)->SetIntField(env, socketAddressObj, ia_familyID, IPv6);
 758         (*env)->SetIntField(env, socketAddressObj, ia6_scopeidID, him.him6.sin6_scope_id);
 759     }
 760     /* fields common to AF_INET and AF_INET6 */
 761 
 762     port = ntohs ((u_short) GET_PORT (&him));
 763     (*env)->SetIntField(env, socket, psi_portID, (int)port);
 764     port = (*env)->GetIntField(env, this, psi_localportID);
 765     (*env)->SetIntField(env, socket, psi_localportID, port);
 766     (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
 767 }
 768 
 769 /*
 770  * Class:     java_net_TwoStacksPlainSocketImpl
 771  * Method:    socketAvailable
 772  * Signature: ()I
 773  */
 774 JNIEXPORT jint JNICALL
 775 Java_java_net_TwoStacksPlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
 776 
 777     jint available = -1;
 778     jint res;
 779     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 780     jint fd;
 781 
 782     if (IS_NULL(fdObj)) {
 783         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 784         return -1;
 785     } else {
 786         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 787     }
 788     res = ioctlsocket(fd, FIONREAD, &available);
 789     /* if result isn't 0, it means an error */
 790     if (res != 0) {
 791         NET_ThrowNew(env, res, "socket available");
 792     }
 793     return available;
 794 }
 795 
 796 /*
 797  * Class:     java_net_TwoStacksPlainSocketImpl
 798  * Method:    socketClose
 799  * Signature: ()V
 800  */
 801 JNIEXPORT void JNICALL
 802 Java_java_net_TwoStacksPlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
 803                                            jboolean useDeferredClose) {
 804 
 805     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 806     jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 807     jint fd=-1, fd1=-1;
 808 
 809     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 810         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 811                         "socket already closed");
 812         return;
 813     }
 814     if (!IS_NULL(fdObj)) {
 815         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 816     }
 817     if (!IS_NULL(fd1Obj)) {
 818         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 819     }
 820     if (fd != -1) {
 821         (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
 822         NET_SocketClose(fd);
 823     }
 824     if (fd1 != -1) {
 825         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
 826         NET_SocketClose(fd1);
 827     }
 828 }
 829 
 830 /*
 831  * Socket options for plainsocketImpl
 832  *
 833  *
 834  * Class:     java_net_TwoStacksPlainSocketImpl
 835  * Method:    socketSetOption
 836  * Signature: (IZLjava/lang/Object;)V
 837  */
 838 JNIEXPORT void JNICALL
 839 Java_java_net_TwoStacksPlainSocketImpl_socketSetOption(JNIEnv *env, jobject this,
 840                                               jint cmd, jboolean on,
 841                                               jobject value) {
 842     int fd, fd1;
 843     int level, optname, optlen;
 844     union {
 845         int i;
 846         struct linger ling;
 847     } optval;
 848 
 849     /*
 850      * Get SOCKET and check that it hasn't been closed
 851      */
 852     fd = getFD(env, this);
 853     fd1 = getFD1(env, this);
 854     if (fd < 0 && fd1 < 0) {
 855         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 856         return;
 857     }
 858 
 859     /*
 860      * SO_TIMEOUT is the socket option used to specify the timeout
 861      * for ServerSocket.accept and Socket.getInputStream().read.
 862      * It does not typically map to a native level socket option.
 863      * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
 864      * socket option to specify a receive timeout on the socket. This
 865      * receive timeout is applicable to Socket only and the socket
 866      * option should not be set on ServerSocket.
 867      */
 868     if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
 869 
 870         /*
 871          * Don't enable the socket option on ServerSocket as it's
 872          * meaningless (we don't receive on a ServerSocket).
 873          */
 874         jobject ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);
 875         if (ssObj != NULL) {
 876             return;
 877         }
 878 
 879         /*
 880          * SO_RCVTIMEO is only supported on Microsoft's implementation
 881          * of Windows Sockets so if WSAENOPROTOOPT returned then
 882          * reset flag and timeout will be implemented using
 883          * select() -- see SocketInputStream.socketRead.
 884          */
 885         if (isRcvTimeoutSupported) {
 886             jclass iCls = (*env)->FindClass(env, "java/lang/Integer");
 887             jfieldID i_valueID;
 888             jint timeout;
 889 
 890             CHECK_NULL(iCls);
 891             i_valueID = (*env)->GetFieldID(env, iCls, "value", "I");
 892             CHECK_NULL(i_valueID);
 893             timeout = (*env)->GetIntField(env, value, i_valueID);
 894 
 895             /*
 896              * Disable SO_RCVTIMEO if timeout is <= 5 second.
 897              */
 898             if (timeout <= 5000) {
 899                 timeout = 0;
 900             }
 901 
 902             if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
 903                 sizeof(timeout)) < 0) {
 904                 if (WSAGetLastError() == WSAENOPROTOOPT) {
 905                     isRcvTimeoutSupported = JNI_FALSE;
 906                 } else {
 907                     NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");
 908                 }
 909             }
 910             if (fd1 != -1) {
 911                 if (setsockopt(fd1, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
 912                                         sizeof(timeout)) < 0) {
 913                     NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");
 914                 }
 915             }
 916         }
 917         return;
 918     }
 919 
 920     /*
 921      * Map the Java level socket option to the platform specific
 922      * level
 923      */
 924     if (NET_MapSocketOption(cmd, &level, &optname)) {
 925         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 926                         "Invalid option");
 927         return;
 928     }
 929 
 930     switch (cmd) {
 931 
 932         case java_net_SocketOptions_TCP_NODELAY :
 933         case java_net_SocketOptions_SO_OOBINLINE :
 934         case java_net_SocketOptions_SO_KEEPALIVE :
 935         case java_net_SocketOptions_SO_REUSEADDR :
 936             optval.i = (on ? 1 : 0);
 937             optlen = sizeof(optval.i);
 938             break;
 939 
 940         case java_net_SocketOptions_SO_SNDBUF :
 941         case java_net_SocketOptions_SO_RCVBUF :
 942         case java_net_SocketOptions_IP_TOS :
 943             {
 944                 jclass cls;
 945                 jfieldID fid;
 946 
 947                 cls = (*env)->FindClass(env, "java/lang/Integer");
 948                 CHECK_NULL(cls);
 949                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 950                 CHECK_NULL(fid);
 951 
 952                 optval.i = (*env)->GetIntField(env, value, fid);
 953                 optlen = sizeof(optval.i);
 954             }
 955             break;
 956 
 957         case java_net_SocketOptions_SO_LINGER :
 958             {
 959                 jclass cls;
 960                 jfieldID fid;
 961 
 962                 cls = (*env)->FindClass(env, "java/lang/Integer");
 963                 CHECK_NULL(cls);
 964                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 965                 CHECK_NULL(fid);
 966 
 967                 if (on) {
 968                     optval.ling.l_onoff = 1;
 969                     optval.ling.l_linger =
 970                         (unsigned short)(*env)->GetIntField(env, value, fid);
 971                 } else {
 972                     optval.ling.l_onoff = 0;
 973                     optval.ling.l_linger = 0;
 974                 }
 975                 optlen = sizeof(optval.ling);
 976             }
 977             break;
 978 
 979         default: /* shouldn't get here */
 980             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 981                 "Option not supported by TwoStacksPlainSocketImpl");
 982             return;
 983     }
 984 
 985     if (fd != -1) {
 986         if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) {
 987             NET_ThrowCurrent(env, "setsockopt");
 988         }
 989     }
 990 
 991     if (fd1 != -1) {
 992         if (NET_SetSockOpt(fd1, level, optname, (void *)&optval, optlen) < 0) {
 993             NET_ThrowCurrent(env, "setsockopt");
 994         }
 995     }
 996 }
 997 
 998 
 999 /*
1000  * Class:     java_net_TwoStacksPlainSocketImpl
1001  * Method:    socketGetOption
1002  * Signature: (I)I
1003  */
1004 JNIEXPORT jint JNICALL
1005 Java_java_net_TwoStacksPlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,
1006                                               jint opt, jobject iaContainerObj) {
1007 
1008     int fd, fd1;
1009     int level, optname, optlen;
1010     union {
1011         int i;
1012         struct linger ling;
1013     } optval;
1014 
1015     /*
1016      * Get SOCKET and check it hasn't been closed
1017      */
1018     fd = getFD(env, this);
1019     fd1 = getFD1(env, this);
1020 
1021     if (fd < 0 && fd1 < 0) {
1022         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1023         return -1;
1024     }
1025     if (fd < 0) {
1026         fd = fd1;
1027     }
1028 
1029     /* For IPv6, we assume both sockets have the same setting always */
1030 
1031     /*
1032      * SO_BINDADDR isn't a socket option
1033      */
1034     if (opt == java_net_SocketOptions_SO_BINDADDR) {
1035         SOCKETADDRESS him;
1036         int len;
1037         int port;
1038         jobject iaObj;
1039         jclass iaCntrClass;
1040         jfieldID iaFieldID;
1041 
1042         len = sizeof(him);
1043 
1044         if (fd == -1) {
1045             /* must be an IPV6 only socket. Case where both sockets are != -1
1046              * is handled in java
1047              */
1048             fd = getFD1 (env, this);
1049         }
1050 
1051         if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) {
1052             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1053                              "Error getting socket name");
1054             return -1;
1055         }
1056         iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1057         CHECK_NULL_RETURN(iaObj, -1);
1058 
1059         iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
1060         iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
1061         CHECK_NULL_RETURN(iaFieldID, -1);
1062         (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
1063         return 0; /* notice change from before */
1064     }
1065 
1066     /*
1067      * Map the Java level socket option to the platform specific
1068      * level and option name.
1069      */
1070     if (NET_MapSocketOption(opt, &level, &optname)) {
1071         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1072         return -1;
1073     }
1074 
1075     /*
1076      * Args are int except for SO_LINGER
1077      */
1078     if (opt == java_net_SocketOptions_SO_LINGER) {
1079         optlen = sizeof(optval.ling);
1080     } else {
1081         optlen = sizeof(optval.i);
1082         optval.i = 0;
1083     }
1084 
1085     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1086         NET_ThrowCurrent(env, "getsockopt");
1087         return -1;
1088     }
1089 
1090     switch (opt) {
1091         case java_net_SocketOptions_SO_LINGER:
1092             return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
1093 
1094         case java_net_SocketOptions_SO_SNDBUF:
1095         case java_net_SocketOptions_SO_RCVBUF:
1096         case java_net_SocketOptions_IP_TOS:
1097             return optval.i;
1098 
1099         case java_net_SocketOptions_TCP_NODELAY :
1100         case java_net_SocketOptions_SO_OOBINLINE :
1101         case java_net_SocketOptions_SO_KEEPALIVE :
1102         case java_net_SocketOptions_SO_REUSEADDR :
1103             return (optval.i == 0) ? -1 : 1;
1104 
1105         default: /* shouldn't get here */
1106             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1107                 "Option not supported by TwoStacksPlainSocketImpl");
1108             return -1;
1109     }
1110 }
1111 
1112 /*
1113  * Class:     java_net_TwoStacksPlainSocketImpl
1114  * Method:    socketShutdown
1115  * Signature: (I)V
1116  */
1117 JNIEXPORT void JNICALL
1118 Java_java_net_TwoStacksPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
1119                                              jint howto)
1120 {
1121 
1122     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1123     jint fd;
1124 
1125     /*
1126      * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
1127      * -1 already?
1128      */
1129     if (IS_NULL(fdObj)) {
1130         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1131                         "socket already closed");
1132         return;
1133     } else {
1134         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1135     }
1136     shutdown(fd, howto);
1137 }
1138 
1139 /*
1140  * Class:     java_net_TwoStacksPlainSocketImpl
1141  * Method:    socketSendUrgentData
1142  * Signature: (B)V
1143  */
1144 JNIEXPORT void JNICALL
1145 Java_java_net_TwoStacksPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
1146                                              jint data) {
1147     /* The fd field */
1148     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1149     int n, fd;
1150     unsigned char d = data & 0xff;
1151 
1152     if (IS_NULL(fdObj)) {
1153         JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1154         return;
1155     } else {
1156         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1157         /* Bug 4086704 - If the Socket associated with this file descriptor
1158          * was closed (sysCloseFD), the the file descriptor is set to -1.
1159          */
1160         if (fd == -1) {
1161             JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1162             return;
1163         }
1164 
1165     }
1166     n = send(fd, (char *)&data, 1, MSG_OOB);
1167     if (n == JVM_IO_ERR) {
1168         NET_ThrowCurrent(env, "send");
1169         return;
1170     }
1171     if (n == JVM_IO_INTR) {
1172         JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
1173         return;
1174     }
1175 }