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