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 /*
 116  * Find an internet address for a given hostname.  Not this this
 117  * code only works for addresses of type INET. The translation
 118  * of %d.%d.%d.%d to an address (int) occurs in java now, so the
 119  * String "host" shouldn't *ever* be a %d.%d.%d.%d string
 120  *
 121  * Class:     java_net_Inet6AddressImpl
 122  * Method:    lookupAllHostAddr
 123  * Signature: (Ljava/lang/String;)[[B
 124  */
 125 
 126 JNIEXPORT jobjectArray JNICALL
 127 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
 128                                                 jstring host) {
 129     const char *hostname;
 130     jobjectArray ret = 0;
 131     int retLen = 0;
 132     jboolean preferIPv6Address;
 133 
 134     int error=0;
 135 #ifdef AF_INET6
 136     struct addrinfo hints, *res, *resNew = NULL;
 137 #endif /* AF_INET6 */
 138 
 139     init(env);














 140 
 141     if (IS_NULL(host)) {
 142         JNU_ThrowNullPointerException(env, "host is null");
 143         return 0;
 144     }
 145     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
 146     CHECK_NULL_RETURN(hostname, NULL);
 147 
 148 #ifdef AF_INET6
 149     if (NET_addrtransAvailable()) {












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