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