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