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