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