Path: blob/master/src/java.base/unix/native/libnio/ch/Net.c
41133 views
/*1* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <poll.h>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#include <limits.h>3233#include "jni.h"34#include "jni_util.h"35#include "jvm.h"36#include "jlong.h"37#include "sun_nio_ch_Net.h"38#include "net_util.h"39#include "net_util_md.h"40#include "nio_util.h"41#include "nio.h"4243#ifdef _AIX44#include <stdlib.h>45#include <sys/utsname.h>46#endif4748/**49* IP_MULTICAST_ALL supported since 2.6.31 but may not be available at50* build time.51*/52#ifdef __linux__53#ifndef IP_MULTICAST_ALL54#define IP_MULTICAST_ALL 4955#endif56#endif5758/**59* IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP may not be defined on OSX and AIX60*/61#if defined(__APPLE__) || defined(_AIX)62#ifndef IPV6_ADD_MEMBERSHIP63#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP64#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP65#endif66#endif6768#define COPY_INET6_ADDRESS(env, source, target) \69(*env)->GetByteArrayRegion(env, source, 0, 16, target)7071/*72* Copy IPv6 group, interface index, and IPv6 source address73* into group_source_req structure.74*/75static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index,76jbyteArray source, struct group_source_req *req)77{78struct sockaddr_in6* sin6;7980req->gsr_interface = (uint32_t)index;8182sin6 = (struct sockaddr_in6 *)&(req->gsr_group);83sin6->sin6_family = AF_INET6;84COPY_INET6_ADDRESS(env, group, (jbyte *)&(sin6->sin6_addr));8586sin6 = (struct sockaddr_in6 *)&(req->gsr_source);87sin6->sin6_family = AF_INET6;88COPY_INET6_ADDRESS(env, source, (jbyte *)&(sin6->sin6_addr));89}9091#ifdef _AIX9293/*94* Checks whether or not "socket extensions for multicast source filters" is supported.95* Returns JNI_TRUE if it is supported, JNI_FALSE otherwise96*/97static jboolean isSourceFilterSupported(){98static jboolean alreadyChecked = JNI_FALSE;99static jboolean result = JNI_TRUE;100if (alreadyChecked != JNI_TRUE){101struct utsname uts;102memset(&uts, 0, sizeof(uts));103strcpy(uts.sysname, "?");104const int utsRes = uname(&uts);105int major = -1;106int minor = -1;107major = atoi(uts.version);108minor = atoi(uts.release);109if (strcmp(uts.sysname, "AIX") == 0) {110if (major < 6 || (major == 6 && minor < 1)) {// unsupported on aix < 6.1111result = JNI_FALSE;112}113}114alreadyChecked = JNI_TRUE;115}116return result;117}118119#endif /* _AIX */120121static jclass isa_class; /* java.net.InetSocketAddress */122static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */123124JNIEXPORT void JNICALL125Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)126{127jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");128CHECK_NULL(cls);129isa_class = (*env)->NewGlobalRef(env, cls);130if (isa_class == NULL) {131JNU_ThrowOutOfMemoryError(env, NULL);132return;133}134isa_ctorID = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/net/InetAddress;I)V");135CHECK_NULL(isa_ctorID);136137initInetAddressIDs(env);138}139140JNIEXPORT jboolean JNICALL141Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)142{143return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;144}145146JNIEXPORT jboolean JNICALL147Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1)148{149return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;150}151152JNIEXPORT jint JNICALL153Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {154return -1;155}156157JNIEXPORT jboolean JNICALL158Java_sun_nio_ch_Net_shouldSetBothIPv4AndIPv6Options0(JNIEnv* env, jclass cl)159{160#if defined(__linux__)161/* Set both IPv4 and IPv6 socket options when setting multicast options */162return JNI_TRUE;163#else164/* Do not set both IPv4 and IPv6 socket options when setting multicast options */165return JNI_FALSE;166#endif167}168169JNIEXPORT jboolean JNICALL170Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)171{172#if defined(__linux__) || defined(__APPLE__)173/* IPv6 sockets can join IPv4 multicast groups */174return JNI_TRUE;175#else176/* IPv6 sockets cannot join IPv4 multicast groups */177return JNI_FALSE;178#endif179}180181JNIEXPORT jboolean JNICALL182Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)183{184#if defined(__APPLE__)185/* IPV6_ADD_MEMBERSHIP can be used to join IPv4 multicast groups */186return JNI_TRUE;187#else188/* IPV6_ADD_MEMBERSHIP cannot be used to join IPv4 multicast groups */189return JNI_FALSE;190#endif191}192193JNIEXPORT jboolean JNICALL194Java_sun_nio_ch_Net_canUseIPv6OptionsWithIPv4LocalAddress0(JNIEnv* env, jclass cl)195{196/* IPV6_XXX socket options can be used on IPv6 sockets bound to IPv4 address */197return JNI_TRUE;198}199200JNIEXPORT jint JNICALL201Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,202jboolean stream, jboolean reuse, jboolean ignored)203{204int fd;205int type = (stream ? SOCK_STREAM : SOCK_DGRAM);206int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;207208fd = socket(domain, type, 0);209if (fd < 0) {210return handleSocketError(env, errno);211}212213/*214* If IPv4 is available, disable IPV6_V6ONLY to ensure dual-socket support.215*/216if (domain == AF_INET6 && ipv4_available()) {217int arg = 0;218if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,219sizeof(int)) < 0) {220JNU_ThrowByNameWithLastError(env,221JNU_JAVANETPKG "SocketException",222"Unable to set IPV6_V6ONLY");223close(fd);224return -1;225}226}227228if (reuse) {229int arg = 1;230if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,231sizeof(arg)) < 0) {232JNU_ThrowByNameWithLastError(env,233JNU_JAVANETPKG "SocketException",234"Unable to set SO_REUSEADDR");235close(fd);236return -1;237}238}239240#if defined(__linux__)241if (type == SOCK_DGRAM) {242int arg = 0;243int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;244if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&245(errno != ENOPROTOOPT)) {246JNU_ThrowByNameWithLastError(env,247JNU_JAVANETPKG "SocketException",248"Unable to set IP_MULTICAST_ALL");249close(fd);250return -1;251}252}253254/* By default, Linux uses the route default */255if (domain == AF_INET6 && type == SOCK_DGRAM) {256int arg = 1;257if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,258sizeof(arg)) < 0) {259JNU_ThrowByNameWithLastError(env,260JNU_JAVANETPKG "SocketException",261"Unable to set IPV6_MULTICAST_HOPS");262close(fd);263return -1;264}265}266#endif267268#ifdef __APPLE__269/**270* Attempt to set SO_SNDBUF to a minimum size to allow sending large datagrams271* (net.inet.udp.maxdgram defaults to 9216).272*/273if (type == SOCK_DGRAM) {274int size;275socklen_t arglen = sizeof(size);276if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, &arglen) == 0) {277int minSize = (domain == AF_INET6) ? 65527 : 65507;278if (size < minSize) {279setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &minSize, sizeof(minSize));280}281}282}283#endif284285return fd;286}287288JNIEXPORT void JNICALL289Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,290jboolean useExclBind, jobject iao, int port)291{292SOCKETADDRESS sa;293int sa_len = 0;294int rv = 0;295296if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,297preferIPv6) != 0) {298return;299}300301rv = NET_Bind(fdval(env, fdo), &sa, sa_len);302if (rv != 0) {303handleSocketError(env, errno);304}305}306307JNIEXPORT void JNICALL308Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)309{310if (listen(fdval(env, fdo), backlog) < 0)311handleSocketError(env, errno);312}313314JNIEXPORT jint JNICALL315Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6,316jobject fdo, jobject iao, jint port)317{318SOCKETADDRESS sa;319int sa_len = 0;320int rv;321322if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) {323return IOS_THROWN;324}325326rv = connect(fdval(env, fdo), &sa.sa, sa_len);327if (rv != 0) {328if (errno == EINPROGRESS) {329return IOS_UNAVAILABLE;330} else if (errno == EINTR) {331return IOS_INTERRUPTED;332}333return handleSocketError(env, errno);334}335return 1;336}337338JNIEXPORT jint JNICALL339Java_sun_nio_ch_Net_accept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,340jobjectArray isaa)341{342jint fd = fdval(env, fdo);343jint newfd;344SOCKETADDRESS sa;345socklen_t sa_len = sizeof(SOCKETADDRESS);346jobject remote_ia;347jint remote_port = 0;348jobject isa;349350/* accept connection but ignore ECONNABORTED */351for (;;) {352newfd = accept(fd, &sa.sa, &sa_len);353if (newfd >= 0) {354break;355}356if (errno != ECONNABORTED) {357break;358}359/* ECONNABORTED => restart accept */360}361362if (newfd < 0) {363if (errno == EAGAIN || errno == EWOULDBLOCK)364return IOS_UNAVAILABLE;365if (errno == EINTR)366return IOS_INTERRUPTED;367JNU_ThrowIOExceptionWithLastError(env, "Accept failed");368return IOS_THROWN;369}370371setfdval(env, newfdo, newfd);372373remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);374CHECK_NULL_RETURN(remote_ia, IOS_THROWN);375376isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port);377CHECK_NULL_RETURN(isa, IOS_THROWN);378(*env)->SetObjectArrayElement(env, isaa, 0, isa);379380return 1;381}382383JNIEXPORT jint JNICALL384Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)385{386SOCKETADDRESS sa;387socklen_t sa_len = sizeof(SOCKETADDRESS);388if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {389#ifdef _ALLBSD_SOURCE390/*391* XXXBSD:392* ECONNRESET is specific to the BSDs. We can not return an error,393* as the calling Java code with raise a java.lang.Error given the expectation394* that getsockname() will never fail. According to the Single UNIX Specification,395* it shouldn't fail. As such, we just fill in generic Linux-compatible values.396*/397if (errno == ECONNRESET) {398bzero(&sa.sa4, sizeof(sa));399sa.sa4.sin_len = sizeof(struct sockaddr_in);400sa.sa4.sin_family = AF_INET;401sa.sa4.sin_port = htonl(0);402sa.sa4.sin_addr.s_addr = INADDR_ANY;403} else {404handleSocketError(env, errno);405return -1;406}407#else /* _ALLBSD_SOURCE */408handleSocketError(env, errno);409return -1;410#endif /* _ALLBSD_SOURCE */411}412return NET_GetPortFromSockaddr(&sa);413}414415JNIEXPORT jobject JNICALL416Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)417{418SOCKETADDRESS sa;419socklen_t sa_len = sizeof(SOCKETADDRESS);420int port;421if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {422#ifdef _ALLBSD_SOURCE423/*424* XXXBSD:425* ECONNRESET is specific to the BSDs. We can not return an error,426* as the calling Java code with raise a java.lang.Error with the expectation427* that getsockname() will never fail. According to the Single UNIX Specification,428* it shouldn't fail. As such, we just fill in generic Linux-compatible values.429*/430if (errno == ECONNRESET) {431bzero(&sa.sa4, sizeof(sa));432sa.sa4.sin_len = sizeof(struct sockaddr_in);433sa.sa4.sin_family = AF_INET;434sa.sa4.sin_port = htonl(0);435sa.sa4.sin_addr.s_addr = INADDR_ANY;436} else {437handleSocketError(env, errno);438return NULL;439}440#else /* _ALLBSD_SOURCE */441handleSocketError(env, errno);442return NULL;443#endif /* _ALLBSD_SOURCE */444}445return NET_SockaddrToInetAddress(env, &sa, &port);446}447448JNIEXPORT jint JNICALL449Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo)450{451SOCKETADDRESS sa;452socklen_t sa_len = sizeof(sa);453454if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {455handleSocketError(env, errno);456return IOS_THROWN;457}458return NET_GetPortFromSockaddr(&sa);459}460461JNIEXPORT jobject JNICALL462Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo)463{464SOCKETADDRESS sa;465socklen_t sa_len = sizeof(sa);466int port;467468if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {469handleSocketError(env, errno);470return NULL;471}472return NET_SockaddrToInetAddress(env, &sa, &port);473}474475JNIEXPORT jint JNICALL476Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,477jboolean mayNeedConversion, jint level, jint opt)478{479int result;480struct linger linger;481u_char carg;482void *arg;483socklen_t arglen;484int n;485486/* Option value is an int except for a few specific cases */487488arg = (void *)&result;489arglen = sizeof(result);490491if (level == IPPROTO_IP &&492(opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {493arg = (void*)&carg;494arglen = sizeof(carg);495}496497if (level == SOL_SOCKET && opt == SO_LINGER) {498arg = (void *)&linger;499arglen = sizeof(linger);500}501502if (mayNeedConversion) {503n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen);504} else {505n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);506}507if (n < 0) {508JNU_ThrowByNameWithLastError(env,509JNU_JAVANETPKG "SocketException",510"sun.nio.ch.Net.getIntOption");511return -1;512}513514if (level == IPPROTO_IP &&515(opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))516{517return (jint)carg;518}519520if (level == SOL_SOCKET && opt == SO_LINGER)521return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;522523return (jint)result;524}525526JNIEXPORT void JNICALL527Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,528jboolean mayNeedConversion, jint level,529jint opt, jint arg, jboolean isIPv6)530{531int result;532struct linger linger;533u_char carg;534void *parg;535socklen_t arglen;536int n;537538/* Option value is an int except for a few specific cases */539540parg = (void*)&arg;541arglen = sizeof(arg);542543if (level == IPPROTO_IP &&544(opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {545parg = (void*)&carg;546arglen = sizeof(carg);547carg = (u_char)arg;548}549550if (level == SOL_SOCKET && opt == SO_LINGER) {551parg = (void *)&linger;552arglen = sizeof(linger);553if (arg >= 0) {554linger.l_onoff = 1;555linger.l_linger = arg;556} else {557linger.l_onoff = 0;558linger.l_linger = 0;559}560}561562if (mayNeedConversion) {563n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);564} else {565n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);566}567if (n < 0) {568JNU_ThrowByNameWithLastError(env,569JNU_JAVANETPKG "SocketException",570"sun.nio.ch.Net.setIntOption");571}572}573574JNIEXPORT jint JNICALL575Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,576jint group, jint interf, jint source)577{578struct ip_mreq mreq;579struct ip_mreq_source mreq_source;580int opt, n, optlen;581void* optval;582583if (source == 0) {584mreq.imr_multiaddr.s_addr = htonl(group);585mreq.imr_interface.s_addr = htonl(interf);586opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;587optval = (void*)&mreq;588optlen = sizeof(mreq);589} else {590591#ifdef _AIX592/* check AIX for support of source filtering */593if (isSourceFilterSupported() != JNI_TRUE){594return IOS_UNAVAILABLE;595}596#endif597598mreq_source.imr_multiaddr.s_addr = htonl(group);599mreq_source.imr_sourceaddr.s_addr = htonl(source);600mreq_source.imr_interface.s_addr = htonl(interf);601opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;602optval = (void*)&mreq_source;603optlen = sizeof(mreq_source);604}605606n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);607#ifdef __APPLE__608// workaround macOS bug where IP_ADD_MEMBERSHIP fails intermittently609if (n < 0 && errno == ENOMEM) {610n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);611}612#endif613614if (n < 0) {615if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))616return IOS_UNAVAILABLE;617handleSocketError(env, errno);618}619return 0;620}621622JNIEXPORT jint JNICALL623Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,624jint group, jint interf, jint source)625{626#ifdef __APPLE__627/* no IPv4 exclude-mode filtering for now */628return IOS_UNAVAILABLE;629#else630struct ip_mreq_source mreq_source;631int n;632int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;633634#ifdef _AIX635/* check AIX for support of source filtering */636if (isSourceFilterSupported() != JNI_TRUE){637return IOS_UNAVAILABLE;638}639#endif640641mreq_source.imr_multiaddr.s_addr = htonl(group);642mreq_source.imr_sourceaddr.s_addr = htonl(source);643mreq_source.imr_interface.s_addr = htonl(interf);644645n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,646(void*)&mreq_source, sizeof(mreq_source));647if (n < 0) {648if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))649return IOS_UNAVAILABLE;650handleSocketError(env, errno);651}652return 0;653#endif654}655656JNIEXPORT jint JNICALL657Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,658jbyteArray group, jint index, jbyteArray source)659{660struct ipv6_mreq mreq6;661struct group_source_req req;662int opt, n, optlen;663void* optval;664665if (source == NULL) {666COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));667mreq6.ipv6mr_interface = (int)index;668opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;669optval = (void*)&mreq6;670optlen = sizeof(mreq6);671} else {672#ifdef __APPLE__673/* no IPv6 include-mode filtering for now */674return IOS_UNAVAILABLE;675#else676initGroupSourceReq(env, group, index, source, &req);677opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;678optval = (void*)&req;679optlen = sizeof(req);680#endif681}682683n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);684#ifdef __APPLE__685// workaround macOS bug where IPV6_ADD_MEMBERSHIP fails intermittently686if (n < 0 && errno == ENOMEM) {687n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);688}689#endif690691if (n < 0) {692if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))693return IOS_UNAVAILABLE;694handleSocketError(env, errno);695}696return 0;697}698699JNIEXPORT jint JNICALL700Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,701jbyteArray group, jint index, jbyteArray source)702{703#ifdef __APPLE__704/* no IPv6 exclude-mode filtering for now */705return IOS_UNAVAILABLE;706#else707struct group_source_req req;708int n;709int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;710711initGroupSourceReq(env, group, index, source, &req);712713n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,714(void*)&req, sizeof(req));715if (n < 0) {716if (block && (errno == ENOPROTOOPT || errno == EOPNOTSUPP))717return IOS_UNAVAILABLE;718handleSocketError(env, errno);719}720return 0;721#endif722}723724JNIEXPORT void JNICALL725Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)726{727struct in_addr in;728socklen_t arglen = sizeof(struct in_addr);729int n;730731in.s_addr = htonl(interf);732733n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,734(void*)&(in.s_addr), arglen);735if (n < 0) {736handleSocketError(env, errno);737}738}739740JNIEXPORT jint JNICALL741Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)742{743struct in_addr in;744socklen_t arglen = sizeof(struct in_addr);745int n;746747n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);748if (n < 0) {749handleSocketError(env, errno);750return -1;751}752return ntohl(in.s_addr);753}754755JNIEXPORT void JNICALL756Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)757{758int value = (jint)index;759socklen_t arglen = sizeof(value);760int n;761762n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,763(void*)&(index), arglen);764if (n < 0) {765handleSocketError(env, errno);766}767}768769JNIEXPORT jint JNICALL770Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)771{772int index;773socklen_t arglen = sizeof(index);774int n;775776n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);777if (n < 0) {778handleSocketError(env, errno);779return -1;780}781return (jint)index;782}783784JNIEXPORT void JNICALL785Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)786{787int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :788(jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;789if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN))790handleSocketError(env, errno);791}792793JNIEXPORT jint JNICALL794Java_sun_nio_ch_Net_available(JNIEnv *env, jclass cl, jobject fdo)795{796int count = 0;797if (NET_SocketAvailable(fdval(env, fdo), &count) != 0) {798handleSocketError(env, errno);799return IOS_THROWN;800}801return (jint) count;802}803804JNIEXPORT jint JNICALL805Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout)806{807struct pollfd pfd;808int rv;809pfd.fd = fdval(env, fdo);810pfd.events = events;811if (timeout < -1) {812timeout = -1;813} else if (timeout > INT_MAX) {814timeout = INT_MAX;815}816rv = poll(&pfd, 1, (int)timeout);817818if (rv >= 0) {819return pfd.revents;820} else if (errno == EINTR) {821// interrupted, no events to return822return 0;823} else {824handleSocketError(env, errno);825return IOS_THROWN;826}827}828829JNIEXPORT jboolean JNICALL830Java_sun_nio_ch_Net_pollConnect(JNIEnv *env, jobject this, jobject fdo, jlong timeout)831{832jint fd = fdval(env, fdo);833struct pollfd poller;834int result;835836poller.fd = fd;837poller.events = POLLOUT;838poller.revents = 0;839if (timeout < -1) {840timeout = -1;841} else if (timeout > INT_MAX) {842timeout = INT_MAX;843}844845result = poll(&poller, 1, (int)timeout);846847if (result > 0) {848int error = 0;849socklen_t n = sizeof(int);850errno = 0;851result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n);852if (result < 0) {853handleSocketError(env, errno);854return JNI_FALSE;855} else if (error) {856handleSocketError(env, error);857return JNI_FALSE;858} else if ((poller.revents & POLLHUP) != 0) {859handleSocketError(env, ENOTCONN);860return JNI_FALSE;861}862// connected863return JNI_TRUE;864} else if (result == 0 || errno == EINTR) {865return JNI_FALSE;866} else {867JNU_ThrowIOExceptionWithLastError(env, "poll failed");868return JNI_FALSE;869}870}871872JNIEXPORT jshort JNICALL873Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this)874{875return (jshort)POLLIN;876}877878JNIEXPORT jshort JNICALL879Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this)880{881return (jshort)POLLOUT;882}883884JNIEXPORT jshort JNICALL885Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this)886{887return (jshort)POLLERR;888}889890JNIEXPORT jshort JNICALL891Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this)892{893return (jshort)POLLHUP;894}895896JNIEXPORT jshort JNICALL897Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this)898{899return (jshort)POLLNVAL;900}901902JNIEXPORT jshort JNICALL903Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this)904{905return (jshort)POLLOUT;906}907908JNIEXPORT jint JNICALL909Java_sun_nio_ch_Net_sendOOB(JNIEnv* env, jclass this, jobject fdo, jbyte b)910{911int n = send(fdval(env, fdo), (const void*)&b, 1, MSG_OOB);912return convertReturnVal(env, n, JNI_FALSE);913}914915/* Declared in nio_util.h */916917jint handleSocketError(JNIEnv *env, jint errorValue)918{919char *xn;920switch (errorValue) {921case EINPROGRESS: /* Non-blocking connect */922return 0;923#ifdef EPROTO924case EPROTO:925xn = JNU_JAVANETPKG "ProtocolException";926break;927#endif928case ECONNREFUSED:929case ETIMEDOUT:930case ENOTCONN:931xn = JNU_JAVANETPKG "ConnectException";932break;933934case EHOSTUNREACH:935xn = JNU_JAVANETPKG "NoRouteToHostException";936break;937case EADDRINUSE: /* Fall through */938case EADDRNOTAVAIL:939case EACCES:940xn = JNU_JAVANETPKG "BindException";941break;942default:943xn = JNU_JAVANETPKG "SocketException";944break;945}946errno = errorValue;947JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");948return IOS_THROWN;949}950951952