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