1 /* 2 * Copyright (c) 2000, 2009, 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 #include "jvm.h" 40 #include "jni_util.h" 41 #include "net_util.h" 42 43 #include "java_net_Inet4AddressImpl.h" 44 45 /* the initial size of our hostent buffers */ 46 #define HENT_BUF_SIZE 1024 47 #define BIG_HENT_BUF_SIZE 10240 /* a jumbo-sized one */ 48 49 /************************************************************************ 50 * Inet4AddressImpl 51 */ 52 53 /* 54 * Class: java_net_Inet4AddressImpl 55 * Method: getLocalHostName 56 * Signature: ()Ljava/lang/String; 57 */ 58 JNIEXPORT jstring JNICALL 59 Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { 60 char hostname[MAXHOSTNAMELEN+1]; 61 62 hostname[0] = '\0'; 63 if (JVM_GetHostName(hostname, MAXHOSTNAMELEN)) { 64 /* Something went wrong, maybe networking is not setup? */ 65 strcpy(hostname, "localhost"); 66 } else { 67 #ifdef __linux__ 68 /* On Linux gethostname() says "host.domain.sun.com". On 69 * Solaris gethostname() says "host", so extra work is needed. 70 */ 71 #else 72 /* Solaris doesn't want to give us a fully qualified domain name. 73 * We do a reverse lookup to try and get one. This works 74 * if DNS occurs before NIS in /etc/resolv.conf, but fails 75 * if NIS comes first (it still gets only a partial name). 76 * We use thread-safe system calls. 77 */ 78 #endif /* __linux__ */ 79 struct hostent res, res2, *hp; 80 char buf[HENT_BUF_SIZE]; 81 char buf2[HENT_BUF_SIZE]; 82 int h_error=0; 83 84 #ifdef __GLIBC__ 85 gethostbyname_r(hostname, &res, buf, sizeof(buf), &hp, &h_error); 86 #else 87 hp = gethostbyname_r(hostname, &res, buf, sizeof(buf), &h_error); 88 #endif 89 if (hp) { 90 #ifdef __GLIBC__ 91 gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET, 92 &res2, buf2, sizeof(buf2), &hp, &h_error); 93 #else 94 hp = gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET, 95 &res2, buf2, sizeof(buf2), &h_error); 96 #endif 97 if (hp) { 98 /* 99 * If gethostbyaddr_r() found a fully qualified host name, 100 * returns that name. Otherwise, returns the hostname 101 * found by gethostname(). 102 */ 103 char *p = hp->h_name; 104 if ((strlen(hp->h_name) > strlen(hostname)) 105 && (strncmp(hostname, hp->h_name, strlen(hostname)) == 0) 106 && (*(p + strlen(hostname)) == '.')) 107 strcpy(hostname, hp->h_name); 108 } 109 } 110 } 111 return (*env)->NewStringUTF(env, hostname); 112 } 113 114 static jclass ni_iacls; 115 static jclass ni_ia4cls; 116 static jmethodID ni_ia4ctrID; 117 static jfieldID ni_iaaddressID; 118 static jfieldID ni_iahostID; 119 static jfieldID ni_iafamilyID; 120 static int initialized = 0; 121 122 /* 123 * Find an internet address for a given hostname. Note that this 124 * code only works for addresses of type INET. The translation 125 * of %d.%d.%d.%d to an address (int) occurs in java now, so the 126 * String "host" shouldn't *ever* be a %d.%d.%d.%d string 127 * 128 * Class: java_net_Inet4AddressImpl 129 * Method: lookupAllHostAddr 130 * Signature: (Ljava/lang/String;)[[B 131 */ 132 133 JNIEXPORT jobjectArray JNICALL 134 Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 135 jstring host) { 136 const char *hostname; 137 jobjectArray ret = 0; 138 struct hostent res, *hp = 0; 139 char buf[HENT_BUF_SIZE]; 140 141 /* temporary buffer, on the off chance we need to expand */ 142 char *tmp = NULL; 143 int h_error=0; 144 145 if (!initialized) { 146 ni_iacls = (*env)->FindClass(env, "java/net/InetAddress"); 147 ni_iacls = (*env)->NewGlobalRef(env, ni_iacls); 148 ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); 149 ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); 150 ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V"); 151 ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I"); 152 ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I"); 153 ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;"); 154 initialized = 1; 155 } 156 157 if (IS_NULL(host)) { 158 JNU_ThrowNullPointerException(env, "host is null"); 159 return 0; 160 } 161 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); 162 CHECK_NULL_RETURN(hostname, NULL); 163 164 #ifdef __solaris__ 165 /* 166 * Workaround for Solaris bug 4160367 - if a hostname contains a 167 * white space then 0.0.0.0 is returned 168 */ 169 if (isspace((unsigned char)hostname[0])) { 170 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 171 (char *)hostname); 172 JNU_ReleaseStringPlatformChars(env, host, hostname); 173 return NULL; 174 } 175 #endif 176 177 /* Try once, with our static buffer. */ 178 #ifdef __GLIBC__ 179 gethostbyname_r(hostname, &res, buf, sizeof(buf), &hp, &h_error); 180 #else 181 hp = gethostbyname_r(hostname, &res, buf, sizeof(buf), &h_error); 182 #endif 183 184 /* With the re-entrant system calls, it's possible that the buffer 185 * we pass to it is not large enough to hold an exceptionally 186 * large DNS entry. This is signaled by errno->ERANGE. We try once 187 * more, with a very big size. 188 */ 189 if (hp == NULL && errno == ERANGE) { 190 if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) { 191 #ifdef __GLIBC__ 192 gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE, 193 &hp, &h_error); 194 #else 195 hp = gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE, 196 &h_error); 197 #endif 198 } 199 } 200 if (hp != NULL) { 201 struct in_addr **addrp = (struct in_addr **) hp->h_addr_list; 202 int i = 0; 203 204 while (*addrp != (struct in_addr *) 0) { 205 i++; 206 addrp++; 207 } 208 209 ret = (*env)->NewObjectArray(env, i, ni_iacls, NULL); 210 if (IS_NULL(ret)) { 211 /* we may have memory to free at the end of this */ 212 goto cleanupAndReturn; 213 } 214 addrp = (struct in_addr **) hp->h_addr_list; 215 i = 0; 216 while (*addrp) { 217 jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); 218 if (IS_NULL(iaObj)) { 219 ret = NULL; 220 goto cleanupAndReturn; 221 } 222 (*env)->SetIntField(env, iaObj, ni_iaaddressID, 223 ntohl((*addrp)->s_addr)); 224 (*env)->SetObjectField(env, iaObj, ni_iahostID, host); 225 (*env)->SetObjectArrayElement(env, ret, i, iaObj); 226 addrp++; 227 i++; 228 } 229 } else { 230 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 231 (char *)hostname); 232 ret = NULL; 233 } 234 235 cleanupAndReturn: 236 JNU_ReleaseStringPlatformChars(env, host, hostname); 237 if (tmp != NULL) { 238 free(tmp); 239 } 240 return ret; 241 } 242 243 /* 244 * Class: java_net_Inet4AddressImpl 245 * Method: getHostByAddr 246 * Signature: (I)Ljava/lang/String; 247 */ 248 JNIEXPORT jstring JNICALL 249 Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 250 jbyteArray addrArray) { 251 jstring ret = NULL; 252 jint addr; 253 struct hostent hent, *hp = 0; 254 char buf[HENT_BUF_SIZE]; 255 int h_error = 0; 256 char *tmp = NULL; 257 258 /* 259 * We are careful here to use the reentrant version of 260 * gethostbyname because at the Java level this routine is not 261 * protected by any synchronization. 262 * 263 * Still keeping the reentrant platform dependent calls temporarily 264 * We should probably conform to one interface later. 265 * 266 */ 267 jbyte caddr[4]; 268 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); 269 addr = ((caddr[0]<<24) & 0xff000000); 270 addr |= ((caddr[1] <<16) & 0xff0000); 271 addr |= ((caddr[2] <<8) & 0xff00); 272 addr |= (caddr[3] & 0xff); 273 addr = htonl(addr); 274 #ifdef __GLIBC__ 275 gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent, 276 buf, sizeof(buf), &hp, &h_error); 277 #else 278 hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent, 279 buf, sizeof(buf), &h_error); 280 #endif 281 /* With the re-entrant system calls, it's possible that the buffer 282 * we pass to it is not large enough to hold an exceptionally 283 * large DNS entry. This is signaled by errno->ERANGE. We try once 284 * more, with a very big size. 285 */ 286 if (hp == NULL && errno == ERANGE) { 287 if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) { 288 #ifdef __GLIBC__ 289 gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, 290 &hent, tmp, BIG_HENT_BUF_SIZE, &hp, &h_error); 291 #else 292 hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, 293 &hent, tmp, BIG_HENT_BUF_SIZE, &h_error); 294 #endif 295 } else { 296 JNU_ThrowOutOfMemoryError(env, "getHostByAddr"); 297 } 298 } 299 if (hp == NULL) { 300 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL); 301 } else { 302 ret = (*env)->NewStringUTF(env, hp->h_name); 303 } 304 if (tmp) { 305 free(tmp); 306 } 307 return ret; 308 } 309 310 #define SET_NONBLOCKING(fd) { \ 311 int flags = fcntl(fd, F_GETFL); \ 312 flags |= O_NONBLOCK; \ 313 fcntl(fd, F_SETFL, flags); \ 314 } 315 316 /** 317 * ping implementation. 318 * Send a ICMP_ECHO_REQUEST packet every second until either the timeout 319 * expires or a answer is received. 320 * Returns true is an ECHO_REPLY is received, otherwise, false. 321 */ 322 static jboolean 323 ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout, 324 struct sockaddr_in* netif, jint ttl) { 325 jint size; 326 jint n, hlen1, icmplen; 327 socklen_t len; 328 char sendbuf[1500]; 329 char recvbuf[1500]; 330 struct icmp *icmp; 331 struct ip *ip; 332 struct sockaddr_in sa_recv; 333 jchar pid; 334 jint tmout2, seq = 1; 335 struct timeval tv; 336 size_t plen; 337 338 /* icmp_id is a 16 bit data type, therefore down cast the pid */ 339 pid = (jchar)getpid(); 340 size = 60*1024; 341 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 342 /* 343 * sets the ttl (max number of hops) 344 */ 345 if (ttl > 0) { 346 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 347 } 348 /* 349 * a specific interface was specified, so let's bind the socket 350 * to that interface to ensure the requests are sent only through it. 351 */ 352 if (netif != NULL) { 353 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) { 354 NET_ThrowNew(env, errno, "Can't bind socket"); 355 close(fd); 356 return JNI_FALSE; 357 } 358 } 359 /* 360 * Make the socket non blocking so we can use select 361 */ 362 SET_NONBLOCKING(fd); 363 do { 364 /* 365 * create the ICMP request 366 */ 367 icmp = (struct icmp *) sendbuf; 368 icmp->icmp_type = ICMP_ECHO; 369 icmp->icmp_code = 0; 370 icmp->icmp_id = htons(pid); 371 icmp->icmp_seq = htons(seq); 372 seq++; 373 gettimeofday(&tv, NULL); 374 memcpy(icmp->icmp_data, &tv, sizeof(tv)); 375 plen = ICMP_ADVLENMIN + sizeof(tv); 376 icmp->icmp_cksum = 0; 377 icmp->icmp_cksum = in_cksum((u_short *)icmp, plen); 378 /* 379 * send it 380 */ 381 n = sendto(fd, sendbuf, plen, 0, (struct sockaddr *)him, 382 sizeof(struct sockaddr)); 383 if (n < 0 && errno != EINPROGRESS ) { 384 #ifdef __linux__ 385 if (errno == EINVAL) { 386 /* 387 * On some Linuxes, when bound to the loopback interface, sendto 388 * will fail and errno will be set to EINVAL. When that happens, 389 * don't throw an exception, just return false. 390 */ 391 close(fd); 392 return JNI_FALSE; 393 } 394 #endif /*__linux__ */ 395 NET_ThrowNew(env, errno, "Can't send ICMP packet"); 396 close(fd); 397 return JNI_FALSE; 398 } 399 400 tmout2 = timeout > 1000 ? 1000 : timeout; 401 do { 402 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); 403 if (tmout2 >= 0) { 404 len = sizeof(sa_recv); 405 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&sa_recv, &len); 406 ip = (struct ip*) recvbuf; 407 hlen1 = (ip->ip_hl) << 2; 408 icmp = (struct icmp *) (recvbuf + hlen1); 409 icmplen = n - hlen1; 410 /* 411 * We did receive something, but is it what we were expecting? 412 * I.E.: A ICMP_ECHOREPLY packet with the proper PID. 413 */ 414 if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY && 415 (ntohs(icmp->icmp_id) == pid) && 416 (him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) { 417 close(fd); 418 return JNI_TRUE; 419 } 420 } 421 } while (tmout2 > 0); 422 timeout -= 1000; 423 } while (timeout >0); 424 close(fd); 425 return JNI_FALSE; 426 } 427 428 /* 429 * Class: java_net_Inet4AddressImpl 430 * Method: isReachable0 431 * Signature: ([bI[bI)Z 432 */ 433 JNIEXPORT jboolean JNICALL 434 Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this, 435 jbyteArray addrArray, 436 jint timeout, 437 jbyteArray ifArray, 438 jint ttl) { 439 jint addr; 440 jbyte caddr[4]; 441 jint fd; 442 struct sockaddr_in him; 443 struct sockaddr_in* netif = NULL; 444 struct sockaddr_in inf; 445 int len = 0; 446 int connect_rv = -1; 447 int sz; 448 449 memset((char *) caddr, 0, sizeof(caddr)); 450 memset((char *) &him, 0, sizeof(him)); 451 sz = (*env)->GetArrayLength(env, addrArray); 452 if (sz != 4) { 453 return JNI_FALSE; 454 } 455 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); 456 addr = ((caddr[0]<<24) & 0xff000000); 457 addr |= ((caddr[1] <<16) & 0xff0000); 458 addr |= ((caddr[2] <<8) & 0xff00); 459 addr |= (caddr[3] & 0xff); 460 addr = htonl(addr); 461 him.sin_addr.s_addr = addr; 462 him.sin_family = AF_INET; 463 len = sizeof(him); 464 /* 465 * If a network interface was specified, let's create the address 466 * for it. 467 */ 468 if (!(IS_NULL(ifArray))) { 469 memset((char *) caddr, 0, sizeof(caddr)); 470 (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr); 471 addr = ((caddr[0]<<24) & 0xff000000); 472 addr |= ((caddr[1] <<16) & 0xff0000); 473 addr |= ((caddr[2] <<8) & 0xff00); 474 addr |= (caddr[3] & 0xff); 475 addr = htonl(addr); 476 inf.sin_addr.s_addr = addr; 477 inf.sin_family = AF_INET; 478 inf.sin_port = 0; 479 netif = &inf; 480 } 481 482 /* 483 * Let's try to create a RAW socket to send ICMP packets 484 * This usually requires "root" privileges, so it's likely to fail. 485 */ 486 fd = JVM_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 487 if (fd != -1) { 488 /* 489 * It didn't fail, so we can use ICMP_ECHO requests. 490 */ 491 return ping4(env, fd, &him, timeout, netif, ttl); 492 } 493 494 /* 495 * Can't create a raw socket, so let's try a TCP socket 496 */ 497 fd = JVM_Socket(AF_INET, SOCK_STREAM, 0); 498 if (fd == JVM_IO_ERR) { 499 /* note: if you run out of fds, you may not be able to load 500 * the exception class, and get a NoClassDefFoundError 501 * instead. 502 */ 503 NET_ThrowNew(env, errno, "Can't create socket"); 504 return JNI_FALSE; 505 } 506 if (ttl > 0) { 507 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 508 } 509 510 /* 511 * A network interface was specified, so let's bind to it. 512 */ 513 if (netif != NULL) { 514 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) { 515 NET_ThrowNew(env, errno, "Can't bind socket"); 516 close(fd); 517 return JNI_FALSE; 518 } 519 } 520 521 /* 522 * Make the socket non blocking so we can use select/poll. 523 */ 524 SET_NONBLOCKING(fd); 525 526 /* no need to use NET_Connect as non-blocking */ 527 him.sin_port = htons(7); /* Echo */ 528 connect_rv = JVM_Connect(fd, (struct sockaddr *)&him, len); 529 530 /** 531 * connection established or refused immediately, either way it means 532 * we were able to reach the host! 533 */ 534 if (connect_rv == 0 || errno == ECONNREFUSED) { 535 close(fd); 536 return JNI_TRUE; 537 } else { 538 int optlen; 539 540 switch (errno) { 541 case ENETUNREACH: /* Network Unreachable */ 542 case EAFNOSUPPORT: /* Address Family not supported */ 543 case EADDRNOTAVAIL: /* address is not available on the remote machine */ 544 #ifdef __linux__ 545 case EINVAL: 546 /* 547 * On some Linuxes, when bound to the loopback interface, connect 548 * will fail and errno will be set to EINVAL. When that happens, 549 * don't throw an exception, just return false. 550 */ 551 #endif /* __linux__ */ 552 close(fd); 553 return JNI_FALSE; 554 } 555 556 if (errno != EINPROGRESS) { 557 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 558 "connect failed"); 559 close(fd); 560 return JNI_FALSE; 561 } 562 563 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); 564 if (timeout >= 0) { 565 /* has connection been established? */ 566 optlen = sizeof(connect_rv); 567 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, 568 &optlen) <0) { 569 connect_rv = errno; 570 } 571 if (connect_rv == 0 || connect_rv == ECONNREFUSED) { 572 close(fd); 573 return JNI_TRUE; 574 } 575 } 576 close(fd); 577 return JNI_FALSE; 578 } 579 } --- EOF ---