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