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