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