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