1 /*
   2  * Copyright (c) 2007, 2018, 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 #include "net_util.h"
  26 
  27 #include "java_net_DualStackPlainSocketImpl.h"
  28 #include "java_net_SocketOptions.h"
  29 
  30 /************************************************************************
  31  * DualStackPlainSocketImpl
  32  */
  33 
  34 static jfieldID IO_fd_fdID;
  35 
  36 jfieldID psi_fdID;
  37 jfieldID psi_addressID;
  38 jfieldID psi_portID;
  39 jfieldID psi_localportID;
  40 jfieldID psi_timeoutID;
  41 
  42 
  43 static jboolean configureBlocking(JNIEnv *env, jint fd, jboolean blocking) {
  44     u_long arg = (blocking == JNI_TRUE) ? 0 : 1;
  45 
  46     if (ioctlsocket(fd, FIONBIO, &arg) == SOCKET_ERROR) {
  47         if (!(*env)->ExceptionCheck(env)) {
  48             NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");
  49         }
  50         return JNI_FALSE;
  51     }
  52 
  53     return JNI_TRUE;
  54 }
  55 
  56 /*
  57  * Class:     java_net_DualStackPlainSocketImpl
  58  * Method:    initProto
  59  * Signature: ()V
  60  */
  61 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initProto
  62   (JNIEnv *env, jclass cls) {
  63 
  64     psi_fdID = (*env)->GetFieldID(env, cls , "fd", "Ljava/io/FileDescriptor;");
  65     CHECK_NULL(psi_fdID);
  66     psi_addressID = (*env)->GetFieldID(env, cls, "address",
  67                                           "Ljava/net/InetAddress;");
  68     CHECK_NULL(psi_addressID);
  69     psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
  70     CHECK_NULL(psi_portID);
  71     psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
  72     CHECK_NULL(psi_localportID);
  73     psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
  74     CHECK_NULL(psi_timeoutID);
  75 
  76     initInetAddressIDs(env);
  77 
  78     // implement read timeout with select.
  79     isRcvTimeoutSupported = 0;
  80 
  81     IO_fd_fdID = NET_GetFileDescriptorID(env);
  82     CHECK_NULL(IO_fd_fdID);
  83 }
  84 
  85 /*
  86  * Class:     java_net_DualStackPlainSocketImpl
  87  * Method:    socketCreate
  88  * Signature: (Z)V
  89  */
  90 JNIEXPORT void JNICALL
  91 Java_java_net_DualStackPlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
  92                                            jboolean stream) {
  93     jobject fdObj;
  94     int fd;
  95 
  96     fdObj = (*env)->GetObjectField(env, this, psi_fdID);
  97 
  98     if (IS_NULL(fdObj)) {
  99         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 100                         "null fd object");
 101         return;
 102     }
 103     fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
 104     if (fd == INVALID_SOCKET) {
 105         NET_ThrowNew(env, WSAGetLastError(), "create");
 106         return;
 107     } else {
 108         int arg = 0;
 109         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
 110                        sizeof(int)) == SOCKET_ERROR) {
 111             NET_ThrowNew(env, WSAGetLastError(), "create");
 112         }
 113 
 114         /* Set socket attribute so it is not passed to any child process */
 115         SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
 116         (*env)->SetIntField(env, fdObj, IO_fd_fdID, (int)fd);
 117     }
 118 }
 119 
 120 /*
 121  * Class:     java_net_DualStackPlainSocketImpl
 122  * Method:    socketBind
 123  * Signature: (Ljava/net/InetAddress;I)V
 124  */
 125 JNIEXPORT void JNICALL
 126 Java_java_net_DualStackPlainSocketImpl_socketBind(JNIEnv *env, jobject this,
 127                                          jobject iaObj, jint localport,
 128                                          jboolean exclBind) {
 129 
 130     /* fdObj is the FileDescriptor field on this */
 131     jobject fdObj;
 132     /* fd is an int field on fdObj */
 133     int fd, len = 0;
 134 
 135     int rv;
 136 
 137     SOCKETADDRESS sa;
 138 
 139     fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 140 
 141     if (IS_NULL(fdObj)) {
 142         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 143                         "Socket closed");
 144         return;
 145     } else {
 146         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 147     }
 148     if (IS_NULL(iaObj)) {
 149         JNU_ThrowNullPointerException(env, "inet address argument");
 150         return;
 151     }
 152 
 153     if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, &len,
 154                                   JNI_TRUE) != 0) {
 155         return;
 156     }
 157     rv = NET_WinBind(fd, &sa, len, exclBind);
 158 
 159     if (rv == SOCKET_ERROR) {
 160         NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
 161         return;
 162     }
 163 
 164     /* set the address */
 165     (*env)->SetObjectField(env, this, psi_addressID, iaObj);
 166 
 167     /* intialize the local port */
 168     if (localport == 0) {
 169         /* Now that we're a bound socket, let's extract the port number
 170          * that the system chose for us and store it in the Socket object.
 171          */
 172         int len = sizeof(SOCKETADDRESS);
 173         u_short port;
 174 
 175         if (getsockname(fd, &sa.sa, &len) == -1) {
 176             NET_ThrowCurrent(env, "getsockname in plain socketBind");
 177             return;
 178         }
 179         port = ntohs((u_short) GET_PORT (&sa));
 180 
 181         (*env)->SetIntField(env, this, psi_localportID, (int)port);
 182     } else {
 183         (*env)->SetIntField(env, this, psi_localportID, localport);
 184     }
 185 }
 186 
 187 /*
 188  * Class:     java_net_DualStackPlainSocketImpl
 189  * Method:    socketConnect
 190  * Signature: (Ljava/net/InetAddress;I)V
 191  */
 192 JNIEXPORT void JNICALL
 193 Java_java_net_DualStackPlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
 194                                                      jobject iaObj, jint port,
 195                                                      jint timeout)
 196 {
 197     jint localport = (*env)->GetIntField(env, this, psi_localportID);
 198 
 199     /* family and localport are int fields of iaObj */
 200     jint fd = -1;
 201     jint len;
 202 
 203     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 204 
 205     SOCKETADDRESS sa;
 206 
 207     /* The result of the connection */
 208     int connect_res;
 209     memset((char *)&sa, 0, sizeof(sa));
 210 
 211     if (IS_NULL(fdObj)) {
 212         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 213                         "socket closed");
 214         return;
 215     }
 216 
 217     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 218 
 219     if (IS_NULL(iaObj)) {
 220         JNU_ThrowNullPointerException(env, "inet address argument is null.");
 221         return;
 222     }
 223 
 224     if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len,
 225                                   JNI_TRUE) != 0) {
 226         return;
 227     }
 228 
 229     if (fd == -1) {
 230         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 231                         "Destination unreachable");
 232         return;
 233     }
 234 
 235     if (timeout <= 0) {
 236         connect_res = connect(fd, &sa.sa, len);
 237         if (connect_res == SOCKET_ERROR) {
 238             int err = WSAGetLastError();
 239             if (err == WSAEADDRNOTAVAIL) {
 240                 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
 241                     "connect: Address is invalid on local machine, or port is not valid on remote machine");
 242             } else {
 243                 NET_ThrowNew(env, err, "connect");
 244             }
 245             return;
 246         }
 247     } else {
 248         if (configureBlocking(env, fd, JNI_FALSE) == JNI_FALSE) {
 249             // exception pending
 250             return;
 251         }
 252 
 253         /* initiate the connect */
 254         connect_res = connect(fd, &sa.sa, len);
 255         if (connect_res == SOCKET_ERROR) {
 256             int err = WSAGetLastError();
 257             if (err != WSAEWOULDBLOCK) {
 258                 connect_res = err;
 259             } else {
 260                 fd_set wr, ex;
 261                 struct timeval t;
 262 
 263                 FD_ZERO(&wr);
 264                 FD_ZERO(&ex);
 265                 FD_SET(fd, &wr);
 266                 FD_SET(fd, &ex);
 267                 t.tv_sec = timeout / 1000;
 268                 t.tv_usec = (timeout % 1000) * 1000;
 269 
 270                 /*
 271                  * Wait for timout, connection established or
 272                  * connection failed.
 273                  */
 274                 connect_res = select(fd+1, 0, &wr, &ex, &t);
 275 
 276                 /*
 277                  * Timeout before connection is established/failed so
 278                  * we throw exception and shutdown input/output to prevent
 279                  * socket from being used.
 280                  * The socket should be closed immediately by the caller.
 281                  */
 282                 if (connect_res == 0) {
 283                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 284                                     "connect timed out");
 285                     shutdown( fd, SD_BOTH );
 286 
 287                     /* make socket blocking again - just in case */
 288                     configureBlocking(env, fd, JNI_TRUE);
 289                     return;
 290                 }
 291                 /*
 292                  * Socket is writable or error occurred. On some Windows editions
 293                  * the socket will appear writable when the connect fails so we
 294                  * check for error rather than writable.
 295                  */
 296                 if (!FD_ISSET(fd, &ex)) {
 297                     connect_res = 0;        /* connection established */
 298                 } else {
 299                     int optlen = sizeof(&connect_res);
 300 
 301                     /*
 302                      * Connection failed. The logic here is designed to work around
 303                      * bug on Windows NT whereby using getsockopt to obtain the
 304                      * last error (SO_ERROR) indicates there is no error. The workaround
 305                      * on NT is to allow winsock to be scheduled and this is done by
 306                      * yielding and retrying. As yielding is problematic in heavy
 307                      * load conditions we attempt up to 3 times to get the error reason.
 308                      */
 309                     int retry;
 310                     for (retry=0; retry<3; retry++) {
 311                         NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
 312                                        (char*)&connect_res, &optlen);
 313                         if (connect_res) {
 314                             break;
 315                         }
 316                         Sleep(0);
 317                     }
 318 
 319                     if (connect_res == 0) {
 320                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 321                                         "Unable to establish connection");
 322                     } else {
 323                         NET_ThrowNew(env, connect_res, "connect");
 324                     }
 325                     return;
 326                 }
 327             }
 328         }
 329 
 330         if (configureBlocking(env, fd, JNI_TRUE) == JNI_FALSE) {
 331             // exception pending
 332             return;
 333         }
 334     }
 335 
 336     if (connect_res) {
 337         if (connect_res == WSAEADDRNOTAVAIL) {
 338             JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
 339                 "connect: Address is invalid on local machine, or port is not valid on remote machine");
 340         } else {
 341             NET_ThrowNew(env, connect_res, "connect");
 342         }
 343         return;
 344     }
 345 
 346     /*
 347      * we need to initialize the local port field if bind was called
 348      * previously to the connect (by the client) then localport field
 349      * will already be initialized
 350      */
 351     if (localport == 0) {
 352         /* Now that we're a connected socket, let's extract the port number
 353          * that the system chose for us and store it in the Socket object.
 354          */
 355         len = sizeof(sa);
 356         memset((char *)&sa, 0, len);
 357 
 358         if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
 359             if (WSAGetLastError() == WSAENOTSOCK) {
 360                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 361                                 "Socket closed");
 362             } else {
 363                 NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
 364             }
 365             return;
 366         }
 367         localport = (jint) ntohs((u_short)GET_PORT(&sa));
 368         (*env)->SetIntField(env, this, psi_localportID, (int) localport);
 369     }
 370 }
 371 
 372 /*
 373  * Class:     java_net_DualStackPlainSocketImpl
 374  * Method:    socketListen
 375  * Signature: (I)V
 376  */
 377 JNIEXPORT void JNICALL
 378 Java_java_net_DualStackPlainSocketImpl_socketListen
 379   (JNIEnv *env, jobject this, jint count)
 380 {
 381     /* this FileDescriptor fd field */
 382     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 383     /* fdObj's int fd field */
 384     int fd = INVALID_SOCKET;
 385 
 386     if (IS_NULL(fdObj)) {
 387         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 388                         "socket closed");
 389         return;
 390     }
 391 
 392     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 393 
 394     if (listen(fd, count) == SOCKET_ERROR) {
 395         NET_ThrowNew(env, WSAGetLastError(), "listen failed");
 396     }
 397 }
 398 
 399 /*
 400  * Class:     java_net_DualStackPlainSocketImpl
 401  * Method:    socketAccept
 402  * Signature: (Ljava/net/SocketImpl;)V
 403  */
 404 JNIEXPORT void JNICALL
 405 Java_java_net_DualStackPlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
 406                                            jobject socket)
 407 {
 408     /* fields on this */
 409     jint port=0;
 410     jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
 411     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 412 
 413     /* the FileDescriptor field on socket */
 414     jobject socketFdObj;
 415 
 416     /* the InetAddress field on socket */
 417     jobject socketAddressObj;
 418 
 419     /* the fd int field on fdObj */
 420     jint fd=-1;
 421 
 422     /* accepted fd */
 423     jint newfd;
 424 
 425     SOCKETADDRESS sa;
 426     jint len;
 427     int ret;
 428 
 429     if (IS_NULL(fdObj)) {
 430         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 431                         "Socket closed");
 432         return;
 433     }
 434 
 435     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 436 
 437     if (IS_NULL(socket)) {
 438         JNU_ThrowNullPointerException(env, "socket is null");
 439         return;
 440     } else {
 441         socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
 442     }
 443     if (IS_NULL(socketFdObj)) {
 444         JNU_ThrowNullPointerException(env, "socket fd obj");
 445         return;
 446     }
 447 
 448     if (timeout > 0) {
 449         if (configureBlocking(env, fd, JNI_FALSE) == JNI_FALSE) {
 450             // exception pending
 451             return;
 452         }
 453 
 454         ret = NET_Timeout(fd, timeout);
 455         if (ret == 0) {
 456             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 457                             "Accept timed out");
 458             configureBlocking(env, fd, JNI_TRUE);
 459             return;
 460         } else if (ret == -1) {
 461             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 462             configureBlocking(env, fd, JNI_TRUE);
 463             return;
 464         } else if (ret == -2) {
 465             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 466                             "operation interrupted");
 467             configureBlocking(env, fd, JNI_TRUE);
 468             return;
 469         }
 470     }
 471 
 472     len = sizeof(sa);
 473     memset((char *)&sa, 0, len);
 474     newfd = accept(fd, &sa.sa, &len);
 475 
 476     if (timeout > 0) {
 477         if (configureBlocking(env, fd, JNI_TRUE) == JNI_FALSE) {
 478             if (newfd != INVALID_SOCKET) {
 479                 closesocket(newfd);
 480             }
 481             // exception pending
 482             return;
 483         }
 484     }
 485 
 486     if (newfd == INVALID_SOCKET) {
 487         if (WSAGetLastError() == -2) {
 488             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 489                             "operation interrupted");
 490         } else {
 491             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 492                             "socket closed");
 493         }
 494         (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, -1);
 495         return;
 496     }
 497     SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
 498     if (configureBlocking(env, newfd, JNI_TRUE) == JNI_FALSE) {
 499         closesocket(newfd);
 500         // exception pending
 501         return;
 502     }
 503 
 504     socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port);
 505     if (socketAddressObj == NULL) {
 506         /* should be pending exception */
 507         closesocket(newfd);
 508         return;
 509     }
 510 
 511     (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd);
 512     (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
 513     (*env)->SetIntField(env, socket, psi_portID, (int)port);
 514     /* also fill up the local port information */
 515     port = (*env)->GetIntField(env, this, psi_localportID);
 516     (*env)->SetIntField(env, socket, psi_localportID, port);
 517 }
 518 
 519 /*
 520  * Class:     java_net_DualStackPlainSocketImpl
 521  * Method:    socketAvailable
 522  * Signature: ()I
 523  */
 524 JNIEXPORT jint JNICALL
 525 Java_java_net_DualStackPlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
 526 
 527     jint available = -1;
 528     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 529     jint fd;
 530 
 531     if (IS_NULL(fdObj)) {
 532         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 533         return -1;
 534     } else {
 535         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 536     }
 537 
 538     if (ioctlsocket(fd, FIONREAD, &available) == SOCKET_ERROR) {
 539         NET_ThrowNew(env, WSAGetLastError(), "socket available");
 540     }
 541     return available;
 542 }
 543 
 544 /*
 545  * Class:     java_net_DualStackPlainSocketImpl
 546  * Method:    socketClose
 547  * Signature: ()V
 548  */
 549 JNIEXPORT void JNICALL
 550 Java_java_net_DualStackPlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
 551                                            jboolean useDeferredClose) {
 552 
 553     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 554     jint fd=-1;
 555 
 556     if (IS_NULL(fdObj)) {
 557         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 558                         "socket already closed");
 559         return;
 560     }
 561     if (!IS_NULL(fdObj)) {
 562         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 563     }
 564     if (fd != -1) {
 565         (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
 566         NET_SocketClose(fd);
 567     }
 568 }
 569 
 570 /*
 571  * Class:     java_net_DualStackPlainSocketImpl
 572  * Method:    socketShutdown
 573  * Signature: (I)V
 574  */
 575 JNIEXPORT void JNICALL
 576 Java_java_net_DualStackPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
 577                                              jint howto)
 578 {
 579 
 580     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 581     jint fd;
 582 
 583     if (IS_NULL(fdObj)) {
 584         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 585                         "socket already closed");
 586         return;
 587     } else {
 588         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 589     }
 590     shutdown(fd, howto);
 591 }
 592 
 593 /*
 594  * Class:     java_net_DualStackPlainSocketImpl
 595  * Method:    socketNativeSetOption
 596  * Signature: (IZLjava/lang/Object;)V
 597  */
 598 JNIEXPORT void JNICALL
 599 Java_java_net_DualStackPlainSocketImpl_socketNativeSetOption
 600   (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value)
 601 {
 602     /* The fd field */
 603     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 604 
 605     jint fd;
 606     int level = 0, optname = 0, optlen = 0;
 607     union {
 608         int i;
 609         struct linger ling;
 610     } optval;
 611 
 612     memset((char *)&optval, 0, sizeof(optval));
 613 
 614     /*
 615      * Get SOCKET and check that it hasn't been closed
 616      */
 617     if (IS_NULL(fdObj)) {
 618         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 619         return;
 620     } else {
 621         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 622     }
 623     if (fd < 0) {
 624         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 625         return;
 626     }
 627 
 628     if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
 629         // timeout implemented through select.
 630         return;
 631     }
 632 
 633     /*
 634      * Map the Java level socket option to the platform specific
 635      * level and option name.
 636      */
 637     if (NET_MapSocketOption(cmd, &level, &optname)) {
 638         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 639         return;
 640     }
 641 
 642     switch (cmd) {
 643 
 644         case java_net_SocketOptions_TCP_NODELAY:
 645         case java_net_SocketOptions_SO_OOBINLINE:
 646         case java_net_SocketOptions_SO_KEEPALIVE:
 647         case java_net_SocketOptions_SO_REUSEADDR:
 648             optval.i = (on ? 1 : 0);
 649             optlen = sizeof(optval.i);
 650             break;
 651 
 652         case java_net_SocketOptions_SO_SNDBUF:
 653         case java_net_SocketOptions_SO_RCVBUF:
 654         case java_net_SocketOptions_IP_TOS:
 655             {
 656                 jclass cls;
 657                 jfieldID fid;
 658 
 659                 cls = (*env)->FindClass(env, "java/lang/Integer");
 660                 CHECK_NULL(cls);
 661                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 662                 CHECK_NULL(fid);
 663 
 664                 optval.i = (*env)->GetIntField(env, value, fid);
 665                 optlen = sizeof(optval.i);
 666             }
 667             break;
 668 
 669         case java_net_SocketOptions_SO_LINGER :
 670             {
 671                 jclass cls;
 672                 jfieldID fid;
 673 
 674                 cls = (*env)->FindClass(env, "java/lang/Integer");
 675                 CHECK_NULL(cls);
 676                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 677                 CHECK_NULL(fid);
 678 
 679                 if (on) {
 680                     optval.ling.l_onoff = 1;
 681                     optval.ling.l_linger =
 682                         (unsigned short)(*env)->GetIntField(env, value, fid);
 683                 } else {
 684                     optval.ling.l_onoff = 0;
 685                     optval.ling.l_linger = 0;
 686                 }
 687                 optlen = sizeof(optval.ling);
 688             }
 689             break;
 690 
 691         default: /* shouldn't get here */
 692             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 693                 "Option not supported by DualStackPlainSocketImpl");
 694             return;
 695     }
 696 
 697     if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) {
 698         NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
 699     }
 700 }
 701 
 702 /*
 703  * Class:     java_net_DualStackPlainSocketImpl
 704  * Method:    socketNativeGetOption
 705  * Signature: (ILjava/lang/Object;)I
 706  */
 707 JNIEXPORT jint JNICALL
 708 Java_java_net_DualStackPlainSocketImpl_socketNativeGetOption
 709   (JNIEnv *env, jobject this, jint opt, jobject iaContainerObj)
 710 {
 711     /* The fd field */
 712     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 713 
 714     int fd;
 715     int level = 0, optname = 0, optlen = 0;
 716     union {
 717         int i;
 718         struct linger ling;
 719     } optval;
 720 
 721     /*
 722      * Get SOCKET and check it hasn't been closed
 723      */
 724     if (IS_NULL(fdObj)) {
 725         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 726         return -1;
 727     } else {
 728         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 729     }
 730     if (fd < 0) {
 731         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 732         return -1;
 733     }
 734     memset((char *)&optval, 0, sizeof(optval));
 735 
 736     /*
 737      * SO_BINDADDR isn't a socket option
 738      */
 739     if (opt == java_net_SocketOptions_SO_BINDADDR) {
 740         SOCKETADDRESS sa;
 741         int len = sizeof(sa);
 742         int port;
 743         jobject iaObj;
 744         jclass iaContainerClass;
 745         jfieldID iaFieldID;
 746 
 747         if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
 748             NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
 749             return -1;
 750         }
 751         iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
 752         CHECK_NULL_RETURN(iaObj, -1);
 753 
 754         iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
 755         iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
 756         CHECK_NULL_RETURN(iaFieldID, -1);
 757         (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
 758         return 0; /* notice change from before */
 759     }
 760 
 761     /*
 762      * Map the Java level socket option to the platform specific
 763      * level and option name.
 764      */
 765     if (NET_MapSocketOption(opt, &level, &optname)) {
 766         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 767         return -1;
 768     }
 769 
 770     /*
 771      * Args are int except for SO_LINGER
 772      */
 773     if (opt == java_net_SocketOptions_SO_LINGER) {
 774         optlen = sizeof(optval.ling);
 775     } else {
 776         optlen = sizeof(optval.i);
 777         optval.i = 0;
 778     }
 779 
 780     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
 781         NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
 782         return -1;
 783     }
 784 
 785     switch (opt) {
 786         case java_net_SocketOptions_SO_LINGER:
 787             return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
 788 
 789         case java_net_SocketOptions_SO_SNDBUF:
 790         case java_net_SocketOptions_SO_RCVBUF:
 791         case java_net_SocketOptions_IP_TOS:
 792             return optval.i;
 793 
 794         case java_net_SocketOptions_TCP_NODELAY:
 795         case java_net_SocketOptions_SO_OOBINLINE:
 796         case java_net_SocketOptions_SO_KEEPALIVE:
 797         case java_net_SocketOptions_SO_REUSEADDR:
 798             return (optval.i == 0) ? -1 : 1;
 799 
 800         default: /* shouldn't get here */
 801             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 802                 "Option not supported by TwoStacksPlainSocketImpl");
 803             return -1;
 804     }
 805 }
 806 
 807 /*
 808  * Class:     java_net_DualStackPlainSocketImpl
 809  * Method:    socketSendUrgentData
 810  * Signature: (B)V
 811  */
 812 JNIEXPORT void JNICALL
 813 Java_java_net_DualStackPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
 814                                              jint data) {
 815     /* The fd field */
 816     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 817     int n, fd;
 818     unsigned char d = (unsigned char) data & 0xff;
 819 
 820     if (IS_NULL(fdObj)) {
 821         JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
 822         return;
 823     } else {
 824         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 825 
 826         if (fd == -1) {
 827             JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
 828             return;
 829         }
 830 
 831     }
 832     n = send(fd, (char *)&data, 1, MSG_OOB);
 833     if (n == SOCKET_ERROR) {
 834         NET_ThrowNew(env, WSAGetLastError(), "send");
 835     }
 836 }