1 /*
   2  * Copyright (c) 2000, 2009, 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, 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.  Note that 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                             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             ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
 214             JNU_ReleaseStringPlatformChars(env, host, hostname);
 215             return NULL;
 216         } else {
 217             int i = 0;
 218             int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
 219             struct addrinfo *itr, *last = NULL, *iterator = res;
 220             while (iterator != NULL) {
 221                 int skip = 0;
 222                 itr = resNew;
 223                 while (itr != NULL) {
 224                     if (iterator->ai_family == itr->ai_family &&
 225                         iterator->ai_addrlen == itr->ai_addrlen) {
 226                         if (itr->ai_family == AF_INET) { /* AF_INET */
 227                             struct sockaddr_in *addr1, *addr2;
 228                             addr1 = (struct sockaddr_in *)iterator->ai_addr;
 229                             addr2 = (struct sockaddr_in *)itr->ai_addr;
 230                             if (addr1->sin_addr.s_addr ==
 231                                 addr2->sin_addr.s_addr) {
 232                                 skip = 1;
 233                                 break;
 234                             }
 235                         } else {
 236                             int t;
 237                             struct sockaddr_in6 *addr1, *addr2;
 238                             addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
 239                             addr2 = (struct sockaddr_in6 *)itr->ai_addr;
 240 
 241                             for (t = 0; t < 16; t++) {
 242                                 if (addr1->sin6_addr.s6_addr[t] !=
 243                                     addr2->sin6_addr.s6_addr[t]) {
 244                                     break;
 245                                 }
 246                             }
 247                             if (t < 16) {
 248                                 itr = itr->ai_next;
 249                                 continue;
 250                             } else {
 251                                 skip = 1;
 252                                 break;
 253                             }
 254                         }
 255                     } else if (iterator->ai_family != AF_INET &&
 256                                iterator->ai_family != AF_INET6) {
 257                         /* we can't handle other family types */
 258                         skip = 1;
 259                         break;
 260                     }
 261                     itr = itr->ai_next;
 262                 }
 263 
 264                 if (!skip) {
 265                     struct addrinfo *next
 266                         = (struct addrinfo*) malloc(sizeof(struct addrinfo));
 267                     if (!next) {
 268                         JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
 269                         ret = NULL;
 270                         goto cleanupAndReturn;
 271                     }
 272                     memcpy(next, iterator, sizeof(struct addrinfo));
 273                     next->ai_next = NULL;
 274                     if (resNew == NULL) {
 275                         resNew = next;
 276                     } else {
 277                         last->ai_next = next;
 278                     }
 279                     last = next;
 280                     i++;
 281                     if (iterator->ai_family == AF_INET) {
 282                         inetCount ++;
 283                     } else if (iterator->ai_family == AF_INET6) {
 284                         inet6Count ++;
 285                     }
 286                 }
 287                 iterator = iterator->ai_next;
 288             }
 289             retLen = i;
 290             iterator = resNew;
 291 
 292             ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
 293 
 294             if (IS_NULL(ret)) {
 295                 /* we may have memory to free at the end of this */
 296                 goto cleanupAndReturn;
 297             }
 298 
 299             if (preferIPv6Address) {
 300                 /* AF_INET addresses will be offset by inet6Count */
 301                 inetIndex = inet6Count;
 302                 inet6Index = 0;
 303             } else {
 304                 /* AF_INET6 addresses will be offset by inetCount */
 305                 inetIndex = 0;
 306                 inet6Index = inetCount;
 307             }
 308 
 309             while (iterator != NULL) {
 310               if (iterator->ai_family == AF_INET) {
 311                 jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
 312                 if (IS_NULL(iaObj)) {
 313                   ret = NULL;
 314                   goto cleanupAndReturn;
 315                 }
 316                 (*env)->SetIntField(env, iaObj, ni_iaaddressID,
 317                                     ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
 318                 (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
 319                 (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
 320                 inetIndex++;
 321               } else if (iterator->ai_family == AF_INET6) {
 322                 jint scope = 0;
 323                 jbyteArray ipaddress;
 324 
 325                 jobject iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
 326                 if (IS_NULL(iaObj)) {
 327                   ret = NULL;
 328                   goto cleanupAndReturn;
 329                 }
 330                 ipaddress = (*env)->NewByteArray(env, 16);
 331                 if (IS_NULL(ipaddress)) {
 332                   ret = NULL;
 333                   goto cleanupAndReturn;
 334                 }
 335                 (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
 336                                            (jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
 337 #ifdef __linux__
 338                 if (!kernelIsV22()) {
 339                   scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
 340                 }
 341 #else
 342                 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
 343 #endif
 344                 if (scope != 0) { /* zero is default value, no need to set */
 345                   (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
 346                   (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
 347                 }
 348                 (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
 349                 (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
 350                 (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
 351                 inet6Index++;
 352               }
 353               iterator = iterator->ai_next;
 354             }
 355         }
 356     }
 357 
 358 cleanupAndReturn:
 359     {
 360         struct addrinfo *iterator, *tmp;
 361         iterator = resNew;
 362         while (iterator != NULL) {
 363             tmp = iterator;
 364             iterator = iterator->ai_next;
 365             free(tmp);
 366         }
 367         JNU_ReleaseStringPlatformChars(env, host, hostname);
 368     }
 369 
 370     if (NET_addrtransAvailable())
 371         (*freeaddrinfo_ptr)(res);
 372 #endif /* AF_INET6 */
 373 
 374     return ret;
 375 }
 376 
 377 /*
 378  * Class:     java_net_Inet6AddressImpl
 379  * Method:    getHostByAddr
 380  * Signature: (I)Ljava/lang/String;
 381  */
 382 JNIEXPORT jstring JNICALL
 383 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
 384                                             jbyteArray addrArray) {
 385 
 386     jstring ret = NULL;
 387 
 388 #ifdef AF_INET6
 389     char host[NI_MAXHOST+1];
 390     int error = 0;
 391     int len = 0;
 392     jbyte caddr[16];
 393 
 394     if (NET_addrtransAvailable()) {
 395         struct sockaddr_in him4;
 396         struct sockaddr_in6 him6;
 397         struct sockaddr *sa;
 398 
 399         /*
 400          * For IPv4 addresses construct a sockaddr_in structure.
 401          */
 402         if ((*env)->GetArrayLength(env, addrArray) == 4) {
 403             jint addr;
 404             (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 405             addr = ((caddr[0]<<24) & 0xff000000);
 406             addr |= ((caddr[1] <<16) & 0xff0000);
 407             addr |= ((caddr[2] <<8) & 0xff00);
 408             addr |= (caddr[3] & 0xff);
 409             memset((void *) &him4, 0, sizeof(him4));
 410             him4.sin_addr.s_addr = (uint32_t) htonl(addr);
 411             him4.sin_family = AF_INET;
 412             sa = (struct sockaddr *) &him4;
 413             len = sizeof(him4);
 414         } else {
 415             /*
 416              * For IPv6 address construct a sockaddr_in6 structure.
 417              */
 418             (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
 419             memset((void *) &him6, 0, sizeof(him6));
 420             memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
 421             him6.sin6_family = AF_INET6;
 422             sa = (struct sockaddr *) &him6 ;
 423             len = sizeof(him6) ;
 424         }
 425 
 426         error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0,
 427                                    NI_NAMEREQD);
 428 
 429         if (!error) {
 430             ret = (*env)->NewStringUTF(env, host);
 431         }
 432     }
 433 #endif /* AF_INET6 */
 434 
 435     if (ret == NULL) {
 436         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
 437     }
 438 
 439     return ret;
 440 }
 441 
 442 #define SET_NONBLOCKING(fd) {           \
 443         int flags = fcntl(fd, F_GETFL); \
 444         flags |= O_NONBLOCK;            \
 445         fcntl(fd, F_SETFL, flags);      \
 446 }
 447 
 448 #ifdef AF_INET6
 449 static jboolean
 450 ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout,
 451       struct sockaddr_in6* netif, jint ttl) {
 452     jint size;
 453     jint n;
 454     socklen_t len;
 455     char sendbuf[1500];
 456     unsigned char recvbuf[1500];
 457     struct icmp6_hdr *icmp6;
 458     struct sockaddr_in6 sa_recv;
 459     jbyte *caddr, *recv_caddr;
 460     jchar pid;
 461     jint tmout2, seq = 1;
 462     struct timeval tv;
 463     size_t plen;
 464 
 465 #ifdef __linux__
 466     {
 467     int csum_offset;
 468     /**
 469      * For some strange reason, the linux kernel won't calculate the
 470      * checksum of ICMPv6 packets unless you set this socket option
 471      */
 472     csum_offset = 2;
 473     setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int));
 474     }
 475 #endif
 476 
 477     caddr = (jbyte *)&(him->sin6_addr);
 478 
 479     /* icmp_id is a 16 bit data type, therefore down cast the pid */
 480     pid = (jchar)getpid();
 481     size = 60*1024;
 482     setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
 483     if (ttl > 0) {
 484       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
 485     }
 486     if (netif != NULL) {
 487       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
 488         NET_ThrowNew(env, errno, "Can't bind socket");
 489         close(fd);
 490         return JNI_FALSE;
 491       }
 492     }
 493     SET_NONBLOCKING(fd);
 494 
 495     do {
 496       icmp6 = (struct icmp6_hdr *) sendbuf;
 497       icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
 498       icmp6->icmp6_code = 0;
 499       /* let's tag the ECHO packet with our pid so we can identify it */
 500       icmp6->icmp6_id = htons(pid);
 501       icmp6->icmp6_seq = htons(seq);
 502       seq++;
 503       icmp6->icmp6_cksum = 0;
 504       gettimeofday(&tv, NULL);
 505       memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv));
 506       plen = sizeof(struct icmp6_hdr) + sizeof(tv);
 507       n = sendto(fd, sendbuf, plen, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6));
 508       if (n < 0 && errno != EINPROGRESS) {
 509 #ifdef __linux__
 510         if (errno != EINVAL)
 511           /*
 512            * On some Linuxes, when bound to the loopback interface, sendto
 513            * will fail and errno will be set to EINVAL. When that happens,
 514            * don't throw an exception, just return false.
 515            */
 516 #endif /*__linux__ */
 517         NET_ThrowNew(env, errno, "Can't send ICMP packet");
 518         close(fd);
 519         return JNI_FALSE;
 520       }
 521 
 522       tmout2 = timeout > 1000 ? 1000 : timeout;
 523       do {
 524         tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
 525 
 526         if (tmout2 >= 0) {
 527           len = sizeof(sa_recv);
 528           n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_recv, &len);
 529           icmp6 = (struct icmp6_hdr *) (recvbuf);
 530           recv_caddr = (jbyte *)&(sa_recv.sin6_addr);
 531           /*
 532            * We did receive something, but is it what we were expecting?
 533            * I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and
 534            *       from the host that we are trying to determine is reachable.
 535            */
 536           if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
 537               (ntohs(icmp6->icmp6_id) == pid) &&
 538               NET_IsEqual(caddr, recv_caddr)) {
 539             close(fd);
 540             return JNI_TRUE;
 541           }
 542         }
 543       } while (tmout2 > 0);
 544       timeout -= 1000;
 545     } while (timeout > 0);
 546     close(fd);
 547     return JNI_FALSE;
 548 }
 549 #endif /* AF_INET6 */
 550 
 551 /*
 552  * Class:     java_net_Inet6AddressImpl
 553  * Method:    isReachable0
 554  * Signature: ([bII[bI)Z
 555  */
 556 JNIEXPORT jboolean JNICALL
 557 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
 558                                            jbyteArray addrArray,
 559                                            jint scope,
 560                                            jint timeout,
 561                                            jbyteArray ifArray,
 562                                            jint ttl, jint if_scope) {
 563 #ifdef AF_INET6
 564     jbyte caddr[16];
 565     jint fd, sz;
 566     struct sockaddr_in6 him6;
 567     struct sockaddr_in6 inf6;
 568     struct sockaddr_in6* netif = NULL;
 569     int len = 0;
 570     int connect_rv = -1;
 571 
 572     /*
 573      * If IPv6 is not enable, then we can't reach an IPv6 address, can we?
 574      */
 575     if (!ipv6_available()) {
 576       return JNI_FALSE;
 577     }
 578     /*
 579      * If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
 580      * therefore, let's delegate to the Inet4Address method.
 581      */
 582     sz = (*env)->GetArrayLength(env, addrArray);
 583     if (sz == 4) {
 584       return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
 585                                                          addrArray,
 586                                                          timeout,
 587                                                          ifArray, ttl);
 588     }
 589 
 590     memset((void *) caddr, 0, 16);
 591     memset((void *) &him6, 0, sizeof(him6));
 592     (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
 593     memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
 594     him6.sin6_family = AF_INET6;
 595 #ifdef __linux__
 596     if (scope > 0)
 597       him6.sin6_scope_id = scope;
 598     else
 599       him6.sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr));
 600     len = sizeof(struct sockaddr_in6);
 601 #else
 602     if (scope > 0)
 603       him6.sin6_scope_id = scope;
 604     len = sizeof(struct sockaddr_in6);
 605 #endif
 606     /*
 607      * If a network interface was specified, let's create the address
 608      * for it.
 609      */
 610     if (!(IS_NULL(ifArray))) {
 611       memset((void *) caddr, 0, 16);
 612       memset((void *) &inf6, 0, sizeof(inf6));
 613       (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
 614       memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
 615       inf6.sin6_family = AF_INET6;
 616       inf6.sin6_scope_id = if_scope;
 617       netif = &inf6;
 618     }
 619     /*
 620      * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST
 621      * otherwise we'll try a tcp socket to the Echo port (7).
 622      * Note that this is empiric, and not connecting could mean it's blocked
 623      * or the echo servioe has been disabled.
 624      */
 625 
 626     fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 627 
 628     if (fd != -1) { /* Good to go, let's do a ping */
 629         return ping6(env, fd, &him6, timeout, netif, ttl);
 630     }
 631 
 632     /* No good, let's fall back on TCP */
 633     fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0);
 634     if (fd == JVM_IO_ERR) {
 635         /* note: if you run out of fds, you may not be able to load
 636          * the exception class, and get a NoClassDefFoundError
 637          * instead.
 638          */
 639         NET_ThrowNew(env, errno, "Can't create socket");
 640         return JNI_FALSE;
 641     }
 642     if (ttl > 0) {
 643       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
 644     }
 645 
 646     /*
 647      * A network interface was specified, so let's bind to it.
 648      */
 649     if (netif != NULL) {
 650       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
 651         NET_ThrowNew(env, errno, "Can't bind socket");
 652         close(fd);
 653         return JNI_FALSE;
 654       }
 655     }
 656     SET_NONBLOCKING(fd);
 657 
 658     /* no need to use NET_Connect as non-blocking */
 659     him6.sin6_port = htons((short) 7); /* Echo port */
 660     connect_rv = JVM_Connect(fd, (struct sockaddr *)&him6, len);
 661 
 662     /**
 663      * connection established or refused immediately, either way it means
 664      * we were able to reach the host!
 665      */
 666     if (connect_rv == 0 || errno == ECONNREFUSED) {
 667         close(fd);
 668         return JNI_TRUE;
 669     } else {
 670         int optlen;
 671 
 672         switch (errno) {
 673         case ENETUNREACH: /* Network Unreachable */
 674         case EAFNOSUPPORT: /* Address Family not supported */
 675         case EADDRNOTAVAIL: /* address is not available on  the  remote machine */
 676 #ifdef __linux__
 677         case EINVAL:
 678           /*
 679            * On some Linuxes, when bound to the loopback interface, connect
 680            * will fail and errno will be set to EINVAL. When that happens,
 681            * don't throw an exception, just return false.
 682            */
 683 #endif /* __linux__ */
 684           close(fd);
 685           return JNI_FALSE;
 686         }
 687 
 688         if (errno != EINPROGRESS) {
 689             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 690                                          "connect failed");
 691             close(fd);
 692             return JNI_FALSE;
 693         }
 694 
 695         timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
 696 
 697         if (timeout >= 0) {
 698           /* has connection been established */
 699           optlen = sizeof(connect_rv);
 700           if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
 701                              &optlen) <0) {
 702             connect_rv = errno;
 703           }
 704           if (connect_rv == 0 || ECONNREFUSED) {
 705             close(fd);
 706             return JNI_TRUE;
 707           }
 708         }
 709         close(fd);
 710         return JNI_FALSE;
 711     }
 712 #else /* AF_INET6 */
 713     return JNI_FALSE;
 714 #endif /* AF_INET6 */
 715 }
--- EOF ---