/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package libcore.io; import java.io.FileDescriptor; import java.lang.reflect.Field; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetFactoryImpl; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.NioUtils; /*-[ #include "BufferUtils.h" #include "TempFailureRetry.h" #include "java/lang/IllegalArgumentException.h" #include "java/lang/System.h" #include "java/net/Inet6Address.h" #include "java/net/InetAddress.h" #include "java/net/InetSocketAddress.h" #include "java/net/InetUnixAddress.h" #include "java/net/SocketException.h" #include "libcore/io/AsynchronousCloseMonitor.h" #include "libcore/io/GaiException.h" #include "libcore/io/Posix.h" #include <arpa/inet.h> #include <ifaddrs.h> #include <net/if.h> #include <netdb.h> #include <sys/ioctl.h> #include <sys/un.h> static inline BOOL throwIfClosed(JavaIoFileDescriptor *fd) { if ([fd getInt$] == -1) { @throw create_JavaNetSocketException_initWithNSString_(@"Socket closed"); } return YES; } #define NET_FAILURE_RETRY(return_type, syscall_name, java_fd, ...) ({ \ return_type _rc = -1; \ do { \ int _fd = [java_fd getInt$]; \ id _monitor = \ LibcoreIoAsynchronousCloseMonitor_newAsynchronousSocketCloseMonitorWithInt_(_fd); \ _rc = syscall_name(_fd, __VA_ARGS__); \ _monitor = nil; \ if (_rc == -1) { \ throwIfClosed(fd); \ if (errno != EINTR) { \ LibcoreIoPosix_throwErrnoExceptionWithNSString_withInt_( \ [NSString stringWithFormat:@"%s", # syscall_name], errno); \ } \ } \ } while (_rc == -1); \ _rc; }) ]-*/ public final class NetworkOs { private NetworkOs() {} /*-[ JavaNetInetAddress *sockaddrToInetAddress(const struct sockaddr_storage *ss, int *port); static JavaNetInetSocketAddress *makeSocketAddress(const struct sockaddr_storage *ss) { int port; JavaNetInetAddress *inetAddress = sockaddrToInetAddress(ss, &port); if (!inetAddress) { return nil; } return create_JavaNetInetSocketAddress_initWithJavaNetInetAddress_withInt_(inetAddress, port); } static BOOL fillIfreq(NSString *interfaceName, struct ifreq *req) { if (!interfaceName) { return NO; } memset(req, 0, sizeof(struct ifreq)); strncpy(req->ifr_name, [interfaceName UTF8String], sizeof(req->ifr_name)); req->ifr_name[sizeof(req->ifr_name) - 1] = '\0'; return YES; } static BOOL fillInetSocketAddress(int rc, JavaNetInetSocketAddress *srcAddress, const struct sockaddr_storage *ss) { if (rc == -1 || !srcAddress) { return YES; } // Fill out the passed-in InetSocketAddress with the sender's IP address and port number. int port; JavaNetInetAddress *sender = sockaddrToInetAddress(ss, &port); if (!sender) { return NO; } LibcoreIoNetworkOs_updateInetSocketAddressWithJavaNetInetSocketAddress_withJavaNetInetAddress_withInt_( srcAddress, RETAIN_(sender), port); return YES; } static JavaNetSocketAddress *doGetSockName(int fd, BOOL is_sockname) { struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *) &ss; socklen_t byteCount = sizeof(ss); memset(&ss, 0, byteCount); int rc = is_sockname ? TEMP_FAILURE_RETRY(getsockname(fd, sa, &byteCount)) : TEMP_FAILURE_RETRY(getpeername(fd, sa, &byteCount)); if (rc == -1) { LibcoreIoPosix_throwErrnoExceptionWithNSString_withInt_( (is_sockname ? @"getsockname" : @"getpeername"), rc); } return makeSocketAddress(&ss); } JavaNetInetAddress *sockaddrToInetAddress(const struct sockaddr_storage *ss, int *port) { // Convert IPv4-mapped IPv6 addresses to IPv4 addresses. // The RI states "Java will never return an IPv4-mapped address". const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) ss; if (ss->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { // Copy the IPv6 address into the temporary sockaddr_storage. struct sockaddr_storage tmp; memset(&tmp, 0, sizeof(tmp)); memcpy(&tmp, ss, sizeof(struct sockaddr_in6)); // Unmap it into an IPv4 address. struct sockaddr_in *sin = (struct sockaddr_in *) &tmp; sin->sin_family = AF_INET; sin->sin_port = sin6->sin6_port; memcpy(&sin->sin_addr.s_addr, &sin6->sin6_addr.s6_addr[12], 4); // Do the regular conversion using the unmapped address. return sockaddrToInetAddress(&tmp, port); } const void *rawAddress; size_t addressLength; int sin_port = 0; int scope_id = 0; if (ss->ss_family == AF_INET) { const struct sockaddr_in *sin = (const struct sockaddr_in *) ss; rawAddress = &sin->sin_addr.s_addr; addressLength = 4; sin_port = ntohs(sin->sin_port); } else if (ss->ss_family == AF_INET6) { const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) ss; rawAddress = &sin6->sin6_addr.s6_addr; addressLength = 16; sin_port = ntohs(sin6->sin6_port); scope_id = sin6->sin6_scope_id; } else if (ss->ss_family == AF_UNIX) { const struct sockaddr_un *sun = (const struct sockaddr_un *) ss; rawAddress = &sun->sun_path; addressLength = strlen(sun->sun_path); } else { // We can't throw SocketException. We aren't meant to see bad addresses, so seeing one // really does imply an internal error. NSString *errMsg = [NSString stringWithFormat:@"sockaddrToInetAddress unsupported ss_family: %i", ss->ss_family]; @throw create_JavaLangIllegalArgumentException_initWithNSString_(errMsg); } if (port != NULL) { *port = sin_port; } IOSByteArray *byteArray = [IOSByteArray arrayWithBytes:(jbyte *)rawAddress count:(jint)addressLength]; if (ss->ss_family == AF_UNIX) { // Note that we get here for AF_UNIX sockets on accept(2). The unix(7) man page claims // that the peer's sun_path will contain the path, but in practice it doesn't, and the // peer length is returned as 2 (meaning only the sun_family field was set). return create_JavaNetInetUnixAddress_initWithByteArray_(byteArray); } return JavaNetInetAddress_getByAddressWithNSString_withByteArray_withInt_( nil, byteArray, scope_id); } static BOOL inetAddressToSockaddrImpl(JavaNetInetAddress *inetAddress, int port, struct sockaddr_storage *ss, socklen_t *sa_len, BOOL map) { memset(ss, 0, sizeof(struct sockaddr_storage)); *sa_len = 0; nil_chk(inetAddress); // Get the address family. ss->ss_family = [inetAddress getFamily]; if (ss->ss_family == AF_UNSPEC) { *sa_len = sizeof(ss->ss_family); return YES; // Job done! } // Check this is an address family we support. if (ss->ss_family != AF_INET && ss->ss_family != AF_INET6 && ss->ss_family != AF_UNIX) { NSString *errMsg = [NSString stringWithFormat:@"inetAddressToSockaddr bad family: %i", ss->ss_family]; @throw create_JavaLangIllegalArgumentException_initWithNSString_(errMsg); } // Handle the AF_UNIX special case. if (ss->ss_family == AF_UNIX) { struct sockaddr_un *sun = (struct sockaddr_un *)ss; jint path_length = inetAddress->ipaddress_->size_; if ((size_t)path_length >= sizeof(sun->sun_path)) { NSString *errMsg = [NSString stringWithFormat:@"inetAddressToSockaddr path too long for AF_UNIX: %d", path_length]; @throw create_JavaLangIllegalArgumentException_initWithNSString_(errMsg); } // Copy the bytes... jbyte* dst = (jbyte *)sun->sun_path; memset(dst, 0, sizeof(sun->sun_path)); [inetAddress->ipaddress_ getBytes:dst length:path_length]; *sa_len = sizeof(sun->sun_path); return YES; } // We use AF_INET6 sockets, so we want an IPv6 address (which may be a IPv4-mapped address). struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss; sin6->sin6_port = htons(port); if (ss->ss_family == AF_INET6) { // IPv6 address. Copy the bytes... jbyte *dst = (jbyte *)sin6->sin6_addr.s6_addr; [inetAddress->ipaddress_ getBytes:dst length:16]; // ...and set the scope id... sin6->sin6_scope_id = [(JavaNetInet6Address *) inetAddress getScopeId]; *sa_len = sizeof(struct sockaddr_in6); return true; } // Deal with Inet4Address instances. if (map) { // We should represent this Inet4Address as an IPv4-mapped IPv6 sockaddr_in6. // Change the family... sin6->sin6_family = AF_INET6; // Copy the bytes... jbyte *dst = (jbyte *)&sin6->sin6_addr.s6_addr[12]; [inetAddress->ipaddress_ getBytes:dst length:4]; // INADDR_ANY and in6addr_any are both all-zeros... if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { // ...but all other IPv4-mapped addresses are ::ffff:a.b.c.d, so insert the ffff... memset(&(sin6->sin6_addr.s6_addr[10]), 0xff, 2); } *sa_len = sizeof(struct sockaddr_in6); } else { // We should represent this Inet4Address as an IPv4 sockaddr_in. struct sockaddr_in *sin = (struct sockaddr_in *) ss; sin->sin_port = htons(port); jbyte *dst = (jbyte *)&sin->sin_addr.s_addr; [inetAddress->ipaddress_ getBytes:dst length:4]; *sa_len = sizeof(struct sockaddr_in); } return YES; } BOOL inetAddressToSockaddrVerbatim(JavaNetInetAddress *inetAddress, int port, struct sockaddr_storage *ss, socklen_t *sa_len) { return inetAddressToSockaddrImpl(inetAddress, port, ss, sa_len, NO); } BOOL inetAddressToSockaddr(JavaNetInetAddress *inetAddress, int port, struct sockaddr_storage *ss, socklen_t *sa_len) { return inetAddressToSockaddrImpl(inetAddress, port, ss, sa_len, YES); } ]-*/ public static native FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException /*-[ struct sockaddr_storage ss; socklen_t sl = sizeof(ss); memset(&ss, 0, sizeof(ss)); struct sockaddr *peer = peerAddress ? (struct sockaddr *) &ss : NULL; socklen_t *peerLength = peerAddress ? &sl : 0; int clientFd = NET_FAILURE_RETRY(int, accept, fd, peer, peerLength); if (clientFd == -1 || !fillInetSocketAddress([fd getInt$], peerAddress, &ss)) { close(clientFd); return nil; } if (clientFd == -1) { return nil; } JavaIoFileDescriptor *newFd = create_JavaIoFileDescriptor_init(); [newFd setInt$WithInt:clientFd]; return newFd; ]-*/; public static native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException /*-[ struct sockaddr_storage ss; socklen_t sa_len; if (!inetAddressToSockaddr(address, port, &ss, &sa_len)) { return; } const struct sockaddr* sa = (const struct sockaddr *) &ss; (void) NET_FAILURE_RETRY(int, bind, fd, sa, sa_len); ]-*/; public static native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException /*-[ struct sockaddr_storage ss; socklen_t sa_len; if (!inetAddressToSockaddr(address, port, &ss, &sa_len)) { return; } bool disconnect = false; if (ss.ss_family == AF_UNSPEC) { // Closing a datagram socket by connecting to AF_UNSPEC doesn't work, // docs say to use an invalid inet address instead. disconnect = true; ss.ss_family = AF_INET6; sa_len = sizeof(const struct sockaddr_in6); } const struct sockaddr* sa = (const struct sockaddr *) &ss; int rc = TEMP_FAILURE_RETRY(connect([fd getInt$], sa, sa_len)); if (rc == -1 && disconnect && errno == EADDRNOTAVAIL) { // It's a valid disconnect from invalid inet address above, so reset errno. errno = 0; } else { LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"connect", rc); } ]-*/; public static native String gai_strerror(int error) /*-[ return [NSString stringWithUTF8String:gai_strerror(error)]; ]-*/; public static native InetAddress[] getaddrinfo(String node, StructAddrinfo javaHints) throws GaiException /*-[ if (!node) { return nil; } struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = javaHints->ai_flags_; hints.ai_family = javaHints->ai_family_; hints.ai_socktype = javaHints->ai_socktype_; hints.ai_protocol = javaHints->ai_protocol_; struct addrinfo* addressList = NULL; errno = 0; int rc = getaddrinfo([node UTF8String], NULL, &hints, &addressList); if (rc != 0) { @throw create_LibcoreIoGaiException_initWithNSString_withInt_(@"getaddrinfo", rc); } // Count results so we know how to size the output array. int addressCount = 0; for (struct addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) { if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) { ++addressCount; } else { NSString *errMsg = [NSString stringWithFormat:@"getaddrinfo unexpected ai_family %i", ai->ai_family]; JavaLangSystem_logEWithNSString_(errMsg); } } if (addressCount == 0) { freeaddrinfo(addressList); return nil; } // Prepare output array. IOSObjectArray *result = [IOSObjectArray arrayWithLength:addressCount type:JavaNetInetAddress_class_()]; // Examine returned addresses one by one, save them in the output array. int index = 0; for (struct addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { // Unknown address family. Skip this address. NSString *errMsg = [NSString stringWithFormat:@"getaddrinfo unexpected ai_family %i", ai->ai_family]; JavaLangSystem_logEWithNSString_(errMsg); continue; } // Convert each IP address into a Java byte array. struct sockaddr_storage *address = (struct sockaddr_storage *) ai->ai_addr; JavaNetInetAddress *inetAddress = sockaddrToInetAddress(address, NULL); if (!inetAddress) { freeaddrinfo(addressList); return nil; } [result replaceObjectAtIndex:index withObject:inetAddress]; ++index; } freeaddrinfo(addressList); return result; ]-*/; public static native String getnameinfo(InetAddress address, int flags) throws GaiException /*-[ struct sockaddr_storage ss; socklen_t sa_len; if (!inetAddressToSockaddrVerbatim(address, 0, &ss, &sa_len)) { return nil; } char buf[NI_MAXHOST]; // NI_MAXHOST is longer than INET6_ADDRSTRLEN. errno = 0; int rc = getnameinfo((struct sockaddr *) &ss, sa_len, buf, sizeof(buf), NULL, 0, flags); if (rc != 0) { @throw create_LibcoreIoGaiException_initWithNSString_withInt_(@"getnameinfo", rc); } return [NSString stringWithUTF8String:buf]; ]-*/; public static native SocketAddress getsockname(FileDescriptor fd) throws ErrnoException /*-[ return doGetSockName([fd getInt$], YES); ]-*/; public static native int getsockoptByte(FileDescriptor fd, int level, int option) throws ErrnoException /*-[ u_char result = 0; socklen_t size = sizeof(result); int rc = TEMP_FAILURE_RETRY(getsockopt([fd getInt$], level, option, &result, &size)); if (rc == -1) { LibcoreIoPosix_throwErrnoExceptionWithNSString_withInt_(@"getsockopt", rc); } return result; ]-*/; public static native InetAddress getsockoptInAddr(FileDescriptor fd, int level, int option) throws ErrnoException /*-[ struct sockaddr_storage ss; memset(&ss, 0, sizeof(ss)); ss.ss_family = AF_INET; // This is only for the IPv4-only IP_MULTICAST_IF. struct sockaddr_in* sa = (struct sockaddr_in *) &ss; socklen_t size = sizeof(sa->sin_addr); int rc = TEMP_FAILURE_RETRY(getsockopt([fd getInt$], level, option, &sa->sin_addr, &size)); if (rc == -1) { LibcoreIoPosix_throwErrnoExceptionWithNSString_withInt_(@"getsockopt", rc); } return sockaddrToInetAddress(&ss, NULL); ]-*/; public static native int getsockoptInt(FileDescriptor fd, int level, int option) throws ErrnoException /*-[ int result = 0; socklen_t size = sizeof(result); int rc = TEMP_FAILURE_RETRY(getsockopt([fd getInt$], level, option, &result, &size)); if (rc == -1) { LibcoreIoPosix_throwErrnoExceptionWithNSString_withInt_(@"getsockopt", rc); } return result; ]-*/; public static native StructLinger getsockoptLinger(FileDescriptor fd, int level, int option) throws ErrnoException /*-[ struct linger l; socklen_t size = sizeof(l); memset(&l, 0, size); int rc = TEMP_FAILURE_RETRY(getsockopt([fd getInt$], level, option, &l, &size)); if (rc == -1) { LibcoreIoPosix_throwErrnoExceptionWithNSString_withInt_(@"getsockopt", rc); } return create_LibcoreIoStructLinger_initWithInt_withInt_(l.l_onoff, l.l_linger); ]-*/; public static native StructTimeval getsockoptTimeval(FileDescriptor fd, int level, int option) throws ErrnoException /*-[ struct timeval tv; socklen_t size = sizeof(tv); memset(&tv, 0, size); int rc = TEMP_FAILURE_RETRY(getsockopt([fd getInt$], level, option, &tv, &size)); if (rc == -1) { LibcoreIoPosix_throwErrnoExceptionWithNSString_withInt_(@"getsockopt", rc); } return create_LibcoreIoStructTimeval_initWithLong_withLong_(tv.tv_sec, tv.tv_usec); ]-*/; public static native InetAddress inet_pton(int family, String address) /*-[ if (!address) { return nil; } struct sockaddr_storage ss; memset(&ss, 0, sizeof(ss)); // sockaddr_in and sockaddr_in6 are at the same address, so we can use either here. void *dst = &((struct sockaddr_in *) &ss)->sin_addr; if (inet_pton(family, [address UTF8String], dst) != 1) { return nil; } ss.ss_family = family; return sockaddrToInetAddress(&ss, NULL); ]-*/; public static native InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException /*-[ struct ifreq req; if (!fillIfreq(interfaceName, &req)) { return nil; } int rc = TEMP_FAILURE_RETRY(ioctl([fd getInt$], cmd, &req)); if (rc == 0) { return sockaddrToInetAddress((struct sockaddr_storage *) &req.ifr_addr, NULL); } int originalError = errno; NSString *msg = [NSString stringWithFormat:@"ioctl (%d, %@)", cmd, interfaceName]; if (originalError != ENOTSUP && originalError != EOPNOTSUPP) { LibcoreIoPosix_throwErrnoExceptionWithNSString_withInt_(msg, originalError); } // Interface doesn't support SIOCGIFADDR, try looking up using ifaddrs struct ifaddrs *interfaces = NULL; void *sinAddress = NULL; if (getifaddrs(&interfaces) == 0) { const char *cname = [interfaceName UTF8String]; struct ifaddrs *addr = interfaces; while (addr) { if (addr->ifa_addr->sa_family == AF_INET && strcmp(addr->ifa_name, cname) == 0) { sinAddress = &((struct sockaddr_in *) addr->ifa_addr)->sin_addr.s_addr; } addr = addr->ifa_next; } } if (!sinAddress) { freeifaddrs(interfaces); LibcoreIoPosix_throwErrnoExceptionWithNSString_withInt_(msg, originalError); } IOSByteArray *byteArray = [IOSByteArray arrayWithBytes:(jbyte *)sinAddress count:4]; freeifaddrs(interfaces); return JavaNetInetAddress_getByAddressWithNSString_withByteArray_withInt_(nil, byteArray, 0); ]-*/; public static int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { if (buffer.isDirect()) { return recvfromBytes(fd, buffer, buffer.position(), buffer.remaining(), flags, srcAddress); } else { return recvfromBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining(), flags, srcAddress); } } public static int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { // This indirection isn't strictly necessary, but ensures that our public // interface is type safe. return recvfromBytes(fd, bytes, byteOffset, byteCount, flags, srcAddress); } private static native int recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException /*-[ char *bytes = BytesRW(buffer); if (!bytes) { return -1; } struct sockaddr_storage ss; socklen_t sl = sizeof(ss); memset(&ss, 0, sizeof(ss)); struct sockaddr* from = (srcAddress) ? (struct sockaddr *) &ss : NULL; socklen_t* fromLength = (srcAddress) ? &sl : 0; if (byteCount == 0) { // iOS doesn't read empty datagram packages, so read one byte and discard it. // That works because if the client is reading an empty packet, any bytes in // that packet are discarded anyway. int _fd = [fd getInt$]; if (_fd != -1) { int type = 0; socklen_t size = sizeof(type); int rc = LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_( @"getsockopt", TEMP_FAILURE_RETRY(getsockopt(_fd, SOL_SOCKET, SO_TYPE, &type, &size))); if (rc == -1) { return rc; } if (type == SOCK_DGRAM) { char b; jint recvCount = (jint)NET_FAILURE_RETRY(ssize_t, recvfrom, fd, &b, 1, flags, from, fromLength); fillInetSocketAddress(recvCount, srcAddress, &ss); return recvCount >= 0 ? 0 : recvCount; } } } jint recvCount = (jint)NET_FAILURE_RETRY(ssize_t, recvfrom, fd, bytes + byteOffset, byteCount, flags, from, fromLength); fillInetSocketAddress(recvCount, srcAddress, &ss); return recvCount; ]-*/; public static int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { if (buffer.isDirect()) { return sendtoBytes(fd, buffer, buffer.position(), buffer.remaining(), flags, inetAddress, port); } else { return sendtoBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining(), flags, inetAddress, port); } } public static int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { // This indirection isn't strictly necessary, but ensures that our public // interface is type safe. return sendtoBytes(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); } private static native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException /*-[ const char *bytes = BytesRO(buffer); if (!bytes) { return -1; } struct sockaddr_storage ss; socklen_t sa_len = 0; if (inetAddress && !inetAddressToSockaddr(inetAddress, port, &ss, &sa_len)) { return -1; } const struct sockaddr *to = inetAddress ? (const struct sockaddr *) &ss : NULL; return (int) NET_FAILURE_RETRY( ssize_t, sendto, fd, bytes + byteOffset, byteCount, flags, to, sa_len); ]-*/; public static native void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException /*-[ u_char byte = value; int rc = TEMP_FAILURE_RETRY(setsockopt([fd getInt$], level, option, &byte, sizeof(byte))); LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"setsockopt", rc); ]-*/; public static native void setsockoptGroupReq(FileDescriptor fd, int level, int option, StructGroupReq structGroupReq) throws ErrnoException /*-[ struct group_req req; memset(&req, 0, sizeof(req)); req.gr_interface = structGroupReq->gr_interface_; // Get the IPv4 or IPv6 multicast address to join or leave. JavaNetInetAddress *group = structGroupReq->gr_group_; socklen_t sa_len; if (!inetAddressToSockaddrVerbatim(group, 0, &req.gr_group, &sa_len)) { return; } int rc = TEMP_FAILURE_RETRY(setsockopt([fd getInt$], level, option, &req, sizeof(req))); if (rc == -1 && errno == EINVAL) { // Maybe we're a 32-bit binary talking to a 64-bit kernel? // glibc doesn't automatically handle this. struct group_req64 { uint32_t gr_interface; uint32_t my_padding; struct sockaddr_storage gr_group; }; struct group_req64 req64; req64.gr_interface = req.gr_interface; memcpy(&req64.gr_group, &req.gr_group, sizeof(req.gr_group)); rc = TEMP_FAILURE_RETRY(setsockopt([fd getInt$], level, option, &req64, sizeof(req64))); } LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"setsockopt", rc); ]-*/; public static native void setsockoptGroupSourceReq(FileDescriptor fd, int level, int option, StructGroupSourceReq structGroupSourceReq) throws ErrnoException /*-[ socklen_t sa_len; struct group_source_req req; memset(&req, 0, sizeof(req)); req.gsr_interface = structGroupSourceReq->gsr_interface_; // Get the IPv4 or IPv6 multicast address to join or leave. JavaNetInetAddress *group = structGroupSourceReq->gsr_group_; if (!inetAddressToSockaddrVerbatim(group, 0, &req.gsr_group, &sa_len)) { return; } // Get the IPv4 or IPv6 multicast address to add to the filter. JavaNetInetAddress *source = structGroupSourceReq->gsr_source_; if (!inetAddressToSockaddrVerbatim(source, 0, &req.gsr_source, &sa_len)) { return; } int rc = TEMP_FAILURE_RETRY(setsockopt([fd getInt$], level, option, &req, sizeof(req))); if (rc == -1 && errno == EINVAL) { // Maybe we're a 32-bit binary talking to a 64-bit kernel? // glibc doesn't automatically handle this. // http://sourceware.org/bugzilla/show_bug.cgi?id=12080 struct group_source_req64 { uint32_t gsr_interface; uint32_t my_padding; struct sockaddr_storage gsr_group; struct sockaddr_storage gsr_source; }; struct group_source_req64 req64; req64.gsr_interface = req.gsr_interface; memcpy(&req64.gsr_group, &req.gsr_group, sizeof(req.gsr_group)); memcpy(&req64.gsr_source, &req.gsr_source, sizeof(req.gsr_source)); rc = TEMP_FAILURE_RETRY(setsockopt([fd getInt$], level, option, &req64, sizeof(req64))); } LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"setsockopt", rc); ]-*/; public static native void setsockoptIfreq(FileDescriptor fd, int level, int option, String interfaceName) throws ErrnoException /*-[ struct ifreq req; if (!fillIfreq(interfaceName, &req)) { return; } int rc = TEMP_FAILURE_RETRY(setsockopt([fd getInt$], level, option, &req, sizeof(req))); LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"setsockopt", rc); ]-*/; public static native void setsockoptInt(FileDescriptor fd, int level, int option, int value) throws ErrnoException /*-[ if (level == IPPROTO_IP && option == IP_TOS) { return; // Already set on iOS, and setting it fails. } int _fd = [fd getInt$]; if (level == SOL_SOCKET && option == SO_REUSEADDR) { int type = 0; socklen_t size = sizeof(type); LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"getsockopt", TEMP_FAILURE_RETRY(getsockopt(_fd, SOL_SOCKET, SO_TYPE, &type, &size))); if (type == SOCK_DGRAM) { LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"setsockopt", TEMP_FAILURE_RETRY(setsockopt(_fd, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value)))); } } int rc = TEMP_FAILURE_RETRY(setsockopt(_fd, level, option, &value, sizeof(value))); LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"setsockopt", rc); ]-*/; public static native void setsockoptIpMreqn(FileDescriptor fd, int level, int option, int value) throws ErrnoException /*-[ struct ip_mreqn req; memset(&req, 0, sizeof(req)); req.imr_ifindex = value; int rc = TEMP_FAILURE_RETRY(setsockopt([fd getInt$], level, option, &req, sizeof(req))); LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"setsockopt", rc); ]-*/; public static native void setsockoptLinger(FileDescriptor fd, int level, int option, StructLinger structLinger) throws ErrnoException /*-[ struct linger value; value.l_onoff = structLinger->l_onoff_; value.l_linger = structLinger->l_linger_; int rc = TEMP_FAILURE_RETRY(setsockopt([fd getInt$], level, option, &value, sizeof(value))); LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"setsockopt", rc); ]-*/; public static native void setsockoptTimeval(FileDescriptor fd, int level, int option, StructTimeval structTimeval) throws ErrnoException /*-[ struct timeval value; value.tv_sec = (long) structTimeval->tv_sec_; value.tv_usec = (int) structTimeval->tv_usec_; int rc = TEMP_FAILURE_RETRY(setsockopt([fd getInt$], level, option, &value, sizeof(value))); LibcoreIoPosix_throwIfMinusOneWithNSString_withInt_(@"setsockopt", rc); ]-*/; private static void updateInetSocketAddress(InetSocketAddress socketAddr, InetAddress addr, int port) { // Fill in socket values using reflection, rather than change an immutable API. try { Field addrField = InetSocketAddress.class.getDeclaredField("addr"); addrField.setAccessible(true); addrField.set(socketAddr, addr); Field portField = InetSocketAddress.class.getDeclaredField("port"); portField.setAccessible(true); portField.set(socketAddr, port); } catch (Exception e) { throw new AssertionError(e); } } // Create a compile-time link to NetFactoryImpl to pull it into binaries that already link other // java.net classes. Most of java.net depends on NetworkOs so this declaration should be // sufficient to ensure that NetFactoryImpl is loaded. private static final Class<?> unused = NetFactoryImpl.class; }