1 /*
   2  * Copyright (c) 2000, 2011, 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 
  37 #include "jvm.h"
  38 #include "jni_util.h"
  39 #include "net_util.h"
  40 #ifndef IPV6_DEFS_H
  41 #include <netinet/icmp6.h>
  42 #endif
  43 
  44 #include "java_net_Inet4AddressImpl.h"
  45 #include "java_net_Inet6AddressImpl.h"
  46 
  47 /* the initial size of our hostent buffers */
  48 #ifndef NI_MAXHOST
  49 #define NI_MAXHOST 1025
  50 #endif
  51 
  52 
  53 /************************************************************************
  54  * Inet6AddressImpl
  55  */
  56 
  57 /*
  58  * Class:     java_net_Inet6AddressImpl
  59  * Method:    getLocalHostName
  60  * Signature: ()Ljava/lang/String;
  61  */
  62 JNIEXPORT jstring JNICALL
  63 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
  64     char hostname[NI_MAXHOST+1];
  65 
  66     hostname[0] = '\0';
  67     if (JVM_GetHostName(hostname, sizeof(hostname))) {
  68         /* Something went wrong, maybe networking is not setup? */
  69         strcpy(hostname, "localhost");
  70     } else {
  71         // ensure null-terminated
  72         hostname[NI_MAXHOST] = '\0';
  73 #ifdef __linux__
  74         /* On Linux gethostname() says "host.domain.sun.com".  On
  75          * Solaris gethostname() says "host", so extra work is needed.
  76          */
  77 #else
  78         /* Solaris doesn't want to give us a fully qualified domain name.
  79          * We do a reverse lookup to try and get one.  This works
  80          * if DNS occurs before NIS in /etc/resolv.conf, but fails
  81          * if NIS comes first (it still gets only a partial name).
  82          * We use thread-safe system calls.
  83          */
  84 #ifdef AF_INET6
  85         if (NET_addrtransAvailable()) {
  86             struct addrinfo  hints, *res;
  87             int error;
  88 
  89             bzero(&hints, sizeof(hints));
  90             hints.ai_flags = AI_CANONNAME;
  91             hints.ai_family = AF_UNSPEC;
  92 
  93             error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
  94 
  95             if (error == 0) {
  96                 /* host is known to name service */
  97                 error = (*getnameinfo_ptr)(res->ai_addr,
  98                                            res->ai_addrlen,
  99                                            hostname,
 100                                            NI_MAXHOST,
 101                                            NULL,
 102                                            0,
 103                                            NI_NAMEREQD);
 104 
 105                 /* if getnameinfo fails hostname is still the value
 106                    from gethostname */
 107 
 108                 (*freeaddrinfo_ptr)(res);
 109             }
 110         }
 111 #endif /* AF_INET6 */
 112 #endif /* __linux__ */
 113     }
 114     return (*env)->NewStringUTF(env, hostname);
 115 }
 116 
 117 static jclass ni_iacls;
 118 static jclass ni_ia4cls;
 119 static jclass ni_ia6cls;
 120 static jmethodID ni_ia4ctrID;
 121 static jmethodID ni_ia6ctrID;
 122 static jfieldID ni_iaaddressID;
 123 static jfieldID ni_iahostID;
 124 static jfieldID ni_iafamilyID;
 125 static jfieldID ni_ia6ipaddressID;
 126 static int initialized = 0;
 127 
 128 /*
 129  * Find an internet address for a given hostname.  Note that this
 130  * code only works for addresses of type INET. The translation
 131  * of %d.%d.%d.%d to an address (int) occurs in java now, so the
 132  * String "host" shouldn't *ever* be a %d.%d.%d.%d string
 133  *
 134  * Class:     java_net_Inet6AddressImpl
 135  * Method:    lookupAllHostAddr
 136  * Signature: (Ljava/lang/String;)[[B
 137  */
 138 
 139 JNIEXPORT jobjectArray JNICALL
 140 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
 141                                                 jstring host) {
 142     const char *hostname;
 143     jobjectArray ret = 0;
 144     int retLen = 0;
 145     jboolean preferIPv6Address;
 146 
 147     int error=0;
 148 #ifdef AF_INET6
 149     struct addrinfo hints, *res, *resNew = NULL;
 150 #endif /* AF_INET6 */
 151 
 152     if (!initialized) {
 153       ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
 154       ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
 155       ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
 156       ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
 157       ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
 158       ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
 159       ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
 160       ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
 161       ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I");
 162       ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I");
 163       ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;");
 164       ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
 165       initialized = 1;
 166     }
 167 
 168     if (IS_NULL(host)) {
 169         JNU_ThrowNullPointerException(env, "host is null");
 170         return 0;
 171     }
 172     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
 173     CHECK_NULL_RETURN(hostname, NULL);
 174 
 175 #ifdef AF_INET6
 176     if (NET_addrtransAvailable()) {
 177         static jfieldID ia_preferIPv6AddressID;
 178         if (ia_preferIPv6AddressID == NULL) {
 179             jclass c = (*env)->FindClass(env,"java/net/InetAddress");
 180             if (c)  {
 181                 ia_preferIPv6AddressID =
 182                     (*env)->GetStaticFieldID(env, c, "preferIPv6Address", "Z");
 183             }
 184             if (ia_preferIPv6AddressID == NULL) {
 185                 JNU_ReleaseStringPlatformChars(env, host, hostname);
 186                 return NULL;
 187             }
 188         }
 189         /* get the address preference */
 190         preferIPv6Address
 191             = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
 192 
 193         /* Try once, with our static buffer. */
 194         bzero(&hints, sizeof(hints));
 195         hints.ai_flags = AI_CANONNAME;
 196         hints.ai_family = AF_UNSPEC;
 197 
 198 #ifdef __solaris__
 199         /*
 200          * Workaround for Solaris bug 4160367 - if a hostname contains a
 201          * white space then 0.0.0.0 is returned
 202          */
 203         if (isspace((unsigned char)hostname[0])) {
 204             JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
 205                             hostname);
 206             JNU_ReleaseStringPlatformChars(env, host, hostname);
 207             return NULL;
 208         }
 209 #endif
 210 
 211         error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
 212 
 213         if (error) {
 214             /* report error */
 215             ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
 216             JNU_ReleaseStringPlatformChars(env, host, hostname);
 217             return NULL;
 218         } else {
 219             int i = 0;
 220             int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
 221             struct addrinfo *itr, *last = NULL, *iterator = res;
 222             while (iterator != NULL) {
 223                 int skip = 0;
 224                 itr = resNew;
 225                 while (itr != NULL) {
 226                     if (iterator->ai_family == itr->ai_family &&
 227                         iterator->ai_addrlen == itr->ai_addrlen) {
 228                         if (itr->ai_family == AF_INET) { /* AF_INET */
 229                             struct sockaddr_in *addr1, *addr2;
 230                             addr1 = (struct sockaddr_in *)iterator->ai_addr;
 231                             addr2 = (struct sockaddr_in *)itr->ai_addr;
 232                             if (addr1->sin_addr.s_addr ==
 233                                 addr2->sin_addr.s_addr) {
 234                                 skip = 1;
 235                                 break;
 236                             }
 237                         } else {
 238                             int t;
 239                             struct sockaddr_in6 *addr1, *addr2;
 240                             addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
 241                             addr2 = (struct sockaddr_in6 *)itr->ai_addr;
 242 
 243                             for (t = 0; t < 16; t++) {
 244                                 if (addr1->sin6_addr.s6_addr[t] !=
 245                                     addr2->sin6_addr.s6_addr[t]) {
 246                                     break;
 247                                 }
 248                             }
 249                             if (t < 16) {
 250                                 itr = itr->ai_next;
 251                                 continue;
 252                             } else {
 253                                 skip = 1;
 254                                 break;
 255                             }
 256                         }
 257                     } else if (iterator->ai_family != AF_INET &&
 258                                iterator->ai_family != AF_INET6) {
 259                         /* we can't handle other family types */
 260                         skip = 1;
 261                         break;
 262                     }
 263                     itr = itr->ai_next;
 264                 }
 265 
 266                 if (!skip) {
 267                     struct addrinfo *next
 268                         = (struct addrinfo*) malloc(sizeof(struct addrinfo));
 269                     if (!next) {
 270                         JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
 271                         ret = NULL;
 272                         goto cleanupAndReturn;
 273                     }
 274                     memcpy(next, iterator, sizeof(struct addrinfo));
 275                     next->ai_next = NULL;
 276                     if (resNew == NULL) {
 277                         resNew = next;
 278                     } else {
 279                         last->ai_next = next;
 280                     }
 281                     last = next;
 282                     i++;
 283                     if (iterator->ai_family == AF_INET) {
 284                         inetCount ++;
 285                     } else if (iterator->ai_family == AF_INET6) {
 286                         inet6Count ++;
 287                     }
 288                 }
 289                 iterator = iterator->ai_next;
 290             }
 291             retLen = i;
 292             iterator = resNew;
 293 
 294             ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
 295 
 296             if (IS_NULL(ret)) {
 297                 /* we may have memory to free at the end of this */
 298                 goto cleanupAndReturn;
 299             }
 300 
 301             if (preferIPv6Address) {
 302                 /* AF_INET addresses will be offset by inet6Count */
 303                 inetIndex = inet6Count;
 304                 inet6Index = 0;
 305             } else {
 306                 /* AF_INET6 addresses will be offset by inetCount */
 307                 inetIndex = 0;
 308                 inet6Index = inetCount;
 309             }
 310 
 311             while (iterator != NULL) {
 312               if (iterator->ai_family == AF_INET) {
 313                 jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
 314                 if (IS_NULL(iaObj)) {
 315                   ret = NULL;
 316                   goto cleanupAndReturn;
 317                 }
 318                 (*env)->SetIntField(env, iaObj, ni_iaaddressID,
 319                                     ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
 320                 (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
 321                 (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
 322                 inetIndex++;
 323               } else if (iterator->ai_family == AF_INET6) {
 324                 jint scope = 0;
 325                 jbyteArray ipaddress;
 326 
 327                 jobject iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
 328                 if (IS_NULL(iaObj)) {
 329                   ret = NULL;
 330                   goto cleanupAndReturn;
 331                 }
 332                 ipaddress = (*env)->NewByteArray(env, 16);
 333                 if (IS_NULL(ipaddress)) {
 334                   ret = NULL;
 335                   goto cleanupAndReturn;
 336                 }
 337                 (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
 338                                            (jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
 339 #ifdef __linux__
 340                 if (!kernelIsV22()) {
 341                   scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
 342                 }
 343 #else
 344                 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
 345 #endif
 346                 if (scope != 0) { /* zero is default value, no need to set */
 347                   (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
 348                   (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
 349                 }
 350                 (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
 351                 (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
 352                 (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
 353                 inet6Index++;
 354               }
 355               iterator = iterator->ai_next;
 356             }
 357         }
 358     }
 359 
 360 cleanupAndReturn:
 361     {
 362         struct addrinfo *iterator, *tmp;
 363         iterator = resNew;
 364         while (iterator != NULL) {
 365             tmp = iterator;
 366             iterator = iterator->ai_next;
 367             free(tmp);
 368         }
 369         JNU_ReleaseStringPlatformChars(env, host, hostname);
 370     }
 371 
 372     if (NET_addrtransAvailable())
 373         (*freeaddrinfo_ptr)(res);
 374 #endif /* AF_INET6 */
 375 
 376     return ret;
 377 }
 378 
 379 /*
 380  * Class:     java_net_Inet6AddressImpl
 381  * Method:    getHostByAddr
 382  * Signature: (I)Ljava/lang/String;
 383  */
 384 JNIEXPORT jstring JNICALL
 385 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
 386                                             jbyteArray addrArray) {
 387 
 388     jstring ret = NULL;
 389 
 390 #ifdef AF_INET6
 391     char host[NI_MAXHOST+1];
 392     int error = 0;
 393     int len = 0;
 394     jbyte caddr[16];
 395 
 396     if (NET_addrtransAvailable()) {
 397         struct sockaddr_in him4;
 398         struct sockaddr_in6 him6;
 399         struct sockaddr *sa;
 400 
 401         /*
 402          * For IPv4 addresses construct a sockaddr_in structure.
 403          */
 404         if ((*env)->GetArrayLength(env, addrArray) == 4) {
 405             jint addr;
 406             (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 407             addr = ((caddr[0]<<24) & 0xff000000);
 408             addr |= ((caddr[1] <<16) & 0xff0000);
 409             addr |= ((caddr[2] <<8) & 0xff00);
 410             addr |= (caddr[3] & 0xff);
 411             memset((void *) &him4, 0, sizeof(him4));
 412             him4.sin_addr.s_addr = (uint32_t) htonl(addr);
 413             him4.sin_family = AF_INET;
 414             sa = (struct sockaddr *) &him4;
 415             len = sizeof(him4);
 416         } else {
 417             /*
 418              * For IPv6 address construct a sockaddr_in6 structure.
 419              */
 420             (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
 421             memset((void *) &him6, 0, sizeof(him6));
 422             memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
 423             him6.sin6_family = AF_INET6;
 424             sa = (struct sockaddr *) &him6 ;
 425             len = sizeof(him6) ;
 426         }
 427 
 428         error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0,
 429                                    NI_NAMEREQD);
 430 
 431         if (!error) {
 432             ret = (*env)->NewStringUTF(env, host);
 433         }
 434     }
 435 #endif /* AF_INET6 */
 436 
 437     if (ret == NULL) {
 438         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
 439     }
 440 
 441     return ret;
 442 }
 443 
 444 #define SET_NONBLOCKING(fd) {           \
 445         int flags = fcntl(fd, F_GETFL); \
 446         flags |= O_NONBLOCK;            \
 447         fcntl(fd, F_SETFL, flags);      \
 448 }
 449 
 450 #ifdef AF_INET6
 451 static jboolean
 452 ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout,
 453       struct sockaddr_in6* netif, jint ttl) {
 454     jint size;
 455     jint n;
 456     socklen_t len;
 457     char sendbuf[1500];
 458     unsigned char recvbuf[1500];
 459     struct icmp6_hdr *icmp6;
 460     struct sockaddr_in6 sa_recv;
 461     jbyte *caddr, *recv_caddr;
 462     jchar pid;
 463     jint tmout2, seq = 1;
 464     struct timeval tv;
 465     size_t plen;
 466 
 467 #ifdef __linux__
 468     {
 469     int csum_offset;
 470     /**
 471      * For some strange reason, the linux kernel won't calculate the
 472      * checksum of ICMPv6 packets unless you set this socket option
 473      */
 474     csum_offset = 2;
 475     setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int));
 476     }
 477 #endif
 478 
 479     caddr = (jbyte *)&(him->sin6_addr);
 480 
 481     /* icmp_id is a 16 bit data type, therefore down cast the pid */
 482     pid = (jchar)getpid();
 483     size = 60*1024;
 484     setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
 485     if (ttl > 0) {
 486       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
 487     }
 488     if (netif != NULL) {
 489       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
 490         NET_ThrowNew(env, errno, "Can't bind socket");
 491         close(fd);
 492         return JNI_FALSE;
 493       }
 494     }
 495     SET_NONBLOCKING(fd);
 496 
 497     do {
 498       icmp6 = (struct icmp6_hdr *) sendbuf;
 499       icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
 500       icmp6->icmp6_code = 0;
 501       /* let's tag the ECHO packet with our pid so we can identify it */
 502       icmp6->icmp6_id = htons(pid);
 503       icmp6->icmp6_seq = htons(seq);
 504       seq++;
 505       icmp6->icmp6_cksum = 0;
 506       gettimeofday(&tv, NULL);
 507       memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv));
 508       plen = sizeof(struct icmp6_hdr) + sizeof(tv);
 509       n = sendto(fd, sendbuf, plen, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6));
 510       if (n < 0 && errno != EINPROGRESS) {
 511 #ifdef __linux__
 512         if (errno != EINVAL)
 513           /*
 514            * On some Linuxes, when bound to the loopback interface, sendto
 515            * will fail and errno will be set to EINVAL. When that happens,
 516            * don't throw an exception, just return false.
 517            */
 518 #endif /*__linux__ */
 519         NET_ThrowNew(env, errno, "Can't send ICMP packet");
 520         close(fd);
 521         return JNI_FALSE;
 522       }
 523 
 524       tmout2 = timeout > 1000 ? 1000 : timeout;
 525       do {
 526         tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
 527 
 528         if (tmout2 >= 0) {
 529           len = sizeof(sa_recv);
 530           n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_recv, &len);
 531           icmp6 = (struct icmp6_hdr *) (recvbuf);
 532           recv_caddr = (jbyte *)&(sa_recv.sin6_addr);
 533           /*
 534            * We did receive something, but is it what we were expecting?
 535            * I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and
 536            *       from the host that we are trying to determine is reachable.
 537            */
 538           if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
 539               (ntohs(icmp6->icmp6_id) == pid) &&
 540               NET_IsEqual(caddr, recv_caddr)) {
 541             close(fd);
 542             return JNI_TRUE;
 543           }
 544         }
 545       } while (tmout2 > 0);
 546       timeout -= 1000;
 547     } while (timeout > 0);
 548     close(fd);
 549     return JNI_FALSE;
 550 }
 551 #endif /* AF_INET6 */
 552 
 553 /*
 554  * Class:     java_net_Inet6AddressImpl
 555  * Method:    isReachable0
 556  * Signature: ([bII[bI)Z
 557  */
 558 JNIEXPORT jboolean JNICALL
 559 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
 560                                            jbyteArray addrArray,
 561                                            jint scope,
 562                                            jint timeout,
 563                                            jbyteArray ifArray,
 564                                            jint ttl, jint if_scope) {
 565 #ifdef AF_INET6
 566     jbyte caddr[16];
 567     jint fd, sz;
 568     struct sockaddr_in6 him6;
 569     struct sockaddr_in6 inf6;
 570     struct sockaddr_in6* netif = NULL;
 571     int len = 0;
 572     int connect_rv = -1;
 573 
 574     /*
 575      * If IPv6 is not enable, then we can't reach an IPv6 address, can we?
 576      */
 577     if (!ipv6_available()) {
 578       return JNI_FALSE;
 579     }
 580     /*
 581      * If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
 582      * therefore, let's delegate to the Inet4Address method.
 583      */
 584     sz = (*env)->GetArrayLength(env, addrArray);
 585     if (sz == 4) {
 586       return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
 587                                                          addrArray,
 588                                                          timeout,
 589                                                          ifArray, ttl);
 590     }
 591 
 592     memset((void *) caddr, 0, 16);
 593     memset((void *) &him6, 0, sizeof(him6));
 594     (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
 595     memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
 596     him6.sin6_family = AF_INET6;
 597 #ifdef __linux__
 598     if (scope > 0)
 599       him6.sin6_scope_id = scope;
 600     else
 601       him6.sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr));
 602     len = sizeof(struct sockaddr_in6);
 603 #else
 604     if (scope > 0)
 605       him6.sin6_scope_id = scope;
 606     len = sizeof(struct sockaddr_in6);
 607 #endif
 608     /*
 609      * If a network interface was specified, let's create the address
 610      * for it.
 611      */
 612     if (!(IS_NULL(ifArray))) {
 613       memset((void *) caddr, 0, 16);
 614       memset((void *) &inf6, 0, sizeof(inf6));
 615       (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
 616       memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
 617       inf6.sin6_family = AF_INET6;
 618       inf6.sin6_scope_id = if_scope;
 619       netif = &inf6;
 620     }
 621     /*
 622      * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST
 623      * otherwise we'll try a tcp socket to the Echo port (7).
 624      * Note that this is empiric, and not connecting could mean it's blocked
 625      * or the echo servioe has been disabled.
 626      */
 627 
 628     fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 629 
 630     if (fd != -1) { /* Good to go, let's do a ping */
 631         return ping6(env, fd, &him6, timeout, netif, ttl);
 632     }
 633 
 634     /* No good, let's fall back on TCP */
 635     fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0);
 636     if (fd == JVM_IO_ERR) {
 637         /* note: if you run out of fds, you may not be able to load
 638          * the exception class, and get a NoClassDefFoundError
 639          * instead.
 640          */
 641         NET_ThrowNew(env, errno, "Can't create socket");
 642         return JNI_FALSE;
 643     }
 644     if (ttl > 0) {
 645       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
 646     }
 647 
 648     /*
 649      * A network interface was specified, so let's bind to it.
 650      */
 651     if (netif != NULL) {
 652       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
 653         NET_ThrowNew(env, errno, "Can't bind socket");
 654         close(fd);
 655         return JNI_FALSE;
 656       }
 657     }
 658     SET_NONBLOCKING(fd);
 659 
 660     /* no need to use NET_Connect as non-blocking */
 661     him6.sin6_port = htons((short) 7); /* Echo port */
 662     connect_rv = JVM_Connect(fd, (struct sockaddr *)&him6, len);
 663 
 664     /**
 665      * connection established or refused immediately, either way it means
 666      * we were able to reach the host!
 667      */
 668     if (connect_rv == 0 || errno == ECONNREFUSED) {
 669         close(fd);
 670         return JNI_TRUE;
 671     } else {
 672         int optlen;
 673 
 674         switch (errno) {
 675         case ENETUNREACH: /* Network Unreachable */
 676         case EAFNOSUPPORT: /* Address Family not supported */
 677         case EADDRNOTAVAIL: /* address is not available on  the  remote machine */
 678 #ifdef __linux__
 679         case EINVAL:
 680           /*
 681            * On some Linuxes, when bound to the loopback interface, connect
 682            * will fail and errno will be set to EINVAL. When that happens,
 683            * don't throw an exception, just return false.
 684            */
 685 #endif /* __linux__ */
 686           close(fd);
 687           return JNI_FALSE;
 688         }
 689 
 690         if (errno != EINPROGRESS) {
 691             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 692                                          "connect failed");
 693             close(fd);
 694             return JNI_FALSE;
 695         }
 696 
 697         timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
 698 
 699         if (timeout >= 0) {
 700           /* has connection been established */
 701           optlen = sizeof(connect_rv);
 702           if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
 703                              &optlen) <0) {
 704             connect_rv = errno;
 705           }
 706           if (connect_rv == 0 || ECONNREFUSED) {
 707             close(fd);
 708             return JNI_TRUE;
 709           }
 710         }
 711         close(fd);
 712         return JNI_FALSE;
 713     }
 714 #else /* AF_INET6 */
 715     return JNI_FALSE;
 716 #endif /* AF_INET6 */
 717 }