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 ---