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