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 */
103 static 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 */
125 static 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
149 static jclass isa_class; /* java.net.InetSocketAddress */
150 static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
151 static jclass usa_class; /* java.net.UnixSocketAddress */
152 static jmethodID usa_ctor; /* UnixSocketAddress() */
153 static jmethodID usa_ctorBytes; /* UnixSocketAddress(byte[]) */
154
155 JNIEXPORT void JNICALL
156 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
157 {
158 jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
159 CHECK_NULL(cls);
160 isa_class = (*env)->NewGlobalRef(env, cls);
161 if (isa_class == NULL) {
162 JNU_ThrowOutOfMemoryError(env, NULL);
163 return;
164 }
165 isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/net/InetAddress;I)V");
166 CHECK_NULL(isa_ctorID);
167
168 cls = (*env)->FindClass(env, "java/net/UnixSocketAddress");
169 CHECK_NULL(cls);
170 usa_class = (*env)->NewGlobalRef(env, cls);
171 if (usa_class == NULL) {
172 JNU_ThrowOutOfMemoryError(env, NULL);
173 return;
174 }
175 usa_ctor = (*env)->GetMethodID(env, cls, "<init>", "()V");
176 CHECK_NULL(usa_ctor);
177 usa_ctorBytes = (*env)->GetMethodID(env, cls, "<init>", "([B)V");
178 CHECK_NULL(usa_ctorBytes);
179
180 initInetAddressIDs(env);
181 }
182
183 JNIEXPORT jboolean JNICALL
184 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
185 {
186 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
187 }
188
189 JNIEXPORT jboolean JNICALL
190 Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1)
191 {
192 return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
193 }
194
195 JNIEXPORT jint JNICALL
196 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
197 return -1;
198 }
199
200 JNIEXPORT jboolean JNICALL
201 Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
202 {
203 #if defined(__APPLE__) || defined(_AIX)
204 /* for now IPv6 sockets cannot join IPv4 multicast groups */
205 return JNI_FALSE;
206 #else
207 return JNI_TRUE;
208 #endif
209 }
210
211 JNIEXPORT jboolean JNICALL
212 Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
213 {
214 #ifdef __solaris__
215 return JNI_TRUE;
216 #else
217 return JNI_FALSE;
218 #endif
219 }
220
221 JNIEXPORT jint JNICALL
222 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
223 jboolean stream, jboolean reuse, jboolean ignored)
224 {
225 int fd;
226 int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
227 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
228
229 fd = socket(domain, type, 0);
230 if (fd < 0) {
231 return handleSocketError(env, errno);
232 }
233
234 /*
235 * If IPv4 is available, disable IPV6_V6ONLY to ensure dual-socket support.
236 */
237 if (domain == AF_INET6 && ipv4_available()) {
238 int arg = 0;
239 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
240 sizeof(int)) < 0) {
241 JNU_ThrowByNameWithLastError(env,
242 JNU_JAVANETPKG "SocketException",
243 "Unable to set IPV6_V6ONLY");
244 close(fd);
245 return -1;
246 }
247 }
248
249 if (reuse) {
250 int arg = 1;
251 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
252 sizeof(arg)) < 0) {
253 JNU_ThrowByNameWithLastError(env,
254 JNU_JAVANETPKG "SocketException",
255 "Unable to set SO_REUSEADDR");
256 close(fd);
257 return -1;
258 }
259 }
260
261 #if defined(__linux__)
262 if (type == SOCK_DGRAM) {
263 int arg = 0;
264 int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
265 if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
266 (errno != ENOPROTOOPT)) {
267 JNU_ThrowByNameWithLastError(env,
268 JNU_JAVANETPKG "SocketException",
269 "Unable to set IP_MULTICAST_ALL");
270 close(fd);
271 return -1;
272 }
273 }
274
275 /* By default, Linux uses the route default */
276 if (domain == AF_INET6 && type == SOCK_DGRAM) {
277 int arg = 1;
278 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
279 sizeof(arg)) < 0) {
280 JNU_ThrowByNameWithLastError(env,
281 JNU_JAVANETPKG "SocketException",
282 "Unable to set IPV6_MULTICAST_HOPS");
283 close(fd);
284 return -1;
285 }
286 }
287 #endif
288 return fd;
289 }
290
291 JNIEXPORT jint JNICALL
292 Java_sun_nio_ch_Net_socket1 (JNIEnv *env, jclass clazz, jboolean stream)
293 {
294 int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
295 int fd = socket(AF_UNIX, type, 0);
296 if (fd < 0) {
297 return handleSocketError(env, errno);
298 }
299 return fd;
300 }
301
302 JNIEXPORT void JNICALL
303 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,
304 jboolean useExclBind, jobject iao, int port)
305 {
306 SOCKETADDRESS sa;
307 int sa_len = 0;
308 int rv = 0;
309
310 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
311 preferIPv6) != 0) {
312 return;
313 }
314
315 rv = NET_Bind(fdval(env, fdo), &sa, sa_len);
316 if (rv != 0) {
317 handleSocketError(env, errno);
318 }
319 }
320
321 JNIEXPORT void JNICALL
322 Java_sun_nio_ch_Net_bind1(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray uao)
323 {
324 SOCKETADDRESS sa;
325 memset(&sa, 0x00, sizeof (sa));
326 sa.sau.sun_family = AF_UNIX;
327 size_t uao_len = (* env) -> GetArrayLength(env, uao);
328 size_t sa_len = sizeof (sa.sau.sun_path);
329 if (uao_len > sa_len) {
330 // TODO: throw propper exception
331 return;
332 }
333 (* env) -> GetByteArrayRegion(env, uao, 0, uao_len, (jbyte *) sa.sau.sun_path);
334 int rv = bind(fdval(env, fdo), &sa.sa, sa_len);
335 if (rv != 0) {
336 handleSocketError(env, errno);
337 }
338 }
339
340 JNIEXPORT void JNICALL
341 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
342 {
343 if (listen(fdval(env, fdo), backlog) < 0)
344 handleSocketError(env, errno);
345 }
346
347 JNIEXPORT jint JNICALL
348 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
349 jobject fdo, jobject iao, jint port)
350 {
351 SOCKETADDRESS sa;
352 int sa_len = 0;
353 int rv;
354
355 if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) {
356 return IOS_THROWN;
357 }
358
359 rv = connect(fdval(env, fdo), &sa.sa, sa_len);
360 if (rv != 0) {
361 if (errno == EINPROGRESS) {
362 return IOS_UNAVAILABLE;
363 } else if (errno == EINTR) {
364 return IOS_INTERRUPTED;
365 }
366 return handleSocketError(env, errno);
367 }
368 return 1;
369 }
370
371 JNIEXPORT jint JNICALL
372 Java_sun_nio_ch_Net_connect1(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray uao)
373 {
374 SOCKETADDRESS sa;
375 memset(&sa, 0x00, sizeof (sa));
376 sa.sau.sun_family = AF_UNIX;
377 size_t uao_len = (* env) -> GetArrayLength(env, uao);
378 size_t sa_len = sizeof (sa.sau.sun_path);
379 if (uao_len > sa_len) {
380 // TODO: throw propper exception
381 return IOS_UNAVAILABLE;
382 }
383 (* env) -> GetByteArrayRegion(env, uao, 0, uao_len, (jbyte *) sa.sau.sun_path);
384
385 // TODO: refactoring, common method
386 int rv = connect(fdval(env, fdo), &sa.sa, sa_len);
387 if (rv != 0) {
388 if (errno == EINPROGRESS) {
389 return IOS_UNAVAILABLE;
390 } else if (errno == EINTR) {
391 return IOS_INTERRUPTED;
392 }
393 return handleSocketError(env, errno);
394 }
395 return 1;
396 }
397
398 JNIEXPORT jint JNICALL
399 Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
400 jobjectArray isaa)
401 {
402 jint fd = fdval(env, fdo);
403 jint newfd;
404 SOCKETADDRESS sa;
405 socklen_t sa_len = sizeof(SOCKETADDRESS);
406 jobject remote_ia;
407 jint remote_port = 0;
408 jobject isa;
409
410 /* accept connection but ignore ECONNABORTED */
411 for (;;) {
412 newfd = accept(fd, &sa.sa, &sa_len);
413 if (newfd >= 0) {
414 break;
415 }
416 if (errno != ECONNABORTED) {
417 break;
418 }
419 /* ECONNABORTED => restart accept */
420 }
421
422 if (newfd < 0) {
423 if (errno == EAGAIN || errno == EWOULDBLOCK)
424 return IOS_UNAVAILABLE;
425 if (errno == EINTR)
426 return IOS_INTERRUPTED;
427 JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
428 return IOS_THROWN;
429 }
430
431 setfdval(env, newfdo, newfd);
432
433 if (sa.sa.sa_family == AF_INET || sa.sa.sa_family == AF_INET6) {
434 remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
435 CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
436
437 isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port);
438 CHECK_NULL_RETURN(isa, IOS_THROWN);
439 (*env)->SetObjectArrayElement(env, isaa, 0, isa);
440
441 return 1;
442 } else if (sa.sa.sa_family == AF_UNIX) {
443 isa = (*env)->NewObject(env, usa_class, usa_ctor);
444 CHECK_NULL_RETURN(isa, IOS_THROWN);
445 (*env)->SetObjectArrayElement(env, isaa, 0, isa);
446 return 1;
447 } else {
448 return -6; // UNSUPPORTED_CASE
449 }
450 }
451
452 JNIEXPORT jint JNICALL
453 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
454 {
455 SOCKETADDRESS sa;
456 socklen_t sa_len = sizeof(SOCKETADDRESS);
457 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
458 #ifdef _ALLBSD_SOURCE
459 /*
460 * XXXBSD:
461 * ECONNRESET is specific to the BSDs. We can not return an error,
462 * as the calling Java code with raise a java.lang.Error given the expectation
463 * that getsockname() will never fail. According to the Single UNIX Specification,
464 * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
465 */
466 if (errno == ECONNRESET) {
467 bzero(&sa.sa4, sizeof(sa));
468 sa.sa4.sin_len = sizeof(struct sockaddr_in);
469 sa.sa4.sin_family = AF_INET;
470 sa.sa4.sin_port = htonl(0);
471 sa.sa4.sin_addr.s_addr = INADDR_ANY;
472 } else {
473 handleSocketError(env, errno);
474 return -1;
475 }
476 #else /* _ALLBSD_SOURCE */
477 handleSocketError(env, errno);
478 return -1;
479 #endif /* _ALLBSD_SOURCE */
480 }
481 return NET_GetPortFromSockaddr(&sa);
482 }
483
484 JNIEXPORT jobject JNICALL
485 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
486 {
487 SOCKETADDRESS sa;
488 socklen_t sa_len = sizeof(SOCKETADDRESS);
489 int port;
490 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
491 #ifdef _ALLBSD_SOURCE
492 /*
493 * XXXBSD:
494 * ECONNRESET is specific to the BSDs. We can not return an error,
495 * as the calling Java code with raise a java.lang.Error with the expectation
496 * that getsockname() will never fail. According to the Single UNIX Specification,
497 * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
498 */
499 if (errno == ECONNRESET) {
500 bzero(&sa.sa4, sizeof(sa));
501 sa.sa4.sin_len = sizeof(struct sockaddr_in);
502 sa.sa4.sin_family = AF_INET;
503 sa.sa4.sin_port = htonl(0);
504 sa.sa4.sin_addr.s_addr = INADDR_ANY;
505 } else {
506 handleSocketError(env, errno);
507 return NULL;
508 }
509 #else /* _ALLBSD_SOURCE */
510 handleSocketError(env, errno);
511 return NULL;
512 #endif /* _ALLBSD_SOURCE */
513 }
514 return NET_SockaddrToInetAddress(env, &sa, &port);
515 }
516
517 JNIEXPORT jobject JNICALL
518 Java_sun_nio_ch_Net_localSocketAddress(JNIEnv *env, jclass clazz, jobject fdo)
519 {
520 SOCKETADDRESS sa;
521 socklen_t sa_len = sizeof (SOCKETADDRESS);
522 memset(&sa, 0x00, sa_len);
523 if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) != 0) {
524 return NULL; // TODO: exception?
525 }
526
527 if (sa.sa.sa_family == AF_UNIX) {
528 jbyteArray addr = (*env)->NewByteArray(env, sizeof(sa.sau.sun_path));
529 (*env)->SetByteArrayRegion(env, addr, 0, sizeof(sa.sau.sun_path), (jbyte *) sa.sau.sun_path);
530 return (*env)->NewObject(env, usa_class, usa_ctorBytes, addr);
531 } else if (sa.sa.sa_family == AF_INET || sa.sa.sa_family == AF_INET6) {
532 jobject address = Java_sun_nio_ch_Net_localInetAddress(env, clazz, fdo);
533 jint port = Java_sun_nio_ch_Net_localPort(env, clazz, fdo);
534 return (*env)->NewObject(env, isa_class, isa_ctorID, address, port);
535 } else {
536 return NULL; // TODO: exception?
537 }
538 }
539
540 JNIEXPORT jint JNICALL
541 Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo)
542 {
543 SOCKETADDRESS sa;
544 socklen_t sa_len = sizeof(sa);
545
546 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
547 handleSocketError(env, errno);
548 return IOS_THROWN;
549 }
550 return NET_GetPortFromSockaddr(&sa);
551 }
552
553 JNIEXPORT jobject JNICALL
554 Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
555 {
556 SOCKETADDRESS sa;
557 socklen_t sa_len = sizeof(sa);
558 int port;
559
560 if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
561 handleSocketError(env, errno);
562 return NULL;
563 }
564 return NET_SockaddrToInetAddress(env, &sa, &port);
565 }
566
567 JNIEXPORT jint JNICALL
568 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
569 jboolean mayNeedConversion, jint level, jint opt)
570 {
571 int result;
572 struct linger linger;
573 u_char carg;
574 void *arg;
575 socklen_t arglen;
576 int n;
577
578 /* Option value is an int except for a few specific cases */
579
580 arg = (void *)&result;
581 arglen = sizeof(result);
582
583 if (level == IPPROTO_IP &&
584 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
585 arg = (void*)&carg;
586 arglen = sizeof(carg);
587 }
588
589 if (level == SOL_SOCKET && opt == SO_LINGER) {
590 arg = (void *)&linger;
591 arglen = sizeof(linger);
592 }
593
594 if (mayNeedConversion) {
595 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen);
596 } else {
597 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
598 }
599 if (n < 0) {
600 JNU_ThrowByNameWithLastError(env,
601 JNU_JAVANETPKG "SocketException",
602 "sun.nio.ch.Net.getIntOption");
603 return -1;
604 }
605
606 if (level == IPPROTO_IP &&
607 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))
608 {
609 return (jint)carg;
610 }
611
612 if (level == SOL_SOCKET && opt == SO_LINGER)
613 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;
614
615 return (jint)result;
616 }
617
618 JNIEXPORT void JNICALL
619 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
620 jboolean mayNeedConversion, jint level,
621 jint opt, jint arg, jboolean isIPv6)
622 {
623 int result;
624 struct linger linger;
625 u_char carg;
626 void *parg;
627 socklen_t arglen;
628 int n;
629
630 /* Option value is an int except for a few specific cases */
631
632 parg = (void*)&arg;
633 arglen = sizeof(arg);
634
635 if (level == IPPROTO_IP &&
636 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
637 parg = (void*)&carg;
638 arglen = sizeof(carg);
639 carg = (u_char)arg;
640 }
641
642 if (level == SOL_SOCKET && opt == SO_LINGER) {
643 parg = (void *)&linger;
644 arglen = sizeof(linger);
645 if (arg >= 0) {
646 linger.l_onoff = 1;
647 linger.l_linger = arg;
648 } else {
649 linger.l_onoff = 0;
650 linger.l_linger = 0;
651 }
652 }
653
654 if (mayNeedConversion) {
655 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
656 } else {
657 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
658 }
659 if (n < 0) {
660 JNU_ThrowByNameWithLastError(env,
661 JNU_JAVANETPKG "SocketException",
662 "sun.nio.ch.Net.setIntOption");
663 }
664 #ifdef __linux__
665 if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS && isIPv6) {
666 // set the V4 option also
667 setsockopt(fdval(env, fdo), IPPROTO_IP, IP_TOS, parg, arglen);
668 }
669 #endif
670 }
671
672 JNIEXPORT jint JNICALL
673 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
674 jint group, jint interf, jint source)
675 {
676 struct ip_mreq mreq;
677 struct ip_mreq_source mreq_source;
678 int opt, n, optlen;
679 void* optval;
680
681 if (source == 0) {
682 mreq.imr_multiaddr.s_addr = htonl(group);
683 mreq.imr_interface.s_addr = htonl(interf);
684 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
685 optval = (void*)&mreq;
686 optlen = sizeof(mreq);
687 } else {
688
689 #ifdef _AIX
690 /* check AIX for support of source filtering */
691 if (isSourceFilterSupported() != JNI_TRUE){
692 return IOS_UNAVAILABLE;
693 }
694 #endif
695
696 mreq_source.imr_multiaddr.s_addr = htonl(group);
697 mreq_source.imr_sourceaddr.s_addr = htonl(source);
698 mreq_source.imr_interface.s_addr = htonl(interf);
699 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
700 optval = (void*)&mreq_source;
701 optlen = sizeof(mreq_source);
702 }
703
704 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
705 if (n < 0) {
706 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
707 return IOS_UNAVAILABLE;
708 handleSocketError(env, errno);
709 }
710 return 0;
711 }
712
713 JNIEXPORT jint JNICALL
714 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
715 jint group, jint interf, jint source)
716 {
717 #ifdef __APPLE__
718 /* no IPv4 exclude-mode filtering for now */
719 return IOS_UNAVAILABLE;
720 #else
721 struct ip_mreq_source mreq_source;
722 int n;
723 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
724
725 #ifdef _AIX
726 /* check AIX for support of source filtering */
727 if (isSourceFilterSupported() != JNI_TRUE){
728 return IOS_UNAVAILABLE;
729 }
730 #endif
731
732 mreq_source.imr_multiaddr.s_addr = htonl(group);
733 mreq_source.imr_sourceaddr.s_addr = htonl(source);
734 mreq_source.imr_interface.s_addr = htonl(interf);
735
736 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
737 (void*)&mreq_source, sizeof(mreq_source));
738 if (n < 0) {
739 if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
740 return IOS_UNAVAILABLE;
741 handleSocketError(env, errno);
742 }
743 return 0;
744 #endif
745 }
746
747 JNIEXPORT jint JNICALL
748 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
749 jbyteArray group, jint index, jbyteArray source)
750 {
751 struct ipv6_mreq mreq6;
752 struct group_source_req req;
753 int opt, n, optlen;
754 void* optval;
755
756 if (source == NULL) {
757 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
758 mreq6.ipv6mr_interface = (int)index;
759 opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
760 optval = (void*)&mreq6;
761 optlen = sizeof(mreq6);
762 } else {
763 #ifdef __APPLE__
764 /* no IPv6 include-mode filtering for now */
765 return IOS_UNAVAILABLE;
766 #else
767 initGroupSourceReq(env, group, index, source, &req);
768 opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
769 optval = (void*)&req;
770 optlen = sizeof(req);
771 #endif
772 }
773
774 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
775 if (n < 0) {
776 if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
777 return IOS_UNAVAILABLE;
778 handleSocketError(env, errno);
779 }
780 return 0;
781 }
782
783 JNIEXPORT jint JNICALL
784 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
785 jbyteArray group, jint index, jbyteArray source)
786 {
787 #ifdef __APPLE__
788 /* no IPv6 exclude-mode filtering for now */
789 return IOS_UNAVAILABLE;
790 #else
791 struct group_source_req req;
792 int n;
793 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
794
795 initGroupSourceReq(env, group, index, source, &req);
796
797 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
798 (void*)&req, sizeof(req));
799 if (n < 0) {
800 if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
801 return IOS_UNAVAILABLE;
802 handleSocketError(env, errno);
803 }
804 return 0;
805 #endif
806 }
807
808 JNIEXPORT void JNICALL
809 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
810 {
811 struct in_addr in;
812 socklen_t arglen = sizeof(struct in_addr);
813 int n;
814
815 in.s_addr = htonl(interf);
816
817 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
818 (void*)&(in.s_addr), arglen);
819 if (n < 0) {
820 handleSocketError(env, errno);
821 }
822 }
823
824 JNIEXPORT jint JNICALL
825 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
826 {
827 struct in_addr in;
828 socklen_t arglen = sizeof(struct in_addr);
829 int n;
830
831 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
832 if (n < 0) {
833 handleSocketError(env, errno);
834 return -1;
835 }
836 return ntohl(in.s_addr);
837 }
838
839 JNIEXPORT void JNICALL
840 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
841 {
842 int value = (jint)index;
843 socklen_t arglen = sizeof(value);
844 int n;
845
846 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
847 (void*)&(index), arglen);
848 if (n < 0) {
849 handleSocketError(env, errno);
850 }
851 }
852
853 JNIEXPORT jint JNICALL
854 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
855 {
856 int index;
857 socklen_t arglen = sizeof(index);
858 int n;
859
860 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
861 if (n < 0) {
862 handleSocketError(env, errno);
863 return -1;
864 }
865 return (jint)index;
866 }
867
868 JNIEXPORT void JNICALL
869 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)
870 {
871 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
872 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
873 if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN))
874 handleSocketError(env, errno);
875 }
876
877 JNIEXPORT jint JNICALL
878 Java_sun_nio_ch_Net_available(JNIEnv *env, jclass cl, jobject fdo)
879 {
880 int count = 0;
881 if (NET_SocketAvailable(fdval(env, fdo), &count) != 0) {
882 handleSocketError(env, errno);
883 return IOS_THROWN;
884 }
885 return (jint) count;
886 }
887
888 JNIEXPORT jint JNICALL
889 Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout)
890 {
891 struct pollfd pfd;
892 int rv;
893 pfd.fd = fdval(env, fdo);
894 pfd.events = events;
895 if (timeout < -1) {
896 timeout = -1;
897 } else if (timeout > INT_MAX) {
898 timeout = INT_MAX;
899 }
900 rv = poll(&pfd, 1, (int)timeout);
901
902 if (rv >= 0) {
903 return pfd.revents;
904 } else if (errno == EINTR) {
905 // interrupted, no events to return
906 return 0;
907 } else {
908 handleSocketError(env, errno);
909 return IOS_THROWN;
910 }
911 }
912
913 JNIEXPORT jboolean JNICALL
914 Java_sun_nio_ch_Net_pollConnect(JNIEnv *env, jobject this, jobject fdo, jlong timeout)
915 {
916 jint fd = fdval(env, fdo);
917 struct pollfd poller;
918 int result;
919
920 poller.fd = fd;
921 poller.events = POLLOUT;
922 poller.revents = 0;
923 if (timeout < -1) {
924 timeout = -1;
925 } else if (timeout > INT_MAX) {
926 timeout = INT_MAX;
927 }
928
929 result = poll(&poller, 1, (int)timeout);
930
931 if (result > 0) {
932 int error = 0;
933 socklen_t n = sizeof(int);
934 errno = 0;
935 result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n);
936 if (result < 0) {
937 handleSocketError(env, errno);
938 return JNI_FALSE;
939 } else if (error) {
940 handleSocketError(env, error);
941 return JNI_FALSE;
942 } else if ((poller.revents & POLLHUP) != 0) {
943 handleSocketError(env, ENOTCONN);
944 return JNI_FALSE;
945 }
946 // connected
947 return JNI_TRUE;
948 } else if (result == 0 || errno == EINTR) {
949 return JNI_FALSE;
950 } else {
951 JNU_ThrowIOExceptionWithLastError(env, "poll failed");
952 return JNI_FALSE;
953 }
954 }
955
956 JNIEXPORT jshort JNICALL
957 Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this)
958 {
959 return (jshort)POLLIN;
960 }
961
962 JNIEXPORT jshort JNICALL
963 Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this)
964 {
965 return (jshort)POLLOUT;
966 }
967
968 JNIEXPORT jshort JNICALL
969 Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this)
970 {
971 return (jshort)POLLERR;
972 }
973
974 JNIEXPORT jshort JNICALL
975 Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this)
976 {
977 return (jshort)POLLHUP;
978 }
979
980 JNIEXPORT jshort JNICALL
981 Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this)
982 {
983 return (jshort)POLLNVAL;
984 }
985
986 JNIEXPORT jshort JNICALL
987 Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this)
988 {
989 return (jshort)POLLOUT;
990 }
991
992 JNIEXPORT jint JNICALL
993 Java_sun_nio_ch_Net_sendOOB(JNIEnv* env, jclass this, jobject fdo, jbyte b)
994 {
995 int n = send(fdval(env, fdo), (const void*)&b, 1, MSG_OOB);
996 return convertReturnVal(env, n, JNI_FALSE);
997 }
998
999 /* Declared in nio_util.h */
1000
1001 jint handleSocketError(JNIEnv *env, jint errorValue)
1002 {
1003 char *xn;
1004 switch (errorValue) {
1005 case EINPROGRESS: /* Non-blocking connect */
1006 return 0;
1007 #ifdef EPROTO
1008 case EPROTO:
1009 xn = JNU_JAVANETPKG "ProtocolException";
1010 break;
1011 #endif
1012 case ECONNREFUSED:
1013 case ETIMEDOUT:
1014 case ENOTCONN:
1015 xn = JNU_JAVANETPKG "ConnectException";
1016 break;
1017
1018 case EHOSTUNREACH:
1019 xn = JNU_JAVANETPKG "NoRouteToHostException";
1020 break;
1021 case EADDRINUSE: /* Fall through */
1022 case EADDRNOTAVAIL:
1023 case EACCES:
1024 xn = JNU_JAVANETPKG "BindException";
1025 break;
1026 default:
1027 xn = JNU_JAVANETPKG "SocketException";
1028 break;
1029 }
1030 errno = errorValue;
1031 JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
1032 return IOS_THROWN;
1033 }