1 /*
   2  * Copyright (c) 1997, 2013, 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         } 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, "JVM_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 scope;
 583     jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
 584     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 585     jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 586 
 587     /* the FileDescriptor field on socket */
 588     jobject socketFdObj;
 589 
 590     /* cache the Inet4/6Address classes */
 591     static jclass inet4Cls;
 592     static jclass inet6Cls;
 593 
 594     /* the InetAddress field on socket */
 595     jobject socketAddressObj;
 596 
 597     /* the fd int field on fdObj */
 598     jint fd=-1, fd1=-1;
 599 
 600     SOCKETADDRESS him;
 601     jint len;
 602 
 603     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 604         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 605                         "Socket closed");
 606         return;
 607     }
 608     if (!IS_NULL(fdObj)) {
 609         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 610     }
 611     if (!IS_NULL(fd1Obj)) {
 612         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 613     }
 614     if (IS_NULL(socket)) {
 615         JNU_ThrowNullPointerException(env, "socket is null");
 616         return;
 617     } else {
 618         socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
 619         socketAddressObj = (*env)->GetObjectField(env, socket, psi_addressID);
 620     }
 621     if ((IS_NULL(socketAddressObj)) || (IS_NULL(socketFdObj))) {
 622         JNU_ThrowNullPointerException(env, "socket address or fd obj");
 623         return;
 624     }
 625     if (fd != -1 && fd1 != -1) {
 626         fd_set rfds;
 627         struct timeval t, *tP=&t;
 628         int lastfd, res, fd2;
 629         FD_ZERO(&rfds);
 630         FD_SET(fd,&rfds);
 631         FD_SET(fd1,&rfds);
 632         if (timeout) {
 633             t.tv_sec = timeout/1000;
 634             t.tv_usec = (timeout%1000)*1000;
 635         } else {
 636             tP = NULL;
 637         }
 638         res = select (fd, &rfds, NULL, NULL, tP);
 639         if (res == 0) {
 640             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 641                             "Accept timed out");
 642             return;
 643         } else if (res == 1) {
 644             fd2 = FD_ISSET(fd, &rfds)? fd: fd1;
 645         } else if (res == 2) {
 646             /* avoid starvation */
 647             lastfd = (*env)->GetIntField(env, this, psi_lastfdID);
 648             if (lastfd != -1) {
 649                 fd2 = lastfd==fd? fd1: fd;
 650             } else {
 651                 fd2 = fd;
 652             }
 653             (*env)->SetIntField(env, this, psi_lastfdID, fd2);
 654         } else {
 655             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 656                             "select failed");
 657             return;
 658         }
 659         if (fd2 == fd) { /* v4 */
 660             len = sizeof (struct sockaddr_in);
 661         } else {
 662             len = sizeof (struct SOCKADDR_IN6);
 663         }
 664         fd = fd2;
 665     } else {
 666         int ret;
 667         if (fd1 != -1) {
 668             fd = fd1;
 669             len = sizeof (struct SOCKADDR_IN6);
 670         } else {
 671             len = sizeof (struct sockaddr_in);
 672         }
 673         if (timeout) {
 674             ret = NET_Timeout(fd, timeout);
 675             if (ret == 0) {
 676                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 677                                 "Accept timed out");
 678                 return;
 679             } else if (ret == -1) {
 680                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 681             /* REMIND: SOCKET CLOSED PROBLEM */
 682     /*        NET_ThrowCurrent(env, "Accept failed"); */
 683                 return;
 684             } else if (ret == -2) {
 685                 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 686                                 "operation interrupted");
 687                 return;
 688             }
 689         }
 690     }
 691     fd = accept(fd, (struct sockaddr *)&him, &len);
 692     if (fd < 0) {
 693         /* REMIND: SOCKET CLOSED PROBLEM */
 694         if (fd == -2) {
 695             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 696                             "operation interrupted");
 697         } else {
 698             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 699                             "socket closed");
 700         }
 701         return;
 702     }
 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, (const 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, optname, optlen;
 847     union {
 848         int i;
 849         struct linger ling;
 850     } optval;
 851 
 852     /*
 853      * Get SOCKET and check that it hasn't been closed
 854      */
 855     fd = getFD(env, this);
 856     fd1 = getFD1(env, this);
 857     if (fd < 0 && fd1 < 0) {
 858         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 859         return;
 860     }
 861 
 862     /*
 863      * SO_TIMEOUT is the socket option used to specify the timeout
 864      * for ServerSocket.accept and Socket.getInputStream().read.
 865      * It does not typically map to a native level socket option.
 866      * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
 867      * socket option to specify a receive timeout on the socket. This
 868      * receive timeout is applicable to Socket only and the socket
 869      * option should not be set on ServerSocket.
 870      */
 871     if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
 872 
 873         /*
 874          * Don't enable the socket option on ServerSocket as it's
 875          * meaningless (we don't receive on a ServerSocket).
 876          */
 877         jobject ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);
 878         if (ssObj != NULL) {
 879             return;
 880         }
 881 
 882         /*
 883          * SO_RCVTIMEO is only supported on Microsoft's implementation
 884          * of Windows Sockets so if WSAENOPROTOOPT returned then
 885          * reset flag and timeout will be implemented using
 886          * select() -- see SocketInputStream.socketRead.
 887          */
 888         if (isRcvTimeoutSupported) {
 889             jclass iCls = (*env)->FindClass(env, "java/lang/Integer");
 890             jfieldID i_valueID;
 891             jint timeout;
 892 
 893             CHECK_NULL(iCls);
 894             i_valueID = (*env)->GetFieldID(env, iCls, "value", "I");
 895             CHECK_NULL(i_valueID);
 896             timeout = (*env)->GetIntField(env, value, i_valueID);
 897 
 898             /*
 899              * Disable SO_RCVTIMEO if timeout is <= 5 second.
 900              */
 901             if (timeout <= 5000) {
 902                 timeout = 0;
 903             }
 904 
 905             if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
 906                 sizeof(timeout)) < 0) {
 907                 if (WSAGetLastError() == WSAENOPROTOOPT) {
 908                     isRcvTimeoutSupported = JNI_FALSE;
 909                 } else {
 910                     NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");
 911                 }
 912             }
 913             if (fd1 != -1) {
 914                 if (setsockopt(fd1, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
 915                                         sizeof(timeout)) < 0) {
 916                     NET_ThrowCurrent(env, "setsockopt SO_RCVTIMEO");
 917                 }
 918             }
 919         }
 920         return;
 921     }
 922 
 923     /*
 924      * Map the Java level socket option to the platform specific
 925      * level
 926      */
 927     if (NET_MapSocketOption(cmd, &level, &optname)) {
 928         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 929                         "Invalid option");
 930         return;
 931     }
 932 
 933     switch (cmd) {
 934 
 935         case java_net_SocketOptions_TCP_NODELAY :
 936         case java_net_SocketOptions_SO_OOBINLINE :
 937         case java_net_SocketOptions_SO_KEEPALIVE :
 938         case java_net_SocketOptions_SO_REUSEADDR :
 939             optval.i = (on ? 1 : 0);
 940             optlen = sizeof(optval.i);
 941             break;
 942 
 943         case java_net_SocketOptions_SO_SNDBUF :
 944         case java_net_SocketOptions_SO_RCVBUF :
 945         case java_net_SocketOptions_IP_TOS :
 946             {
 947                 jclass cls;
 948                 jfieldID fid;
 949 
 950                 cls = (*env)->FindClass(env, "java/lang/Integer");
 951                 CHECK_NULL(cls);
 952                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 953                 CHECK_NULL(fid);
 954 
 955                 optval.i = (*env)->GetIntField(env, value, fid);
 956                 optlen = sizeof(optval.i);
 957             }
 958             break;
 959 
 960         case java_net_SocketOptions_SO_LINGER :
 961             {
 962                 jclass cls;
 963                 jfieldID fid;
 964 
 965                 cls = (*env)->FindClass(env, "java/lang/Integer");
 966                 CHECK_NULL(cls);
 967                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 968                 CHECK_NULL(fid);
 969 
 970                 if (on) {
 971                     optval.ling.l_onoff = 1;
 972                     optval.ling.l_linger =
 973                         (unsigned short)(*env)->GetIntField(env, value, fid);
 974                 } else {
 975                     optval.ling.l_onoff = 0;
 976                     optval.ling.l_linger = 0;
 977                 }
 978                 optlen = sizeof(optval.ling);
 979             }
 980             break;
 981 
 982         default: /* shouldn't get here */
 983             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 984                 "Option not supported by TwoStacksPlainSocketImpl");
 985             return;
 986     }
 987 
 988     if (fd != -1) {
 989         if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) {
 990             NET_ThrowCurrent(env, "setsockopt");
 991         }
 992     }
 993 
 994     if (fd1 != -1) {
 995         if (NET_SetSockOpt(fd1, level, optname, (void *)&optval, optlen) < 0) {
 996             NET_ThrowCurrent(env, "setsockopt");
 997         }
 998     }
 999 }
1000 
1001 
1002 /*
1003  * Class:     java_net_TwoStacksPlainSocketImpl
1004  * Method:    socketGetOption
1005  * Signature: (I)I
1006  */
1007 JNIEXPORT jint JNICALL
1008 Java_java_net_TwoStacksPlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,
1009                                               jint opt, jobject iaContainerObj) {
1010 
1011     int fd, fd1;
1012     int level, optname, optlen;
1013     union {
1014         int i;
1015         struct linger ling;
1016     } optval;
1017 
1018     /*
1019      * Get SOCKET and check it hasn't been closed
1020      */
1021     fd = getFD(env, this);
1022     fd1 = getFD1(env, this);
1023 
1024     if (fd < 0 && fd1 < 0) {
1025         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1026         return -1;
1027     }
1028     if (fd < 0) {
1029         fd = fd1;
1030     }
1031 
1032     /* For IPv6, we assume both sockets have the same setting always */
1033 
1034     /*
1035      * SO_BINDADDR isn't a socket option
1036      */
1037     if (opt == java_net_SocketOptions_SO_BINDADDR) {
1038         SOCKETADDRESS him;
1039         int len;
1040         int port;
1041         jobject iaObj;
1042         jclass iaCntrClass;
1043         jfieldID iaFieldID;
1044 
1045         len = sizeof(him);
1046 
1047         if (fd == -1) {
1048             /* must be an IPV6 only socket. Case where both sockets are != -1
1049              * is handled in java
1050              */
1051             fd = getFD1 (env, this);
1052         }
1053 
1054         if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) {
1055             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1056                              "Error getting socket name");
1057             return -1;
1058         }
1059         iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
1060         CHECK_NULL_RETURN(iaObj, -1);
1061 
1062         iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
1063         iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
1064         CHECK_NULL_RETURN(iaFieldID, -1);
1065         (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
1066         return 0; /* notice change from before */
1067     }
1068 
1069     /*
1070      * Map the Java level socket option to the platform specific
1071      * level and option name.
1072      */
1073     if (NET_MapSocketOption(opt, &level, &optname)) {
1074         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1075         return -1;
1076     }
1077 
1078     /*
1079      * Args are int except for SO_LINGER
1080      */
1081     if (opt == java_net_SocketOptions_SO_LINGER) {
1082         optlen = sizeof(optval.ling);
1083     } else {
1084         optlen = sizeof(optval.i);
1085         optval.i = 0;
1086     }
1087 
1088     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1089         NET_ThrowCurrent(env, "getsockopt");
1090         return -1;
1091     }
1092 
1093     switch (opt) {
1094         case java_net_SocketOptions_SO_LINGER:
1095             return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
1096 
1097         case java_net_SocketOptions_SO_SNDBUF:
1098         case java_net_SocketOptions_SO_RCVBUF:
1099         case java_net_SocketOptions_IP_TOS:
1100             return optval.i;
1101 
1102         case java_net_SocketOptions_TCP_NODELAY :
1103         case java_net_SocketOptions_SO_OOBINLINE :
1104         case java_net_SocketOptions_SO_KEEPALIVE :
1105         case java_net_SocketOptions_SO_REUSEADDR :
1106             return (optval.i == 0) ? -1 : 1;
1107 
1108         default: /* shouldn't get here */
1109             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1110                 "Option not supported by TwoStacksPlainSocketImpl");
1111             return -1;
1112     }
1113 }
1114 
1115 /*
1116  * Class:     java_net_TwoStacksPlainSocketImpl
1117  * Method:    socketShutdown
1118  * Signature: (I)V
1119  */
1120 JNIEXPORT void JNICALL
1121 Java_java_net_TwoStacksPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
1122                                              jint howto)
1123 {
1124 
1125     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1126     jint fd;
1127 
1128     /*
1129      * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
1130      * -1 already?
1131      */
1132     if (IS_NULL(fdObj)) {
1133         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1134                         "socket already closed");
1135         return;
1136     } else {
1137         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1138     }
1139     shutdown(fd, howto);
1140 }
1141 
1142 /*
1143  * Class:     java_net_TwoStacksPlainSocketImpl
1144  * Method:    socketSendUrgentData
1145  * Signature: (B)V
1146  */
1147 JNIEXPORT void JNICALL
1148 Java_java_net_TwoStacksPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
1149                                              jint data) {
1150     /* The fd field */
1151     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
1152     int n, fd;
1153     unsigned char d = data & 0xff;
1154 
1155     if (IS_NULL(fdObj)) {
1156         JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1157         return;
1158     } else {
1159         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1160         /* Bug 4086704 - If the Socket associated with this file descriptor
1161          * was closed (sysCloseFD), the the file descriptor is set to -1.
1162          */
1163         if (fd == -1) {
1164             JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
1165             return;
1166         }
1167 
1168     }
1169     n = send(fd, (char *)&data, 1, MSG_OOB);
1170     if (n == JVM_IO_ERR) {
1171         NET_ThrowCurrent(env, "send");
1172         return;
1173     }
1174     if (n == JVM_IO_INTR) {
1175         JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
1176         return;
1177     }
1178 }