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