1 /*
   2  * Copyright (c) 1997, 2016, 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     memset((char *)&him, 0, sizeof(him));
 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 = 0;
 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         } else {
 471             /* NET_BindV6() closes both sockets upon a failure */
 472             (*env)->SetObjectField(env, this, psi_fdID, NULL);
 473             (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
 474         }
 475     } else {
 476         rv = NET_WinBind(fd, (struct sockaddr *)&him, len, exclBind);
 477     }
 478 
 479     if (rv == -1) {
 480         NET_ThrowCurrent(env, "NET_Bind");
 481         return;
 482     }
 483 
 484     /* set the address */
 485     (*env)->SetObjectField(env, this, psi_addressID, iaObj);
 486 
 487     /* intialize the local port */
 488     if (localport == 0) {
 489         /* Now that we're a bound socket, let's extract the port number
 490          * that the system chose for us and store it in the Socket object.
 491          */
 492         int len = SOCKETADDRESS_LEN(&him);
 493         u_short port;
 494         fd = him.him.sa_family == AF_INET? fd: fd1;
 495 
 496         if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
 497             NET_ThrowCurrent(env, "getsockname in plain socketBind");
 498             return;
 499         }
 500         port = ntohs ((u_short) GET_PORT (&him));
 501 
 502         (*env)->SetIntField(env, this, psi_localportID, (int) port);
 503     } else {
 504         (*env)->SetIntField(env, this, psi_localportID, localport);
 505     }
 506 }
 507 
 508 /*
 509  * Class:     java_net_TwoStacksPlainSocketImpl
 510  * Method:    socketListen
 511  * Signature: (I)V
 512  */
 513 JNIEXPORT void JNICALL
 514 Java_java_net_TwoStacksPlainSocketImpl_socketListen (JNIEnv *env, jobject this,
 515                                             jint count)
 516 {
 517     /* this FileDescriptor fd field */
 518     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 519     jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 520     jobject address;
 521     /* fdObj's int fd field */
 522     int fd, fd1;
 523     SOCKETADDRESS addr; int addrlen;
 524 
 525     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 526         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 527                         "socket closed");
 528         return;
 529     }
 530 
 531     if (!IS_NULL(fdObj)) {
 532         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 533     }
 534     /* Listen on V4 if address type is v4 or if v6 and address is ::0.
 535      * Listen on V6 if address type is v6 or if v4 and address is 0.0.0.0.
 536      * In cases, where we listen on one space only, we close the other socket.
 537      */
 538     address = (*env)->GetObjectField(env, this, psi_addressID);
 539     if (IS_NULL(address)) {
 540         JNU_ThrowNullPointerException(env, "socket address");
 541         return;
 542     }
 543     if (NET_InetAddressToSockaddr(env, address, 0, (struct sockaddr *)&addr,
 544                                   &addrlen, JNI_FALSE) != 0) {
 545       return;
 546     }
 547 
 548     if (addr.him.sa_family == AF_INET || IN6ADDR_ISANY(&addr.him6)) {
 549         /* listen on v4 */
 550         if (listen(fd, count) == -1) {
 551             NET_ThrowCurrent(env, "listen failed");
 552         }
 553     } else {
 554         NET_SocketClose (fd);
 555         (*env)->SetObjectField(env, this, psi_fdID, NULL);
 556     }
 557     if (ipv6_available() && !IS_NULL(fd1Obj)) {
 558         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 559         if (addr.him.sa_family == AF_INET6 || addr.him4.sin_addr.s_addr == INADDR_ANY) {
 560             /* listen on v6 */
 561             if (listen(fd1, count) == -1) {
 562                 NET_ThrowCurrent(env, "listen failed");
 563             }
 564         } else {
 565             NET_SocketClose (fd1);
 566             (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
 567         }
 568     }
 569 }
 570 
 571 /*
 572  * Class:     java_net_TwoStacksPlainSocketImpl
 573  * Method:    socketAccept
 574  * Signature: (Ljava/net/SocketImpl;)V
 575  */
 576 JNIEXPORT void JNICALL
 577 Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
 578                                            jobject socket)
 579 {
 580     /* fields on this */
 581     jint port;
 582     jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
 583     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 584     jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 585 
 586     /* the FileDescriptor field on socket */
 587     jobject socketFdObj;
 588 
 589     /* cache the Inet4/6Address classes */
 590     static jclass inet4Cls;
 591     static jclass inet6Cls;
 592 
 593     /* the InetAddress field on socket */
 594     jobject socketAddressObj;
 595 
 596     /* the fd int field on fdObj */
 597     jint fd=-1, fd1=-1;
 598 
 599     SOCKETADDRESS him;
 600     jint len;
 601 
 602     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 603         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 604                         "Socket closed");
 605         return;
 606     }
 607     if (!IS_NULL(fdObj)) {
 608         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 609     }
 610     if (!IS_NULL(fd1Obj)) {
 611         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 612     }
 613     if (IS_NULL(socket)) {
 614         JNU_ThrowNullPointerException(env, "socket is null");
 615         return;
 616     } else {
 617         socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
 618         socketAddressObj = (*env)->GetObjectField(env, socket, psi_addressID);
 619     }
 620     if ((IS_NULL(socketAddressObj)) || (IS_NULL(socketFdObj))) {
 621         JNU_ThrowNullPointerException(env, "socket address or fd obj");
 622         return;
 623     }
 624     if (fd != -1 && fd1 != -1) {
 625         fd_set rfds;
 626         struct timeval t, *tP=&t;
 627         int lastfd, res, fd2;
 628         FD_ZERO(&rfds);
 629         FD_SET(fd,&rfds);
 630         FD_SET(fd1,&rfds);
 631         if (timeout) {
 632             t.tv_sec = timeout/1000;
 633             t.tv_usec = (timeout%1000)*1000;
 634         } else {
 635             tP = NULL;
 636         }
 637         res = select (fd, &rfds, NULL, NULL, tP);
 638         if (res == 0) {
 639             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 640                             "Accept timed out");
 641             return;
 642         } else if (res == 1) {
 643             fd2 = FD_ISSET(fd, &rfds)? fd: fd1;
 644         } else if (res == 2) {
 645             /* avoid starvation */
 646             lastfd = (*env)->GetIntField(env, this, psi_lastfdID);
 647             if (lastfd != -1) {
 648                 fd2 = lastfd==fd? fd1: fd;
 649             } else {
 650                 fd2 = fd;
 651             }
 652             (*env)->SetIntField(env, this, psi_lastfdID, fd2);
 653         } else {
 654             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 655                             "select failed");
 656             return;
 657         }
 658         if (fd2 == fd) { /* v4 */
 659             len = sizeof (struct sockaddr_in);
 660         } else {
 661             len = sizeof (struct SOCKADDR_IN6);
 662         }
 663         fd = fd2;
 664     } else {
 665         int ret;
 666         if (fd1 != -1) {
 667             fd = fd1;
 668             len = sizeof (struct SOCKADDR_IN6);
 669         } else {
 670             len = sizeof (struct sockaddr_in);
 671         }
 672         if (timeout) {
 673             ret = NET_Timeout(fd, timeout);
 674             if (ret == 0) {
 675                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 676                                 "Accept timed out");
 677                 return;
 678             } else if (ret == -1) {
 679                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 680             /* REMIND: SOCKET CLOSED PROBLEM */
 681     /*        NET_ThrowCurrent(env, "Accept failed"); */
 682                 return;
 683             } else if (ret == -2) {
 684                 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 685                                 "operation interrupted");
 686                 return;
 687             }
 688         }
 689     }
 690     fd = accept(fd, (struct sockaddr *)&him, &len);
 691     if (fd < 0) {
 692         /* REMIND: SOCKET CLOSED PROBLEM */
 693         if (fd == -2) {
 694             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 695                             "operation interrupted");
 696         } else {
 697             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 698                             "socket closed");
 699         }
 700         return;
 701     }
 702     SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0);
 703     (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd);
 704 
 705     if (him.him.sa_family == AF_INET) {
 706         if (inet4Cls == NULL) {
 707             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
 708             if (c != NULL) {
 709                 inet4Cls = (*env)->NewGlobalRef(env, c);
 710                 (*env)->DeleteLocalRef(env, c);
 711             }
 712         }
 713 
 714         /*
 715          * fill up the remote peer port and address in the new socket structure
 716          */
 717         if (inet4Cls != NULL) {
 718             socketAddressObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
 719         } else {
 720             socketAddressObj = NULL;
 721         }
 722         if (socketAddressObj == NULL) {
 723             /*
 724              * FindClass or NewObject failed so close connection and
 725              * exist (there will be a pending exception).
 726              */
 727             NET_SocketClose(fd);
 728             return;
 729         }
 730 
 731         setInetAddress_addr(env, socketAddressObj, ntohl(him.him4.sin_addr.s_addr));
 732         setInetAddress_family(env, socketAddressObj, IPv4);
 733         (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
 734     } else {
 735         /* AF_INET6 -> Inet6Address */
 736         if (inet6Cls == 0) {
 737             jclass c = (*env)->FindClass(env, "java/net/Inet6Address");
 738             if (c != NULL) {
 739                 inet6Cls = (*env)->NewGlobalRef(env, c);
 740                 (*env)->DeleteLocalRef(env, c);
 741             }
 742         }
 743 
 744         if (inet6Cls != NULL) {
 745             socketAddressObj = (*env)->NewObject(env, inet6Cls, ia6_ctrID);
 746         } else {
 747             socketAddressObj = NULL;
 748         }
 749         if (socketAddressObj == NULL) {
 750             /*
 751              * FindClass or NewObject failed so close connection and
 752              * exist (there will be a pending exception).
 753              */
 754             NET_SocketClose(fd);
 755             return;
 756         }
 757         setInet6Address_ipaddress(env, socketAddressObj, (char *)&him.him6.sin6_addr);
 758         setInetAddress_family(env, socketAddressObj, IPv6);
 759         setInet6Address_scopeid(env, socketAddressObj, him.him6.sin6_scope_id);
 760 
 761     }
 762     /* fields common to AF_INET and AF_INET6 */
 763 
 764     port = ntohs ((u_short) GET_PORT (&him));
 765     (*env)->SetIntField(env, socket, psi_portID, (int)port);
 766     port = (*env)->GetIntField(env, this, psi_localportID);
 767     (*env)->SetIntField(env, socket, psi_localportID, port);
 768     (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
 769 }
 770 
 771 /*
 772  * Class:     java_net_TwoStacksPlainSocketImpl
 773  * Method:    socketAvailable
 774  * Signature: ()I
 775  */
 776 JNIEXPORT jint JNICALL
 777 Java_java_net_TwoStacksPlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
 778 
 779     jint available = -1;
 780     jint res;
 781     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 782     jint fd;
 783 
 784     if (IS_NULL(fdObj)) {
 785         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 786         return -1;
 787     } else {
 788         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 789     }
 790     res = ioctlsocket(fd, FIONREAD, &available);
 791     /* if result isn't 0, it means an error */
 792     if (res != 0) {
 793         NET_ThrowNew(env, res, "socket available");
 794     }
 795     return available;
 796 }
 797 
 798 /*
 799  * Class:     java_net_TwoStacksPlainSocketImpl
 800  * Method:    socketClose
 801  * Signature: ()V
 802  */
 803 JNIEXPORT void JNICALL
 804 Java_java_net_TwoStacksPlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
 805                                            jboolean useDeferredClose) {
 806 
 807     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 808     jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 809     jint fd=-1, fd1=-1;
 810 
 811     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 812         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 813                         "socket already closed");
 814         return;
 815     }
 816     if (!IS_NULL(fdObj)) {
 817         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 818     }
 819     if (!IS_NULL(fd1Obj)) {
 820         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 821     }
 822     if (fd != -1) {
 823         (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
 824         NET_SocketClose(fd);
 825     }
 826     if (fd1 != -1) {
 827         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
 828         NET_SocketClose(fd1);
 829     }
 830 }
 831 
 832 /*
 833  * Socket options for plainsocketImpl
 834  *
 835  *
 836  * Class:     java_net_TwoStacksPlainSocketImpl
 837  * Method:    socketNativeSetOption
 838  * Signature: (IZLjava/lang/Object;)V
 839  */
 840 JNIEXPORT void JNICALL
 841 Java_java_net_TwoStacksPlainSocketImpl_socketNativeSetOption(JNIEnv *env,
 842                                               jobject this,
 843                                               jint cmd, jboolean on,
 844                                               jobject value) {
 845     int fd, fd1;
 846     int level = 0, optname = 0, optlen = 0;
 847     union {
 848         int i;
 849         struct linger ling;
 850     } optval;
 851 
 852     memset((char *)&optval, 0, sizeof(optval));
 853     /*
 854      * Get SOCKET and check that it hasn't been closed
 855      */
 856     fd = getFD(env, this);
 857     fd1 = getFD1(env, this);
 858     if (fd < 0 && fd1 < 0) {
 859         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 860         return;
 861     }
 862 
 863     /*
 864      * SO_TIMEOUT is the socket option used to specify the timeout
 865      * for ServerSocket.accept and Socket.getInputStream().read.
 866      * It does not typically map to a native level socket option.
 867      * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
 868      * socket option to specify a receive timeout on the socket. This
 869      * receive timeout is applicable to Socket only and the socket
 870      * option should not be set on ServerSocket.
 871      */
 872     if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
 873 
 874         /*
 875          * Don't enable the socket option on ServerSocket as it's
 876          * meaningless (we don't receive on a ServerSocket).
 877          */
 878         jobject ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);
 879         if (ssObj != NULL) {
 880             return;
 881         }
 882 
 883         /*
 884          * SO_RCVTIMEO is only supported on Microsoft's implementation
 885          * of Windows Sockets so if WSAENOPROTOOPT returned then
 886          * reset flag and timeout will be implemented using
 887          * select() -- see SocketInputStream.socketRead.
 888          */
 889         if (isRcvTimeoutSupported) {
 890             jclass iCls = (*env)->FindClass(env, "java/lang/Integer");
 891             jfieldID i_valueID;
 892             jint timeout;
 893 
 894             CHECK_NULL(iCls);
 895             i_valueID = (*env)->GetFieldID(env, iCls, "value", "I");
 896             CHECK_NULL(i_valueID);
 897             timeout = (*env)->GetIntField(env, value, i_valueID);
 898 
 899             /*
 900              * Disable SO_RCVTIMEO if timeout is <= 5 second.
 901              */
 902             if (timeout <= 5000) {
 903                 timeout = 0;
 904             }
 905 
 906             if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
 907                 sizeof(timeout)) < 0) {
 908                 if (WSAGetLastError() == WSAENOPROTOOPT) {
 909                     isRcvTimeoutSupported = JNI_FALSE;
 910                 } else {
 911                     NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");
 912                 }
 913             }
 914             if (fd1 != -1) {
 915                 if (setsockopt(fd1, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
 916                                         sizeof(timeout)) < 0) {
 917                     NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");
 918                 }
 919             }
 920         }
 921         return;
 922     }
 923 
 924     /*
 925      * Map the Java level socket option to the platform specific
 926      * level
 927      */
 928     if (NET_MapSocketOption(cmd, &level, &optname)) {
 929         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 930                         "Invalid option");
 931         return;
 932     }
 933 
 934     switch (cmd) {
 935 
 936         case java_net_SocketOptions_TCP_NODELAY :
 937         case java_net_SocketOptions_SO_OOBINLINE :
 938         case java_net_SocketOptions_SO_KEEPALIVE :
 939         case java_net_SocketOptions_SO_REUSEADDR :
 940             optval.i = (on ? 1 : 0);
 941             optlen = sizeof(optval.i);
 942             break;
 943 
 944         case java_net_SocketOptions_SO_SNDBUF :
 945         case java_net_SocketOptions_SO_RCVBUF :
 946         case java_net_SocketOptions_IP_TOS :
 947             {
 948                 jclass cls;
 949                 jfieldID fid;
 950 
 951                 cls = (*env)->FindClass(env, "java/lang/Integer");
 952                 CHECK_NULL(cls);
 953                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 954                 CHECK_NULL(fid);
 955 
 956                 optval.i = (*env)->GetIntField(env, value, fid);
 957                 optlen = sizeof(optval.i);
 958             }
 959             break;
 960 
 961         case java_net_SocketOptions_SO_LINGER :
 962             {
 963                 jclass cls;
 964                 jfieldID fid;
 965 
 966                 cls = (*env)->FindClass(env, "java/lang/Integer");
 967                 CHECK_NULL(cls);
 968                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 969                 CHECK_NULL(fid);
 970 
 971                 if (on) {
 972                     optval.ling.l_onoff = 1;
 973                     optval.ling.l_linger =
 974                         (unsigned short)(*env)->GetIntField(env, value, fid);
 975                 } else {
 976                     optval.ling.l_onoff = 0;
 977                     optval.ling.l_linger = 0;
 978                 }
 979                 optlen = sizeof(optval.ling);
 980             }
 981             break;
 982 
 983         default: /* shouldn't get here */
 984             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 985                 "Option not supported by TwoStacksPlainSocketImpl");
 986             return;
 987     }
 988 
 989     if (fd != -1) {
 990         if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) {
 991             NET_ThrowCurrent(env, "setsockopt");
 992         }
 993     }
 994 
 995     if (fd1 != -1) {
 996         if (NET_SetSockOpt(fd1, level, optname, (void *)&optval, optlen) < 0) {
 997             NET_ThrowCurrent(env, "setsockopt");
 998         }
 999     }
1000 }
1001 
1002 
1003 /*
1004  * Class:     java_net_TwoStacksPlainSocketImpl
1005  * Method:    socketGetOption
1006  * Signature: (I)I
1007  */
1008 JNIEXPORT jint JNICALL
1009 Java_java_net_TwoStacksPlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,
1010                                               jint opt, jobject iaContainerObj) {
1011 
1012     int fd, fd1;
1013     int level = 0, optname = 0, optlen = 0;
1014     union {
1015         int i;
1016         struct linger ling;
1017     } optval;
1018     /*
1019      * Get SOCKET and check it hasn't been closed
1020      */
1021     fd = getFD(env, this);
1022     fd1 = getFD1(env, this);
1023     memset((char *)&optval, 0, sizeof(optval));
1024 
1025     if (fd < 0 && fd1 < 0) {
1026         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1027         return -1;
1028     }
1029     if (fd < 0) {
1030         fd = fd1;
1031     }
1032 
1033     /* For IPv6, we assume both sockets have the same setting always */
1034 
1035     /*
1036      * SO_BINDADDR isn't a socket option
1037      */
1038     if (opt == java_net_SocketOptions_SO_BINDADDR) {
1039         SOCKETADDRESS him;
1040         int len;
1041         int port;
1042         jobject iaObj;
1043         jclass iaCntrClass;
1044         jfieldID iaFieldID;
1045 
1046         len = sizeof(him);
1047         memset((char *)&him, 0, len);
1048 
1049         if (fd == -1) {
1050             /* must be an IPV6 only socket. Case where both sockets are != -1
1051              * is handled in java
1052              */
1053             fd = getFD1 (env, this);
1054         }
1055 
1056         if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) {
1057             JNU_ThrowByNameWithMessageAndLastError
1058                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
1059             return -1;
1060         }
1061         iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1062         CHECK_NULL_RETURN(iaObj, -1);
1063 
1064         iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
1065         iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
1066         CHECK_NULL_RETURN(iaFieldID, -1);
1067         (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
1068         return 0; /* notice change from before */
1069     }
1070 
1071     /*
1072      * Map the Java level socket option to the platform specific
1073      * level and option name.
1074      */
1075     if (NET_MapSocketOption(opt, &level, &optname)) {
1076         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1077         return -1;
1078     }
1079 
1080     /*
1081      * Args are int except for SO_LINGER
1082      */
1083     if (opt == java_net_SocketOptions_SO_LINGER) {
1084         optlen = sizeof(optval.ling);
1085     } else {
1086         optlen = sizeof(optval.i);
1087         optval.i = 0;
1088     }
1089 
1090     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1091         NET_ThrowCurrent(env, "getsockopt");
1092         return -1;
1093     }
1094 
1095     switch (opt) {
1096         case java_net_SocketOptions_SO_LINGER:
1097             return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
1098 
1099         case java_net_SocketOptions_SO_SNDBUF:
1100         case java_net_SocketOptions_SO_RCVBUF:
1101         case java_net_SocketOptions_IP_TOS:
1102             return optval.i;
1103 
1104         case java_net_SocketOptions_TCP_NODELAY :
1105         case java_net_SocketOptions_SO_OOBINLINE :
1106         case java_net_SocketOptions_SO_KEEPALIVE :
1107         case java_net_SocketOptions_SO_REUSEADDR :
1108             return (optval.i == 0) ? -1 : 1;
1109 
1110         default: /* shouldn't get here */
1111             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1112                 "Option not supported by TwoStacksPlainSocketImpl");
1113             return -1;
1114     }
1115 }
1116 
1117 /*
1118  * Class:     java_net_TwoStacksPlainSocketImpl
1119  * Method:    socketShutdown
1120  * Signature: (I)V
1121  */
1122 JNIEXPORT void JNICALL
1123 Java_java_net_TwoStacksPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
1124                                              jint howto)
1125 {
1126 
1127     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1128     jint fd;
1129 
1130     /*
1131      * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
1132      * -1 already?
1133      */
1134     if (IS_NULL(fdObj)) {
1135         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1136                         "socket already closed");
1137         return;
1138     } else {
1139         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1140     }
1141     shutdown(fd, howto);
1142 }
1143 
1144 /*
1145  * Class:     java_net_TwoStacksPlainSocketImpl
1146  * Method:    socketSendUrgentData
1147  * Signature: (B)V
1148  */
1149 JNIEXPORT void JNICALL
1150 Java_java_net_TwoStacksPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
1151                                              jint data) {
1152     /* The fd field */
1153     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1154     int n, fd;
1155     unsigned char d = data & 0xff;
1156 
1157     if (IS_NULL(fdObj)) {
1158         JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1159         return;
1160     } else {
1161         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1162         /* Bug 4086704 - If the Socket associated with this file descriptor
1163          * was closed (sysCloseFD), the file descriptor is set to -1.
1164          */
1165         if (fd == -1) {
1166             JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1167             return;
1168         }
1169 
1170     }
1171     n = send(fd, (char *)&data, 1, MSG_OOB);
1172     if (n == -1) {
1173         NET_ThrowCurrent(env, "send");
1174         return;
1175     }
1176 }