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