Home | History | Annotate | Download | only in native
      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 <nativehelper/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
    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  */
    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
    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
    206 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
    207     return -1;
    208 }
    209 
    210 JNIEXPORT jboolean JNICALL
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    790 Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this)
    791 {
    792     return (jshort)POLLIN;
    793 }
    794 
    795 JNIEXPORT jshort JNICALL
    796 Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this)
    797 {
    798     return (jshort)POLLOUT;
    799 }
    800 
    801 JNIEXPORT jshort JNICALL
    802 Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this)
    803 {
    804     return (jshort)POLLERR;
    805 }
    806 
    807 JNIEXPORT jshort JNICALL
    808 Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this)
    809 {
    810     return (jshort)POLLHUP;
    811 }
    812 
    813 JNIEXPORT jshort JNICALL
    814 Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this)
    815 {
    816     return (jshort)POLLNVAL;
    817 }
    818 
    819 JNIEXPORT jshort JNICALL
    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
    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
    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 
    902 void register_sun_nio_ch_Net(JNIEnv* env) {
    903   jniRegisterNativeMethods(env, "sun/nio/ch/Net", gMethods, NELEM(gMethods));
    904 }
    905