Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/windows/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 <malloc.h>
26
27
#include "net_util.h"
28
29
#include "java_net_InetAddress.h"
30
#include "java_net_Inet4AddressImpl.h"
31
#include "java_net_Inet6AddressImpl.h"
32
33
/*
34
* Inet6AddressImpl
35
*/
36
37
/*
38
* Class: java_net_Inet6AddressImpl
39
* Method: getLocalHostName
40
* Signature: ()Ljava/lang/String;
41
*/
42
JNIEXPORT jstring JNICALL
43
Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
44
char hostname[256];
45
46
if (gethostname(hostname, sizeof(hostname)) == -1) {
47
strcpy(hostname, "localhost");
48
}
49
return JNU_NewStringPlatform(env, hostname);
50
}
51
52
/*
53
* Class: java_net_Inet6AddressImpl
54
* Method: lookupAllHostAddr
55
* Signature: (Ljava/lang/String;)[[B
56
*/
57
JNIEXPORT jobjectArray JNICALL
58
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
59
jstring host) {
60
jobjectArray ret = NULL;
61
const char *hostname;
62
int error = 0;
63
struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL,
64
*iterator;
65
66
initInetAddressIDs(env);
67
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
68
69
if (IS_NULL(host)) {
70
JNU_ThrowNullPointerException(env, "host argument is null");
71
return NULL;
72
}
73
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
74
CHECK_NULL_RETURN(hostname, NULL);
75
76
// try once, with our static buffer
77
memset(&hints, 0, sizeof(hints));
78
hints.ai_flags = AI_CANONNAME;
79
hints.ai_family = AF_UNSPEC;
80
81
error = getaddrinfo(hostname, NULL, &hints, &res);
82
83
if (error) {
84
// report error
85
NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException",
86
hostname);
87
goto cleanupAndReturn;
88
} else {
89
int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0,
90
inet6Index = 0, originalIndex = 0;
91
int addressPreference =
92
(*env)->GetStaticIntField(env, ia_class, ia_preferIPv6AddressID);
93
iterator = res;
94
while (iterator != NULL) {
95
// skip duplicates
96
int skip = 0;
97
struct addrinfo *iteratorNew = resNew;
98
while (iteratorNew != NULL) {
99
if (iterator->ai_family == iteratorNew->ai_family &&
100
iterator->ai_addrlen == iteratorNew->ai_addrlen) {
101
if (iteratorNew->ai_family == AF_INET) { /* AF_INET */
102
struct sockaddr_in *addr1, *addr2;
103
addr1 = (struct sockaddr_in *)iterator->ai_addr;
104
addr2 = (struct sockaddr_in *)iteratorNew->ai_addr;
105
if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) {
106
skip = 1;
107
break;
108
}
109
} else {
110
int t;
111
struct sockaddr_in6 *addr1, *addr2;
112
addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
113
addr2 = (struct sockaddr_in6 *)iteratorNew->ai_addr;
114
115
for (t = 0; t < 16; t++) {
116
if (addr1->sin6_addr.s6_addr[t] !=
117
addr2->sin6_addr.s6_addr[t]) {
118
break;
119
}
120
}
121
if (t < 16) {
122
iteratorNew = iteratorNew->ai_next;
123
continue;
124
} else {
125
skip = 1;
126
break;
127
}
128
}
129
} else if (iterator->ai_family != AF_INET &&
130
iterator->ai_family != AF_INET6) {
131
// we can't handle other family types
132
skip = 1;
133
break;
134
}
135
iteratorNew = iteratorNew->ai_next;
136
}
137
138
if (!skip) {
139
struct addrinfo *next
140
= (struct addrinfo *)malloc(sizeof(struct addrinfo));
141
if (!next) {
142
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
143
ret = NULL;
144
goto cleanupAndReturn;
145
}
146
memcpy(next, iterator, sizeof(struct addrinfo));
147
next->ai_next = NULL;
148
if (resNew == NULL) {
149
resNew = next;
150
} else {
151
last->ai_next = next;
152
}
153
last = next;
154
i++;
155
if (iterator->ai_family == AF_INET) {
156
inetCount++;
157
} else if (iterator->ai_family == AF_INET6) {
158
inet6Count++;
159
}
160
}
161
iterator = iterator->ai_next;
162
}
163
164
// allocate array - at this point i contains the number of addresses
165
ret = (*env)->NewObjectArray(env, i, ia_class, NULL);
166
if (IS_NULL(ret)) {
167
/* we may have memory to free at the end of this */
168
goto cleanupAndReturn;
169
}
170
171
if (addressPreference == java_net_InetAddress_PREFER_IPV6_VALUE) {
172
inetIndex = inet6Count;
173
inet6Index = 0;
174
} else if (addressPreference == java_net_InetAddress_PREFER_IPV4_VALUE) {
175
inetIndex = 0;
176
inet6Index = inetCount;
177
} else if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) {
178
inetIndex = inet6Index = originalIndex = 0;
179
}
180
181
iterator = resNew;
182
while (iterator != NULL) {
183
if (iterator->ai_family == AF_INET) {
184
jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
185
if (IS_NULL(iaObj)) {
186
ret = NULL;
187
goto cleanupAndReturn;
188
}
189
setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
190
if ((*env)->ExceptionCheck(env))
191
goto cleanupAndReturn;
192
setInetAddress_hostName(env, iaObj, host);
193
if ((*env)->ExceptionCheck(env))
194
goto cleanupAndReturn;
195
(*env)->SetObjectArrayElement(env, ret, (inetIndex | originalIndex), iaObj);
196
inetIndex++;
197
} else if (iterator->ai_family == AF_INET6) {
198
jint scope = 0;
199
jboolean ret1;
200
jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
201
if (IS_NULL(iaObj)) {
202
ret = NULL;
203
goto cleanupAndReturn;
204
}
205
ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
206
if (ret1 == JNI_FALSE) {
207
ret = NULL;
208
goto cleanupAndReturn;
209
}
210
scope = ((struct sockaddr_in6 *)iterator->ai_addr)->sin6_scope_id;
211
if (scope != 0) { // zero is default value, no need to set
212
setInet6Address_scopeid(env, iaObj, scope);
213
}
214
setInetAddress_hostName(env, iaObj, host);
215
if ((*env)->ExceptionCheck(env))
216
goto cleanupAndReturn;
217
(*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj);
218
inet6Index++;
219
}
220
if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) {
221
originalIndex++;
222
inetIndex = inet6Index = 0;
223
}
224
iterator = iterator->ai_next;
225
}
226
}
227
cleanupAndReturn:
228
JNU_ReleaseStringPlatformChars(env, host, hostname);
229
while (resNew != NULL) {
230
last = resNew;
231
resNew = resNew->ai_next;
232
free(last);
233
}
234
if (res != NULL) {
235
freeaddrinfo(res);
236
}
237
return ret;
238
}
239
240
/*
241
* Class: java_net_Inet6AddressImpl
242
* Method: getHostByAddr
243
* Signature: ([B)Ljava/lang/String;
244
*
245
* Theoretically the UnknownHostException could be enriched with gai error
246
* information. But as it is silently ignored anyway, there's no need for this.
247
* It's only important that either a valid hostname is returned or an
248
* UnknownHostException is thrown.
249
*/
250
JNIEXPORT jstring JNICALL
251
Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
252
jbyteArray addrArray) {
253
jstring ret = NULL;
254
char host[NI_MAXHOST + 1];
255
int len = 0;
256
jbyte caddr[16];
257
SOCKETADDRESS sa;
258
259
memset((void *)&sa, 0, sizeof(SOCKETADDRESS));
260
261
// construct a sockaddr_in structure (AF_INET or AF_INET6)
262
if ((*env)->GetArrayLength(env, addrArray) == 4) {
263
jint addr;
264
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
265
addr = ((caddr[0] << 24) & 0xff000000);
266
addr |= ((caddr[1] << 16) & 0xff0000);
267
addr |= ((caddr[2] << 8) & 0xff00);
268
addr |= (caddr[3] & 0xff);
269
sa.sa4.sin_addr.s_addr = htonl(addr);
270
sa.sa4.sin_family = AF_INET;
271
len = sizeof(struct sockaddr_in);
272
} else {
273
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
274
memcpy((void *)&sa.sa6.sin6_addr, caddr, sizeof(struct in6_addr));
275
sa.sa6.sin6_family = AF_INET6;
276
len = sizeof(struct sockaddr_in6);
277
}
278
279
if (getnameinfo(&sa.sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) {
280
JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
281
} else {
282
ret = (*env)->NewStringUTF(env, host);
283
if (ret == NULL) {
284
JNU_ThrowByName(env, "java/net/UnknownHostException", NULL);
285
}
286
}
287
288
return ret;
289
}
290
291
/**
292
* ping implementation using tcp port 7 (echo)
293
*/
294
static jboolean
295
tcp_ping6(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout,
296
jint ttl)
297
{
298
jint fd;
299
int connect_rv = -1;
300
WSAEVENT hEvent;
301
302
// open a TCP socket
303
fd = NET_Socket(AF_INET6, SOCK_STREAM, 0);
304
if (fd == SOCKET_ERROR) {
305
// note: if you run out of fds, you may not be able to load
306
// the exception class, and get a NoClassDefFoundError instead.
307
NET_ThrowNew(env, WSAGetLastError(), "Can't create socket");
308
return JNI_FALSE;
309
}
310
311
// set TTL
312
if (ttl > 0) {
313
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl));
314
}
315
316
// A network interface was specified, so let's bind to it.
317
if (netif != NULL) {
318
if (bind(fd, &netif->sa, sizeof(struct sockaddr_in6)) < 0) {
319
NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface");
320
closesocket(fd);
321
return JNI_FALSE;
322
}
323
}
324
325
// Make the socket non blocking so we can use select/poll.
326
hEvent = WSACreateEvent();
327
WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
328
329
sa->sa6.sin6_port = htons(7); // echo port
330
connect_rv = connect(fd, &sa->sa, sizeof(struct sockaddr_in6));
331
332
// connection established or refused immediately, either way it means
333
// we were able to reach the host!
334
if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) {
335
WSACloseEvent(hEvent);
336
closesocket(fd);
337
return JNI_TRUE;
338
}
339
340
switch (WSAGetLastError()) {
341
case WSAEHOSTUNREACH: // Host Unreachable
342
case WSAENETUNREACH: // Network Unreachable
343
case WSAENETDOWN: // Network is down
344
case WSAEPFNOSUPPORT: // Protocol Family unsupported
345
WSACloseEvent(hEvent);
346
closesocket(fd);
347
return JNI_FALSE;
348
case WSAEWOULDBLOCK: // this is expected as we'll probably have to wait
349
break;
350
default:
351
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
352
"connect failed");
353
WSACloseEvent(hEvent);
354
closesocket(fd);
355
return JNI_FALSE;
356
}
357
358
timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
359
if (timeout >= 0) {
360
// connection has been established, check for error condition
361
int optlen = sizeof(connect_rv);
362
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&connect_rv,
363
&optlen) < 0)
364
{
365
connect_rv = WSAGetLastError();
366
}
367
if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) {
368
WSACloseEvent(hEvent);
369
closesocket(fd);
370
return JNI_TRUE;
371
}
372
}
373
WSACloseEvent(hEvent);
374
closesocket(fd);
375
return JNI_FALSE;
376
}
377
378
/**
379
* ping implementation.
380
* Send a ICMP_ECHO_REQUEST packet every second until either the timeout
381
* expires or a answer is received.
382
* Returns true is an ECHO_REPLY is received, otherwise, false.
383
*/
384
static jboolean
385
ping6(JNIEnv *env, HANDLE hIcmpFile, SOCKETADDRESS *sa,
386
SOCKETADDRESS *netif, jint timeout)
387
{
388
DWORD dwRetVal = 0;
389
char SendData[32] = {0};
390
LPVOID ReplyBuffer = NULL;
391
DWORD ReplySize = 0;
392
IP_OPTION_INFORMATION ipInfo = {255, 0, 0, 0, NULL};
393
SOCKETADDRESS dftNetif;
394
395
ReplySize = sizeof(ICMPV6_ECHO_REPLY) + sizeof(SendData);
396
ReplyBuffer = (VOID *)malloc(ReplySize);
397
if (ReplyBuffer == NULL) {
398
IcmpCloseHandle(hIcmpFile);
399
NET_ThrowNew(env, -1, "Unable to allocate memory");
400
return JNI_FALSE;
401
}
402
403
//define local source information
404
if (netif == NULL) {
405
dftNetif.sa6.sin6_addr = in6addr_any;
406
dftNetif.sa6.sin6_family = AF_INET6;
407
dftNetif.sa6.sin6_flowinfo = 0;
408
dftNetif.sa6.sin6_port = 0;
409
netif = &dftNetif;
410
}
411
412
dwRetVal = Icmp6SendEcho2(hIcmpFile, // HANDLE IcmpHandle,
413
NULL, // HANDLE Event,
414
NULL, // PIO_APC_ROUTINE ApcRoutine,
415
NULL, // PVOID ApcContext,
416
&netif->sa6, // struct sockaddr_in6 *SourceAddress,
417
&sa->sa6, // struct sockaddr_in6 *DestinationAddress,
418
SendData, // LPVOID RequestData,
419
sizeof(SendData), // WORD RequestSize,
420
&ipInfo, // PIP_OPTION_INFORMATION RequestOptions,
421
ReplyBuffer, // LPVOID ReplyBuffer,
422
ReplySize, // DWORD ReplySize,
423
timeout); // DWORD Timeout
424
425
free(ReplyBuffer);
426
IcmpCloseHandle(hIcmpFile);
427
428
if (dwRetVal == 0) { // if the call failed
429
return JNI_FALSE;
430
} else {
431
return JNI_TRUE;
432
}
433
}
434
435
/*
436
* Class: java_net_Inet6AddressImpl
437
* Method: isReachable0
438
* Signature: ([BII[BII)Z
439
*/
440
JNIEXPORT jboolean JNICALL
441
Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
442
jbyteArray addrArray, jint scope,
443
jint timeout, jbyteArray ifArray,
444
jint ttl, jint if_scope)
445
{
446
jbyte caddr[16];
447
jint sz;
448
SOCKETADDRESS sa, inf, *netif = NULL;
449
HANDLE hIcmpFile;
450
451
// If IPv6 is not enabled, then we can't reach an IPv6 address, can we?
452
// Actually, we probably shouldn't even get here.
453
if (!ipv6_available()) {
454
return JNI_FALSE;
455
}
456
457
// If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
458
// therefore, let's delegate to the Inet4Address method.
459
sz = (*env)->GetArrayLength(env, addrArray);
460
if (sz == 4) {
461
return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
462
addrArray, timeout,
463
ifArray, ttl);
464
}
465
466
// load address to SOCKETADDRESS
467
memset((char *)caddr, 0, 16);
468
(*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
469
memset((char *)&sa, 0, sizeof(SOCKETADDRESS));
470
memcpy((void *)&sa.sa6.sin6_addr, caddr, sizeof(struct in6_addr));
471
sa.sa6.sin6_family = AF_INET6;
472
if (scope > 0) {
473
sa.sa6.sin6_scope_id = scope;
474
}
475
476
// load network interface address to SOCKETADDRESS, if specified
477
if (!(IS_NULL(ifArray))) {
478
memset((char *)caddr, 0, 16);
479
(*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
480
memset((char *)&inf, 0, sizeof(SOCKETADDRESS));
481
memcpy((void *)&inf.sa6.sin6_addr, caddr, sizeof(struct in6_addr));
482
inf.sa6.sin6_family = AF_INET6;
483
inf.sa6.sin6_scope_id = if_scope;
484
netif = &inf;
485
}
486
487
// Let's try to create an ICMP handle.
488
hIcmpFile = Icmp6CreateFile();
489
if (hIcmpFile == INVALID_HANDLE_VALUE) {
490
int err = WSAGetLastError();
491
if (err == ERROR_ACCESS_DENIED) {
492
// fall back to TCP echo if access is denied to ICMP
493
return tcp_ping6(env, &sa, netif, timeout, ttl);
494
} else {
495
NET_ThrowNew(env, err, "Unable to create ICMP file handle");
496
return JNI_FALSE;
497
}
498
} else {
499
// It didn't fail, so we can use ICMP.
500
return ping6(env, hIcmpFile, &sa, netif, timeout);
501
}
502
}
503
504