1 /*
   2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <errno.h>
  27 #include <sys/time.h>
  28 #include <sys/types.h>
  29 #include <sys/socket.h>
  30 #include <netinet/in.h>
  31 #include <netdb.h>
  32 #include <string.h>
  33 #include <strings.h>
  34 #include <stdlib.h>
  35 #include <ctype.h>
  36 #ifdef MACOSX
  37 #include <ifaddrs.h>
  38 #include <net/if.h>
  39 #include <unistd.h> /* gethostname */
  40 #endif
  41 
  42 #include "jvm.h"
  43 #include "jni_util.h"
  44 #include "net_util.h"
  45 #ifndef IPV6_DEFS_H
  46 #include <netinet/icmp6.h>
  47 #endif
  48 
  49 #include "java_net_Inet4AddressImpl.h"
  50 #include "java_net_Inet6AddressImpl.h"
  51 
  52 /* the initial size of our hostent buffers */
  53 #ifndef NI_MAXHOST
  54 #define NI_MAXHOST 1025
  55 #endif
  56 
  57 
  58 /************************************************************************
  59  * Inet6AddressImpl
  60  */
  61 
  62 /*
  63  * Class:     java_net_Inet6AddressImpl
  64  * Method:    getLocalHostName
  65  * Signature: ()Ljava/lang/String;
  66  */
  67 JNIEXPORT jstring JNICALL
  68 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
  69     char hostname[NI_MAXHOST+1];
  70 
  71     hostname[0] = '\0';
  72     if (JVM_GetHostName(hostname, sizeof(hostname))) {
  73         /* Something went wrong, maybe networking is not setup? */
  74         strcpy(hostname, "localhost");
  75     } else {
  76         // ensure null-terminated
  77         hostname[NI_MAXHOST] = '\0';
  78 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
  79         /* On Linux/FreeBSD gethostname() says "host.domain.sun.com".  On
  80          * Solaris gethostname() says "host", so extra work is needed.
  81          */
  82 #else
  83         /* Solaris doesn't want to give us a fully qualified domain name.
  84          * We do a reverse lookup to try and get one.  This works
  85          * if DNS occurs before NIS in /etc/resolv.conf, but fails
  86          * if NIS comes first (it still gets only a partial name).
  87          * We use thread-safe system calls.
  88          */
  89 #ifdef AF_INET6
  90         struct addrinfo  hints, *res;
  91         int error;
  92 
  93         memset(&hints, 0, sizeof(hints));
  94         hints.ai_flags = AI_CANONNAME;
  95         hints.ai_family = AF_UNSPEC;
  96 
  97         error = getaddrinfo(hostname, NULL, &hints, &res);
  98 
  99         if (error == 0) {
 100             /* host is known to name service */
 101             error = getnameinfo(res->ai_addr,
 102                                 res->ai_addrlen,
 103                                 hostname,
 104                                 NI_MAXHOST,
 105                                 NULL,
 106                                 0,
 107                                 NI_NAMEREQD);
 108 
 109             /* if getnameinfo fails hostname is still the value
 110                from gethostname */
 111 
 112             freeaddrinfo(res);
 113         }
 114 #endif /* AF_INET6 */
 115 #endif /* __linux__ || _ALLBSD_SOURCE */
 116     }
 117     return (*env)->NewStringUTF(env, hostname);
 118 }
 119 
 120 static jclass ni_iacls;
 121 static jclass ni_ia4cls;
 122 static jclass ni_ia6cls;
 123 static jmethodID ni_ia4ctrID;
 124 static jmethodID ni_ia6ctrID;
 125 static jboolean preferIPv6Address;
 126 
 127 static jboolean initializeInetClasses(JNIEnv *env)
 128 {
 129     jfieldID ni_preferIPv6AddressID;
 130     static int initialized = 0;
 131     if (!initialized) {
 132         ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
 133         CHECK_NULL_RETURN(ni_iacls, JNI_FALSE);
 134         ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
 135         CHECK_NULL_RETURN(ni_iacls, JNI_FALSE);
 136         ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
 137         CHECK_NULL_RETURN(ni_ia4cls, JNI_FALSE);
 138         ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
 139         CHECK_NULL_RETURN(ni_ia4cls, JNI_FALSE);
 140         ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
 141         CHECK_NULL_RETURN(ni_ia6cls, JNI_FALSE);
 142         ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
 143         CHECK_NULL_RETURN(ni_ia6cls, JNI_FALSE);
 144         ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
 145         CHECK_NULL_RETURN(ni_ia4ctrID, JNI_FALSE);
 146         ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
 147         CHECK_NULL_RETURN(ni_ia6ctrID, JNI_FALSE);
 148         ni_preferIPv6AddressID =
 149             (*env)->GetStaticFieldID(env, ni_iacls, "preferIPv6Address", "Z");
 150         CHECK_NULL_RETURN(ni_preferIPv6AddressID, JNI_FALSE);
 151         preferIPv6Address =
 152             (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
 153         initialized = 1;
 154     }
 155     return JNI_TRUE;
 156 }
 157 
 158 #ifdef MACOSX
 159 /* also called from Inet4AddressImpl.c */
 160 __private_extern__ jobjectArray
 161 lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6)
 162 {
 163     jobjectArray result = NULL;
 164     char myhostname[NI_MAXHOST+1];
 165     struct ifaddrs *ifa = NULL;
 166     int familyOrder = 0;
 167     int count = 0, i, j;
 168     int addrs4 = 0, addrs6 = 0, numV4Loopbacks = 0, numV6Loopbacks = 0;
 169     jboolean includeLoopback = JNI_FALSE;
 170     jobject name;
 171 
 172     // Make sure static variables we need are set.
 173     if (!initializeInetClasses(env))
 174         return NULL;
 175 
 176     /* If the requested name matches this host's hostname, return IP addresses
 177      * from all attached interfaces. (#2844683 et al) This prevents undesired
 178      * PPP dialup, but may return addresses that don't actually correspond to
 179      * the name (if the name actually matches something in DNS etc.
 180      */
 181     myhostname[0] = '\0';
 182     if (JVM_GetHostName(myhostname, NI_MAXHOST)) {
 183         /* Something went wrong, maybe networking is not setup? */
 184         return NULL;
 185     }
 186     myhostname[NI_MAXHOST] = '\0';
 187 
 188     if (strcmp(myhostname, hostname) != 0) {
 189         // Non-self lookup
 190         return NULL;
 191     }
 192 
 193     if (getifaddrs(&ifa) != 0) {
 194         NET_ThrowNew(env, errno, "Can't get local interface addresses");
 195         return NULL;
 196     }
 197 
 198     name = (*env)->NewStringUTF(env, hostname);
 199     CHECK_NULL_RETURN(name);
 200 
 201     /* Iterate over the interfaces, and total up the number of IPv4 and IPv6
 202      * addresses we have. Also keep a count of loopback addresses. We need to
 203      * exclude them in the normal case, but return them if we don't get an IP
 204      * address.
 205      */
 206     struct ifaddrs *iter = ifa;
 207     while (iter) {
 208         int family = iter->ifa_addr->sa_family;
 209         if (iter->ifa_name[0] != '\0'  &&  iter->ifa_addr)
 210         {
 211             jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
 212             if (family == AF_INET) {
 213                 addrs4++;
 214                 if (isLoopback) numV4Loopbacks++;
 215             } else if (family == AF_INET6 && includeV6) {
 216                 addrs6++;
 217                 if (isLoopback) numV6Loopbacks++;
 218             } else {
 219                 /* We don't care e.g. AF_LINK */
 220             }
 221         }
 222         iter = iter->ifa_next;
 223     }
 224 
 225     if (addrs4 == numV4Loopbacks && addrs6 == numV6Loopbacks) {
 226         // We don't have a real IP address, just loopback. We need to include
 227         // loopback in our results.
 228         includeLoopback = JNI_TRUE;
 229     }
 230 
 231     /* Create and fill the Java array. */
 232     int arraySize = addrs4 + addrs6 -
 233         (includeLoopback ? 0 : (numV4Loopbacks + numV6Loopbacks));
 234     result = (*env)->NewObjectArray(env, arraySize, ni_iacls, NULL);
 235     if (!result) goto done;
 236 
 237     if (preferIPv6Address) {
 238         i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
 239         j = 0;
 240     } else {
 241         i = 0;
 242         j = includeLoopback ? addrs4 : (addrs4 - numV4Loopbacks);
 243     }
 244 
 245     // Now loop around the ifaddrs
 246     iter = ifa;
 247     while (iter != NULL) {
 248         jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
 249         int family = iter->ifa_addr->sa_family;
 250 
 251         if (iter->ifa_name[0] != '\0'  &&  iter->ifa_addr
 252             && (family == AF_INET || (family == AF_INET6 && includeV6))
 253             && (!isLoopback || includeLoopback))
 254         {
 255             int port;
 256             int index = (family == AF_INET) ? i++ : j++;
 257             jobject o = NET_SockaddrToInetAddress(env, iter->ifa_addr, &port);
 258             if (!o) {
 259                 freeifaddrs(ifa);
 260                 if (!(*env)->ExceptionCheck(env))
 261                     JNU_ThrowOutOfMemoryError(env, "Object allocation failed");
 262                 return NULL;
 263             }
 264             setInetAddress_hostName(env, o, name);
 265             (*env)->SetObjectArrayElement(env, result, index, o);
 266             (*env)->DeleteLocalRef(env, o);
 267         }
 268         iter = iter->ifa_next;
 269     }
 270 
 271   done:
 272     freeifaddrs(ifa);
 273 
 274     return result;
 275 }
 276 #endif
 277 
 278 /*
 279  * Find an internet address for a given hostname.  Note that this
 280  * code only works for addresses of type INET. The translation
 281  * of %d.%d.%d.%d to an address (int) occurs in java now, so the
 282  * String "host" shouldn't *ever* be a %d.%d.%d.%d string
 283  *
 284  * Class:     java_net_Inet6AddressImpl
 285  * Method:    lookupAllHostAddr
 286  * Signature: (Ljava/lang/String;)[[B
 287  */
 288 
 289 JNIEXPORT jobjectArray JNICALL
 290 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
 291                                                 jstring host) {
 292     const char *hostname;
 293     jobjectArray ret = 0;
 294     int retLen = 0;
 295 
 296     int error=0;
 297 #ifdef AF_INET6
 298     struct addrinfo hints, *res, *resNew = NULL;
 299 #endif /* AF_INET6 */
 300 
 301     if (!initializeInetClasses(env))
 302         return NULL;
 303 
 304     if (IS_NULL(host)) {
 305         JNU_ThrowNullPointerException(env, "host is null");
 306         return 0;
 307     }
 308     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
 309     CHECK_NULL_RETURN(hostname, NULL);
 310 
 311 #ifdef MACOSX
 312     /*
 313      * If we're looking up the local machine, attempt to get the address
 314      * from getifaddrs. This ensures we get an IPv6 address for the local
 315      * machine.
 316      */
 317     ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
 318     if (ret != NULL || (*env)->ExceptionCheck(env)) {
 319         JNU_ReleaseStringPlatformChars(env, host, hostname);
 320         return ret;
 321     }
 322 #endif
 323 
 324 #ifdef AF_INET6
 325     /* Try once, with our static buffer. */
 326     memset(&hints, 0, sizeof(hints));
 327     hints.ai_flags = AI_CANONNAME;
 328     hints.ai_family = AF_UNSPEC;
 329 
 330 #ifdef __solaris__
 331     /*
 332      * Workaround for Solaris bug 4160367 - if a hostname contains a
 333      * white space then 0.0.0.0 is returned
 334      */
 335     if (isspace((unsigned char)hostname[0])) {
 336         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
 337                         hostname);
 338         JNU_ReleaseStringPlatformChars(env, host, hostname);
 339         return NULL;
 340     }
 341 #endif
 342 
 343     error = getaddrinfo(hostname, NULL, &hints, &res);
 344 
 345     if (error) {
 346         /* report error */
 347         ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
 348         JNU_ReleaseStringPlatformChars(env, host, hostname);
 349         return NULL;
 350     } else {
 351         int i = 0;
 352         int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
 353         struct addrinfo *itr, *last = NULL, *iterator = res;
 354         while (iterator != NULL) {
 355             int skip = 0;
 356             itr = resNew;
 357             while (itr != NULL) {
 358                 if (iterator->ai_family == itr->ai_family &&
 359                     iterator->ai_addrlen == itr->ai_addrlen) {
 360                     if (itr->ai_family == AF_INET) { /* AF_INET */
 361                         struct sockaddr_in *addr1, *addr2;
 362                         addr1 = (struct sockaddr_in *)iterator->ai_addr;
 363                         addr2 = (struct sockaddr_in *)itr->ai_addr;
 364                         if (addr1->sin_addr.s_addr ==
 365                             addr2->sin_addr.s_addr) {
 366                             skip = 1;
 367                             break;
 368                         }
 369                     } else {
 370                         int t;
 371                         struct sockaddr_in6 *addr1, *addr2;
 372                         addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
 373                         addr2 = (struct sockaddr_in6 *)itr->ai_addr;
 374 
 375                         for (t = 0; t < 16; t++) {
 376                             if (addr1->sin6_addr.s6_addr[t] !=
 377                                 addr2->sin6_addr.s6_addr[t]) {
 378                                 break;
 379                             }
 380                         }
 381                         if (t < 16) {
 382                             itr = itr->ai_next;
 383                             continue;
 384                         } else {
 385                             skip = 1;
 386                             break;
 387                         }
 388                     }
 389                 } else if (iterator->ai_family != AF_INET &&
 390                            iterator->ai_family != AF_INET6) {
 391                     /* we can't handle other family types */
 392                     skip = 1;
 393                     break;
 394                 }
 395                 itr = itr->ai_next;
 396             }
 397 
 398             if (!skip) {
 399                 struct addrinfo *next
 400                     = (struct addrinfo*) malloc(sizeof(struct addrinfo));
 401                 if (!next) {
 402                     JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
 403                     ret = NULL;
 404                     goto cleanupAndReturn;
 405                 }
 406                 memcpy(next, iterator, sizeof(struct addrinfo));
 407                 next->ai_next = NULL;
 408                 if (resNew == NULL) {
 409                     resNew = next;
 410                 } else {
 411                     last->ai_next = next;
 412                 }
 413                 last = next;
 414                 i++;
 415                 if (iterator->ai_family == AF_INET) {
 416                     inetCount ++;
 417                 } else if (iterator->ai_family == AF_INET6) {
 418                     inet6Count ++;
 419                 }
 420             }
 421             iterator = iterator->ai_next;
 422         }
 423         retLen = i;
 424         iterator = resNew;
 425 
 426         ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
 427 
 428         if (IS_NULL(ret)) {
 429             /* we may have memory to free at the end of this */
 430             goto cleanupAndReturn;
 431         }
 432 
 433         if (preferIPv6Address) {
 434             /* AF_INET addresses will be offset by inet6Count */
 435             inetIndex = inet6Count;
 436             inet6Index = 0;
 437         } else {
 438             /* AF_INET6 addresses will be offset by inetCount */
 439             inetIndex = 0;
 440             inet6Index = inetCount;
 441         }
 442 
 443         while (iterator != NULL) {
 444             int ret1;
 445             if (iterator->ai_family == AF_INET) {
 446                 jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
 447                 if (IS_NULL(iaObj)) {
 448                     ret = NULL;
 449                     goto cleanupAndReturn;
 450                 }
 451                 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
 452                 setInetAddress_hostName(env, iaObj, host);
 453                 (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
 454                 inetIndex++;
 455             } else if (iterator->ai_family == AF_INET6) {
 456                 jint scope = 0;
 457 
 458                 jobject iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
 459                 if (IS_NULL(iaObj)) {
 460                     ret = NULL;
 461                     goto cleanupAndReturn;
 462                 }
 463                 ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
 464                 if (!ret1) {
 465                     ret = NULL;
 466                     goto cleanupAndReturn;
 467                 }
 468 
 469                 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
 470                 if (scope != 0) { /* zero is default value, no need to set */
 471                     setInet6Address_scopeid(env, iaObj, scope);
 472                 }
 473                 setInetAddress_hostName(env, iaObj, host);
 474                 (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
 475                 inet6Index++;
 476             }
 477             iterator = iterator->ai_next;
 478         }
 479     }
 480 
 481  cleanupAndReturn:
 482     {
 483       struct addrinfo *iterator, *tmp;
 484         iterator = resNew;
 485         while (iterator != NULL) {
 486             tmp = iterator;
 487             iterator = iterator->ai_next;
 488             free(tmp);
 489         }
 490         JNU_ReleaseStringPlatformChars(env, host, hostname);
 491     }
 492 
 493     freeaddrinfo(res);
 494 #endif /* AF_INET6 */
 495 
 496     return ret;
 497 }
 498 
 499 /*
 500  * Class:     java_net_Inet6AddressImpl
 501  * Method:    getHostByAddr
 502  * Signature: (I)Ljava/lang/String;
 503  */
 504 JNIEXPORT jstring JNICALL
 505 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
 506                                             jbyteArray addrArray) {
 507 
 508     jstring ret = NULL;
 509 
 510 #ifdef AF_INET6
 511     char host[NI_MAXHOST+1];
 512     int error = 0;
 513     int len = 0;
 514     jbyte caddr[16];
 515 
 516     struct sockaddr_in him4;
 517     struct sockaddr_in6 him6;
 518     struct sockaddr *sa;
 519 
 520     /*
 521      * For IPv4 addresses construct a sockaddr_in structure.
 522      */
 523     if ((*env)->GetArrayLength(env, addrArray) == 4) {
 524         jint addr;
 525         (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 526         addr = ((caddr[0]<<24) & 0xff000000);
 527         addr |= ((caddr[1] <<16) & 0xff0000);
 528         addr |= ((caddr[2] <<8) & 0xff00);
 529         addr |= (caddr[3] & 0xff);
 530         memset((void *) &him4, 0, sizeof(him4));
 531         him4.sin_addr.s_addr = (uint32_t) htonl(addr);
 532         him4.sin_family = AF_INET;
 533         sa = (struct sockaddr *) &him4;
 534         len = sizeof(him4);
 535     } else {
 536         /*
 537          * For IPv6 address construct a sockaddr_in6 structure.
 538          */
 539         (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
 540         memset((void *) &him6, 0, sizeof(him6));
 541         memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
 542         him6.sin6_family = AF_INET6;
 543         sa = (struct sockaddr *) &him6 ;
 544         len = sizeof(him6) ;
 545     }
 546 
 547     error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
 548                         NI_NAMEREQD);
 549 
 550     if (!error) {
 551         ret = (*env)->NewStringUTF(env, host);
 552     }
 553 #endif /* AF_INET6 */
 554 
 555     if (ret == NULL) {
 556         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
 557     }
 558 
 559     return ret;
 560 }
 561 
 562 #define SET_NONBLOCKING(fd) {           \
 563         int flags = fcntl(fd, F_GETFL); \
 564         flags |= O_NONBLOCK;            \
 565         fcntl(fd, F_SETFL, flags);      \
 566 }
 567 
 568 #ifdef AF_INET6
 569 static jboolean
 570 ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout,
 571       struct sockaddr_in6* netif, jint ttl) {
 572     jint size;
 573     jint n;
 574     socklen_t len;
 575     char sendbuf[1500];
 576     unsigned char recvbuf[1500];
 577     struct icmp6_hdr *icmp6;
 578     struct sockaddr_in6 sa_recv;
 579     jbyte *caddr, *recv_caddr;
 580     jchar pid;
 581     jint tmout2, seq = 1;
 582     struct timeval tv;
 583     size_t plen;
 584 
 585 #ifdef __linux__
 586     {
 587     int csum_offset;
 588     /**
 589      * For some strange reason, the linux kernel won't calculate the
 590      * checksum of ICMPv6 packets unless you set this socket option
 591      */
 592     csum_offset = 2;
 593     setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int));
 594     }
 595 #endif
 596 
 597     caddr = (jbyte *)&(him->sin6_addr);
 598 
 599     /* icmp_id is a 16 bit data type, therefore down cast the pid */
 600     pid = (jchar)getpid();
 601     size = 60*1024;
 602     setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
 603     if (ttl > 0) {
 604       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
 605     }
 606     if (netif != NULL) {
 607       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
 608         NET_ThrowNew(env, errno, "Can't bind socket");
 609         close(fd);
 610         return JNI_FALSE;
 611       }
 612     }
 613     SET_NONBLOCKING(fd);
 614 
 615     do {
 616       icmp6 = (struct icmp6_hdr *) sendbuf;
 617       icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
 618       icmp6->icmp6_code = 0;
 619       /* let's tag the ECHO packet with our pid so we can identify it */
 620       icmp6->icmp6_id = htons(pid);
 621       icmp6->icmp6_seq = htons(seq);
 622       seq++;
 623       icmp6->icmp6_cksum = 0;
 624       gettimeofday(&tv, NULL);
 625       memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv));
 626       plen = sizeof(struct icmp6_hdr) + sizeof(tv);
 627       n = sendto(fd, sendbuf, plen, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6));
 628       if (n < 0 && errno != EINPROGRESS) {
 629 #ifdef __linux__
 630         if (errno != EINVAL && errno != EHOSTUNREACH)
 631           /*
 632            * On some Linux versions, when a socket is  bound to the
 633            * loopback interface, sendto will fail and errno will be
 634            * set to EINVAL or EHOSTUNREACH.
 635            * When that happens, don't throw an exception, just return false.
 636            */
 637 #endif /*__linux__ */
 638         NET_ThrowNew(env, errno, "Can't send ICMP packet");
 639         close(fd);
 640         return JNI_FALSE;
 641       }
 642 
 643       tmout2 = timeout > 1000 ? 1000 : timeout;
 644       do {
 645         tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
 646 
 647         if (tmout2 >= 0) {
 648           len = sizeof(sa_recv);
 649           n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_recv, &len);
 650           icmp6 = (struct icmp6_hdr *) (recvbuf);
 651           recv_caddr = (jbyte *)&(sa_recv.sin6_addr);
 652           /*
 653            * We did receive something, but is it what we were expecting?
 654            * I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and
 655            *       from the host that we are trying to determine is reachable.
 656            */
 657           if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
 658               (ntohs(icmp6->icmp6_id) == pid)) {
 659             if (NET_IsEqual(caddr, recv_caddr)) {
 660               close(fd);
 661               return JNI_TRUE;
 662             }
 663             if (NET_IsZeroAddr(caddr)) {
 664               close(fd);
 665               return JNI_TRUE;
 666             }
 667           }
 668         }
 669       } while (tmout2 > 0);
 670       timeout -= 1000;
 671     } while (timeout > 0);
 672     close(fd);
 673     return JNI_FALSE;
 674 }
 675 #endif /* AF_INET6 */
 676 
 677 /*
 678  * Class:     java_net_Inet6AddressImpl
 679  * Method:    isReachable0
 680  * Signature: ([bII[bI)Z
 681  */
 682 JNIEXPORT jboolean JNICALL
 683 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
 684                                            jbyteArray addrArray,
 685                                            jint scope,
 686                                            jint timeout,
 687                                            jbyteArray ifArray,
 688                                            jint ttl, jint if_scope) {
 689 #ifdef AF_INET6
 690     jbyte caddr[16];
 691     jint fd, sz;
 692     struct sockaddr_in6 him6;
 693     struct sockaddr_in6 inf6;
 694     struct sockaddr_in6* netif = NULL;
 695     int len = 0;
 696     int connect_rv = -1;
 697 
 698     /*
 699      * If IPv6 is not enable, then we can't reach an IPv6 address, can we?
 700      */
 701     if (!ipv6_available()) {
 702       return JNI_FALSE;
 703     }
 704     /*
 705      * If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
 706      * therefore, let's delegate to the Inet4Address method.
 707      */
 708     sz = (*env)->GetArrayLength(env, addrArray);
 709     if (sz == 4) {
 710       return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
 711                                                          addrArray,
 712                                                          timeout,
 713                                                          ifArray, ttl);
 714     }
 715 
 716     memset((void *) caddr, 0, 16);
 717     memset((void *) &him6, 0, sizeof(him6));
 718     (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
 719     memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
 720     him6.sin6_family = AF_INET6;
 721 #ifdef __linux__
 722     if (scope > 0)
 723       him6.sin6_scope_id = scope;
 724     else
 725       him6.sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr));
 726     len = sizeof(struct sockaddr_in6);
 727 #else
 728     if (scope > 0)
 729       him6.sin6_scope_id = scope;
 730     len = sizeof(struct sockaddr_in6);
 731 #endif
 732     /*
 733      * If a network interface was specified, let's create the address
 734      * for it.
 735      */
 736     if (!(IS_NULL(ifArray))) {
 737       memset((void *) caddr, 0, 16);
 738       memset((void *) &inf6, 0, sizeof(inf6));
 739       (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
 740       memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
 741       inf6.sin6_family = AF_INET6;
 742       inf6.sin6_scope_id = if_scope;
 743       netif = &inf6;
 744     }
 745     /*
 746      * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST
 747      * otherwise we'll try a tcp socket to the Echo port (7).
 748      * Note that this is empiric, and not connecting could mean it's blocked
 749      * or the echo service has been disabled.
 750      */
 751 
 752     fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 753 
 754     if (fd != -1) { /* Good to go, let's do a ping */
 755         return ping6(env, fd, &him6, timeout, netif, ttl);
 756     }
 757 
 758     /* No good, let's fall back on TCP */
 759     fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0);
 760     if (fd == JVM_IO_ERR) {
 761         /* note: if you run out of fds, you may not be able to load
 762          * the exception class, and get a NoClassDefFoundError
 763          * instead.
 764          */
 765         NET_ThrowNew(env, errno, "Can't create socket");
 766         return JNI_FALSE;
 767     }
 768     if (ttl > 0) {
 769       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
 770     }
 771 
 772     /*
 773      * A network interface was specified, so let's bind to it.
 774      */
 775     if (netif != NULL) {
 776       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
 777         NET_ThrowNew(env, errno, "Can't bind socket");
 778         close(fd);
 779         return JNI_FALSE;
 780       }
 781     }
 782     SET_NONBLOCKING(fd);
 783 
 784     /* no need to use NET_Connect as non-blocking */
 785     him6.sin6_port = htons((short) 7); /* Echo port */
 786     connect_rv = JVM_Connect(fd, (struct sockaddr *)&him6, len);
 787 
 788     /**
 789      * connection established or refused immediately, either way it means
 790      * we were able to reach the host!
 791      */
 792     if (connect_rv == 0 || errno == ECONNREFUSED) {
 793         close(fd);
 794         return JNI_TRUE;
 795     } else {
 796         int optlen;
 797 
 798         switch (errno) {
 799         case ENETUNREACH: /* Network Unreachable */
 800         case EAFNOSUPPORT: /* Address Family not supported */
 801         case EADDRNOTAVAIL: /* address is not available on  the  remote machine */
 802 #ifdef __linux__
 803         case EINVAL:
 804         case EHOSTUNREACH:
 805           /*
 806            * On some Linux versions, when  a socket is bound to the
 807            * loopback interface, connect will fail and errno will
 808            * be set to EINVAL or EHOSTUNREACH.  When that happens,
 809            * don't throw an exception, just return false.
 810            */
 811 #endif /* __linux__ */
 812           close(fd);
 813           return JNI_FALSE;
 814         }
 815 
 816         if (errno != EINPROGRESS) {
 817             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 818                                          "connect failed");
 819             close(fd);
 820             return JNI_FALSE;
 821         }
 822 
 823         timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
 824 
 825         if (timeout >= 0) {
 826           /* has connection been established */
 827           optlen = sizeof(connect_rv);
 828           if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
 829                              &optlen) <0) {
 830             connect_rv = errno;
 831           }
 832           if (connect_rv == 0 || ECONNREFUSED) {
 833             close(fd);
 834             return JNI_TRUE;
 835           }
 836         }
 837         close(fd);
 838         return JNI_FALSE;
 839     }
 840 #else /* AF_INET6 */
 841     return JNI_FALSE;
 842 #endif /* AF_INET6 */
 843 }