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