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