Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/unix/native/libnio/ch/Net.c
41133 views
1
/*
2
* Copyright (c) 2001, 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
26
#include <poll.h>
27
#include <sys/types.h>
28
#include <sys/socket.h>
29
#include <string.h>
30
#include <netinet/in.h>
31
#include <netinet/tcp.h>
32
#include <limits.h>
33
34
#include "jni.h"
35
#include "jni_util.h"
36
#include "jvm.h"
37
#include "jlong.h"
38
#include "sun_nio_ch_Net.h"
39
#include "net_util.h"
40
#include "net_util_md.h"
41
#include "nio_util.h"
42
#include "nio.h"
43
44
#ifdef _AIX
45
#include <stdlib.h>
46
#include <sys/utsname.h>
47
#endif
48
49
/**
50
* IP_MULTICAST_ALL supported since 2.6.31 but may not be available at
51
* build time.
52
*/
53
#ifdef __linux__
54
#ifndef IP_MULTICAST_ALL
55
#define IP_MULTICAST_ALL 49
56
#endif
57
#endif
58
59
/**
60
* IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP may not be defined on OSX and AIX
61
*/
62
#if defined(__APPLE__) || defined(_AIX)
63
#ifndef IPV6_ADD_MEMBERSHIP
64
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
65
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
66
#endif
67
#endif
68
69
#define COPY_INET6_ADDRESS(env, source, target) \
70
(*env)->GetByteArrayRegion(env, source, 0, 16, target)
71
72
/*
73
* Copy IPv6 group, interface index, and IPv6 source address
74
* into group_source_req structure.
75
*/
76
static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index,
77
jbyteArray source, struct group_source_req *req)
78
{
79
struct sockaddr_in6* sin6;
80
81
req->gsr_interface = (uint32_t)index;
82
83
sin6 = (struct sockaddr_in6 *)&(req->gsr_group);
84
sin6->sin6_family = AF_INET6;
85
COPY_INET6_ADDRESS(env, group, (jbyte *)&(sin6->sin6_addr));
86
87
sin6 = (struct sockaddr_in6 *)&(req->gsr_source);
88
sin6->sin6_family = AF_INET6;
89
COPY_INET6_ADDRESS(env, source, (jbyte *)&(sin6->sin6_addr));
90
}
91
92
#ifdef _AIX
93
94
/*
95
* Checks whether or not "socket extensions for multicast source filters" is supported.
96
* Returns JNI_TRUE if it is supported, JNI_FALSE otherwise
97
*/
98
static jboolean isSourceFilterSupported(){
99
static jboolean alreadyChecked = JNI_FALSE;
100
static jboolean result = JNI_TRUE;
101
if (alreadyChecked != JNI_TRUE){
102
struct utsname uts;
103
memset(&uts, 0, sizeof(uts));
104
strcpy(uts.sysname, "?");
105
const int utsRes = uname(&uts);
106
int major = -1;
107
int minor = -1;
108
major = atoi(uts.version);
109
minor = atoi(uts.release);
110
if (strcmp(uts.sysname, "AIX") == 0) {
111
if (major < 6 || (major == 6 && minor < 1)) {// unsupported on aix < 6.1
112
result = JNI_FALSE;
113
}
114
}
115
alreadyChecked = JNI_TRUE;
116
}
117
return result;
118
}
119
120
#endif /* _AIX */
121
122
static jclass isa_class; /* java.net.InetSocketAddress */
123
static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
124
125
JNIEXPORT void JNICALL
126
Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
127
{
128
jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
129
CHECK_NULL(cls);
130
isa_class = (*env)->NewGlobalRef(env, cls);
131
if (isa_class == NULL) {
132
JNU_ThrowOutOfMemoryError(env, NULL);
133
return;
134
}
135
isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/net/InetAddress;I)V");
136
CHECK_NULL(isa_ctorID);
137
138
initInetAddressIDs(env);
139
}
140
141
JNIEXPORT jboolean JNICALL
142
Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
143
{
144
return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
145
}
146
147
JNIEXPORT jboolean JNICALL
148
Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1)
149
{
150
return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
151
}
152
153
JNIEXPORT jint JNICALL
154
Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
155
return -1;
156
}
157
158
JNIEXPORT jboolean JNICALL
159
Java_sun_nio_ch_Net_shouldSetBothIPv4AndIPv6Options0(JNIEnv* env, jclass cl)
160
{
161
#if defined(__linux__)
162
/* Set both IPv4 and IPv6 socket options when setting multicast options */
163
return JNI_TRUE;
164
#else
165
/* Do not set both IPv4 and IPv6 socket options when setting multicast options */
166
return JNI_FALSE;
167
#endif
168
}
169
170
JNIEXPORT jboolean JNICALL
171
Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
172
{
173
#if defined(__linux__) || defined(__APPLE__)
174
/* IPv6 sockets can join IPv4 multicast groups */
175
return JNI_TRUE;
176
#else
177
/* IPv6 sockets cannot join IPv4 multicast groups */
178
return JNI_FALSE;
179
#endif
180
}
181
182
JNIEXPORT jboolean JNICALL
183
Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
184
{
185
#if defined(__APPLE__)
186
/* IPV6_ADD_MEMBERSHIP can be used to join IPv4 multicast groups */
187
return JNI_TRUE;
188
#else
189
/* IPV6_ADD_MEMBERSHIP cannot be used to join IPv4 multicast groups */
190
return JNI_FALSE;
191
#endif
192
}
193
194
JNIEXPORT jboolean JNICALL
195
Java_sun_nio_ch_Net_canUseIPv6OptionsWithIPv4LocalAddress0(JNIEnv* env, jclass cl)
196
{
197
/* IPV6_XXX socket options can be used on IPv6 sockets bound to IPv4 address */
198
return JNI_TRUE;
199
}
200
201
JNIEXPORT jint JNICALL
202
Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
203
jboolean stream, jboolean reuse, jboolean ignored)
204
{
205
int fd;
206
int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
207
int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
208
209
fd = socket(domain, type, 0);
210
if (fd < 0) {
211
return handleSocketError(env, errno);
212
}
213
214
/*
215
* If IPv4 is available, disable IPV6_V6ONLY to ensure dual-socket support.
216
*/
217
if (domain == AF_INET6 && ipv4_available()) {
218
int arg = 0;
219
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
220
sizeof(int)) < 0) {
221
JNU_ThrowByNameWithLastError(env,
222
JNU_JAVANETPKG "SocketException",
223
"Unable to set IPV6_V6ONLY");
224
close(fd);
225
return -1;
226
}
227
}
228
229
if (reuse) {
230
int arg = 1;
231
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
232
sizeof(arg)) < 0) {
233
JNU_ThrowByNameWithLastError(env,
234
JNU_JAVANETPKG "SocketException",
235
"Unable to set SO_REUSEADDR");
236
close(fd);
237
return -1;
238
}
239
}
240
241
#if defined(__linux__)
242
if (type == SOCK_DGRAM) {
243
int arg = 0;
244
int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
245
if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
246
(errno != ENOPROTOOPT)) {
247
JNU_ThrowByNameWithLastError(env,
248
JNU_JAVANETPKG "SocketException",
249
"Unable to set IP_MULTICAST_ALL");
250
close(fd);
251
return -1;
252
}
253
}
254
255
/* By default, Linux uses the route default */
256
if (domain == AF_INET6 && type == SOCK_DGRAM) {
257
int arg = 1;
258
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
259
sizeof(arg)) < 0) {
260
JNU_ThrowByNameWithLastError(env,
261
JNU_JAVANETPKG "SocketException",
262
"Unable to set IPV6_MULTICAST_HOPS");
263
close(fd);
264
return -1;
265
}
266
}
267
#endif
268
269
#ifdef __APPLE__
270
/**
271
* Attempt to set SO_SNDBUF to a minimum size to allow sending large datagrams
272
* (net.inet.udp.maxdgram defaults to 9216).
273
*/
274
if (type == SOCK_DGRAM) {
275
int size;
276
socklen_t arglen = sizeof(size);
277
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, &arglen) == 0) {
278
int minSize = (domain == AF_INET6) ? 65527 : 65507;
279
if (size < minSize) {
280
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &minSize, sizeof(minSize));
281
}
282
}
283
}
284
#endif
285
286
return fd;
287
}
288
289
JNIEXPORT void JNICALL
290
Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,
291
jboolean useExclBind, jobject iao, int port)
292
{
293
SOCKETADDRESS sa;
294
int sa_len = 0;
295
int rv = 0;
296
297
if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
298
preferIPv6) != 0) {
299
return;
300
}
301
302
rv = NET_Bind(fdval(env, fdo), &sa, sa_len);
303
if (rv != 0) {
304
handleSocketError(env, errno);
305
}
306
}
307
308
JNIEXPORT void JNICALL
309
Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
310
{
311
if (listen(fdval(env, fdo), backlog) < 0)
312
handleSocketError(env, errno);
313
}
314
315
JNIEXPORT jint JNICALL
316
Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
317
jobject fdo, jobject iao, jint port)
318
{
319
SOCKETADDRESS sa;
320
int sa_len = 0;
321
int rv;
322
323
if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) {
324
return IOS_THROWN;
325
}
326
327
rv = connect(fdval(env, fdo), &sa.sa, sa_len);
328
if (rv != 0) {
329
if (errno == EINPROGRESS) {
330
return IOS_UNAVAILABLE;
331
} else if (errno == EINTR) {
332
return IOS_INTERRUPTED;
333
}
334
return handleSocketError(env, errno);
335
}
336
return 1;
337
}
338
339
JNIEXPORT jint JNICALL
340
Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
341
jobjectArray isaa)
342
{
343
jint fd = fdval(env, fdo);
344
jint newfd;
345
SOCKETADDRESS sa;
346
socklen_t sa_len = sizeof(SOCKETADDRESS);
347
jobject remote_ia;
348
jint remote_port = 0;
349
jobject isa;
350
351
/* accept connection but ignore ECONNABORTED */
352
for (;;) {
353
newfd = accept(fd, &sa.sa, &sa_len);
354
if (newfd >= 0) {
355
break;
356
}
357
if (errno != ECONNABORTED) {
358
break;
359
}
360
/* ECONNABORTED => restart accept */
361
}
362
363
if (newfd < 0) {
364
if (errno == EAGAIN || errno == EWOULDBLOCK)
365
return IOS_UNAVAILABLE;
366
if (errno == EINTR)
367
return IOS_INTERRUPTED;
368
JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
369
return IOS_THROWN;
370
}
371
372
setfdval(env, newfdo, newfd);
373
374
remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
375
CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
376
377
isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port);
378
CHECK_NULL_RETURN(isa, IOS_THROWN);
379
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
380
381
return 1;
382
}
383
384
JNIEXPORT jint JNICALL
385
Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
386
{
387
SOCKETADDRESS sa;
388
socklen_t sa_len = sizeof(SOCKETADDRESS);
389
if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
390
#ifdef _ALLBSD_SOURCE
391
/*
392
* XXXBSD:
393
* ECONNRESET is specific to the BSDs. We can not return an error,
394
* as the calling Java code with raise a java.lang.Error given the expectation
395
* that getsockname() will never fail. According to the Single UNIX Specification,
396
* it shouldn't fail. As such, we just fill in generic Linux-compatible values.
397
*/
398
if (errno == ECONNRESET) {
399
bzero(&sa.sa4, sizeof(sa));
400
sa.sa4.sin_len = sizeof(struct sockaddr_in);
401
sa.sa4.sin_family = AF_INET;
402
sa.sa4.sin_port = htonl(0);
403
sa.sa4.sin_addr.s_addr = INADDR_ANY;
404
} else {
405
handleSocketError(env, errno);
406
return -1;
407
}
408
#else /* _ALLBSD_SOURCE */
409
handleSocketError(env, errno);
410
return -1;
411
#endif /* _ALLBSD_SOURCE */
412
}
413
return NET_GetPortFromSockaddr(&sa);
414
}
415
416
JNIEXPORT jobject JNICALL
417
Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
418
{
419
SOCKETADDRESS sa;
420
socklen_t sa_len = sizeof(SOCKETADDRESS);
421
int port;
422
if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
423
#ifdef _ALLBSD_SOURCE
424
/*
425
* XXXBSD:
426
* ECONNRESET is specific to the BSDs. We can not return an error,
427
* as the calling Java code with raise a java.lang.Error with the expectation
428
* that getsockname() will never fail. According to the Single UNIX Specification,
429
* it shouldn't fail. As such, we just fill in generic Linux-compatible values.
430
*/
431
if (errno == ECONNRESET) {
432
bzero(&sa.sa4, sizeof(sa));
433
sa.sa4.sin_len = sizeof(struct sockaddr_in);
434
sa.sa4.sin_family = AF_INET;
435
sa.sa4.sin_port = htonl(0);
436
sa.sa4.sin_addr.s_addr = INADDR_ANY;
437
} else {
438
handleSocketError(env, errno);
439
return NULL;
440
}
441
#else /* _ALLBSD_SOURCE */
442
handleSocketError(env, errno);
443
return NULL;
444
#endif /* _ALLBSD_SOURCE */
445
}
446
return NET_SockaddrToInetAddress(env, &sa, &port);
447
}
448
449
JNIEXPORT jint JNICALL
450
Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo)
451
{
452
SOCKETADDRESS sa;
453
socklen_t sa_len = sizeof(sa);
454
455
if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
456
handleSocketError(env, errno);
457
return IOS_THROWN;
458
}
459
return NET_GetPortFromSockaddr(&sa);
460
}
461
462
JNIEXPORT jobject JNICALL
463
Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
464
{
465
SOCKETADDRESS sa;
466
socklen_t sa_len = sizeof(sa);
467
int port;
468
469
if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
470
handleSocketError(env, errno);
471
return NULL;
472
}
473
return NET_SockaddrToInetAddress(env, &sa, &port);
474
}
475
476
JNIEXPORT jint JNICALL
477
Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
478
jboolean mayNeedConversion, jint level, jint opt)
479
{
480
int result;
481
struct linger linger;
482
u_char carg;
483
void *arg;
484
socklen_t arglen;
485
int n;
486
487
/* Option value is an int except for a few specific cases */
488
489
arg = (void *)&result;
490
arglen = sizeof(result);
491
492
if (level == IPPROTO_IP &&
493
(opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
494
arg = (void*)&carg;
495
arglen = sizeof(carg);
496
}
497
498
if (level == SOL_SOCKET && opt == SO_LINGER) {
499
arg = (void *)&linger;
500
arglen = sizeof(linger);
501
}
502
503
if (mayNeedConversion) {
504
n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen);
505
} else {
506
n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
507
}
508
if (n < 0) {
509
JNU_ThrowByNameWithLastError(env,
510
JNU_JAVANETPKG "SocketException",
511
"sun.nio.ch.Net.getIntOption");
512
return -1;
513
}
514
515
if (level == IPPROTO_IP &&
516
(opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))
517
{
518
return (jint)carg;
519
}
520
521
if (level == SOL_SOCKET && opt == SO_LINGER)
522
return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;
523
524
return (jint)result;
525
}
526
527
JNIEXPORT void JNICALL
528
Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
529
jboolean mayNeedConversion, jint level,
530
jint opt, jint arg, jboolean isIPv6)
531
{
532
int result;
533
struct linger linger;
534
u_char carg;
535
void *parg;
536
socklen_t arglen;
537
int n;
538
539
/* Option value is an int except for a few specific cases */
540
541
parg = (void*)&arg;
542
arglen = sizeof(arg);
543
544
if (level == IPPROTO_IP &&
545
(opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
546
parg = (void*)&carg;
547
arglen = sizeof(carg);
548
carg = (u_char)arg;
549
}
550
551
if (level == SOL_SOCKET && opt == SO_LINGER) {
552
parg = (void *)&linger;
553
arglen = sizeof(linger);
554
if (arg >= 0) {
555
linger.l_onoff = 1;
556
linger.l_linger = arg;
557
} else {
558
linger.l_onoff = 0;
559
linger.l_linger = 0;
560
}
561
}
562
563
if (mayNeedConversion) {
564
n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
565
} else {
566
n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
567
}
568
if (n < 0) {
569
JNU_ThrowByNameWithLastError(env,
570
JNU_JAVANETPKG "SocketException",
571
"sun.nio.ch.Net.setIntOption");
572
}
573
}
574
575
JNIEXPORT jint JNICALL
576
Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
577
jint group, jint interf, jint source)
578
{
579
struct ip_mreq mreq;
580
struct ip_mreq_source mreq_source;
581
int opt, n, optlen;
582
void* optval;
583
584
if (source == 0) {
585
mreq.imr_multiaddr.s_addr = htonl(group);
586
mreq.imr_interface.s_addr = htonl(interf);
587
opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
588
optval = (void*)&mreq;
589
optlen = sizeof(mreq);
590
} else {
591
592
#ifdef _AIX
593
/* check AIX for support of source filtering */
594
if (isSourceFilterSupported() != JNI_TRUE){
595
return IOS_UNAVAILABLE;
596
}
597
#endif
598
599
mreq_source.imr_multiaddr.s_addr = htonl(group);
600
mreq_source.imr_sourceaddr.s_addr = htonl(source);
601
mreq_source.imr_interface.s_addr = htonl(interf);
602
opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
603
optval = (void*)&mreq_source;
604
optlen = sizeof(mreq_source);
605
}
606
607
n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
608
#ifdef __APPLE__
609
// workaround macOS bug where IP_ADD_MEMBERSHIP fails intermittently
610
if (n < 0 && errno == ENOMEM) {
611
n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
612
}
613
#endif
614
615
if (n < 0) {
616
if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
617
return IOS_UNAVAILABLE;
618
handleSocketError(env, errno);
619
}
620
return 0;
621
}
622
623
JNIEXPORT jint JNICALL
624
Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
625
jint group, jint interf, jint source)
626
{
627
#ifdef __APPLE__
628
/* no IPv4 exclude-mode filtering for now */
629
return IOS_UNAVAILABLE;
630
#else
631
struct ip_mreq_source mreq_source;
632
int n;
633
int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
634
635
#ifdef _AIX
636
/* check AIX for support of source filtering */
637
if (isSourceFilterSupported() != JNI_TRUE){
638
return IOS_UNAVAILABLE;
639
}
640
#endif
641
642
mreq_source.imr_multiaddr.s_addr = htonl(group);
643
mreq_source.imr_sourceaddr.s_addr = htonl(source);
644
mreq_source.imr_interface.s_addr = htonl(interf);
645
646
n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
647
(void*)&mreq_source, sizeof(mreq_source));
648
if (n < 0) {
649
if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
650
return IOS_UNAVAILABLE;
651
handleSocketError(env, errno);
652
}
653
return 0;
654
#endif
655
}
656
657
JNIEXPORT jint JNICALL
658
Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
659
jbyteArray group, jint index, jbyteArray source)
660
{
661
struct ipv6_mreq mreq6;
662
struct group_source_req req;
663
int opt, n, optlen;
664
void* optval;
665
666
if (source == NULL) {
667
COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
668
mreq6.ipv6mr_interface = (int)index;
669
opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
670
optval = (void*)&mreq6;
671
optlen = sizeof(mreq6);
672
} else {
673
#ifdef __APPLE__
674
/* no IPv6 include-mode filtering for now */
675
return IOS_UNAVAILABLE;
676
#else
677
initGroupSourceReq(env, group, index, source, &req);
678
opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
679
optval = (void*)&req;
680
optlen = sizeof(req);
681
#endif
682
}
683
684
n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
685
#ifdef __APPLE__
686
// workaround macOS bug where IPV6_ADD_MEMBERSHIP fails intermittently
687
if (n < 0 && errno == ENOMEM) {
688
n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
689
}
690
#endif
691
692
if (n < 0) {
693
if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
694
return IOS_UNAVAILABLE;
695
handleSocketError(env, errno);
696
}
697
return 0;
698
}
699
700
JNIEXPORT jint JNICALL
701
Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
702
jbyteArray group, jint index, jbyteArray source)
703
{
704
#ifdef __APPLE__
705
/* no IPv6 exclude-mode filtering for now */
706
return IOS_UNAVAILABLE;
707
#else
708
struct group_source_req req;
709
int n;
710
int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
711
712
initGroupSourceReq(env, group, index, source, &req);
713
714
n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
715
(void*)&req, sizeof(req));
716
if (n < 0) {
717
if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
718
return IOS_UNAVAILABLE;
719
handleSocketError(env, errno);
720
}
721
return 0;
722
#endif
723
}
724
725
JNIEXPORT void JNICALL
726
Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
727
{
728
struct in_addr in;
729
socklen_t arglen = sizeof(struct in_addr);
730
int n;
731
732
in.s_addr = htonl(interf);
733
734
n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
735
(void*)&(in.s_addr), arglen);
736
if (n < 0) {
737
handleSocketError(env, errno);
738
}
739
}
740
741
JNIEXPORT jint JNICALL
742
Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
743
{
744
struct in_addr in;
745
socklen_t arglen = sizeof(struct in_addr);
746
int n;
747
748
n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
749
if (n < 0) {
750
handleSocketError(env, errno);
751
return -1;
752
}
753
return ntohl(in.s_addr);
754
}
755
756
JNIEXPORT void JNICALL
757
Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
758
{
759
int value = (jint)index;
760
socklen_t arglen = sizeof(value);
761
int n;
762
763
n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
764
(void*)&(index), arglen);
765
if (n < 0) {
766
handleSocketError(env, errno);
767
}
768
}
769
770
JNIEXPORT jint JNICALL
771
Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
772
{
773
int index;
774
socklen_t arglen = sizeof(index);
775
int n;
776
777
n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
778
if (n < 0) {
779
handleSocketError(env, errno);
780
return -1;
781
}
782
return (jint)index;
783
}
784
785
JNIEXPORT void JNICALL
786
Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)
787
{
788
int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
789
(jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
790
if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN))
791
handleSocketError(env, errno);
792
}
793
794
JNIEXPORT jint JNICALL
795
Java_sun_nio_ch_Net_available(JNIEnv *env, jclass cl, jobject fdo)
796
{
797
int count = 0;
798
if (NET_SocketAvailable(fdval(env, fdo), &count) != 0) {
799
handleSocketError(env, errno);
800
return IOS_THROWN;
801
}
802
return (jint) count;
803
}
804
805
JNIEXPORT jint JNICALL
806
Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout)
807
{
808
struct pollfd pfd;
809
int rv;
810
pfd.fd = fdval(env, fdo);
811
pfd.events = events;
812
if (timeout < -1) {
813
timeout = -1;
814
} else if (timeout > INT_MAX) {
815
timeout = INT_MAX;
816
}
817
rv = poll(&pfd, 1, (int)timeout);
818
819
if (rv >= 0) {
820
return pfd.revents;
821
} else if (errno == EINTR) {
822
// interrupted, no events to return
823
return 0;
824
} else {
825
handleSocketError(env, errno);
826
return IOS_THROWN;
827
}
828
}
829
830
JNIEXPORT jboolean JNICALL
831
Java_sun_nio_ch_Net_pollConnect(JNIEnv *env, jobject this, jobject fdo, jlong timeout)
832
{
833
jint fd = fdval(env, fdo);
834
struct pollfd poller;
835
int result;
836
837
poller.fd = fd;
838
poller.events = POLLOUT;
839
poller.revents = 0;
840
if (timeout < -1) {
841
timeout = -1;
842
} else if (timeout > INT_MAX) {
843
timeout = INT_MAX;
844
}
845
846
result = poll(&poller, 1, (int)timeout);
847
848
if (result > 0) {
849
int error = 0;
850
socklen_t n = sizeof(int);
851
errno = 0;
852
result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n);
853
if (result < 0) {
854
handleSocketError(env, errno);
855
return JNI_FALSE;
856
} else if (error) {
857
handleSocketError(env, error);
858
return JNI_FALSE;
859
} else if ((poller.revents & POLLHUP) != 0) {
860
handleSocketError(env, ENOTCONN);
861
return JNI_FALSE;
862
}
863
// connected
864
return JNI_TRUE;
865
} else if (result == 0 || errno == EINTR) {
866
return JNI_FALSE;
867
} else {
868
JNU_ThrowIOExceptionWithLastError(env, "poll failed");
869
return JNI_FALSE;
870
}
871
}
872
873
JNIEXPORT jshort JNICALL
874
Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this)
875
{
876
return (jshort)POLLIN;
877
}
878
879
JNIEXPORT jshort JNICALL
880
Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this)
881
{
882
return (jshort)POLLOUT;
883
}
884
885
JNIEXPORT jshort JNICALL
886
Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this)
887
{
888
return (jshort)POLLERR;
889
}
890
891
JNIEXPORT jshort JNICALL
892
Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this)
893
{
894
return (jshort)POLLHUP;
895
}
896
897
JNIEXPORT jshort JNICALL
898
Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this)
899
{
900
return (jshort)POLLNVAL;
901
}
902
903
JNIEXPORT jshort JNICALL
904
Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this)
905
{
906
return (jshort)POLLOUT;
907
}
908
909
JNIEXPORT jint JNICALL
910
Java_sun_nio_ch_Net_sendOOB(JNIEnv* env, jclass this, jobject fdo, jbyte b)
911
{
912
int n = send(fdval(env, fdo), (const void*)&b, 1, MSG_OOB);
913
return convertReturnVal(env, n, JNI_FALSE);
914
}
915
916
/* Declared in nio_util.h */
917
918
jint handleSocketError(JNIEnv *env, jint errorValue)
919
{
920
char *xn;
921
switch (errorValue) {
922
case EINPROGRESS: /* Non-blocking connect */
923
return 0;
924
#ifdef EPROTO
925
case EPROTO:
926
xn = JNU_JAVANETPKG "ProtocolException";
927
break;
928
#endif
929
case ECONNREFUSED:
930
case ETIMEDOUT:
931
case ENOTCONN:
932
xn = JNU_JAVANETPKG "ConnectException";
933
break;
934
935
case EHOSTUNREACH:
936
xn = JNU_JAVANETPKG "NoRouteToHostException";
937
break;
938
case EADDRINUSE: /* Fall through */
939
case EADDRNOTAVAIL:
940
case EACCES:
941
xn = JNU_JAVANETPKG "BindException";
942
break;
943
default:
944
xn = JNU_JAVANETPKG "SocketException";
945
break;
946
}
947
errno = errorValue;
948
JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
949
return IOS_THROWN;
950
}
951
952