1 /*
   2  * Copyright (c) 2001, 2020, 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 <poll.h>
  27 #include <sys/types.h>
  28 #include <sys/socket.h>
  29 #include <string.h>
  30 #include <netinet/in.h>
  31 #include <netinet/tcp.h>
  32 #include <limits.h>
  33 
  34 #include "jni.h"
  35 #include "jni_util.h"
  36 #include "jvm.h"
  37 #include "jlong.h"
  38 #include "sun_nio_ch_Net.h"
  39 #include "net_util.h"
  40 #include "net_util_md.h"
  41 #include "nio_util.h"
  42 #include "nio.h"
  43 
  44 #ifdef _AIX
  45 #include <stdlib.h>
  46 #include <sys/utsname.h>
  47 #endif
  48 
  49 /**
  50  * IP_MULTICAST_ALL supported since 2.6.31 but may not be available at
  51  * build time.
  52  */
  53 #ifdef __linux__
  54   #ifndef IP_MULTICAST_ALL
  55     #define IP_MULTICAST_ALL    49
  56   #endif
  57 #endif
  58 
  59 /**
  60  * IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP may not be defined on OSX and AIX
  61  */
  62 #if defined(__APPLE__) || defined(_AIX)
  63   #ifndef IPV6_ADD_MEMBERSHIP
  64     #define IPV6_ADD_MEMBERSHIP     IPV6_JOIN_GROUP
  65     #define IPV6_DROP_MEMBERSHIP    IPV6_LEAVE_GROUP
  66   #endif
  67 #endif
  68 
  69 #define COPY_INET6_ADDRESS(env, source, target) \
  70     (*env)->GetByteArrayRegion(env, source, 0, 16, target)
  71 
  72 /*
  73  * Copy IPv6 group, interface index, and IPv6 source address
  74  * into group_source_req structure.
  75  */
  76 static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index,
  77                                jbyteArray source, struct group_source_req *req)
  78 {
  79     struct sockaddr_in6* sin6;
  80 
  81     req->gsr_interface = (uint32_t)index;
  82 
  83     sin6 = (struct sockaddr_in6 *)&(req->gsr_group);
  84     sin6->sin6_family = AF_INET6;
  85     COPY_INET6_ADDRESS(env, group, (jbyte *)&(sin6->sin6_addr));
  86 
  87     sin6 = (struct sockaddr_in6 *)&(req->gsr_source);
  88     sin6->sin6_family = AF_INET6;
  89     COPY_INET6_ADDRESS(env, source, (jbyte *)&(sin6->sin6_addr));
  90 }
  91 
  92 #ifdef _AIX
  93 
  94 /*
  95  * Checks whether or not "socket extensions for multicast source filters" is supported.
  96  * Returns JNI_TRUE if it is supported, JNI_FALSE otherwise
  97  */
  98 static jboolean isSourceFilterSupported(){
  99     static jboolean alreadyChecked = JNI_FALSE;
 100     static jboolean result = JNI_TRUE;
 101     if (alreadyChecked != JNI_TRUE){
 102         struct utsname uts;
 103         memset(&uts, 0, sizeof(uts));
 104         strcpy(uts.sysname, "?");
 105         const int utsRes = uname(&uts);
 106         int major = -1;
 107         int minor = -1;
 108         major = atoi(uts.version);
 109         minor = atoi(uts.release);
 110         if (strcmp(uts.sysname, "AIX") == 0) {
 111             if (major < 6 || (major == 6 && minor < 1)) {// unsupported on aix < 6.1
 112                 result = JNI_FALSE;
 113             }
 114         }
 115         alreadyChecked = JNI_TRUE;
 116     }
 117     return result;
 118 }
 119 
 120 #endif  /* _AIX */
 121 
 122 static jclass isa_class;        /* java.net.InetSocketAddress */
 123 static jmethodID isa_ctorID;    /* InetSocketAddress(InetAddress, int) */
 124 
 125 JNIEXPORT void JNICALL
 126 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
 127 {
 128      jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
 129      CHECK_NULL(cls);
 130      isa_class = (*env)->NewGlobalRef(env, cls);
 131      if (isa_class == NULL) {
 132          JNU_ThrowOutOfMemoryError(env, NULL);
 133          return;
 134      }
 135      isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/net/InetAddress;I)V");
 136      CHECK_NULL(isa_ctorID);
 137 
 138      initInetAddressIDs(env);
 139 }
 140 
 141 JNIEXPORT jboolean JNICALL
 142 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
 143 {
 144     return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
 145 }
 146 
 147 JNIEXPORT jboolean JNICALL
 148 Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1)
 149 {
 150     return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
 151 }
 152 
 153 JNIEXPORT jint JNICALL
 154 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
 155     return -1;
 156 }
 157 
 158 JNIEXPORT jboolean JNICALL
 159 Java_sun_nio_ch_Net_shouldSetBothIPv4AndIPv6Options0(JNIEnv* env, jclass cl)
 160 {
 161 #if defined(__linux__)
 162     /* Set both IPv4 and IPv6 socket options when setting multicast options */
 163     return JNI_TRUE;
 164 #else
 165     /* Do not set both IPv4 and IPv6 socket options when setting multicast options */
 166     return JNI_FALSE;
 167 #endif
 168 }
 169 
 170 JNIEXPORT jboolean JNICALL
 171 Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
 172 {
 173 #if defined(__linux__) || defined(__APPLE__)
 174     /* IPv6 sockets can join IPv4 multicast groups */
 175     return JNI_TRUE;
 176 #else
 177     /* IPv6 sockets cannot join IPv4 multicast groups */
 178     return JNI_FALSE;
 179 #endif
 180 }
 181 
 182 JNIEXPORT jboolean JNICALL
 183 Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
 184 {
 185 #if defined(__APPLE__)
 186     /* IPV6_ADD_MEMBERSHIP can be used to join IPv4 multicast groups */
 187     return JNI_TRUE;
 188 #else
 189     /* IPV6_ADD_MEMBERSHIP cannot be used to join IPv4 multicast groups */
 190     return JNI_FALSE;
 191 #endif
 192 }
 193 
 194 JNIEXPORT jboolean JNICALL
 195 Java_sun_nio_ch_Net_canUseIPv6OptionsWithIPv4LocalAddress0(JNIEnv* env, jclass cl)
 196 {
 197     /* IPV6_XXX socket options can be used on IPv6 sockets bound to IPv4 address */
 198     return JNI_TRUE;
 199 }
 200 
 201 JNIEXPORT jint JNICALL
 202 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
 203                             jboolean stream, jboolean reuse, jboolean ignored)
 204 {
 205     int fd;
 206     int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
 207     int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
 208 
 209     fd = socket(domain, type, 0);
 210     if (fd < 0) {
 211         return handleSocketError(env, errno);
 212     }
 213 
 214     /*
 215      * If IPv4 is available, disable IPV6_V6ONLY to ensure dual-socket support.
 216      */
 217     if (domain == AF_INET6 && ipv4_available()) {
 218         int arg = 0;
 219         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
 220                        sizeof(int)) < 0) {
 221             JNU_ThrowByNameWithLastError(env,
 222                                          JNU_JAVANETPKG "SocketException",
 223                                          "Unable to set IPV6_V6ONLY");
 224             close(fd);
 225             return -1;
 226         }
 227     }
 228 
 229     if (reuse) {
 230         int arg = 1;
 231         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
 232                        sizeof(arg)) < 0) {
 233             JNU_ThrowByNameWithLastError(env,
 234                                          JNU_JAVANETPKG "SocketException",
 235                                          "Unable to set SO_REUSEADDR");
 236             close(fd);
 237             return -1;
 238         }
 239     }
 240 
 241 #if defined(__linux__)
 242     if (type == SOCK_DGRAM) {
 243         int arg = 0;
 244         int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
 245         if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
 246             (errno != ENOPROTOOPT)) {
 247             JNU_ThrowByNameWithLastError(env,
 248                                          JNU_JAVANETPKG "SocketException",
 249                                          "Unable to set IP_MULTICAST_ALL");
 250             close(fd);
 251             return -1;
 252         }
 253     }
 254 
 255     /* By default, Linux uses the route default */
 256     if (domain == AF_INET6 && type == SOCK_DGRAM) {
 257         int arg = 1;
 258         if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
 259                        sizeof(arg)) < 0) {
 260             JNU_ThrowByNameWithLastError(env,
 261                                          JNU_JAVANETPKG "SocketException",
 262                                          "Unable to set IPV6_MULTICAST_HOPS");
 263             close(fd);
 264             return -1;
 265         }
 266     }
 267 #endif
 268 
 269 #ifdef __APPLE__
 270     /**
 271      * Attempt to set SO_SNDBUF to a minimum size to allow sending large datagrams
 272      * (net.inet.udp.maxdgram defaults to 9216).
 273      */
 274     if (type == SOCK_DGRAM) {
 275         int size;
 276         socklen_t arglen = sizeof(size);
 277         if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, &arglen) == 0) {
 278             int minSize = (domain == AF_INET6) ? 65527  : 65507;
 279             if (size < minSize) {
 280                 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &minSize, sizeof(minSize));
 281             }
 282         }
 283     }
 284 #endif
 285 
 286     return fd;
 287 }
 288 
 289 JNIEXPORT void JNICALL
 290 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,
 291                           jboolean useExclBind, jobject iao, int port)
 292 {
 293     SOCKETADDRESS sa;
 294     int sa_len = 0;
 295     int rv = 0;
 296 
 297     if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
 298                                   preferIPv6) != 0) {
 299         return;
 300     }
 301 
 302     rv = NET_Bind(fdval(env, fdo), &sa, sa_len);
 303     if (rv != 0) {
 304         handleSocketError(env, errno);
 305     }
 306 }
 307 
 308 JNIEXPORT void JNICALL
 309 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
 310 {
 311     if (listen(fdval(env, fdo), backlog) < 0)
 312         handleSocketError(env, errno);
 313 }
 314 
 315 JNIEXPORT jint JNICALL
 316 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
 317                              jobject fdo, jobject iao, jint port)
 318 {
 319     SOCKETADDRESS sa;
 320     int sa_len = 0;
 321     int rv;
 322 
 323     if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) {
 324         return IOS_THROWN;
 325     }
 326 
 327     rv = connect(fdval(env, fdo), &sa.sa, sa_len);
 328     if (rv != 0) {
 329         if (errno == EINPROGRESS) {
 330             return IOS_UNAVAILABLE;
 331         } else if (errno == EINTR) {
 332             return IOS_INTERRUPTED;
 333         }
 334         return handleSocketError(env, errno);
 335     }
 336     return 1;
 337 }
 338 
 339 JNIEXPORT jint JNICALL
 340 Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
 341                            jobjectArray isaa)
 342 {
 343     jint fd = fdval(env, fdo);
 344     jint newfd;
 345     SOCKETADDRESS sa;
 346     socklen_t sa_len = sizeof(SOCKETADDRESS);
 347     jobject remote_ia;
 348     jint remote_port = 0;
 349     jobject isa;
 350 
 351     /* accept connection but ignore ECONNABORTED */
 352     for (;;) {
 353         newfd = accept(fd, &sa.sa, &sa_len);
 354         if (newfd >= 0) {
 355             break;
 356         }
 357         if (errno != ECONNABORTED) {
 358             break;
 359         }
 360         /* ECONNABORTED => restart accept */
 361     }
 362 
 363     if (newfd < 0) {
 364         if (errno == EAGAIN || errno == EWOULDBLOCK)
 365             return IOS_UNAVAILABLE;
 366         if (errno == EINTR)
 367             return IOS_INTERRUPTED;
 368         JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
 369         return IOS_THROWN;
 370     }
 371 
 372     setfdval(env, newfdo, newfd);
 373 
 374     remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
 375     CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
 376 
 377     isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port);
 378     CHECK_NULL_RETURN(isa, IOS_THROWN);
 379     (*env)->SetObjectArrayElement(env, isaa, 0, isa);
 380 
 381     return 1;
 382 }
 383 
 384 JNIEXPORT jint JNICALL
 385 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
 386 {
 387     SOCKETADDRESS sa;
 388     socklen_t sa_len = sizeof(SOCKETADDRESS);
 389     if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
 390 #ifdef _ALLBSD_SOURCE
 391         /*
 392          * XXXBSD:
 393          * ECONNRESET is specific to the BSDs. We can not return an error,
 394          * as the calling Java code with raise a java.lang.Error given the expectation
 395          * that getsockname() will never fail. According to the Single UNIX Specification,
 396          * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
 397          */
 398         if (errno == ECONNRESET) {
 399             bzero(&sa.sa4, sizeof(sa));
 400             sa.sa4.sin_len = sizeof(struct sockaddr_in);
 401             sa.sa4.sin_family = AF_INET;
 402             sa.sa4.sin_port = htonl(0);
 403             sa.sa4.sin_addr.s_addr = INADDR_ANY;
 404         } else {
 405             handleSocketError(env, errno);
 406             return -1;
 407         }
 408 #else /* _ALLBSD_SOURCE */
 409         handleSocketError(env, errno);
 410         return -1;
 411 #endif /* _ALLBSD_SOURCE */
 412     }
 413     return NET_GetPortFromSockaddr(&sa);
 414 }
 415 
 416 JNIEXPORT jobject JNICALL
 417 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
 418 {
 419     SOCKETADDRESS sa;
 420     socklen_t sa_len = sizeof(SOCKETADDRESS);
 421     int port;
 422     if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
 423 #ifdef _ALLBSD_SOURCE
 424         /*
 425          * XXXBSD:
 426          * ECONNRESET is specific to the BSDs. We can not return an error,
 427          * as the calling Java code with raise a java.lang.Error with the expectation
 428          * that getsockname() will never fail. According to the Single UNIX Specification,
 429          * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
 430          */
 431         if (errno == ECONNRESET) {
 432             bzero(&sa.sa4, sizeof(sa));
 433             sa.sa4.sin_len  = sizeof(struct sockaddr_in);
 434             sa.sa4.sin_family = AF_INET;
 435             sa.sa4.sin_port = htonl(0);
 436             sa.sa4.sin_addr.s_addr = INADDR_ANY;
 437         } else {
 438             handleSocketError(env, errno);
 439             return NULL;
 440         }
 441 #else /* _ALLBSD_SOURCE */
 442         handleSocketError(env, errno);
 443         return NULL;
 444 #endif /* _ALLBSD_SOURCE */
 445     }
 446     return NET_SockaddrToInetAddress(env, &sa, &port);
 447 }
 448 
 449 JNIEXPORT jint JNICALL
 450 Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo)
 451 {
 452     SOCKETADDRESS sa;
 453     socklen_t sa_len = sizeof(sa);
 454 
 455     if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
 456         handleSocketError(env, errno);
 457         return IOS_THROWN;
 458     }
 459     return NET_GetPortFromSockaddr(&sa);
 460 }
 461 
 462 JNIEXPORT jobject JNICALL
 463 Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
 464 {
 465     SOCKETADDRESS sa;
 466     socklen_t sa_len = sizeof(sa);
 467     int port;
 468 
 469     if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
 470         handleSocketError(env, errno);
 471         return NULL;
 472     }
 473     return NET_SockaddrToInetAddress(env, &sa, &port);
 474 }
 475 
 476 JNIEXPORT jint JNICALL
 477 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
 478                                   jboolean mayNeedConversion, jint level, jint opt)
 479 {
 480     int result;
 481     struct linger linger;
 482     u_char carg;
 483     void *arg;
 484     socklen_t arglen;
 485     int n;
 486 
 487     /* Option value is an int except for a few specific cases */
 488 
 489     arg = (void *)&result;
 490     arglen = sizeof(result);
 491 
 492     if (level == IPPROTO_IP &&
 493         (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
 494         arg = (void*)&carg;
 495         arglen = sizeof(carg);
 496     }
 497 
 498     if (level == SOL_SOCKET && opt == SO_LINGER) {
 499         arg = (void *)&linger;
 500         arglen = sizeof(linger);
 501     }
 502 
 503     if (mayNeedConversion) {
 504         n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen);
 505     } else {
 506         n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
 507     }
 508     if (n < 0) {
 509         JNU_ThrowByNameWithLastError(env,
 510                                      JNU_JAVANETPKG "SocketException",
 511                                      "sun.nio.ch.Net.getIntOption");
 512         return -1;
 513     }
 514 
 515     if (level == IPPROTO_IP &&
 516         (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))
 517     {
 518         return (jint)carg;
 519     }
 520 
 521     if (level == SOL_SOCKET && opt == SO_LINGER)
 522         return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;
 523 
 524     return (jint)result;
 525 }
 526 
 527 JNIEXPORT void JNICALL
 528 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
 529                                   jboolean mayNeedConversion, jint level,
 530                                   jint opt, jint arg, jboolean isIPv6)
 531 {
 532     int result;
 533     struct linger linger;
 534     u_char carg;
 535     void *parg;
 536     socklen_t arglen;
 537     int n;
 538 
 539     /* Option value is an int except for a few specific cases */
 540 
 541     parg = (void*)&arg;
 542     arglen = sizeof(arg);
 543 
 544     if (level == IPPROTO_IP &&
 545         (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
 546         parg = (void*)&carg;
 547         arglen = sizeof(carg);
 548         carg = (u_char)arg;
 549     }
 550 
 551     if (level == SOL_SOCKET && opt == SO_LINGER) {
 552         parg = (void *)&linger;
 553         arglen = sizeof(linger);
 554         if (arg >= 0) {
 555             linger.l_onoff = 1;
 556             linger.l_linger = arg;
 557         } else {
 558             linger.l_onoff = 0;
 559             linger.l_linger = 0;
 560         }
 561     }
 562 
 563     if (mayNeedConversion) {
 564         n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
 565     } else {
 566         n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
 567     }
 568     if (n < 0) {
 569         JNU_ThrowByNameWithLastError(env,
 570                                      JNU_JAVANETPKG "SocketException",
 571                                      "sun.nio.ch.Net.setIntOption");
 572     }
 573 }
 574 
 575 JNIEXPORT jint JNICALL
 576 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
 577                                 jint group, jint interf, jint source)
 578 {
 579     struct ip_mreq mreq;
 580     struct ip_mreq_source mreq_source;
 581     int opt, n, optlen;
 582     void* optval;
 583 
 584     if (source == 0) {
 585         mreq.imr_multiaddr.s_addr = htonl(group);
 586         mreq.imr_interface.s_addr = htonl(interf);
 587         opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
 588         optval = (void*)&mreq;
 589         optlen = sizeof(mreq);
 590     } else {
 591 
 592 #ifdef _AIX
 593         /* check AIX for support of source filtering */
 594         if (isSourceFilterSupported() != JNI_TRUE){
 595             return IOS_UNAVAILABLE;
 596         }
 597 #endif
 598 
 599         mreq_source.imr_multiaddr.s_addr = htonl(group);
 600         mreq_source.imr_sourceaddr.s_addr = htonl(source);
 601         mreq_source.imr_interface.s_addr = htonl(interf);
 602         opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
 603         optval = (void*)&mreq_source;
 604         optlen = sizeof(mreq_source);
 605     }
 606 
 607     n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
 608 #ifdef __APPLE__
 609     // workaround macOS bug where IP_ADD_MEMBERSHIP fails intermittently
 610     if (n < 0 && errno == ENOMEM) {
 611         n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
 612     }
 613 #endif
 614 
 615     if (n < 0) {
 616         if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
 617             return IOS_UNAVAILABLE;
 618         handleSocketError(env, errno);
 619     }
 620     return 0;
 621 }
 622 
 623 JNIEXPORT jint JNICALL
 624 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
 625                                     jint group, jint interf, jint source)
 626 {
 627 #ifdef __APPLE__
 628     /* no IPv4 exclude-mode filtering for now */
 629     return IOS_UNAVAILABLE;
 630 #else
 631     struct ip_mreq_source mreq_source;
 632     int n;
 633     int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
 634 
 635 #ifdef _AIX
 636     /* check AIX for support of source filtering */
 637     if (isSourceFilterSupported() != JNI_TRUE){
 638         return IOS_UNAVAILABLE;
 639     }
 640 #endif
 641 
 642     mreq_source.imr_multiaddr.s_addr = htonl(group);
 643     mreq_source.imr_sourceaddr.s_addr = htonl(source);
 644     mreq_source.imr_interface.s_addr = htonl(interf);
 645 
 646     n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
 647                    (void*)&mreq_source, sizeof(mreq_source));
 648     if (n < 0) {
 649         if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
 650             return IOS_UNAVAILABLE;
 651         handleSocketError(env, errno);
 652     }
 653     return 0;
 654 #endif
 655 }
 656 
 657 JNIEXPORT jint JNICALL
 658 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
 659                                 jbyteArray group, jint index, jbyteArray source)
 660 {
 661     struct ipv6_mreq mreq6;
 662     struct group_source_req req;
 663     int opt, n, optlen;
 664     void* optval;
 665 
 666     if (source == NULL) {
 667         COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
 668         mreq6.ipv6mr_interface = (int)index;
 669         opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
 670         optval = (void*)&mreq6;
 671         optlen = sizeof(mreq6);
 672     } else {
 673 #ifdef __APPLE__
 674         /* no IPv6 include-mode filtering for now */
 675         return IOS_UNAVAILABLE;
 676 #else
 677         initGroupSourceReq(env, group, index, source, &req);
 678         opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
 679         optval = (void*)&req;
 680         optlen = sizeof(req);
 681 #endif
 682     }
 683 
 684     n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
 685 #ifdef __APPLE__
 686     // workaround macOS bug where IPV6_ADD_MEMBERSHIP fails intermittently
 687     if (n < 0 && errno == ENOMEM) {
 688         n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
 689     }
 690 #endif
 691 
 692     if (n < 0) {
 693         if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
 694             return IOS_UNAVAILABLE;
 695         handleSocketError(env, errno);
 696     }
 697     return 0;
 698 }
 699 
 700 JNIEXPORT jint JNICALL
 701 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
 702                                     jbyteArray group, jint index, jbyteArray source)
 703 {
 704 #ifdef __APPLE__
 705     /* no IPv6 exclude-mode filtering for now */
 706     return IOS_UNAVAILABLE;
 707 #else
 708     struct group_source_req req;
 709     int n;
 710     int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
 711 
 712     initGroupSourceReq(env, group, index, source, &req);
 713 
 714     n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
 715         (void*)&req, sizeof(req));
 716     if (n < 0) {
 717         if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))
 718             return IOS_UNAVAILABLE;
 719         handleSocketError(env, errno);
 720     }
 721     return 0;
 722 #endif
 723 }
 724 
 725 JNIEXPORT void JNICALL
 726 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
 727 {
 728     struct in_addr in;
 729     socklen_t arglen = sizeof(struct in_addr);
 730     int n;
 731 
 732     in.s_addr = htonl(interf);
 733 
 734     n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
 735                    (void*)&(in.s_addr), arglen);
 736     if (n < 0) {
 737         handleSocketError(env, errno);
 738     }
 739 }
 740 
 741 JNIEXPORT jint JNICALL
 742 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
 743 {
 744     struct in_addr in;
 745     socklen_t arglen = sizeof(struct in_addr);
 746     int n;
 747 
 748     n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
 749     if (n < 0) {
 750         handleSocketError(env, errno);
 751         return -1;
 752     }
 753     return ntohl(in.s_addr);
 754 }
 755 
 756 JNIEXPORT void JNICALL
 757 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
 758 {
 759     int value = (jint)index;
 760     socklen_t arglen = sizeof(value);
 761     int n;
 762 
 763     n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
 764                    (void*)&(index), arglen);
 765     if (n < 0) {
 766         handleSocketError(env, errno);
 767     }
 768 }
 769 
 770 JNIEXPORT jint JNICALL
 771 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
 772 {
 773     int index;
 774     socklen_t arglen = sizeof(index);
 775     int n;
 776 
 777     n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
 778     if (n < 0) {
 779         handleSocketError(env, errno);
 780         return -1;
 781     }
 782     return (jint)index;
 783 }
 784 
 785 JNIEXPORT void JNICALL
 786 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)
 787 {
 788     int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
 789         (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
 790     if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN))
 791         handleSocketError(env, errno);
 792 }
 793 
 794 JNIEXPORT jint JNICALL
 795 Java_sun_nio_ch_Net_available(JNIEnv *env, jclass cl, jobject fdo)
 796 {
 797     int count = 0;
 798     if (NET_SocketAvailable(fdval(env, fdo), &count) != 0) {
 799         handleSocketError(env, errno);
 800         return IOS_THROWN;
 801     }
 802     return (jint) count;
 803 }
 804 
 805 JNIEXPORT jint JNICALL
 806 Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout)
 807 {
 808     struct pollfd pfd;
 809     int rv;
 810     pfd.fd = fdval(env, fdo);
 811     pfd.events = events;
 812     if (timeout < -1) {
 813         timeout = -1;
 814     } else if (timeout > INT_MAX) {
 815         timeout = INT_MAX;
 816     }
 817     rv = poll(&pfd, 1, (int)timeout);
 818 
 819     if (rv >= 0) {
 820         return pfd.revents;
 821     } else if (errno == EINTR) {
 822         // interrupted, no events to return
 823         return 0;
 824     } else {
 825         handleSocketError(env, errno);
 826         return IOS_THROWN;
 827     }
 828 }
 829 
 830 JNIEXPORT jboolean JNICALL
 831 Java_sun_nio_ch_Net_pollConnect(JNIEnv *env, jobject this, jobject fdo, jlong timeout)
 832 {
 833     jint fd = fdval(env, fdo);
 834     struct pollfd poller;
 835     int result;
 836 
 837     poller.fd = fd;
 838     poller.events = POLLOUT;
 839     poller.revents = 0;
 840     if (timeout < -1) {
 841         timeout = -1;
 842     } else if (timeout > INT_MAX) {
 843         timeout = INT_MAX;
 844     }
 845 
 846     result = poll(&poller, 1, (int)timeout);
 847 
 848     if (result > 0) {
 849         int error = 0;
 850         socklen_t n = sizeof(int);
 851         errno = 0;
 852         result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n);
 853         if (result < 0) {
 854             handleSocketError(env, errno);
 855             return JNI_FALSE;
 856         } else if (error) {
 857             handleSocketError(env, error);
 858             return JNI_FALSE;
 859         } else if ((poller.revents & POLLHUP) != 0) {
 860             handleSocketError(env, ENOTCONN);
 861             return JNI_FALSE;
 862         }
 863         // connected
 864         return JNI_TRUE;
 865     } else if (result == 0 || errno == EINTR) {
 866         return JNI_FALSE;
 867     } else {
 868         JNU_ThrowIOExceptionWithLastError(env, "poll failed");
 869         return JNI_FALSE;
 870     }
 871 }
 872 
 873 JNIEXPORT jshort JNICALL
 874 Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this)
 875 {
 876     return (jshort)POLLIN;
 877 }
 878 
 879 JNIEXPORT jshort JNICALL
 880 Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this)
 881 {
 882     return (jshort)POLLOUT;
 883 }
 884 
 885 JNIEXPORT jshort JNICALL
 886 Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this)
 887 {
 888     return (jshort)POLLERR;
 889 }
 890 
 891 JNIEXPORT jshort JNICALL
 892 Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this)
 893 {
 894     return (jshort)POLLHUP;
 895 }
 896 
 897 JNIEXPORT jshort JNICALL
 898 Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this)
 899 {
 900     return (jshort)POLLNVAL;
 901 }
 902 
 903 JNIEXPORT jshort JNICALL
 904 Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this)
 905 {
 906     return (jshort)POLLOUT;
 907 }
 908 
 909 JNIEXPORT jint JNICALL
 910 Java_sun_nio_ch_Net_sendOOB(JNIEnv* env, jclass this, jobject fdo, jbyte b)
 911 {
 912     int n = send(fdval(env, fdo), (const void*)&b, 1, MSG_OOB);
 913     return convertReturnVal(env, n, JNI_FALSE);
 914 }
 915 
 916 /* Declared in nio_util.h */
 917 
 918 jint handleSocketError(JNIEnv *env, jint errorValue)
 919 {
 920     char *xn;
 921     switch (errorValue) {
 922         case EINPROGRESS:       /* Non-blocking connect */
 923             return 0;
 924 #ifdef EPROTO
 925         case EPROTO:
 926             xn = JNU_JAVANETPKG "ProtocolException";
 927             break;
 928 #endif
 929         case ECONNREFUSED:
 930         case ETIMEDOUT:
 931         case ENOTCONN:
 932             xn = JNU_JAVANETPKG "ConnectException";
 933             break;
 934 
 935         case EHOSTUNREACH:
 936             xn = JNU_JAVANETPKG "NoRouteToHostException";
 937             break;
 938         case EADDRINUSE:  /* Fall through */
 939         case EADDRNOTAVAIL:
 940         case EACCES:
 941             xn = JNU_JAVANETPKG "BindException";
 942             break;
 943         default:
 944             xn = JNU_JAVANETPKG "SocketException";
 945             break;
 946     }
 947     errno = errorValue;
 948     JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
 949     return IOS_THROWN;
 950 }