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