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