1 /*
   2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <errno.h>
  27 #include <sys/time.h>
  28 #include <sys/types.h>
  29 #include <sys/socket.h>
  30 #include <netinet/in_systm.h>
  31 #include <netinet/in.h>
  32 #include <netinet/ip.h>
  33 #include <netinet/ip_icmp.h>
  34 #include <netdb.h>
  35 #include <string.h>
  36 #include <stdlib.h>
  37 #include <ctype.h>
  38 
  39 #ifdef _ALLBSD_SOURCE
  40 #include <unistd.h>
  41 #include <sys/param.h>
  42 #endif
  43 
  44 #include "jvm.h"
  45 #include "jni_util.h"
  46 #include "net_util.h"
  47 
  48 #include "java_net_Inet4AddressImpl.h"
  49 
  50 #if defined(__GLIBC__) || (defined(__FreeBSD__) && (__FreeBSD_version >= 601104))
  51 #define HAS_GLIBC_GETHOSTBY_R   1
  52 #endif
  53 
  54 
  55 #if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R)
  56 extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6);
  57 
  58 /* Use getaddrinfo(3), which is thread safe */
  59 /************************************************************************
  60  * Inet4AddressImpl
  61  */
  62 
  63 /*
  64  * Class:     java_net_Inet4AddressImpl
  65  * Method:    getLocalHostName
  66  * Signature: ()Ljava/lang/String;
  67  */
  68 JNIEXPORT jstring JNICALL
  69 Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
  70     char hostname[NI_MAXHOST+1];
  71 
  72     hostname[0] = '\0';
  73     if (gethostname(hostname, NI_MAXHOST)) {
  74         /* Something went wrong, maybe networking is not setup? */
  75         strcpy(hostname, "localhost");
  76     } else {
  77          struct addrinfo  hints, *res;
  78          int error;
  79 
  80          memset(&hints, 0, sizeof(hints));
  81          hints.ai_flags = AI_CANONNAME;
  82          hints.ai_family = AF_UNSPEC;
  83 
  84          error = getaddrinfo(hostname, NULL, &hints, &res);
  85 
  86          if (error == 0) {
  87              /* host is known to name service */
  88              error = getnameinfo(res->ai_addr,
  89                                  res->ai_addrlen,
  90                                  hostname,
  91                                  NI_MAXHOST,
  92                                  NULL,
  93                                  0,
  94                                  NI_NAMEREQD);
  95 
  96              /* if getnameinfo fails hostname is still the value
  97                 from gethostname */
  98 
  99              freeaddrinfo(res);
 100         }
 101     }
 102     return (*env)->NewStringUTF(env, hostname);
 103 }
 104 
 105 /*
 106  * Find an internet address for a given hostname.  Note that this
 107  * code only works for addresses of type INET. The translation
 108  * of %d.%d.%d.%d to an address (int) occurs in java now, so the
 109  * String "host" shouldn't *ever* be a %d.%d.%d.%d string
 110  *
 111  * Class:     java_net_Inet4AddressImpl
 112  * Method:    lookupAllHostAddr
 113  * Signature: (Ljava/lang/String;)[[B
 114  */
 115 
 116 JNIEXPORT jobjectArray JNICALL
 117 Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
 118                                                 jstring host) {
 119     const char *hostname;
 120     jobject name;
 121     jobjectArray ret = 0;
 122     int retLen = 0;
 123 
 124     int getaddrinfo_error=0;
 125     struct addrinfo hints, *res, *resNew = NULL;
 126 
 127     initInetAddressIDs(env);
 128     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 129 
 130     if (IS_NULL(host)) {
 131         JNU_ThrowNullPointerException(env, "host is null");
 132         return 0;
 133     }
 134     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
 135     CHECK_NULL_RETURN(hostname, NULL);
 136 
 137     memset(&hints, 0, sizeof(hints));
 138     hints.ai_flags = AI_CANONNAME;
 139     hints.ai_family = AF_INET;
 140 
 141     /*
 142      * Workaround for Solaris bug 4160367 - if a hostname contains a
 143      * white space then 0.0.0.0 is returned
 144      */
 145     if (isspace((unsigned char)hostname[0])) {
 146         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
 147                         (char *)hostname);
 148         JNU_ReleaseStringPlatformChars(env, host, hostname);
 149         return NULL;
 150     }
 151 
 152 
 153     getaddrinfo_error = getaddrinfo(hostname, NULL, &hints, &res);
 154 
 155 #ifdef MACOSX
 156     if (getaddrinfo_error) {
 157         // If getaddrinfo fails try getifaddrs.
 158         ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
 159         if (ret != NULL || (*env)->ExceptionCheck(env)) {
 160             JNU_ReleaseStringPlatformChars(env, host, hostname);
 161             return ret;
 162         }
 163     }
 164 #endif
 165 
 166     if (getaddrinfo_error) {
 167         /* report error */
 168         NET_ThrowUnknownHostExceptionWithGaiError(
 169             env, hostname, getaddrinfo_error);
 170         JNU_ReleaseStringPlatformChars(env, host, hostname);
 171         return NULL;
 172     } else {
 173         int i = 0;
 174         struct addrinfo *itr, *last = NULL, *iterator = res;
 175         while (iterator != NULL) {
 176             int skip = 0;
 177             itr = resNew;
 178 
 179             while (itr != NULL) {
 180                 struct sockaddr_in *addr1, *addr2;
 181 
 182                 addr1 = (struct sockaddr_in *)iterator->ai_addr;
 183                 addr2 = (struct sockaddr_in *)itr->ai_addr;
 184                 if (addr1->sin_addr.s_addr ==
 185                     addr2->sin_addr.s_addr) {
 186                     skip = 1;
 187                     break;
 188                 }
 189 
 190                 itr = itr->ai_next;
 191             }
 192 
 193             if (!skip) {
 194                 struct addrinfo *next
 195                     = (struct addrinfo*) malloc(sizeof(struct addrinfo));
 196                 if (!next) {
 197                     JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
 198                     ret = NULL;
 199                     goto cleanupAndReturn;
 200                 }
 201                 memcpy(next, iterator, sizeof(struct addrinfo));
 202                 next->ai_next = NULL;
 203                 if (resNew == NULL) {
 204                     resNew = next;
 205                 } else {
 206                     last->ai_next = next;
 207                 }
 208                 last = next;
 209                 i++;
 210             }
 211             iterator = iterator->ai_next;
 212         }
 213 
 214         retLen = i;
 215         iterator = resNew;
 216         i = 0;
 217 
 218         name = (*env)->NewStringUTF(env, hostname);
 219         if (IS_NULL(name)) {
 220           goto cleanupAndReturn;
 221         }
 222 
 223         ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
 224         if (IS_NULL(ret)) {
 225             /* we may have memory to free at the end of this */
 226             goto cleanupAndReturn;
 227         }
 228 
 229         while (iterator != NULL) {
 230             /* We need 4 bytes to store ipv4 address; */
 231             int len = 4;
 232 
 233             jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 234             if (IS_NULL(iaObj)) {
 235                 /* we may have memory to free at the end of this */
 236                 ret = NULL;
 237                 goto cleanupAndReturn;
 238             }
 239             setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr));
 240             setInetAddress_hostName(env, iaObj, name);
 241             (*env)->SetObjectArrayElement(env, ret, retLen - i -1, iaObj);
 242             i++;
 243             iterator = iterator->ai_next;
 244         }
 245     }
 246 
 247 cleanupAndReturn:
 248     {
 249         struct addrinfo *iterator, *tmp;
 250         iterator = resNew;
 251         while (iterator != NULL) {
 252             tmp = iterator;
 253             iterator = iterator->ai_next;
 254             free(tmp);
 255         }
 256         JNU_ReleaseStringPlatformChars(env, host, hostname);
 257     }
 258 
 259     freeaddrinfo(res);
 260 
 261     return ret;
 262 
 263 }
 264 
 265 /*
 266  * Class:     java_net_Inet4AddressImpl
 267  * Method:    getHostByAddr
 268  * Signature: (I)Ljava/lang/String;
 269  */
 270 JNIEXPORT jstring JNICALL
 271 Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
 272                                             jbyteArray addrArray) {
 273     jstring ret = NULL;
 274 
 275     char host[NI_MAXHOST+1];
 276     jfieldID fid;
 277     int error = 0;
 278     jint family;
 279     struct sockaddr *him ;
 280     int len = 0;
 281     jbyte caddr[4];
 282     jint addr;
 283 
 284     struct sockaddr_in him4;
 285     struct sockaddr *sa;
 286 
 287     /*
 288          * For IPv4 addresses construct a sockaddr_in structure.
 289          */
 290     (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 291     addr = ((caddr[0]<<24) & 0xff000000);
 292     addr |= ((caddr[1] <<16) & 0xff0000);
 293     addr |= ((caddr[2] <<8) & 0xff00);
 294     addr |= (caddr[3] & 0xff);
 295     memset((char *) &him4, 0, sizeof(him4));
 296     him4.sin_addr.s_addr = (uint32_t) htonl(addr);
 297     him4.sin_family = AF_INET;
 298     sa = (struct sockaddr *) &him4;
 299     len = sizeof(him4);
 300 
 301     error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
 302                                NI_NAMEREQD);
 303 
 304     if (!error) {
 305         ret = (*env)->NewStringUTF(env, host);
 306     }
 307 
 308     if (ret == NULL) {
 309         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
 310     }
 311 
 312     return ret;
 313 
 314 }
 315 
 316 #else /* defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R) */
 317 
 318 /* the initial size of our hostent buffers */
 319 #ifndef NI_MAXHOST
 320 #define NI_MAXHOST 1025
 321 #endif
 322 
 323 /************************************************************************
 324  * Inet4AddressImpl
 325  */
 326 
 327 /*
 328  * Class:     java_net_Inet4AddressImpl
 329  * Method:    getLocalHostName
 330  * Signature: ()Ljava/lang/String;
 331  */
 332 JNIEXPORT jstring JNICALL
 333 Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
 334     char hostname[NI_MAXHOST+1];
 335 
 336     hostname[0] = '\0';
 337     if (gethostname(hostname, NI_MAXHOST)) {
 338         /* Something went wrong, maybe networking is not setup? */
 339         strcpy(hostname, "localhost");
 340     } else {
 341         struct addrinfo hints, *res;
 342         int error;
 343 
 344         hostname[NI_MAXHOST] = '\0';
 345         memset(&hints, 0, sizeof(hints));
 346         hints.ai_flags = AI_CANONNAME;
 347         hints.ai_family = AF_INET;
 348 
 349         error = getaddrinfo(hostname, NULL, &hints, &res);
 350 
 351         if (error == 0) {/* host is known to name service */
 352             getnameinfo(res->ai_addr,
 353                         res->ai_addrlen,
 354                         hostname,
 355                         NI_MAXHOST,
 356                         NULL,
 357                         0,
 358                         NI_NAMEREQD);
 359 
 360             /* if getnameinfo fails hostname is still the value
 361                from gethostname */
 362 
 363             freeaddrinfo(res);
 364         }
 365     }
 366     return (*env)->NewStringUTF(env, hostname);
 367 }
 368 
 369 /*
 370  * Find an internet address for a given hostname.  Note that this
 371  * code only works for addresses of type INET. The translation
 372  * of %d.%d.%d.%d to an address (int) occurs in java now, so the
 373  * String "host" shouldn't *ever* be a %d.%d.%d.%d string
 374  *
 375  * Class:     java_net_Inet4AddressImpl
 376  * Method:    lookupAllHostAddr
 377  * Signature: (Ljava/lang/String;)[[B
 378  */
 379 
 380 JNIEXPORT jobjectArray JNICALL
 381 Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
 382                                                 jstring host) {
 383     const char *hostname;
 384     jobjectArray ret = 0;
 385     int retLen = 0;
 386     int error = 0;
 387     struct addrinfo hints, *res, *resNew = NULL;
 388 
 389     initInetAddressIDs(env);
 390     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 391 
 392     if (IS_NULL(host)) {
 393         JNU_ThrowNullPointerException(env, "host is null");
 394         return 0;
 395     }
 396     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
 397     CHECK_NULL_RETURN(hostname, NULL);
 398 
 399     /* Try once, with our static buffer. */
 400     memset(&hints, 0, sizeof(hints));
 401     hints.ai_flags = AI_CANONNAME;
 402     hints.ai_family = AF_INET;
 403 
 404 #ifdef __solaris__
 405     /*
 406      * Workaround for Solaris bug 4160367 - if a hostname contains a
 407      * white space then 0.0.0.0 is returned
 408      */
 409     if (isspace((unsigned char)hostname[0])) {
 410         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
 411                         (char *)hostname);
 412         JNU_ReleaseStringPlatformChars(env, host, hostname);
 413         return NULL;
 414     }
 415 #endif
 416 
 417     error = getaddrinfo(hostname, NULL, &hints, &res);
 418 
 419     if (error) {
 420         /* report error */
 421         NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
 422         JNU_ReleaseStringPlatformChars(env, host, hostname);
 423         return NULL;
 424     } else {
 425         int i = 0;
 426         struct addrinfo *itr, *last = NULL, *iterator = res;
 427 
 428         while (iterator != NULL) {
 429             // remove the duplicate one
 430             int skip = 0;
 431             itr = resNew;
 432             while (itr != NULL) {
 433                 struct sockaddr_in *addr1, *addr2;
 434                 addr1 = (struct sockaddr_in *)iterator->ai_addr;
 435                 addr2 = (struct sockaddr_in *)itr->ai_addr;
 436                 if (addr1->sin_addr.s_addr ==
 437                     addr2->sin_addr.s_addr) {
 438                     skip = 1;
 439                     break;
 440                 }
 441                 itr = itr->ai_next;
 442             }
 443 
 444             if (!skip) {
 445                 struct addrinfo *next
 446                     = (struct addrinfo*) malloc(sizeof(struct addrinfo));
 447                 if (!next) {
 448                     JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
 449                     ret = NULL;
 450                     goto cleanupAndReturn;
 451                 }
 452                 memcpy(next, iterator, sizeof(struct addrinfo));
 453                 next->ai_next = NULL;
 454                 if (resNew == NULL) {
 455                     resNew = next;
 456                 } else {
 457                     last->ai_next = next;
 458                 }
 459                 last = next;
 460                 i++;
 461             }
 462             iterator = iterator->ai_next;
 463         }
 464 
 465         retLen = i;
 466         iterator = resNew;
 467 
 468         ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
 469 
 470         if (IS_NULL(ret)) {
 471             /* we may have memory to free at the end of this */
 472             goto cleanupAndReturn;
 473         }
 474 
 475         i = 0;
 476         while (iterator != NULL) {
 477             jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 478             if (IS_NULL(iaObj)) {
 479                 ret = NULL;
 480                 goto cleanupAndReturn;
 481             }
 482             setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
 483             setInetAddress_hostName(env, iaObj, host);
 484             (*env)->SetObjectArrayElement(env, ret, i++, iaObj);
 485             iterator = iterator->ai_next;
 486         }
 487     }
 488 
 489  cleanupAndReturn:
 490     {
 491         struct addrinfo *iterator, *tmp;
 492         iterator = resNew;
 493         while (iterator != NULL) {
 494             tmp = iterator;
 495             iterator = iterator->ai_next;
 496             free(tmp);
 497         }
 498         JNU_ReleaseStringPlatformChars(env, host, hostname);
 499     }
 500 
 501     freeaddrinfo(res);
 502 
 503     return ret;
 504 }
 505 
 506 /*
 507  * Class:     java_net_Inet4AddressImpl
 508  * Method:    getHostByAddr
 509  * Signature: (I)Ljava/lang/String;
 510  */
 511 JNIEXPORT jstring JNICALL
 512 Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
 513                                             jbyteArray addrArray) {
 514     jstring ret = NULL;
 515 
 516     char host[NI_MAXHOST+1];
 517     int error = 0;
 518     int len = 0;
 519     jbyte caddr[4];
 520 
 521     struct sockaddr_in him4;
 522     struct sockaddr *sa;
 523 
 524     jint addr;
 525     (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 526     addr = ((caddr[0]<<24) & 0xff000000);
 527     addr |= ((caddr[1] <<16) & 0xff0000);
 528     addr |= ((caddr[2] <<8) & 0xff00);
 529     addr |= (caddr[3] & 0xff);
 530     memset((void *) &him4, 0, sizeof(him4));
 531     him4.sin_addr.s_addr = (uint32_t) htonl(addr);
 532     him4.sin_family = AF_INET;
 533     sa = (struct sockaddr *) &him4;
 534     len = sizeof(him4);
 535 
 536     error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
 537                         NI_NAMEREQD);
 538 
 539     if (!error) {
 540         ret = (*env)->NewStringUTF(env, host);
 541     }
 542 
 543     if (ret == NULL) {
 544         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
 545     }
 546 
 547     return ret;
 548 }
 549 
 550 #endif /* _ALLBSD_SOURCE */
 551 
 552 #define SET_NONBLOCKING(fd) {           \
 553         int flags = fcntl(fd, F_GETFL); \
 554         flags |= O_NONBLOCK;            \
 555         fcntl(fd, F_SETFL, flags);      \
 556 }
 557 
 558 /**
 559  * ping implementation.
 560  * Send a ICMP_ECHO_REQUEST packet every second until either the timeout
 561  * expires or a answer is received.
 562  * Returns true is an ECHO_REPLY is received, otherwise, false.
 563  */
 564 static jboolean
 565 ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout,
 566       struct sockaddr_in* netif, jint ttl) {
 567     jint size;
 568     jint n, hlen1, icmplen;
 569     socklen_t len;
 570     char sendbuf[1500];
 571     char recvbuf[1500];
 572     struct icmp *icmp;
 573     struct ip *ip;
 574     struct sockaddr_in sa_recv;
 575     jchar pid;
 576     jint tmout2, seq = 1;
 577     struct timeval tv;
 578     size_t plen;
 579 
 580     /* icmp_id is a 16 bit data type, therefore down cast the pid */
 581     pid = (jchar)getpid();
 582     size = 60*1024;
 583     setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
 584     /*
 585      * sets the ttl (max number of hops)
 586      */
 587     if (ttl > 0) {
 588       setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
 589     }
 590     /*
 591      * a specific interface was specified, so let's bind the socket
 592      * to that interface to ensure the requests are sent only through it.
 593      */
 594     if (netif != NULL) {
 595       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
 596         NET_ThrowNew(env, errno, "Can't bind socket");
 597         close(fd);
 598         return JNI_FALSE;
 599       }
 600     }
 601     /*
 602      * Make the socket non blocking so we can use select
 603      */
 604     SET_NONBLOCKING(fd);
 605     do {
 606       /*
 607        * create the ICMP request
 608        */
 609       icmp = (struct icmp *) sendbuf;
 610       icmp->icmp_type = ICMP_ECHO;
 611       icmp->icmp_code = 0;
 612       icmp->icmp_id = htons(pid);
 613       icmp->icmp_seq = htons(seq);
 614       seq++;
 615       gettimeofday(&tv, NULL);
 616       memcpy(icmp->icmp_data, &tv, sizeof(tv));
 617       plen = ICMP_ADVLENMIN + sizeof(tv);
 618       icmp->icmp_cksum = 0;
 619       icmp->icmp_cksum = in_cksum((u_short *)icmp, plen);
 620       /*
 621        * send it
 622        */
 623       n = sendto(fd, sendbuf, plen, 0, (struct sockaddr *)him,
 624                  sizeof(struct sockaddr));
 625       if (n < 0 && errno != EINPROGRESS ) {
 626 #ifdef __linux__
 627         if (errno != EINVAL && errno != EHOSTUNREACH)
 628           /*
 629            * On some Linux versions, when a socket is bound to the loopback
 630            * interface, sendto will fail and errno will be set to
 631            * EINVAL or EHOSTUNREACH. When that happens, don't throw an
 632            * exception, just return false.
 633            */
 634 #endif /*__linux__ */
 635           NET_ThrowNew(env, errno, "Can't send ICMP packet");
 636         close(fd);
 637         return JNI_FALSE;
 638       }
 639 
 640       tmout2 = timeout > 1000 ? 1000 : timeout;
 641       do {
 642         tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
 643         if (tmout2 >= 0) {
 644           len = sizeof(sa_recv);
 645           n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&sa_recv, &len);
 646           ip = (struct ip*) recvbuf;
 647           hlen1 = (ip->ip_hl) << 2;
 648           icmp = (struct icmp *) (recvbuf + hlen1);
 649           icmplen = n - hlen1;
 650           /*
 651            * We did receive something, but is it what we were expecting?
 652            * I.E.: A ICMP_ECHOREPLY packet with the proper PID.
 653            */
 654           if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY
 655                && (ntohs(icmp->icmp_id) == pid)) {
 656             if ((him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) {
 657               close(fd);
 658               return JNI_TRUE;
 659             }
 660 
 661             if (him->sin_addr.s_addr == 0) {
 662               close(fd);
 663               return JNI_TRUE;
 664             }
 665          }
 666 
 667         }
 668       } while (tmout2 > 0);
 669       timeout -= 1000;
 670     } while (timeout >0);
 671     close(fd);
 672     return JNI_FALSE;
 673 }
 674 
 675 /*
 676  * Class:     java_net_Inet4AddressImpl
 677  * Method:    isReachable0
 678  * Signature: ([bI[bI)Z
 679  */
 680 JNIEXPORT jboolean JNICALL
 681 Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this,
 682                                            jbyteArray addrArray,
 683                                            jint timeout,
 684                                            jbyteArray ifArray,
 685                                            jint ttl) {
 686     jint addr;
 687     jbyte caddr[4];
 688     jint fd;
 689     struct sockaddr_in him;
 690     struct sockaddr_in* netif = NULL;
 691     struct sockaddr_in inf;
 692     int len = 0;
 693     int connect_rv = -1;
 694     int sz;
 695 
 696     memset((char *) caddr, 0, sizeof(caddr));
 697     memset((char *) &him, 0, sizeof(him));
 698     memset((char *) &inf, 0, sizeof(inf));
 699     sz = (*env)->GetArrayLength(env, addrArray);
 700     if (sz != 4) {
 701       return JNI_FALSE;
 702     }
 703     (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 704     addr = ((caddr[0]<<24) & 0xff000000);
 705     addr |= ((caddr[1] <<16) & 0xff0000);
 706     addr |= ((caddr[2] <<8) & 0xff00);
 707     addr |= (caddr[3] & 0xff);
 708     addr = htonl(addr);
 709     him.sin_addr.s_addr = addr;
 710     him.sin_family = AF_INET;
 711     len = sizeof(him);
 712     /*
 713      * If a network interface was specified, let's create the address
 714      * for it.
 715      */
 716     if (!(IS_NULL(ifArray))) {
 717       memset((char *) caddr, 0, sizeof(caddr));
 718       (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
 719       addr = ((caddr[0]<<24) & 0xff000000);
 720       addr |= ((caddr[1] <<16) & 0xff0000);
 721       addr |= ((caddr[2] <<8) & 0xff00);
 722       addr |= (caddr[3] & 0xff);
 723       addr = htonl(addr);
 724       inf.sin_addr.s_addr = addr;
 725       inf.sin_family = AF_INET;
 726       inf.sin_port = 0;
 727       netif = &inf;
 728     }
 729 
 730     /*
 731      * Let's try to create a RAW socket to send ICMP packets
 732      * This usually requires "root" privileges, so it's likely to fail.
 733      */
 734     fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 735     if (fd != -1) {
 736       /*
 737        * It didn't fail, so we can use ICMP_ECHO requests.
 738        */
 739       return ping4(env, fd, &him, timeout, netif, ttl);
 740     }
 741 
 742     /*
 743      * Can't create a raw socket, so let's try a TCP socket
 744      */
 745     fd = socket(AF_INET, SOCK_STREAM, 0);
 746     if (fd == -1) {
 747         /* note: if you run out of fds, you may not be able to load
 748          * the exception class, and get a NoClassDefFoundError
 749          * instead.
 750          */
 751         NET_ThrowNew(env, errno, "Can't create socket");
 752         return JNI_FALSE;
 753     }
 754     if (ttl > 0) {
 755       setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
 756     }
 757 
 758     /*
 759      * A network interface was specified, so let's bind to it.
 760      */
 761     if (netif != NULL) {
 762       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
 763         NET_ThrowNew(env, errno, "Can't bind socket");
 764         close(fd);
 765         return JNI_FALSE;
 766       }
 767     }
 768 
 769     /*
 770      * Make the socket non blocking so we can use select/poll.
 771      */
 772     SET_NONBLOCKING(fd);
 773 
 774     him.sin_port = htons(7);    /* Echo */
 775     connect_rv = NET_Connect(fd, (struct sockaddr *)&him, len);
 776 
 777     /**
 778      * connection established or refused immediately, either way it means
 779      * we were able to reach the host!
 780      */
 781     if (connect_rv == 0 || errno == ECONNREFUSED) {
 782         close(fd);
 783         return JNI_TRUE;
 784     } else {
 785         socklen_t optlen = (socklen_t)sizeof(connect_rv);
 786 
 787         switch (errno) {
 788         case ENETUNREACH: /* Network Unreachable */
 789         case EAFNOSUPPORT: /* Address Family not supported */
 790         case EADDRNOTAVAIL: /* address is not available on  the  remote machine */
 791 #ifdef __linux__
 792         case EINVAL:
 793         case EHOSTUNREACH:
 794           /*
 795            * On some Linux versions, when a socket is bound to the loopback
 796            * interface, connect will fail and errno will be set to EINVAL
 797            * or EHOSTUNREACH.  When that happens, don't throw an exception,
 798            * just return false.
 799            */
 800 #endif /* __linux__ */
 801           close(fd);
 802           return JNI_FALSE;
 803         }
 804 
 805         if (errno != EINPROGRESS) {
 806           NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 807                                        "connect failed");
 808           close(fd);
 809           return JNI_FALSE;
 810         }
 811 
 812         timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
 813         if (timeout >= 0) {
 814           /* has connection been established? */
 815           if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
 816                          &optlen) <0) {
 817             connect_rv = errno;
 818           }
 819           if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
 820             close(fd);
 821             return JNI_TRUE;
 822           }
 823         }
 824         close(fd);
 825         return JNI_FALSE;
 826     }
 827 }