1 /*
   2  * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/socket.h>
  28 #include <string.h>
  29 #include <netinet/in.h>
  30 #include <netinet/tcp.h>
  31 
  32 #include "jni.h"
  33 #include "jni_util.h"
  34 #include "jvm.h"
  35 #include "jlong.h"
  36 #include "sun_nio_ch_Net.h"
  37 #include "net_util.h"
  38 #include "net_util_md.h"
  39 #include "nio_util.h"
  40 #include "nio.h"
  41 
  42 /**
  43  * Definitions for source-specific multicast to allow for building
  44  * with older header files.
  45  */
  46 
  47 #ifdef __solaris__
  48 
  49 #ifndef IP_BLOCK_SOURCE
  50 
  51 #define IP_BLOCK_SOURCE                 0x15
  52 #define IP_UNBLOCK_SOURCE               0x16
  53 #define IP_ADD_SOURCE_MEMBERSHIP        0x17
  54 #define IP_DROP_SOURCE_MEMBERSHIP       0x18
  55 
  56 #define MCAST_BLOCK_SOURCE              0x2b
  57 #define MCAST_UNBLOCK_SOURCE            0x2c
  58 #define MCAST_JOIN_SOURCE_GROUP         0x2d
  59 #define MCAST_LEAVE_SOURCE_GROUP        0x2e
  60 
  61 #endif  /* IP_BLOCK_SOURCE */
  62 
  63 struct my_ip_mreq_source {
  64         struct in_addr  imr_multiaddr;
  65         struct in_addr  imr_sourceaddr;
  66         struct in_addr  imr_interface;
  67 };
  68 
  69 /*
  70  * Use #pragma pack() construct to force 32-bit alignment on amd64.
  71  */
  72 #if defined(amd64)
  73 #pragma pack(4)
  74 #endif
  75 
  76 struct my_group_source_req {
  77         uint32_t                gsr_interface;  /* interface index */
  78         struct sockaddr_storage gsr_group;      /* group address */
  79         struct sockaddr_storage gsr_source;     /* source address */
  80 };
  81 
  82 #if defined(amd64)
  83 #pragma pack()
  84 #endif
  85 
  86 #endif  /* __solaris__ */
  87 
  88 
  89 #ifdef __linux__
  90 
  91 #ifndef IP_BLOCK_SOURCE
  92 
  93 #define IP_BLOCK_SOURCE                 38
  94 #define IP_UNBLOCK_SOURCE               37
  95 #define IP_ADD_SOURCE_MEMBERSHIP        39
  96 #define IP_DROP_SOURCE_MEMBERSHIP       40
  97 
  98 #define MCAST_BLOCK_SOURCE              43
  99 #define MCAST_UNBLOCK_SOURCE            44
 100 #define MCAST_JOIN_SOURCE_GROUP         42
 101 #define MCAST_LEAVE_SOURCE_GROUP        45
 102 
 103 #endif  /* IP_BLOCK_SOURCE */
 104 
 105 struct my_ip_mreq_source {
 106         struct in_addr  imr_multiaddr;
 107         struct in_addr  imr_interface;
 108         struct in_addr  imr_sourceaddr;
 109 };
 110 
 111 struct my_group_source_req {
 112         uint32_t                gsr_interface;  /* interface index */
 113         struct sockaddr_storage gsr_group;      /* group address */
 114         struct sockaddr_storage gsr_source;     /* source address */
 115 };
 116 
 117 #endif   /* __linux__ */
 118 
 119 #ifdef _ALLBSD_SOURCE
 120 
 121 #ifndef IP_BLOCK_SOURCE
 122 
 123 #define IP_ADD_SOURCE_MEMBERSHIP        70   /* join a source-specific group */
 124 #define IP_DROP_SOURCE_MEMBERSHIP       71   /* drop a single source */
 125 #define IP_BLOCK_SOURCE                 72   /* block a source */
 126 #define IP_UNBLOCK_SOURCE               73   /* unblock a source */
 127 
 128 #endif  /* IP_BLOCK_SOURCE */
 129 
 130 #ifndef MCAST_BLOCK_SOURCE
 131 
 132 #define MCAST_JOIN_SOURCE_GROUP         82   /* join a source-specific group */
 133 #define MCAST_LEAVE_SOURCE_GROUP        83   /* leave a single source */
 134 #define MCAST_BLOCK_SOURCE              84   /* block a source */
 135 #define MCAST_UNBLOCK_SOURCE            85   /* unblock a source */
 136 
 137 #endif /* MCAST_BLOCK_SOURCE */
 138 
 139 #ifndef IPV6_ADD_MEMBERSHIP
 140 
 141 #define IPV6_ADD_MEMBERSHIP     IPV6_JOIN_GROUP
 142 #define IPV6_DROP_MEMBERSHIP    IPV6_LEAVE_GROUP
 143 
 144 #endif /* IPV6_ADD_MEMBERSHIP */
 145 
 146 struct my_ip_mreq_source {
 147         struct in_addr  imr_multiaddr;
 148         struct in_addr  imr_interface;
 149         struct in_addr  imr_sourceaddr;
 150 };
 151 
 152 struct my_group_source_req {
 153         uint32_t                gsr_interface;  /* interface index */
 154         struct sockaddr_storage gsr_group;      /* group address */
 155         struct sockaddr_storage gsr_source;     /* source address */
 156 };
 157 
 158 #endif   /* _ALLBSD_SOURCE */
 159 
 160 
 161 #define COPY_INET6_ADDRESS(env, source, target) \
 162     (*env)->GetByteArrayRegion(env, source, 0, 16, target)
 163 
 164 /*
 165  * Copy IPv6 group, interface index, and IPv6 source address
 166  * into group_source_req structure.
 167  */
 168 #ifdef AF_INET6
 169 static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index,
 170                                jbyteArray source, struct my_group_source_req* req)
 171 {
 172     struct sockaddr_in6* sin6;
 173 
 174     req->gsr_interface = (uint32_t)index;
 175 
 176     sin6 = (struct sockaddr_in6*)&(req->gsr_group);
 177     sin6->sin6_family = AF_INET6;
 178     COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr));
 179 
 180     sin6 = (struct sockaddr_in6*)&(req->gsr_source);
 181     sin6->sin6_family = AF_INET6;
 182     COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr));
 183 }
 184 #endif
 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 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                                          "sun.nio.ch.Net.setIntOption");
 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                                          "sun.nio.ch.Net.setIntOption");
 258             close(fd);
 259             return -1;
 260         }
 261     }
 262 #if defined(__linux__) && defined(AF_INET6)
 263     /* By default, Linux uses the route default */
 264     if (domain == AF_INET6 && type == SOCK_DGRAM) {
 265         int arg = 1;
 266         if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
 267                        sizeof(arg)) < 0) {
 268             JNU_ThrowByNameWithLastError(env,
 269                                          JNU_JAVANETPKG "SocketException",
 270                                          "sun.nio.ch.Net.setIntOption");
 271             close(fd);
 272             return -1;
 273         }
 274     }
 275 #endif
 276     return fd;
 277 }
 278 
 279 JNIEXPORT void JNICALL
 280 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
 281                           jobject fdo, jobject iao, int port)
 282 {
 283     SOCKADDR sa;
 284     int sa_len = SOCKADDR_LEN;
 285     int rv = 0;
 286 
 287     if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
 288       return;
 289     }
 290 
 291     rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
 292     if (rv != 0) {
 293         handleSocketError(env, errno);
 294     }
 295 }
 296 
 297 JNIEXPORT void JNICALL
 298 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
 299 {
 300     if (listen(fdval(env, fdo), backlog) < 0)
 301         handleSocketError(env, errno);
 302 }
 303 
 304 JNIEXPORT jint JNICALL
 305 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
 306                              jobject fdo, jobject iao, jint port)
 307 {
 308     SOCKADDR sa;
 309     int sa_len = SOCKADDR_LEN;
 310     int rv;
 311 
 312     if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa,
 313                                   &sa_len, preferIPv6) != 0)
 314     {
 315       return IOS_THROWN;
 316     }
 317 
 318     rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
 319     if (rv != 0) {
 320         if (errno == EINPROGRESS) {
 321             return IOS_UNAVAILABLE;
 322         } else if (errno == EINTR) {
 323             return IOS_INTERRUPTED;
 324         }
 325         return handleSocketError(env, errno);
 326     }
 327     return 1;
 328 }
 329 
 330 JNIEXPORT jint JNICALL
 331 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
 332 {
 333     SOCKADDR sa;
 334     socklen_t sa_len = SOCKADDR_LEN;
 335     if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
 336 #ifdef _ALLBSD_SOURCE
 337         /*
 338          * XXXBSD:
 339          * ECONNRESET is specific to the BSDs. We can not return an error,
 340          * as the calling Java code with raise a java.lang.Error given the expectation
 341          * that getsockname() will never fail. According to the Single UNIX Specification,
 342          * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
 343          */
 344         if (errno == ECONNRESET) {
 345             struct sockaddr_in *sin;
 346             sin = (struct sockaddr_in *) &sa;
 347             bzero(sin, sizeof(*sin));
 348             sin->sin_len  = sizeof(struct sockaddr_in);
 349             sin->sin_family = AF_INET;
 350             sin->sin_port = htonl(0);
 351             sin->sin_addr.s_addr = INADDR_ANY;
 352         } else {
 353             handleSocketError(env, errno);
 354             return -1;
 355         }
 356 #else /* _ALLBSD_SOURCE */
 357         handleSocketError(env, errno);
 358         return -1;
 359 #endif /* _ALLBSD_SOURCE */
 360     }
 361     return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
 362 }
 363 
 364 JNIEXPORT jobject JNICALL
 365 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
 366 {
 367     SOCKADDR sa;
 368     socklen_t sa_len = SOCKADDR_LEN;
 369     int port;
 370     if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
 371 #ifdef _ALLBSD_SOURCE
 372         /*
 373          * XXXBSD:
 374          * ECONNRESET is specific to the BSDs. We can not return an error,
 375          * as the calling Java code with raise a java.lang.Error with the expectation
 376          * that getsockname() will never fail. According to the Single UNIX Specification,
 377          * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
 378          */
 379         if (errno == ECONNRESET) {
 380             struct sockaddr_in *sin;
 381             sin = (struct sockaddr_in *) &sa;
 382             bzero(sin, sizeof(*sin));
 383             sin->sin_len  = sizeof(struct sockaddr_in);
 384             sin->sin_family = AF_INET;
 385             sin->sin_port = htonl(0);
 386             sin->sin_addr.s_addr = INADDR_ANY;
 387         } else {
 388             handleSocketError(env, errno);
 389             return NULL;
 390         }
 391 #else /* _ALLBSD_SOURCE */
 392         handleSocketError(env, errno);
 393         return NULL;
 394 #endif /* _ALLBSD_SOURCE */
 395     }
 396     return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
 397 }
 398 
 399 JNIEXPORT jint JNICALL
 400 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
 401                                   jboolean mayNeedConversion, jint level, jint opt)
 402 {
 403     int result;
 404     struct linger linger;
 405     u_char carg;
 406     void *arg;
 407     socklen_t arglen;
 408     int n;
 409 
 410     /* Option value is an int except for a few specific cases */
 411 
 412     arg = (void *)&result;
 413     arglen = sizeof(result);
 414 
 415     if (level == IPPROTO_IP &&
 416         (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
 417         arg = (void*)&carg;
 418         arglen = sizeof(carg);
 419     }
 420 
 421     if (level == SOL_SOCKET && opt == SO_LINGER) {
 422         arg = (void *)&linger;
 423         arglen = sizeof(linger);
 424     }
 425 
 426     if (mayNeedConversion) {
 427         n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen);
 428     } else {
 429         n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
 430     }
 431     if (n < 0) {
 432         JNU_ThrowByNameWithLastError(env,
 433                                      JNU_JAVANETPKG "SocketException",
 434                                      "sun.nio.ch.Net.getIntOption");
 435         return -1;
 436     }
 437 
 438     if (level == IPPROTO_IP &&
 439         (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))
 440     {
 441         return (jint)carg;
 442     }
 443 
 444     if (level == SOL_SOCKET && opt == SO_LINGER)
 445         return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;
 446 
 447     return (jint)result;
 448 }
 449 
 450 JNIEXPORT void JNICALL
 451 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
 452                                   jboolean mayNeedConversion, jint level, jint opt, jint arg)
 453 {
 454     int result;
 455     struct linger linger;
 456     u_char carg;
 457     void *parg;
 458     socklen_t arglen;
 459     int n;
 460 
 461     /* Option value is an int except for a few specific cases */
 462 
 463     parg = (void*)&arg;
 464     arglen = sizeof(arg);
 465 
 466     if (level == IPPROTO_IP &&
 467         (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
 468         parg = (void*)&carg;
 469         arglen = sizeof(carg);
 470         carg = (u_char)arg;
 471     }
 472 
 473     if (level == SOL_SOCKET && opt == SO_LINGER) {
 474         parg = (void *)&linger;
 475         arglen = sizeof(linger);
 476         if (arg >= 0) {
 477             linger.l_onoff = 1;
 478             linger.l_linger = arg;
 479         } else {
 480             linger.l_onoff = 0;
 481             linger.l_linger = 0;
 482         }
 483     }
 484 
 485     if (mayNeedConversion) {
 486         n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
 487     } else {
 488         n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
 489     }
 490     if (n < 0) {
 491         JNU_ThrowByNameWithLastError(env,
 492                                      JNU_JAVANETPKG "SocketException",
 493                                      "sun.nio.ch.Net.setIntOption");
 494     }
 495 }
 496 
 497 JNIEXPORT jint JNICALL
 498 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
 499                                 jint group, jint interf, jint source)
 500 {
 501     struct ip_mreq mreq;
 502     struct my_ip_mreq_source mreq_source;
 503     int opt, n, optlen;
 504     void* optval;
 505 
 506     if (source == 0) {
 507         mreq.imr_multiaddr.s_addr = htonl(group);
 508         mreq.imr_interface.s_addr = htonl(interf);
 509         opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
 510         optval = (void*)&mreq;
 511         optlen = sizeof(mreq);
 512     } else {
 513 #ifdef MACOSX
 514         /* no IPv4 include-mode filtering for now */
 515         return IOS_UNAVAILABLE;
 516 #else
 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 #endif
 524     }
 525 
 526     n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
 527     if (n < 0) {
 528         if (join && (errno == ENOPROTOOPT))
 529             return IOS_UNAVAILABLE;
 530         handleSocketError(env, errno);
 531     }
 532     return 0;
 533 }
 534 
 535 JNIEXPORT jint JNICALL
 536 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
 537                                     jint group, jint interf, jint source)
 538 {
 539 #ifdef MACOSX
 540     /* no IPv4 exclude-mode filtering for now */
 541     return IOS_UNAVAILABLE;
 542 #else
 543     struct my_ip_mreq_source mreq_source;
 544     int n;
 545     int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
 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 
 551     n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
 552                    (void*)&mreq_source, sizeof(mreq_source));
 553     if (n < 0) {
 554         if (block && (errno == ENOPROTOOPT))
 555             return IOS_UNAVAILABLE;
 556         handleSocketError(env, errno);
 557     }
 558     return 0;
 559 #endif
 560 }
 561 
 562 JNIEXPORT jint JNICALL
 563 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
 564                                 jbyteArray group, jint index, jbyteArray source)
 565 {
 566 #ifdef AF_INET6
 567     struct ipv6_mreq mreq6;
 568     struct my_group_source_req req;
 569     int opt, n, optlen;
 570     void* optval;
 571 
 572     if (source == NULL) {
 573         COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
 574         mreq6.ipv6mr_interface = (int)index;
 575         opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
 576         optval = (void*)&mreq6;
 577         optlen = sizeof(mreq6);
 578     } else {
 579 #if defined (__linux__) || defined(MACOSX)
 580         /* Include-mode filtering broken on Mac OS & Linux at least to 2.6.24 */
 581         return IOS_UNAVAILABLE;
 582 #else
 583         initGroupSourceReq(env, group, index, source, &req);
 584         opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
 585         optval = (void*)&req;
 586         optlen = sizeof(req);
 587 #endif
 588     }
 589 
 590     n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
 591     if (n < 0) {
 592         if (join && (errno == ENOPROTOOPT))
 593             return IOS_UNAVAILABLE;
 594         handleSocketError(env, errno);
 595     }
 596     return 0;
 597 #else
 598     JNU_ThrowInternalError(env, "Should not get here");
 599     return IOS_THROWN;
 600 #endif  /* AF_INET6 */
 601 }
 602 
 603 JNIEXPORT jint JNICALL
 604 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
 605                                     jbyteArray group, jint index, jbyteArray source)
 606 {
 607 #ifdef AF_INET6
 608   #ifdef MACOSX
 609     /* no IPv6 exclude-mode filtering for now */
 610     return IOS_UNAVAILABLE;
 611   #else
 612     struct my_group_source_req req;
 613     int n;
 614     int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
 615 
 616     initGroupSourceReq(env, group, index, source, &req);
 617 
 618     n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
 619         (void*)&req, sizeof(req));
 620     if (n < 0) {
 621         if (block && (errno == ENOPROTOOPT))
 622             return IOS_UNAVAILABLE;
 623         handleSocketError(env, errno);
 624     }
 625     return 0;
 626   #endif
 627 #else
 628     JNU_ThrowInternalError(env, "Should not get here");
 629     return IOS_THROWN;
 630 #endif
 631 }
 632 
 633 JNIEXPORT void JNICALL
 634 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
 635 {
 636     struct in_addr in;
 637     socklen_t arglen = sizeof(struct in_addr);
 638     int n;
 639 
 640     in.s_addr = htonl(interf);
 641 
 642     n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
 643                    (void*)&(in.s_addr), arglen);
 644     if (n < 0) {
 645         handleSocketError(env, errno);
 646     }
 647 }
 648 
 649 JNIEXPORT jint JNICALL
 650 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
 651 {
 652     struct in_addr in;
 653     socklen_t arglen = sizeof(struct in_addr);
 654     int n;
 655 
 656     n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
 657     if (n < 0) {
 658         handleSocketError(env, errno);
 659         return -1;
 660     }
 661     return ntohl(in.s_addr);
 662 }
 663 
 664 JNIEXPORT void JNICALL
 665 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
 666 {
 667     int value = (jint)index;
 668     socklen_t arglen = sizeof(value);
 669     int n;
 670 
 671     n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
 672                    (void*)&(index), arglen);
 673     if (n < 0) {
 674         handleSocketError(env, errno);
 675     }
 676 }
 677 
 678 JNIEXPORT jint JNICALL
 679 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
 680 {
 681     int index;
 682     socklen_t arglen = sizeof(index);
 683     int n;
 684 
 685     n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
 686     if (n < 0) {
 687         handleSocketError(env, errno);
 688         return -1;
 689     }
 690     return (jint)index;
 691 }
 692 
 693 JNIEXPORT void JNICALL
 694 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)
 695 {
 696     int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
 697         (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
 698     if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN))
 699         handleSocketError(env, errno);
 700 }
 701 
 702 /* Declared in nio_util.h */
 703 
 704 jint
 705 handleSocketError(JNIEnv *env, jint errorValue)
 706 {
 707     char *xn;
 708     switch (errorValue) {
 709         case EINPROGRESS:       /* Non-blocking connect */
 710             return 0;
 711 #ifdef EPROTO
 712         case EPROTO:
 713             xn = JNU_JAVANETPKG "ProtocolException";
 714             break;
 715 #endif
 716         case ECONNREFUSED:
 717             xn = JNU_JAVANETPKG "ConnectException";
 718             break;
 719         case ETIMEDOUT:
 720             xn = JNU_JAVANETPKG "ConnectException";
 721             break;
 722         case EHOSTUNREACH:
 723             xn = JNU_JAVANETPKG "NoRouteToHostException";
 724             break;
 725         case EADDRINUSE:  /* Fall through */
 726         case EADDRNOTAVAIL:
 727             xn = JNU_JAVANETPKG "BindException";
 728             break;
 729         default:
 730             xn = JNU_JAVANETPKG "SocketException";
 731             break;
 732     }
 733     errno = errorValue;
 734     JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
 735     return IOS_THROWN;
 736 }