提交 3114becf 编写于 作者: K khazra

7170730: Improve Windows network stack support.

Summary: Enable exclusive binding of ports on Windows
Reviewed-by: alanb, chegar, ahgross
上级 21f59d92
...@@ -109,6 +109,7 @@ SUNWprivate_1.1 { ...@@ -109,6 +109,7 @@ SUNWprivate_1.1 {
Java_sun_nio_ch_Net_getInterface6; Java_sun_nio_ch_Net_getInterface6;
Java_sun_nio_ch_Net_shutdown; Java_sun_nio_ch_Net_shutdown;
Java_sun_nio_ch_Net_poll; Java_sun_nio_ch_Net_poll;
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
Java_sun_nio_ch_PollArrayWrapper_interrupt; Java_sun_nio_ch_PollArrayWrapper_interrupt;
Java_sun_nio_ch_PollArrayWrapper_poll0; Java_sun_nio_ch_PollArrayWrapper_poll0;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
......
...@@ -117,6 +117,7 @@ SUNWprivate_1.1 { ...@@ -117,6 +117,7 @@ SUNWprivate_1.1 {
Java_sun_nio_ch_Net_getInterface6; Java_sun_nio_ch_Net_getInterface6;
Java_sun_nio_ch_Net_shutdown; Java_sun_nio_ch_Net_shutdown;
Java_sun_nio_ch_Net_poll; Java_sun_nio_ch_Net_poll;
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
Java_sun_nio_ch_PollArrayWrapper_interrupt; Java_sun_nio_ch_PollArrayWrapper_interrupt;
Java_sun_nio_ch_PollArrayWrapper_poll0; Java_sun_nio_ch_PollArrayWrapper_poll0;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
......
...@@ -105,6 +105,7 @@ SUNWprivate_1.1 { ...@@ -105,6 +105,7 @@ SUNWprivate_1.1 {
Java_sun_nio_ch_Net_getInterface6; Java_sun_nio_ch_Net_getInterface6;
Java_sun_nio_ch_Net_shutdown; Java_sun_nio_ch_Net_shutdown;
Java_sun_nio_ch_Net_poll; Java_sun_nio_ch_Net_poll;
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
Java_sun_nio_ch_PollArrayWrapper_interrupt; Java_sun_nio_ch_PollArrayWrapper_interrupt;
Java_sun_nio_ch_PollArrayWrapper_poll0; Java_sun_nio_ch_PollArrayWrapper_poll0;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
......
...@@ -117,6 +117,7 @@ SUNWprivate_1.1 { ...@@ -117,6 +117,7 @@ SUNWprivate_1.1 {
Java_sun_nio_ch_Net_getInterface6; Java_sun_nio_ch_Net_getInterface6;
Java_sun_nio_ch_Net_shutdown; Java_sun_nio_ch_Net_shutdown;
Java_sun_nio_ch_Net_poll; Java_sun_nio_ch_Net_poll;
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
Java_sun_nio_ch_PollArrayWrapper_interrupt; Java_sun_nio_ch_PollArrayWrapper_interrupt;
Java_sun_nio_ch_PollArrayWrapper_poll0; Java_sun_nio_ch_PollArrayWrapper_poll0;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
......
...@@ -109,6 +109,7 @@ SUNWprivate_1.1 { ...@@ -109,6 +109,7 @@ SUNWprivate_1.1 {
Java_sun_nio_ch_Net_getInterface6; Java_sun_nio_ch_Net_getInterface6;
Java_sun_nio_ch_Net_shutdown; Java_sun_nio_ch_Net_shutdown;
Java_sun_nio_ch_Net_poll; Java_sun_nio_ch_Net_poll;
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
Java_sun_nio_ch_PollArrayWrapper_interrupt; Java_sun_nio_ch_PollArrayWrapper_interrupt;
Java_sun_nio_ch_PollArrayWrapper_poll0; Java_sun_nio_ch_PollArrayWrapper_poll0;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
......
...@@ -105,6 +105,7 @@ SUNWprivate_1.1 { ...@@ -105,6 +105,7 @@ SUNWprivate_1.1 {
Java_sun_nio_ch_Net_getInterface6; Java_sun_nio_ch_Net_getInterface6;
Java_sun_nio_ch_Net_shutdown; Java_sun_nio_ch_Net_shutdown;
Java_sun_nio_ch_Net_poll; Java_sun_nio_ch_Net_poll;
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
Java_sun_nio_ch_PollArrayWrapper_interrupt; Java_sun_nio_ch_PollArrayWrapper_interrupt;
Java_sun_nio_ch_PollArrayWrapper_poll0; Java_sun_nio_ch_PollArrayWrapper_poll0;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0; Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
......
...@@ -63,6 +63,8 @@ abstract class AsynchronousServerSocketChannelImpl ...@@ -63,6 +63,8 @@ abstract class AsynchronousServerSocketChannelImpl
// set true when accept operation is cancelled // set true when accept operation is cancelled
private volatile boolean acceptKilled; private volatile boolean acceptKilled;
// set true when exclusive binding is on and SO_REUSEADDR is emulated
private boolean isReuseAddress;
AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) { AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) {
super(group.provider()); super(group.provider());
...@@ -186,7 +188,14 @@ abstract class AsynchronousServerSocketChannelImpl ...@@ -186,7 +188,14 @@ abstract class AsynchronousServerSocketChannelImpl
try { try {
begin(); begin();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = (Boolean)value;
} else {
Net.setSocketOption(fd, Net.UNSPEC, name, value); Net.setSocketOption(fd, Net.UNSPEC, name, value);
}
return this; return this;
} finally { } finally {
end(); end();
...@@ -203,6 +212,12 @@ abstract class AsynchronousServerSocketChannelImpl ...@@ -203,6 +212,12 @@ abstract class AsynchronousServerSocketChannelImpl
try { try {
begin(); begin();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
return (T)Boolean.valueOf(isReuseAddress);
}
return (T) Net.getSocketOption(fd, Net.UNSPEC, name); return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
} finally { } finally {
end(); end();
......
...@@ -79,6 +79,9 @@ abstract class AsynchronousSocketChannelImpl ...@@ -79,6 +79,9 @@ abstract class AsynchronousSocketChannelImpl
private final ReadWriteLock closeLock = new ReentrantReadWriteLock(); private final ReadWriteLock closeLock = new ReentrantReadWriteLock();
private volatile boolean open = true; private volatile boolean open = true;
// set true when exclusive binding is on and SO_REUSEADDR is emulated
private boolean isReuseAddress;
AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group) AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group)
throws IOException throws IOException
{ {
...@@ -455,7 +458,14 @@ abstract class AsynchronousSocketChannelImpl ...@@ -455,7 +458,14 @@ abstract class AsynchronousSocketChannelImpl
begin(); begin();
if (writeShutdown) if (writeShutdown)
throw new IOException("Connection has been shutdown for writing"); throw new IOException("Connection has been shutdown for writing");
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = (Boolean)value;
} else {
Net.setSocketOption(fd, Net.UNSPEC, name, value); Net.setSocketOption(fd, Net.UNSPEC, name, value);
}
return this; return this;
} finally { } finally {
end(); end();
...@@ -472,6 +482,12 @@ abstract class AsynchronousSocketChannelImpl ...@@ -472,6 +482,12 @@ abstract class AsynchronousSocketChannelImpl
try { try {
begin(); begin();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
return (T)Boolean.valueOf(isReuseAddress);
}
return (T) Net.getSocketOption(fd, Net.UNSPEC, name); return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
} finally { } finally {
end(); end();
......
...@@ -94,6 +94,12 @@ class DatagramChannelImpl ...@@ -94,6 +94,12 @@ class DatagramChannelImpl
// Multicast support // Multicast support
private MembershipRegistry registry; 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 // -- End of fields protected by stateLock
...@@ -222,6 +228,12 @@ class DatagramChannelImpl ...@@ -222,6 +228,12 @@ class DatagramChannelImpl
} }
return this; 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 // remaining options don't need any special handling
Net.setSocketOption(fd, Net.UNSPEC, name, value); Net.setSocketOption(fd, Net.UNSPEC, name, value);
...@@ -280,6 +292,12 @@ class DatagramChannelImpl ...@@ -280,6 +292,12 @@ class DatagramChannelImpl
} }
} }
if (name == StandardSocketOptions.SO_REUSEADDR &&
reuseAddressEmulated)
{
return (T)Boolean.valueOf(isReuseAddress);
}
// no special handling // no special handling
return (T) Net.getSocketOption(fd, Net.UNSPEC, name); return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
} }
......
...@@ -44,6 +44,34 @@ public class Net { ...@@ -44,6 +44,34 @@ public class Net {
} }
}; };
// 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 -- // -- Miscellaneous utilities --
private static volatile boolean checkedIPv6 = false; private static volatile boolean checkedIPv6 = false;
...@@ -60,6 +88,13 @@ public class Net { ...@@ -60,6 +88,13 @@ public class Net {
return isIPv6Available; return isIPv6Available;
} }
/**
* Returns true if exclusive binding is on
*/
static boolean useExclusiveBind() {
return exclusiveBind;
}
/** /**
* Tells whether IPv6 sockets can join IPv4 multicast groups * Tells whether IPv6 sockets can join IPv4 multicast groups
*/ */
...@@ -308,6 +343,12 @@ public class Net { ...@@ -308,6 +343,12 @@ public class Net {
private static native boolean isIPv6Available0(); 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 canIPv6SocketJoinIPv4Group0();
private static native boolean canJoin6WithIPv4Group0(); private static native boolean canJoin6WithIPv4Group0();
...@@ -341,11 +382,12 @@ public class Net { ...@@ -341,11 +382,12 @@ public class Net {
{ {
boolean preferIPv6 = isIPv6Available() && boolean preferIPv6 = isIPv6Available() &&
(family != StandardProtocolFamily.INET); (family != StandardProtocolFamily.INET);
bind0(preferIPv6, fd, addr, port); bind0(fd, preferIPv6, exclusiveBind, addr, port);
} }
private static native void bind0(boolean preferIPv6, FileDescriptor fd, private static native void bind0(FileDescriptor fd, boolean preferIPv6,
InetAddress addr, int port) boolean useExclBind, InetAddress addr,
int port)
throws IOException; throws IOException;
static native void listen(FileDescriptor fd, int backlog) throws IOException; static native void listen(FileDescriptor fd, int backlog) throws IOException;
......
...@@ -74,6 +74,9 @@ class ServerSocketChannelImpl ...@@ -74,6 +74,9 @@ class ServerSocketChannelImpl
// Binding // Binding
private SocketAddress localAddress; // null => unbound private SocketAddress localAddress; // null => unbound
// set true when exclusive binding is on and SO_REUSEADDR is emulated
private boolean isReuseAddress;
// Our socket adaptor, if any // Our socket adaptor, if any
ServerSocket socket; ServerSocket socket;
...@@ -125,13 +128,18 @@ class ServerSocketChannelImpl ...@@ -125,13 +128,18 @@ class ServerSocketChannelImpl
throw new NullPointerException(); throw new NullPointerException();
if (!supportedOptions().contains(name)) if (!supportedOptions().contains(name))
throw new UnsupportedOperationException("'" + name + "' not supported"); throw new UnsupportedOperationException("'" + name + "' not supported");
synchronized (stateLock) { synchronized (stateLock) {
if (!isOpen()) if (!isOpen())
throw new ClosedChannelException(); throw new ClosedChannelException();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = (Boolean)value;
} else {
// no options that require special handling // no options that require special handling
Net.setSocketOption(fd, Net.UNSPEC, name, value); Net.setSocketOption(fd, Net.UNSPEC, name, value);
}
return this; return this;
} }
} }
...@@ -149,7 +157,12 @@ class ServerSocketChannelImpl ...@@ -149,7 +157,12 @@ class ServerSocketChannelImpl
synchronized (stateLock) { synchronized (stateLock) {
if (!isOpen()) if (!isOpen())
throw new ClosedChannelException(); throw new ClosedChannelException();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
return (T)Boolean.valueOf(isReuseAddress);
}
// no options that require special handling // no options that require special handling
return (T) Net.getSocketOption(fd, Net.UNSPEC, name); return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
} }
......
...@@ -70,6 +70,9 @@ class SocketChannelImpl ...@@ -70,6 +70,9 @@ class SocketChannelImpl
// -- The following fields are protected by stateLock // -- The following fields are protected by stateLock
// set true when exclusive binding is on and SO_REUSEADDR is emulated
private boolean isReuseAddress;
// State, increases monotonically // State, increases monotonically
private static final int ST_UNINITIALIZED = -1; private static final int ST_UNINITIALIZED = -1;
private static final int ST_UNCONNECTED = 0; private static final int ST_UNCONNECTED = 0;
...@@ -174,6 +177,12 @@ class SocketChannelImpl ...@@ -174,6 +177,12 @@ class SocketChannelImpl
if (!Net.isIPv6Available()) if (!Net.isIPv6Available())
Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value); Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value);
return this; return this;
} else if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = (Boolean)value;
return this;
} }
// no options that require special handling // no options that require special handling
...@@ -196,6 +205,13 @@ class SocketChannelImpl ...@@ -196,6 +205,13 @@ class SocketChannelImpl
if (!isOpen()) if (!isOpen())
throw new ClosedChannelException(); throw new ClosedChannelException();
if (name == StandardSocketOptions.SO_REUSEADDR &&
Net.useExclusiveBind())
{
// SO_REUSEADDR emulated when using exclusive bind
return (T)Boolean.valueOf(isReuseAddress);
}
// special handling for IP_TOS: always return 0 when IPv6 // special handling for IP_TOS: always return 0 when IPv6
if (name == StandardSocketOptions.IP_TOS) { if (name == StandardSocketOptions.IP_TOS) {
return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) : return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) :
......
...@@ -124,6 +124,11 @@ Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) ...@@ -124,6 +124,11 @@ Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
} }
JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
return -1;
}
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
{ {
...@@ -206,8 +211,8 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, ...@@ -206,8 +211,8 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,
jobject fdo, jobject iao, int port) jboolean useExclBind, jobject iao, int port)
{ {
SOCKADDR sa; SOCKADDR sa;
int sa_len = SOCKADDR_LEN; int sa_len = SOCKADDR_LEN;
......
...@@ -56,25 +56,46 @@ class DefaultDatagramSocketImplFactory ...@@ -56,25 +56,46 @@ class DefaultDatagramSocketImplFactory
/* If the version supports a dual stack TCP implementation */ /* If the version supports a dual stack TCP implementation */
private static boolean useDualStackImpl = false; private static boolean useDualStackImpl = false;
/* sun.net.useExclusiveBind */
private static String exclBindProp;
/* True if exclusive binding is on for Windows */
private static boolean exclusiveBind = true;
static { static {
// Determine Windows Version. // Determine Windows Version.
java.security.AccessController.doPrivileged( new PrivilegedAction<Object>() { java.security.AccessController.doPrivileged(
new PrivilegedAction<Object>() {
public Object run() { public Object run() {
version = 0; version = 0;
try { try {
version = Float.parseFloat(System.getProperties().getProperty("os.version")); version = Float.parseFloat(System.getProperties()
.getProperty("os.version"));
preferIPv4Stack = Boolean.parseBoolean( preferIPv4Stack = Boolean.parseBoolean(
System.getProperties().getProperty("java.net.preferIPv4Stack")); System.getProperties()
.getProperty(
"java.net.preferIPv4Stack"));
exclBindProp = System.getProperty(
"sun.net.useExclusiveBind");
} catch (NumberFormatException e ) { } catch (NumberFormatException e ) {
assert false : e; assert false : e;
} }
return null; // nothing to return return null; // nothing to return
} }); }
});
// (version >= 6.0) implies Vista or greater. // (version >= 6.0) implies Vista or greater.
if (version >= 6.0 && !preferIPv4Stack) { if (version >= 6.0 && !preferIPv4Stack) {
useDualStackImpl = true; useDualStackImpl = true;
} }
if (exclBindProp != null) {
// sun.net.useExclusiveBind is true
exclusiveBind = exclBindProp.length() == 0 ? true
: Boolean.parseBoolean(exclBindProp);
} else if (version < 6.0) {
exclusiveBind = false;
}
// impl.prefix // impl.prefix
String prefix = null; String prefix = null;
...@@ -105,10 +126,12 @@ class DefaultDatagramSocketImplFactory ...@@ -105,10 +126,12 @@ class DefaultDatagramSocketImplFactory
throw new SocketException("can't instantiate DatagramSocketImpl"); throw new SocketException("can't instantiate DatagramSocketImpl");
} }
} else { } else {
if (isMulticast)
exclusiveBind = false;
if (useDualStackImpl && !isMulticast) if (useDualStackImpl && !isMulticast)
return new DualStackPlainDatagramSocketImpl(); return new DualStackPlainDatagramSocketImpl(exclusiveBind);
else else
return new TwoStacksPlainDatagramSocketImpl(); return new TwoStacksPlainDatagramSocketImpl(exclusiveBind);
} }
} }
} }
...@@ -45,6 +45,22 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -45,6 +45,22 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
{ {
static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess(); static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
// true if this socket is exclusively bound
private final boolean exclusiveBind;
/*
* Set to true if SO_REUSEADDR is set after the socket is bound to
* indicate SO_REUSEADDR is being emulated
*/
private boolean reuseAddressEmulated;
// emulates SO_REUSEADDR when exclusiveBind is true and socket is bound
private boolean isReuseAddress;
DualStackPlainDatagramSocketImpl(boolean exclBind) {
exclusiveBind = exclBind;
}
protected void datagramSocketCreate() throws SocketException { protected void datagramSocketCreate() throws SocketException {
if (fd == null) if (fd == null)
throw new SocketException("Socket closed"); throw new SocketException("Socket closed");
...@@ -61,7 +77,7 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -61,7 +77,7 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
if (laddr == null) if (laddr == null)
throw new NullPointerException("argument address"); throw new NullPointerException("argument address");
socketBind(nativefd, laddr, lport); socketBind(nativefd, laddr, lport, exclusiveBind);
if (lport == 0) { if (lport == 0) {
localPort = socketLocalPort(nativefd); localPort = socketLocalPort(nativefd);
} else { } else {
...@@ -141,6 +157,7 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -141,6 +157,7 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
fdAccess.set(fd, -1); fdAccess.set(fd, -1);
} }
@SuppressWarnings("fallthrough")
protected void socketSetOption(int opt, Object val) throws SocketException { protected void socketSetOption(int opt, Object val) throws SocketException {
int nativefd = checkAndReturnNativeFD(); int nativefd = checkAndReturnNativeFD();
...@@ -153,6 +170,13 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -153,6 +170,13 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
optionValue = ((Integer)val).intValue(); optionValue = ((Integer)val).intValue();
break; break;
case SO_REUSEADDR : case SO_REUSEADDR :
if (exclusiveBind && localPort != 0) {
// socket already bound, emulate SO_REUSEADDR
reuseAddressEmulated = true;
isReuseAddress = (Boolean)val;
return;
}
//Intentional fallthrough
case SO_BROADCAST : case SO_BROADCAST :
optionValue = ((Boolean)val).booleanValue() ? 1 : 0; optionValue = ((Boolean)val).booleanValue() ? 1 : 0;
break; break;
...@@ -170,6 +194,8 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -170,6 +194,8 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
if (opt == SO_BINDADDR) { if (opt == SO_BINDADDR) {
return socketLocalAddress(nativefd); return socketLocalAddress(nativefd);
} }
if (opt == SO_REUSEADDR && reuseAddressEmulated)
return isReuseAddress;
int value = socketGetIntOption(nativefd, opt); int value = socketGetIntOption(nativefd, opt);
Object returnValue = null; Object returnValue = null;
...@@ -238,8 +264,8 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -238,8 +264,8 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
private static native int socketCreate(boolean v6Only); private static native int socketCreate(boolean v6Only);
private static native void socketBind(int fd, InetAddress localAddress, int localport) private static native void socketBind(int fd, InetAddress localAddress,
throws SocketException; int localport, boolean exclBind) throws SocketException;
private static native void socketConnect(int fd, InetAddress address, int port) private static native void socketConnect(int fd, InetAddress address, int port)
throws SocketException; throws SocketException;
......
...@@ -42,10 +42,20 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -42,10 +42,20 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
{ {
static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess(); static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
public DualStackPlainSocketImpl() {}
public DualStackPlainSocketImpl(FileDescriptor fd) { // true if this socket is exclusively bound
private final boolean exclusiveBind;
// emulates SO_REUSEADDR when exclusiveBind is true
private boolean isReuseAddress;
public DualStackPlainSocketImpl(boolean exclBind) {
exclusiveBind = exclBind;
}
public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
this.fd = fd; this.fd = fd;
exclusiveBind = exclBind;
} }
void socketCreate(boolean stream) throws IOException { void socketCreate(boolean stream) throws IOException {
...@@ -93,7 +103,7 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -93,7 +103,7 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
if (address == null) if (address == null)
throw new NullPointerException("inet address argument is null."); throw new NullPointerException("inet address argument is null.");
bind0(nativefd, address, port); bind0(nativefd, address, port, exclusiveBind);
if (port == 0) { if (port == 0) {
localport = localPort0(nativefd); localport = localPort0(nativefd);
} else { } else {
...@@ -162,6 +172,8 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -162,6 +172,8 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
shutdown0(nativefd, howto); shutdown0(nativefd, howto);
} }
// Intentional fallthrough after SO_REUSEADDR
@SuppressWarnings("fallthrough")
void socketSetOption(int opt, boolean on, Object value) void socketSetOption(int opt, boolean on, Object value)
throws SocketException { throws SocketException {
int nativefd = checkAndReturnNativeFD(); int nativefd = checkAndReturnNativeFD();
...@@ -175,8 +187,13 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -175,8 +187,13 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
switch(opt) { switch(opt) {
case TCP_NODELAY : case TCP_NODELAY :
case SO_OOBINLINE : case SO_OOBINLINE :
case SO_KEEPALIVE :
case SO_REUSEADDR : case SO_REUSEADDR :
if (exclusiveBind) {
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = on;
return;
}
case SO_KEEPALIVE :
optionValue = on ? 1 : 0; optionValue = on ? 1 : 0;
break; break;
case SO_SNDBUF : case SO_SNDBUF :
...@@ -207,6 +224,10 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -207,6 +224,10 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
return 0; // return value doesn't matter. return 0; // return value doesn't matter.
} }
// SO_REUSEADDR emulated when using exclusive bind
if (opt == SO_REUSEADDR && exclusiveBind)
return isReuseAddress? 1 : -1;
int value = getIntOption(nativefd, opt); int value = getIntOption(nativefd, opt);
switch (opt) { switch (opt) {
...@@ -243,7 +264,8 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -243,7 +264,8 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
static native int socket0(boolean stream, boolean v6Only) throws IOException; static native int socket0(boolean stream, boolean v6Only) throws IOException;
static native void bind0(int fd, InetAddress localAddress, int localport) static native void bind0(int fd, InetAddress localAddress, int localport,
boolean exclBind)
throws IOException; throws IOException;
static native int connect0(int fd, InetAddress remote, int remotePort) static native int connect0(int fd, InetAddress remote, int remotePort)
......
...@@ -54,6 +54,12 @@ class PlainSocketImpl extends AbstractPlainSocketImpl ...@@ -54,6 +54,12 @@ class PlainSocketImpl extends AbstractPlainSocketImpl
/* If the version supports a dual stack TCP implementation */ /* If the version supports a dual stack TCP implementation */
private static boolean useDualStackImpl = false; private static boolean useDualStackImpl = false;
/* sun.net.useExclusiveBind */
private static String exclBindProp;
/* True if exclusive binding is on for Windows */
private static boolean exclusiveBind = true;
static { static {
java.security.AccessController.doPrivileged( new PrivilegedAction<Object>() { java.security.AccessController.doPrivileged( new PrivilegedAction<Object>() {
public Object run() { public Object run() {
...@@ -62,6 +68,7 @@ class PlainSocketImpl extends AbstractPlainSocketImpl ...@@ -62,6 +68,7 @@ class PlainSocketImpl extends AbstractPlainSocketImpl
version = Float.parseFloat(System.getProperties().getProperty("os.version")); version = Float.parseFloat(System.getProperties().getProperty("os.version"));
preferIPv4Stack = Boolean.parseBoolean( preferIPv4Stack = Boolean.parseBoolean(
System.getProperties().getProperty("java.net.preferIPv4Stack")); System.getProperties().getProperty("java.net.preferIPv4Stack"));
exclBindProp = System.getProperty("sun.net.useExclusiveBind");
} catch (NumberFormatException e ) { } catch (NumberFormatException e ) {
assert false : e; assert false : e;
} }
...@@ -72,6 +79,14 @@ class PlainSocketImpl extends AbstractPlainSocketImpl ...@@ -72,6 +79,14 @@ class PlainSocketImpl extends AbstractPlainSocketImpl
if (version >= 6.0 && !preferIPv4Stack) { if (version >= 6.0 && !preferIPv4Stack) {
useDualStackImpl = true; useDualStackImpl = true;
} }
if (exclBindProp != null) {
// sun.net.useExclusiveBind is true
exclusiveBind = exclBindProp.length() == 0 ? true
: Boolean.parseBoolean(exclBindProp);
} else if (version < 6.0) {
exclusiveBind = false;
}
} }
/** /**
...@@ -79,9 +94,9 @@ class PlainSocketImpl extends AbstractPlainSocketImpl ...@@ -79,9 +94,9 @@ class PlainSocketImpl extends AbstractPlainSocketImpl
*/ */
PlainSocketImpl() { PlainSocketImpl() {
if (useDualStackImpl) { if (useDualStackImpl) {
impl = new DualStackPlainSocketImpl(); impl = new DualStackPlainSocketImpl(exclusiveBind);
} else { } else {
impl = new TwoStacksPlainSocketImpl(); impl = new TwoStacksPlainSocketImpl(exclusiveBind);
} }
} }
...@@ -90,9 +105,9 @@ class PlainSocketImpl extends AbstractPlainSocketImpl ...@@ -90,9 +105,9 @@ class PlainSocketImpl extends AbstractPlainSocketImpl
*/ */
PlainSocketImpl(FileDescriptor fd) { PlainSocketImpl(FileDescriptor fd) {
if (useDualStackImpl) { if (useDualStackImpl) {
impl = new DualStackPlainSocketImpl(fd); impl = new DualStackPlainSocketImpl(fd, exclusiveBind);
} else { } else {
impl = new TwoStacksPlainSocketImpl(fd); impl = new TwoStacksPlainSocketImpl(fd, exclusiveBind);
} }
} }
......
...@@ -66,6 +66,22 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -66,6 +66,22 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
init(); init();
} }
// true if this socket is exclusively bound
private final boolean exclusiveBind;
/*
* Set to true if SO_REUSEADDR is set after the socket is bound to
* indicate SO_REUSEADDR is being emulated
*/
private boolean reuseAddressEmulated;
// emulates SO_REUSEADDR when exclusiveBind is true and socket is bound
private boolean isReuseAddress;
TwoStacksPlainDatagramSocketImpl(boolean exclBind) {
exclusiveBind = exclBind;
}
protected synchronized void create() throws SocketException { protected synchronized void create() throws SocketException {
fd1 = new FileDescriptor(); fd1 = new FileDescriptor();
try { try {
...@@ -84,6 +100,14 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -84,6 +100,14 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
} }
} }
@Override
protected synchronized void bind0(int lport, InetAddress laddr)
throws SocketException
{
bind0(lport, laddr, exclusiveBind);
}
protected synchronized void receive(DatagramPacket p) protected synchronized void receive(DatagramPacket p)
throws IOException { throws IOException {
try { try {
...@@ -104,9 +128,25 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -104,9 +128,25 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
} }
int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily(); int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily();
return socketLocalAddress(family); return socketLocalAddress(family);
} else } else if (optID == SO_REUSEADDR && reuseAddressEmulated) {
return isReuseAddress;
} else {
return super.getOption(optID); return super.getOption(optID);
} }
}
protected void socketSetOption(int opt, Object val)
throws SocketException
{
if (opt == SO_REUSEADDR && exclusiveBind && localPort != 0) {
// socket already bound, emulate
reuseAddressEmulated = true;
isReuseAddress = (Boolean)val;
} else {
socketNativeSetOption(opt, val);
}
}
protected boolean isClosed() { protected boolean isClosed() {
return (fd == null && fd1 == null) ? true : false; return (fd == null && fd1 == null) ? true : false;
...@@ -123,7 +163,8 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -123,7 +163,8 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
/* Native methods */ /* Native methods */
protected synchronized native void bind0(int lport, InetAddress laddr) protected synchronized native void bind0(int lport, InetAddress laddr,
boolean exclBind)
throws SocketException; throws SocketException;
protected native void send(DatagramPacket p) throws IOException; protected native void send(DatagramPacket p) throws IOException;
...@@ -155,7 +196,7 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl ...@@ -155,7 +196,7 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
protected native void datagramSocketClose(); protected native void datagramSocketClose();
protected native void socketSetOption(int opt, Object val) protected native void socketNativeSetOption(int opt, Object val)
throws SocketException; throws SocketException;
protected native Object socketGetOption(int opt) throws SocketException; protected native Object socketGetOption(int opt) throws SocketException;
......
...@@ -66,14 +66,23 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -66,14 +66,23 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl
*/ */
private int lastfd = -1; private int lastfd = -1;
// true if this socket is exclusively bound
private final boolean exclusiveBind;
// emulates SO_REUSEADDR when exclusiveBind is true
private boolean isReuseAddress;
static { static {
initProto(); initProto();
} }
public TwoStacksPlainSocketImpl() {} public TwoStacksPlainSocketImpl(boolean exclBind) {
exclusiveBind = exclBind;
}
public TwoStacksPlainSocketImpl(FileDescriptor fd) { public TwoStacksPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
this.fd = fd; this.fd = fd;
exclusiveBind = exclBind;
} }
/** /**
...@@ -116,13 +125,33 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -116,13 +125,33 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl
InetAddressContainer in = new InetAddressContainer(); InetAddressContainer in = new InetAddressContainer();
socketGetOption(opt, in); socketGetOption(opt, in);
return in.addr; return in.addr;
} else if (opt == SO_REUSEADDR && exclusiveBind) {
// SO_REUSEADDR emulated when using exclusive bind
return isReuseAddress;
} else } else
return super.getOption(opt); return super.getOption(opt);
} }
@Override
void socketBind(InetAddress address, int port) throws IOException {
socketBind(address, port, exclusiveBind);
}
@Override
void socketSetOption(int opt, boolean on, Object value)
throws SocketException
{
// SO_REUSEADDR emulated when using exclusive bind
if (opt == SO_REUSEADDR && exclusiveBind)
isReuseAddress = on;
else
socketNativeSetOption(opt, on, value);
}
/** /**
* Closes the socket. * Closes the socket.
*/ */
@Override
protected void close() throws IOException { protected void close() throws IOException {
synchronized(fdLock) { synchronized(fdLock) {
if (fd != null || fd1 != null) { if (fd != null || fd1 != null) {
...@@ -155,6 +184,7 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -155,6 +184,7 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl
} }
} }
@Override
void reset() throws IOException { void reset() throws IOException {
if (fd != null || fd1 != null) { if (fd != null || fd1 != null) {
socketClose(); socketClose();
...@@ -167,6 +197,7 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -167,6 +197,7 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl
/* /*
* Return true if already closed or close is pending * Return true if already closed or close is pending
*/ */
@Override
public boolean isClosedOrPending() { public boolean isClosedOrPending() {
/* /*
* Lock on fdLock to ensure that we wait if a * Lock on fdLock to ensure that we wait if a
...@@ -190,7 +221,7 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -190,7 +221,7 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl
native void socketConnect(InetAddress address, int port, int timeout) native void socketConnect(InetAddress address, int port, int timeout)
throws IOException; throws IOException;
native void socketBind(InetAddress address, int port) native void socketBind(InetAddress address, int port, boolean exclBind)
throws IOException; throws IOException;
native void socketListen(int count) throws IOException; native void socketListen(int count) throws IOException;
...@@ -203,7 +234,7 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl ...@@ -203,7 +234,7 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl
native void socketShutdown(int howto) throws IOException; native void socketShutdown(int howto) throws IOException;
native void socketSetOption(int cmd, boolean on, Object value) native void socketNativeSetOption(int cmd, boolean on, Object value)
throws SocketException; throws SocketException;
native int socketGetOption(int opt, Object iaContainerObj) throws SocketException; native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
......
...@@ -113,7 +113,7 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketCrea ...@@ -113,7 +113,7 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketCrea
* Signature: (ILjava/net/InetAddress;I)V * Signature: (ILjava/net/InetAddress;I)V
*/ */
JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port, jboolean exclBind) {
SOCKETADDRESS sa; SOCKETADDRESS sa;
int rv; int rv;
int sa_len = sizeof(sa); int sa_len = sizeof(sa);
...@@ -122,8 +122,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind ...@@ -122,8 +122,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind
&sa_len, JNI_TRUE) != 0) { &sa_len, JNI_TRUE) != 0) {
return; return;
} }
rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind);
rv = bind(fd, (struct sockaddr *)&sa, sa_len);
if (rv == SOCKET_ERROR) { if (rv == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEACCES) { if (WSAGetLastError() == WSAEACCES) {
......
...@@ -82,7 +82,9 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0 ...@@ -82,7 +82,9 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
* Signature: (ILjava/net/InetAddress;I)V * Signature: (ILjava/net/InetAddress;I)V
*/ */
JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
jboolean exclBind)
{
SOCKETADDRESS sa; SOCKETADDRESS sa;
int rv; int rv;
int sa_len = sizeof(sa); int sa_len = sizeof(sa);
...@@ -92,7 +94,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0 ...@@ -92,7 +94,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
return; return;
} }
rv = NET_Bind(fd, (struct sockaddr *)&sa, sa_len); rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind);
if (rv == SOCKET_ERROR) if (rv == SOCKET_ERROR)
NET_ThrowNew(env, WSAGetLastError(), "JVM_Bind"); NET_ThrowNew(env, WSAGetLastError(), "JVM_Bind");
......
...@@ -421,7 +421,8 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) { ...@@ -421,7 +421,8 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this, Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
jint port, jobject addressObj) { jint port, jobject addressObj,
jboolean exclBind) {
jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID); jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
...@@ -464,7 +465,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this, ...@@ -464,7 +465,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
v6bind.addr = &lcladdr; v6bind.addr = &lcladdr;
v6bind.ipv4_fd = fd; v6bind.ipv4_fd = fd;
v6bind.ipv6_fd = fd1; v6bind.ipv6_fd = fd1;
if (NET_BindV6(&v6bind) != -1) { if (NET_BindV6(&v6bind, exclBind) != -1) {
/* check if the fds have changed */ /* check if the fds have changed */
if (v6bind.ipv4_fd != fd) { if (v6bind.ipv4_fd != fd) {
fd = v6bind.ipv4_fd; fd = v6bind.ipv4_fd;
...@@ -491,7 +492,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this, ...@@ -491,7 +492,7 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
return; return;
} }
} else { } else {
if (bind(fd, (struct sockaddr *)&lcladdr, lcladdrlen) == -1) { if (NET_WinBind(fd, (struct sockaddr *)&lcladdr, lcladdrlen, exclBind) == -1) {
if (WSAGetLastError() == WSAEACCES) { if (WSAGetLastError() == WSAEACCES) {
WSASetLastError(WSAEADDRINUSE); WSASetLastError(WSAEADDRINUSE);
} }
...@@ -1776,11 +1777,11 @@ static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, ...@@ -1776,11 +1777,11 @@ static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1,
/* /*
* Class: java_net_TwoStacksPlainDatagramSocketImpl * Class: java_net_TwoStacksPlainDatagramSocketImpl
* Method: socketSetOption * Method: socketNativeSetOption
* Signature: (ILjava/lang/Object;)V * Signature: (ILjava/lang/Object;)V
*/ */
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainDatagramSocketImpl_socketSetOption(JNIEnv *env,jobject this, Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption(JNIEnv *env,jobject this,
jint opt,jobject value) { jint opt,jobject value) {
int fd=-1, fd1=-1; int fd=-1, fd1=-1;
......
...@@ -394,7 +394,8 @@ Java_java_net_TwoStacksPlainSocketImpl_socketConnect(JNIEnv *env, jobject this, ...@@ -394,7 +394,8 @@ Java_java_net_TwoStacksPlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
*/ */
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this, Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this,
jobject iaObj, jint localport) { jobject iaObj, jint localport,
jboolean exclBind) {
/* fdObj is the FileDescriptor field on this */ /* fdObj is the FileDescriptor field on this */
jobject fdObj, fd1Obj; jobject fdObj, fd1Obj;
...@@ -438,13 +439,12 @@ Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this, ...@@ -438,13 +439,12 @@ Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this,
(struct sockaddr *)&him, &len, JNI_FALSE) != 0) { (struct sockaddr *)&him, &len, JNI_FALSE) != 0) {
return; return;
} }
if (ipv6_supported) { if (ipv6_supported) {
struct ipv6bind v6bind; struct ipv6bind v6bind;
v6bind.addr = &him; v6bind.addr = &him;
v6bind.ipv4_fd = fd; v6bind.ipv4_fd = fd;
v6bind.ipv6_fd = fd1; v6bind.ipv6_fd = fd1;
rv = NET_BindV6(&v6bind); rv = NET_BindV6(&v6bind, exclBind);
if (rv != -1) { if (rv != -1) {
/* check if the fds have changed */ /* check if the fds have changed */
if (v6bind.ipv4_fd != fd) { if (v6bind.ipv4_fd != fd) {
...@@ -469,7 +469,7 @@ Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this, ...@@ -469,7 +469,7 @@ Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this,
} }
} }
} else { } else {
rv = NET_Bind(fd, (struct sockaddr *)&him, len); rv = NET_WinBind(fd, (struct sockaddr *)&him, len, exclBind);
} }
if (rv == -1) { if (rv == -1) {
...@@ -835,11 +835,12 @@ Java_java_net_TwoStacksPlainSocketImpl_socketClose0(JNIEnv *env, jobject this, ...@@ -835,11 +835,12 @@ Java_java_net_TwoStacksPlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
* *
* *
* Class: java_net_TwoStacksPlainSocketImpl * Class: java_net_TwoStacksPlainSocketImpl
* Method: socketSetOption * Method: socketNativeSetOption
* Signature: (IZLjava/lang/Object;)V * Signature: (IZLjava/lang/Object;)V
*/ */
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_java_net_TwoStacksPlainSocketImpl_socketSetOption(JNIEnv *env, jobject this, Java_java_net_TwoStacksPlainSocketImpl_socketNativeSetOption(JNIEnv *env,
jobject this,
jint cmd, jboolean on, jint cmd, jboolean on,
jobject value) { jobject value) {
int fd, fd1; int fd, fd1;
......
...@@ -387,12 +387,24 @@ NET_SetSockOpt(int s, int level, int optname, const void *optval, ...@@ -387,12 +387,24 @@ NET_SetSockOpt(int s, int level, int optname, const void *optval,
int optlen) int optlen)
{ {
int rv; int rv;
int parg;
int plen = sizeof(parg);
if (level == IPPROTO_IP && optname == IP_TOS) { if (level == IPPROTO_IP && optname == IP_TOS) {
int *tos = (int *)optval; int *tos = (int *)optval;
*tos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK); *tos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
} }
if (optname == SO_REUSEADDR) {
/*
* Do not set SO_REUSEADDE if SO_EXCLUSIVEADDUSE is already set
*/
rv = NET_GetSockOpt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&parg, &plen);
if (rv == 0 && parg == 1) {
return rv;
}
}
rv = setsockopt(s, level, optname, optval, optlen); rv = setsockopt(s, level, optname, optval, optlen);
if (rv == SOCKET_ERROR) { if (rv == SOCKET_ERROR) {
...@@ -455,16 +467,33 @@ NET_GetSockOpt(int s, int level, int optname, void *optval, ...@@ -455,16 +467,33 @@ NET_GetSockOpt(int s, int level, int optname, void *optval,
return rv; return rv;
} }
/*
* Sets SO_ECLUSIVEADDRUSE if SO_REUSEADDR is not already set.
*/
void setExclusiveBind(int fd) {
int parg;
int plen = sizeof(parg);
int rv = 0;
rv = NET_GetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&parg, &plen);
if (rv == 0 && parg == 0) {
parg = 1;
rv = NET_SetSockOpt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char*)&parg, plen);
}
}
/* /*
* Wrapper for bind winsock call - transparent converts an * Wrapper for bind winsock call - transparent converts an
* error related to binding to a port that has exclusive access * error related to binding to a port that has exclusive access
* into an error indicating the port is in use (facilitates * into an error indicating the port is in use (facilitates
* better error reporting). * better error reporting).
*
* Should be only called by the wrapper method NET_WinBind
*/ */
JNIEXPORT int JNICALL JNIEXPORT int JNICALL
NET_Bind(int s, struct sockaddr *him, int len) NET_Bind(int s, struct sockaddr *him, int len)
{ {
int rv = bind(s, him, len); int rv;
rv = bind(s, him, len);
if (rv == SOCKET_ERROR) { if (rv == SOCKET_ERROR) {
/* /*
...@@ -479,6 +508,18 @@ NET_Bind(int s, struct sockaddr *him, int len) ...@@ -479,6 +508,18 @@ NET_Bind(int s, struct sockaddr *him, int len)
return rv; return rv;
} }
/*
* Wrapper for NET_Bind call. Sets SO_EXCLUSIVEADDRUSE
* if required, and then calls NET_BIND
*/
JNIEXPORT int JNICALL
NET_WinBind(int s, struct sockaddr *him, int len, jboolean exclBind)
{
if (exclBind == JNI_TRUE)
setExclusiveBind(s);
return NET_Bind(s, him, len);
}
JNIEXPORT int JNICALL JNIEXPORT int JNICALL
NET_SocketClose(int fd) { NET_SocketClose(int fd) {
struct linger l; struct linger l;
...@@ -625,7 +666,7 @@ void dumpAddr (char *str, void *addr) { ...@@ -625,7 +666,7 @@ void dumpAddr (char *str, void *addr) {
*/ */
JNIEXPORT int JNICALL JNIEXPORT int JNICALL
NET_BindV6(struct ipv6bind* b) { NET_BindV6(struct ipv6bind* b, jboolean exclBind) {
int fd=-1, ofd=-1, rv, len; int fd=-1, ofd=-1, rv, len;
/* need to defer close until new sockets created */ /* need to defer close until new sockets created */
int close_fd=-1, close_ofd=-1; int close_fd=-1, close_ofd=-1;
...@@ -638,8 +679,8 @@ NET_BindV6(struct ipv6bind* b) { ...@@ -638,8 +679,8 @@ NET_BindV6(struct ipv6bind* b) {
if (family == AF_INET && (b->addr->him4.sin_addr.s_addr != INADDR_ANY)) { if (family == AF_INET && (b->addr->him4.sin_addr.s_addr != INADDR_ANY)) {
/* bind to v4 only */ /* bind to v4 only */
int ret; int ret;
ret = NET_Bind ((int)b->ipv4_fd, (struct sockaddr *)b->addr, ret = NET_WinBind ((int)b->ipv4_fd, (struct sockaddr *)b->addr,
sizeof (struct sockaddr_in)); sizeof (struct sockaddr_in), exclBind);
if (ret == SOCKET_ERROR) { if (ret == SOCKET_ERROR) {
CLOSE_SOCKETS_AND_RETURN; CLOSE_SOCKETS_AND_RETURN;
} }
...@@ -650,8 +691,8 @@ NET_BindV6(struct ipv6bind* b) { ...@@ -650,8 +691,8 @@ NET_BindV6(struct ipv6bind* b) {
if (family == AF_INET6 && (!IN6_IS_ADDR_ANY(&b->addr->him6.sin6_addr))) { if (family == AF_INET6 && (!IN6_IS_ADDR_ANY(&b->addr->him6.sin6_addr))) {
/* bind to v6 only */ /* bind to v6 only */
int ret; int ret;
ret = NET_Bind ((int)b->ipv6_fd, (struct sockaddr *)b->addr, ret = NET_WinBind ((int)b->ipv6_fd, (struct sockaddr *)b->addr,
sizeof (struct SOCKADDR_IN6)); sizeof (struct SOCKADDR_IN6), exclBind);
if (ret == SOCKET_ERROR) { if (ret == SOCKET_ERROR) {
CLOSE_SOCKETS_AND_RETURN; CLOSE_SOCKETS_AND_RETURN;
} }
...@@ -680,7 +721,7 @@ NET_BindV6(struct ipv6bind* b) { ...@@ -680,7 +721,7 @@ NET_BindV6(struct ipv6bind* b) {
oaddr.him4.sin_addr.s_addr = INADDR_ANY; oaddr.him4.sin_addr.s_addr = INADDR_ANY;
} }
rv = NET_Bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr)); rv = NET_WinBind(fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr), exclBind);
if (rv == SOCKET_ERROR) { if (rv == SOCKET_ERROR) {
CLOSE_SOCKETS_AND_RETURN; CLOSE_SOCKETS_AND_RETURN;
} }
...@@ -692,8 +733,8 @@ NET_BindV6(struct ipv6bind* b) { ...@@ -692,8 +733,8 @@ NET_BindV6(struct ipv6bind* b) {
} }
bound_port = GET_PORT (b->addr); bound_port = GET_PORT (b->addr);
SET_PORT (&oaddr, bound_port); SET_PORT (&oaddr, bound_port);
if ((rv=NET_Bind (ofd, (struct sockaddr *) &oaddr, if ((rv=NET_WinBind (ofd, (struct sockaddr *) &oaddr,
SOCKETADDRESS_LEN (&oaddr))) == SOCKET_ERROR) { SOCKETADDRESS_LEN (&oaddr), exclBind)) == SOCKET_ERROR) {
int retries; int retries;
int sotype, arglen=sizeof(sotype); int sotype, arglen=sizeof(sotype);
...@@ -729,7 +770,8 @@ NET_BindV6(struct ipv6bind* b) { ...@@ -729,7 +770,8 @@ NET_BindV6(struct ipv6bind* b) {
/* bind random port on first socket */ /* bind random port on first socket */
SET_PORT (&oaddr, 0); SET_PORT (&oaddr, 0);
rv = NET_Bind (ofd, (struct sockaddr *)&oaddr, SOCKETADDRESS_LEN(&oaddr)); rv = NET_WinBind (ofd, (struct sockaddr *)&oaddr, SOCKETADDRESS_LEN(&oaddr),
exclBind);
if (rv == SOCKET_ERROR) { if (rv == SOCKET_ERROR) {
CLOSE_SOCKETS_AND_RETURN; CLOSE_SOCKETS_AND_RETURN;
} }
...@@ -745,7 +787,8 @@ NET_BindV6(struct ipv6bind* b) { ...@@ -745,7 +787,8 @@ NET_BindV6(struct ipv6bind* b) {
} }
bound_port = GET_PORT (&oaddr); bound_port = GET_PORT (&oaddr);
SET_PORT (b->addr, bound_port); SET_PORT (b->addr, bound_port);
rv = NET_Bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr)); rv = NET_WinBind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr),
exclBind);
if (rv != SOCKET_ERROR) { if (rv != SOCKET_ERROR) {
if (family == AF_INET) { if (family == AF_INET) {
......
...@@ -311,7 +311,7 @@ void NET_ThrowSocketException(JNIEnv *env, char* msg); ...@@ -311,7 +311,7 @@ void NET_ThrowSocketException(JNIEnv *env, char* msg);
*/ */
JNIEXPORT int JNICALL NET_Timeout2(int fd, int fd1, long timeout, int *fdret); JNIEXPORT int JNICALL NET_Timeout2(int fd, int fd1, long timeout, int *fdret);
JNIEXPORT int JNICALL NET_BindV6(struct ipv6bind* b); JNIEXPORT int JNICALL NET_BindV6(struct ipv6bind* b, jboolean exclBind);
#define NET_WAIT_READ 0x01 #define NET_WAIT_READ 0x01
#define NET_WAIT_WRITE 0x02 #define NET_WAIT_WRITE 0x02
...@@ -319,6 +319,9 @@ JNIEXPORT int JNICALL NET_BindV6(struct ipv6bind* b); ...@@ -319,6 +319,9 @@ JNIEXPORT int JNICALL NET_BindV6(struct ipv6bind* b);
extern jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout); extern jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout);
JNIEXPORT int JNICALL NET_WinBind(int s, struct sockaddr *him, int len,
jboolean exclBind);
/* XP versions of the native routines */ /* XP versions of the native routines */
JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP
......
...@@ -101,6 +101,18 @@ Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) ...@@ -101,6 +101,18 @@ Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
return JNI_FALSE; return JNI_FALSE;
} }
JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
OSVERSIONINFO ver;
int version;
ver.dwOSVersionInfoSize = sizeof(ver);
GetVersionEx(&ver);
version = ver.dwMajorVersion * 10 + ver.dwMinorVersion;
//if os <= xp exclusive binding is off by default
return version >= 60 ? 1 : 0;
}
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
{ {
...@@ -144,8 +156,8 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, ...@@ -144,8 +156,8 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,
jobject fdo, jobject iao, jint port) jboolean isExclBind, jobject iao, jint port)
{ {
SOCKETADDRESS sa; SOCKETADDRESS sa;
int rv; int rv;
...@@ -155,7 +167,7 @@ Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, ...@@ -155,7 +167,7 @@ Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
return; return;
} }
rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); rv = NET_WinBind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len, isExclBind);
if (rv == SOCKET_ERROR) if (rv == SOCKET_ERROR)
NET_ThrowNew(env, WSAGetLastError(), "bind"); NET_ThrowNew(env, WSAGetLastError(), "bind");
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册