annotate src/solaris/native/java/net/Inet6AddressImpl.c @ 5512:79ce384ed535

7163874: InetAddress.isReachable should support pinging 0.0.0.0 Reviewed-by: alanb, chegar
author youdwei
date Fri, 11 May 2012 16:20:46 +0800
parents a48da818ed65
children eefd9678efbd
rev   line source
duke@0 1 /*
robm@4989 2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
ohair@2362 7 * published by the Free Software Foundation. Oracle designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
ohair@2362 9 * by Oracle in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
ohair@2362 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2362 22 * or visit www.oracle.com if you need additional information or have any
ohair@2362 23 * questions.
duke@0 24 */
duke@0 25
duke@0 26 #include <errno.h>
andrew@1392 27 #include <sys/time.h>
duke@0 28 #include <sys/types.h>
duke@0 29 #include <sys/socket.h>
duke@0 30 #include <netinet/in.h>
duke@0 31 #include <netdb.h>
duke@0 32 #include <string.h>
duke@0 33 #include <strings.h>
duke@0 34 #include <stdlib.h>
duke@0 35 #include <ctype.h>
michaelm@4628 36 #ifdef _ALLBSD_SOURCE
michaelm@4628 37 #include <unistd.h> /* gethostname */
michaelm@4628 38 #endif
duke@0 39
duke@0 40 #include "jvm.h"
duke@0 41 #include "jni_util.h"
duke@0 42 #include "net_util.h"
duke@0 43 #ifndef IPV6_DEFS_H
duke@0 44 #include <netinet/icmp6.h>
duke@0 45 #endif
duke@0 46
duke@0 47 #include "java_net_Inet4AddressImpl.h"
duke@0 48 #include "java_net_Inet6AddressImpl.h"
duke@0 49
duke@0 50 /* the initial size of our hostent buffers */
duke@0 51 #ifndef NI_MAXHOST
duke@0 52 #define NI_MAXHOST 1025
duke@0 53 #endif
duke@0 54
duke@0 55
duke@0 56 /************************************************************************
duke@0 57 * Inet6AddressImpl
duke@0 58 */
duke@0 59
duke@0 60 /*
duke@0 61 * Class: java_net_Inet6AddressImpl
duke@0 62 * Method: getLocalHostName
duke@0 63 * Signature: ()Ljava/lang/String;
duke@0 64 */
duke@0 65 JNIEXPORT jstring JNICALL
duke@0 66 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
duke@0 67 char hostname[NI_MAXHOST+1];
duke@0 68
duke@0 69 hostname[0] = '\0';
chegar@3745 70 if (JVM_GetHostName(hostname, sizeof(hostname))) {
duke@0 71 /* Something went wrong, maybe networking is not setup? */
duke@0 72 strcpy(hostname, "localhost");
duke@0 73 } else {
chegar@3745 74 // ensure null-terminated
chegar@3745 75 hostname[NI_MAXHOST] = '\0';
robm@4989 76 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
michaelm@4628 77 /* On Linux/FreeBSD gethostname() says "host.domain.sun.com". On
duke@0 78 * Solaris gethostname() says "host", so extra work is needed.
duke@0 79 */
duke@0 80 #else
duke@0 81 /* Solaris doesn't want to give us a fully qualified domain name.
duke@0 82 * We do a reverse lookup to try and get one. This works
duke@0 83 * if DNS occurs before NIS in /etc/resolv.conf, but fails
duke@0 84 * if NIS comes first (it still gets only a partial name).
duke@0 85 * We use thread-safe system calls.
duke@0 86 */
duke@0 87 #ifdef AF_INET6
duke@0 88 if (NET_addrtransAvailable()) {
duke@0 89 struct addrinfo hints, *res;
duke@0 90 int error;
duke@0 91
duke@0 92 bzero(&hints, sizeof(hints));
duke@0 93 hints.ai_flags = AI_CANONNAME;
duke@0 94 hints.ai_family = AF_UNSPEC;
duke@0 95
duke@0 96 error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
duke@0 97
duke@0 98 if (error == 0) {
duke@0 99 /* host is known to name service */
duke@0 100 error = (*getnameinfo_ptr)(res->ai_addr,
duke@0 101 res->ai_addrlen,
duke@0 102 hostname,
duke@0 103 NI_MAXHOST,
duke@0 104 NULL,
duke@0 105 0,
duke@0 106 NI_NAMEREQD);
duke@0 107
duke@0 108 /* if getnameinfo fails hostname is still the value
duke@0 109 from gethostname */
duke@0 110
duke@0 111 (*freeaddrinfo_ptr)(res);
duke@0 112 }
duke@0 113 }
duke@0 114 #endif /* AF_INET6 */
michaelm@4628 115 #endif /* __linux__ || _ALLBSD_SOURCE */
duke@0 116 }
duke@0 117 return (*env)->NewStringUTF(env, hostname);
duke@0 118 }
duke@0 119
duke@0 120 static jclass ni_iacls;
duke@0 121 static jclass ni_ia4cls;
duke@0 122 static jclass ni_ia6cls;
duke@0 123 static jmethodID ni_ia4ctrID;
duke@0 124 static jmethodID ni_ia6ctrID;
duke@0 125 static jfieldID ni_iaaddressID;
duke@0 126 static jfieldID ni_iahostID;
duke@0 127 static jfieldID ni_iafamilyID;
duke@0 128 static jfieldID ni_ia6ipaddressID;
duke@0 129 static int initialized = 0;
duke@0 130
duke@0 131 /*
martin@2801 132 * Find an internet address for a given hostname. Note that this
duke@0 133 * code only works for addresses of type INET. The translation
duke@0 134 * of %d.%d.%d.%d to an address (int) occurs in java now, so the
duke@0 135 * String "host" shouldn't *ever* be a %d.%d.%d.%d string
duke@0 136 *
duke@0 137 * Class: java_net_Inet6AddressImpl
duke@0 138 * Method: lookupAllHostAddr
duke@0 139 * Signature: (Ljava/lang/String;)[[B
duke@0 140 */
duke@0 141
duke@0 142 JNIEXPORT jobjectArray JNICALL
duke@0 143 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
duke@0 144 jstring host) {
duke@0 145 const char *hostname;
duke@0 146 jobjectArray ret = 0;
duke@0 147 int retLen = 0;
duke@0 148 jboolean preferIPv6Address;
duke@0 149
duke@0 150 int error=0;
duke@0 151 #ifdef AF_INET6
duke@0 152 struct addrinfo hints, *res, *resNew = NULL;
duke@0 153 #endif /* AF_INET6 */
duke@0 154
duke@0 155 if (!initialized) {
duke@0 156 ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
duke@0 157 ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
duke@0 158 ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
duke@0 159 ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
duke@0 160 ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
duke@0 161 ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
duke@0 162 ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
duke@0 163 ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
duke@0 164 ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I");
duke@0 165 ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I");
duke@0 166 ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;");
duke@0 167 ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
duke@0 168 initialized = 1;
duke@0 169 }
duke@0 170
duke@0 171 if (IS_NULL(host)) {
duke@0 172 JNU_ThrowNullPointerException(env, "host is null");
duke@0 173 return 0;
duke@0 174 }
duke@0 175 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
duke@0 176 CHECK_NULL_RETURN(hostname, NULL);
duke@0 177
duke@0 178 #ifdef AF_INET6
duke@0 179 if (NET_addrtransAvailable()) {
duke@0 180 static jfieldID ia_preferIPv6AddressID;
duke@0 181 if (ia_preferIPv6AddressID == NULL) {
duke@0 182 jclass c = (*env)->FindClass(env,"java/net/InetAddress");
duke@0 183 if (c) {
duke@0 184 ia_preferIPv6AddressID =
duke@0 185 (*env)->GetStaticFieldID(env, c, "preferIPv6Address", "Z");
duke@0 186 }
duke@0 187 if (ia_preferIPv6AddressID == NULL) {
duke@0 188 JNU_ReleaseStringPlatformChars(env, host, hostname);
duke@0 189 return NULL;
duke@0 190 }
duke@0 191 }
duke@0 192 /* get the address preference */
duke@0 193 preferIPv6Address
duke@0 194 = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
duke@0 195
duke@0 196 /* Try once, with our static buffer. */
duke@0 197 bzero(&hints, sizeof(hints));
duke@0 198 hints.ai_flags = AI_CANONNAME;
duke@0 199 hints.ai_family = AF_UNSPEC;
duke@0 200
chegar@892 201 #ifdef __solaris__
duke@0 202 /*
duke@0 203 * Workaround for Solaris bug 4160367 - if a hostname contains a
duke@0 204 * white space then 0.0.0.0 is returned
duke@0 205 */
chegar@892 206 if (isspace((unsigned char)hostname[0])) {
duke@0 207 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
martin@2801 208 hostname);
duke@0 209 JNU_ReleaseStringPlatformChars(env, host, hostname);
duke@0 210 return NULL;
duke@0 211 }
chegar@892 212 #endif
duke@0 213
duke@0 214 error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
duke@0 215
duke@0 216 if (error) {
duke@0 217 /* report error */
martin@2801 218 ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
duke@0 219 JNU_ReleaseStringPlatformChars(env, host, hostname);
duke@0 220 return NULL;
duke@0 221 } else {
duke@0 222 int i = 0;
duke@0 223 int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
chegar@453 224 struct addrinfo *itr, *last = NULL, *iterator = res;
duke@0 225 while (iterator != NULL) {
duke@0 226 int skip = 0;
duke@0 227 itr = resNew;
duke@0 228 while (itr != NULL) {
duke@0 229 if (iterator->ai_family == itr->ai_family &&
duke@0 230 iterator->ai_addrlen == itr->ai_addrlen) {
duke@0 231 if (itr->ai_family == AF_INET) { /* AF_INET */
duke@0 232 struct sockaddr_in *addr1, *addr2;
duke@0 233 addr1 = (struct sockaddr_in *)iterator->ai_addr;
duke@0 234 addr2 = (struct sockaddr_in *)itr->ai_addr;
duke@0 235 if (addr1->sin_addr.s_addr ==
duke@0 236 addr2->sin_addr.s_addr) {
duke@0 237 skip = 1;
duke@0 238 break;
duke@0 239 }
duke@0 240 } else {
duke@0 241 int t;
duke@0 242 struct sockaddr_in6 *addr1, *addr2;
duke@0 243 addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
duke@0 244 addr2 = (struct sockaddr_in6 *)itr->ai_addr;
duke@0 245
duke@0 246 for (t = 0; t < 16; t++) {
duke@0 247 if (addr1->sin6_addr.s6_addr[t] !=
duke@0 248 addr2->sin6_addr.s6_addr[t]) {
duke@0 249 break;
duke@0 250 }
duke@0 251 }
duke@0 252 if (t < 16) {
duke@0 253 itr = itr->ai_next;
duke@0 254 continue;
duke@0 255 } else {
duke@0 256 skip = 1;
duke@0 257 break;
duke@0 258 }
duke@0 259 }
duke@0 260 } else if (iterator->ai_family != AF_INET &&
duke@0 261 iterator->ai_family != AF_INET6) {
duke@0 262 /* we can't handle other family types */
duke@0 263 skip = 1;
duke@0 264 break;
duke@0 265 }
duke@0 266 itr = itr->ai_next;
duke@0 267 }
duke@0 268
duke@0 269 if (!skip) {
duke@0 270 struct addrinfo *next
duke@0 271 = (struct addrinfo*) malloc(sizeof(struct addrinfo));
duke@0 272 if (!next) {
zhouyx@5400 273 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
duke@0 274 ret = NULL;
duke@0 275 goto cleanupAndReturn;
duke@0 276 }
duke@0 277 memcpy(next, iterator, sizeof(struct addrinfo));
duke@0 278 next->ai_next = NULL;
duke@0 279 if (resNew == NULL) {
duke@0 280 resNew = next;
duke@0 281 } else {
duke@0 282 last->ai_next = next;
duke@0 283 }
duke@0 284 last = next;
duke@0 285 i++;
duke@0 286 if (iterator->ai_family == AF_INET) {
duke@0 287 inetCount ++;
duke@0 288 } else if (iterator->ai_family == AF_INET6) {
duke@0 289 inet6Count ++;
duke@0 290 }
duke@0 291 }
duke@0 292 iterator = iterator->ai_next;
duke@0 293 }
duke@0 294 retLen = i;
duke@0 295 iterator = resNew;
duke@0 296
duke@0 297 ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
duke@0 298
duke@0 299 if (IS_NULL(ret)) {
duke@0 300 /* we may have memory to free at the end of this */
duke@0 301 goto cleanupAndReturn;
duke@0 302 }
duke@0 303
duke@0 304 if (preferIPv6Address) {
duke@0 305 /* AF_INET addresses will be offset by inet6Count */
duke@0 306 inetIndex = inet6Count;
duke@0 307 inet6Index = 0;
duke@0 308 } else {
duke@0 309 /* AF_INET6 addresses will be offset by inetCount */
duke@0 310 inetIndex = 0;
duke@0 311 inet6Index = inetCount;
duke@0 312 }
duke@0 313
duke@0 314 while (iterator != NULL) {
duke@0 315 if (iterator->ai_family == AF_INET) {
duke@0 316 jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
duke@0 317 if (IS_NULL(iaObj)) {
duke@0 318 ret = NULL;
duke@0 319 goto cleanupAndReturn;
duke@0 320 }
duke@0 321 (*env)->SetIntField(env, iaObj, ni_iaaddressID,
duke@0 322 ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
chegar@373 323 (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
duke@0 324 (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
duke@0 325 inetIndex++;
duke@0 326 } else if (iterator->ai_family == AF_INET6) {
duke@0 327 jint scope = 0;
duke@0 328 jbyteArray ipaddress;
duke@0 329
duke@0 330 jobject iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
duke@0 331 if (IS_NULL(iaObj)) {
duke@0 332 ret = NULL;
duke@0 333 goto cleanupAndReturn;
duke@0 334 }
duke@0 335 ipaddress = (*env)->NewByteArray(env, 16);
duke@0 336 if (IS_NULL(ipaddress)) {
duke@0 337 ret = NULL;
duke@0 338 goto cleanupAndReturn;
duke@0 339 }
duke@0 340 (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
duke@0 341 (jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
duke@0 342 #ifdef __linux__
duke@0 343 if (!kernelIsV22()) {
duke@0 344 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
duke@0 345 }
duke@0 346 #else
duke@0 347 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
duke@0 348 #endif
duke@0 349 if (scope != 0) { /* zero is default value, no need to set */
duke@0 350 (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
duke@0 351 (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
duke@0 352 }
duke@0 353 (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
chegar@373 354 (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
duke@0 355 (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
duke@0 356 inet6Index++;
duke@0 357 }
duke@0 358 iterator = iterator->ai_next;
duke@0 359 }
duke@0 360 }
duke@0 361 }
duke@0 362
duke@0 363 cleanupAndReturn:
duke@0 364 {
duke@0 365 struct addrinfo *iterator, *tmp;
duke@0 366 iterator = resNew;
duke@0 367 while (iterator != NULL) {
duke@0 368 tmp = iterator;
duke@0 369 iterator = iterator->ai_next;
duke@0 370 free(tmp);
duke@0 371 }
duke@0 372 JNU_ReleaseStringPlatformChars(env, host, hostname);
duke@0 373 }
duke@0 374
duke@0 375 if (NET_addrtransAvailable())
duke@0 376 (*freeaddrinfo_ptr)(res);
duke@0 377 #endif /* AF_INET6 */
duke@0 378
duke@0 379 return ret;
duke@0 380 }
duke@0 381
duke@0 382 /*
duke@0 383 * Class: java_net_Inet6AddressImpl
duke@0 384 * Method: getHostByAddr
duke@0 385 * Signature: (I)Ljava/lang/String;
duke@0 386 */
duke@0 387 JNIEXPORT jstring JNICALL
duke@0 388 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
duke@0 389 jbyteArray addrArray) {
duke@0 390
duke@0 391 jstring ret = NULL;
duke@0 392
duke@0 393 #ifdef AF_INET6
duke@0 394 char host[NI_MAXHOST+1];
duke@0 395 int error = 0;
duke@0 396 int len = 0;
duke@0 397 jbyte caddr[16];
duke@0 398
duke@0 399 if (NET_addrtransAvailable()) {
duke@0 400 struct sockaddr_in him4;
duke@0 401 struct sockaddr_in6 him6;
duke@0 402 struct sockaddr *sa;
duke@0 403
duke@0 404 /*
duke@0 405 * For IPv4 addresses construct a sockaddr_in structure.
duke@0 406 */
duke@0 407 if ((*env)->GetArrayLength(env, addrArray) == 4) {
duke@0 408 jint addr;
duke@0 409 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
duke@0 410 addr = ((caddr[0]<<24) & 0xff000000);
duke@0 411 addr |= ((caddr[1] <<16) & 0xff0000);
duke@0 412 addr |= ((caddr[2] <<8) & 0xff00);
duke@0 413 addr |= (caddr[3] & 0xff);
martin@2801 414 memset((void *) &him4, 0, sizeof(him4));
duke@0 415 him4.sin_addr.s_addr = (uint32_t) htonl(addr);
duke@0 416 him4.sin_family = AF_INET;
duke@0 417 sa = (struct sockaddr *) &him4;
duke@0 418 len = sizeof(him4);
duke@0 419 } else {
duke@0 420 /*
duke@0 421 * For IPv6 address construct a sockaddr_in6 structure.
duke@0 422 */
duke@0 423 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
martin@2801 424 memset((void *) &him6, 0, sizeof(him6));
duke@0 425 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
duke@0 426 him6.sin6_family = AF_INET6;
duke@0 427 sa = (struct sockaddr *) &him6 ;
duke@0 428 len = sizeof(him6) ;
duke@0 429 }
duke@0 430
duke@0 431 error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0,
duke@0 432 NI_NAMEREQD);
duke@0 433
duke@0 434 if (!error) {
duke@0 435 ret = (*env)->NewStringUTF(env, host);
duke@0 436 }
duke@0 437 }
duke@0 438 #endif /* AF_INET6 */
duke@0 439
duke@0 440 if (ret == NULL) {
duke@0 441 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
duke@0 442 }
duke@0 443
duke@0 444 return ret;
duke@0 445 }
duke@0 446
duke@0 447 #define SET_NONBLOCKING(fd) { \
duke@0 448 int flags = fcntl(fd, F_GETFL); \
duke@0 449 flags |= O_NONBLOCK; \
duke@0 450 fcntl(fd, F_SETFL, flags); \
duke@0 451 }
duke@0 452
duke@0 453 #ifdef AF_INET6
duke@0 454 static jboolean
duke@0 455 ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout,
duke@0 456 struct sockaddr_in6* netif, jint ttl) {
duke@0 457 jint size;
chegar@892 458 jint n;
chegar@892 459 socklen_t len;
duke@0 460 char sendbuf[1500];
duke@0 461 unsigned char recvbuf[1500];
duke@0 462 struct icmp6_hdr *icmp6;
duke@0 463 struct sockaddr_in6 sa_recv;
duke@0 464 jbyte *caddr, *recv_caddr;
duke@0 465 jchar pid;
duke@0 466 jint tmout2, seq = 1;
duke@0 467 struct timeval tv;
duke@0 468 size_t plen;
duke@0 469
duke@0 470 #ifdef __linux__
duke@0 471 {
duke@0 472 int csum_offset;
duke@0 473 /**
duke@0 474 * For some strange reason, the linux kernel won't calculate the
duke@0 475 * checksum of ICMPv6 packets unless you set this socket option
duke@0 476 */
duke@0 477 csum_offset = 2;
duke@0 478 setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int));
duke@0 479 }
duke@0 480 #endif
duke@0 481
duke@0 482 caddr = (jbyte *)&(him->sin6_addr);
duke@0 483
duke@0 484 /* icmp_id is a 16 bit data type, therefore down cast the pid */
duke@0 485 pid = (jchar)getpid();
duke@0 486 size = 60*1024;
duke@0 487 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
duke@0 488 if (ttl > 0) {
duke@0 489 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
duke@0 490 }
duke@0 491 if (netif != NULL) {
duke@0 492 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
duke@0 493 NET_ThrowNew(env, errno, "Can't bind socket");
duke@0 494 close(fd);
duke@0 495 return JNI_FALSE;
duke@0 496 }
duke@0 497 }
duke@0 498 SET_NONBLOCKING(fd);
duke@0 499
duke@0 500 do {
duke@0 501 icmp6 = (struct icmp6_hdr *) sendbuf;
duke@0 502 icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
duke@0 503 icmp6->icmp6_code = 0;
duke@0 504 /* let's tag the ECHO packet with our pid so we can identify it */
duke@0 505 icmp6->icmp6_id = htons(pid);
duke@0 506 icmp6->icmp6_seq = htons(seq);
duke@0 507 seq++;
duke@0 508 icmp6->icmp6_cksum = 0;
duke@0 509 gettimeofday(&tv, NULL);
duke@0 510 memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv));
duke@0 511 plen = sizeof(struct icmp6_hdr) + sizeof(tv);
duke@0 512 n = sendto(fd, sendbuf, plen, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6));
duke@0 513 if (n < 0 && errno != EINPROGRESS) {
chegar@2983 514 #ifdef __linux__
ngmr@5186 515 if (errno != EINVAL && errno != EHOSTUNREACH)
chegar@2983 516 /*
chegar@2983 517 * On some Linuxes, when bound to the loopback interface, sendto
ngmr@5186 518 * will fail and errno will be set to EINVAL or EHOSTUNREACH.
ngmr@5186 519 * When that happens, don't throw an exception, just return false.
chegar@2983 520 */
chegar@2983 521 #endif /*__linux__ */
duke@0 522 NET_ThrowNew(env, errno, "Can't send ICMP packet");
chegar@2983 523 close(fd);
duke@0 524 return JNI_FALSE;
duke@0 525 }
duke@0 526
duke@0 527 tmout2 = timeout > 1000 ? 1000 : timeout;
duke@0 528 do {
duke@0 529 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
duke@0 530
duke@0 531 if (tmout2 >= 0) {
duke@0 532 len = sizeof(sa_recv);
duke@0 533 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_recv, &len);
duke@0 534 icmp6 = (struct icmp6_hdr *) (recvbuf);
duke@0 535 recv_caddr = (jbyte *)&(sa_recv.sin6_addr);
duke@0 536 /*
duke@0 537 * We did receive something, but is it what we were expecting?
duke@0 538 * I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and
duke@0 539 * from the host that we are trying to determine is reachable.
duke@0 540 */
duke@0 541 if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
youdwei@5512 542 (ntohs(icmp6->icmp6_id) == pid)) {
youdwei@5512 543 if (NET_IsEqual(caddr, recv_caddr)) {
youdwei@5512 544 close(fd);
youdwei@5512 545 return JNI_TRUE;
youdwei@5512 546 }
youdwei@5512 547 if (NET_IsZeroAddr(caddr)) {
youdwei@5512 548 close(fd);
youdwei@5512 549 return JNI_TRUE;
youdwei@5512 550 }
duke@0 551 }
duke@0 552 }
duke@0 553 } while (tmout2 > 0);
duke@0 554 timeout -= 1000;
duke@0 555 } while (timeout > 0);
duke@0 556 close(fd);
duke@0 557 return JNI_FALSE;
duke@0 558 }
duke@0 559 #endif /* AF_INET6 */
duke@0 560
duke@0 561 /*
duke@0 562 * Class: java_net_Inet6AddressImpl
duke@0 563 * Method: isReachable0
duke@0 564 * Signature: ([bII[bI)Z
duke@0 565 */
duke@0 566 JNIEXPORT jboolean JNICALL
duke@0 567 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
duke@0 568 jbyteArray addrArray,
duke@0 569 jint scope,
duke@0 570 jint timeout,
duke@0 571 jbyteArray ifArray,
duke@0 572 jint ttl, jint if_scope) {
duke@0 573 #ifdef AF_INET6
duke@0 574 jbyte caddr[16];
duke@0 575 jint fd, sz;
duke@0 576 struct sockaddr_in6 him6;
duke@0 577 struct sockaddr_in6 inf6;
duke@0 578 struct sockaddr_in6* netif = NULL;
duke@0 579 int len = 0;
duke@0 580 int connect_rv = -1;
duke@0 581
duke@0 582 /*
duke@0 583 * If IPv6 is not enable, then we can't reach an IPv6 address, can we?
duke@0 584 */
duke@0 585 if (!ipv6_available()) {
duke@0 586 return JNI_FALSE;
duke@0 587 }
duke@0 588 /*
duke@0 589 * If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
duke@0 590 * therefore, let's delegate to the Inet4Address method.
duke@0 591 */
duke@0 592 sz = (*env)->GetArrayLength(env, addrArray);
duke@0 593 if (sz == 4) {
duke@0 594 return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
duke@0 595 addrArray,
duke@0 596 timeout,
duke@0 597 ifArray, ttl);
duke@0 598 }
duke@0 599
martin@2801 600 memset((void *) caddr, 0, 16);
martin@2801 601 memset((void *) &him6, 0, sizeof(him6));
duke@0 602 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
duke@0 603 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
duke@0 604 him6.sin6_family = AF_INET6;
duke@0 605 #ifdef __linux__
duke@0 606 if (scope > 0)
duke@0 607 him6.sin6_scope_id = scope;
duke@0 608 else
duke@0 609 him6.sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr));
duke@0 610 len = sizeof(struct sockaddr_in6);
duke@0 611 #else
duke@0 612 if (scope > 0)
duke@0 613 him6.sin6_scope_id = scope;
duke@0 614 len = sizeof(struct sockaddr_in6);
duke@0 615 #endif
duke@0 616 /*
duke@0 617 * If a network interface was specified, let's create the address
duke@0 618 * for it.
duke@0 619 */
duke@0 620 if (!(IS_NULL(ifArray))) {
martin@2801 621 memset((void *) caddr, 0, 16);
martin@2801 622 memset((void *) &inf6, 0, sizeof(inf6));
duke@0 623 (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
duke@0 624 memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
duke@0 625 inf6.sin6_family = AF_INET6;
duke@0 626 inf6.sin6_scope_id = if_scope;
duke@0 627 netif = &inf6;
duke@0 628 }
duke@0 629 /*
duke@0 630 * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST
duke@0 631 * otherwise we'll try a tcp socket to the Echo port (7).
duke@0 632 * Note that this is empiric, and not connecting could mean it's blocked
duke@0 633 * or the echo servioe has been disabled.
duke@0 634 */
duke@0 635
duke@0 636 fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
duke@0 637
duke@0 638 if (fd != -1) { /* Good to go, let's do a ping */
duke@0 639 return ping6(env, fd, &him6, timeout, netif, ttl);
duke@0 640 }
duke@0 641
duke@0 642 /* No good, let's fall back on TCP */
duke@0 643 fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0);
duke@0 644 if (fd == JVM_IO_ERR) {
duke@0 645 /* note: if you run out of fds, you may not be able to load
duke@0 646 * the exception class, and get a NoClassDefFoundError
duke@0 647 * instead.
duke@0 648 */
duke@0 649 NET_ThrowNew(env, errno, "Can't create socket");
duke@0 650 return JNI_FALSE;
duke@0 651 }
duke@0 652 if (ttl > 0) {
duke@0 653 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
duke@0 654 }
duke@0 655
duke@0 656 /*
duke@0 657 * A network interface was specified, so let's bind to it.
duke@0 658 */
duke@0 659 if (netif != NULL) {
duke@0 660 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
duke@0 661 NET_ThrowNew(env, errno, "Can't bind socket");
duke@0 662 close(fd);
duke@0 663 return JNI_FALSE;
duke@0 664 }
duke@0 665 }
duke@0 666 SET_NONBLOCKING(fd);
duke@0 667
duke@0 668 /* no need to use NET_Connect as non-blocking */
duke@0 669 him6.sin6_port = htons((short) 7); /* Echo port */
duke@0 670 connect_rv = JVM_Connect(fd, (struct sockaddr *)&him6, len);
duke@0 671
duke@0 672 /**
duke@0 673 * connection established or refused immediately, either way it means
duke@0 674 * we were able to reach the host!
duke@0 675 */
duke@0 676 if (connect_rv == 0 || errno == ECONNREFUSED) {
duke@0 677 close(fd);
duke@0 678 return JNI_TRUE;
duke@0 679 } else {
duke@0 680 int optlen;
duke@0 681
duke@0 682 switch (errno) {
duke@0 683 case ENETUNREACH: /* Network Unreachable */
duke@0 684 case EAFNOSUPPORT: /* Address Family not supported */
duke@0 685 case EADDRNOTAVAIL: /* address is not available on the remote machine */
duke@0 686 #ifdef __linux__
duke@0 687 case EINVAL:
ngmr@5186 688 case EHOSTUNREACH:
duke@0 689 /*
duke@0 690 * On some Linuxes, when bound to the loopback interface, connect
ngmr@5186 691 * will fail and errno will be set to EINVAL or EHOSTUNREACH.
ngmr@5186 692 * When that happens, don't throw an exception, just return false.
duke@0 693 */
duke@0 694 #endif /* __linux__ */
duke@0 695 close(fd);
duke@0 696 return JNI_FALSE;
duke@0 697 }
duke@0 698
duke@0 699 if (errno != EINPROGRESS) {
duke@0 700 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
duke@0 701 "connect failed");
duke@0 702 close(fd);
duke@0 703 return JNI_FALSE;
duke@0 704 }
duke@0 705
duke@0 706 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
duke@0 707
duke@0 708 if (timeout >= 0) {
duke@0 709 /* has connection been established */
duke@0 710 optlen = sizeof(connect_rv);
duke@0 711 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
duke@0 712 &optlen) <0) {
duke@0 713 connect_rv = errno;
duke@0 714 }
duke@0 715 if (connect_rv == 0 || ECONNREFUSED) {
duke@0 716 close(fd);
duke@0 717 return JNI_TRUE;
duke@0 718 }
duke@0 719 }
duke@0 720 close(fd);
duke@0 721 return JNI_FALSE;
duke@0 722 }
duke@0 723 #else /* AF_INET6 */
duke@0 724 return JNI_FALSE;
duke@0 725 #endif /* AF_INET6 */
duke@0 726 }