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