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