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