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