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