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