diff options
23 files changed, 389 insertions, 299 deletions
diff --git a/dalvik/src/main/java/dalvik/system/BlockGuard.java b/dalvik/src/main/java/dalvik/system/BlockGuard.java index 56abeb8..d3c5088 100644 --- a/dalvik/src/main/java/dalvik/system/BlockGuard.java +++ b/dalvik/src/main/java/dalvik/system/BlockGuard.java @@ -24,7 +24,10 @@ import java.net.InetAddress; import java.net.SocketException; import java.net.SocketImpl; import java.net.SocketOptions; +import libcore.io.Libcore; +import libcore.io.StructLinger; import org.apache.harmony.luni.platform.INetworkSystem; +import static libcore.io.OsConstants.*; /** * Mechanism to let threads set restrictions on what code is allowed @@ -254,10 +257,6 @@ public final class BlockGuard { mNetwork.connect(aFD, inetAddress, port, timeout); } - public InetAddress getSocketLocalAddress(FileDescriptor aFD) { - return mNetwork.getSocketLocalAddress(aFD); - } - public boolean select(FileDescriptor[] readFDs, FileDescriptor[] writeFDs, int numReadable, int numWritable, long timeout, int[] flags) throws SocketException { @@ -265,15 +264,6 @@ public final class BlockGuard { return mNetwork.select(readFDs, writeFDs, numReadable, numWritable, timeout, flags); } - public int getSocketLocalPort(FileDescriptor aFD) { - return mNetwork.getSocketLocalPort(aFD); - } - - public Object getSocketOption(FileDescriptor aFD, int opt) - throws SocketException { - return mNetwork.getSocketOption(aFD, opt); - } - public void setSocketOption(FileDescriptor aFD, int opt, Object optVal) throws SocketException { mNetwork.setSocketOption(aFD, opt, optVal); @@ -291,13 +281,8 @@ public final class BlockGuard { private boolean isLingerSocket(FileDescriptor fd) throws SocketException { try { - Object lingerValue = mNetwork.getSocketOption(fd, SocketOptions.SO_LINGER); - if (lingerValue instanceof Boolean) { - return (Boolean) lingerValue; - } else if (lingerValue instanceof Integer) { - return ((Integer) lingerValue) != 0; - } - throw new AssertionError(lingerValue.getClass().getName()); + StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER); + return linger.isOn() && linger.l_linger > 0; } catch (Exception ignored) { // We're called via Socket.close (which doesn't ask for us to be called), so we // must not throw here, because Socket.close must not throw if asked to close an diff --git a/luni/src/main/java/java/net/DatagramSocketImpl.java b/luni/src/main/java/java/net/DatagramSocketImpl.java index e92cb72..4485b18 100644 --- a/luni/src/main/java/java/net/DatagramSocketImpl.java +++ b/luni/src/main/java/java/net/DatagramSocketImpl.java @@ -19,7 +19,7 @@ package java.net; import java.io.FileDescriptor; import java.io.IOException; -import org.apache.harmony.luni.platform.Platform; +import libcore.io.IoUtils; /** * The abstract superclass for datagram and multicast socket implementations. @@ -82,18 +82,14 @@ public abstract class DatagramSocketImpl implements SocketOptions { } /** - * Gets the local address to which the socket is bound. - * - * @return the local address to which the socket is bound. + * Returns the local address to which the socket is bound. */ InetAddress getLocalAddress() { - return Platform.NETWORK.getSocketLocalAddress(fd); + return IoUtils.getSocketLocalAddress(fd); } /** - * Gets the local port of this socket. - * - * @return the local port to which this socket is bound. + * Returns the local port to which this socket is bound. */ protected int getLocalPort() { return localPort; diff --git a/luni/src/main/java/java/net/PlainDatagramSocketImpl.java b/luni/src/main/java/java/net/PlainDatagramSocketImpl.java index e023cae..e3ef565 100644 --- a/luni/src/main/java/java/net/PlainDatagramSocketImpl.java +++ b/luni/src/main/java/java/net/PlainDatagramSocketImpl.java @@ -38,13 +38,6 @@ import org.apache.harmony.luni.platform.Platform; */ public class PlainDatagramSocketImpl extends DatagramSocketImpl { - private static final int MCAST_JOIN_GROUP = 19; - private static final int MCAST_LEAVE_GROUP = 20; - - private static final int SO_BROADCAST = 32; - - private static final int IP_MULTICAST_TTL = 17; - private volatile boolean isNativeConnected; private final CloseGuard guard = CloseGuard.get(); @@ -75,11 +68,11 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl { if (port != 0) { localPort = port; } else { - localPort = Platform.NETWORK.getSocketLocalPort(fd); + localPort = IoUtils.getSocketLocalPort(fd); } try { - setOption(SO_BROADCAST, Boolean.TRUE); + setOption(SocketOptions.SO_BROADCAST, Boolean.TRUE); } catch (IOException ignored) { } } @@ -109,13 +102,13 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl { } } - public Object getOption(int optID) throws SocketException { - return Platform.NETWORK.getSocketOption(fd, optID); + @Override public Object getOption(int option) throws SocketException { + return IoUtils.getSocketOption(fd, option); } @Override public int getTimeToLive() throws IOException { - return (Integer) getOption(IP_MULTICAST_TTL); + return (Integer) getOption(IoUtils.IP_MULTICAST_TTL); } @Override @@ -125,27 +118,27 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl { @Override public void join(InetAddress addr) throws IOException { - setOption(MCAST_JOIN_GROUP, new MulticastGroupRequest(addr, null)); + setOption(IoUtils.MCAST_JOIN_GROUP, new MulticastGroupRequest(addr, null)); } @Override public void joinGroup(SocketAddress addr, NetworkInterface netInterface) throws IOException { if (addr instanceof InetSocketAddress) { InetAddress groupAddr = ((InetSocketAddress) addr).getAddress(); - setOption(MCAST_JOIN_GROUP, new MulticastGroupRequest(groupAddr, netInterface)); + setOption(IoUtils.MCAST_JOIN_GROUP, new MulticastGroupRequest(groupAddr, netInterface)); } } @Override public void leave(InetAddress addr) throws IOException { - setOption(MCAST_LEAVE_GROUP, new MulticastGroupRequest(addr, null)); + setOption(IoUtils.MCAST_LEAVE_GROUP, new MulticastGroupRequest(addr, null)); } @Override public void leaveGroup(SocketAddress addr, NetworkInterface netInterface) throws IOException { if (addr instanceof InetSocketAddress) { InetAddress groupAddr = ((InetSocketAddress) addr).getAddress(); - setOption(MCAST_LEAVE_GROUP, new MulticastGroupRequest(groupAddr, netInterface)); + setOption(IoUtils.MCAST_LEAVE_GROUP, new MulticastGroupRequest(groupAddr, netInterface)); } } @@ -192,7 +185,7 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl { @Override public void setTimeToLive(int ttl) throws IOException { - setOption(IP_MULTICAST_TTL, Integer.valueOf(ttl)); + setOption(IoUtils.IP_MULTICAST_TTL, Integer.valueOf(ttl)); } @Override diff --git a/luni/src/main/java/java/net/PlainSocketImpl.java b/luni/src/main/java/java/net/PlainSocketImpl.java index 7e608a9..937193e 100644 --- a/luni/src/main/java/java/net/PlainSocketImpl.java +++ b/luni/src/main/java/java/net/PlainSocketImpl.java @@ -133,7 +133,7 @@ public class PlainSocketImpl extends SocketImpl { if (port != 0) { this.localport = port; } else { - this.localport = Platform.NETWORK.getSocketLocalPort(fd); + this.localport = IoUtils.getSocketLocalPort(fd); } } @@ -226,9 +226,8 @@ public class PlainSocketImpl extends SocketImpl { } } - @Override - public Object getOption(int optID) throws SocketException { - return Platform.NETWORK.getSocketOption(fd, optID); + @Override public Object getOption(int option) throws SocketException { + return IoUtils.getSocketOption(fd, option); } @Override protected synchronized OutputStream getOutputStream() throws IOException { diff --git a/luni/src/main/java/java/net/Socket.java b/luni/src/main/java/java/net/Socket.java index 3caf6ac..337f414 100644 --- a/luni/src/main/java/java/net/Socket.java +++ b/luni/src/main/java/java/net/Socket.java @@ -21,7 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.channels.SocketChannel; -import org.apache.harmony.luni.platform.Platform; +import libcore.io.IoUtils; /** * Provides a client-side TCP socket. @@ -948,7 +948,7 @@ public class Socket { } private void cacheLocalAddress() { - this.localAddress = Platform.NETWORK.getSocketLocalAddress(impl.fd); + this.localAddress = IoUtils.getSocketLocalAddress(impl.fd); } /** diff --git a/luni/src/main/java/java/nio/DatagramChannelImpl.java b/luni/src/main/java/java/nio/DatagramChannelImpl.java index 7333549..9887394 100644 --- a/luni/src/main/java/java/nio/DatagramChannelImpl.java +++ b/luni/src/main/java/java/nio/DatagramChannelImpl.java @@ -96,14 +96,10 @@ class DatagramChannelImpl extends DatagramChannel implements FileDescriptorChann } /** - * Returns the local address from the IP stack. This method should not be - * called directly as it does not check the security policy. - * - * @return InetAddress the local address to which the socket is bound. - * @see DatagramSocket + * Returns the local address to which the socket is bound. */ InetAddress getLocalAddress() { - return Platform.NETWORK.getSocketLocalAddress(fd); + return IoUtils.getSocketLocalAddress(fd); } /** diff --git a/luni/src/main/java/java/nio/SocketChannelImpl.java b/luni/src/main/java/java/nio/SocketChannelImpl.java index 7d92502..35f5490 100644 --- a/luni/src/main/java/java/nio/SocketChannelImpl.java +++ b/luni/src/main/java/java/nio/SocketChannelImpl.java @@ -220,8 +220,10 @@ class SocketChannelImpl extends SocketChannel implements FileDescriptorChannel { } private void initLocalAddressAndPort() { - localAddress = Platform.NETWORK.getSocketLocalAddress(fd); - localPort = Platform.NETWORK.getSocketLocalPort(fd); + SocketAddress sa = Libcore.os.getsockname(fd); + InetSocketAddress isa = (InetSocketAddress) sa; + localAddress = isa.getAddress(); + localPort = isa.getPort(); if (socket != null) { socket.socketImpl().initLocalPort(localPort); } diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java index 1f263a1..352a41e 100644 --- a/luni/src/main/java/libcore/io/ForwardingOs.java +++ b/luni/src/main/java/libcore/io/ForwardingOs.java @@ -17,6 +17,8 @@ package libcore.io; import java.io.FileDescriptor; +import java.net.InetAddress; +import java.net.SocketAddress; import java.nio.ByteBuffer; import libcore.util.MutableInt; import libcore.util.MutableLong; @@ -44,6 +46,12 @@ public class ForwardingOs implements Os { public void fsync(FileDescriptor fd) throws ErrnoException { os.fsync(fd); } public void ftruncate(FileDescriptor fd, long length) throws ErrnoException { os.ftruncate(fd, length); } public String getenv(String name) { return os.getenv(name); } + public SocketAddress getsockname(FileDescriptor fd) throws ErrnoException { return os.getsockname(fd); } + public int getsockoptByte(FileDescriptor fd, int level, int option) throws ErrnoException { return os.getsockoptByte(fd, level, option); } + public InetAddress getsockoptInAddr(FileDescriptor fd, int level, int option) throws ErrnoException { return os.getsockoptInAddr(fd, level, option); } + public int getsockoptInt(FileDescriptor fd, int level, int option) throws ErrnoException { return os.getsockoptInt(fd, level, option); } + public StructLinger getsockoptLinger(FileDescriptor fd, int level, int option) throws ErrnoException { return os.getsockoptLinger(fd, level, option); } + public StructTimeval getsockoptTimeval(FileDescriptor fd, int level, int option) throws ErrnoException { return os.getsockoptTimeval(fd, level, option); } public int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException { return os.ioctlInt(fd, cmd, arg); } public boolean isatty(FileDescriptor fd) { return os.isatty(fd); } public void listen(FileDescriptor fd, int backlog) throws ErrnoException { os.listen(fd, backlog); } diff --git a/luni/src/main/java/libcore/io/IoUtils.java b/luni/src/main/java/libcore/io/IoUtils.java index 4effb4b..0a4de9f 100644 --- a/luni/src/main/java/libcore/io/IoUtils.java +++ b/luni/src/main/java/libcore/io/IoUtils.java @@ -21,8 +21,13 @@ import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; +import java.net.InetAddress; +import java.net.Inet4Address; +import java.net.InetSocketAddress; import java.net.Socket; +import java.net.SocketAddress; import java.net.SocketException; +import java.net.SocketOptions; import java.util.Arrays; import libcore.io.ErrnoException; import libcore.io.Libcore; @@ -225,6 +230,109 @@ public final class IoUtils { } /** + * java.net has its own socket options similar to the underlying Unix ones. We paper over the + * differences here. + */ + public static Object getSocketOption(FileDescriptor fd, int option) throws SocketException { + try { + return getSocketOptionErrno(fd, option); + } catch (ErrnoException errnoException) { + throw errnoException.rethrowAsSocketException(); + } + } + + // Socket options used by java.net but not exposed in SocketOptions. + public static final int MCAST_JOIN_GROUP = 19; + public static final int MCAST_LEAVE_GROUP = 20; + public static final int IP_MULTICAST_TTL = 17; + + private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws SocketException { + switch (option) { + case SocketOptions.IP_MULTICAST_IF2: + if (boundIPv4(fd)) { + // The caller's asking for an interface index, but that's not how IPv4 works. + // Our Java should never get here, because we'll try IP_MULTICAST_IF first and + // that will satisfy us. + throw new SocketException("no interface index for IPv4"); + } else { + return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF); + } + case SocketOptions.IP_MULTICAST_IF: + return Libcore.os.getsockoptInAddr(fd, IPPROTO_IP, IP_MULTICAST_IF); + case SocketOptions.IP_MULTICAST_LOOP: + if (boundIPv4(fd)) { + // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int, + // IPv4 multicast TTL uses a byte. + return booleanFromInt(Libcore.os.getsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP)); + } else { + return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP)); + } + case IoUtils.IP_MULTICAST_TTL: + if (boundIPv4(fd)) { + // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte. + return Libcore.os.getsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_TTL); + } else { + return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); + } + case SocketOptions.IP_TOS: + if (boundIPv4(fd)) { + return Libcore.os.getsockoptInt(fd, IPPROTO_IP, IP_TOS); + } else { + return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS); + } + case SocketOptions.SO_BROADCAST: + return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_BROADCAST)); + case SocketOptions.SO_KEEPALIVE: + return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE)); + case SocketOptions.SO_LINGER: + StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER); + if (!linger.isOn()) { + return false; + } + return linger.l_linger; + case SocketOptions.SO_OOBINLINE: + return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE)); + case SocketOptions.SO_RCVBUF: + return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF); + case SocketOptions.SO_REUSEADDR: + return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR)); + case SocketOptions.SO_SNDBUF: + return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF); + case SocketOptions.SO_TIMEOUT: + return (int) Libcore.os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO).toMillis(); + case SocketOptions.TCP_NODELAY: + return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY)); + default: + throw new SocketException("unknown socket option " + option); + } + } + + private static boolean boundIPv4(FileDescriptor fd) { + SocketAddress sa = Libcore.os.getsockname(fd); + if (!(sa instanceof InetSocketAddress)) { + return false; + } + InetSocketAddress isa = (InetSocketAddress) sa; + return (isa.getAddress() instanceof Inet4Address); + } + + private static boolean booleanFromInt(int i) { + return (i != 0); + } + + public static InetAddress getSocketLocalAddress(FileDescriptor fd) { + SocketAddress sa = Libcore.os.getsockname(fd); + InetSocketAddress isa = (InetSocketAddress) sa; + return isa.getAddress(); + } + + public static int getSocketLocalPort(FileDescriptor fd) { + SocketAddress sa = Libcore.os.getsockname(fd); + InetSocketAddress isa = (InetSocketAddress) sa; + return isa.getPort(); + } + + /** * Returns the contents of 'path' as a byte array. */ public static byte[] readFileAsByteArray(String path) throws IOException { diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java index 0052e7a..0f10584 100644 --- a/luni/src/main/java/libcore/io/Os.java +++ b/luni/src/main/java/libcore/io/Os.java @@ -17,6 +17,8 @@ package libcore.io; import java.io.FileDescriptor; +import java.net.InetAddress; +import java.net.SocketAddress; import java.nio.ByteBuffer; import libcore.util.MutableInt; import libcore.util.MutableLong; @@ -35,6 +37,12 @@ public interface Os { public void fsync(FileDescriptor fd) throws ErrnoException; public void ftruncate(FileDescriptor fd, long length) throws ErrnoException; public String getenv(String name); + public SocketAddress getsockname(FileDescriptor fd) throws ErrnoException; + public int getsockoptByte(FileDescriptor fd, int level, int option) throws ErrnoException; + public InetAddress getsockoptInAddr(FileDescriptor fd, int level, int option) throws ErrnoException; + public int getsockoptInt(FileDescriptor fd, int level, int option) throws ErrnoException; + public StructLinger getsockoptLinger(FileDescriptor fd, int level, int option) throws ErrnoException; + public StructTimeval getsockoptTimeval(FileDescriptor fd, int level, int option) throws ErrnoException; public int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException; public boolean isatty(FileDescriptor fd); public void listen(FileDescriptor fd, int backlog) throws ErrnoException; diff --git a/luni/src/main/java/libcore/io/OsConstants.java b/luni/src/main/java/libcore/io/OsConstants.java index 69cb5a4..616e60a 100644 --- a/luni/src/main/java/libcore/io/OsConstants.java +++ b/luni/src/main/java/libcore/io/OsConstants.java @@ -155,6 +155,7 @@ public final class OsConstants { public static final int IPV6_RECVPKTINFO = placeholder(); public static final int IPV6_RECVRTHDR = placeholder(); public static final int IPV6_RECVTCLASS = placeholder(); + public static final int IPV6_TCLASS = placeholder(); public static final int IPV6_UNICAST_HOPS = placeholder(); public static final int IPV6_V6ONLY = placeholder(); public static final int IP_MULTICAST_IF = placeholder(); @@ -205,6 +206,7 @@ public final class OsConstants { public static final int SOCK_RAW = placeholder(); public static final int SOCK_SEQPACKET = placeholder(); public static final int SOCK_STREAM = placeholder(); + public static final int SOL_SOCKET = placeholder(); public static final int SO_BROADCAST = placeholder(); public static final int SO_DEBUG = placeholder(); public static final int SO_DONTROUTE = placeholder(); @@ -246,6 +248,7 @@ public final class OsConstants { public static final int S_IXGRP = placeholder(); public static final int S_IXOTH = placeholder(); public static final int S_IXUSR = placeholder(); + public static final int TCP_NODELAY = placeholder(); public static final int WCONTINUED = placeholder(); public static final int WEXITED = placeholder(); public static final int WNOHANG = placeholder(); diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java index 77d32f0..6c49e51 100644 --- a/luni/src/main/java/libcore/io/Posix.java +++ b/luni/src/main/java/libcore/io/Posix.java @@ -17,6 +17,8 @@ package libcore.io; import java.io.FileDescriptor; +import java.net.InetAddress; +import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.NioUtils; import libcore.util.MutableInt; @@ -38,6 +40,12 @@ public final class Posix implements Os { public native void fsync(FileDescriptor fd) throws ErrnoException; public native void ftruncate(FileDescriptor fd, long length) throws ErrnoException; public native String getenv(String name); + public native SocketAddress getsockname(FileDescriptor fd) throws ErrnoException; + public native int getsockoptByte(FileDescriptor fd, int level, int option) throws ErrnoException; + public native InetAddress getsockoptInAddr(FileDescriptor fd, int level, int option) throws ErrnoException; + public native int getsockoptInt(FileDescriptor fd, int level, int option) throws ErrnoException; + public native StructLinger getsockoptLinger(FileDescriptor fd, int level, int option) throws ErrnoException; + public native StructTimeval getsockoptTimeval(FileDescriptor fd, int level, int option) throws ErrnoException; public native int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException; public native boolean isatty(FileDescriptor fd); public native void listen(FileDescriptor fd, int backlog) throws ErrnoException; diff --git a/luni/src/main/java/libcore/io/StructLinger.java b/luni/src/main/java/libcore/io/StructLinger.java new file mode 100644 index 0000000..9f149af --- /dev/null +++ b/luni/src/main/java/libcore/io/StructLinger.java @@ -0,0 +1,42 @@ +/* + * 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; + +/** + * Corresponds to C's {@code struct linger} from + * <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html"><sys/socket.h></a> + */ +public final class StructLinger { + /** Whether or not linger is enabled. Non-zero is on. */ + public final int l_onoff; + + /** Linger time in seconds. */ + public final int l_linger; + + public StructLinger(int l_onoff, int l_linger) { + this.l_onoff = l_onoff; + this.l_linger = l_linger; + } + + public boolean isOn() { + return l_onoff != 0; + } + + @Override public String toString() { + return "StructLinger[l_onoff=" + l_onoff + ",l_linger=" + l_linger + "]"; + } +} diff --git a/luni/src/main/java/libcore/io/StructTimeval.java b/luni/src/main/java/libcore/io/StructTimeval.java new file mode 100644 index 0000000..0ed3509 --- /dev/null +++ b/luni/src/main/java/libcore/io/StructTimeval.java @@ -0,0 +1,48 @@ +/* + * 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; + +/** + * Corresponds to C's {@code struct timeval} from + * <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_time.h.html"><sys/time.h></a> + */ +public final class StructTimeval { + /** Seconds. */ + public final long tv_sec; + + /** Microseconds. */ + public final long tv_usec; + + private StructTimeval(long tv_sec, long tv_usec) { + this.tv_sec = tv_sec; + this.tv_usec = tv_usec; + } + + public static StructTimeval fromMillis(long millis) { + long tv_sec = millis / 1000; + long tv_usec = (millis - (tv_sec * 1000)) * 1000; + return new StructTimeval(tv_sec, tv_usec); + } + + public long toMillis() { + return (tv_sec * 1000) + (tv_usec / 1000); + } + + @Override public String toString() { + return "StructTimeval[tv_sec=" + tv_sec + ",tv_usec=" + tv_usec + "]"; + } +} diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java index 18c01dd..e5a511e 100644 --- a/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java +++ b/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java @@ -62,8 +62,6 @@ public interface INetworkSystem { public void connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeout) throws SocketException; - public InetAddress getSocketLocalAddress(FileDescriptor fd); - /** * Select the given file descriptors for read and write operations. * @@ -99,25 +97,6 @@ public interface INetworkSystem { throws SocketException; /* - * Query the IP stack for the local port to which this socket is bound. - * - * @param fd the socket descriptor - * @return int the local port to which the socket is bound - */ - public int getSocketLocalPort(FileDescriptor fd); - - /* - * Query the IP stack for the nominated socket option. - * - * @param fd the socket descriptor @param opt the socket option type - * @return the nominated socket option value - * - * @throws SocketException if the option is invalid - */ - public Object getSocketOption(FileDescriptor fd, int opt) - throws SocketException; - - /* * Set the nominated socket option in the IP stack. * * @param fd the socket descriptor @param opt the option selector @param diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java index 930846a..3fc4ab4 100644 --- a/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java +++ b/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java @@ -52,12 +52,6 @@ final class OSNetworkSystem implements INetworkSystem { public native void disconnectDatagram(FileDescriptor fd) throws SocketException; - public native InetAddress getSocketLocalAddress(FileDescriptor fd); - - public native int getSocketLocalPort(FileDescriptor fd); - - public native Object getSocketOption(FileDescriptor fd, int opt) throws SocketException; - public native int read(FileDescriptor fd, byte[] data, int offset, int count) throws IOException; diff --git a/luni/src/main/native/JniConstants.cpp b/luni/src/main/native/JniConstants.cpp index 004eb4c..646bd3f 100644 --- a/luni/src/main/native/JniConstants.cpp +++ b/luni/src/main/native/JniConstants.cpp @@ -33,6 +33,7 @@ jclass JniConstants::fieldClass; jclass JniConstants::fieldPositionIteratorClass; jclass JniConstants::fileDescriptorClass; jclass JniConstants::inetAddressClass; +jclass JniConstants::inetSocketAddressClass; jclass JniConstants::inflaterClass; jclass JniConstants::integerClass; jclass JniConstants::interfaceAddressClass; @@ -50,8 +51,10 @@ jclass JniConstants::socketImplClass; jclass JniConstants::stringArrayClass; jclass JniConstants::stringClass; jclass JniConstants::structFlockClass; +jclass JniConstants::structLingerClass; jclass JniConstants::structStatClass; jclass JniConstants::structStatFsClass; +jclass JniConstants::structTimevalClass; jclass JniConstants::structUtsnameClass; static jclass findClass(JNIEnv* env, const char* name) { @@ -79,6 +82,7 @@ void JniConstants::init(JNIEnv* env) { fieldPositionIteratorClass = findClass(env, "libcore/icu/NativeDecimalFormat$FieldPositionIterator"); fileDescriptorClass = findClass(env, "java/io/FileDescriptor"); inetAddressClass = findClass(env, "java/net/InetAddress"); + inetSocketAddressClass = findClass(env, "java/net/InetSocketAddress"); inflaterClass = findClass(env, "java/util/zip/Inflater"); integerClass = findClass(env, "java/lang/Integer"); interfaceAddressClass = findClass(env, "java/net/InterfaceAddress"); @@ -96,7 +100,9 @@ void JniConstants::init(JNIEnv* env) { stringArrayClass = findClass(env, "[Ljava/lang/String;"); stringClass = findClass(env, "java/lang/String"); structFlockClass = findClass(env, "libcore/io/StructFlock"); + structLingerClass = findClass(env, "libcore/io/StructLinger"); structStatClass = findClass(env, "libcore/io/StructStat"); structStatFsClass = findClass(env, "libcore/io/StructStatFs"); + structTimevalClass = findClass(env, "libcore/io/StructTimeval"); structUtsnameClass = findClass(env, "libcore/io/StructUtsname"); } diff --git a/luni/src/main/native/JniConstants.h b/luni/src/main/native/JniConstants.h index aa78907..2cc41a7 100644 --- a/luni/src/main/native/JniConstants.h +++ b/luni/src/main/native/JniConstants.h @@ -55,6 +55,7 @@ struct JniConstants { static jclass fieldPositionIteratorClass; static jclass fileDescriptorClass; static jclass inetAddressClass; + static jclass inetSocketAddressClass; static jclass inflaterClass; static jclass integerClass; static jclass interfaceAddressClass; @@ -72,8 +73,10 @@ struct JniConstants { static jclass stringArrayClass; static jclass stringClass; static jclass structFlockClass; + static jclass structLingerClass; static jclass structStatClass; static jclass structStatFsClass; + static jclass structTimevalClass; static jclass structUtsnameClass; }; diff --git a/luni/src/main/native/NetworkUtilities.cpp b/luni/src/main/native/NetworkUtilities.cpp index 23c1edf..7628478 100644 --- a/luni/src/main/native/NetworkUtilities.cpp +++ b/luni/src/main/native/NetworkUtilities.cpp @@ -60,15 +60,15 @@ bool byteArrayToSocketAddress(JNIEnv* env, jclass, jbyteArray byteArray, int por return true; } -jbyteArray socketAddressToByteArray(JNIEnv* env, sockaddr_storage* ss) { - void* rawAddress; +jbyteArray socketAddressToByteArray(JNIEnv* env, const sockaddr_storage* ss) { + const void* rawAddress; size_t addressLength; if (ss->ss_family == AF_INET) { - sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ss); + const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(ss); rawAddress = &sin->sin_addr.s_addr; addressLength = 4; } else if (ss->ss_family == AF_INET6) { - sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(ss); + const sockaddr_in6* sin6 = reinterpret_cast<const sockaddr_in6*>(ss); rawAddress = &sin6->sin6_addr.s6_addr; addressLength = 16; } else { @@ -85,7 +85,7 @@ jbyteArray socketAddressToByteArray(JNIEnv* env, sockaddr_storage* ss) { if (byteArray == NULL) { return NULL; } - env->SetByteArrayRegion(byteArray, 0, addressLength, reinterpret_cast<jbyte*>(rawAddress)); + env->SetByteArrayRegion(byteArray, 0, addressLength, reinterpret_cast<const jbyte*>(rawAddress)); return byteArray; } @@ -101,7 +101,7 @@ jobject byteArrayToInetAddress(JNIEnv* env, jbyteArray byteArray) { return env->CallStaticObjectMethod(JniConstants::inetAddressClass, getByAddressMethod, byteArray); } -jobject socketAddressToInetAddress(JNIEnv* env, sockaddr_storage* ss) { +jobject socketAddressToInetAddress(JNIEnv* env, const sockaddr_storage* ss) { jbyteArray byteArray = socketAddressToByteArray(env, ss); return byteArrayToInetAddress(env, byteArray); } diff --git a/luni/src/main/native/NetworkUtilities.h b/luni/src/main/native/NetworkUtilities.h index 76e622e..b2622c7 100644 --- a/luni/src/main/native/NetworkUtilities.h +++ b/luni/src/main/native/NetworkUtilities.h @@ -25,10 +25,10 @@ jobject byteArrayToInetAddress(JNIEnv* env, jbyteArray byteArray); bool byteArrayToSocketAddress(JNIEnv* env, jclass, jbyteArray byteArray, int port, sockaddr_storage* ss); // Convert from sockaddr_storage to byte[]. -jbyteArray socketAddressToByteArray(JNIEnv* env, sockaddr_storage* ss); +jbyteArray socketAddressToByteArray(JNIEnv* env, const sockaddr_storage* ss); // Convert from sockaddr_storage to InetAddress. -jobject socketAddressToInetAddress(JNIEnv* env, sockaddr_storage* ss); +jobject socketAddressToInetAddress(JNIEnv* env, const sockaddr_storage* ss); diff --git a/luni/src/main/native/libcore_io_OsConstants.cpp b/luni/src/main/native/libcore_io_OsConstants.cpp index a1bd88c..6165256 100644 --- a/luni/src/main/native/libcore_io_OsConstants.cpp +++ b/luni/src/main/native/libcore_io_OsConstants.cpp @@ -23,6 +23,7 @@ #include <errno.h> #include <fcntl.h> #include <netinet/in.h> +#include <netinet/tcp.h> #include <stdlib.h> #include <sys/ioctl.h> #include <sys/mman.h> @@ -157,6 +158,7 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) { initConstant(env, c, "IPV6_RECVPKTINFO", IPV6_RECVPKTINFO); initConstant(env, c, "IPV6_RECVRTHDR", IPV6_RECVRTHDR); initConstant(env, c, "IPV6_RECVTCLASS", IPV6_RECVTCLASS); + initConstant(env, c, "IPV6_TCLASS", IPV6_TCLASS); initConstant(env, c, "IPV6_UNICAST_HOPS", IPV6_UNICAST_HOPS); initConstant(env, c, "IPV6_V6ONLY", IPV6_V6ONLY); initConstant(env, c, "IP_MULTICAST_IF", IP_MULTICAST_IF); @@ -207,6 +209,7 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) { initConstant(env, c, "SOCK_RAW", SOCK_RAW); initConstant(env, c, "SOCK_SEQPACKET", SOCK_SEQPACKET); initConstant(env, c, "SOCK_STREAM", SOCK_STREAM); + initConstant(env, c, "SOL_SOCKET", SOL_SOCKET); initConstant(env, c, "SO_BROADCAST", SO_BROADCAST); initConstant(env, c, "SO_DEBUG", SO_DEBUG); initConstant(env, c, "SO_DONTROUTE", SO_DONTROUTE); @@ -248,6 +251,7 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) { initConstant(env, c, "S_IXGRP", S_IXGRP); initConstant(env, c, "S_IXOTH", S_IXOTH); initConstant(env, c, "S_IXUSR", S_IXUSR); + initConstant(env, c, "TCP_NODELAY", TCP_NODELAY); initConstant(env, c, "WCONTINUED", WCONTINUED); initConstant(env, c, "WEXITED", WEXITED); initConstant(env, c, "WNOHANG", WNOHANG); diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp index 3feef86..447d099 100644 --- a/luni/src/main/native/libcore_io_Posix.cpp +++ b/luni/src/main/native/libcore_io_Posix.cpp @@ -19,6 +19,7 @@ #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" +#include "NetworkUtilities.h" #include "ScopedPrimitiveArray.h" #include "ScopedUtfChars.h" #include "StaticAssert.h" @@ -26,12 +27,14 @@ #include <errno.h> #include <fcntl.h> +#include <netinet/in.h> #include <stdlib.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/sendfile.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/time.h> #include <sys/types.h> #include <sys/uio.h> #include <sys/utsname.h> @@ -141,6 +144,28 @@ private: std::vector<T*> mScopedByteArrays; }; +static jobject makeInetSocketAddress(JNIEnv* env, const sockaddr_storage* ss, int port) { + jobject inetAddress = socketAddressToInetAddress(env, ss); + if (inetAddress == NULL) { + return NULL; + } + static jmethodID ctor = env->GetMethodID(JniConstants::inetSocketAddressClass, "<init>", + "(Ljava/net/InetAddress;I)V"); + return env->NewObject(JniConstants::inetSocketAddressClass, ctor, inetAddress, port); +} + +static jobject makeSocketAddress(JNIEnv* env, const sockaddr_storage* ss) { + if (ss->ss_family == AF_INET) { + int port = ntohs(reinterpret_cast<const sockaddr_in*>(ss)->sin_port); + return makeInetSocketAddress(env, ss, port); + } else if (ss->ss_family == AF_INET6) { + int port = ntohs(reinterpret_cast<const sockaddr_in6*>(ss)->sin6_port); + return makeInetSocketAddress(env, ss, port); + } + // TODO: support AF_UNIX and AF_UNSPEC, and have some other behavior for other families + return NULL; +} + static jobject makeStructStat(JNIEnv* env, const struct stat& sb) { static jmethodID ctor = env->GetMethodID(JniConstants::structStatClass, "<init>", "(JJIJIIJJJJJJJ)V"); @@ -168,6 +193,17 @@ static jobject makeStructStatFs(JNIEnv* env, const struct statfs& sb) { static_cast<jlong>(sb.f_frsize)); } +static jobject makeStructLinger(JNIEnv* env, const struct linger& l) { + static jmethodID ctor = env->GetMethodID(JniConstants::structLingerClass, "<init>", "(II)V"); + return env->NewObject(JniConstants::structLingerClass, ctor, l.l_onoff, l.l_linger); +} + +static jobject makeStructTimeval(JNIEnv* env, const struct timeval& tv) { + static jmethodID ctor = env->GetMethodID(JniConstants::structTimevalClass, "<init>", "(JJ)V"); + return env->NewObject(JniConstants::structTimevalClass, ctor, + static_cast<jlong>(tv.tv_sec), static_cast<jlong>(tv.tv_usec)); +} + static jobject makeStructUtsname(JNIEnv* env, const struct utsname& buf) { #define TO_JAVA_STRING(NAME) \ jstring NAME = env->NewStringUTF(buf. NAME); \ @@ -320,6 +356,77 @@ static jstring Posix_getenv(JNIEnv* env, jobject, jstring javaName) { return env->NewStringUTF(getenv(name.c_str())); } +static jobject Posix_getsockname(JNIEnv* env, jobject, jobject javaFd) { + int fd = jniGetFDFromFileDescriptor(env, javaFd); + sockaddr_storage ss; + sockaddr* sa = reinterpret_cast<sockaddr*>(&ss); + socklen_t byteCount = sizeof(ss); + memset(&ss, 0, byteCount); + int rc = TEMP_FAILURE_RETRY(getsockname(fd, sa, &byteCount)); + if (rc == -1) { + throwErrnoException(env, "getsockname"); + return NULL; + } + return makeSocketAddress(env, &ss); +} + +static jint Posix_getsockoptByte(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) { + int fd = jniGetFDFromFileDescriptor(env, javaFd); + u_char result = 0; + socklen_t size = sizeof(result); + throwIfMinusOne(env, "getsockopt", TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &result, &size))); + return result; +} + +static jobject Posix_getsockoptInAddr(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) { + int fd = jniGetFDFromFileDescriptor(env, javaFd); + sockaddr_storage ss; + memset(&ss, 0, sizeof(ss)); + ss.ss_family = AF_INET; // This is only for the IPv4-only IP_MULTICAST_IF. + sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ss); + socklen_t size = sizeof(sa->sin_addr); + int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &sa->sin_addr, &size)); + if (rc == -1) { + throwErrnoException(env, "getsockopt"); + return NULL; + } + return socketAddressToInetAddress(env, &ss); +} + +static jint Posix_getsockoptInt(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) { + int fd = jniGetFDFromFileDescriptor(env, javaFd); + jint result = 0; + socklen_t size = sizeof(result); + throwIfMinusOne(env, "getsockopt", TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &result, &size))); + return result; +} + +static jobject Posix_getsockoptLinger(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) { + int fd = jniGetFDFromFileDescriptor(env, javaFd); + struct linger l; + socklen_t size = sizeof(l); + memset(&l, 0, size); + int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &l, &size)); + if (rc == -1) { + throwErrnoException(env, "getsockopt"); + return NULL; + } + return makeStructLinger(env, l); +} + +static jobject Posix_getsockoptTimeval(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) { + int fd = jniGetFDFromFileDescriptor(env, javaFd); + struct timeval tv; + socklen_t size = sizeof(tv); + memset(&tv, 0, size); + int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &tv, &size)); + if (rc == -1) { + throwErrnoException(env, "getsockopt"); + return NULL; + } + return makeStructTimeval(env, tv); +} + static jint Posix_ioctlInt(JNIEnv* env, jobject, jobject javaFd, jint cmd, jobject javaArg) { // This is complicated because ioctls may return their result by updating their argument // or via their return value, so we need to support both. @@ -598,6 +705,12 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(Posix, fsync, "(Ljava/io/FileDescriptor;)V"), NATIVE_METHOD(Posix, ftruncate, "(Ljava/io/FileDescriptor;J)V"), NATIVE_METHOD(Posix, getenv, "(Ljava/lang/String;)Ljava/lang/String;"), + NATIVE_METHOD(Posix, getsockname, "(Ljava/io/FileDescriptor;)Ljava/net/SocketAddress;"), + NATIVE_METHOD(Posix, getsockoptByte, "(Ljava/io/FileDescriptor;II)I"), + NATIVE_METHOD(Posix, getsockoptInAddr, "(Ljava/io/FileDescriptor;II)Ljava/net/InetAddress;"), + NATIVE_METHOD(Posix, getsockoptInt, "(Ljava/io/FileDescriptor;II)I"), + NATIVE_METHOD(Posix, getsockoptLinger, "(Ljava/io/FileDescriptor;II)Llibcore/io/StructLinger;"), + NATIVE_METHOD(Posix, getsockoptTimeval, "(Ljava/io/FileDescriptor;II)Llibcore/io/StructTimeval;"), NATIVE_METHOD(Posix, ioctlInt, "(Ljava/io/FileDescriptor;ILlibcore/util/MutableInt;)I"), NATIVE_METHOD(Posix, isatty, "(Ljava/io/FileDescriptor;)Z"), NATIVE_METHOD(Posix, listen, "(Ljava/io/FileDescriptor;I)V"), diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp index 4bac577..9e1c4b2 100644 --- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp +++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp @@ -40,23 +40,6 @@ #include <sys/un.h> #include <unistd.h> -// Temporary hack to build on systems that don't have up-to-date libc headers. -#ifndef IPV6_TCLASS -#ifdef __linux__ -#define IPV6_TCLASS 67 // Linux -#else -#define IPV6_TCLASS -1 // BSD(-like); TODO: Something better than this! -#endif -#endif - -/* - * TODO: The multicast code is highly platform-dependent, and for now - * we just punt on anything but Linux. - */ -#ifdef __linux__ -#define ENABLE_MULTICAST -#endif - #define JAVASOCKOPT_IP_MULTICAST_IF 16 #define JAVASOCKOPT_IP_MULTICAST_IF2 31 #define JAVASOCKOPT_IP_MULTICAST_LOOP 18 @@ -339,7 +322,6 @@ private: JNIEnv* mEnv; }; -#ifdef ENABLE_MULTICAST static void mcastJoinLeaveGroup(JNIEnv* env, int fd, jobject javaGroupRequest, bool join) { group_req groupRequest; @@ -379,7 +361,6 @@ static void mcastJoinLeaveGroup(JNIEnv* env, int fd, jobject javaGroupRequest, b return; } } -#endif // def ENABLE_MULTICAST static jint OSNetworkSystem_writeDirect(JNIEnv* env, jobject, jobject fileDescriptor, jint address, jint offset, jint count) { @@ -905,178 +886,6 @@ static jboolean OSNetworkSystem_selectImpl(JNIEnv* env, jclass, translateFdSet(env, writeFDArray, countWriteC, writeFds, flagArray.get(), countReadC, SOCKET_OP_WRITE); } -static jobject OSNetworkSystem_getSocketLocalAddress(JNIEnv* env, - jobject, jobject fileDescriptor) { - NetFd fd(env, fileDescriptor); - if (fd.isClosed()) { - return NULL; - } - - sockaddr_storage ss; - socklen_t ssLen = sizeof(ss); - memset(&ss, 0, ssLen); - int rc = getsockname(fd.get(), reinterpret_cast<sockaddr*>(&ss), &ssLen); - if (rc == -1) { - // TODO: the public API doesn't allow failure, so this whole method - // represents a broken design. In practice, though, getsockname can't - // fail unless we give it invalid arguments. - LOGE("getsockname failed: %s (errno=%i)", strerror(errno), errno); - return NULL; - } - return socketAddressToInetAddress(env, &ss); -} - -static jint OSNetworkSystem_getSocketLocalPort(JNIEnv* env, jobject, - jobject fileDescriptor) { - NetFd fd(env, fileDescriptor); - if (fd.isClosed()) { - return 0; - } - - sockaddr_storage ss; - socklen_t ssLen = sizeof(ss); - memset(&ss, 0, sizeof(ss)); - int rc = getsockname(fd.get(), reinterpret_cast<sockaddr*>(&ss), &ssLen); - if (rc == -1) { - // TODO: the public API doesn't allow failure, so this whole method - // represents a broken design. In practice, though, getsockname can't - // fail unless we give it invalid arguments. - LOGE("getsockname failed: %s (errno=%i)", strerror(errno), errno); - return 0; - } - return getSocketAddressPort(&ss); -} - -template <typename T> -static bool getSocketOption(JNIEnv* env, const NetFd& fd, int level, int option, T* value) { - socklen_t size = sizeof(*value); - int rc = getsockopt(fd.get(), level, option, value, &size); - if (rc == -1) { - LOGE("getSocketOption(fd=%i, level=%i, option=%i) failed: %s (errno=%i)", - fd.get(), level, option, strerror(errno), errno); - jniThrowSocketException(env, errno); - return false; - } - return true; -} - -static jobject getSocketOption_Boolean(JNIEnv* env, const NetFd& fd, int level, int option) { - int value; - return getSocketOption(env, fd, level, option, &value) ? booleanValueOf(env, value) : NULL; -} - -static jobject getSocketOption_Integer(JNIEnv* env, const NetFd& fd, int level, int option) { - int value; - return getSocketOption(env, fd, level, option, &value) ? integerValueOf(env, value) : NULL; -} - -static jobject OSNetworkSystem_getSocketOption(JNIEnv* env, jobject, jobject fileDescriptor, jint option) { - NetFd fd(env, fileDescriptor); - if (fd.isClosed()) { - return NULL; - } - - int family = getSocketAddressFamily(fd.get()); - if (family != AF_INET && family != AF_INET6) { - jniThrowSocketException(env, EAFNOSUPPORT); - return NULL; - } - - switch (option) { - case JAVASOCKOPT_TCP_NODELAY: - return getSocketOption_Boolean(env, fd, IPPROTO_TCP, TCP_NODELAY); - case JAVASOCKOPT_SO_SNDBUF: - return getSocketOption_Integer(env, fd, SOL_SOCKET, SO_SNDBUF); - case JAVASOCKOPT_SO_RCVBUF: - return getSocketOption_Integer(env, fd, SOL_SOCKET, SO_RCVBUF); - case JAVASOCKOPT_SO_BROADCAST: - return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_BROADCAST); - case JAVASOCKOPT_SO_REUSEADDR: - return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_REUSEADDR); - case JAVASOCKOPT_SO_KEEPALIVE: - return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_KEEPALIVE); - case JAVASOCKOPT_SO_OOBINLINE: - return getSocketOption_Boolean(env, fd, SOL_SOCKET, SO_OOBINLINE); - case JAVASOCKOPT_IP_TOS: - if (family == AF_INET) { - return getSocketOption_Integer(env, fd, IPPROTO_IP, IP_TOS); - } else { - return getSocketOption_Integer(env, fd, IPPROTO_IPV6, IPV6_TCLASS); - } - case JAVASOCKOPT_SO_LINGER: - { - linger lingr; - bool ok = getSocketOption(env, fd, SOL_SOCKET, SO_LINGER, &lingr); - if (!ok) { - return NULL; // We already threw. - } else if (!lingr.l_onoff) { - return booleanValueOf(env, false); - } else { - return integerValueOf(env, lingr.l_linger); - } - } - case JAVASOCKOPT_SO_TIMEOUT: - { - timeval timeout; - bool ok = getSocketOption(env, fd, SOL_SOCKET, SO_RCVTIMEO, &timeout); - return ok ? integerValueOf(env, toMs(timeout)) : NULL; - } -#ifdef ENABLE_MULTICAST - case JAVASOCKOPT_IP_MULTICAST_IF: - { - // Although setsockopt(2) can take an ip_mreqn for IP_MULTICAST_IF, getsockopt(2) - // always returns an in_addr. - sockaddr_storage ss; - memset(&ss, 0, sizeof(ss)); - ss.ss_family = AF_INET; // This call is IPv4-only. - sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ss); - if (!getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_IF, &sa->sin_addr)) { - return NULL; - } - return socketAddressToInetAddress(env, &ss); - } - case JAVASOCKOPT_IP_MULTICAST_IF2: - if (family == AF_INET) { - // The caller's asking for an interface index, but that's not how IPv4 works. - // Our Java should never get here, because we'll try IP_MULTICAST_IF first and - // that will satisfy us. - jniThrowSocketException(env, EAFNOSUPPORT); - } else { - return getSocketOption_Integer(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_IF); - } - case JAVASOCKOPT_IP_MULTICAST_LOOP: - if (family == AF_INET) { - // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte. - u_char loopback; - bool ok = getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loopback); - return ok ? booleanValueOf(env, loopback) : NULL; - } else { - return getSocketOption_Boolean(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); - } - case JAVASOCKOPT_MULTICAST_TTL: - if (family == AF_INET) { - // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int, - // IPv4 multicast TTL uses a byte. - u_char ttl; - bool ok = getSocketOption(env, fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl); - return ok ? integerValueOf(env, ttl) : NULL; - } else { - return getSocketOption_Integer(env, fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); - } -#else - case JAVASOCKOPT_MULTICAST_TTL: - case JAVASOCKOPT_IP_MULTICAST_IF: - case JAVASOCKOPT_IP_MULTICAST_IF2: - case JAVASOCKOPT_IP_MULTICAST_LOOP: - jniThrowException(env, "java/lang/UnsupportedOperationException", NULL); - return NULL; -#endif // def ENABLE_MULTICAST - default: - jniThrowSocketException(env, ENOPROTOOPT); - return NULL; - } -} - template <typename T> static void setSocketOption(JNIEnv* env, const NetFd& fd, int level, int option, T* value) { int rc = setsockopt(fd.get(), level, option, value, sizeof(*value)); @@ -1176,7 +985,6 @@ static void OSNetworkSystem_setSocketOption(JNIEnv* env, jobject, jobject fileDe case JAVASOCKOPT_TCP_NODELAY: setSocketOption(env, fd, IPPROTO_TCP, TCP_NODELAY, &intVal); return; -#ifdef ENABLE_MULTICAST case JAVASOCKOPT_MCAST_JOIN_GROUP: mcastJoinLeaveGroup(env, fd.get(), optVal, true); return; @@ -1237,16 +1045,6 @@ static void OSNetworkSystem_setSocketOption(JNIEnv* env, jobject, jobject fileDe } return; } -#else - case JAVASOCKOPT_MULTICAST_TTL: - case JAVASOCKOPT_MCAST_JOIN_GROUP: - case JAVASOCKOPT_MCAST_LEAVE_GROUP: - case JAVASOCKOPT_IP_MULTICAST_IF: - case JAVASOCKOPT_IP_MULTICAST_IF2: - case JAVASOCKOPT_IP_MULTICAST_LOOP: - jniThrowException(env, "java/lang/UnsupportedOperationException", NULL); - return; -#endif // def ENABLE_MULTICAST default: jniThrowSocketException(env, ENOPROTOOPT); } @@ -1273,9 +1071,6 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(OSNetworkSystem, connectNonBlocking, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)Z"), NATIVE_METHOD(OSNetworkSystem, connect, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;II)V"), NATIVE_METHOD(OSNetworkSystem, disconnectDatagram, "(Ljava/io/FileDescriptor;)V"), - NATIVE_METHOD(OSNetworkSystem, getSocketLocalAddress, "(Ljava/io/FileDescriptor;)Ljava/net/InetAddress;"), - NATIVE_METHOD(OSNetworkSystem, getSocketLocalPort, "(Ljava/io/FileDescriptor;)I"), - NATIVE_METHOD(OSNetworkSystem, getSocketOption, "(Ljava/io/FileDescriptor;I)Ljava/lang/Object;"), NATIVE_METHOD(OSNetworkSystem, isConnected, "(Ljava/io/FileDescriptor;I)Z"), NATIVE_METHOD(OSNetworkSystem, read, "(Ljava/io/FileDescriptor;[BII)I"), NATIVE_METHOD(OSNetworkSystem, readDirect, "(Ljava/io/FileDescriptor;II)I"), |