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