diff options
-rw-r--r-- | openjdk/sun/nio/ch/DatagramChannelImpl.java | 52 | ||||
-rw-r--r-- | openjdk/sun/nio/ch/Net.java | 107 | ||||
-rw-r--r-- | runtime/openjdk/sun.nio.ch.cs | 21 |
3 files changed, 156 insertions, 24 deletions
diff --git a/openjdk/sun/nio/ch/DatagramChannelImpl.java b/openjdk/sun/nio/ch/DatagramChannelImpl.java index b2631530..08cc5c95 100644 --- a/openjdk/sun/nio/ch/DatagramChannelImpl.java +++ b/openjdk/sun/nio/ch/DatagramChannelImpl.java @@ -86,8 +86,8 @@ class DatagramChannelImpl private int state = ST_UNINITIALIZED; // Binding - private SocketAddress localAddress; - private SocketAddress remoteAddress; + private InetSocketAddress localAddress; + private InetSocketAddress remoteAddress; // Our socket adaptor, if any private DatagramSocket socket; @@ -95,6 +95,12 @@ class DatagramChannelImpl // Multicast support private MembershipRegistry registry; + // set true when socket is bound and SO_REUSEADDRESS is emulated + private boolean reuseAddressEmulated; + + // set true/false when socket is already bound and SO_REUSEADDR is emulated + private boolean isReuseAddress; + // -- End of fields protected by stateLock @@ -163,7 +169,7 @@ class DatagramChannelImpl synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); - return localAddress; + return Net.getRevealedLocalAddress(localAddress); } } @@ -223,6 +229,12 @@ class DatagramChannelImpl } return this; } + if (name == StandardSocketOptions.SO_REUSEADDR && + Net.useExclusiveBind() && localAddress != null) + { + reuseAddressEmulated = true; + this.isReuseAddress = (Boolean)value; + } // remaining options don't need any special handling Net.setSocketOption(fd, Net.UNSPEC, name, value); @@ -281,6 +293,12 @@ class DatagramChannelImpl } } + if (name == StandardSocketOptions.SO_REUSEADDR && + reuseAddressEmulated) + { + return (T)Boolean.valueOf(isReuseAddress); + } + // no special handling return (T) Net.getSocketOption(fd, Net.UNSPEC, name); } @@ -416,7 +434,7 @@ class DatagramChannelImpl synchronized (writeLock) { ensureOpen(); - InetSocketAddress isa = (InetSocketAddress)target; + InetSocketAddress isa = Net.checkAddress(target); InetAddress ia = isa.getAddress(); if (ia == null) throw new IOException("Target address not resolved"); @@ -427,9 +445,9 @@ class DatagramChannelImpl SecurityManager sm = System.getSecurityManager(); if (sm != null) { if (ia.isMulticastAddress()) { - sm.checkMulticast(isa.getAddress()); + sm.checkMulticast(ia); } else { - sm.checkConnect(isa.getAddress().getHostAddress(), + sm.checkConnect(ia.getHostAddress(), isa.getPort()); } } @@ -449,7 +467,7 @@ class DatagramChannelImpl return 0; writerThread = NativeThread.current(); do { - n = send(fd, src, target); + n = send(fd, src, isa); } while ((n == IOStatus.INTERRUPTED) && isOpen()); synchronized (stateLock) { @@ -466,7 +484,7 @@ class DatagramChannelImpl } } - private int send(FileDescriptor fd, ByteBuffer src, SocketAddress target) + private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target) throws IOException { if (src.hasArray()) @@ -496,7 +514,7 @@ class DatagramChannelImpl } private int sendFromManagedBuffer(FileDescriptor fd, ByteBuffer bb, - SocketAddress target) + InetSocketAddress target) throws IOException { int pos = bb.position(); @@ -508,7 +526,7 @@ class DatagramChannelImpl int written; try { written = send0(preferIPv6, fd, bb.array(), bb.arrayOffset() + pos, - rem, target); + rem, target.getAddress(), target.getPort()); } catch (PortUnreachableException pue) { if (isConnected()) throw pue; @@ -700,6 +718,7 @@ class DatagramChannelImpl } } + @Override public DatagramChannel connect(SocketAddress sa) throws IOException { int localPort = 0; @@ -721,7 +740,7 @@ class DatagramChannelImpl // Connection succeeded; disallow further invocation state = ST_CONNECTED; - remoteAddress = sa; + remoteAddress = isa; sender = isa; cachedSenderInetAddress = isa.getAddress(); cachedSenderPort = isa.getPort(); @@ -740,12 +759,13 @@ class DatagramChannelImpl synchronized (stateLock) { if (!isConnected() || !isOpen()) return this; - InetSocketAddress isa = (InetSocketAddress)remoteAddress; + InetSocketAddress isa = remoteAddress; SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); - disconnect0(fd); + boolean isIPv6 = (family == StandardProtocolFamily.INET6); + disconnect0(fd, isIPv6); remoteAddress = null; state = ST_UNCONNECTED; @@ -1074,15 +1094,15 @@ class DatagramChannelImpl private static native void initIDs(); - private static native void disconnect0(FileDescriptor fd) + private static native void disconnect0(FileDescriptor fd, boolean isIPv6) throws IOException; private native int receive0(FileDescriptor fd, byte[] buf, int pos, int len, boolean connected) throws IOException; - private native int send0(boolean preferIPv6, FileDescriptor fd, byte[] buf, int pos, int len, - SocketAddress sa) + private native int send0(boolean preferIPv6, FileDescriptor fd, byte[] buf, int pos, + int len, InetAddress addr, int port) throws IOException; static { diff --git a/openjdk/sun/nio/ch/Net.java b/openjdk/sun/nio/ch/Net.java index 71ae5436..d9ab0f0f 100644 --- a/openjdk/sun/nio/ch/Net.java +++ b/openjdk/sun/nio/ch/Net.java @@ -31,6 +31,7 @@ import java.nio.channels.*; import java.util.*; import java.security.AccessController; import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; class Net { // package-private @@ -44,6 +45,40 @@ class Net { // package-private } }; + // Value of jdk.net.revealLocalAddress + private static boolean revealLocalAddress; + + // True if jdk.net.revealLocalAddress had been read + private static volatile boolean propRevealLocalAddress; + + // set to true if exclusive binding is on for Windows + private static final boolean exclusiveBind; + + static { + int availLevel = isExclusiveBindAvailable(); + if (availLevel >= 0) { + String exclBindProp = + java.security.AccessController.doPrivileged( + new PrivilegedAction<String>() { + @Override + public String run() { + return System.getProperty( + "sun.net.useExclusiveBind"); + } + }); + if (exclBindProp != null) { + exclusiveBind = exclBindProp.length() == 0 ? + true : Boolean.parseBoolean(exclBindProp); + } else if (availLevel == 1) { + exclusiveBind = true; + } else { + exclusiveBind = false; + } + } else { + exclusiveBind = false; + } + } + // -- Miscellaneous utilities -- private static volatile boolean checkedIPv6 = false; @@ -61,6 +96,13 @@ class Net { // package-private } /** + * Returns true if exclusive binding is on + */ + static boolean useExclusiveBind() { + return exclusiveBind; + } + + /** * Tells whether IPv6 sockets can join IPv4 multicast groups */ static boolean canIPv6SocketJoinIPv4Group() { @@ -148,6 +190,58 @@ class Net { // package-private } /** + * Returns the local address after performing a SecurityManager#checkConnect. + */ + static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) { + SecurityManager sm = System.getSecurityManager(); + if (addr == null || sm == null) + return addr; + + if (!getRevealLocalAddress()) { + // Return loopback address only if security check fails + try{ + sm.checkConnect(addr.getAddress().getHostAddress(), -1); + //Security check passed + } catch (SecurityException e) { + //Return loopback address + addr = getLoopbackAddress(addr.getPort()); + } + } + return addr; + } + + static String getRevealedLocalAddressAsString(InetSocketAddress addr) { + if (!getRevealLocalAddress() && System.getSecurityManager() != null) + addr = getLoopbackAddress(addr.getPort()); + return addr.toString(); + } + + private static boolean getRevealLocalAddress() { + if (!propRevealLocalAddress) { + try { + revealLocalAddress = Boolean.parseBoolean( + AccessController.doPrivileged( + new PrivilegedExceptionAction<String>() { + public String run() { + return System.getProperty( + "jdk.net.revealLocalAddress"); + } + })); + + } catch (Exception e) { + // revealLocalAddress is false + } + propRevealLocalAddress = true; + } + return revealLocalAddress; + } + + private static InetSocketAddress getLoopbackAddress(int port) { + return new InetSocketAddress(InetAddress.getLoopbackAddress(), + port); + } + + /** * Returns any IPv4 address of the given network interface, or * null if the interface does not have any IPv4 addresses. */ @@ -308,6 +402,12 @@ class Net { // package-private private static native boolean isIPv6Available0(); + /* + * Returns 1 for Windows versions that support exclusive binding by default, 0 + * for those that do not, and -1 for Solaris/Linux/Mac OS + */ + private static native int isExclusiveBindAvailable(); + private static native boolean canIPv6SocketJoinIPv4Group0(); private static native boolean canJoin6WithIPv4Group0(); @@ -341,11 +441,12 @@ class Net { // package-private { boolean preferIPv6 = isIPv6Available() && (family != StandardProtocolFamily.INET); - bind0(preferIPv6, fd, addr, port); + bind0(fd, preferIPv6, exclusiveBind, addr, port); } - private static native void bind0(boolean preferIPv6, FileDescriptor fd, - InetAddress addr, int port) + private static native void bind0(FileDescriptor fd, boolean preferIPv6, + boolean useExclBind, InetAddress addr, + int port) throws IOException; static native void listen(FileDescriptor fd, int backlog) throws IOException; diff --git a/runtime/openjdk/sun.nio.ch.cs b/runtime/openjdk/sun.nio.ch.cs index 723e4347..7b5258fa 100644 --- a/runtime/openjdk/sun.nio.ch.cs +++ b/runtime/openjdk/sun.nio.ch.cs @@ -34,7 +34,7 @@ static class Java_sun_nio_ch_DatagramChannelImpl { } - public static void disconnect0(FileDescriptor fd) + public static void disconnect0(FileDescriptor fd, bool isIPv6) { #if !FIRST_PASS try @@ -120,15 +120,14 @@ static class Java_sun_nio_ch_DatagramChannelImpl #endif } - public static int send0(object obj, bool preferIPv6, FileDescriptor fd, byte[] buf, int pos, int len, object sa) + public static int send0(object obj, bool preferIPv6, FileDescriptor fd, byte[] buf, int pos, int len, InetAddress addr, int port) { #if FIRST_PASS return 0; #else - java.net.InetSocketAddress addr = (java.net.InetSocketAddress)sa; try { - return fd.getSocket().SendTo(buf, pos, len, System.Net.Sockets.SocketFlags.None, new System.Net.IPEndPoint(java.net.SocketUtil.getAddressFromInetAddress(addr.getAddress(), preferIPv6), addr.getPort())); + return fd.getSocket().SendTo(buf, pos, len, System.Net.Sockets.SocketFlags.None, new System.Net.IPEndPoint(java.net.SocketUtil.getAddressFromInetAddress(addr, preferIPv6), port)); } catch (System.Net.Sockets.SocketException x) { @@ -521,6 +520,13 @@ namespace IKVM.NativeCode.sun.nio.ch && Environment.OSVersion.Version.Major >= 6; } + public static int isExclusiveBindAvailable() + { + return Environment.OSVersion.Platform == PlatformID.Win32NT + ? Environment.OSVersion.Version.Major >= 6 ? 1 : 0 + : -1; + } + public static bool canIPv6SocketJoinIPv4Group0() { return false; @@ -985,11 +991,16 @@ namespace IKVM.NativeCode.sun.nio.ch #endif } - public static void bind0(bool preferIPv6, FileDescriptor fd, InetAddress addr, int port) + public static void bind0(FileDescriptor fd, bool preferIPv6, bool useExclBind, InetAddress addr, int port) { #if !FIRST_PASS try { + if (useExclBind) + { + // TODO enable this after we merge OpenJDK 7u40 + //global::java.net.net_util_md.setExclusiveBind(fd.getSocket()); + } fd.getSocket().Bind(new System.Net.IPEndPoint(global::java.net.SocketUtil.getAddressFromInetAddress(addr, preferIPv6), port)); } catch (System.Net.Sockets.SocketException x) |