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/types.h>
27 #include <sys/socket.h>
28 #include <string.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 
32 #include "jni.h"
33 #include "jni_util.h"
34 #include "jvm.h"
35 #include "jlong.h"
36 #include "sun_nio_ch_Net.h"
37 #include "net_util.h"
38 #include "net_util_md.h"
39 #include "nio_util.h"
40 #include "nio.h"
41 
42 #include "JNIHelp.h"
43 
44 #define NATIVE_METHOD(className, functionName, signature) \
45 { #functionName, signature, (void*)(Java_sun_nio_ch_ ## className ## _ ## functionName) }
46 
47 #ifdef _ALLBSD_SOURCE
48 
49 #ifndef IP_BLOCK_SOURCE
50 
51 #define IP_ADD_SOURCE_MEMBERSHIP        70   /* join a source-specific group */
52 #define IP_DROP_SOURCE_MEMBERSHIP       71   /* drop a single source */
53 #define IP_BLOCK_SOURCE                 72   /* block a source */
54 #define IP_UNBLOCK_SOURCE               73   /* unblock a source */
55 
56 #endif  /* IP_BLOCK_SOURCE */
57 
58 #ifndef MCAST_BLOCK_SOURCE
59 
60 #define MCAST_JOIN_SOURCE_GROUP         82   /* join a source-specific group */
61 #define MCAST_LEAVE_SOURCE_GROUP        83   /* leave a single source */
62 #define MCAST_BLOCK_SOURCE              84   /* block a source */
63 #define MCAST_UNBLOCK_SOURCE            85   /* unblock a source */
64 
65 #endif /* MCAST_BLOCK_SOURCE */
66 
67 #ifndef IPV6_ADD_MEMBERSHIP
68 
69 #define IPV6_ADD_MEMBERSHIP     IPV6_JOIN_GROUP
70 #define IPV6_DROP_MEMBERSHIP    IPV6_LEAVE_GROUP
71 
72 #endif /* IPV6_ADD_MEMBERSHIP */
73 
74 struct my_ip_mreq_source {
75         struct in_addr  imr_multiaddr;
76         struct in_addr  imr_interface;
77         struct in_addr  imr_sourceaddr;
78 };
79 
80 struct my_group_source_req {
81         uint32_t                gsr_interface;  /* interface index */
82         struct sockaddr_storage gsr_group;      /* group address */
83         struct sockaddr_storage gsr_source;     /* source address */
84 };
85 
86 #else   /* _ALLBSD_SOURCE */
87 
88 #define my_ip_mreq_source         ip_mreq_source
89 #define my_group_source_req       group_source_req
90 
91 #endif
92 
93 
94 #define COPY_INET6_ADDRESS(env, source, target) \
95     (*env)->GetByteArrayRegion(env, source, 0, 16, target)
96 
97 /*
98  * Copy IPv6 group, interface index, and IPv6 source address
99  * into group_source_req structure.
100  */
101 #ifdef AF_INET6
initGroupSourceReq(JNIEnv * env,jbyteArray group,jint index,jbyteArray source,struct my_group_source_req * req)102 static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index,
103                                jbyteArray source, struct my_group_source_req* req)
104 {
105     struct sockaddr_in6* sin6;
106 
107     req->gsr_interface = (uint32_t)index;
108 
109     sin6 = (struct sockaddr_in6*)&(req->gsr_group);
110     sin6->sin6_family = AF_INET6;
111     COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr));
112 
113     sin6 = (struct sockaddr_in6*)&(req->gsr_source);
114     sin6->sin6_family = AF_INET6;
115     COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr));
116 }
117 #endif
118 
119 JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv * env,jclass cl)120 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
121 {
122     return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
123 }
124 
125 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv * env,jclass clazz)126 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
127     return -1;
128 }
129 
130 JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv * env,jclass cl)131 Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
132 {
133 #ifdef MACOSX
134     /* for now IPv6 sockets cannot join IPv4 multicast groups */
135     return JNI_FALSE;
136 #else
137     return JNI_TRUE;
138 #endif
139 }
140 
141 JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv * env,jclass cl)142 Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
143 {
144 #ifdef __solaris__
145     return JNI_TRUE;
146 #else
147     return JNI_FALSE;
148 #endif
149 }
150 
151 JNIEXPORT int JNICALL
Java_sun_nio_ch_Net_socket0(JNIEnv * env,jclass cl,jboolean preferIPv6,jboolean stream,jboolean reuse)152 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
153                             jboolean stream, jboolean reuse)
154 {
155     int fd;
156     int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
157 #ifdef AF_INET6
158     int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
159 #else
160     int domain = AF_INET;
161 #endif
162 
163     fd = socket(domain, type, 0);
164     tagSocket(env, fd);
165     if (fd < 0) {
166         return handleSocketError(env, errno);
167     }
168 
169 #ifdef AF_INET6
170     /* Disable IPV6_V6ONLY to ensure dual-socket support */
171     if (domain == AF_INET6) {
172         int arg = 0;
173         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
174                        sizeof(int)) < 0) {
175             JNU_ThrowByNameWithLastError(env,
176                                          JNU_JAVANETPKG "SocketException",
177                                          "sun.nio.ch.Net.setIntOption");
178             untagSocket(env, fd);
179             close(fd);
180             return -1;
181         }
182     }
183 #endif
184 
185     if (reuse) {
186         int arg = 1;
187         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
188                        sizeof(arg)) < 0) {
189             JNU_ThrowByNameWithLastError(env,
190                                          JNU_JAVANETPKG "SocketException",
191                                          "sun.nio.ch.Net.setIntOption");
192             untagSocket(env, fd);
193             close(fd);
194             return -1;
195         }
196     }
197 #if defined(__linux__) && defined(AF_INET6)
198     /* By default, Linux uses the route default */
199     if (domain == AF_INET6 && type == SOCK_DGRAM) {
200         int arg = 1;
201         if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
202                        sizeof(arg)) < 0) {
203             JNU_ThrowByNameWithLastError(env,
204                                          JNU_JAVANETPKG "SocketException",
205                                          "sun.nio.ch.Net.setIntOption");
206             untagSocket(env, fd);
207             close(fd);
208             return -1;
209         }
210     }
211 #endif
212     return fd;
213 }
214 
215 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_bind0(JNIEnv * env,jclass clazz,jobject fdo,jboolean preferIPv6,jboolean useExclBind,jobject iao,int port)216 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,
217                           jboolean useExclBind, jobject iao, int port)
218 {
219     SOCKADDR sa;
220     int sa_len = SOCKADDR_LEN;
221     int rv = 0;
222 
223     if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
224       return;
225     }
226 
227     rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
228     if (rv != 0) {
229         handleSocketError(env, errno);
230     }
231 }
232 
233 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_listen(JNIEnv * env,jclass cl,jobject fdo,jint backlog)234 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
235 {
236     if (listen(fdval(env, fdo), backlog) < 0)
237         handleSocketError(env, errno);
238 }
239 
240 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_connect0(JNIEnv * env,jclass clazz,jboolean preferIPv6,jobject fdo,jobject iao,jint port)241 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
242                              jobject fdo, jobject iao, jint port)
243 {
244     SOCKADDR sa;
245     int sa_len = SOCKADDR_LEN;
246     int rv;
247 
248     if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa,
249                                   &sa_len, preferIPv6) != 0)
250     {
251       return IOS_THROWN;
252     }
253 
254     rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
255     if (rv != 0) {
256         if (errno == EINPROGRESS) {
257             return IOS_UNAVAILABLE;
258         } else if (errno == EINTR) {
259             return IOS_INTERRUPTED;
260         }
261         return handleSocketErrorWithDefault(env, errno, JNU_JAVANETPKG "ConnectException");
262     }
263     return 1;
264 }
265 
266 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_localPort(JNIEnv * env,jclass clazz,jobject fdo)267 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
268 {
269     SOCKADDR sa;
270     socklen_t sa_len = SOCKADDR_LEN;
271     if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
272 #ifdef _ALLBSD_SOURCE
273         /*
274          * XXXBSD:
275          * ECONNRESET is specific to the BSDs. We can not return an error,
276          * as the calling Java code with raise a java.lang.Error given the expectation
277          * that getsockname() will never fail. According to the Single UNIX Specification,
278          * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
279          */
280         if (errno == ECONNRESET) {
281             struct sockaddr_in *sin;
282             sin = (struct sockaddr_in *) &sa;
283             bzero(sin, sizeof(*sin));
284             sin->sin_len  = sizeof(struct sockaddr_in);
285             sin->sin_family = AF_INET;
286             sin->sin_port = htonl(0);
287             sin->sin_addr.s_addr = INADDR_ANY;
288         } else {
289             handleSocketError(env, errno);
290             return -1;
291         }
292 #else /* _ALLBSD_SOURCE */
293         handleSocketError(env, errno);
294         return -1;
295 #endif /* _ALLBSD_SOURCE */
296     }
297     return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
298 }
299 
300 JNIEXPORT jobject JNICALL
Java_sun_nio_ch_Net_localInetAddress(JNIEnv * env,jclass clazz,jobject fdo)301 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
302 {
303     SOCKADDR sa;
304     socklen_t sa_len = SOCKADDR_LEN;
305     int port;
306     if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
307 #ifdef _ALLBSD_SOURCE
308         /*
309          * XXXBSD:
310          * ECONNRESET is specific to the BSDs. We can not return an error,
311          * as the calling Java code with raise a java.lang.Error with the expectation
312          * that getsockname() will never fail. According to the Single UNIX Specification,
313          * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
314          */
315         if (errno == ECONNRESET) {
316             struct sockaddr_in *sin;
317             sin = (struct sockaddr_in *) &sa;
318             bzero(sin, sizeof(*sin));
319             sin->sin_len  = sizeof(struct sockaddr_in);
320             sin->sin_family = AF_INET;
321             sin->sin_port = htonl(0);
322             sin->sin_addr.s_addr = INADDR_ANY;
323         } else {
324             handleSocketError(env, errno);
325             return NULL;
326         }
327 #else /* _ALLBSD_SOURCE */
328         handleSocketError(env, errno);
329         return NULL;
330 #endif /* _ALLBSD_SOURCE */
331     }
332     return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
333 }
334 
335 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getIntOption0(JNIEnv * env,jclass clazz,jobject fdo,jboolean mayNeedConversion,jint level,jint opt)336 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
337                                   jboolean mayNeedConversion, jint level, jint opt)
338 {
339     int result;
340     struct linger linger;
341     u_char carg;
342     void *arg;
343     socklen_t arglen;
344     int n;
345 
346     /* Option value is an int except for a few specific cases */
347 
348     arg = (void *)&result;
349     arglen = sizeof(result);
350 
351     if (level == IPPROTO_IP &&
352         (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
353         arg = (void*)&carg;
354         arglen = sizeof(carg);
355     }
356 
357     if (level == SOL_SOCKET && opt == SO_LINGER) {
358         arg = (void *)&linger;
359         arglen = sizeof(linger);
360     }
361 
362     if (mayNeedConversion) {
363         n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen);
364     } else {
365         n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
366     }
367     if (n < 0) {
368         JNU_ThrowByNameWithLastError(env,
369                                      JNU_JAVANETPKG "SocketException",
370                                      "sun.nio.ch.Net.getIntOption");
371         return -1;
372     }
373 
374     if (level == IPPROTO_IP &&
375         (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))
376     {
377         return (jint)carg;
378     }
379 
380     if (level == SOL_SOCKET && opt == SO_LINGER)
381         return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;
382 
383     return (jint)result;
384 }
385 
386 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setIntOption0(JNIEnv * env,jclass clazz,jobject fdo,jboolean mayNeedConversion,jint level,jint opt,jint arg)387 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
388                                   jboolean mayNeedConversion, jint level, jint opt, jint arg)
389 {
390     int result;
391     struct linger linger;
392     u_char carg;
393     void *parg;
394     socklen_t arglen;
395     int n;
396 
397     /* Option value is an int except for a few specific cases */
398 
399     parg = (void*)&arg;
400     arglen = sizeof(arg);
401 
402     if (level == IPPROTO_IP &&
403         (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
404         parg = (void*)&carg;
405         arglen = sizeof(carg);
406         carg = (u_char)arg;
407     }
408 
409     if (level == SOL_SOCKET && opt == SO_LINGER) {
410         parg = (void *)&linger;
411         arglen = sizeof(linger);
412         if (arg >= 0) {
413             linger.l_onoff = 1;
414             linger.l_linger = arg;
415         } else {
416             linger.l_onoff = 0;
417             linger.l_linger = 0;
418         }
419     }
420 
421     if (mayNeedConversion) {
422         n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
423     } else {
424         n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
425     }
426     if (n < 0) {
427         JNU_ThrowByNameWithLastError(env,
428                                      JNU_JAVANETPKG "SocketException",
429                                      "sun.nio.ch.Net.setIntOption");
430     }
431 }
432 
433 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv * env,jobject this,jboolean join,jobject fdo,jint group,jint interf,jint source)434 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
435                                 jint group, jint interf, jint source)
436 {
437     struct ip_mreq mreq;
438     struct my_ip_mreq_source mreq_source;
439     int opt, n, optlen;
440     void* optval;
441 
442     if (source == 0) {
443         mreq.imr_multiaddr.s_addr = htonl(group);
444         mreq.imr_interface.s_addr = htonl(interf);
445         opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
446         optval = (void*)&mreq;
447         optlen = sizeof(mreq);
448     } else {
449 #ifdef MACOSX
450         /* no IPv4 include-mode filtering for now */
451         return IOS_UNAVAILABLE;
452 #else
453 // Begin Android changed.
454 #if defined(__GLIBC__)
455         mreq_source.imr_multiaddr.s_addr = htonl(group);
456         mreq_source.imr_sourceaddr.s_addr = htonl(source);
457         mreq_source.imr_interface.s_addr = htonl(interf);
458 #else
459         mreq_source.imr_multiaddr = htonl(group);
460         mreq_source.imr_sourceaddr = htonl(source);
461         mreq_source.imr_interface = htonl(interf);
462 #endif
463 // End Android changed.
464         opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
465         optval = (void*)&mreq_source;
466         optlen = sizeof(mreq_source);
467 #endif
468     }
469 
470     n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
471     if (n < 0) {
472         if (join && (errno == ENOPROTOOPT))
473             return IOS_UNAVAILABLE;
474         handleSocketError(env, errno);
475     }
476     return 0;
477 }
478 
479 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv * env,jobject this,jboolean block,jobject fdo,jint group,jint interf,jint source)480 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
481                                     jint group, jint interf, jint source)
482 {
483 #ifdef MACOSX
484     /* no IPv4 exclude-mode filtering for now */
485     return IOS_UNAVAILABLE;
486 #else
487     struct my_ip_mreq_source mreq_source;
488     int n;
489     int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
490 
491 // Begin Android changed.
492 #if defined(__GLIBC__)
493         mreq_source.imr_multiaddr.s_addr = htonl(group);
494         mreq_source.imr_sourceaddr.s_addr = htonl(source);
495         mreq_source.imr_interface.s_addr = htonl(interf);
496 #else
497         mreq_source.imr_multiaddr = htonl(group);
498         mreq_source.imr_sourceaddr = htonl(source);
499         mreq_source.imr_interface = htonl(interf);
500 #endif
501 
502     n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
503                    (void*)&mreq_source, sizeof(mreq_source));
504     if (n < 0) {
505         if (block && (errno == ENOPROTOOPT))
506             return IOS_UNAVAILABLE;
507         handleSocketError(env, errno);
508     }
509     return 0;
510 #endif
511 }
512 
513 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv * env,jobject this,jboolean join,jobject fdo,jbyteArray group,jint index,jbyteArray source)514 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
515                                 jbyteArray group, jint index, jbyteArray source)
516 {
517 #ifdef AF_INET6
518     struct ipv6_mreq mreq6;
519     struct my_group_source_req req;
520     int opt, n, optlen;
521     void* optval;
522 
523     if (source == NULL) {
524         COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
525         mreq6.ipv6mr_interface = (int)index;
526         opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
527         optval = (void*)&mreq6;
528         optlen = sizeof(mreq6);
529     } else {
530 #ifdef MACOSX
531         /* no IPv6 include-mode filtering for now */
532         return IOS_UNAVAILABLE;
533 #else
534         initGroupSourceReq(env, group, index, source, &req);
535         opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
536         optval = (void*)&req;
537         optlen = sizeof(req);
538 #endif
539     }
540 
541     n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
542     if (n < 0) {
543         if (join && (errno == ENOPROTOOPT))
544             return IOS_UNAVAILABLE;
545         handleSocketError(env, errno);
546     }
547     return 0;
548 #else
549     JNU_ThrowInternalError(env, "Should not get here");
550     return IOS_THROWN;
551 #endif  /* AF_INET6 */
552 }
553 
554 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv * env,jobject this,jboolean block,jobject fdo,jbyteArray group,jint index,jbyteArray source)555 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
556                                     jbyteArray group, jint index, jbyteArray source)
557 {
558 #ifdef AF_INET6
559   #ifdef MACOSX
560     /* no IPv6 exclude-mode filtering for now */
561     return IOS_UNAVAILABLE;
562   #else
563     struct my_group_source_req req;
564     int n;
565     int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
566 
567     initGroupSourceReq(env, group, index, source, &req);
568 
569     n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
570         (void*)&req, sizeof(req));
571     if (n < 0) {
572         if (block && (errno == ENOPROTOOPT))
573             return IOS_UNAVAILABLE;
574         handleSocketError(env, errno);
575     }
576     return 0;
577   #endif
578 #else
579     JNU_ThrowInternalError(env, "Should not get here");
580     return IOS_THROWN;
581 #endif
582 }
583 
584 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setInterface4(JNIEnv * env,jobject this,jobject fdo,jint interf)585 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
586 {
587     struct in_addr in;
588     socklen_t arglen = sizeof(struct in_addr);
589     int n;
590 
591     in.s_addr = htonl(interf);
592 
593     n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
594                    (void*)&(in.s_addr), arglen);
595     if (n < 0) {
596         handleSocketError(env, errno);
597     }
598 }
599 
600 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getInterface4(JNIEnv * env,jobject this,jobject fdo)601 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
602 {
603     struct in_addr in;
604     socklen_t arglen = sizeof(struct in_addr);
605     int n;
606 
607     n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
608     if (n < 0) {
609         handleSocketError(env, errno);
610         return -1;
611     }
612     return ntohl(in.s_addr);
613 }
614 
615 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setInterface6(JNIEnv * env,jobject this,jobject fdo,jint index)616 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
617 {
618     int value = (jint)index;
619     socklen_t arglen = sizeof(value);
620     int n;
621 
622     n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
623                    (void*)&(index), arglen);
624     if (n < 0) {
625         handleSocketError(env, errno);
626     }
627 }
628 
629 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getInterface6(JNIEnv * env,jobject this,jobject fdo)630 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
631 {
632     int index;
633     socklen_t arglen = sizeof(index);
634     int n;
635 
636     n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
637     if (n < 0) {
638         handleSocketError(env, errno);
639         return -1;
640     }
641     return (jint)index;
642 }
643 
644 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_shutdown(JNIEnv * env,jclass cl,jobject fdo,jint jhow)645 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)
646 {
647     int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
648         (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
649     if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN))
650         handleSocketError(env, errno);
651 }
652 
653 /* Declared in nio_util.h */
654 
655 jint
handleSocketErrorWithDefault(JNIEnv * env,jint errorValue,const char * defaultException)656 handleSocketErrorWithDefault(JNIEnv *env, jint errorValue, const char *defaultException)
657 {
658     const char *xn;
659     switch (errorValue) {
660         case EINPROGRESS:       /* Non-blocking connect */
661             return 0;
662 #ifdef EPROTO
663         case EPROTO:
664             xn = JNU_JAVANETPKG "ProtocolException";
665             break;
666 #endif
667         case ECONNREFUSED:
668             xn = JNU_JAVANETPKG "ConnectException";
669             break;
670         case ETIMEDOUT:
671             xn = JNU_JAVANETPKG "ConnectException";
672             break;
673         case EHOSTUNREACH:
674             xn = JNU_JAVANETPKG "NoRouteToHostException";
675             break;
676         case EADDRINUSE:  /* Fall through */
677         case EADDRNOTAVAIL:
678             xn = JNU_JAVANETPKG "BindException";
679             break;
680         default:
681             xn = defaultException;
682             break;
683     }
684     errno = errorValue;
685     JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
686     return IOS_THROWN;
687 }
688 
689 /* Declared in nio_util.h */
690 
691 jint
handleSocketError(JNIEnv * env,jint errorValue)692 handleSocketError(JNIEnv *env, jint errorValue) {
693     return handleSocketErrorWithDefault(env, errorValue,
694                                         JNU_JAVANETPKG "SocketException");
695 }
696 
697 
698 static JNINativeMethod gMethods[] = {
699   NATIVE_METHOD(Net, isIPv6Available0, "()Z"),
700   NATIVE_METHOD(Net, isExclusiveBindAvailable, "()I"),
701   NATIVE_METHOD(Net, canIPv6SocketJoinIPv4Group0, "()Z"),
702   NATIVE_METHOD(Net, canJoin6WithIPv4Group0, "()Z"),
703   NATIVE_METHOD(Net, socket0, "(ZZZ)I"),
704   NATIVE_METHOD(Net, bind0, "(Ljava/io/FileDescriptor;ZZLjava/net/InetAddress;I)V"),
705   NATIVE_METHOD(Net, listen, "(Ljava/io/FileDescriptor;I)V"),
706   NATIVE_METHOD(Net, connect0, "(ZLjava/io/FileDescriptor;Ljava/net/InetAddress;I)I"),
707   NATIVE_METHOD(Net, shutdown, "(Ljava/io/FileDescriptor;I)V"),
708   NATIVE_METHOD(Net, localPort, "(Ljava/io/FileDescriptor;)I"),
709   NATIVE_METHOD(Net, localInetAddress, "(Ljava/io/FileDescriptor;)Ljava/net/InetAddress;"),
710   NATIVE_METHOD(Net, getIntOption0, "(Ljava/io/FileDescriptor;ZII)I"),
711   NATIVE_METHOD(Net, setIntOption0, "(Ljava/io/FileDescriptor;ZIII)V"),
712   NATIVE_METHOD(Net, joinOrDrop4, "(ZLjava/io/FileDescriptor;III)I"),
713   NATIVE_METHOD(Net, blockOrUnblock4, "(ZLjava/io/FileDescriptor;III)I"),
714   NATIVE_METHOD(Net, joinOrDrop6, "(ZLjava/io/FileDescriptor;[BI[B)I"),
715   NATIVE_METHOD(Net, blockOrUnblock6, "(ZLjava/io/FileDescriptor;[BI[B)I"),
716   NATIVE_METHOD(Net, setInterface4, "(Ljava/io/FileDescriptor;I)V"),
717   NATIVE_METHOD(Net, getInterface4, "(Ljava/io/FileDescriptor;)I"),
718   NATIVE_METHOD(Net, setInterface6, "(Ljava/io/FileDescriptor;I)V"),
719   NATIVE_METHOD(Net, getInterface6, "(Ljava/io/FileDescriptor;)I"),
720 };
721 
register_sun_nio_ch_Net(JNIEnv * env)722 void register_sun_nio_ch_Net(JNIEnv* env) {
723   jniRegisterNativeMethods(env, "sun/nio/ch/Net", gMethods, NELEM(gMethods));
724 }
725