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