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