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