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