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