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