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