Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/java/net/Inet6AddressImpl.c
32287 views
1
/*
2
* Copyright (c) 2000, 2018, 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
#ifdef MACOSX
37
#include <ifaddrs.h>
38
#include <net/if.h>
39
#include <unistd.h> /* gethostname */
40
#endif
41
42
#include "jvm.h"
43
#include "jni_util.h"
44
#include "net_util.h"
45
#ifndef IPV6_DEFS_H
46
#include <netinet/icmp6.h>
47
#endif
48
49
#include "java_net_Inet4AddressImpl.h"
50
#include "java_net_Inet6AddressImpl.h"
51
52
/* the initial size of our hostent buffers */
53
#ifndef NI_MAXHOST
54
#define NI_MAXHOST 1025
55
#endif
56
57
58
/************************************************************************
59
* Inet6AddressImpl
60
*/
61
62
/*
63
* Class: java_net_Inet6AddressImpl
64
* Method: getLocalHostName
65
* Signature: ()Ljava/lang/String;
66
*/
67
JNIEXPORT jstring JNICALL
68
Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
69
char hostname[NI_MAXHOST + 1];
70
71
hostname[0] = '\0';
72
if (JVM_GetHostName(hostname, sizeof(hostname))) {
73
strcpy(hostname, "localhost");
74
#if defined(__solaris__) && defined(AF_INET6)
75
} else {
76
// try to resolve hostname via nameservice
77
// if it is known but getnameinfo fails, hostname will still be the
78
// value from gethostname
79
struct addrinfo hints, *res;
80
81
// make sure string is null-terminated
82
hostname[NI_MAXHOST] = '\0';
83
memset(&hints, 0, sizeof(hints));
84
hints.ai_flags = AI_CANONNAME;
85
hints.ai_family = AF_UNSPEC;
86
87
if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
88
getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST,
89
NULL, 0, NI_NAMEREQD);
90
freeaddrinfo(res);
91
}
92
}
93
#else
94
} else {
95
// make sure string is null-terminated
96
hostname[NI_MAXHOST] = '\0';
97
}
98
#endif
99
return (*env)->NewStringUTF(env, hostname);
100
}
101
102
#ifdef MACOSX
103
/* also called from Inet4AddressImpl.c */
104
__private_extern__ jobjectArray
105
lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6)
106
{
107
jobjectArray result = NULL;
108
char myhostname[NI_MAXHOST+1];
109
struct ifaddrs *ifa = NULL;
110
int familyOrder = 0;
111
int count = 0, i, j;
112
int addrs4 = 0, addrs6 = 0, numV4Loopbacks = 0, numV6Loopbacks = 0;
113
jboolean includeLoopback = JNI_FALSE;
114
jobject name;
115
116
initInetAddressIDs(env);
117
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
118
119
/* If the requested name matches this host's hostname, return IP addresses
120
* from all attached interfaces. (#2844683 et al) This prevents undesired
121
* PPP dialup, but may return addresses that don't actually correspond to
122
* the name (if the name actually matches something in DNS etc.
123
*/
124
myhostname[0] = '\0';
125
if (JVM_GetHostName(myhostname, NI_MAXHOST)) {
126
/* Something went wrong, maybe networking is not setup? */
127
return NULL;
128
}
129
myhostname[NI_MAXHOST] = '\0';
130
131
if (strcmp(myhostname, hostname) != 0) {
132
// Non-self lookup
133
return NULL;
134
}
135
136
if (getifaddrs(&ifa) != 0) {
137
NET_ThrowNew(env, errno, "Can't get local interface addresses");
138
return NULL;
139
}
140
141
name = (*env)->NewStringUTF(env, hostname);
142
if (name == NULL) {
143
freeifaddrs(ifa);
144
return NULL;
145
}
146
147
/* Iterate over the interfaces, and total up the number of IPv4 and IPv6
148
* addresses we have. Also keep a count of loopback addresses. We need to
149
* exclude them in the normal case, but return them if we don't get an IP
150
* address.
151
*/
152
struct ifaddrs *iter = ifa;
153
while (iter) {
154
int family = iter->ifa_addr->sa_family;
155
if (iter->ifa_name[0] != '\0' && iter->ifa_addr)
156
{
157
jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
158
if (family == AF_INET) {
159
addrs4++;
160
if (isLoopback) numV4Loopbacks++;
161
} else if (family == AF_INET6 && includeV6) {
162
addrs6++;
163
if (isLoopback) numV6Loopbacks++;
164
} else {
165
/* We don't care e.g. AF_LINK */
166
}
167
}
168
iter = iter->ifa_next;
169
}
170
171
if (addrs4 == numV4Loopbacks && addrs6 == numV6Loopbacks) {
172
// We don't have a real IP address, just loopback. We need to include
173
// loopback in our results.
174
includeLoopback = JNI_TRUE;
175
}
176
177
/* Create and fill the Java array. */
178
int arraySize = addrs4 + addrs6 -
179
(includeLoopback ? 0 : (numV4Loopbacks + numV6Loopbacks));
180
result = (*env)->NewObjectArray(env, arraySize, ia_class, NULL);
181
if (!result) goto done;
182
183
if ((*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID)) {
184
i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
185
j = 0;
186
} else {
187
i = 0;
188
j = includeLoopback ? addrs4 : (addrs4 - numV4Loopbacks);
189
}
190
191
// Now loop around the ifaddrs
192
iter = ifa;
193
while (iter != NULL) {
194
jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
195
int family = iter->ifa_addr->sa_family;
196
197
if (iter->ifa_name[0] != '\0' && iter->ifa_addr
198
&& (family == AF_INET || (family == AF_INET6 && includeV6))
199
&& (!isLoopback || includeLoopback))
200
{
201
int port;
202
int index = (family == AF_INET) ? i++ : j++;
203
jobject o = NET_SockaddrToInetAddress(env, iter->ifa_addr, &port);
204
if (!o) {
205
freeifaddrs(ifa);
206
if (!(*env)->ExceptionCheck(env))
207
JNU_ThrowOutOfMemoryError(env, "Object allocation failed");
208
return NULL;
209
}
210
setInetAddress_hostName(env, o, name);
211
if ((*env)->ExceptionCheck(env))
212
goto done;
213
(*env)->SetObjectArrayElement(env, result, index, o);
214
(*env)->DeleteLocalRef(env, o);
215
}
216
iter = iter->ifa_next;
217
}
218
219
done:
220
freeifaddrs(ifa);
221
222
return result;
223
}
224
#endif
225
226
/*
227
* Find an internet address for a given hostname. Note that this
228
* code only works for addresses of type INET. The translation
229
* of %d.%d.%d.%d to an address (int) occurs in java now, so the
230
* String "host" shouldn't *ever* be a %d.%d.%d.%d string
231
*
232
* Class: java_net_Inet6AddressImpl
233
* Method: lookupAllHostAddr
234
* Signature: (Ljava/lang/String;)[[B
235
*/
236
237
JNIEXPORT jobjectArray JNICALL
238
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
239
jstring host) {
240
const char *hostname;
241
jobjectArray ret = 0;
242
int retLen = 0;
243
244
int getaddrinfo_error=0;
245
#ifdef AF_INET6
246
struct addrinfo hints, *res, *resNew = NULL;
247
#endif /* AF_INET6 */
248
249
initInetAddressIDs(env);
250
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
251
252
if (IS_NULL(host)) {
253
JNU_ThrowNullPointerException(env, "host is null");
254
return 0;
255
}
256
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
257
CHECK_NULL_RETURN(hostname, NULL);
258
259
#ifdef AF_INET6
260
/* Try once, with our static buffer. */
261
memset(&hints, 0, sizeof(hints));
262
hints.ai_flags = AI_CANONNAME;
263
hints.ai_family = AF_UNSPEC;
264
265
#ifdef __solaris__
266
/*
267
* Workaround for Solaris bug 4160367 - if a hostname contains a
268
* white space then 0.0.0.0 is returned
269
*/
270
if (isspace((unsigned char)hostname[0])) {
271
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
272
hostname);
273
JNU_ReleaseStringPlatformChars(env, host, hostname);
274
return NULL;
275
}
276
#endif
277
278
getaddrinfo_error = getaddrinfo(hostname, NULL, &hints, &res);
279
280
#ifdef MACOSX
281
if (getaddrinfo_error) {
282
/*
283
* If getaddrinfo fails looking up the local machine, attempt to get the
284
* address from getifaddrs. This ensures we get an IPv6 address for the
285
* local machine.
286
*/
287
ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
288
if (ret != NULL || (*env)->ExceptionCheck(env)) {
289
JNU_ReleaseStringPlatformChars(env, host, hostname);
290
return ret;
291
}
292
}
293
#endif
294
295
if (getaddrinfo_error) {
296
/* report error */
297
ThrowUnknownHostExceptionWithGaiError(
298
env, hostname, getaddrinfo_error);
299
JNU_ReleaseStringPlatformChars(env, host, hostname);
300
return NULL;
301
} else {
302
int i = 0;
303
int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
304
struct addrinfo *itr, *last = NULL, *iterator = res;
305
while (iterator != NULL) {
306
int skip = 0;
307
itr = resNew;
308
while (itr != NULL) {
309
if (iterator->ai_family == itr->ai_family &&
310
iterator->ai_addrlen == itr->ai_addrlen) {
311
if (itr->ai_family == AF_INET) { /* AF_INET */
312
struct sockaddr_in *addr1, *addr2;
313
addr1 = (struct sockaddr_in *)iterator->ai_addr;
314
addr2 = (struct sockaddr_in *)itr->ai_addr;
315
if (addr1->sin_addr.s_addr ==
316
addr2->sin_addr.s_addr) {
317
skip = 1;
318
break;
319
}
320
} else {
321
int t;
322
struct sockaddr_in6 *addr1, *addr2;
323
addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
324
addr2 = (struct sockaddr_in6 *)itr->ai_addr;
325
326
for (t = 0; t < 16; t++) {
327
if (addr1->sin6_addr.s6_addr[t] !=
328
addr2->sin6_addr.s6_addr[t]) {
329
break;
330
}
331
}
332
if (t < 16) {
333
itr = itr->ai_next;
334
continue;
335
} else {
336
skip = 1;
337
break;
338
}
339
}
340
} else if (iterator->ai_family != AF_INET &&
341
iterator->ai_family != AF_INET6) {
342
/* we can't handle other family types */
343
skip = 1;
344
break;
345
}
346
itr = itr->ai_next;
347
}
348
349
if (!skip) {
350
struct addrinfo *next
351
= (struct addrinfo*) malloc(sizeof(struct addrinfo));
352
if (!next) {
353
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
354
ret = NULL;
355
goto cleanupAndReturn;
356
}
357
memcpy(next, iterator, sizeof(struct addrinfo));
358
next->ai_next = NULL;
359
if (resNew == NULL) {
360
resNew = next;
361
} else {
362
last->ai_next = next;
363
}
364
last = next;
365
i++;
366
if (iterator->ai_family == AF_INET) {
367
inetCount ++;
368
} else if (iterator->ai_family == AF_INET6) {
369
inet6Count ++;
370
}
371
}
372
iterator = iterator->ai_next;
373
}
374
retLen = i;
375
iterator = resNew;
376
377
ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
378
379
if (IS_NULL(ret)) {
380
/* we may have memory to free at the end of this */
381
goto cleanupAndReturn;
382
}
383
384
if ((*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID)) {
385
/* AF_INET addresses will be offset by inet6Count */
386
inetIndex = inet6Count;
387
inet6Index = 0;
388
} else {
389
/* AF_INET6 addresses will be offset by inetCount */
390
inetIndex = 0;
391
inet6Index = inetCount;
392
}
393
394
while (iterator != NULL) {
395
int ret1;
396
if (iterator->ai_family == AF_INET) {
397
jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
398
if (IS_NULL(iaObj)) {
399
ret = NULL;
400
goto cleanupAndReturn;
401
}
402
setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
403
if ((*env)->ExceptionCheck(env))
404
goto cleanupAndReturn;
405
setInetAddress_hostName(env, iaObj, host);
406
if ((*env)->ExceptionCheck(env))
407
goto cleanupAndReturn;
408
(*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
409
inetIndex++;
410
} else if (iterator->ai_family == AF_INET6) {
411
jint scope = 0;
412
413
jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
414
if (IS_NULL(iaObj)) {
415
ret = NULL;
416
goto cleanupAndReturn;
417
}
418
ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
419
if (!ret1) {
420
ret = NULL;
421
goto cleanupAndReturn;
422
}
423
424
scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
425
if (scope != 0) { /* zero is default value, no need to set */
426
setInet6Address_scopeid(env, iaObj, scope);
427
}
428
setInetAddress_hostName(env, iaObj, host);
429
if ((*env)->ExceptionCheck(env))
430
goto cleanupAndReturn;
431
(*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
432
inet6Index++;
433
}
434
iterator = iterator->ai_next;
435
}
436
}
437
438
cleanupAndReturn:
439
{
440
struct addrinfo *iterator, *tmp;
441
iterator = resNew;
442
while (iterator != NULL) {
443
tmp = iterator;
444
iterator = iterator->ai_next;
445
free(tmp);
446
}
447
JNU_ReleaseStringPlatformChars(env, host, hostname);
448
}
449
450
freeaddrinfo(res);
451
#endif /* AF_INET6 */
452
453
return ret;
454
}
455
456
/*
457
* Class: java_net_Inet6AddressImpl
458
* Method: getHostByAddr
459
* Signature: (I)Ljava/lang/String;
460
*/
461
JNIEXPORT jstring JNICALL
462
Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
463
jbyteArray addrArray) {
464
465
jstring ret = NULL;
466
467
#ifdef AF_INET6
468
char host[NI_MAXHOST+1];
469
int error = 0;
470
int len = 0;
471
jbyte caddr[16];
472
473
struct sockaddr_in him4;
474
struct sockaddr_in6 him6;
475
struct sockaddr *sa;
476
477
/*
478
* For IPv4 addresses construct a sockaddr_in structure.
479
*/
480
if ((*env)->GetArrayLength(env, addrArray) == 4) {
481
jint addr;
482
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
483
addr = ((caddr[0]<<24) & 0xff000000);
484
addr |= ((caddr[1] <<16) & 0xff0000);
485
addr |= ((caddr[2] <<8) & 0xff00);
486
addr |= (caddr[3] & 0xff);
487
memset((void *) &him4, 0, sizeof(him4));
488
him4.sin_addr.s_addr = (uint32_t) htonl(addr);
489
him4.sin_family = AF_INET;
490
sa = (struct sockaddr *) &him4;
491
len = sizeof(him4);
492
} else {
493
/*
494
* For IPv6 address construct a sockaddr_in6 structure.
495
*/
496
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
497
memset((void *) &him6, 0, sizeof(him6));
498
memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
499
him6.sin6_family = AF_INET6;
500
sa = (struct sockaddr *) &him6 ;
501
len = sizeof(him6) ;
502
}
503
504
error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
505
NI_NAMEREQD);
506
507
if (!error) {
508
ret = (*env)->NewStringUTF(env, host);
509
CHECK_NULL_RETURN(ret, NULL);
510
}
511
#endif /* AF_INET6 */
512
513
if (ret == NULL) {
514
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
515
}
516
517
return ret;
518
}
519
520
#define SET_NONBLOCKING(fd) { \
521
int flags = fcntl(fd, F_GETFL); \
522
flags |= O_NONBLOCK; \
523
fcntl(fd, F_SETFL, flags); \
524
}
525
526
#ifdef AF_INET6
527
static jboolean
528
ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout,
529
struct sockaddr_in6* netif, jint ttl) {
530
jint size;
531
jint n;
532
socklen_t len;
533
char sendbuf[1500];
534
unsigned char recvbuf[1500];
535
struct icmp6_hdr *icmp6;
536
struct sockaddr_in6 sa_recv;
537
jbyte *caddr, *recv_caddr;
538
jchar pid;
539
jint tmout2, seq = 1;
540
struct timeval tv;
541
size_t plen;
542
543
#ifdef __linux__
544
{
545
int csum_offset;
546
/**
547
* For some strange reason, the linux kernel won't calculate the
548
* checksum of ICMPv6 packets unless you set this socket option
549
*/
550
csum_offset = 2;
551
setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int));
552
}
553
#endif
554
555
caddr = (jbyte *)&(him->sin6_addr);
556
557
/* icmp_id is a 16 bit data type, therefore down cast the pid */
558
pid = (jchar)getpid();
559
size = 60*1024;
560
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
561
if (ttl > 0) {
562
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
563
}
564
if (netif != NULL) {
565
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
566
NET_ThrowNew(env, errno, "Can't bind socket");
567
close(fd);
568
return JNI_FALSE;
569
}
570
}
571
SET_NONBLOCKING(fd);
572
573
do {
574
icmp6 = (struct icmp6_hdr *) sendbuf;
575
icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
576
icmp6->icmp6_code = 0;
577
/* let's tag the ECHO packet with our pid so we can identify it */
578
icmp6->icmp6_id = htons(pid);
579
icmp6->icmp6_seq = htons(seq);
580
seq++;
581
icmp6->icmp6_cksum = 0;
582
gettimeofday(&tv, NULL);
583
memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv));
584
plen = sizeof(struct icmp6_hdr) + sizeof(tv);
585
n = sendto(fd, sendbuf, plen, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6));
586
if (n < 0 && errno != EINPROGRESS) {
587
#ifdef __linux__
588
if (errno != EINVAL && errno != EHOSTUNREACH)
589
/*
590
* On some Linux versions, when a socket is bound to the
591
* loopback interface, sendto will fail and errno will be
592
* set to EINVAL or EHOSTUNREACH.
593
* When that happens, don't throw an exception, just return false.
594
*/
595
#endif /*__linux__ */
596
NET_ThrowNew(env, errno, "Can't send ICMP packet");
597
close(fd);
598
return JNI_FALSE;
599
}
600
601
tmout2 = timeout > 1000 ? 1000 : timeout;
602
do {
603
tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
604
605
if (tmout2 >= 0) {
606
len = sizeof(sa_recv);
607
n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_recv, &len);
608
icmp6 = (struct icmp6_hdr *) (recvbuf);
609
recv_caddr = (jbyte *)&(sa_recv.sin6_addr);
610
/*
611
* We did receive something, but is it what we were expecting?
612
* I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and
613
* from the host that we are trying to determine is reachable.
614
*/
615
if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
616
(ntohs(icmp6->icmp6_id) == pid)) {
617
if (NET_IsEqual(caddr, recv_caddr)) {
618
close(fd);
619
return JNI_TRUE;
620
}
621
if (NET_IsZeroAddr(caddr)) {
622
close(fd);
623
return JNI_TRUE;
624
}
625
}
626
}
627
} while (tmout2 > 0);
628
timeout -= 1000;
629
} while (timeout > 0);
630
close(fd);
631
return JNI_FALSE;
632
}
633
#endif /* AF_INET6 */
634
635
/*
636
* Class: java_net_Inet6AddressImpl
637
* Method: isReachable0
638
* Signature: ([bII[bI)Z
639
*/
640
JNIEXPORT jboolean JNICALL
641
Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
642
jbyteArray addrArray,
643
jint scope,
644
jint timeout,
645
jbyteArray ifArray,
646
jint ttl, jint if_scope) {
647
#ifdef AF_INET6
648
jbyte caddr[16];
649
jint fd, sz;
650
struct sockaddr_in6 him6;
651
struct sockaddr_in6 inf6;
652
struct sockaddr_in6* netif = NULL;
653
int len = 0;
654
int connect_rv = -1;
655
656
/*
657
* If IPv6 is not enable, then we can't reach an IPv6 address, can we?
658
*/
659
if (!ipv6_available()) {
660
return JNI_FALSE;
661
}
662
/*
663
* If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
664
* therefore, let's delegate to the Inet4Address method.
665
*/
666
sz = (*env)->GetArrayLength(env, addrArray);
667
if (sz == 4) {
668
return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
669
addrArray,
670
timeout,
671
ifArray, ttl);
672
}
673
674
memset((void *) caddr, 0, 16);
675
memset((void *) &him6, 0, sizeof(him6));
676
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
677
memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
678
him6.sin6_family = AF_INET6;
679
#ifdef __linux__
680
if (scope > 0)
681
him6.sin6_scope_id = scope;
682
else
683
him6.sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr));
684
len = sizeof(struct sockaddr_in6);
685
#else
686
if (scope > 0)
687
him6.sin6_scope_id = scope;
688
len = sizeof(struct sockaddr_in6);
689
#endif
690
/*
691
* If a network interface was specified, let's create the address
692
* for it.
693
*/
694
if (!(IS_NULL(ifArray))) {
695
memset((void *) caddr, 0, 16);
696
memset((void *) &inf6, 0, sizeof(inf6));
697
(*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
698
memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
699
inf6.sin6_family = AF_INET6;
700
inf6.sin6_scope_id = if_scope;
701
netif = &inf6;
702
}
703
/*
704
* If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST
705
* otherwise we'll try a tcp socket to the Echo port (7).
706
* Note that this is empiric, and not connecting could mean it's blocked
707
* or the echo service has been disabled.
708
*/
709
710
fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
711
712
if (fd != -1) { /* Good to go, let's do a ping */
713
return ping6(env, fd, &him6, timeout, netif, ttl);
714
}
715
716
/* No good, let's fall back on TCP */
717
fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0);
718
if (fd == JVM_IO_ERR) {
719
/* note: if you run out of fds, you may not be able to load
720
* the exception class, and get a NoClassDefFoundError
721
* instead.
722
*/
723
NET_ThrowNew(env, errno, "Can't create socket");
724
return JNI_FALSE;
725
}
726
if (ttl > 0) {
727
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
728
}
729
730
/*
731
* A network interface was specified, so let's bind to it.
732
*/
733
if (netif != NULL) {
734
if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
735
NET_ThrowNew(env, errno, "Can't bind socket");
736
close(fd);
737
return JNI_FALSE;
738
}
739
}
740
SET_NONBLOCKING(fd);
741
742
/* no need to use NET_Connect as non-blocking */
743
him6.sin6_port = htons((short) 7); /* Echo port */
744
connect_rv = JVM_Connect(fd, (struct sockaddr *)&him6, len);
745
746
/**
747
* connection established or refused immediately, either way it means
748
* we were able to reach the host!
749
*/
750
if (connect_rv == 0 || errno == ECONNREFUSED) {
751
close(fd);
752
return JNI_TRUE;
753
} else {
754
int optlen;
755
756
switch (errno) {
757
case ENETUNREACH: /* Network Unreachable */
758
case EAFNOSUPPORT: /* Address Family not supported */
759
case EADDRNOTAVAIL: /* address is not available on the remote machine */
760
#ifdef __linux__
761
case EINVAL:
762
case EHOSTUNREACH:
763
/*
764
* On some Linux versions, when a socket is bound to the
765
* loopback interface, connect will fail and errno will
766
* be set to EINVAL or EHOSTUNREACH. When that happens,
767
* don't throw an exception, just return false.
768
*/
769
#endif /* __linux__ */
770
close(fd);
771
return JNI_FALSE;
772
}
773
774
if (errno != EINPROGRESS) {
775
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
776
"connect failed");
777
close(fd);
778
return JNI_FALSE;
779
}
780
781
timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
782
783
if (timeout >= 0) {
784
/* has connection been established */
785
optlen = sizeof(connect_rv);
786
if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
787
&optlen) <0) {
788
connect_rv = errno;
789
}
790
if (connect_rv == 0 || ECONNREFUSED) {
791
close(fd);
792
return JNI_TRUE;
793
}
794
}
795
close(fd);
796
return JNI_FALSE;
797
}
798
#else /* AF_INET6 */
799
return JNI_FALSE;
800
#endif /* AF_INET6 */
801
}
802
803