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:    localAddress
 375  * Signature: (ILjava/net/InetAddressContainer;)V
 376  */
 377 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_localAddress
 378   (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {
 379     int port;
 380     SOCKETADDRESS sa;
 381     int len = sizeof(sa);
 382     jobject iaObj;
 383     jclass iaContainerClass;
 384     jfieldID iaFieldID;
 385 
 386     if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
 387         NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
 388         return;
 389     }
 390     iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
 391     CHECK_NULL(iaObj);
 392 
 393     iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
 394     iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
 395     CHECK_NULL(iaFieldID);
 396     (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
 397 }
 398 
 399 /*
 400  * Class:     java_net_DualStackPlainSocketImpl
 401  * Method:    socketListen
 402  * Signature: (I)V
 403  */
 404 JNIEXPORT void JNICALL
 405 Java_java_net_DualStackPlainSocketImpl_socketListen
 406   (JNIEnv *env, jobject this, jint count)
 407 {
 408     /* this FileDescriptor fd field */
 409     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 410     /* fdObj's int fd field */
 411     int fd = INVALID_SOCKET;
 412 
 413     if (IS_NULL(fdObj)) {
 414         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 415                         "socket closed");
 416         return;
 417     }
 418 
 419     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 420 
 421     if (listen(fd, count) == SOCKET_ERROR) {
 422         NET_ThrowNew(env, WSAGetLastError(), "listen failed");
 423     }
 424 }
 425 
 426 /*
 427  * Class:     java_net_DualStackPlainSocketImpl
 428  * Method:    socketAccept
 429  * Signature: (Ljava/net/SocketImpl;)V
 430  */
 431 JNIEXPORT void JNICALL
 432 Java_java_net_DualStackPlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
 433                                            jobject socket)
 434 {
 435     /* fields on this */
 436     jint port=0;
 437     jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
 438     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 439 
 440     /* the FileDescriptor field on socket */
 441     jobject socketFdObj;
 442 
 443     /* the InetAddress field on socket */
 444     jobject socketAddressObj;
 445 
 446     /* the fd int field on fdObj */
 447     jint fd=-1;
 448 
 449     /* accepted fd */
 450     jint newfd;
 451 
 452     SOCKETADDRESS sa;
 453     jint len;
 454     int ret;
 455 
 456     if (IS_NULL(fdObj)) {
 457         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 458                         "Socket closed");
 459         return;
 460     }
 461 
 462     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 463 
 464     if (IS_NULL(socket)) {
 465         JNU_ThrowNullPointerException(env, "socket is null");
 466         return;
 467     } else {
 468         socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
 469     }
 470     if (IS_NULL(socketFdObj)) {
 471         JNU_ThrowNullPointerException(env, "socket fd obj");
 472         return;
 473     }
 474 
 475     if (timeout > 0) {
 476         if (configureBlocking(env, fd, JNI_FALSE) == JNI_FALSE) {
 477             // exception pending
 478             return;
 479         }
 480 
 481         ret = NET_Timeout(fd, timeout);
 482         if (ret == 0) {
 483             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 484                             "Accept timed out");
 485             configureBlocking(env, fd, JNI_TRUE);
 486             return;
 487         } else if (ret == -1) {
 488             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 489             configureBlocking(env, fd, JNI_TRUE);
 490             return;
 491         } else if (ret == -2) {
 492             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 493                             "operation interrupted");
 494             configureBlocking(env, fd, JNI_TRUE);
 495             return;
 496         }
 497     }
 498 
 499     len = sizeof(sa);
 500     memset((char *)&sa, 0, len);
 501     newfd = accept(fd, &sa.sa, &len);
 502 
 503     if (timeout > 0) {
 504         if (configureBlocking(env, fd, JNI_TRUE) == JNI_FALSE) {
 505             if (newfd != INVALID_SOCKET) {
 506                 closesocket(newfd);
 507             }
 508             // exception pending
 509             return;
 510         }
 511     }
 512 
 513     if (newfd == INVALID_SOCKET) {
 514         if (WSAGetLastError() == -2) {
 515             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 516                             "operation interrupted");
 517         } else {
 518             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 519                             "socket closed");
 520         }
 521         (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, -1);
 522         return;
 523     }
 524     SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
 525     if (configureBlocking(env, newfd, JNI_TRUE) == JNI_FALSE) {
 526         closesocket(newfd);
 527         // exception pending
 528         return;
 529     }
 530 
 531     socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port);
 532     if (socketAddressObj == NULL) {
 533         /* should be pending exception */
 534         closesocket(newfd);
 535         return;
 536     }
 537 
 538     (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd);
 539     (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
 540     (*env)->SetIntField(env, socket, psi_portID, (int)port);
 541     /* also fill up the local port information */
 542     port = (*env)->GetIntField(env, this, psi_localportID);
 543     (*env)->SetIntField(env, socket, psi_localportID, port);
 544 }
 545 
 546 /*
 547  * Class:     java_net_DualStackPlainSocketImpl
 548  * Method:    socketAvailable
 549  * Signature: ()I
 550  */
 551 JNIEXPORT jint JNICALL
 552 Java_java_net_DualStackPlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
 553 
 554     jint available = -1;
 555     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 556     jint fd;
 557 
 558     if (IS_NULL(fdObj)) {
 559         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 560         return -1;
 561     } else {
 562         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 563     }
 564 
 565     if (ioctlsocket(fd, FIONREAD, &available) == SOCKET_ERROR) {
 566         NET_ThrowNew(env, WSAGetLastError(), "socket available");
 567     }
 568     return available;
 569 }
 570 
 571 /*
 572  * Class:     java_net_DualStackPlainSocketImpl
 573  * Method:    socketClose
 574  * Signature: ()V
 575  */
 576 JNIEXPORT void JNICALL
 577 Java_java_net_DualStackPlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
 578                                            jboolean useDeferredClose) {
 579 
 580     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 581     jint fd=-1;
 582 
 583     if (IS_NULL(fdObj)) {
 584         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 585                         "socket already closed");
 586         return;
 587     }
 588     if (!IS_NULL(fdObj)) {
 589         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 590     }
 591     if (fd != -1) {
 592         (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
 593         NET_SocketClose(fd);
 594     }
 595 }
 596 
 597 /*
 598  * Class:     java_net_DualStackPlainSocketImpl
 599  * Method:    socketShutdown
 600  * Signature: (I)V
 601  */
 602 JNIEXPORT void JNICALL
 603 Java_java_net_DualStackPlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
 604                                              jint howto)
 605 {
 606 
 607     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 608     jint fd;
 609 
 610     if (IS_NULL(fdObj)) {
 611         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 612                         "socket already closed");
 613         return;
 614     } else {
 615         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 616     }
 617     shutdown(fd, howto);
 618 }
 619 
 620 /*
 621  * Class:     java_net_DualStackPlainSocketImpl
 622  * Method:    getIntOption
 623  * Signature: (II)I
 624  */
 625 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption
 626   (JNIEnv *env, jclass clazz, jint fd, jint cmd)
 627 {
 628     int level = 0, opt = 0;
 629     int result=0;
 630     struct linger linger = {0, 0};
 631     char *arg;
 632     int arglen;
 633 
 634     if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
 635         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 636         return -1;
 637     }
 638 
 639     if (opt == java_net_SocketOptions_SO_LINGER) {
 640         arg = (char *)&linger;
 641         arglen = sizeof(linger);
 642     } else {
 643         arg = (char *)&result;
 644         arglen = sizeof(result);
 645     }
 646 
 647     if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
 648         NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
 649         return -1;
 650     }
 651 
 652     if (opt == java_net_SocketOptions_SO_LINGER)
 653         return linger.l_onoff ? linger.l_linger : -1;
 654     else
 655         return result;
 656 }
 657 
 658 /*
 659  * Class:     java_net_DualStackPlainSocketImpl
 660  * Method:    socketNativeSetOption
 661  * Signature: (IZLjava/lang/Object;)V
 662  */
 663 JNIEXPORT void JNICALL
 664 Java_java_net_DualStackPlainSocketImpl_socketNativeSetOption
 665   (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value)
 666 {
 667     /* The fd field */
 668     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 669 
 670     jint fd;
 671     int level = 0, optname = 0, optlen = 0;
 672     union {
 673         int i;
 674         struct linger ling;
 675     } optval;
 676 
 677     memset((char *)&optval, 0, sizeof(optval));
 678 
 679     /*
 680      * Get SOCKET and check that it hasn't been closed
 681      */
 682     if (IS_NULL(fdObj)) {
 683         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 684         return;
 685     } else {
 686         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 687     }
 688     if (fd < 0) {
 689         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 690         return;
 691     }
 692 
 693     if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
 694         // timeout implemented through select.
 695         return;
 696     }
 697 
 698     /*
 699      * Map the Java level socket option to the platform specific
 700      * level and option name.
 701      */
 702     if (NET_MapSocketOption(cmd, &level, &optname)) {
 703         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
 704         return;
 705     }
 706 
 707     switch (cmd) {
 708 
 709         case java_net_SocketOptions_TCP_NODELAY :
 710         case java_net_SocketOptions_SO_OOBINLINE :
 711         case java_net_SocketOptions_SO_KEEPALIVE :
 712         case java_net_SocketOptions_SO_REUSEADDR :
 713             optval.i = (on ? 1 : 0);
 714             optlen = sizeof(optval.i);
 715             break;
 716 
 717         case java_net_SocketOptions_SO_SNDBUF :
 718         case java_net_SocketOptions_SO_RCVBUF :
 719         case java_net_SocketOptions_IP_TOS :
 720             {
 721                 jclass cls;
 722                 jfieldID fid;
 723 
 724                 cls = (*env)->FindClass(env, "java/lang/Integer");
 725                 CHECK_NULL(cls);
 726                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 727                 CHECK_NULL(fid);
 728 
 729                 optval.i = (*env)->GetIntField(env, value, fid);
 730                 optlen = sizeof(optval.i);
 731             }
 732             break;
 733 
 734         case java_net_SocketOptions_SO_LINGER :
 735             {
 736                 jclass cls;
 737                 jfieldID fid;
 738 
 739                 cls = (*env)->FindClass(env, "java/lang/Integer");
 740                 CHECK_NULL(cls);
 741                 fid = (*env)->GetFieldID(env, cls, "value", "I");
 742                 CHECK_NULL(fid);
 743 
 744                 if (on) {
 745                     optval.ling.l_onoff = 1;
 746                     optval.ling.l_linger =
 747                         (unsigned short)(*env)->GetIntField(env, value, fid);
 748                 } else {
 749                     optval.ling.l_onoff = 0;
 750                     optval.ling.l_linger = 0;
 751                 }
 752                 optlen = sizeof(optval.ling);
 753             }
 754             break;
 755 
 756         default: /* shouldn't get here */
 757             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 758                 "Option not supported by DualStackPlainSocketImpl");
 759             return;
 760     }
 761 
 762     if (NET_SetSockOpt(fd, level, optname, (void *)&optval, optlen) < 0) {
 763         NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
 764     }
 765 }
 766 
 767 /*
 768  * Class:     java_net_DualStackPlainSocketImpl
 769  * Method:    socketNativeGetOption
 770  * Signature: (ILjava/lang/Object;)I
 771  */
 772 JNIEXPORT jint JNICALL
 773 Java_java_net_DualStackPlainSocketImpl_socketNativeGetOption
 774   (JNIEnv *env, jobject this, jint opt, jobject iaContainerObj)
 775 {
 776     return -1;
 777 }
 778 
 779 /*
 780  * Class:     java_net_DualStackPlainSocketImpl
 781  * Method:    socketSendUrgentData
 782  * Signature: (B)V
 783  */
 784 JNIEXPORT void JNICALL
 785 Java_java_net_DualStackPlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
 786                                              jint data) {
 787     /* The fd field */
 788     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
 789     int n, fd;
 790     unsigned char d = (unsigned char) data & 0xff;
 791 
 792     if (IS_NULL(fdObj)) {
 793         JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
 794         return;
 795     } else {
 796         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 797 
 798         if (fd == -1) {
 799             JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
 800             return;
 801         }
 802 
 803     }
 804     n = send(fd, (char *)&data, 1, MSG_OOB);
 805     if (n == SOCKET_ERROR) {
 806         NET_ThrowNew(env, WSAGetLastError(), "send");
 807     }
 808 }