1 /*
   2  * Copyright (c) 1997, 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 <malloc.h>
  26 
  27 #include "net_util.h"
  28 #include "NetworkInterface.h"
  29 
  30 #include "java_net_TwoStacksPlainDatagramSocketImpl.h"
  31 #include "java_net_SocketOptions.h"
  32 #include "java_net_NetworkInterface.h"
  33 #include "java_net_InetAddress.h"
  34 
  35 #ifndef IPTOS_TOS_MASK
  36 #define IPTOS_TOS_MASK 0x1e
  37 #endif
  38 #ifndef IPTOS_PREC_MASK
  39 #define IPTOS_PREC_MASK 0xe0
  40 #endif
  41 
  42 
  43 #define IN_CLASSD(i)    (((long)(i) & 0xf0000000) == 0xe0000000)
  44 #define IN_MULTICAST(i) IN_CLASSD(i)
  45 
  46 extern int getAllInterfacesAndAddresses(JNIEnv *env, netif **netifPP);
  47 
  48 /************************************************************************
  49  * TwoStacksPlainDatagramSocketImpl
  50  */
  51 
  52 static jfieldID IO_fd_fdID;
  53 static jfieldID pdsi_trafficClassID;
  54 jfieldID pdsi_fdID;
  55 jfieldID pdsi_fd1ID;
  56 jfieldID pdsi_fduseID;
  57 jfieldID pdsi_lastfdID;
  58 jfieldID pdsi_timeoutID;
  59 
  60 jfieldID pdsi_localPortID;
  61 jfieldID pdsi_connected;
  62 
  63 static jclass ia4_clazz;
  64 static jmethodID ia4_ctor;
  65 
  66 /*
  67  * Notes about UDP/IPV6 on Windows (XP and 2003 server):
  68  *
  69  * fd always points to the IPv4 fd, and fd1 points to the IPv6 fd.
  70  * Both fds are used when we bind to a wild-card address. When a specific
  71  * address is used, only one of them is used.
  72  */
  73 
  74 /*
  75  * Returns a java.lang.Integer based on 'i'
  76  */
  77 jobject createInteger(JNIEnv *env, int i) {
  78     static jclass i_class = NULL;
  79     static jmethodID i_ctrID;
  80     static jfieldID i_valueID;
  81 
  82     if (i_class == NULL) {
  83         jclass c = (*env)->FindClass(env, "java/lang/Integer");
  84         CHECK_NULL_RETURN(c, NULL);
  85         i_ctrID = (*env)->GetMethodID(env, c, "<init>", "(I)V");
  86         CHECK_NULL_RETURN(i_ctrID, NULL);
  87         i_class = (*env)->NewGlobalRef(env, c);
  88         CHECK_NULL_RETURN(i_class, NULL);
  89     }
  90 
  91     return (*env)->NewObject(env, i_class, i_ctrID, i);
  92 }
  93 
  94 /*
  95  * Returns a java.lang.Boolean based on 'b'
  96  */
  97 jobject createBoolean(JNIEnv *env, int b) {
  98     static jclass b_class = NULL;
  99     static jmethodID b_ctrID;
 100     static jfieldID b_valueID;
 101 
 102     if (b_class == NULL) {
 103         jclass c = (*env)->FindClass(env, "java/lang/Boolean");
 104         CHECK_NULL_RETURN(c, NULL);
 105         b_ctrID = (*env)->GetMethodID(env, c, "<init>", "(Z)V");
 106         CHECK_NULL_RETURN(b_ctrID, NULL);
 107         b_class = (*env)->NewGlobalRef(env, c);
 108         CHECK_NULL_RETURN(b_class, NULL);
 109     }
 110 
 111     return (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0));
 112 }
 113 
 114 static int getFD(JNIEnv *env, jobject this) {
 115     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 116 
 117     if (fdObj == NULL) {
 118         return -1;
 119     }
 120     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 121 }
 122 
 123 static int getFD1(JNIEnv *env, jobject this) {
 124     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 125 
 126     if (fdObj == NULL) {
 127         return -1;
 128     }
 129     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 130 }
 131 
 132 /*
 133  * This function "purges" all outstanding ICMP port unreachable packets
 134  * outstanding on a socket and returns JNI_TRUE if any ICMP messages
 135  * have been purged. The rational for purging is to emulate normal BSD
 136  * behaviour whereby receiving a "connection reset" status resets the
 137  * socket.
 138  */
 139 static jboolean purgeOutstandingICMP(JNIEnv *env, jobject this, jint fd)
 140 {
 141     jboolean got_icmp = JNI_FALSE;
 142     char buf[1];
 143     fd_set tbl;
 144     struct timeval t = { 0, 0 };
 145     SOCKETADDRESS rmtaddr;
 146     int addrlen = sizeof(SOCKETADDRESS);
 147 
 148     memset((char *)&rmtaddr, 0, sizeof(rmtaddr));
 149 
 150     /*
 151      * Peek at the queue to see if there is an ICMP port unreachable. If there
 152      * is then receive it.
 153      */
 154     FD_ZERO(&tbl);
 155     FD_SET(fd, &tbl);
 156     while(1) {
 157         if (select(/*ignored*/fd+1, &tbl, 0, 0, &t) <= 0) {
 158             break;
 159         }
 160         if (recvfrom(fd, buf, 1, MSG_PEEK, &rmtaddr.sa, &addrlen) != SOCKET_ERROR) {
 161             break;
 162         }
 163         if (WSAGetLastError() != WSAECONNRESET) {
 164             /* some other error - we don't care here */
 165             break;
 166         }
 167 
 168         recvfrom(fd, buf, 1, 0, &rmtaddr.sa, &addrlen);
 169         got_icmp = JNI_TRUE;
 170     }
 171 
 172     return got_icmp;
 173 }
 174 
 175 
 176 /*
 177  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 178  * Method:    init
 179  * Signature: ()V
 180  */
 181 JNIEXPORT void JNICALL
 182 Java_java_net_TwoStacksPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
 183     /* get fieldIDs */
 184     pdsi_fdID = (*env)->GetFieldID(env, cls, "fd", "Ljava/io/FileDescriptor;");
 185     CHECK_NULL(pdsi_fdID);
 186     pdsi_fd1ID = (*env)->GetFieldID(env, cls, "fd1", "Ljava/io/FileDescriptor;");
 187     CHECK_NULL(pdsi_fd1ID);
 188     pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
 189     CHECK_NULL(pdsi_timeoutID);
 190     pdsi_fduseID = (*env)->GetFieldID(env, cls, "fduse", "I");
 191     CHECK_NULL(pdsi_fduseID);
 192     pdsi_lastfdID = (*env)->GetFieldID(env, cls, "lastfd", "I");
 193     CHECK_NULL(pdsi_lastfdID);
 194     pdsi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
 195     CHECK_NULL(pdsi_trafficClassID);
 196     pdsi_localPortID = (*env)->GetFieldID(env, cls, "localPort", "I");
 197     CHECK_NULL(pdsi_localPortID);
 198     pdsi_connected = (*env)->GetFieldID(env, cls, "connected", "Z");
 199     CHECK_NULL(pdsi_connected);
 200 
 201     cls = (*env)->FindClass(env, "java/io/FileDescriptor");
 202     CHECK_NULL(cls);
 203     IO_fd_fdID = NET_GetFileDescriptorID(env);
 204     CHECK_NULL(IO_fd_fdID);
 205 
 206     ia4_clazz = (*env)->FindClass(env, "java/net/Inet4Address");
 207     CHECK_NULL(ia4_clazz);
 208     ia4_clazz = (*env)->NewGlobalRef(env, ia4_clazz);
 209     CHECK_NULL(ia4_clazz);
 210     ia4_ctor = (*env)->GetMethodID(env, ia4_clazz, "<init>", "()V");
 211     CHECK_NULL(ia4_ctor);
 212 }
 213 
 214 JNIEXPORT void JNICALL
 215 Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
 216                                            jint port, jobject addressObj,
 217                                            jboolean exclBind) {
 218     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 219     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 220     int ipv6_supported = ipv6_available();
 221     int fd, fd1 = -1, lcladdrlen = 0;
 222     jint family;
 223     SOCKETADDRESS lcladdr;
 224 
 225     family = getInetAddress_family(env, addressObj);
 226     JNU_CHECK_EXCEPTION(env);
 227     if (family == java_net_InetAddress_IPv6 && !ipv6_supported) {
 228         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 229                         "Protocol family not supported");
 230         return;
 231     }
 232     if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
 233         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 234         return;
 235     } else {
 236         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 237         if (ipv6_supported) {
 238             fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 239         }
 240     }
 241 
 242     if (IS_NULL(addressObj)) {
 243         JNU_ThrowNullPointerException(env, "argument address");
 244         return;
 245     }
 246 
 247     if (NET_InetAddressToSockaddr(env, addressObj, port, &lcladdr,
 248                                   &lcladdrlen, JNI_FALSE) != 0) {
 249         return;
 250     }
 251 
 252     if (ipv6_supported) {
 253         struct ipv6bind v6bind;
 254         v6bind.addr = &lcladdr;
 255         v6bind.ipv4_fd = fd;
 256         v6bind.ipv6_fd = fd1;
 257         if (NET_BindV6(&v6bind, exclBind) != -1) {
 258             /* check if the fds have changed */
 259             if (v6bind.ipv4_fd != fd) {
 260                 fd = v6bind.ipv4_fd;
 261                 if (fd == -1) {
 262                     /* socket is closed. */
 263                     (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
 264                 } else {
 265                     /* socket was re-created */
 266                     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
 267                 }
 268             }
 269             if (v6bind.ipv6_fd != fd1) {
 270                 fd1 = v6bind.ipv6_fd;
 271                 if (fd1 == -1) {
 272                     /* socket is closed. */
 273                     (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
 274                 } else {
 275                     /* socket was re-created */
 276                     (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
 277                 }
 278             }
 279         } else {
 280             /* NET_BindV6() closes both sockets upon a failure */
 281             (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
 282             (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
 283             NET_ThrowCurrent (env, "Cannot bind");
 284             return;
 285         }
 286     } else {
 287         if (NET_WinBind(fd, &lcladdr, lcladdrlen, exclBind) == -1) {
 288             if (WSAGetLastError() == WSAEACCES) {
 289                 WSASetLastError(WSAEADDRINUSE);
 290             }
 291             (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
 292             NET_ThrowCurrent(env, "Cannot bind");
 293             closesocket(fd);
 294             return;
 295         }
 296     }
 297 
 298     if (port == 0) {
 299         if (getsockname(fd == -1 ? fd1 : fd, &lcladdr.sa, &lcladdrlen) == -1) {
 300             NET_ThrowCurrent(env, "getsockname");
 301             return;
 302         }
 303         port = ntohs((u_short)GET_PORT(&lcladdr));
 304     }
 305     (*env)->SetIntField(env, this, pdsi_localPortID, port);
 306 }
 307 
 308 
 309 /*
 310  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 311  * Method:    connect0
 312  * Signature: (Ljava/net/InetAddress;I)V
 313  */
 314 
 315 JNIEXPORT void JNICALL
 316 Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0
 317   (JNIEnv *env, jobject this, jobject address, jint port)
 318 {
 319     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 320     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 321     jint fd = -1, fd1 = -1, fdc, family;
 322     SOCKETADDRESS rmtaddr;
 323     int rmtaddrlen = 0;
 324     DWORD x1, x2; /* ignored result codes */
 325     int res, t;
 326 
 327     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 328         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 329                         "Socket closed");
 330         return;
 331     }
 332 
 333     if (!IS_NULL(fdObj)) {
 334         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 335     }
 336 
 337     if (!IS_NULL(fd1Obj)) {
 338         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 339     }
 340 
 341     if (IS_NULL(address)) {
 342         JNU_ThrowNullPointerException(env, "address");
 343         return;
 344     }
 345 
 346     family = getInetAddress_family(env, address);
 347     JNU_CHECK_EXCEPTION(env);
 348     if (family == java_net_InetAddress_IPv6 && !ipv6_available()) {
 349         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 350                         "Protocol family not supported");
 351         return;
 352     }
 353 
 354     fdc = family == java_net_InetAddress_IPv4 ? fd : fd1;
 355 
 356     /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
 357      * returns connection reset errors on connected UDP sockets (as well
 358      * as connected sockets). The solution is to only enable this feature
 359      * when the socket is connected
 360      */
 361     t = TRUE;
 362     res = WSAIoctl(fdc, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
 363 
 364     if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr,
 365                                   &rmtaddrlen, JNI_FALSE) != 0) {
 366         return;
 367     }
 368 
 369     if (connect(fdc, &rmtaddr.sa, rmtaddrlen) == -1) {
 370         NET_ThrowCurrent(env, "connect");
 371         return;
 372     }
 373 }
 374 
 375 /*
 376  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 377  * Method:    disconnect0
 378  * Signature: ()V
 379  */
 380 
 381 JNIEXPORT void JNICALL
 382 Java_java_net_TwoStacksPlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jint family) {
 383     /* The object's field */
 384     jobject fdObj;
 385     /* The fdObj'fd */
 386     jint fd, len;
 387     SOCKETADDRESS addr;
 388     DWORD x1 = 0, x2 = 0; /* ignored result codes */
 389     int t;
 390 
 391     if (family == java_net_InetAddress_IPv4) {
 392         fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 393         len = sizeof(struct sockaddr_in);
 394     } else {
 395         fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 396         len = sizeof(struct sockaddr_in6);
 397     }
 398 
 399     if (IS_NULL(fdObj)) {
 400         /* disconnect doesn't throw any exceptions */
 401         return;
 402     }
 403     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 404 
 405     memset((char *)&addr, 0, len);
 406     connect(fd, &addr.sa, len);
 407 
 408     /*
 409      * use SIO_UDP_CONNRESET
 410      * to disable ICMP port unreachable handling here.
 411      */
 412     t = FALSE;
 413     WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
 414 }
 415 
 416 /*
 417  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 418  * Method:    send
 419  * Signature: (Ljava/net/DatagramPacket;)V
 420  */
 421 JNIEXPORT void JNICALL
 422 Java_java_net_TwoStacksPlainDatagramSocketImpl_send
 423   (JNIEnv *env, jobject this, jobject packet)
 424 {
 425     char BUF[MAX_BUFFER_LEN];
 426     char *fullPacket;
 427     jobject fdObj;
 428     jint fd;
 429 
 430     jobject iaObj;
 431     jint family;
 432 
 433     jint packetBufferOffset, packetBufferLen, packetPort;
 434     jbyteArray packetBuffer;
 435     jboolean connected;
 436 
 437     SOCKETADDRESS rmtaddr;
 438     struct sockaddr *addrp = 0;
 439     int addrlen = 0;
 440     int ret;
 441 
 442     if (IS_NULL(packet)) {
 443         JNU_ThrowNullPointerException(env, "null packet");
 444         return;
 445     }
 446 
 447     iaObj = (*env)->GetObjectField(env, packet, dp_addressID);
 448 
 449     packetPort = (*env)->GetIntField(env, packet, dp_portID);
 450     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
 451     packetBuffer = (jbyteArray)(*env)->GetObjectField(env, packet, dp_bufID);
 452     connected = (*env)->GetBooleanField(env, this, pdsi_connected);
 453 
 454     if (IS_NULL(iaObj) || IS_NULL(packetBuffer)) {
 455         JNU_ThrowNullPointerException(env, "null address || null buffer");
 456         return;
 457     }
 458 
 459     family = getInetAddress_family(env, iaObj);
 460     JNU_CHECK_EXCEPTION(env);
 461     if (family == java_net_InetAddress_IPv4) {
 462         fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 463     } else {
 464         if (!ipv6_available()) {
 465             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 466                         "Protocol not allowed");
 467             return;
 468         }
 469         fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 470     }
 471 
 472     if (IS_NULL(fdObj)) {
 473         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 474                         "Socket closed");
 475         return;
 476     }
 477     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 478 
 479     packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
 480     /* Note: the buffer needn't be greater than 65,536 (0xFFFF)...
 481      * the maximum size of an IP packet. Anything bigger is truncated anyway.
 482      */
 483     if (packetBufferLen > MAX_PACKET_LEN) {
 484         packetBufferLen = MAX_PACKET_LEN;
 485     }
 486 
 487     // sockaddr arg to sendto() is null if already connected
 488     if (!connected) {
 489         if (NET_InetAddressToSockaddr(env, iaObj, packetPort, &rmtaddr,
 490                                       &addrlen, JNI_FALSE) != 0) {
 491             return;
 492         }
 493         addrp = &rmtaddr.sa;
 494     }
 495 
 496     if (packetBufferLen > MAX_BUFFER_LEN) {
 497         /* When JNI-ifying the JDK's IO routines, we turned
 498          * reads and writes of byte arrays of size greater
 499          * than 2048 bytes into several operations of size 2048.
 500          * This saves a malloc()/memcpy()/free() for big
 501          * buffers.  This is OK for file IO and TCP, but that
 502          * strategy violates the semantics of a datagram protocol.
 503          * (one big send) != (several smaller sends).  So here
 504          * we *must* alloc the buffer.  Note it needn't be bigger
 505          * than 65,536 (0xFFFF) the max size of an IP packet.
 506          * anything bigger is truncated anyway.
 507          */
 508         fullPacket = (char *)malloc(packetBufferLen);
 509         if (!fullPacket) {
 510             JNU_ThrowOutOfMemoryError(env, "Send buf native heap allocation failed");
 511             return;
 512         }
 513     } else {
 514         fullPacket = &(BUF[0]);
 515     }
 516 
 517     (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset,
 518                                packetBufferLen, (jbyte *)fullPacket);
 519     if (ret = sendto(fd, fullPacket, packetBufferLen, 0, addrp,
 520                addrlen) == SOCKET_ERROR)
 521     {
 522         NET_ThrowCurrent(env, "Datagram send failed");
 523     }
 524 
 525     if (ret > 0) {
 526       JVM_callFileWriteBytes(env, ret);
 527     }
 528 
 529     if (packetBufferLen > MAX_BUFFER_LEN) {
 530         free(fullPacket);
 531     }
 532 }
 533 
 534 /*
 535  * check which socket was last serviced when there was data on both sockets.
 536  * Only call this if sure that there is data on both sockets.
 537  */
 538 static int checkLastFD (JNIEnv *env, jobject this, int fd, int fd1) {
 539     int nextfd, lastfd = (*env)->GetIntField(env, this, pdsi_lastfdID);
 540     if (lastfd == -1) {
 541         /* arbitrary. Choose fd */
 542         (*env)->SetIntField(env, this, pdsi_lastfdID, fd);
 543         return fd;
 544     } else {
 545         if (lastfd == fd) {
 546             nextfd = fd1;
 547         } else {
 548             nextfd = fd;
 549         }
 550         (*env)->SetIntField(env, this, pdsi_lastfdID, nextfd);
 551         return nextfd;
 552     }
 553 }
 554 
 555 /*
 556  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 557  * Method:    peek
 558  * Signature: (Ljava/net/InetAddress;)I
 559  */
 560 JNIEXPORT jint JNICALL
 561 Java_java_net_TwoStacksPlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
 562                                            jobject addressObj) {
 563 
 564     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 565     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 566     jint fd;
 567 
 568     /* The address and family fields of addressObj */
 569     jint address, family;
 570 
 571     int n;
 572     SOCKETADDRESS remote_addr;
 573     jint remote_addrsize = sizeof(SOCKETADDRESS);
 574     char buf[1];
 575     BOOL retry;
 576     jlong prevTime = 0;
 577 
 578     if (IS_NULL(fdObj)) {
 579         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 580         return -1;
 581     } else {
 582         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 583         if (fd < 0) {
 584            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 585                            "socket closed");
 586            return -1;
 587         }
 588     }
 589     if (IS_NULL(addressObj)) {
 590         JNU_ThrowNullPointerException(env, "Null address in peek()");
 591         return -1;
 592     } else {
 593         address = getInetAddress_addr(env, addressObj);
 594         JNU_CHECK_EXCEPTION_RETURN(env, -1);
 595         /* We only handle IPv4 for now. Will support IPv6 once its in the os */
 596         family = AF_INET;
 597     }
 598 
 599     do {
 600         retry = FALSE;
 601 
 602         /*
 603          * If a timeout has been specified then we select on the socket
 604          * waiting for a read event or a timeout.
 605          */
 606         if (timeout) {
 607             int ret;
 608             prevTime = JVM_CurrentTimeMillis(env, 0);
 609             ret = NET_Timeout (fd, timeout);
 610             if (ret == 0) {
 611                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 612                                 "Peek timed out");
 613                 return ret;
 614             } else if (ret == -1) {
 615                 NET_ThrowCurrent(env, "timeout in datagram socket peek");
 616                 return ret;
 617             }
 618         }
 619 
 620         /* now try the peek */
 621         n = recvfrom(fd, buf, 1, MSG_PEEK, &remote_addr.sa, &remote_addrsize);
 622 
 623         if (n == SOCKET_ERROR) {
 624             if (WSAGetLastError() == WSAECONNRESET) {
 625                 jboolean connected;
 626 
 627                 /*
 628                  * An icmp port unreachable - we must receive this as Windows
 629                  * does not reset the state of the socket until this has been
 630                  * received.
 631                  */
 632                 purgeOutstandingICMP(env, this, fd);
 633 
 634                 connected =  (*env)->GetBooleanField(env, this, pdsi_connected);
 635                 if (connected) {
 636                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 637                                        "ICMP Port Unreachable");
 638                     return 0;
 639                 }
 640 
 641                 /*
 642                  * If a timeout was specified then we need to adjust it because
 643                  * we may have used up some of the timeout befor the icmp port
 644                  * unreachable arrived.
 645                  */
 646                 if (timeout) {
 647                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
 648                     timeout -= (jint)(newTime - prevTime);
 649                     if (timeout <= 0) {
 650                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 651                                 "Receive timed out");
 652                         return 0;
 653                     }
 654                     prevTime = newTime;
 655                 }
 656 
 657                 /* Need to retry the recv */
 658                 retry = TRUE;
 659             }
 660         }
 661     } while (retry);
 662 
 663     if (n == SOCKET_ERROR && WSAGetLastError() != WSAEMSGSIZE) {
 664         NET_ThrowCurrent(env, "Datagram peek failed");
 665         return 0;
 666     }
 667     setInetAddress_addr(env, addressObj, ntohl(remote_addr.sa4.sin_addr.s_addr));
 668     JNU_CHECK_EXCEPTION_RETURN(env, -1);
 669     setInetAddress_family(env, addressObj, java_net_InetAddress_IPv4);
 670     JNU_CHECK_EXCEPTION_RETURN(env, -1);
 671 
 672     /* return port */
 673     return ntohs(remote_addr.sa4.sin_port);
 674 }
 675 
 676 JNIEXPORT jint JNICALL
 677 Java_java_net_TwoStacksPlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
 678                                            jobject packet) {
 679 
 680      char BUF[MAX_BUFFER_LEN];
 681     char *fullPacket;
 682     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 683     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 684     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 685 
 686     jbyteArray packetBuffer;
 687     jint packetBufferOffset, packetBufferLen;
 688 
 689     int fd = -1, fd1 = -1, fduse, nsockets = 0, errorCode;
 690     int port;
 691 
 692     int checkBoth = 0;
 693     int n;
 694     SOCKETADDRESS remote_addr;
 695     jint remote_addrsize = sizeof(SOCKETADDRESS);
 696     BOOL retry;
 697     jlong prevTime = 0;
 698 
 699     if (!IS_NULL(fdObj)) {
 700         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 701         if (fd < 0) {
 702            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 703                            "socket closed");
 704            return -1;
 705         }
 706         nsockets = 1;
 707     }
 708 
 709     if (!IS_NULL(fd1Obj)) {
 710         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 711         if (fd1 < 0) {
 712            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 713                            "socket closed");
 714            return -1;
 715         }
 716         nsockets ++;
 717     }
 718 
 719     switch (nsockets) {
 720       case 0:
 721         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 722                        "socket closed");
 723         return -1;
 724       case 1:
 725         if (!IS_NULL(fdObj)) {
 726            fduse = fd;
 727         } else {
 728            fduse = fd1;
 729         }
 730         break;
 731       case 2:
 732         checkBoth = TRUE;
 733         break;
 734     }
 735 
 736     if (IS_NULL(packet)) {
 737         JNU_ThrowNullPointerException(env, "packet");
 738         return -1;
 739     }
 740 
 741     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
 742 
 743     if (IS_NULL(packetBuffer)) {
 744         JNU_ThrowNullPointerException(env, "packet buffer");
 745         return -1;
 746     }
 747 
 748     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
 749     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
 750 
 751     if (packetBufferLen > MAX_BUFFER_LEN) {
 752 
 753         /* When JNI-ifying the JDK's IO routines, we turned
 754          * read's and write's of byte arrays of size greater
 755          * than 2048 bytes into several operations of size 2048.
 756          * This saves a malloc()/memcpy()/free() for big
 757          * buffers.  This is OK for file IO and TCP, but that
 758          * strategy violates the semantics of a datagram protocol.
 759          * (one big send) != (several smaller sends).  So here
 760          * we *must* alloc the buffer.  Note it needn't be bigger
 761          * than 65,536 (0xFFFF) the max size of an IP packet.
 762          * anything bigger is truncated anyway.
 763          */
 764         fullPacket = (char *)malloc(packetBufferLen);
 765         if (!fullPacket) {
 766             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
 767             return -1;
 768         }
 769     } else {
 770         fullPacket = &(BUF[0]);
 771     }
 772 
 773     do {
 774         int ret;
 775         retry = FALSE;
 776 
 777         /*
 778          * If a timeout has been specified then we select on the socket
 779          * waiting for a read event or a timeout.
 780          */
 781         if (checkBoth) {
 782             int t = timeout == 0 ? -1: timeout;
 783             prevTime = JVM_CurrentTimeMillis(env, 0);
 784             ret = NET_Timeout2 (fd, fd1, t, &fduse);
 785             /* all subsequent calls to recv() or select() will use the same fd
 786              * for this call to peek() */
 787             if (ret <= 0) {
 788                 if (ret == 0) {
 789                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
 790                                         "Peek timed out");
 791                 } else if (ret == -1) {
 792                     NET_ThrowCurrent(env, "timeout in datagram socket peek");
 793                 }
 794                 if (packetBufferLen > MAX_BUFFER_LEN) {
 795                     free(fullPacket);
 796                 }
 797                 return -1;
 798             }
 799             if (ret == 2) {
 800                 fduse = checkLastFD (env, this, fd, fd1);
 801             }
 802             checkBoth = FALSE;
 803         } else if (timeout) {
 804             if (prevTime == 0) {
 805                 prevTime = JVM_CurrentTimeMillis(env, 0);
 806             }
 807             ret = NET_Timeout (fduse, timeout);
 808             if (ret <= 0) {
 809                 if (ret == 0) {
 810                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
 811                                     "Receive timed out");
 812                 } else if (ret == -1) {
 813                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 814                                     "Socket closed");
 815                 }
 816                 if (packetBufferLen > MAX_BUFFER_LEN) {
 817                     free(fullPacket);
 818                 }
 819                 return -1;
 820             }
 821         }
 822 
 823         /* receive the packet */
 824         n = recvfrom(fduse, fullPacket, packetBufferLen, MSG_PEEK,
 825                      &remote_addr.sa, &remote_addrsize);
 826         port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&remote_addr));
 827         if (n == SOCKET_ERROR) {
 828             if (WSAGetLastError() == WSAECONNRESET) {
 829                 jboolean connected;
 830 
 831                 /*
 832                  * An icmp port unreachable - we must receive this as Windows
 833                  * does not reset the state of the socket until this has been
 834                  * received.
 835                  */
 836                 purgeOutstandingICMP(env, this, fduse);
 837 
 838                 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
 839                 if (connected) {
 840                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 841                                        "ICMP Port Unreachable");
 842 
 843                     if (packetBufferLen > MAX_BUFFER_LEN) {
 844                         free(fullPacket);
 845                     }
 846                     return -1;
 847                 }
 848 
 849                 /*
 850                  * If a timeout was specified then we need to adjust it because
 851                  * we may have used up some of the timeout befor the icmp port
 852                  * unreachable arrived.
 853                  */
 854                 if (timeout) {
 855                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
 856                     timeout -= (jint)(newTime - prevTime);
 857                     if (timeout <= 0) {
 858                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 859                                 "Receive timed out");
 860                         if (packetBufferLen > MAX_BUFFER_LEN) {
 861                             free(fullPacket);
 862                         }
 863                         return -1;
 864                     }
 865                     prevTime = newTime;
 866                 }
 867                 retry = TRUE;
 868             }
 869         }
 870     } while (retry);
 871 
 872     /* truncate the data if the packet's length is too small */
 873     if (n > packetBufferLen) {
 874         n = packetBufferLen;
 875     }
 876     if (n < 0) {
 877         errorCode = WSAGetLastError();
 878         /* check to see if it's because the buffer was too small */
 879         if (errorCode == WSAEMSGSIZE) {
 880             /* it is because the buffer is too small. It's UDP, it's
 881              * unreliable, it's all good. discard the rest of the
 882              * data..
 883              */
 884             n = packetBufferLen;
 885         } else {
 886             /* failure */
 887             (*env)->SetIntField(env, packet, dp_lengthID, 0);
 888         }
 889     }
 890     if (n == -1) {
 891         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
 892         if (packetBufferLen > MAX_BUFFER_LEN) {
 893             free(fullPacket);
 894         }
 895         return -1;
 896     } else if (n == -2) {
 897         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 898                         "operation interrupted");
 899         if (packetBufferLen > MAX_BUFFER_LEN) {
 900             free(fullPacket);
 901         }
 902         return -1;
 903     } else if (n < 0) {
 904         NET_ThrowCurrent(env, "Datagram receive failed");
 905         if (packetBufferLen > MAX_BUFFER_LEN) {
 906             free(fullPacket);
 907         }
 908         return -1;
 909     } else {
 910         jobject packetAddress;
 911 
 912         /*
 913          * Check if there is an InetAddress already associated with this
 914          * packet. If so we check if it is the same source address. We
 915          * can't update any existing InetAddress because it is immutable
 916          */
 917         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
 918         if (packetAddress != NULL) {
 919             if (!NET_SockaddrEqualsInetAddress(env, &remote_addr,
 920                                                packetAddress)) {
 921                 /* force a new InetAddress to be created */
 922                 packetAddress = NULL;
 923             }
 924         }
 925         if (packetAddress == NULL) {
 926             packetAddress = NET_SockaddrToInetAddress(env, &remote_addr,
 927                                                       &port);
 928             /* stuff the new Inetaddress in the packet */
 929             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
 930         }
 931 
 932         /* populate the packet */
 933         (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
 934                                    (jbyte *)fullPacket);
 935         (*env)->SetIntField(env, packet, dp_portID, port);
 936         (*env)->SetIntField(env, packet, dp_lengthID, n);
 937     }
 938 
 939     /* make sure receive() picks up the right fd */
 940     (*env)->SetIntField(env, this, pdsi_fduseID, fduse);
 941 
 942     if (packetBufferLen > MAX_BUFFER_LEN) {
 943         free(fullPacket);
 944     }
 945     return port;
 946 }
 947 
 948 /*
 949  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 950  * Method:    receive
 951  * Signature: (Ljava/net/DatagramPacket;)V
 952  */
 953 JNIEXPORT void JNICALL
 954 Java_java_net_TwoStacksPlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
 955                                               jobject packet) {
 956 
 957     char BUF[MAX_BUFFER_LEN];
 958     char *fullPacket;
 959     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 960     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 961     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 962     jbyteArray packetBuffer;
 963     jint packetBufferOffset, packetBufferLen;
 964     int ipv6_supported = ipv6_available();
 965 
 966     /* as a result of the changes for ipv6, peek() or peekData()
 967      * must be called prior to receive() so that fduse can be set.
 968      */
 969     int fd = -1, fd1 = -1, fduse, errorCode;
 970 
 971     int n, nsockets=0;
 972     SOCKETADDRESS remote_addr;
 973     jint remote_addrsize = sizeof(SOCKETADDRESS);
 974     BOOL retry;
 975     jlong prevTime = 0, selectTime=0;
 976     jboolean connected;
 977 
 978     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
 979         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 980                         "Socket closed");
 981         return;
 982     }
 983 
 984     if (!IS_NULL(fdObj)) {
 985         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 986         nsockets ++;
 987     }
 988     if (!IS_NULL(fd1Obj)) {
 989         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 990         nsockets ++;
 991     }
 992 
 993     if (nsockets == 2) { /* need to choose one of them */
 994         /* was fduse set in peek? */
 995         fduse = (*env)->GetIntField(env, this, pdsi_fduseID);
 996         if (fduse == -1) {
 997             /* not set in peek(), must select on both sockets */
 998             int ret, t = (timeout == 0) ? -1: timeout;
 999             ret = NET_Timeout2 (fd, fd1, t, &fduse);
1000             if (ret == 2) {
1001                 fduse = checkLastFD (env, this, fd, fd1);
1002             } else if (ret <= 0) {
1003                 if (ret == 0) {
1004                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1005                                     "Receive timed out");
1006                 } else if (ret == -1) {
1007                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1008                                     "Socket closed");
1009                 }
1010                 return;
1011             }
1012         }
1013     } else if (!ipv6_supported) {
1014         fduse = fd;
1015     } else if (IS_NULL(fdObj)) {
1016         /* ipv6 supported: and this socket bound to an IPV6 only address */
1017         fduse = fd1;
1018     } else {
1019         /* ipv6 supported: and this socket bound to an IPV4 only address */
1020         fduse = fd;
1021     }
1022 
1023     if (IS_NULL(packet)) {
1024         JNU_ThrowNullPointerException(env, "packet");
1025         return;
1026     }
1027 
1028     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
1029 
1030     if (IS_NULL(packetBuffer)) {
1031         JNU_ThrowNullPointerException(env, "packet buffer");
1032         return;
1033     }
1034 
1035     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
1036     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
1037 
1038     if (packetBufferLen > MAX_BUFFER_LEN) {
1039 
1040         /* When JNI-ifying the JDK's IO routines, we turned
1041          * read's and write's of byte arrays of size greater
1042          * than 2048 bytes into several operations of size 2048.
1043          * This saves a malloc()/memcpy()/free() for big
1044          * buffers.  This is OK for file IO and TCP, but that
1045          * strategy violates the semantics of a datagram protocol.
1046          * (one big send) != (several smaller sends).  So here
1047          * we *must* alloc the buffer.  Note it needn't be bigger
1048          * than 65,536 (0xFFFF) the max size of an IP packet.
1049          * anything bigger is truncated anyway.
1050          */
1051         fullPacket = (char *)malloc(packetBufferLen);
1052         if (!fullPacket) {
1053             JNU_ThrowOutOfMemoryError(env, "Receive buf native heap allocation failed");
1054             return;
1055         }
1056     } else {
1057         fullPacket = &(BUF[0]);
1058     }
1059 
1060 
1061 
1062     /*
1063      * If we are not connected then we need to know if a timeout has been
1064      * specified and if so we need to pick up the current time. These are
1065      * required in order to implement the semantics of timeout, viz :-
1066      * timeout set to t1 but ICMP port unreachable arrives in t2 where
1067      * t2 < t1. In this case we must discard the ICMP packets and then
1068      * wait for the next packet up to a maximum of t1 minus t2.
1069      */
1070     connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1071     if (!connected && timeout && !ipv6_supported) {
1072         prevTime = JVM_CurrentTimeMillis(env, 0);
1073     }
1074 
1075     if (timeout && nsockets == 1) {
1076         int ret;
1077         ret = NET_Timeout(fduse, timeout);
1078         if (ret <= 0) {
1079             if (ret == 0) {
1080                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1081                                 "Receive timed out");
1082             } else if (ret == -1) {
1083                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1084                                 "Socket closed");
1085             }
1086             if (packetBufferLen > MAX_BUFFER_LEN) {
1087                 free(fullPacket);
1088             }
1089             return;
1090         }
1091     }
1092 
1093     /*
1094      * Loop only if we discarding ICMP port unreachable packets
1095      */
1096     do {
1097         retry = FALSE;
1098 
1099         /* receive the packet */
1100         n = recvfrom(fduse, fullPacket, packetBufferLen, 0, &remote_addr.sa,
1101                      &remote_addrsize);
1102 
1103         if (n == SOCKET_ERROR) {
1104             if (WSAGetLastError() == WSAECONNRESET) {
1105                 /*
1106                  * An icmp port unreachable has been received - consume any other
1107                  * outstanding packets.
1108                  */
1109                 purgeOutstandingICMP(env, this, fduse);
1110 
1111                 /*
1112                  * If connected throw a PortUnreachableException
1113                  */
1114 
1115                 if (connected) {
1116                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1117                                        "ICMP Port Unreachable");
1118 
1119                     if (packetBufferLen > MAX_BUFFER_LEN) {
1120                         free(fullPacket);
1121                     }
1122 
1123                     return;
1124                 }
1125 
1126                 /*
1127                  * If a timeout was specified then we need to adjust it because
1128                  * we may have used up some of the timeout before the icmp port
1129                  * unreachable arrived.
1130                  */
1131                 if (timeout) {
1132                     int ret;
1133                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
1134                     timeout -= (jint)(newTime - prevTime);
1135                     prevTime = newTime;
1136 
1137                     if (timeout <= 0) {
1138                         ret = 0;
1139                     } else {
1140                         ret = NET_Timeout(fduse, timeout);
1141                     }
1142 
1143                     if (ret <= 0) {
1144                         if (ret == 0) {
1145                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1146                                             "Receive timed out");
1147                         } else if (ret == -1) {
1148                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1149                                             "Socket closed");
1150                         }
1151                         if (packetBufferLen > MAX_BUFFER_LEN) {
1152                             free(fullPacket);
1153                         }
1154                         return;
1155                     }
1156                 }
1157 
1158                 /*
1159                  * An ICMP port unreachable was received but we are
1160                  * not connected so ignore it.
1161                  */
1162                 retry = TRUE;
1163             }
1164         }
1165         if (n > 0) {
1166             JVM_callNetworkReadBytes(env, n);
1167         }
1168     } while (retry);
1169 
1170     /* truncate the data if the packet's length is too small */
1171     if (n > packetBufferLen) {
1172         n = packetBufferLen;
1173     }
1174     if (n < 0) {
1175         errorCode = WSAGetLastError();
1176         /* check to see if it's because the buffer was too small */
1177         if (errorCode == WSAEMSGSIZE) {
1178             /* it is because the buffer is too small. It's UDP, it's
1179              * unreliable, it's all good. discard the rest of the
1180              * data..
1181              */
1182             n = packetBufferLen;
1183         } else {
1184             /* failure */
1185             (*env)->SetIntField(env, packet, dp_lengthID, 0);
1186         }
1187     }
1188     if (n == -1) {
1189         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1190     } else if (n == -2) {
1191         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1192                         "operation interrupted");
1193     } else if (n < 0) {
1194         NET_ThrowCurrent(env, "Datagram receive failed");
1195     } else {
1196         int port = 0;
1197         jobject packetAddress;
1198 
1199         /*
1200          * Check if there is an InetAddress already associated with this
1201          * packet. If so we check if it is the same source address. We
1202          * can't update any existing InetAddress because it is immutable
1203          */
1204         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
1205         if (packetAddress != NULL) {
1206             if (!NET_SockaddrEqualsInetAddress(env, &remote_addr,
1207                                                packetAddress)) {
1208                 /* force a new InetAddress to be created */
1209                 packetAddress = NULL;
1210             }
1211         }
1212         if (packetAddress == NULL) {
1213             packetAddress = NET_SockaddrToInetAddress(env, &remote_addr,
1214                                                       &port);
1215             /* stuff the new Inetaddress in the packet */
1216             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
1217         } else {
1218             /* only get the new port number */
1219             port = NET_GetPortFromSockaddr(&remote_addr);
1220         }
1221         /* populate the packet */
1222         (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
1223                                    (jbyte *)fullPacket);
1224         (*env)->SetIntField(env, packet, dp_portID, port);
1225         (*env)->SetIntField(env, packet, dp_lengthID, n);
1226     }
1227     if (packetBufferLen > MAX_BUFFER_LEN) {
1228         free(fullPacket);
1229     }
1230 }
1231 
1232 /*
1233  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1234  * Method:    datagramSocketCreate
1235  * Signature: ()V
1236  */
1237 JNIEXPORT void JNICALL
1238 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
1239                                                            jobject this) {
1240     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1241     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1242 
1243     int fd, fd1;
1244     int t = TRUE;
1245     DWORD x1, x2; /* ignored result codes */
1246     int ipv6_supported = ipv6_available();
1247 
1248     int arg = -1;
1249 
1250     if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
1251         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1252         return;
1253     } else {
1254         fd =  (int) socket (AF_INET, SOCK_DGRAM, 0);
1255     }
1256     if (fd == SOCKET_ERROR) {
1257         NET_ThrowCurrent(env, "Socket creation failed");
1258         return;
1259     }
1260     SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
1261     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
1262     NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1263 
1264     if (ipv6_supported) {
1265         /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
1266          * returns connection reset errors un connected UDP sockets (as well
1267          * as connected sockets. The solution is to only enable this feature
1268          * when the socket is connected
1269          */
1270         t = FALSE;
1271         WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1272         t = TRUE;
1273         fd1 = socket (AF_INET6, SOCK_DGRAM, 0);
1274         if (fd1 == SOCKET_ERROR) {
1275             NET_ThrowCurrent(env, "Socket creation failed");
1276             return;
1277         }
1278         NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1279         t = FALSE;
1280         WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1281         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
1282         SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
1283     } else {
1284         /* drop the second fd */
1285         (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
1286     }
1287 }
1288 
1289 /*
1290  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1291  * Method:    datagramSocketClose
1292  * Signature: ()V
1293  */
1294 JNIEXPORT void JNICALL
1295 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env,
1296                                                           jobject this) {
1297     /*
1298      * REMIND: PUT A LOCK AROUND THIS CODE
1299      */
1300     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1301     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1302     int ipv6_supported = ipv6_available();
1303     int fd = -1, fd1 = -1;
1304 
1305     if (IS_NULL(fdObj) && (!ipv6_supported || IS_NULL(fd1Obj))) {
1306         return;
1307     }
1308 
1309     if (!IS_NULL(fdObj)) {
1310         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1311         if (fd != -1) {
1312             (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
1313             NET_SocketClose(fd);
1314         }
1315     }
1316 
1317     if (ipv6_supported && fd1Obj != NULL) {
1318         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1319         if (fd1 == -1) {
1320             return;
1321         }
1322         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
1323         NET_SocketClose(fd1);
1324     }
1325 }
1326 
1327 /*
1328  * check the addresses attached to the NetworkInterface object
1329  * and return the first one (of the requested family Ipv4 or Ipv6)
1330  * in *iaddr
1331  */
1332 
1333 static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iaddr)
1334 {
1335     jobjectArray addrArray;
1336     static jfieldID ni_addrsID=0;
1337     jsize len;
1338     jobject addr;
1339     int i;
1340 
1341     if (ni_addrsID == NULL ) {
1342         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1343         CHECK_NULL_RETURN (c, -1);
1344         ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1345                                         "[Ljava/net/InetAddress;");
1346         CHECK_NULL_RETURN (ni_addrsID, -1);
1347     }
1348 
1349     addrArray = (*env)->GetObjectField(env, nif, ni_addrsID);
1350     len = (*env)->GetArrayLength(env, addrArray);
1351 
1352     /*
1353      * Check that there is at least one address bound to this
1354      * interface.
1355      */
1356     if (len < 1) {
1357         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1358             "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1359         return -1;
1360     }
1361     for (i=0; i<len; i++) {
1362         int fam;
1363         addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1364         fam = getInetAddress_family(env, addr);
1365         JNU_CHECK_EXCEPTION_RETURN(env, -1);
1366         if (fam == family) {
1367             *iaddr = addr;
1368             return 0;
1369         }
1370     }
1371     return -1;
1372 }
1373 
1374 static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr)
1375 {
1376     jobject addr;
1377 
1378     int ret = getInetAddrFromIf(env, java_net_InetAddress_IPv4, nif, &addr);
1379     if (ret == -1) {
1380         return -1;
1381     }
1382 
1383     iaddr->s_addr = htonl(getInetAddress_addr(env, addr));
1384     JNU_CHECK_EXCEPTION_RETURN(env, -1);
1385     return 0;
1386 }
1387 
1388 /* Get the multicasting index from the interface */
1389 
1390 static int getIndexFromIf (JNIEnv *env, jobject nif) {
1391     static jfieldID ni_indexID = NULL;
1392 
1393     if (ni_indexID == NULL) {
1394         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1395         CHECK_NULL_RETURN(c, -1);
1396         ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1397         CHECK_NULL_RETURN(ni_indexID, -1);
1398     }
1399 
1400     return (*env)->GetIntField(env, nif, ni_indexID);
1401 }
1402 
1403 static int isAdapterIpv6Enabled(JNIEnv *env, int index) {
1404   netif *ifList, *curr;
1405   int ipv6Enabled = 0;
1406   if (getAllInterfacesAndAddresses(env, &ifList) < 0) {
1407       return ipv6Enabled;
1408   }
1409 
1410   /* search by index */
1411   curr = ifList;
1412   while (curr != NULL) {
1413       if (index == curr->index) {
1414           break;
1415       }
1416       curr = curr->next;
1417   }
1418 
1419   /* if found ipv6Index != 0 then interface is configured with IPV6 */
1420   if ((curr != NULL) && (curr->ipv6Index !=0)) {
1421       ipv6Enabled = 1;
1422   }
1423 
1424   /* release the interface list */
1425   free_netif(ifList);
1426 
1427   return ipv6Enabled;
1428 }
1429 
1430 /*
1431  * Sets the multicast interface.
1432  *
1433  * SocketOptions.IP_MULTICAST_IF (argument is an InetAddress) :-
1434  *      IPv4:   set outgoing multicast interface using
1435  *              IPPROTO_IP/IP_MULTICAST_IF
1436  *
1437  *      IPv6:   Get the interface to which the
1438  *              InetAddress is bound
1439  *              and do same as SockOptions.IF_MULTICAST_IF2
1440  *
1441  * SockOptions.IF_MULTICAST_IF2 (argument is a NetworkInterface ) :-
1442  *      For each stack:
1443  *      IPv4:   Obtain IP address bound to network interface
1444  *              (NetworkInterface.addres[0])
1445  *              set outgoing multicast interface using
1446  *              IPPROTO_IP/IP_MULTICAST_IF
1447  *
1448  *      IPv6:   Obtain NetworkInterface.index
1449  *              Set outgoing multicast interface using
1450  *              IPPROTO_IPV6/IPV6_MULTICAST_IF
1451  *
1452  */
1453 static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1,
1454                                   jint opt, jobject value)
1455 {
1456     int ipv6_supported = ipv6_available();
1457 
1458     if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1459         /*
1460          * value is an InetAddress.
1461          * On IPv4 system use IP_MULTICAST_IF socket option
1462          * On IPv6 system get the NetworkInterface that this IP
1463          * address is bound to and use the IPV6_MULTICAST_IF
1464          * option instead of IP_MULTICAST_IF
1465          */
1466         if (ipv6_supported) {
1467             static jclass ni_class = NULL;
1468             if (ni_class == NULL) {
1469                 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1470                 CHECK_NULL(c);
1471                 ni_class = (*env)->NewGlobalRef(env, c);
1472                 CHECK_NULL(ni_class);
1473             }
1474 
1475             value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1476             if (value == NULL) {
1477                 if (!(*env)->ExceptionOccurred(env)) {
1478                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1479                          "bad argument for IP_MULTICAST_IF"
1480                          ": address not bound to any interface");
1481                 }
1482                 return;
1483             }
1484             opt = java_net_SocketOptions_IP_MULTICAST_IF2;
1485         } else {
1486             struct in_addr in;
1487 
1488             in.s_addr = htonl(getInetAddress_addr(env, value));
1489             JNU_CHECK_EXCEPTION(env);
1490             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1491                                (const char*)&in, sizeof(in)) < 0) {
1492                 JNU_ThrowByNameWithMessageAndLastError
1493                     (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1494             }
1495             return;
1496         }
1497     }
1498 
1499     if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1500         /*
1501          * value is a NetworkInterface.
1502          * On IPv6 system get the index of the interface and use the
1503          * IPV6_MULTICAST_IF socket option
1504          * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF
1505          * option. For IPv6 both must be done.
1506          */
1507         if (ipv6_supported) {
1508             static jfieldID ni_indexID = NULL;
1509             struct in_addr in;
1510             int index;
1511 
1512             if (ni_indexID == NULL) {
1513                 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1514                 CHECK_NULL(c);
1515                 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1516                 CHECK_NULL(ni_indexID);
1517             }
1518             index = (*env)->GetIntField(env, value, ni_indexID);
1519 
1520             if (isAdapterIpv6Enabled(env, index) != 0) {
1521                 if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1522                                (const char*)&index, sizeof(index)) < 0) {
1523                     if (errno == EINVAL && index > 0) {
1524                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1525                             "IPV6_MULTICAST_IF failed (interface has IPv4 "
1526                             "address only?)");
1527                     } else {
1528                         JNU_ThrowByNameWithMessageAndLastError
1529                             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1530                     }
1531                     return;
1532                 }
1533             }
1534             /* If there are any IPv4 addresses on this interface then
1535              * repeat the operation on the IPv4 fd */
1536 
1537             if (getInet4AddrFromIf(env, value, &in) < 0) {
1538                 return;
1539             }
1540             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1541                                (const char*)&in, sizeof(in)) < 0) {
1542                 JNU_ThrowByNameWithMessageAndLastError
1543                     (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1544             }
1545             return;
1546         } else {
1547             struct in_addr in;
1548 
1549             if (getInet4AddrFromIf (env, value, &in) < 0) {
1550                 if ((*env)->ExceptionOccurred(env)) {
1551                     return;
1552                 }
1553                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1554                         "no InetAddress instances of requested type");
1555                 return;
1556             }
1557 
1558             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1559                                (const char*)&in, sizeof(in)) < 0) {
1560                 JNU_ThrowByNameWithMessageAndLastError
1561                     (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
1562             }
1563             return;
1564         }
1565     }
1566 }
1567 
1568 /*
1569  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1570  * Method:    socketNativeSetOption
1571  * Signature: (ILjava/lang/Object;)V
1572  */
1573 JNIEXPORT void JNICALL
1574 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption
1575   (JNIEnv *env,jobject this, jint opt,jobject value)
1576 {
1577     int fd = -1, fd1 = -1;
1578     int levelv4 = 0, levelv6 = 0, optnamev4 = 0, optnamev6 = 0, optlen = 0;
1579     union {
1580         int i;
1581         char c;
1582     } optval = { 0 };
1583     int ipv6_supported = ipv6_available();
1584     fd = getFD(env, this);
1585 
1586     if (ipv6_supported) {
1587         fd1 = getFD1(env, this);
1588     }
1589     if (fd < 0 && fd1 < 0) {
1590         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1591         return;
1592     }
1593 
1594     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1595         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1596 
1597         setMulticastInterface(env, this, fd, fd1, opt, value);
1598         return;
1599     }
1600 
1601     /*
1602      * Map the Java level socket option to the platform specific
1603      * level(s) and option name(s).
1604      */
1605     if (fd1 != -1) {
1606         if (NET_MapSocketOptionV6(opt, &levelv6, &optnamev6)) {
1607             JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1608             return;
1609         }
1610     }
1611     if (fd != -1) {
1612         if (NET_MapSocketOption(opt, &levelv4, &optnamev4)) {
1613             JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1614             return;
1615         }
1616     }
1617 
1618     switch (opt) {
1619         case java_net_SocketOptions_SO_SNDBUF :
1620         case java_net_SocketOptions_SO_RCVBUF :
1621         case java_net_SocketOptions_IP_TOS :
1622             {
1623                 jclass cls;
1624                 jfieldID fid;
1625 
1626                 cls = (*env)->FindClass(env, "java/lang/Integer");
1627                 CHECK_NULL(cls);
1628                 fid =  (*env)->GetFieldID(env, cls, "value", "I");
1629                 CHECK_NULL(fid);
1630 
1631                 optval.i = (*env)->GetIntField(env, value, fid);
1632                 optlen = sizeof(optval.i);
1633             }
1634             break;
1635 
1636         case java_net_SocketOptions_SO_REUSEADDR:
1637         case java_net_SocketOptions_SO_BROADCAST:
1638         case java_net_SocketOptions_IP_MULTICAST_LOOP:
1639             {
1640                 jclass cls;
1641                 jfieldID fid;
1642                 jboolean on;
1643 
1644                 cls = (*env)->FindClass(env, "java/lang/Boolean");
1645                 CHECK_NULL(cls);
1646                 fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1647                 CHECK_NULL(fid);
1648 
1649                 on = (*env)->GetBooleanField(env, value, fid);
1650                 optval.i = (on ? 1 : 0);
1651                 /*
1652                  * setLoopbackMode (true) disables IP_MULTICAST_LOOP rather
1653                  * than enabling it.
1654                  */
1655                 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1656                     optval.i = !optval.i;
1657                 }
1658                 optlen = sizeof(optval.i);
1659             }
1660             break;
1661 
1662         default :
1663             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1664                 "Socket option not supported by PlainDatagramSocketImp");
1665             return;
1666 
1667     }
1668 
1669     if (fd1 != -1) {
1670         if (NET_SetSockOpt(fd1, levelv6, optnamev6, (void *)&optval, optlen) < 0) {
1671             NET_ThrowCurrent(env, "setsockopt IPv6");
1672             return;
1673         }
1674     }
1675     if (fd != -1) {
1676         if (NET_SetSockOpt(fd, levelv4, optnamev4, (void *)&optval, optlen) < 0) {
1677             NET_ThrowCurrent(env, "setsockopt");
1678             return;
1679         }
1680     }
1681 }
1682 
1683 /*
1684  *
1685  * called by getMulticastInterface to retrieve a NetworkInterface
1686  * configured for IPv4.
1687  * The ipv4Mode parameter, is a closet boolean, which allows for a NULL return,
1688  * or forces the creation of a NetworkInterface object with null data.
1689  * It relates to its calling context in getMulticastInterface.
1690  * ipv4Mode == 1, the context is IPV4 processing only.
1691  * ipv4Mode == 0, the context is IPV6 processing
1692  *
1693  */
1694 static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint opt, int ipv4Mode) {
1695         static jclass inet4_class;
1696         static jmethodID inet4_ctrID;
1697 
1698         static jclass ni_class; static jmethodID ni_ctrID;
1699         static jfieldID ni_indexID;
1700         static jfieldID ni_addrsID;
1701 
1702         jobjectArray addrArray;
1703         jobject addr;
1704         jobject ni;
1705 
1706         struct in_addr in;
1707         struct in_addr *inP = &in;
1708         int len = sizeof(struct in_addr);
1709         if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1710                            (char *)inP, &len) < 0) {
1711             JNU_ThrowByNameWithMessageAndLastError
1712                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1713             return NULL;
1714         }
1715 
1716         /*
1717          * Construct and populate an Inet4Address
1718          */
1719         if (inet4_class == NULL) {
1720             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1721             CHECK_NULL_RETURN(c, NULL);
1722             inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1723             CHECK_NULL_RETURN(inet4_ctrID, NULL);
1724             inet4_class = (*env)->NewGlobalRef(env, c);
1725             CHECK_NULL_RETURN(inet4_class, NULL);
1726         }
1727         addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1728         CHECK_NULL_RETURN(addr, NULL);
1729 
1730         setInetAddress_addr(env, addr, ntohl(in.s_addr));
1731         JNU_CHECK_EXCEPTION_RETURN(env, NULL);
1732         /*
1733          * For IP_MULTICAST_IF return InetAddress
1734          */
1735         if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1736             return addr;
1737         }
1738 
1739         /*
1740          * For IP_MULTICAST_IF2 we get the NetworkInterface for
1741          * this address and return it
1742          */
1743         if (ni_class == NULL) {
1744             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1745             CHECK_NULL_RETURN(c, NULL);
1746             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1747             CHECK_NULL_RETURN(ni_ctrID, NULL);
1748             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1749             CHECK_NULL_RETURN(ni_indexID, NULL);
1750             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1751                                             "[Ljava/net/InetAddress;");
1752             CHECK_NULL_RETURN(ni_addrsID, NULL);
1753             ni_class = (*env)->NewGlobalRef(env, c);
1754             CHECK_NULL_RETURN(ni_class, NULL);
1755         }
1756         ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr);
1757         if (ni) {
1758             return ni;
1759         }
1760         if (ipv4Mode) {
1761             ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
1762             CHECK_NULL_RETURN(ni, NULL);
1763 
1764             (*env)->SetIntField(env, ni, ni_indexID, -1);
1765             addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
1766             CHECK_NULL_RETURN(addrArray, NULL);
1767             (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
1768             (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1769         } else {
1770             ni = NULL;
1771         }
1772         return ni;
1773 }
1774 
1775 /*
1776  * Return the multicast interface:
1777  *
1778  * SocketOptions.IP_MULTICAST_IF
1779  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
1780  *              Create InetAddress
1781  *              IP_MULTICAST_IF returns struct ip_mreqn on 2.2
1782  *              kernel but struct in_addr on 2.4 kernel
1783  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
1784  *              obtain from impl is Linux 2.2 kernel
1785  *              If index == 0 return InetAddress representing
1786  *              anyLocalAddress.
1787  *              If index > 0 query NetworkInterface by index
1788  *              and returns addrs[0]
1789  *
1790  * SocketOptions.IP_MULTICAST_IF2
1791  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
1792  *              Query NetworkInterface by IP address and
1793  *              return the NetworkInterface that the address
1794  *              is bound too.
1795  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
1796  *              (except Linux .2 kernel)
1797  *              Query NetworkInterface by index and
1798  *              return NetworkInterface.
1799  */
1800 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
1801     jboolean isIPV4 = !ipv6_available() || fd1 == -1;
1802 
1803     /*
1804      * IPv4 implementation
1805      */
1806     if (isIPV4) {
1807         jobject netObject = NULL; // return is either an addr or a netif
1808         netObject = getIPv4NetworkInterface(env, this, fd, opt, 1);
1809         return netObject;
1810     }
1811 
1812     /*
1813      * IPv6 implementation
1814      */
1815     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1816         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1817 
1818         static jclass ni_class;
1819         static jmethodID ni_ctrID;
1820         static jfieldID ni_indexID;
1821         static jfieldID ni_addrsID;
1822         static jclass ia_class;
1823         static jmethodID ia_anyLocalAddressID;
1824 
1825         int index;
1826         int len = sizeof(index);
1827 
1828         jobjectArray addrArray;
1829         jobject addr;
1830         jobject ni;
1831 
1832         {
1833             if (getsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1834                                (char*)&index, &len) < 0) {
1835                 JNU_ThrowByNameWithMessageAndLastError
1836                     (env, JNU_JAVANETPKG "SocketException", "Error getting socket option");
1837                 return NULL;
1838             }
1839         }
1840 
1841         if (ni_class == NULL) {
1842             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1843             CHECK_NULL_RETURN(c, NULL);
1844             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1845             CHECK_NULL_RETURN(ni_ctrID, NULL);
1846             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1847             CHECK_NULL_RETURN(ni_indexID, NULL);
1848             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1849                                             "[Ljava/net/InetAddress;");
1850             CHECK_NULL_RETURN(ni_addrsID, NULL);
1851 
1852             ia_class = (*env)->FindClass(env, "java/net/InetAddress");
1853             CHECK_NULL_RETURN(ia_class, NULL);
1854             ia_class = (*env)->NewGlobalRef(env, ia_class);
1855             CHECK_NULL_RETURN(ia_class, NULL);
1856             ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
1857                                                              ia_class,
1858                                                              "anyLocalAddress",
1859                                                              "()Ljava/net/InetAddress;");
1860             CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);
1861             ni_class = (*env)->NewGlobalRef(env, c);
1862             CHECK_NULL_RETURN(ni_class, NULL);
1863         }
1864 
1865         /*
1866          * If multicast to a specific interface then return the
1867          * interface (for IF2) or the any address on that interface
1868          * (for IF).
1869          */
1870         if (index > 0) {
1871             ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
1872                                                                    index);
1873             if (ni == NULL) {
1874                 char errmsg[255];
1875                 sprintf(errmsg,
1876                         "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
1877                         index);
1878                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1879                 return NULL;
1880             }
1881 
1882             /*
1883              * For IP_MULTICAST_IF2 return the NetworkInterface
1884              */
1885             if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1886                 return ni;
1887             }
1888 
1889             /*
1890              * For IP_MULTICAST_IF return addrs[0]
1891              */
1892             addrArray = (*env)->GetObjectField(env, ni, ni_addrsID);
1893             if ((*env)->GetArrayLength(env, addrArray) < 1) {
1894                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1895                     "IPV6_MULTICAST_IF returned interface without IP bindings");
1896                 return NULL;
1897             }
1898 
1899             addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
1900             return addr;
1901         } else if (index == 0) { // index == 0 typically means IPv6 not configured on the interfaces
1902             // falling back to treat interface as configured for IPv4
1903             jobject netObject = NULL;
1904             netObject = getIPv4NetworkInterface(env, this, fd, opt, 0);
1905             if (netObject != NULL) {
1906                 return netObject;
1907             }
1908         }
1909 
1910         /*
1911          * Multicast to any address - return anyLocalAddress
1912          * or a NetworkInterface with addrs[0] set to anyLocalAddress
1913          */
1914 
1915         addr = (*env)->CallStaticObjectMethod(env, ia_class, ia_anyLocalAddressID,
1916                                               NULL);
1917         if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1918             return addr;
1919         }
1920 
1921         ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
1922         CHECK_NULL_RETURN(ni, NULL);
1923         (*env)->SetIntField(env, ni, ni_indexID, -1);
1924         addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL);
1925         CHECK_NULL_RETURN(addrArray, NULL);
1926         (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
1927         (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
1928         return ni;
1929     }
1930     return NULL;
1931 }
1932 
1933 
1934 /*
1935  * Returns relevant info as a jint.
1936  *
1937  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1938  * Method:    socketGetOption
1939  * Signature: (I)Ljava/lang/Object;
1940  */
1941 JNIEXPORT jobject JNICALL
1942 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption
1943   (JNIEnv *env, jobject this, jint opt)
1944 {
1945     int fd = -1, fd1 = -1;
1946     int level, optname, optlen;
1947     union {
1948         int i;
1949     } optval = {0};
1950     int ipv6_supported = ipv6_available();
1951 
1952     fd = getFD(env, this);
1953     if (ipv6_supported) {
1954         fd1 = getFD1(env, this);
1955     }
1956 
1957     if (fd < 0 && fd1 < 0) {
1958         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1959                         "Socket closed");
1960         return NULL;
1961     }
1962 
1963     /*
1964      * Handle IP_MULTICAST_IF separately
1965      */
1966     if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
1967         opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1968         return getMulticastInterface(env, this, fd, fd1, opt);
1969     }
1970 
1971     /*
1972      * Map the Java level socket option to the platform specific
1973      * level and option name.
1974      */
1975     if (NET_MapSocketOption(opt, &level, &optname)) {
1976         JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1977         return NULL;
1978     }
1979 
1980     if (fd == -1) {
1981         if (NET_MapSocketOptionV6(opt, &level, &optname)) {
1982             JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
1983             return NULL;
1984         }
1985         fd = fd1; /* must be IPv6 only */
1986     }
1987 
1988     optlen = sizeof(optval.i);
1989     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
1990         char tmpbuf[255];
1991         int size = 0;
1992         char errmsg[255 + 31];
1993         getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1994         sprintf(errmsg, "error getting socket option: %s", tmpbuf);
1995         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
1996         return NULL;
1997     }
1998 
1999     switch (opt) {
2000         case java_net_SocketOptions_SO_BROADCAST:
2001         case java_net_SocketOptions_SO_REUSEADDR:
2002             return createBoolean(env, optval.i);
2003 
2004         case java_net_SocketOptions_IP_MULTICAST_LOOP:
2005             /* getLoopbackMode() returns true if IP_MULTICAST_LOOP is disabled */
2006             return createBoolean(env, !optval.i);
2007 
2008         case java_net_SocketOptions_SO_SNDBUF:
2009         case java_net_SocketOptions_SO_RCVBUF:
2010         case java_net_SocketOptions_IP_TOS:
2011             return createInteger(env, optval.i);
2012 
2013         default :
2014             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2015                 "Socket option not supported by TwoStacksPlainDatagramSocketImpl");
2016             return NULL;
2017 
2018     }
2019 }
2020 
2021 /*
2022  * Returns local address of the socket.
2023  *
2024  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2025  * Method:    socketLocalAddress
2026  * Signature: (I)Ljava/lang/Object;
2027  */
2028 JNIEXPORT jobject JNICALL
2029 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketLocalAddress
2030   (JNIEnv *env, jobject this, jint family)
2031 {
2032     int fd = -1, fd1 = -1;
2033     SOCKETADDRESS sa;
2034     int len = 0;
2035     int port;
2036     jobject iaObj;
2037     int ipv6_supported = ipv6_available();
2038 
2039     fd = getFD(env, this);
2040     if (ipv6_supported) {
2041         fd1 = getFD1(env, this);
2042     }
2043 
2044     if (fd < 0 && fd1 < 0) {
2045         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2046                         "Socket closed");
2047         return NULL;
2048     }
2049 
2050     /* find out local IP address */
2051 
2052     len = sizeof(struct sockaddr_in);
2053 
2054     /* family==-1 when socket is not connected */
2055     if ((family == java_net_InetAddress_IPv6) || (family == -1 && fd == -1)) {
2056         fd = fd1; /* must be IPv6 only */
2057         len = sizeof(struct sockaddr_in6);
2058     }
2059 
2060     if (fd == -1) {
2061         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2062                         "Socket closed");
2063         return NULL;
2064     }
2065 
2066     if (getsockname(fd, &sa.sa, &len) == -1) {
2067         JNU_ThrowByNameWithMessageAndLastError
2068             (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
2069         return NULL;
2070     }
2071     iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
2072 
2073     return iaObj;
2074 }
2075 
2076 /*
2077  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2078  * Method:    setTimeToLive
2079  * Signature: (I)V
2080  */
2081 JNIEXPORT void JNICALL
2082 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
2083                                                     jint ttl) {
2084 
2085     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2086     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2087     int fd = -1, fd1 = -1;
2088     int ittl = (int)ttl;
2089 
2090     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2091         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2092                         "Socket closed");
2093         return;
2094     } else {
2095       if (!IS_NULL(fdObj)) {
2096         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2097       }
2098       if (!IS_NULL(fd1Obj)) {
2099         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2100       }
2101     }
2102 
2103     /* setsockopt to be correct ttl */
2104     if (fd >= 0) {
2105       if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
2106                          sizeof (ittl)) < 0) {
2107         NET_ThrowCurrent(env, "set IP_MULTICAST_TTL failed");
2108         return;
2109       }
2110     }
2111 
2112     if (fd1 >= 0) {
2113       if (NET_SetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ittl,
2114                          sizeof(ittl)) <0) {
2115         NET_ThrowCurrent(env, "set IPV6_MULTICAST_HOPS failed");
2116       }
2117     }
2118 }
2119 
2120 /*
2121  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2122  * Method:    setTTL
2123  * Signature: (B)V
2124  */
2125 JNIEXPORT void JNICALL
2126 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
2127                                              jbyte ttl) {
2128     Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(env, this,
2129                                                         (jint)ttl & 0xFF);
2130 }
2131 
2132 /*
2133  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2134  * Method:    getTimeToLive
2135  * Signature: ()I
2136  */
2137 JNIEXPORT jint JNICALL
2138 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
2139     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2140     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2141     int fd = -1, fd1 = -1;
2142     int ttl = 0;
2143     int len = sizeof(ttl);
2144 
2145     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2146         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2147                         "Socket closed");
2148         return -1;
2149     } else {
2150       if (!IS_NULL(fdObj)) {
2151         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2152       }
2153       if (!IS_NULL(fd1Obj)) {
2154         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2155       }
2156     }
2157 
2158     /* getsockopt of ttl */
2159     if (fd >= 0) {
2160       if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, &len) < 0) {
2161         NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2162         return -1;
2163       }
2164       return (jint)ttl;
2165     }
2166     if (fd1 >= 0) {
2167       if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl, &len) < 0) {
2168         NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2169         return -1;
2170       }
2171       return (jint)ttl;
2172     }
2173     return -1;
2174 }
2175 
2176 /*
2177  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2178  * Method:    getTTL
2179  * Signature: ()B
2180  */
2181 JNIEXPORT jbyte JNICALL
2182 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) {
2183     int result = Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(env, this);
2184 
2185     return (jbyte)result;
2186 }
2187 
2188 /* join/leave the named group on the named interface, or if no interface specified
2189  * then the interface set with setInterfac(), or the default interface otherwise */
2190 
2191 static void mcast_join_leave(JNIEnv *env, jobject this,
2192                              jobject iaObj, jobject niObj,
2193                              jboolean join)
2194 {
2195     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2196     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2197     jint fd = -1, fd1 = -1;
2198 
2199     SOCKETADDRESS name;
2200     struct ip_mreq mname;
2201     struct ipv6_mreq mname6;
2202 
2203     struct in_addr in;
2204     DWORD ifindex = 0;
2205 
2206     int len, family;
2207     int ipv6_supported = ipv6_available();
2208     int cmd;
2209 
2210     memset((char *)&in, 0, sizeof(in));
2211     memset((char *)&name, 0, sizeof(name));
2212 
2213     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2214         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2215                         "Socket closed");
2216         return;
2217     }
2218     if (!IS_NULL(fdObj)) {
2219         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2220     }
2221     if (ipv6_supported && !IS_NULL(fd1Obj)) {
2222         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2223     }
2224 
2225     if (IS_NULL(iaObj)) {
2226         JNU_ThrowNullPointerException(env, "address");
2227         return;
2228     }
2229 
2230     if (NET_InetAddressToSockaddr(env, iaObj, 0, &name, &len, JNI_FALSE) != 0) {
2231       return;
2232     }
2233 
2234     /* Set the multicast group address in the ip_mreq field
2235      * eventually this check should be done by the security manager
2236      */
2237     family = name.sa.sa_family;
2238 
2239     if (family == AF_INET) {
2240         int address = name.sa4.sin_addr.s_addr;
2241         if (!IN_MULTICAST(ntohl(address))) {
2242             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in multicast");
2243             return;
2244         }
2245         mname.imr_multiaddr.s_addr = address;
2246         if (fd < 0) {
2247           JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv4 group on an IPv6 only socket");
2248           return;
2249         }
2250         if (IS_NULL(niObj)) {
2251             len = sizeof(in);
2252             if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
2253                            (char *)&in, &len) < 0) {
2254                 NET_ThrowCurrent(env, "get IP_MULTICAST_IF failed");
2255                 return;
2256             }
2257             mname.imr_interface.s_addr = in.s_addr;
2258         } else {
2259             if (getInet4AddrFromIf (env, niObj, &mname.imr_interface) != 0) {
2260                 NET_ThrowCurrent(env, "no Inet4Address associated with interface");
2261                 return;
2262             }
2263         }
2264 
2265         cmd = join ? IP_ADD_MEMBERSHIP: IP_DROP_MEMBERSHIP;
2266 
2267         /* Join the multicast group */
2268         if (NET_SetSockOpt(fd, IPPROTO_IP, cmd, (char *) &mname, sizeof (mname)) < 0) {
2269             if (WSAGetLastError() == WSAENOBUFS) {
2270                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2271                     "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2272             } else {
2273                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2274             }
2275         }
2276     } else /* AF_INET6 */ {
2277         if (ipv6_supported) {
2278             struct in6_addr *address;
2279             address = &name.sa6.sin6_addr;
2280             if (!IN6_IS_ADDR_MULTICAST(address)) {
2281                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in6 multicast");
2282                 return;
2283             }
2284             mname6.ipv6mr_multiaddr = *address;
2285         } else {
2286             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "IPv6 not supported");
2287             return;
2288         }
2289         if (fd1 < 0) {
2290           JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv6 group on a IPv4 socket");
2291           return;
2292         }
2293         if (IS_NULL(niObj)) {
2294             len = sizeof (ifindex);
2295             if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, &len) < 0) {
2296                 NET_ThrowCurrent(env, "get IPV6_MULTICAST_IF failed");
2297                 return;
2298             }
2299         } else {
2300             ifindex = getIndexFromIf (env, niObj);
2301             if (ifindex == -1) {
2302                 if ((*env)->ExceptionOccurred(env)) {
2303                     return;
2304                 }
2305                 NET_ThrowCurrent(env, "get ifindex failed");
2306                 return;
2307             }
2308         }
2309         mname6.ipv6mr_interface = ifindex;
2310         cmd = join ? IPV6_ADD_MEMBERSHIP: IPV6_DROP_MEMBERSHIP;
2311 
2312         /* Join the multicast group */
2313         if (NET_SetSockOpt(fd1, IPPROTO_IPV6, cmd, (char *) &mname6, sizeof (mname6)) < 0) {
2314             if (WSAGetLastError() == WSAENOBUFS) {
2315                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2316                     "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2317             } else {
2318                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2319             }
2320         }
2321     }
2322 
2323     return;
2324 }
2325 
2326 /*
2327  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2328  * Method:    join
2329  * Signature: (Ljava/net/InetAddress;)V
2330  */
2331 JNIEXPORT void JNICALL
2332 Java_java_net_TwoStacksPlainDatagramSocketImpl_join(JNIEnv *env, jobject this,
2333                                            jobject iaObj, jobject niObj)
2334 {
2335     mcast_join_leave (env, this, iaObj, niObj, JNI_TRUE);
2336 }
2337 
2338 /*
2339  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2340  * Method:    leave
2341  * Signature: (Ljava/net/InetAddress;)V
2342  */
2343 JNIEXPORT void JNICALL
2344 Java_java_net_TwoStacksPlainDatagramSocketImpl_leave(JNIEnv *env, jobject this,
2345                                             jobject iaObj, jobject niObj)
2346 {
2347     mcast_join_leave (env, this, iaObj, niObj, JNI_FALSE);
2348 }
2349 
2350 /*
2351  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2352  * Method:    dataAvailable
2353  * Signature: ()I
2354  */
2355 JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainDatagramSocketImpl_dataAvailable
2356 (JNIEnv *env, jobject this) {
2357     SOCKET fd;
2358     SOCKET fd1;
2359     int  rv = -1, rv1 = -1;
2360     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2361     jobject fd1Obj;
2362 
2363     if (!IS_NULL(fdObj)) {
2364         int retval = 0;
2365         fd = (SOCKET)(*env)->GetIntField(env, fdObj, IO_fd_fdID);
2366         rv = ioctlsocket(fd, FIONREAD, &retval);
2367         if (retval > 0) {
2368             return retval;
2369         }
2370     }
2371 
2372     fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2373     if (!IS_NULL(fd1Obj)) {
2374         int retval = 0;
2375         fd1 = (SOCKET)(*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2376         rv1 = ioctlsocket(fd1, FIONREAD, &retval);
2377         if (retval > 0) {
2378             return retval;
2379         }
2380     }
2381 
2382     if (rv < 0 && rv1 < 0) {
2383         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2384                         "Socket closed");
2385         return -1;
2386     }
2387 
2388     return 0;
2389 }