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) != JVM_IO_ERR) {
 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, "JVM_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 JVM_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     switch (sendto(fd, fullPacket, packetBufferLen, 0,
 761                        (struct sockaddr *)addrp, addrlen)) {
 762         case JVM_IO_ERR:
 763             NET_ThrowCurrent(env, "Datagram send failed");
 764             break;
 765 
 766         case JVM_IO_INTR:
 767             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 768                             "operation interrupted");
 769     }
 770 
 771     if (packetBufferLen > MAX_BUFFER_LEN) {
 772         free(fullPacket);
 773     }
 774 }
 775 
 776 /*
 777  * check which socket was last serviced when there was data on both sockets.
 778  * Only call this if sure that there is data on both sockets.
 779  */
 780 static int checkLastFD (JNIEnv *env, jobject this, int fd, int fd1) {
 781     int nextfd, lastfd = (*env)->GetIntField(env, this, pdsi_lastfdID);
 782     if (lastfd == -1) {
 783         /* arbitrary. Choose fd */
 784         (*env)->SetIntField(env, this, pdsi_lastfdID, fd);
 785         return fd;
 786     } else {
 787         if (lastfd == fd) {
 788             nextfd = fd1;
 789         } else {
 790             nextfd = fd;
 791         }
 792         (*env)->SetIntField(env, this, pdsi_lastfdID, nextfd);
 793         return nextfd;
 794     }
 795 }
 796 
 797 /*
 798  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 799  * Method:    peek
 800  * Signature: (Ljava/net/InetAddress;)I
 801  */
 802 JNIEXPORT jint JNICALL
 803 Java_java_net_TwoStacksPlainDatagramSocketImpl_peek(JNIEnv *env, jobject this,
 804                                            jobject addressObj) {
 805 
 806     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 807     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 808     jint fd;
 809 
 810     /* The address and family fields of addressObj */
 811     jint address, family;
 812 
 813     int n;
 814     struct sockaddr_in remote_addr;
 815     jint remote_addrsize = sizeof (remote_addr);
 816     char buf[1];
 817     BOOL retry;
 818     jlong prevTime = 0;
 819 
 820     if (IS_NULL(fdObj)) {
 821         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
 822         return -1;
 823     } else {
 824         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 825         if (fd < 0) {
 826            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 827                            "socket closed");
 828            return -1;
 829         }
 830     }
 831     if (IS_NULL(addressObj)) {
 832         JNU_ThrowNullPointerException(env, "Null address in peek()");
 833     } else {
 834         address = getInetAddress_addr(env, addressObj);
 835         /* We only handle IPv4 for now. Will support IPv6 once its in the os */
 836         family = AF_INET;
 837     }
 838 
 839     do {
 840         retry = FALSE;
 841 
 842         /*
 843          * If a timeout has been specified then we select on the socket
 844          * waiting for a read event or a timeout.
 845          */
 846         if (timeout) {
 847             int ret;
 848             prevTime = JVM_CurrentTimeMillis(env, 0);
 849             ret = NET_Timeout (fd, timeout);
 850             if (ret == 0) {
 851                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 852                                 "Peek timed out");
 853                 return ret;
 854             } else if (ret == JVM_IO_ERR) {
 855                 NET_ThrowCurrent(env, "timeout in datagram socket peek");
 856                 return ret;
 857             } else if (ret == JVM_IO_INTR) {
 858                 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 859                                 "operation interrupted");
 860                 return ret;
 861             }
 862         }
 863 
 864         /* now try the peek */
 865         n = recvfrom(fd, buf, 1, MSG_PEEK,
 866                          (struct sockaddr *)&remote_addr, &remote_addrsize);
 867 
 868         if (n == JVM_IO_ERR) {
 869             if (WSAGetLastError() == WSAECONNRESET) {
 870                 jboolean connected;
 871 
 872                 /*
 873                  * An icmp port unreachable - we must receive this as Windows
 874                  * does not reset the state of the socket until this has been
 875                  * received.
 876                  */
 877                 purgeOutstandingICMP(env, this, fd);
 878 
 879                 connected =  (*env)->GetBooleanField(env, this, pdsi_connected);
 880                 if (connected) {
 881                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 882                                        "ICMP Port Unreachable");
 883                     return 0;
 884                 }
 885 
 886                 /*
 887                  * If a timeout was specified then we need to adjust it because
 888                  * we may have used up some of the timeout befor the icmp port
 889                  * unreachable arrived.
 890                  */
 891                 if (timeout) {
 892                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
 893                     timeout -= (jint)(newTime - prevTime);
 894                     if (timeout <= 0) {
 895                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 896                                 "Receive timed out");
 897                         return 0;
 898                     }
 899                     prevTime = newTime;
 900                 }
 901 
 902                 /* Need to retry the recv */
 903                 retry = TRUE;
 904             }
 905         }
 906     } while (retry);
 907 
 908     if (n == JVM_IO_ERR && WSAGetLastError() != WSAEMSGSIZE) {
 909         NET_ThrowCurrent(env, "Datagram peek failed");
 910         return 0;
 911     }
 912     if (n == JVM_IO_INTR) {
 913         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 0);
 914         return 0;
 915     }
 916     setInetAddress_addr(env, addressObj, ntohl(remote_addr.sin_addr.s_addr));
 917     setInetAddress_family(env, addressObj, IPv4);
 918 
 919     /* return port */
 920     return ntohs(remote_addr.sin_port);
 921 }
 922 
 923 JNIEXPORT jint JNICALL
 924 Java_java_net_TwoStacksPlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
 925                                            jobject packet) {
 926 
 927      char BUF[MAX_BUFFER_LEN];
 928     char *fullPacket;
 929     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 930     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 931     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 932 
 933     jbyteArray packetBuffer;
 934     jint packetBufferOffset, packetBufferLen;
 935 
 936     int fd, fd1, fduse, nsockets=0, errorCode;
 937     int port;
 938 
 939     int checkBoth = 0;
 940     int n;
 941     SOCKETADDRESS remote_addr;
 942     jint remote_addrsize=sizeof(remote_addr);
 943     BOOL retry;
 944     jlong prevTime = 0;
 945 
 946     if (!IS_NULL(fdObj)) {
 947         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 948         if (fd < 0) {
 949            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 950                            "socket closed");
 951            return -1;
 952         }
 953         nsockets = 1;
 954     }
 955 
 956     if (!IS_NULL(fd1Obj)) {
 957         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
 958         if (fd1 < 0) {
 959            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 960                            "socket closed");
 961            return -1;
 962         }
 963         nsockets ++;
 964     }
 965 
 966     switch (nsockets) {
 967       case 0:
 968         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 969                        "socket closed");
 970         return -1;
 971       case 1:
 972         if (!IS_NULL(fdObj)) {
 973            fduse = fd;
 974         } else {
 975            fduse = fd1;
 976         }
 977         break;
 978       case 2:
 979         checkBoth = TRUE;
 980         break;
 981     }
 982 
 983     if (IS_NULL(packet)) {
 984         JNU_ThrowNullPointerException(env, "packet");
 985         return -1;
 986     }
 987 
 988     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
 989 
 990     if (IS_NULL(packetBuffer)) {
 991         JNU_ThrowNullPointerException(env, "packet buffer");
 992         return -1;
 993     }
 994 
 995     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
 996     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
 997 
 998     if (packetBufferLen > MAX_BUFFER_LEN) {
 999 
1000         /* When JNI-ifying the JDK's IO routines, we turned
1001          * read's and write's of byte arrays of size greater
1002          * than 2048 bytes into several operations of size 2048.
1003          * This saves a malloc()/memcpy()/free() for big
1004          * buffers.  This is OK for file IO and TCP, but that
1005          * strategy violates the semantics of a datagram protocol.
1006          * (one big send) != (several smaller sends).  So here
1007          * we *must* alloc the buffer.  Note it needn't be bigger
1008          * than 65,536 (0xFFFF) the max size of an IP packet.
1009          * anything bigger is truncated anyway.
1010          */
1011         fullPacket = (char *)malloc(packetBufferLen);
1012         if (!fullPacket) {
1013             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
1014             return -1;
1015         }
1016     } else {
1017         fullPacket = &(BUF[0]);
1018     }
1019 
1020     do {
1021         int ret;
1022         retry = FALSE;
1023 
1024         /*
1025          * If a timeout has been specified then we select on the socket
1026          * waiting for a read event or a timeout.
1027          */
1028         if (checkBoth) {
1029             int t = timeout == 0 ? -1: timeout;
1030             prevTime = JVM_CurrentTimeMillis(env, 0);
1031             ret = NET_Timeout2 (fd, fd1, t, &fduse);
1032             /* all subsequent calls to recv() or select() will use the same fd
1033              * for this call to peek() */
1034             if (ret <= 0) {
1035                 if (ret == 0) {
1036                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
1037                                         "Peek timed out");
1038                 } else if (ret == JVM_IO_ERR) {
1039                     NET_ThrowCurrent(env, "timeout in datagram socket peek");
1040                 } else if (ret == JVM_IO_INTR) {
1041                     JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1042                                     "operation interrupted");
1043                 }
1044                 if (packetBufferLen > MAX_BUFFER_LEN) {
1045                     free(fullPacket);
1046                 }
1047                 return -1;
1048             }
1049             if (ret == 2) {
1050                 fduse = checkLastFD (env, this, fd, fd1);
1051             }
1052             checkBoth = FALSE;
1053         } else if (timeout) {
1054             if (prevTime == 0) {
1055                 prevTime = JVM_CurrentTimeMillis(env, 0);
1056             }
1057             ret = NET_Timeout (fduse, timeout);
1058             if (ret <= 0) {
1059                 if (ret == 0) {
1060                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
1061                                     "Receive timed out");
1062                 } else if (ret == JVM_IO_ERR) {
1063                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1064                                     "Socket closed");
1065                 } else if (ret == JVM_IO_INTR) {
1066                     JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1067                                     "operation interrupted");
1068                 }
1069                 if (packetBufferLen > MAX_BUFFER_LEN) {
1070                     free(fullPacket);
1071                 }
1072                 return -1;
1073             }
1074         }
1075 
1076         /* receive the packet */
1077         n = recvfrom(fduse, fullPacket, packetBufferLen, MSG_PEEK,
1078                          (struct sockaddr *)&remote_addr, &remote_addrsize);
1079         port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&remote_addr));
1080         if (n == JVM_IO_ERR) {
1081             if (WSAGetLastError() == WSAECONNRESET) {
1082                 jboolean connected;
1083 
1084                 /*
1085                  * An icmp port unreachable - we must receive this as Windows
1086                  * does not reset the state of the socket until this has been
1087                  * received.
1088                  */
1089                 purgeOutstandingICMP(env, this, fduse);
1090 
1091                 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1092                 if (connected) {
1093                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1094                                        "ICMP Port Unreachable");
1095 
1096                     if (packetBufferLen > MAX_BUFFER_LEN) {
1097                         free(fullPacket);
1098                     }
1099                     return -1;
1100                 }
1101 
1102                 /*
1103                  * If a timeout was specified then we need to adjust it because
1104                  * we may have used up some of the timeout befor the icmp port
1105                  * unreachable arrived.
1106                  */
1107                 if (timeout) {
1108                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
1109                     timeout -= (jint)(newTime - prevTime);
1110                     if (timeout <= 0) {
1111                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1112                                 "Receive timed out");
1113                         if (packetBufferLen > MAX_BUFFER_LEN) {
1114                             free(fullPacket);
1115                         }
1116                         return -1;
1117                     }
1118                     prevTime = newTime;
1119                 }
1120                 retry = TRUE;
1121             }
1122         }
1123     } while (retry);
1124 
1125     /* truncate the data if the packet's length is too small */
1126     if (n > packetBufferLen) {
1127         n = packetBufferLen;
1128     }
1129     if (n < 0) {
1130         errorCode = WSAGetLastError();
1131         /* check to see if it's because the buffer was too small */
1132         if (errorCode == WSAEMSGSIZE) {
1133             /* it is because the buffer is too small. It's UDP, it's
1134              * unreliable, it's all good. discard the rest of the
1135              * data..
1136              */
1137             n = packetBufferLen;
1138         } else {
1139             /* failure */
1140             (*env)->SetIntField(env, packet, dp_lengthID, 0);
1141         }
1142     }
1143     if (n == -1) {
1144         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1145     } else if (n == -2) {
1146         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1147                         "operation interrupted");
1148     } else if (n < 0) {
1149         NET_ThrowCurrent(env, "Datagram receive failed");
1150     } else {
1151         jobject packetAddress;
1152 
1153         /*
1154          * Check if there is an InetAddress already associated with this
1155          * packet. If so we check if it is the same source address. We
1156          * can't update any existing InetAddress because it is immutable
1157          */
1158         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
1159         if (packetAddress != NULL) {
1160             if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)
1161                                                 &remote_addr, packetAddress)) {
1162                 /* force a new InetAddress to be created */
1163                 packetAddress = NULL;
1164             }
1165         }
1166         if (packetAddress == NULL) {
1167             packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)
1168                                 &remote_addr, &port);
1169             /* stuff the new Inetaddress in the packet */
1170             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
1171         }
1172 
1173         /* populate the packet */
1174         (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
1175                                    (jbyte *)fullPacket);
1176         (*env)->SetIntField(env, packet, dp_portID, port);
1177         (*env)->SetIntField(env, packet, dp_lengthID, n);
1178     }
1179 
1180     /* make sure receive() picks up the right fd */
1181     (*env)->SetIntField(env, this, pdsi_fduseID, fduse);
1182 
1183     if (packetBufferLen > MAX_BUFFER_LEN) {
1184         free(fullPacket);
1185     }
1186     return port;
1187 }
1188 
1189 /*
1190  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1191  * Method:    receive
1192  * Signature: (Ljava/net/DatagramPacket;)V
1193  */
1194 JNIEXPORT void JNICALL
1195 Java_java_net_TwoStacksPlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this,
1196                                               jobject packet) {
1197 
1198     char BUF[MAX_BUFFER_LEN];
1199     char *fullPacket;
1200     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1201     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1202     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
1203     jbyteArray packetBuffer;
1204     jint packetBufferOffset, packetBufferLen;
1205     int ipv6_supported = ipv6_available();
1206 
1207     /* as a result of the changes for ipv6, peek() or peekData()
1208      * must be called prior to receive() so that fduse can be set.
1209      */
1210     int fd, fd1, fduse, errorCode;
1211 
1212     int n, nsockets=0;
1213     SOCKETADDRESS remote_addr;
1214     jint remote_addrsize=sizeof(remote_addr);
1215     BOOL retry;
1216     jlong prevTime = 0, selectTime=0;
1217     jboolean connected;
1218 
1219     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
1220         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1221                         "Socket closed");
1222         return;
1223     }
1224 
1225     if (!IS_NULL(fdObj)) {
1226         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1227         nsockets ++;
1228     }
1229     if (!IS_NULL(fd1Obj)) {
1230         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1231         nsockets ++;
1232     }
1233 
1234     if (nsockets == 2) { /* need to choose one of them */
1235         /* was fduse set in peek? */
1236         fduse = (*env)->GetIntField(env, this, pdsi_fduseID);
1237         if (fduse == -1) {
1238             /* not set in peek(), must select on both sockets */
1239             int ret, t = (timeout == 0) ? -1: timeout;
1240             ret = NET_Timeout2 (fd, fd1, t, &fduse);
1241             if (ret == 2) {
1242                 fduse = checkLastFD (env, this, fd, fd1);
1243             } else if (ret <= 0) {
1244                 if (ret == 0) {
1245                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1246                                     "Receive timed out");
1247                 } else if (ret == JVM_IO_ERR) {
1248                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1249                                     "Socket closed");
1250                 } else if (ret == JVM_IO_INTR) {
1251                     JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1252                                     "operation interrupted");
1253                 }
1254                 return;
1255             }
1256         }
1257     } else if (!ipv6_supported) {
1258         fduse = fd;
1259     } else if (IS_NULL(fdObj)) {
1260         /* ipv6 supported: and this socket bound to an IPV6 only address */
1261         fduse = fd1;
1262     } else {
1263         /* ipv6 supported: and this socket bound to an IPV4 only address */
1264         fduse = fd;
1265     }
1266 
1267     if (IS_NULL(packet)) {
1268         JNU_ThrowNullPointerException(env, "packet");
1269         return;
1270     }
1271 
1272     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);
1273 
1274     if (IS_NULL(packetBuffer)) {
1275         JNU_ThrowNullPointerException(env, "packet buffer");
1276         return;
1277     }
1278 
1279     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
1280     packetBufferLen = (*env)->GetIntField(env, packet, dp_bufLengthID);
1281 
1282     if (packetBufferLen > MAX_BUFFER_LEN) {
1283 
1284         /* When JNI-ifying the JDK's IO routines, we turned
1285          * read's and write's of byte arrays of size greater
1286          * than 2048 bytes into several operations of size 2048.
1287          * This saves a malloc()/memcpy()/free() for big
1288          * buffers.  This is OK for file IO and TCP, but that
1289          * strategy violates the semantics of a datagram protocol.
1290          * (one big send) != (several smaller sends).  So here
1291          * we *must* alloc the buffer.  Note it needn't be bigger
1292          * than 65,536 (0xFFFF) the max size of an IP packet.
1293          * anything bigger is truncated anyway.
1294          */
1295         fullPacket = (char *)malloc(packetBufferLen);
1296         if (!fullPacket) {
1297             JNU_ThrowOutOfMemoryError(env, "Receive buf native heap allocation failed");
1298             return;
1299         }
1300     } else {
1301         fullPacket = &(BUF[0]);
1302     }
1303 
1304 
1305 
1306     /*
1307      * If this Windows edition supports ICMP port unreachable and if we
1308      * are not connected then we need to know if a timeout has been specified
1309      * and if so we need to pick up the current time. These are required in
1310      * order to implement the semantics of timeout, viz :-
1311      * timeout set to t1 but ICMP port unreachable arrives in t2 where
1312      * t2 < t1. In this case we must discard the ICMP packets and then
1313      * wait for the next packet up to a maximum of t1 minus t2.
1314      */
1315     connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1316     if (supportPortUnreachable() && !connected && timeout &&!ipv6_supported) {
1317         prevTime = JVM_CurrentTimeMillis(env, 0);
1318     }
1319 
1320     if (timeout && nsockets == 1) {
1321         int ret;
1322         ret = NET_Timeout(fduse, timeout);
1323         if (ret <= 0) {
1324             if (ret == 0) {
1325                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1326                                 "Receive timed out");
1327             } else if (ret == JVM_IO_ERR) {
1328                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1329                                 "Socket closed");
1330             } else if (ret == JVM_IO_INTR) {
1331                 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1332                                 "operation interrupted");
1333             }
1334             if (packetBufferLen > MAX_BUFFER_LEN) {
1335                 free(fullPacket);
1336             }
1337             return;
1338         }
1339     }
1340 
1341     /*
1342      * Loop only if we discarding ICMP port unreachable packets
1343      */
1344     do {
1345         retry = FALSE;
1346 
1347         /* receive the packet */
1348         n = recvfrom(fduse, fullPacket, packetBufferLen, 0,
1349                          (struct sockaddr *)&remote_addr, &remote_addrsize);
1350 
1351         if (n == JVM_IO_ERR) {
1352             if (WSAGetLastError() == WSAECONNRESET) {
1353                 /*
1354                  * An icmp port unreachable has been received - consume any other
1355                  * outstanding packets.
1356                  */
1357                 purgeOutstandingICMP(env, this, fduse);
1358 
1359                 /*
1360                  * If connected throw a PortUnreachableException
1361                  */
1362 
1363                 if (connected) {
1364                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1365                                        "ICMP Port Unreachable");
1366 
1367                     if (packetBufferLen > MAX_BUFFER_LEN) {
1368                         free(fullPacket);
1369                     }
1370 
1371                     return;
1372                 }
1373 
1374                 /*
1375                  * If a timeout was specified then we need to adjust it because
1376                  * we may have used up some of the timeout before the icmp port
1377                  * unreachable arrived.
1378                  */
1379                 if (timeout) {
1380                     int ret;
1381                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
1382                     timeout -= (jint)(newTime - prevTime);
1383                     prevTime = newTime;
1384 
1385                     if (timeout <= 0) {
1386                         ret = 0;
1387                     } else {
1388                         ret = NET_Timeout(fduse, timeout);
1389                     }
1390 
1391                     if (ret <= 0) {
1392                         if (ret == 0) {
1393                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1394                                             "Receive timed out");
1395                         } else if (ret == JVM_IO_ERR) {
1396                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1397                                             "Socket closed");
1398                         } else if (ret == JVM_IO_INTR) {
1399                             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1400                                             "operation interrupted");
1401                         }
1402                         if (packetBufferLen > MAX_BUFFER_LEN) {
1403                             free(fullPacket);
1404                         }
1405                         return;
1406                     }
1407                 }
1408 
1409                 /*
1410                  * An ICMP port unreachable was received but we are
1411                  * not connected so ignore it.
1412                  */
1413                 retry = TRUE;
1414             }
1415         }
1416     } while (retry);
1417 
1418     /* truncate the data if the packet's length is too small */
1419     if (n > packetBufferLen) {
1420         n = packetBufferLen;
1421     }
1422     if (n < 0) {
1423         errorCode = WSAGetLastError();
1424         /* check to see if it's because the buffer was too small */
1425         if (errorCode == WSAEMSGSIZE) {
1426             /* it is because the buffer is too small. It's UDP, it's
1427              * unreliable, it's all good. discard the rest of the
1428              * data..
1429              */
1430             n = packetBufferLen;
1431         } else {
1432             /* failure */
1433             (*env)->SetIntField(env, packet, dp_lengthID, 0);
1434         }
1435     }
1436     if (n == -1) {
1437         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1438     } else if (n == -2) {
1439         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1440                         "operation interrupted");
1441     } else if (n < 0) {
1442         NET_ThrowCurrent(env, "Datagram receive failed");
1443     } else {
1444         int port;
1445         jobject packetAddress;
1446 
1447         /*
1448          * Check if there is an InetAddress already associated with this
1449          * packet. If so we check if it is the same source address. We
1450          * can't update any existing InetAddress because it is immutable
1451          */
1452         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
1453 
1454         if (packetAddress != NULL) {
1455             if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {
1456                 /* force a new InetAddress to be created */
1457                 packetAddress = NULL;
1458             }
1459         }
1460         if (packetAddress == NULL) {
1461             packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);
1462             /* stuff the new Inetaddress in the packet */
1463             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
1464         } else {
1465             /* only get the new port number */
1466             port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr);
1467         }
1468         /* populate the packet */
1469         (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
1470                                    (jbyte *)fullPacket);
1471         (*env)->SetIntField(env, packet, dp_portID, port);
1472         (*env)->SetIntField(env, packet, dp_lengthID, n);
1473     }
1474     if (packetBufferLen > MAX_BUFFER_LEN) {
1475         free(fullPacket);
1476     }
1477 }
1478 
1479 /*
1480  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1481  * Method:    datagramSocketCreate
1482  * Signature: ()V
1483  */
1484 JNIEXPORT void JNICALL
1485 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
1486                                                            jobject this) {
1487     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1488     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1489 
1490     int fd, fd1;
1491     int t = TRUE;
1492     DWORD x1, x2; /* ignored result codes */
1493     int ipv6_supported = ipv6_available();
1494 
1495     int arg = -1;
1496 
1497     if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
1498         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1499         return;
1500     } else {
1501         fd =  (int) socket (AF_INET, SOCK_DGRAM, 0);
1502     }
1503     if (fd == JVM_IO_ERR) {
1504         NET_ThrowCurrent(env, "Socket creation failed");
1505         return;
1506     }
1507     SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
1508     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
1509     NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1510 
1511     if (ipv6_supported) {
1512         /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
1513          * returns connection reset errors un connected UDP sockets (as well
1514          * as connected sockets. The solution is to only enable this feature
1515          * when the socket is connected
1516          */
1517         t = FALSE;
1518         WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1519         t = TRUE;
1520         fd1 = socket (AF_INET6, SOCK_DGRAM, 0);
1521         if (fd1 == JVM_IO_ERR) {
1522             NET_ThrowCurrent(env, "Socket creation failed");
1523             return;
1524         }
1525         NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1526         t = FALSE;
1527         WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1528         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
1529         SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
1530     } else {
1531         /* drop the second fd */
1532         (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
1533     }
1534 }
1535 
1536 /*
1537  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1538  * Method:    datagramSocketClose
1539  * Signature: ()V
1540  */
1541 JNIEXPORT void JNICALL
1542 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env,
1543                                                           jobject this) {
1544     /*
1545      * REMIND: PUT A LOCK AROUND THIS CODE
1546      */
1547     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1548     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1549     int ipv6_supported = ipv6_available();
1550     int fd=-1, fd1=-1;
1551 
1552     if (IS_NULL(fdObj) && (!ipv6_supported || IS_NULL(fd1Obj))) {
1553         return;
1554     }
1555 
1556     if (!IS_NULL(fdObj)) {
1557         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
1558         if (fd != -1) {
1559             (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
1560             NET_SocketClose(fd);
1561         }
1562     }
1563 
1564     if (ipv6_supported && fd1Obj != NULL) {
1565         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1566         if (fd1 == -1) {
1567             return;
1568         }
1569         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, -1);
1570         NET_SocketClose(fd1);
1571     }
1572 }
1573 
1574 /*
1575  * check the addresses attached to the NetworkInterface object
1576  * and return the first one (of the requested family Ipv4 or Ipv6)
1577  * in *iaddr
1578  */
1579 
1580 static int getInetAddrFromIf (JNIEnv *env, int family, jobject nif, jobject *iaddr)
1581 {
1582     jobjectArray addrArray;
1583     static jfieldID ni_addrsID=0;
1584     jsize len;
1585     jobject addr;
1586     int i;
1587 
1588     if (ni_addrsID == NULL ) {
1589         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1590         CHECK_NULL_RETURN (c, -1);
1591         ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1592                                         "[Ljava/net/InetAddress;");
1593         CHECK_NULL_RETURN (ni_addrsID, -1);
1594     }
1595 
1596     addrArray = (*env)->GetObjectField(env, nif, ni_addrsID);
1597     len = (*env)->GetArrayLength(env, addrArray);
1598 
1599     /*
1600      * Check that there is at least one address bound to this
1601      * interface.
1602      */
1603     if (len < 1) {
1604         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1605             "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");
1606         return -1;
1607     }
1608     for (i=0; i<len; i++) {
1609         int fam;
1610         addr = (*env)->GetObjectArrayElement(env, addrArray, i);
1611         fam = getInetAddress_family(env, addr);
1612         if (fam == family) {
1613             *iaddr = addr;
1614             return 0;
1615         }
1616     }
1617     return -1;
1618 }
1619 
1620 static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr)
1621 {
1622     jobject addr;
1623 
1624     int ret = getInetAddrFromIf (env, IPv4, nif, &addr);
1625     if (ret == -1) {
1626         return -1;
1627     }
1628 
1629     iaddr->s_addr = htonl(getInetAddress_addr(env, addr));
1630     return 0;
1631 }
1632 
1633 /* Get the multicasting index from the interface */
1634 
1635 static int getIndexFromIf (JNIEnv *env, jobject nif) {
1636     static jfieldID ni_indexID;
1637 
1638     if (ni_indexID == NULL) {
1639         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1640         CHECK_NULL_RETURN(c, -1);
1641         ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1642         CHECK_NULL_RETURN(ni_indexID, -1);
1643     }
1644 
1645     return (*env)->GetIntField(env, nif, ni_indexID);
1646 }
1647 
1648 static int isAdapterIpv6Enabled(JNIEnv *env, int index) {
1649   extern int getAllInterfacesAndAddresses (JNIEnv *env, netif **netifPP);
1650   netif *ifList, *curr;
1651   int ipv6Enabled = 0;
1652   if (getAllInterfacesAndAddresses (env, &ifList) < 0) {
1653       return ipv6Enabled;
1654   }
1655 
1656   /* search by index */
1657   curr = ifList;
1658   while (curr != NULL) {
1659       if (index == curr->index) {
1660           break;
1661       }
1662       curr = curr->next;
1663   }
1664 
1665   /* if found ipv6Index != 0 then interface is configured with IPV6 */
1666   if ((curr != NULL) && (curr->ipv6Index !=0)) {
1667       ipv6Enabled = 1;
1668   }
1669 
1670   /* release the interface list */
1671   free_netif(ifList);
1672 
1673   return ipv6Enabled;
1674 }
1675 
1676 /*
1677  * Sets the multicast interface.
1678  *
1679  * SocketOptions.IP_MULTICAST_IF (argument is an InetAddress) :-
1680  *      IPv4:   set outgoing multicast interface using
1681  *              IPPROTO_IP/IP_MULTICAST_IF
1682  *
1683  *      IPv6:   Get the interface to which the
1684  *              InetAddress is bound
1685  *              and do same as SockOptions.IF_MULTICAST_IF2
1686  *
1687  * SockOptions.IF_MULTICAST_IF2 (argument is a NetworkInterface ) :-
1688  *      For each stack:
1689  *      IPv4:   Obtain IP address bound to network interface
1690  *              (NetworkInterface.addres[0])
1691  *              set outgoing multicast interface using
1692  *              IPPROTO_IP/IP_MULTICAST_IF
1693  *
1694  *      IPv6:   Obtain NetworkInterface.index
1695  *              Set outgoing multicast interface using
1696  *              IPPROTO_IPV6/IPV6_MULTICAST_IF
1697  *
1698  */
1699 static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1,
1700                                   jint opt, jobject value)
1701 {
1702     int ipv6_supported = ipv6_available();
1703 
1704     if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1705         /*
1706          * value is an InetAddress.
1707          * On IPv4 system use IP_MULTICAST_IF socket option
1708          * On IPv6 system get the NetworkInterface that this IP
1709          * address is bound to and use the IPV6_MULTICAST_IF
1710          * option instead of IP_MULTICAST_IF
1711          */
1712         if (ipv6_supported) {
1713             static jclass ni_class;
1714             if (ni_class == NULL) {
1715                 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1716                 CHECK_NULL(c);
1717                 ni_class = (*env)->NewGlobalRef(env, c);
1718                 CHECK_NULL(ni_class);
1719             }
1720 
1721             value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);
1722             if (value == NULL) {
1723                 if (!(*env)->ExceptionOccurred(env)) {
1724                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1725                          "bad argument for IP_MULTICAST_IF"
1726                          ": address not bound to any interface");
1727                 }
1728                 return;
1729             }
1730             opt = java_net_SocketOptions_IP_MULTICAST_IF2;
1731         } else {
1732             struct in_addr in;
1733 
1734             in.s_addr = htonl(getInetAddress_addr(env, value));
1735             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1736                                (const char*)&in, sizeof(in)) < 0) {
1737                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1738                                  "Error setting socket option");
1739             }
1740             return;
1741         }
1742     }
1743 
1744     if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
1745         /*
1746          * value is a NetworkInterface.
1747          * On IPv6 system get the index of the interface and use the
1748          * IPV6_MULTICAST_IF socket option
1749          * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF
1750          * option. For IPv6 both must be done.
1751          */
1752         if (ipv6_supported) {
1753             static jfieldID ni_indexID;
1754             struct in_addr in;
1755             int index;
1756 
1757             if (ni_indexID == NULL) {
1758                 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1759                 CHECK_NULL(c);
1760                 ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1761                 CHECK_NULL(ni_indexID);
1762             }
1763             index = (*env)->GetIntField(env, value, ni_indexID);
1764 
1765             if ( isAdapterIpv6Enabled(env, index) != 0 ) {
1766                 if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1767                                (const char*)&index, sizeof(index)) < 0) {
1768                     if (errno == EINVAL && index > 0) {
1769                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1770                             "IPV6_MULTICAST_IF failed (interface has IPv4 "
1771                             "address only?)");
1772                     } else {
1773                         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1774                                    "Error setting socket option");
1775                     }
1776                     return;
1777                 }
1778             }
1779             /* If there are any IPv4 addresses on this interface then
1780              * repeat the operation on the IPv4 fd */
1781 
1782             if (getInet4AddrFromIf (env, value, &in) < 0) {
1783                 return;
1784             }
1785             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1786                                (const char*)&in, sizeof(in)) < 0) {
1787                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1788                                  "Error setting socket option");
1789             }
1790             return;
1791         } else {
1792             struct in_addr in;
1793 
1794             if (getInet4AddrFromIf (env, value, &in) < 0) {
1795                 if ((*env)->ExceptionOccurred(env)) {
1796                     return;
1797                 }
1798                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1799                         "no InetAddress instances of requested type");
1800                 return;
1801             }
1802 
1803             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1804                                (const char*)&in, sizeof(in)) < 0) {
1805                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1806                                "Error setting socket option");
1807             }
1808             return;
1809         }
1810     }
1811 }
1812 
1813 /*
1814  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1815  * Method:    socketNativeSetOption
1816  * Signature: (ILjava/lang/Object;)V
1817  */
1818 JNIEXPORT void JNICALL
1819 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption(JNIEnv *env,jobject this,
1820                                                       jint opt,jobject value) {
1821 
1822     int fd=-1, fd1=-1;
1823     int levelv4, levelv6, optnamev4, optnamev6, optlen;
1824     union {
1825         int i;
1826         char c;
1827     } optval;
1828     int ipv6_supported = ipv6_available();
1829     fd = getFD(env, this);
1830 
1831     if (ipv6_supported) {
1832         fd1 = getFD1(env, this);
1833     }
1834     if (fd < 0 && fd1 < 0) {
1835         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
1836         return;
1837     }
1838 
1839     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
1840         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
1841 
1842         setMulticastInterface(env, this, fd, fd1, opt, value);
1843         return;
1844     }
1845 
1846     /*
1847      * Map the Java level socket option to the platform specific
1848      * level(s) and option name(s).
1849      */
1850     if (fd1 != -1) {
1851         if (NET_MapSocketOptionV6(opt, &levelv6, &optnamev6)) {
1852             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1853             return;
1854         }
1855     }
1856     if (fd != -1) {
1857         if (NET_MapSocketOption(opt, &levelv4, &optnamev4)) {
1858             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
1859             return;
1860         }
1861     }
1862 
1863     switch (opt) {
1864         case java_net_SocketOptions_SO_SNDBUF :
1865         case java_net_SocketOptions_SO_RCVBUF :
1866         case java_net_SocketOptions_IP_TOS :
1867             {
1868                 jclass cls;
1869                 jfieldID fid;
1870 
1871                 cls = (*env)->FindClass(env, "java/lang/Integer");
1872                 CHECK_NULL(cls);
1873                 fid =  (*env)->GetFieldID(env, cls, "value", "I");
1874                 CHECK_NULL(fid);
1875 
1876                 optval.i = (*env)->GetIntField(env, value, fid);
1877                 optlen = sizeof(optval.i);
1878             }
1879             break;
1880 
1881         case java_net_SocketOptions_SO_REUSEADDR:
1882         case java_net_SocketOptions_SO_BROADCAST:
1883         case java_net_SocketOptions_IP_MULTICAST_LOOP:
1884             {
1885                 jclass cls;
1886                 jfieldID fid;
1887                 jboolean on;
1888 
1889                 cls = (*env)->FindClass(env, "java/lang/Boolean");
1890                 CHECK_NULL(cls);
1891                 fid =  (*env)->GetFieldID(env, cls, "value", "Z");
1892                 CHECK_NULL(fid);
1893 
1894                 on = (*env)->GetBooleanField(env, value, fid);
1895                 optval.i = (on ? 1 : 0);
1896                 /*
1897                  * setLoopbackMode (true) disables IP_MULTICAST_LOOP rather
1898                  * than enabling it.
1899                  */
1900                 if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP) {
1901                     optval.i = !optval.i;
1902                 }
1903                 optlen = sizeof(optval.i);
1904             }
1905             break;
1906 
1907         default :
1908             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1909                 "Socket option not supported by PlainDatagramSocketImp");
1910             break;
1911 
1912     }
1913 
1914     if (fd1 != -1) {
1915         if (NET_SetSockOpt(fd1, levelv6, optnamev6, (void *)&optval, optlen) < 0) {
1916             NET_ThrowCurrent(env, "setsockopt IPv6");
1917             return;
1918         }
1919     }
1920     if (fd != -1) {
1921         if (NET_SetSockOpt(fd, levelv4, optnamev4, (void *)&optval, optlen) < 0) {
1922             NET_ThrowCurrent(env, "setsockopt");
1923             return;
1924         }
1925     }
1926 }
1927 
1928 /*
1929  *
1930  * called by getMulticastInterface to retrieve a NetworkInterface
1931  * configured for IPv4.
1932  * The ipv4Mode parameter, is a closet boolean, which allows for a NULL return,
1933  * or forces the creation of a NetworkInterface object with null data.
1934  * It relates to its calling context in getMulticastInterface.
1935  * ipv4Mode == 1, the context is IPV4 processing only.
1936  * ipv4Mode == 0, the context is IPV6 processing
1937  *
1938  */
1939 static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint opt, int ipv4Mode) {
1940         static jclass inet4_class;
1941         static jmethodID inet4_ctrID;
1942 
1943         static jclass ni_class; static jmethodID ni_ctrID;
1944         static jfieldID ni_indexID;
1945         static jfieldID ni_addrsID;
1946 
1947         jobjectArray addrArray;
1948         jobject addr;
1949         jobject ni;
1950 
1951         struct in_addr in;
1952         struct in_addr *inP = &in;
1953         int len = sizeof(struct in_addr);
1954         if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
1955                            (char *)inP, &len) < 0) {
1956             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
1957                              "Error getting socket option");
1958             return NULL;
1959         }
1960 
1961         /*
1962          * Construct and populate an Inet4Address
1963          */
1964         if (inet4_class == NULL) {
1965             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
1966             CHECK_NULL_RETURN(c, NULL);
1967             inet4_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1968             CHECK_NULL_RETURN(inet4_ctrID, NULL);
1969             inet4_class = (*env)->NewGlobalRef(env, c);
1970             CHECK_NULL_RETURN(inet4_class, NULL);
1971         }
1972         addr = (*env)->NewObject(env, inet4_class, inet4_ctrID, 0);
1973         CHECK_NULL_RETURN(addr, NULL);
1974 
1975         setInetAddress_addr(env, addr, ntohl(in.s_addr));
1976 
1977         /*
1978          * For IP_MULTICAST_IF return InetAddress
1979          */
1980         if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
1981             return addr;
1982         }
1983 
1984         /*
1985          * For IP_MULTICAST_IF2 we get the NetworkInterface for
1986          * this address and return it
1987          */
1988         if (ni_class == NULL) {
1989             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
1990             CHECK_NULL_RETURN(c, NULL);
1991             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
1992             CHECK_NULL_RETURN(ni_ctrID, NULL);
1993             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
1994             CHECK_NULL_RETURN(ni_indexID, NULL);
1995             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
1996                                             "[Ljava/net/InetAddress;");
1997             CHECK_NULL_RETURN(ni_addrsID, NULL);
1998             ni_class = (*env)->NewGlobalRef(env, c);
1999             CHECK_NULL_RETURN(ni_class, NULL);
2000         }
2001         ni = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, addr);
2002         if (ni) {
2003             return ni;
2004         }
2005         if (ipv4Mode) {
2006             ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
2007             CHECK_NULL_RETURN(ni, NULL);
2008 
2009             (*env)->SetIntField(env, ni, ni_indexID, -1);
2010             addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
2011             CHECK_NULL_RETURN(addrArray, NULL);
2012             (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
2013             (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
2014         } else {
2015             ni = NULL;
2016         }
2017         return ni;
2018 }
2019 
2020 /*
2021  * Return the multicast interface:
2022  *
2023  * SocketOptions.IP_MULTICAST_IF
2024  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
2025  *              Create InetAddress
2026  *              IP_MULTICAST_IF returns struct ip_mreqn on 2.2
2027  *              kernel but struct in_addr on 2.4 kernel
2028  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
2029  *              obtain from impl is Linux 2.2 kernel
2030  *              If index == 0 return InetAddress representing
2031  *              anyLocalAddress.
2032  *              If index > 0 query NetworkInterface by index
2033  *              and returns addrs[0]
2034  *
2035  * SocketOptions.IP_MULTICAST_IF2
2036  *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
2037  *              Query NetworkInterface by IP address and
2038  *              return the NetworkInterface that the address
2039  *              is bound too.
2040  *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
2041  *              (except Linux .2 kernel)
2042  *              Query NetworkInterface by index and
2043  *              return NetworkInterface.
2044  */
2045 jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
2046     jboolean isIPV4 = !ipv6_available() || fd1 == -1;
2047 
2048     /*
2049      * IPv4 implementation
2050      */
2051     if (isIPV4) {
2052         jobject netObject = NULL; // return is either an addr or a netif
2053         netObject = getIPv4NetworkInterface(env, this, fd, opt, 1);
2054         return netObject;
2055     }
2056 
2057     /*
2058      * IPv6 implementation
2059      */
2060     if ((opt == java_net_SocketOptions_IP_MULTICAST_IF) ||
2061         (opt == java_net_SocketOptions_IP_MULTICAST_IF2)) {
2062 
2063         static jclass ni_class;
2064         static jmethodID ni_ctrID;
2065         static jfieldID ni_indexID;
2066         static jfieldID ni_addrsID;
2067         static jclass ia_class;
2068         static jmethodID ia_anyLocalAddressID;
2069 
2070         int index;
2071         int len = sizeof(index);
2072 
2073         jobjectArray addrArray;
2074         jobject addr;
2075         jobject ni;
2076 
2077         {
2078             if (getsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
2079                                (char*)&index, &len) < 0) {
2080                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
2081                                "Error getting socket option");
2082                 return NULL;
2083             }
2084         }
2085 
2086         if (ni_class == NULL) {
2087             jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
2088             CHECK_NULL_RETURN(c, NULL);
2089             ni_ctrID = (*env)->GetMethodID(env, c, "<init>", "()V");
2090             CHECK_NULL_RETURN(ni_ctrID, NULL);
2091             ni_indexID = (*env)->GetFieldID(env, c, "index", "I");
2092             CHECK_NULL_RETURN(ni_indexID, NULL);
2093             ni_addrsID = (*env)->GetFieldID(env, c, "addrs",
2094                                             "[Ljava/net/InetAddress;");
2095             CHECK_NULL_RETURN(ni_addrsID, NULL);
2096 
2097             ia_class = (*env)->FindClass(env, "java/net/InetAddress");
2098             CHECK_NULL_RETURN(ia_class, NULL);
2099             ia_class = (*env)->NewGlobalRef(env, ia_class);
2100             CHECK_NULL_RETURN(ia_class, NULL);
2101             ia_anyLocalAddressID = (*env)->GetStaticMethodID(env,
2102                                                              ia_class,
2103                                                              "anyLocalAddress",
2104                                                              "()Ljava/net/InetAddress;");
2105             CHECK_NULL_RETURN(ia_anyLocalAddressID, NULL);
2106             ni_class = (*env)->NewGlobalRef(env, c);
2107             CHECK_NULL_RETURN(ni_class, NULL);
2108         }
2109 
2110         /*
2111          * If multicast to a specific interface then return the
2112          * interface (for IF2) or the any address on that interface
2113          * (for IF).
2114          */
2115         if (index > 0) {
2116             ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class,
2117                                                                    index);
2118             if (ni == NULL) {
2119                 char errmsg[255];
2120                 sprintf(errmsg,
2121                         "IPV6_MULTICAST_IF returned index to unrecognized interface: %d",
2122                         index);
2123                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
2124                 return NULL;
2125             }
2126 
2127             /*
2128              * For IP_MULTICAST_IF2 return the NetworkInterface
2129              */
2130             if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
2131                 return ni;
2132             }
2133 
2134             /*
2135              * For IP_MULTICAST_IF return addrs[0]
2136              */
2137             addrArray = (*env)->GetObjectField(env, ni, ni_addrsID);
2138             if ((*env)->GetArrayLength(env, addrArray) < 1) {
2139                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2140                     "IPV6_MULTICAST_IF returned interface without IP bindings");
2141                 return NULL;
2142             }
2143 
2144             addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
2145             return addr;
2146         } else if (index == 0) { // index == 0 typically means IPv6 not configured on the interfaces
2147             // falling back to treat interface as configured for IPv4
2148             jobject netObject = NULL;
2149             netObject = getIPv4NetworkInterface(env, this, fd, opt, 0);
2150             if (netObject != NULL) {
2151                 return netObject;
2152             }
2153         }
2154 
2155         /*
2156          * Multicast to any address - return anyLocalAddress
2157          * or a NetworkInterface with addrs[0] set to anyLocalAddress
2158          */
2159 
2160         addr = (*env)->CallStaticObjectMethod(env, ia_class, ia_anyLocalAddressID,
2161                                               NULL);
2162         if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {
2163             return addr;
2164         }
2165 
2166         ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
2167         CHECK_NULL_RETURN(ni, NULL);
2168         (*env)->SetIntField(env, ni, ni_indexID, -1);
2169         addrArray = (*env)->NewObjectArray(env, 1, ia_class, NULL);
2170         CHECK_NULL_RETURN(addrArray, NULL);
2171         (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
2172         (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
2173         return ni;
2174     }
2175     return NULL;
2176 }
2177 
2178 
2179 /*
2180  * Returns relevant info as a jint.
2181  *
2182  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2183  * Method:    socketGetOption
2184  * Signature: (I)Ljava/lang/Object;
2185  */
2186 JNIEXPORT jobject JNICALL
2187 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this,
2188                                                       jint opt) {
2189 
2190     int fd=-1, fd1=-1;
2191     int level, optname, optlen;
2192     union {
2193         int i;
2194     } optval;
2195     int ipv6_supported = ipv6_available();
2196 
2197     fd = getFD(env, this);
2198     if (ipv6_supported) {
2199         fd1 = getFD1(env, this);
2200     }
2201 
2202     if (fd < 0 && fd1 < 0) {
2203         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2204                         "Socket closed");
2205         return NULL;
2206     }
2207 
2208     /*
2209      * Handle IP_MULTICAST_IF separately
2210      */
2211     if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||
2212         opt == java_net_SocketOptions_IP_MULTICAST_IF2) {
2213         return getMulticastInterface(env, this, fd, fd1, opt);
2214     }
2215 
2216     /*
2217      * Map the Java level socket option to the platform specific
2218      * level and option name.
2219      */
2220     if (NET_MapSocketOption(opt, &level, &optname)) {
2221         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
2222         return NULL;
2223     }
2224 
2225     if (fd == -1) {
2226         if (NET_MapSocketOptionV6(opt, &level, &optname)) {
2227             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
2228             return NULL;
2229         }
2230         fd = fd1; /* must be IPv6 only */
2231     }
2232 
2233     optlen = sizeof(optval.i);
2234     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
2235         char errmsg[255];
2236         sprintf(errmsg, "error getting socket option: %s\n", strerror(errno));
2237         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
2238         return NULL;
2239     }
2240 
2241     switch (opt) {
2242         case java_net_SocketOptions_SO_BROADCAST:
2243         case java_net_SocketOptions_SO_REUSEADDR:
2244             return createBoolean(env, optval.i);
2245 
2246         case java_net_SocketOptions_IP_MULTICAST_LOOP:
2247             /* getLoopbackMode() returns true if IP_MULTICAST_LOOP is disabled */
2248             return createBoolean(env, !optval.i);
2249 
2250         case java_net_SocketOptions_SO_SNDBUF:
2251         case java_net_SocketOptions_SO_RCVBUF:
2252         case java_net_SocketOptions_IP_TOS:
2253             return createInteger(env, optval.i);
2254 
2255         default :
2256             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2257                 "Socket option not supported by TwoStacksPlainDatagramSocketImpl");
2258             return NULL;
2259 
2260     }
2261 }
2262 
2263 /*
2264  * Returns local address of the socket.
2265  *
2266  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2267  * Method:    socketLocalAddress
2268  * Signature: (I)Ljava/lang/Object;
2269  */
2270 JNIEXPORT jobject JNICALL
2271 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketLocalAddress(JNIEnv *env, jobject this,
2272                                                       jint family) {
2273 
2274     int fd=-1, fd1=-1;
2275     SOCKETADDRESS him;
2276     int len = 0;
2277     int port;
2278     jobject iaObj;
2279     int ipv6_supported = ipv6_available();
2280 
2281     fd = getFD(env, this);
2282     if (ipv6_supported) {
2283         fd1 = getFD1(env, this);
2284     }
2285 
2286     if (fd < 0 && fd1 < 0) {
2287         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2288                         "Socket closed");
2289         return NULL;
2290     }
2291 
2292     /* find out local IP address */
2293 
2294     len = sizeof (struct sockaddr_in);
2295 
2296     /* family==-1 when socket is not connected */
2297     if ((family == IPv6) || (family == -1 && fd == -1)) {
2298         fd = fd1; /* must be IPv6 only */
2299         len = sizeof (struct SOCKADDR_IN6);
2300     }
2301 
2302     if (fd == -1) {
2303         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2304                         "Socket closed");
2305         return NULL;
2306     }
2307 
2308     if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {
2309         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
2310                        "Error getting socket name");
2311         return NULL;
2312     }
2313     iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
2314 
2315     return iaObj;
2316 }
2317 
2318 /*
2319  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2320  * Method:    setTimeToLive
2321  * Signature: (I)V
2322  */
2323 JNIEXPORT void JNICALL
2324 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,
2325                                                     jint ttl) {
2326 
2327     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2328     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2329     int fd = -1, fd1 = -1;
2330     int ittl = (int)ttl;
2331 
2332     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2333         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2334                         "Socket closed");
2335         return;
2336     } else {
2337       if (!IS_NULL(fdObj)) {
2338         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2339       }
2340       if (!IS_NULL(fd1Obj)) {
2341         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2342       }
2343     }
2344 
2345     /* setsockopt to be correct ttl */
2346     if (fd >= 0) {
2347       if (NET_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ittl,
2348                          sizeof (ittl)) < 0) {
2349         NET_ThrowCurrent(env, "set IP_MULTICAST_TTL failed");
2350       }
2351     }
2352 
2353     if (fd1 >= 0) {
2354       if (NET_SetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ittl,
2355                          sizeof(ittl)) <0) {
2356         NET_ThrowCurrent(env, "set IPV6_MULTICAST_HOPS failed");
2357       }
2358     }
2359 }
2360 
2361 /*
2362  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2363  * Method:    setTTL
2364  * Signature: (B)V
2365  */
2366 JNIEXPORT void JNICALL
2367 Java_java_net_TwoStacksPlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,
2368                                              jbyte ttl) {
2369     Java_java_net_TwoStacksPlainDatagramSocketImpl_setTimeToLive(env, this,
2370                                                         (jint)ttl & 0xFF);
2371 }
2372 
2373 /*
2374  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2375  * Method:    getTimeToLive
2376  * Signature: ()I
2377  */
2378 JNIEXPORT jint JNICALL
2379 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {
2380     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2381     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2382     int fd = -1, fd1 = -1;
2383     int ttl = 0;
2384     int len = sizeof(ttl);
2385 
2386     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2387         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2388                         "Socket closed");
2389         return -1;
2390     } else {
2391       if (!IS_NULL(fdObj)) {
2392         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2393       }
2394       if (!IS_NULL(fd1Obj)) {
2395         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2396       }
2397     }
2398 
2399     /* getsockopt of ttl */
2400     if (fd >= 0) {
2401       if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, &len) < 0) {
2402         NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2403         return -1;
2404       }
2405       return (jint)ttl;
2406     }
2407     if (fd1 >= 0) {
2408       if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&ttl, &len) < 0) {
2409         NET_ThrowCurrent(env, "get IP_MULTICAST_TTL failed");
2410         return -1;
2411       }
2412       return (jint)ttl;
2413     }
2414     return -1;
2415 }
2416 
2417 /*
2418  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2419  * Method:    getTTL
2420  * Signature: ()B
2421  */
2422 JNIEXPORT jbyte JNICALL
2423 Java_java_net_TwoStacksPlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) {
2424     int result = Java_java_net_TwoStacksPlainDatagramSocketImpl_getTimeToLive(env, this);
2425 
2426     return (jbyte)result;
2427 }
2428 
2429 /* join/leave the named group on the named interface, or if no interface specified
2430  * then the interface set with setInterfac(), or the default interface otherwise */
2431 
2432 static void mcast_join_leave(JNIEnv *env, jobject this,
2433                              jobject iaObj, jobject niObj,
2434                              jboolean join)
2435 {
2436     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
2437     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
2438     jint fd = -1, fd1 = -1;
2439 
2440     SOCKETADDRESS name;
2441     struct ip_mreq mname;
2442     struct ipv6_mreq mname6;
2443 
2444     struct in_addr in;
2445     DWORD ifindex;
2446 
2447     int len, family;
2448     int ipv6_supported = ipv6_available();
2449     int cmd ;
2450 
2451     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
2452         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2453                         "Socket closed");
2454         return;
2455     }
2456     if (!IS_NULL(fdObj)) {
2457         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
2458     }
2459     if (ipv6_supported && !IS_NULL(fd1Obj)) {
2460         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
2461     }
2462 
2463     if (IS_NULL(iaObj)) {
2464         JNU_ThrowNullPointerException(env, "address");
2465         return;
2466     }
2467 
2468     if (NET_InetAddressToSockaddr(env, iaObj, 0, (struct sockaddr *)&name, &len, JNI_FALSE) != 0) {
2469       return;
2470     }
2471 
2472     /* Set the multicast group address in the ip_mreq field
2473      * eventually this check should be done by the security manager
2474      */
2475     family = name.him.sa_family;
2476 
2477     if (family == AF_INET) {
2478         int address = name.him4.sin_addr.s_addr;
2479         if (!IN_MULTICAST(ntohl(address))) {
2480             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in multicast");
2481             return;
2482         }
2483         mname.imr_multiaddr.s_addr = address;
2484         if (fd < 0) {
2485           JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv4 group on an IPv6 only socket");
2486           return;
2487         }
2488         if (IS_NULL(niObj)) {
2489             len = sizeof (in);
2490             if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
2491                            (char *)&in, &len) < 0) {
2492                 NET_ThrowCurrent(env, "get IP_MULTICAST_IF failed");
2493                 return;
2494             }
2495             mname.imr_interface.s_addr = in.s_addr;
2496         } else {
2497             if (getInet4AddrFromIf (env, niObj, &mname.imr_interface) != 0) {
2498                 NET_ThrowCurrent(env, "no Inet4Address associated with interface");
2499                 return;
2500             }
2501         }
2502 
2503         cmd = join ? IP_ADD_MEMBERSHIP: IP_DROP_MEMBERSHIP;
2504 
2505         /* Join the multicast group */
2506         if (NET_SetSockOpt(fd, IPPROTO_IP, cmd, (char *) &mname, sizeof (mname)) < 0) {
2507             if (WSAGetLastError() == WSAENOBUFS) {
2508                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2509                     "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2510             } else {
2511                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2512             }
2513         }
2514     } else /* AF_INET6 */ {
2515         if (ipv6_supported) {
2516             struct in6_addr *address;
2517             address = &name.him6.sin6_addr;
2518             if (!IN6_IS_ADDR_MULTICAST(address)) {
2519                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "not in6 multicast");
2520                 return;
2521             }
2522             mname6.ipv6mr_multiaddr = *address;
2523         } else {
2524             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "IPv6 not supported");
2525             return;
2526         }
2527         if (fd1 < 0) {
2528           JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Can't join an IPv6 group on a IPv4 socket");
2529           return;
2530         }
2531         if (IS_NULL(niObj)) {
2532             len = sizeof (ifindex);
2533             if (NET_GetSockOpt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, &len) < 0) {
2534                 NET_ThrowCurrent(env, "get IPV6_MULTICAST_IF failed");
2535                 return;
2536             }
2537         } else {
2538             ifindex = getIndexFromIf (env, niObj);
2539             if (ifindex == -1) {
2540                 NET_ThrowCurrent(env, "get ifindex failed");
2541                 return;
2542             }
2543         }
2544         mname6.ipv6mr_interface = ifindex;
2545         cmd = join ? IPV6_ADD_MEMBERSHIP: IPV6_DROP_MEMBERSHIP;
2546 
2547         /* Join the multicast group */
2548         if (NET_SetSockOpt(fd1, IPPROTO_IPV6, cmd, (char *) &mname6, sizeof (mname6)) < 0) {
2549             if (WSAGetLastError() == WSAENOBUFS) {
2550                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
2551                     "IP_ADD_MEMBERSHIP failed (out of hardware filters?)");
2552             } else {
2553                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException","error setting options");
2554             }
2555         }
2556     }
2557 
2558     return;
2559 }
2560 
2561 /*
2562  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2563  * Method:    join
2564  * Signature: (Ljava/net/InetAddress;)V
2565  */
2566 JNIEXPORT void JNICALL
2567 Java_java_net_TwoStacksPlainDatagramSocketImpl_join(JNIEnv *env, jobject this,
2568                                            jobject iaObj, jobject niObj)
2569 {
2570     mcast_join_leave (env, this, iaObj, niObj, JNI_TRUE);
2571 }
2572 
2573 /*
2574  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
2575  * Method:    leave
2576  * Signature: (Ljava/net/InetAddress;)V
2577  */
2578 JNIEXPORT void JNICALL
2579 Java_java_net_TwoStacksPlainDatagramSocketImpl_leave(JNIEnv *env, jobject this,
2580                                             jobject iaObj, jobject niObj)
2581 {
2582     mcast_join_leave (env, this, iaObj, niObj, JNI_FALSE);
2583 }