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