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