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 }