8241072: Reimplement the Legacy DatagramSocket API
Replace the underlying implementations of the java.net.DatagramSocket and java.net.MulticastSocket APIs with simpler and more modern implementations that are easy to maintain and debug. Co-authored-by: Alan Bateman <alan.bateman@oracle.com> Co-authored-by: Chris Hegarty <chris.hegarty@oracle.com> Co-authored-by: Daniel Fuchs <daniel.fuchs@oracle.com> Reviewed-by: alanb, chegar, dfuchs
This commit is contained in:
parent
3930460af5
commit
fad2cf51ba
@ -29,10 +29,10 @@ import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Objects;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Set;
|
||||
import java.util.Collections;
|
||||
import sun.net.NetProperties;
|
||||
import sun.nio.ch.DefaultSelectorProvider;
|
||||
|
||||
/**
|
||||
* This class represents a socket for sending and receiving datagram packets.
|
||||
@ -113,117 +113,27 @@ import java.util.Collections;
|
||||
* @since 1.0
|
||||
*/
|
||||
public class DatagramSocket implements java.io.Closeable {
|
||||
/**
|
||||
* Various states of this socket.
|
||||
*/
|
||||
private boolean bound = false;
|
||||
private boolean closed = false;
|
||||
private volatile boolean created;
|
||||
private final Object closeLock = new Object();
|
||||
|
||||
/*
|
||||
* The implementation of this DatagramSocket.
|
||||
*/
|
||||
private final DatagramSocketImpl impl;
|
||||
// An instance of DatagramSocketAdaptor, NetMulticastSocket, or null
|
||||
private final DatagramSocket delegate;
|
||||
|
||||
/**
|
||||
* Are we using an older DatagramSocketImpl?
|
||||
*/
|
||||
final boolean oldImpl;
|
||||
|
||||
/**
|
||||
* Set when a socket is ST_CONNECTED until we are certain
|
||||
* that any packets which might have been received prior
|
||||
* to calling connect() but not read by the application
|
||||
* have been read. During this time we check the source
|
||||
* address of all packets received to be sure they are from
|
||||
* the connected destination. Other packets are read but
|
||||
* silently dropped.
|
||||
*/
|
||||
private boolean explicitFilter = false;
|
||||
private int bytesLeftToFilter;
|
||||
/*
|
||||
* Connection state:
|
||||
* ST_NOT_CONNECTED = socket not connected
|
||||
* ST_CONNECTED = socket connected
|
||||
* ST_CONNECTED_NO_IMPL = socket connected but not at impl level
|
||||
*/
|
||||
static final int ST_NOT_CONNECTED = 0;
|
||||
static final int ST_CONNECTED = 1;
|
||||
static final int ST_CONNECTED_NO_IMPL = 2;
|
||||
|
||||
int connectState = ST_NOT_CONNECTED;
|
||||
|
||||
/*
|
||||
* Connected address & port
|
||||
*/
|
||||
InetAddress connectedAddress = null;
|
||||
int connectedPort = -1;
|
||||
|
||||
/**
|
||||
* Connects this socket to a remote socket address (IP address + port number).
|
||||
* Binds socket if not already bound.
|
||||
*
|
||||
* @param address The remote address.
|
||||
* @param port The remote port
|
||||
* @throws SocketException if binding the socket fails.
|
||||
*/
|
||||
private synchronized void connectInternal(InetAddress address, int port) throws SocketException {
|
||||
if (port < 0 || port > 0xFFFF) {
|
||||
throw new IllegalArgumentException("connect: " + port);
|
||||
DatagramSocket delegate() {
|
||||
if (delegate == null) {
|
||||
throw new InternalError("Should not get here");
|
||||
}
|
||||
if (address == null) {
|
||||
throw new IllegalArgumentException("connect: null address");
|
||||
}
|
||||
checkAddress (address, "connect");
|
||||
if (isClosed())
|
||||
return;
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
if (address.isMulticastAddress()) {
|
||||
security.checkMulticast(address);
|
||||
} else {
|
||||
security.checkConnect(address.getHostAddress(), port);
|
||||
security.checkAccept(address.getHostAddress(), port);
|
||||
}
|
||||
}
|
||||
|
||||
if (port == 0) {
|
||||
throw new SocketException("Can't connect to port 0");
|
||||
}
|
||||
if (!isBound())
|
||||
bind(new InetSocketAddress(0));
|
||||
|
||||
// old impls do not support connect/disconnect
|
||||
if (oldImpl || (impl instanceof AbstractPlainDatagramSocketImpl &&
|
||||
((AbstractPlainDatagramSocketImpl)impl).nativeConnectDisabled())) {
|
||||
connectState = ST_CONNECTED_NO_IMPL;
|
||||
} else {
|
||||
try {
|
||||
getImpl().connect(address, port);
|
||||
|
||||
// socket is now connected by the impl
|
||||
connectState = ST_CONNECTED;
|
||||
// Do we need to filter some packets?
|
||||
int avail = getImpl().dataAvailable();
|
||||
if (avail == -1) {
|
||||
throw new SocketException();
|
||||
}
|
||||
explicitFilter = avail > 0;
|
||||
if (explicitFilter) {
|
||||
bytesLeftToFilter = getReceiveBufferSize();
|
||||
}
|
||||
} catch (SocketException se) {
|
||||
|
||||
// connection will be emulated by DatagramSocket
|
||||
connectState = ST_CONNECTED_NO_IMPL;
|
||||
}
|
||||
}
|
||||
|
||||
connectedAddress = address;
|
||||
connectedPort = port;
|
||||
return delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* All constructors eventually call this one.
|
||||
* @param delegate The wrapped DatagramSocket implementation, or null.
|
||||
*/
|
||||
DatagramSocket(DatagramSocket delegate) {
|
||||
assert delegate == null
|
||||
|| delegate instanceof NetMulticastSocket
|
||||
|| delegate instanceof sun.nio.ch.DatagramSocketAdaptor;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a datagram socket and binds it to any available port
|
||||
@ -256,10 +166,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
*/
|
||||
protected DatagramSocket(DatagramSocketImpl impl) {
|
||||
if (impl == null)
|
||||
throw new NullPointerException();
|
||||
this.impl = impl;
|
||||
this.oldImpl = checkOldImpl(impl);
|
||||
this(new NetMulticastSocket(impl));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -286,28 +193,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
*/
|
||||
public DatagramSocket(SocketAddress bindaddr) throws SocketException {
|
||||
// Special case initialization for the DatagramChannel socket adaptor.
|
||||
if (this instanceof sun.nio.ch.DatagramSocketAdaptor) {
|
||||
this.impl = null; // no DatagramSocketImpl
|
||||
this.oldImpl = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// create a datagram socket.
|
||||
boolean multicast = (this instanceof MulticastSocket);
|
||||
this.impl = createImpl(multicast);
|
||||
// creates the udp socket
|
||||
impl.create();
|
||||
created = true;
|
||||
this.oldImpl = checkOldImpl(impl);
|
||||
if (bindaddr != null) {
|
||||
try {
|
||||
bind(bindaddr);
|
||||
} finally {
|
||||
if (!isBound())
|
||||
close();
|
||||
}
|
||||
}
|
||||
this(createDelegate(bindaddr, DatagramSocket.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -362,67 +248,6 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
this(new InetSocketAddress(laddr, port));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given DatagramSocketImpl is an "old" impl. An old impl
|
||||
* is one that doesn't implement the abstract methods added in Java SE 1.4.
|
||||
*/
|
||||
private static boolean checkOldImpl(DatagramSocketImpl impl) {
|
||||
// DatagramSocketImpl.peekData() is a protected method, therefore we need to use
|
||||
// getDeclaredMethod, therefore we need permission to access the member
|
||||
try {
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<>() {
|
||||
public Void run() throws NoSuchMethodException {
|
||||
Class<?>[] cl = new Class<?>[1];
|
||||
cl[0] = DatagramPacket.class;
|
||||
impl.getClass().getDeclaredMethod("peekData", cl);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
} catch (java.security.PrivilegedActionException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static Class<?> implClass = null;
|
||||
|
||||
/**
|
||||
* Creates a DatagramSocketImpl.
|
||||
* @param multicast true if the DatagramSocketImpl is for a MulticastSocket
|
||||
*/
|
||||
private static DatagramSocketImpl createImpl(boolean multicast) throws SocketException {
|
||||
DatagramSocketImpl impl;
|
||||
DatagramSocketImplFactory factory = DatagramSocket.factory;
|
||||
if (factory != null) {
|
||||
impl = factory.createDatagramSocketImpl();
|
||||
} else {
|
||||
impl = DefaultDatagramSocketImplFactory.createDatagramSocketImpl(multicast);
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code DatagramSocketImpl} attached to this socket,
|
||||
* creating the socket if not already created.
|
||||
*
|
||||
* @return the {@code DatagramSocketImpl} attached to that
|
||||
* DatagramSocket
|
||||
* @throws SocketException if creating the socket fails
|
||||
* @since 1.4
|
||||
*/
|
||||
final DatagramSocketImpl getImpl() throws SocketException {
|
||||
if (!created) {
|
||||
synchronized (this) {
|
||||
if (!created) {
|
||||
impl.create();
|
||||
created = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds this DatagramSocket to a specific address and port.
|
||||
* <p>
|
||||
@ -438,41 +263,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* not supported by this socket.
|
||||
* @since 1.4
|
||||
*/
|
||||
public synchronized void bind(SocketAddress addr) throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
if (isBound())
|
||||
throw new SocketException("already bound");
|
||||
if (addr == null)
|
||||
addr = new InetSocketAddress(0);
|
||||
if (!(addr instanceof InetSocketAddress))
|
||||
throw new IllegalArgumentException("Unsupported address type!");
|
||||
InetSocketAddress epoint = (InetSocketAddress) addr;
|
||||
if (epoint.isUnresolved())
|
||||
throw new SocketException("Unresolved address");
|
||||
InetAddress iaddr = epoint.getAddress();
|
||||
int port = epoint.getPort();
|
||||
checkAddress(iaddr, "bind");
|
||||
SecurityManager sec = System.getSecurityManager();
|
||||
if (sec != null) {
|
||||
sec.checkListen(port);
|
||||
}
|
||||
try {
|
||||
getImpl().bind(port, iaddr);
|
||||
} catch (SocketException e) {
|
||||
getImpl().close();
|
||||
throw e;
|
||||
}
|
||||
bound = true;
|
||||
}
|
||||
|
||||
void checkAddress (InetAddress addr, String op) {
|
||||
if (addr == null) {
|
||||
return;
|
||||
}
|
||||
if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
|
||||
throw new IllegalArgumentException(op + ": invalid address type");
|
||||
}
|
||||
public void bind(SocketAddress addr) throws SocketException {
|
||||
delegate().bind(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -534,11 +326,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.2
|
||||
*/
|
||||
public void connect(InetAddress address, int port) {
|
||||
try {
|
||||
connectInternal(address, port);
|
||||
} catch (SocketException se) {
|
||||
throw new UncheckedIOException("connect failed", se);
|
||||
}
|
||||
delegate().connect(address, port);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -566,14 +354,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
*/
|
||||
public void connect(SocketAddress addr) throws SocketException {
|
||||
if (addr == null)
|
||||
throw new IllegalArgumentException("Address can't be null");
|
||||
if (!(addr instanceof InetSocketAddress))
|
||||
throw new IllegalArgumentException("Unsupported address type");
|
||||
InetSocketAddress epoint = (InetSocketAddress) addr;
|
||||
if (epoint.isUnresolved())
|
||||
throw new SocketException("Unresolved address");
|
||||
connectInternal(epoint.getAddress(), epoint.getPort());
|
||||
delegate().connect(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -594,17 +375,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.2
|
||||
*/
|
||||
public void disconnect() {
|
||||
synchronized (this) {
|
||||
if (isClosed())
|
||||
return;
|
||||
if (connectState == ST_CONNECTED) {
|
||||
impl.disconnect ();
|
||||
}
|
||||
connectedAddress = null;
|
||||
connectedPort = -1;
|
||||
connectState = ST_NOT_CONNECTED;
|
||||
explicitFilter = false;
|
||||
}
|
||||
delegate().disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -618,7 +389,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean isBound() {
|
||||
return bound;
|
||||
return delegate().isBound();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -632,7 +403,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean isConnected() {
|
||||
return connectState != ST_NOT_CONNECTED;
|
||||
return delegate().isConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -647,7 +418,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.2
|
||||
*/
|
||||
public InetAddress getInetAddress() {
|
||||
return connectedAddress;
|
||||
return delegate().getInetAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -662,7 +433,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.2
|
||||
*/
|
||||
public int getPort() {
|
||||
return connectedPort;
|
||||
return delegate().getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -682,9 +453,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
*/
|
||||
public SocketAddress getRemoteSocketAddress() {
|
||||
if (!isConnected())
|
||||
return null;
|
||||
return new InetSocketAddress(getInetAddress(), getPort());
|
||||
return delegate().getRemoteSocketAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -698,11 +467,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
*/
|
||||
public SocketAddress getLocalSocketAddress() {
|
||||
if (isClosed())
|
||||
return null;
|
||||
if (!isBound())
|
||||
return null;
|
||||
return new InetSocketAddress(getLocalAddress(), getLocalPort());
|
||||
return delegate().getLocalSocketAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -748,54 +513,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @spec JSR-51
|
||||
*/
|
||||
public void send(DatagramPacket p) throws IOException {
|
||||
synchronized (p) {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
InetAddress packetAddress = p.getAddress();
|
||||
int packetPort = p.getPort();
|
||||
checkAddress (packetAddress, "send");
|
||||
if (connectState == ST_NOT_CONNECTED) {
|
||||
if (packetAddress == null) {
|
||||
throw new IllegalArgumentException("Address not set");
|
||||
}
|
||||
if (packetPort < 0 || packetPort > 0xFFFF)
|
||||
throw new IllegalArgumentException("port out of range:" + packetPort);
|
||||
// check the address is ok with the security manager on every send.
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
|
||||
// The reason you want to synchronize on datagram packet
|
||||
// is because you don't want an applet to change the address
|
||||
// while you are trying to send the packet for example
|
||||
// after the security check but before the send.
|
||||
if (security != null) {
|
||||
if (packetAddress.isMulticastAddress()) {
|
||||
security.checkMulticast(packetAddress);
|
||||
} else {
|
||||
security.checkConnect(packetAddress.getHostAddress(),
|
||||
packetPort);
|
||||
}
|
||||
}
|
||||
if (packetPort == 0) {
|
||||
throw new SocketException("Can't send to port 0");
|
||||
}
|
||||
} else {
|
||||
// we're connected
|
||||
if (packetAddress == null) {
|
||||
p.setAddress(connectedAddress);
|
||||
p.setPort(connectedPort);
|
||||
} else if ((!packetAddress.equals(connectedAddress)) ||
|
||||
packetPort != connectedPort) {
|
||||
throw new IllegalArgumentException("connected address " +
|
||||
"and packet address" +
|
||||
" differ");
|
||||
}
|
||||
}
|
||||
// Check whether the socket is bound
|
||||
if (!isBound())
|
||||
bind(new InetSocketAddress(0));
|
||||
// call the method to send
|
||||
getImpl().send(p);
|
||||
}
|
||||
delegate().send(p);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -831,105 +549,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @revised 1.4
|
||||
* @spec JSR-51
|
||||
*/
|
||||
public synchronized void receive(DatagramPacket p) throws IOException {
|
||||
synchronized (p) {
|
||||
if (!isBound())
|
||||
bind(new InetSocketAddress(0));
|
||||
if (connectState == ST_NOT_CONNECTED) {
|
||||
// check the address is ok with the security manager before every recv.
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
while(true) {
|
||||
String peekAd = null;
|
||||
int peekPort = 0;
|
||||
// peek at the packet to see who it is from.
|
||||
if (!oldImpl) {
|
||||
// We can use the new peekData() API
|
||||
DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
|
||||
peekPort = getImpl().peekData(peekPacket);
|
||||
peekAd = peekPacket.getAddress().getHostAddress();
|
||||
} else {
|
||||
InetAddress adr = new InetAddress();
|
||||
peekPort = getImpl().peek(adr);
|
||||
peekAd = adr.getHostAddress();
|
||||
}
|
||||
try {
|
||||
security.checkAccept(peekAd, peekPort);
|
||||
// security check succeeded - so now break
|
||||
// and recv the packet.
|
||||
break;
|
||||
} catch (SecurityException se) {
|
||||
// Throw away the offending packet by consuming
|
||||
// it in a tmp buffer.
|
||||
DatagramPacket tmp = new DatagramPacket(new byte[1], 1);
|
||||
getImpl().receive(tmp);
|
||||
|
||||
// silently discard the offending packet
|
||||
// and continue: unknown/malicious
|
||||
// entities on nets should not make
|
||||
// runtime throw security exception and
|
||||
// disrupt the applet by sending random
|
||||
// datagram packets.
|
||||
continue;
|
||||
}
|
||||
} // end of while
|
||||
}
|
||||
}
|
||||
DatagramPacket tmp = null;
|
||||
if ((connectState == ST_CONNECTED_NO_IMPL) || explicitFilter) {
|
||||
// We have to do the filtering the old fashioned way since
|
||||
// the native impl doesn't support connect or the connect
|
||||
// via the impl failed, or .. "explicitFilter" may be set when
|
||||
// a socket is connected via the impl, for a period of time
|
||||
// when packets from other sources might be queued on socket.
|
||||
boolean stop = false;
|
||||
while (!stop) {
|
||||
InetAddress peekAddress = null;
|
||||
int peekPort = -1;
|
||||
// peek at the packet to see who it is from.
|
||||
if (!oldImpl) {
|
||||
// We can use the new peekData() API
|
||||
DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
|
||||
peekPort = getImpl().peekData(peekPacket);
|
||||
peekAddress = peekPacket.getAddress();
|
||||
} else {
|
||||
// this api only works for IPv4
|
||||
peekAddress = new InetAddress();
|
||||
peekPort = getImpl().peek(peekAddress);
|
||||
}
|
||||
if ((!connectedAddress.equals(peekAddress)) ||
|
||||
(connectedPort != peekPort)) {
|
||||
// throw the packet away and silently continue
|
||||
tmp = new DatagramPacket(
|
||||
new byte[1024], 1024);
|
||||
getImpl().receive(tmp);
|
||||
if (explicitFilter) {
|
||||
if (checkFiltering(tmp)) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the security check succeeds, or the datagram is
|
||||
// connected then receive the packet
|
||||
getImpl().receive(p);
|
||||
if (explicitFilter && tmp == null) {
|
||||
// packet was not filtered, account for it here
|
||||
checkFiltering(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkFiltering(DatagramPacket p) throws SocketException {
|
||||
bytesLeftToFilter -= p.getLength();
|
||||
if (bytesLeftToFilter <= 0 || getImpl().dataAvailable() <= 0) {
|
||||
explicitFilter = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
public void receive(DatagramPacket p) throws IOException {
|
||||
delegate().receive(p);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -951,22 +572,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.1
|
||||
*/
|
||||
public InetAddress getLocalAddress() {
|
||||
if (isClosed())
|
||||
return null;
|
||||
InetAddress in;
|
||||
try {
|
||||
in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
|
||||
if (in.isAnyLocalAddress()) {
|
||||
in = InetAddress.anyLocalAddress();
|
||||
}
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
if (s != null) {
|
||||
s.checkConnect(in.getHostAddress(), -1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
in = InetAddress.anyLocalAddress(); // "0.0.0.0"
|
||||
}
|
||||
return in;
|
||||
return delegate().getLocalAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -978,13 +584,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* {@code 0} if it is not bound yet.
|
||||
*/
|
||||
public int getLocalPort() {
|
||||
if (isClosed())
|
||||
return -1;
|
||||
try {
|
||||
return getImpl().getLocalPort();
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
return delegate().getLocalPort();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1004,12 +604,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.1
|
||||
* @see #getSoTimeout()
|
||||
*/
|
||||
public synchronized void setSoTimeout(int timeout) throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("timeout < 0");
|
||||
getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout);
|
||||
public void setSoTimeout(int timeout) throws SocketException {
|
||||
delegate().setSoTimeout(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1021,18 +617,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.1
|
||||
* @see #setSoTimeout(int)
|
||||
*/
|
||||
public synchronized int getSoTimeout() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
if (getImpl() == null)
|
||||
return 0;
|
||||
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
|
||||
/* extra type safety */
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o).intValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
public int getSoTimeout() throws SocketException {
|
||||
return delegate().getSoTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1065,13 +651,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @see #getSendBufferSize()
|
||||
* @since 1.2
|
||||
*/
|
||||
public synchronized void setSendBufferSize(int size) throws SocketException {
|
||||
if (!(size > 0)) {
|
||||
throw new IllegalArgumentException("negative send size");
|
||||
}
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.SO_SNDBUF, size);
|
||||
public void setSendBufferSize(int size) throws SocketException {
|
||||
delegate().setSendBufferSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1084,15 +665,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @see #setSendBufferSize
|
||||
* @since 1.2
|
||||
*/
|
||||
public synchronized int getSendBufferSize() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
int result = 0;
|
||||
Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
|
||||
if (o instanceof Integer) {
|
||||
result = ((Integer)o).intValue();
|
||||
}
|
||||
return result;
|
||||
public int getSendBufferSize() throws SocketException {
|
||||
return delegate().getSendBufferSize();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1124,13 +698,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @see #getReceiveBufferSize()
|
||||
* @since 1.2
|
||||
*/
|
||||
public synchronized void setReceiveBufferSize(int size) throws SocketException {
|
||||
if (size <= 0) {
|
||||
throw new IllegalArgumentException("invalid receive size");
|
||||
}
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.SO_RCVBUF, size);
|
||||
public void setReceiveBufferSize(int size) throws SocketException {
|
||||
delegate().setReceiveBufferSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1142,15 +711,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @see #setReceiveBufferSize(int)
|
||||
* @since 1.2
|
||||
*/
|
||||
public synchronized int getReceiveBufferSize() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
int result = 0;
|
||||
Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
|
||||
if (o instanceof Integer) {
|
||||
result = ((Integer)o).intValue();
|
||||
}
|
||||
return result;
|
||||
public int getReceiveBufferSize() throws SocketException {
|
||||
return delegate().getReceiveBufferSize();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1187,14 +749,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @see #isBound()
|
||||
* @see #isClosed()
|
||||
*/
|
||||
public synchronized void setReuseAddress(boolean on) throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
// Integer instead of Boolean for compatibility with older DatagramSocketImpl
|
||||
if (oldImpl)
|
||||
getImpl().setOption(SocketOptions.SO_REUSEADDR, on?-1:0);
|
||||
else
|
||||
getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
|
||||
public void setReuseAddress(boolean on) throws SocketException {
|
||||
delegate().setReuseAddress(on);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1206,11 +762,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
* @see #setReuseAddress(boolean)
|
||||
*/
|
||||
public synchronized boolean getReuseAddress() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR);
|
||||
return ((Boolean)o).booleanValue();
|
||||
public boolean getReuseAddress() throws SocketException {
|
||||
return delegate().getReuseAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1230,10 +783,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
* @see #getBroadcast()
|
||||
*/
|
||||
public synchronized void setBroadcast(boolean on) throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on));
|
||||
public void setBroadcast(boolean on) throws SocketException {
|
||||
delegate().setBroadcast(on);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1244,10 +795,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
* @see #setBroadcast(boolean)
|
||||
*/
|
||||
public synchronized boolean getBroadcast() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
return ((Boolean)(getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue();
|
||||
public boolean getBroadcast() throws SocketException {
|
||||
return delegate().getBroadcast();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1287,20 +836,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
* @see #getTrafficClass
|
||||
*/
|
||||
public synchronized void setTrafficClass(int tc) throws SocketException {
|
||||
if (tc < 0 || tc > 255)
|
||||
throw new IllegalArgumentException("tc is not in range 0 -- 255");
|
||||
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
try {
|
||||
getImpl().setOption(SocketOptions.IP_TOS, tc);
|
||||
} catch (SocketException se) {
|
||||
// not supported if socket already connected
|
||||
// Solaris returns error in such cases
|
||||
if(!isConnected())
|
||||
throw se;
|
||||
}
|
||||
public void setTrafficClass(int tc) throws SocketException {
|
||||
delegate().setTrafficClass(tc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1319,10 +856,8 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
* @see #setTrafficClass(int)
|
||||
*/
|
||||
public synchronized int getTrafficClass() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
return ((Integer)(getImpl().getOption(SocketOptions.IP_TOS))).intValue();
|
||||
public int getTrafficClass() throws SocketException {
|
||||
return delegate().getTrafficClass();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1338,12 +873,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @spec JSR-51
|
||||
*/
|
||||
public void close() {
|
||||
synchronized(closeLock) {
|
||||
if (isClosed())
|
||||
return;
|
||||
impl.close();
|
||||
closed = true;
|
||||
}
|
||||
delegate().close();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1353,9 +883,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean isClosed() {
|
||||
synchronized(closeLock) {
|
||||
return closed;
|
||||
}
|
||||
return delegate().isClosed();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1409,7 +937,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
*/
|
||||
public static synchronized void
|
||||
setDatagramSocketImplFactory(DatagramSocketImplFactory fac)
|
||||
throws IOException
|
||||
throws IOException
|
||||
{
|
||||
if (factory != null) {
|
||||
throw new SocketException("factory already defined");
|
||||
@ -1452,10 +980,7 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
public <T> DatagramSocket setOption(SocketOption<T> name, T value)
|
||||
throws IOException
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(name, value);
|
||||
delegate().setOption(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1483,15 +1008,9 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 9
|
||||
*/
|
||||
public <T> T getOption(SocketOption<T> name) throws IOException {
|
||||
Objects.requireNonNull(name);
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
return getImpl().getOption(name);
|
||||
return delegate().getOption(name);
|
||||
}
|
||||
|
||||
private volatile Set<SocketOption<?>> options;
|
||||
private final Object optionsLock = new Object();
|
||||
|
||||
/**
|
||||
* Returns a set of the socket options supported by this socket.
|
||||
*
|
||||
@ -1504,22 +1023,117 @@ public class DatagramSocket implements java.io.Closeable {
|
||||
* @since 9
|
||||
*/
|
||||
public Set<SocketOption<?>> supportedOptions() {
|
||||
Set<SocketOption<?>> options = this.options;
|
||||
if (options != null)
|
||||
return options;
|
||||
|
||||
synchronized (optionsLock) {
|
||||
options = this.options;
|
||||
if (options != null)
|
||||
return options;
|
||||
|
||||
try {
|
||||
DatagramSocketImpl impl = getImpl();
|
||||
options = Collections.unmodifiableSet(impl.supportedOptions());
|
||||
} catch (IOException e) {
|
||||
options = Collections.emptySet();
|
||||
}
|
||||
return this.options = options;
|
||||
}
|
||||
return delegate().supportedOptions();
|
||||
}
|
||||
|
||||
// Temporary solution until JDK-8237352 is addressed
|
||||
private static final SocketAddress NO_DELEGATE = new SocketAddress() {};
|
||||
private static final boolean USE_PLAINDATAGRAMSOCKET = usePlainDatagramSocketImpl();
|
||||
|
||||
private static boolean usePlainDatagramSocketImpl() {
|
||||
PrivilegedAction<String> pa = () -> NetProperties.get("jdk.net.usePlainDatagramSocketImpl");
|
||||
String s = AccessController.doPrivileged(pa);
|
||||
return (s != null) && (s.isEmpty() || s.equalsIgnoreCase("true"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Best effort to convert an {@link IOException}
|
||||
* into a {@link SocketException}.
|
||||
*
|
||||
* @param e an instance of {@link IOException}
|
||||
* @return an instance of {@link SocketException}
|
||||
*/
|
||||
private static SocketException toSocketException(IOException e) {
|
||||
if (e instanceof SocketException)
|
||||
return (SocketException) e;
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof SocketException)
|
||||
return (SocketException) cause;
|
||||
SocketException se = new SocketException(e.getMessage());
|
||||
se.initCause(e);
|
||||
return se;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a delegate for the specific requested {@code type}. This method should
|
||||
* only be called by {@code DatagramSocket} and {@code MulticastSocket}
|
||||
* public constructors.
|
||||
*
|
||||
* @param bindaddr An address to bind to, or {@code null} if creating an unbound
|
||||
* socket.
|
||||
* @param type This is either {@code MulticastSocket.class}, if the delegate needs
|
||||
* to support joining multicast groups, or {@code DatagramSocket.class},
|
||||
* if it doesn't. Typically, this will be {@code DatagramSocket.class}
|
||||
* when creating a delegate for {@code DatagramSocket}, and
|
||||
* {@code MulticastSocket.class} when creating a delegate for
|
||||
* {@code MulticastSocket}.
|
||||
* @param <T> The target type for which the delegate is created.
|
||||
* This is either {@code java.net.DatagramSocket} or
|
||||
* {@code java.net.MulticastSocket}.
|
||||
* @return {@code null} if {@code bindaddr == NO_DELEGATE}, otherwise returns a
|
||||
* delegate for the requested {@code type}.
|
||||
* @throws SocketException if an exception occurs while creating or binding the
|
||||
* the delegate.
|
||||
*/
|
||||
static <T extends DatagramSocket> T createDelegate(SocketAddress bindaddr, Class<T> type)
|
||||
throws SocketException {
|
||||
|
||||
// Temporary solution until JDK-8237352 is addressed
|
||||
if (bindaddr == NO_DELEGATE) return null;
|
||||
|
||||
assert type == DatagramSocket.class || type == MulticastSocket.class;
|
||||
boolean multicast = (type == MulticastSocket.class);
|
||||
DatagramSocket delegate = null;
|
||||
boolean initialized = false;
|
||||
try {
|
||||
DatagramSocketImplFactory factory = DatagramSocket.factory;
|
||||
if (USE_PLAINDATAGRAMSOCKET || factory != null) {
|
||||
// create legacy DatagramSocket delegate
|
||||
DatagramSocketImpl impl;
|
||||
if (factory != null) {
|
||||
impl = factory.createDatagramSocketImpl();
|
||||
} else {
|
||||
impl = DefaultDatagramSocketImplFactory.createDatagramSocketImpl(multicast);
|
||||
}
|
||||
delegate = new NetMulticastSocket(impl);
|
||||
((NetMulticastSocket) delegate).getImpl(); // ensure impl.create() is called.
|
||||
} else {
|
||||
// create NIO adaptor
|
||||
delegate = DefaultSelectorProvider.get()
|
||||
.openUninterruptibleDatagramChannel()
|
||||
.socket();
|
||||
}
|
||||
|
||||
if (multicast) {
|
||||
// set reuseaddress if multicasting
|
||||
// (must be set before binding)
|
||||
delegate.setReuseAddress(true);
|
||||
}
|
||||
|
||||
if (bindaddr != null) {
|
||||
// bind if needed
|
||||
delegate.bind(bindaddr);
|
||||
}
|
||||
|
||||
// enable broadcast if possible
|
||||
try {
|
||||
delegate.setBroadcast(true);
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
} catch (IOException ioe) {
|
||||
throw toSocketException(ioe);
|
||||
} finally {
|
||||
// make sure the delegate is closed if anything
|
||||
// went wrong
|
||||
if (!initialized && delegate != null) {
|
||||
delegate.close();
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
T result = (T) delegate;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,6 +32,25 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* Abstract datagram and multicast socket implementation base class.
|
||||
*
|
||||
* @implNote Sockets created with the {@code DatagramSocket} and {@code
|
||||
* MulticastSocket} public constructors historically delegated all socket
|
||||
* operations to a {@code DatagramSocketImpl} implementation named
|
||||
* "PlainDatagramSocketImpl". {@code DatagramSocket} and {@code MulticastSocket}
|
||||
* have since been changed to a new implementation based on {@code DatagramChannel}.
|
||||
* The JDK continues to ship with the older implementation to allow code to run
|
||||
* that depends on unspecified behavior that differs between the old and new
|
||||
* implementations. The old implementation will be used if the Java virtual
|
||||
* machine is started with the system property {@systemProperty
|
||||
* jdk.net.usePlainDatagramSocketImpl} set to use the old implementation. It may
|
||||
* also be set in the JDK's network configuration file, located in {@code
|
||||
* ${java.home}/conf/net.properties}. The value of the property is the string
|
||||
* representation of a boolean. If set without a value then it defaults to {@code
|
||||
* true}, hence running with {@code -Djdk.net.usePlainDatagramSocketImpl} or
|
||||
* {@code -Djdk.net.usePlainDatagramSocketImpl=true} will configure the Java
|
||||
* virtual machine to use the old implementation. The property and old
|
||||
* implementation will be removed in a future version.
|
||||
*
|
||||
* @author Pavani Diwanji
|
||||
* @since 1.1
|
||||
*/
|
||||
|
@ -28,9 +28,6 @@ package java.net;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.MulticastChannel;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The multicast datagram socket class is useful for sending
|
||||
@ -135,11 +132,19 @@ import java.util.Set;
|
||||
*/
|
||||
public class MulticastSocket extends DatagramSocket {
|
||||
|
||||
@Override
|
||||
final MulticastSocket delegate() {
|
||||
return (MulticastSocket) super.delegate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used on some platforms to record if an outgoing interface
|
||||
* has been set for this socket.
|
||||
* Create a MulticastSocket that delegates to the given delegate if not null.
|
||||
* @param delegate the delegate, can be null.
|
||||
*/
|
||||
private boolean interfaceSet;
|
||||
MulticastSocket(MulticastSocket delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a multicast socket.
|
||||
@ -216,44 +221,9 @@ public class MulticastSocket extends DatagramSocket {
|
||||
* @since 1.4
|
||||
*/
|
||||
public MulticastSocket(SocketAddress bindaddr) throws IOException {
|
||||
super((SocketAddress) null);
|
||||
|
||||
// No further initialization when this is a DatagramChannel socket adaptor
|
||||
if (this instanceof sun.nio.ch.DatagramSocketAdaptor)
|
||||
return;
|
||||
|
||||
// Enable SO_REUSEADDR before binding
|
||||
setReuseAddress(true);
|
||||
|
||||
if (bindaddr != null) {
|
||||
try {
|
||||
bind(bindaddr);
|
||||
} finally {
|
||||
if (!isBound()) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
this(createDelegate(bindaddr, MulticastSocket.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* The lock on the socket's TTL. This is for set/getTTL and
|
||||
* send(packet,ttl).
|
||||
*/
|
||||
private Object ttlLock = new Object();
|
||||
|
||||
/**
|
||||
* The lock on the socket's interface - used by setInterface
|
||||
* and getInterface
|
||||
*/
|
||||
private Object infLock = new Object();
|
||||
|
||||
/**
|
||||
* The "last" interface set by setInterface on this MulticastSocket
|
||||
*/
|
||||
private InetAddress infAddress = null;
|
||||
|
||||
|
||||
/**
|
||||
* Set the default time-to-live for multicast packets sent out
|
||||
* on this {@code MulticastSocket} in order to control the
|
||||
@ -271,9 +241,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTTL(byte ttl) throws IOException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setTTL(ttl);
|
||||
delegate().setTTL(ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -297,12 +265,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setTimeToLive(int ttl) throws IOException {
|
||||
if (ttl < 0 || ttl > 255) {
|
||||
throw new IllegalArgumentException("ttl out of range");
|
||||
}
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setTimeToLive(ttl);
|
||||
delegate().setTimeToLive(ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -318,9 +281,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
@Deprecated
|
||||
public byte getTTL() throws IOException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
return getImpl().getTTL();
|
||||
return delegate().getTTL();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -333,9 +294,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
* @since 1.2
|
||||
*/
|
||||
public int getTimeToLive() throws IOException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
return getImpl().getTimeToLive();
|
||||
return delegate().getTimeToLive();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -359,31 +318,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
@Deprecated(since="14")
|
||||
public void joinGroup(InetAddress mcastaddr) throws IOException {
|
||||
if (isClosed()) {
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
|
||||
checkAddress(mcastaddr, "joinGroup");
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkMulticast(mcastaddr);
|
||||
}
|
||||
|
||||
if (!mcastaddr.isMulticastAddress()) {
|
||||
throw new SocketException("Not a multicast address");
|
||||
}
|
||||
|
||||
/**
|
||||
* required for some platforms where it's not possible to join
|
||||
* a group without setting the interface first.
|
||||
*/
|
||||
NetworkInterface defaultInterface = NetworkInterface.getDefault();
|
||||
|
||||
if (!interfaceSet && defaultInterface != null) {
|
||||
setNetworkInterface(defaultInterface);
|
||||
}
|
||||
|
||||
getImpl().join(mcastaddr);
|
||||
delegate().joinGroup(mcastaddr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -406,21 +341,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
@Deprecated(since="14")
|
||||
public void leaveGroup(InetAddress mcastaddr) throws IOException {
|
||||
if (isClosed()) {
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
|
||||
checkAddress(mcastaddr, "leaveGroup");
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkMulticast(mcastaddr);
|
||||
}
|
||||
|
||||
if (!mcastaddr.isMulticastAddress()) {
|
||||
throw new SocketException("Not a multicast address");
|
||||
}
|
||||
|
||||
getImpl().leave(mcastaddr);
|
||||
delegate().leaveGroup(mcastaddr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -452,26 +373,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
|
||||
throws IOException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
|
||||
if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
|
||||
throw new IllegalArgumentException("Unsupported address type");
|
||||
|
||||
if (oldImpl)
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "joinGroup");
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
|
||||
}
|
||||
|
||||
if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
|
||||
throw new SocketException("Not a multicast address");
|
||||
}
|
||||
|
||||
getImpl().joinGroup(mcastaddr, netIf);
|
||||
delegate().joinGroup(mcastaddr, netIf);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -500,26 +402,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
|
||||
throws IOException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
|
||||
if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
|
||||
throw new IllegalArgumentException("Unsupported address type");
|
||||
|
||||
if (oldImpl)
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "leaveGroup");
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
|
||||
}
|
||||
|
||||
if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
|
||||
throw new SocketException("Not a multicast address");
|
||||
}
|
||||
|
||||
getImpl().leaveGroup(mcastaddr, netIf);
|
||||
delegate().leaveGroup(mcastaddr, netIf);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -537,15 +420,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
@Deprecated(since="14")
|
||||
public void setInterface(InetAddress inf) throws SocketException {
|
||||
if (isClosed()) {
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
checkAddress(inf, "setInterface");
|
||||
synchronized (infLock) {
|
||||
getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf);
|
||||
infAddress = inf;
|
||||
interfaceSet = true;
|
||||
}
|
||||
delegate().setInterface(inf);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -565,53 +440,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
@Deprecated(since="14")
|
||||
public InetAddress getInterface() throws SocketException {
|
||||
if (isClosed()) {
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
synchronized (infLock) {
|
||||
InetAddress ia =
|
||||
(InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF);
|
||||
|
||||
/**
|
||||
* No previous setInterface or interface can be
|
||||
* set using setNetworkInterface
|
||||
*/
|
||||
if (infAddress == null) {
|
||||
return ia;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same interface set with setInterface?
|
||||
*/
|
||||
if (ia.equals(infAddress)) {
|
||||
return ia;
|
||||
}
|
||||
|
||||
/**
|
||||
* Different InetAddress from what we set with setInterface
|
||||
* so enumerate the current interface to see if the
|
||||
* address set by setInterface is bound to this interface.
|
||||
*/
|
||||
try {
|
||||
NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
|
||||
Enumeration<InetAddress> addrs = ni.getInetAddresses();
|
||||
while (addrs.hasMoreElements()) {
|
||||
InetAddress addr = addrs.nextElement();
|
||||
if (addr.equals(infAddress)) {
|
||||
return infAddress;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* No match so reset infAddress to indicate that the
|
||||
* interface has changed via means
|
||||
*/
|
||||
infAddress = null;
|
||||
return ia;
|
||||
} catch (Exception e) {
|
||||
return ia;
|
||||
}
|
||||
}
|
||||
return delegate().getInterface();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -626,12 +455,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
public void setNetworkInterface(NetworkInterface netIf)
|
||||
throws SocketException {
|
||||
|
||||
synchronized (infLock) {
|
||||
getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf);
|
||||
infAddress = null;
|
||||
interfaceSet = true;
|
||||
}
|
||||
delegate().setNetworkInterface(netIf);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -646,15 +470,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
* @since 1.4
|
||||
*/
|
||||
public NetworkInterface getNetworkInterface() throws SocketException {
|
||||
NetworkInterface ni
|
||||
= (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2);
|
||||
if (ni == null) {
|
||||
InetAddress[] addrs = new InetAddress[1];
|
||||
addrs[0] = InetAddress.anyLocalAddress();
|
||||
return new NetworkInterface(addrs[0].getHostName(), 0, addrs);
|
||||
} else {
|
||||
return ni;
|
||||
}
|
||||
return delegate().getNetworkInterface();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -678,7 +494,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
@Deprecated(since="14")
|
||||
public void setLoopbackMode(boolean disable) throws SocketException {
|
||||
getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable));
|
||||
delegate().setLoopbackMode(disable);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -694,7 +510,7 @@ public class MulticastSocket extends DatagramSocket {
|
||||
*/
|
||||
@Deprecated(since="14")
|
||||
public boolean getLoopbackMode() throws SocketException {
|
||||
return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue();
|
||||
return delegate().getLoopbackMode();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -755,60 +571,6 @@ public class MulticastSocket extends DatagramSocket {
|
||||
@Deprecated
|
||||
public void send(DatagramPacket p, byte ttl)
|
||||
throws IOException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
synchronized(ttlLock) {
|
||||
synchronized(p) {
|
||||
InetAddress packetAddress = p.getAddress();
|
||||
int packetPort = p.getPort();
|
||||
checkAddress(packetAddress, "send");
|
||||
if (connectState == ST_NOT_CONNECTED) {
|
||||
if (packetAddress == null) {
|
||||
throw new IllegalArgumentException("Address not set");
|
||||
}
|
||||
if (packetPort < 0 || packetPort > 0xFFFF)
|
||||
throw new IllegalArgumentException("port out of range:" + packetPort);
|
||||
// Security manager makes sure that the multicast address
|
||||
// is allowed one and that the ttl used is less
|
||||
// than the allowed maxttl.
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
if (packetAddress.isMulticastAddress()) {
|
||||
security.checkMulticast(packetAddress, ttl);
|
||||
} else {
|
||||
security.checkConnect(packetAddress.getHostAddress(),
|
||||
packetPort);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we're connected
|
||||
if (packetAddress == null) {
|
||||
p.setAddress(connectedAddress);
|
||||
p.setPort(connectedPort);
|
||||
} else if ((!packetAddress.equals(connectedAddress)) ||
|
||||
packetPort != connectedPort) {
|
||||
throw new IllegalArgumentException("connected address and packet address" +
|
||||
" differ");
|
||||
}
|
||||
}
|
||||
byte dttl = getTTL();
|
||||
try {
|
||||
if (ttl != dttl) {
|
||||
// set the ttl
|
||||
getImpl().setTTL(ttl);
|
||||
}
|
||||
if (packetPort == 0) {
|
||||
throw new SocketException("Can't send to port 0");
|
||||
}
|
||||
// call the datagram method to send
|
||||
getImpl().send(p);
|
||||
} finally {
|
||||
// set it back to default
|
||||
if (ttl != dttl) {
|
||||
getImpl().setTTL(dttl);
|
||||
}
|
||||
}
|
||||
} // synch p
|
||||
} //synch ttl
|
||||
} //method
|
||||
delegate().send(p, ttl);
|
||||
}
|
||||
}
|
||||
|
1007
src/java.base/share/classes/java/net/NetMulticastSocket.java
Normal file
1007
src/java.base/share/classes/java/net/NetMulticastSocket.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -74,7 +74,7 @@ public class DatagramSocketAdaptor
|
||||
private volatile int timeout;
|
||||
|
||||
private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
|
||||
super(/*SocketAddress*/null);
|
||||
super(/*SocketAddress*/ DatagramSockets.NO_DELEGATE);
|
||||
this.dc = dc;
|
||||
}
|
||||
|
||||
@ -769,4 +769,24 @@ public class DatagramSocketAdaptor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the value of the private static DatagramSocket.NO_DELEGATE
|
||||
*/
|
||||
private static class DatagramSockets {
|
||||
private static final SocketAddress NO_DELEGATE;
|
||||
|
||||
static {
|
||||
try {
|
||||
PrivilegedExceptionAction<Lookup> pa = () ->
|
||||
MethodHandles.privateLookupIn(DatagramSocket.class, MethodHandles.lookup());
|
||||
MethodHandles.Lookup l = AccessController.doPrivileged(pa);
|
||||
NO_DELEGATE = (SocketAddress)
|
||||
l.findStaticVarHandle(DatagramSocket.class, "NO_DELEGATE",
|
||||
SocketAddress.class).get();
|
||||
} catch (Exception e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -627,8 +627,6 @@ java/net/MulticastSocket/Test.java 7145658 macosx-a
|
||||
|
||||
java/net/MulticastSocket/SetGetNetworkInterfaceTest.java 8219083 windows-all
|
||||
|
||||
java/net/DatagramSocket/SendDatagramToBadAddress.java 7143960 macosx-all
|
||||
|
||||
java/net/ServerSocket/AcceptInheritHandle.java 8211854 aix-ppc64
|
||||
|
||||
|
||||
@ -638,8 +636,6 @@ java/net/ServerSocket/AcceptInheritHandle.java 8211854 aix-ppc6
|
||||
|
||||
java/nio/Buffer/EqualsCompareTest.java 8193917 solaris-all
|
||||
|
||||
java/nio/channels/DatagramChannel/ChangingAddress.java 7141822 macosx-all
|
||||
|
||||
java/nio/channels/DatagramChannel/Unref.java 8233519 generic-all
|
||||
|
||||
java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc64
|
||||
|
@ -27,6 +27,7 @@
|
||||
* @summary DatagramSocket.send should throw IllegalArgumentException
|
||||
* when the packet address is not correctly set.
|
||||
* @run main AddressNotSet
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl AddressNotSet
|
||||
*/
|
||||
|
||||
import java.net.DatagramPacket;
|
||||
|
@ -70,6 +70,9 @@ public class B6411513 {
|
||||
System.out.print("disconnect...");
|
||||
s.disconnect();
|
||||
|
||||
System.out.println("local addr: " + s.getLocalAddress());
|
||||
System.out.println("local port: " + s.getLocalPort());
|
||||
|
||||
byte[] data = { 0, 1, 2 };
|
||||
DatagramPacket p = new DatagramPacket(data, data.length,
|
||||
s.getLocalAddress(), s.getLocalPort());
|
||||
|
@ -27,52 +27,90 @@
|
||||
* @summary Test to see if timeout hangs. Also checks that
|
||||
* negative timeout value fails as expected.
|
||||
* @run testng DatagramTimeout
|
||||
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl DatagramTimeout
|
||||
*/
|
||||
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.MulticastSocket;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
|
||||
import org.testng.annotations.AfterTest;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.expectThrows;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
public class DatagramTimeout {
|
||||
private static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
|
||||
private static final Class<SocketTimeoutException> STE = SocketTimeoutException.class;
|
||||
private static final Class<IllegalArgumentException> IAE =
|
||||
IllegalArgumentException.class;
|
||||
private static final Class<SocketTimeoutException> STE =
|
||||
SocketTimeoutException.class;
|
||||
private static final Class<SocketException> SE = SocketException.class;
|
||||
|
||||
/**
|
||||
* Test DatagramSocket setSoTimeout with a valid timeout value.
|
||||
*/
|
||||
@Test
|
||||
public void testSetTimeout() throws Exception {
|
||||
try (DatagramSocket s = new DatagramSocket()) {
|
||||
byte[] buffer = new byte[50];
|
||||
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
|
||||
s.setSoTimeout(2);
|
||||
expectThrows(STE, () -> s.receive(p));
|
||||
}
|
||||
private DatagramSocket datagramSocket, multicastSocket,
|
||||
datagramSocketAdaptor;
|
||||
|
||||
@BeforeTest
|
||||
public void setUp() throws Exception {
|
||||
datagramSocket = new DatagramSocket();
|
||||
multicastSocket = new MulticastSocket();
|
||||
datagramSocketAdaptor = DatagramChannel.open().socket();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test DatagramSocket setSoTimeout with a negative timeout.
|
||||
*/
|
||||
@Test
|
||||
public void testSetNegativeTimeout() throws Exception {
|
||||
try (DatagramSocket s = new DatagramSocket()) {
|
||||
expectThrows(IAE, () -> s.setSoTimeout(-1));
|
||||
}
|
||||
@DataProvider(name = "data")
|
||||
public Object[][] variants() {
|
||||
return new Object[][]{
|
||||
{ datagramSocket },
|
||||
{ datagramSocketAdaptor },
|
||||
{ multicastSocket },
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "data")
|
||||
public void testSetNegTimeout(DatagramSocket ds) {
|
||||
assertThrows(IAE, () -> ds.setSoTimeout(-1));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "data")
|
||||
public void testSetTimeout(DatagramSocket ds) throws Exception {
|
||||
byte[] buffer = new byte[50];
|
||||
DatagramPacket pkt = new DatagramPacket(buffer, buffer.length);
|
||||
ds.setSoTimeout(2);
|
||||
assertThrows(STE, () -> ds.receive(pkt));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "data")
|
||||
public void testGetTimeout(DatagramSocket ds) throws Exception {
|
||||
ds.setSoTimeout(10);
|
||||
assertEquals(10, ds.getSoTimeout());
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
public void tearDown() {
|
||||
datagramSocket.close();
|
||||
multicastSocket.close();
|
||||
datagramSocketAdaptor.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test DatagramSocketAdaptor setSoTimeout with a negative timeout.
|
||||
*/
|
||||
@Test
|
||||
public void testNegativeTimeout() throws Exception {
|
||||
try (DatagramChannel dc = DatagramChannel.open()) {
|
||||
var s = dc.socket();
|
||||
expectThrows(IAE, () -> s.setSoTimeout(-1));
|
||||
}
|
||||
public void testSetGetAfterClose() throws Exception {
|
||||
var ds = new DatagramSocket();
|
||||
var ms = new MulticastSocket();
|
||||
var dsa = DatagramChannel.open().socket();
|
||||
|
||||
ds.close();
|
||||
ms.close();
|
||||
dsa.close();
|
||||
assertThrows(SE, () -> ds.setSoTimeout(10));
|
||||
assertThrows(SE, () -> ds.getSoTimeout());
|
||||
assertThrows(SE, () -> ms.setSoTimeout(10));
|
||||
assertThrows(SE, () -> ms.getSoTimeout());
|
||||
assertThrows(SE, () -> dsa.setSoTimeout(10));
|
||||
assertThrows(SE, () -> dsa.getSoTimeout());
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ import static java.lang.Thread.sleep;
|
||||
* @test
|
||||
* @summary Check interrupt mechanism for DatagramSocket,
|
||||
* MulticastSocket, and DatagramSocketAdaptor
|
||||
* @run main InterruptibleDatagramSocket
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl InterruptibleDatagramSocket
|
||||
*/
|
||||
|
||||
public class InterruptibleDatagramSocket {
|
||||
|
@ -36,6 +36,7 @@ import java.net.SocketException;
|
||||
* @summary Expected SocketException not thrown when calling bind() with
|
||||
* setReuseAddress(false)
|
||||
* @run main/othervm ReuseAddressTest
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl ReuseAddressTest
|
||||
*/
|
||||
|
||||
public class ReuseAddressTest {
|
||||
|
@ -47,7 +47,8 @@ import static org.testng.Assert.expectThrows;
|
||||
* DatagramSocketAdaptor and DatagramChannel all
|
||||
* throw expected Execption when passed a DatagramPacket
|
||||
* with invalid details
|
||||
* @run testng/othervm SendCheck
|
||||
* @run testng SendCheck
|
||||
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl SendCheck
|
||||
*/
|
||||
|
||||
public class SendCheck {
|
||||
|
@ -48,7 +48,8 @@ import static org.testng.Assert.assertThrows;
|
||||
* @bug 8236105 8240533
|
||||
* @summary Check that DatagramSocket throws expected
|
||||
* Exception when sending a DatagramPacket with port 0
|
||||
* @run testng/othervm SendPortZero
|
||||
* @run testng SendPortZero
|
||||
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl SendPortZero
|
||||
*/
|
||||
|
||||
public class SendPortZero {
|
||||
|
@ -27,6 +27,7 @@
|
||||
* @summary Check that setReceiveBufferSize and getReceiveBufferSize work as expected
|
||||
* @run testng SetGetReceiveBufferSize
|
||||
* @run testng/othervm -Djava.net.preferIPv4Stack=true SetGetReceiveBufferSize
|
||||
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl SetGetReceiveBufferSize
|
||||
*/
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
|
@ -29,6 +29,7 @@
|
||||
* @summary Check that setSendBufferSize and getSendBufferSize work as expected
|
||||
* @run testng SetGetSendBufferSize
|
||||
* @run testng/othervm -Djava.net.preferIPv4Stack=true SetGetSendBufferSize
|
||||
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl SetGetSendBufferSize
|
||||
*/
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
|
@ -25,6 +25,8 @@
|
||||
* @test
|
||||
* @bug 6505016
|
||||
* @summary Socket spec should clarify what getInetAddress/getPort/etc return after the Socket is closed
|
||||
* @run main TestAfterClose
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl TestAfterClose
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,8 +25,10 @@
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @modules java.management java.base/java.io:+open java.base/java.net:+open
|
||||
* java.base/sun.net
|
||||
* @run main/othervm UnreferencedDatagramSockets
|
||||
* @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedDatagramSockets
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl UnreferencedDatagramSockets
|
||||
* @summary Check that unreferenced datagram sockets are closed
|
||||
*/
|
||||
|
||||
@ -37,14 +39,18 @@ import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.DatagramSocketImpl;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -54,6 +60,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import com.sun.management.UnixOperatingSystemMXBean;
|
||||
|
||||
import jdk.test.lib.net.IPSupport;
|
||||
import sun.net.NetProperties;
|
||||
|
||||
public class UnreferencedDatagramSockets {
|
||||
|
||||
@ -185,32 +192,62 @@ public class UnreferencedDatagramSockets {
|
||||
: -1L;
|
||||
}
|
||||
|
||||
private static boolean usePlainDatagramSocketImpl() {
|
||||
PrivilegedAction<String> pa = () -> NetProperties.get("jdk.net.usePlainDatagramSocketImpl");
|
||||
String s = AccessController.doPrivileged(pa);
|
||||
return (s != null) && (s.isEmpty() || s.equalsIgnoreCase("true"));
|
||||
}
|
||||
|
||||
// Reflect to find references in the datagram implementation that will be gc'd
|
||||
private static void extractRefs(DatagramSocket s, String name) {
|
||||
try {
|
||||
Field datagramSocketField = DatagramSocket.class.getDeclaredField("delegate");
|
||||
datagramSocketField.setAccessible(true);
|
||||
|
||||
Field socketImplField = DatagramSocket.class.getDeclaredField("impl");
|
||||
socketImplField.setAccessible(true);
|
||||
Object socketImpl = socketImplField.get(s);
|
||||
if (!usePlainDatagramSocketImpl()) {
|
||||
// DatagramSocket using DatagramSocketAdaptor
|
||||
Object DatagramSocket = datagramSocketField.get(s);
|
||||
assert DatagramSocket.getClass() == Class.forName("sun.nio.ch.DatagramSocketAdaptor");
|
||||
|
||||
Field fileDescriptorField = DatagramSocketImpl.class.getDeclaredField("fd");
|
||||
fileDescriptorField.setAccessible(true);
|
||||
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(socketImpl);
|
||||
extractRefs(fileDescriptor, name);
|
||||
Method m = DatagramSocket.class.getDeclaredMethod("getChannel");
|
||||
m.setAccessible(true);
|
||||
DatagramChannel datagramChannel = (DatagramChannel) m.invoke(DatagramSocket);
|
||||
|
||||
Class<?> socketImplClass = socketImpl.getClass();
|
||||
System.out.printf("socketImplClass: %s%n", socketImplClass);
|
||||
if (socketImplClass.getName().equals("java.net.TwoStacksPlainDatagramSocketImpl")) {
|
||||
Field fileDescriptor1Field = socketImplClass.getDeclaredField("fd1");
|
||||
fileDescriptor1Field.setAccessible(true);
|
||||
FileDescriptor fileDescriptor1 = (FileDescriptor) fileDescriptor1Field.get(socketImpl);
|
||||
extractRefs(fileDescriptor1, name + "::twoStacksFd1");
|
||||
assert datagramChannel.getClass() == Class.forName("sun.nio.ch.DatagramChannelImpl");
|
||||
|
||||
Field fileDescriptorField = datagramChannel.getClass().getDeclaredField("fd");
|
||||
fileDescriptorField.setAccessible(true);
|
||||
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(datagramChannel);
|
||||
extractRefs(fileDescriptor, name);
|
||||
|
||||
} else {
|
||||
System.out.printf("socketImpl class name not matched: %s != %s%n",
|
||||
socketImplClass.getName(), "java.net.TwoStacksPlainDatagramSocketImpl");
|
||||
// DatagramSocket using PlainDatagramSocketImpl
|
||||
Object DatagramSocket = datagramSocketField.get(s);
|
||||
assert DatagramSocket.getClass() == Class.forName("java.net.NetMulticastSocket");
|
||||
|
||||
Method m = DatagramSocket.getClass().getDeclaredMethod("getImpl");
|
||||
m.setAccessible(true);
|
||||
DatagramSocketImpl datagramSocketImpl = (DatagramSocketImpl) m.invoke(DatagramSocket);
|
||||
|
||||
Field fileDescriptorField = DatagramSocketImpl.class.getDeclaredField("fd");
|
||||
fileDescriptorField.setAccessible(true);
|
||||
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(datagramSocketImpl);
|
||||
extractRefs(fileDescriptor, name);
|
||||
|
||||
Class<?> socketImplClass = datagramSocketImpl.getClass();
|
||||
System.out.printf("socketImplClass: %s%n", socketImplClass);
|
||||
if (socketImplClass.getName().equals("java.net.TwoStacksPlainDatagramSocketImpl")) {
|
||||
Field fileDescriptor1Field = socketImplClass.getDeclaredField("fd1");
|
||||
fileDescriptor1Field.setAccessible(true);
|
||||
FileDescriptor fileDescriptor1 = (FileDescriptor) fileDescriptor1Field.get(datagramSocketImpl);
|
||||
extractRefs(fileDescriptor1, name + "::twoStacksFd1");
|
||||
|
||||
} else {
|
||||
System.out.printf("socketImpl class name not matched: %s != %s%n",
|
||||
socketImplClass.getName(), "java.net.TwoStacksPlainDatagramSocketImpl");
|
||||
}
|
||||
}
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
throw new AssertionError("missing field", ex);
|
||||
}
|
||||
|
@ -60,10 +60,10 @@ public class TestCreate {
|
||||
Iterator<CustomDatagramSocketImpl> iterator = List.of(dsi2, dsi3).iterator();
|
||||
DatagramSocket.setDatagramSocketImplFactory(() -> iterator.next());
|
||||
|
||||
DatagramSocket ds2 = new DatagramSocket();
|
||||
DatagramSocket ds2 = new DatagramSocket(null);
|
||||
assertTrue(dsi2.created.get(), "new DatagramSocket()");
|
||||
|
||||
MulticastSocket ds3 = new MulticastSocket();
|
||||
MulticastSocket ds3 = new MulticastSocket(null);
|
||||
assertTrue(dsi3.created.get(), "new MulticastSocket()");
|
||||
}
|
||||
|
||||
|
@ -83,6 +83,10 @@ public class CheckJNI {
|
||||
static void testDatagram(InetAddress ia) throws Exception {
|
||||
DatagramSocket s1 = new DatagramSocket(0, ia);
|
||||
DatagramSocket s2 = new DatagramSocket(0, ia);
|
||||
System.out.println("s1: local address=" + s1.getLocalAddress()
|
||||
+ ", local port=" + s1.getLocalPort());
|
||||
System.out.println("s2: local address=" + s2.getLocalAddress()
|
||||
+ ", local port=" + s2.getLocalPort());
|
||||
|
||||
DatagramPacket p1 = new DatagramPacket (
|
||||
"hello world".getBytes(),
|
||||
|
@ -25,6 +25,8 @@
|
||||
* @test
|
||||
* @bug 6427403
|
||||
* @summary java.net.MulticastSocket.joinGroup() reports 'socket closed'
|
||||
* @run main B6427403
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl B6427403
|
||||
*/
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
|
@ -27,6 +27,8 @@
|
||||
* @library /test/lib
|
||||
* @summary Test that MutlicastSocket.joinGroup is working for
|
||||
* various multicast and non-multicast addresses.
|
||||
* @run main MulticastAddresses
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl MulticastAddresses
|
||||
*/
|
||||
|
||||
import jdk.test.lib.NetworkConfiguration;
|
||||
|
@ -28,6 +28,7 @@
|
||||
* @run main/othervm NoSetNetworkInterface
|
||||
* @run main/othervm -Djava.net.preferIPv4Stack=true NoSetNetworkInterface
|
||||
* @run main/othervm -Djava.net.preferIPv6Addresses=true NoSetNetworkInterface
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl NoSetNetworkInterface
|
||||
* @summary Check that methods that are used to set and get the NetworkInterface
|
||||
* for a MulticastSocket work as expected. This test also checks that getOption
|
||||
* returns null correctly when a NetworkInterface has not been set
|
||||
|
@ -26,6 +26,7 @@
|
||||
* @library /test/lib
|
||||
* @summary Test for interference when two sockets are bound to the same
|
||||
* port but joined to different multicast groups
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl Promiscuous
|
||||
* @run main Promiscuous
|
||||
* @run main/othervm -Djava.net.preferIPv4Stack=true Promiscuous
|
||||
*/
|
||||
|
@ -48,7 +48,8 @@ import static org.testng.Assert.assertThrows;
|
||||
* @bug 8243408
|
||||
* @summary Check that MulticastSocket throws expected
|
||||
* Exception when sending a DatagramPacket with port 0
|
||||
* @run testng/othervm SendPortZero
|
||||
* @run testng SendPortZero
|
||||
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl SendPortZero
|
||||
*/
|
||||
|
||||
public class SendPortZero {
|
||||
|
@ -30,6 +30,7 @@
|
||||
* @build jdk.test.lib.NetworkConfiguration
|
||||
* jdk.test.lib.Platform
|
||||
* @run main/othervm SetLoopbackMode
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl SetLoopbackMode
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@ -53,6 +54,8 @@ public class SetLoopbackMode {
|
||||
System.out.println("Loopback mode is enabled.");
|
||||
}
|
||||
|
||||
System.out.println(mc.getLocalSocketAddress());
|
||||
|
||||
byte b[] = "hello".getBytes();
|
||||
DatagramPacket p = new DatagramPacket(b, b.length, grp,
|
||||
mc.getLocalPort());
|
||||
|
@ -32,6 +32,8 @@
|
||||
* SetLoopbackMode
|
||||
* SetLoopbackModeIPv4
|
||||
* @run main/othervm -Djava.net.preferIPv4Stack=true SetLoopbackModeIPv4
|
||||
* @run main/othervm -Djava.net.preferIPv4Stack=true
|
||||
* -Djdk.net.usePlainDatagramSocketImpl SetLoopbackModeIPv4
|
||||
*/
|
||||
|
||||
import jdk.test.lib.net.IPSupport;
|
||||
|
@ -31,6 +31,7 @@
|
||||
* @run testng/othervm SetLoopbackOption
|
||||
* @run testng/othervm -Djava.net.preferIPv4Stack=true SetLoopbackOption
|
||||
* @run testng/othervm -Djava.net.preferIPv6Addresses=true SetLoopbackOption
|
||||
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl SetLoopbackOption
|
||||
*/
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
|
@ -26,6 +26,7 @@
|
||||
* @bug 4742177 8241786
|
||||
* @library /test/lib
|
||||
* @run main/othervm SetOutgoingIf
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl SetOutgoingIf
|
||||
* @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
|
||||
*/
|
||||
import java.io.IOException;
|
||||
|
@ -24,6 +24,8 @@
|
||||
/* @test
|
||||
* @bug 4189640
|
||||
* @summary Make setTTL/getTTL works
|
||||
* @run main SetTTLAndGetTTL
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl SetTTLAndGetTTL
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
|
@ -24,6 +24,8 @@
|
||||
/* @test
|
||||
* @bug 4148757
|
||||
* @summary Make sure TTL can be set to 0
|
||||
* @run main SetTTLTo0
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl SetTTLTo0
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,7 +25,9 @@
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @modules java.management java.base/java.io:+open java.base/java.net:+open
|
||||
* java.base/sun.net
|
||||
* @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedMulticastSockets
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl UnreferencedMulticastSockets
|
||||
* @run main/othervm UnreferencedMulticastSockets
|
||||
* @summary Check that unreferenced multicast sockets are closed
|
||||
*/
|
||||
@ -37,6 +39,7 @@ import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.DatagramSocketImpl;
|
||||
@ -44,9 +47,12 @@ import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MulticastSocket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -56,6 +62,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import jdk.test.lib.net.IPSupport;
|
||||
|
||||
import com.sun.management.UnixOperatingSystemMXBean;
|
||||
import sun.net.NetProperties;
|
||||
|
||||
public class UnreferencedMulticastSockets {
|
||||
|
||||
@ -223,32 +230,62 @@ public class UnreferencedMulticastSockets {
|
||||
: -1L;
|
||||
}
|
||||
|
||||
// Reflect to find references in the socket implementation that will be gc'd
|
||||
private static void extractRefs(MulticastSocket s, String name) {
|
||||
private static boolean usePlainDatagramSocketImpl() {
|
||||
PrivilegedAction<String> pa = () -> NetProperties.get("jdk.net.usePlainDatagramSocketImpl");
|
||||
String s = AccessController.doPrivileged(pa);
|
||||
return (s != null) && (s.isEmpty() || s.equalsIgnoreCase("true"));
|
||||
}
|
||||
|
||||
// Reflect to find references in the datagram implementation that will be gc'd
|
||||
private static void extractRefs(DatagramSocket s, String name) {
|
||||
|
||||
try {
|
||||
Field datagramSocketField = DatagramSocket.class.getDeclaredField("delegate");
|
||||
datagramSocketField.setAccessible(true);
|
||||
|
||||
Field socketImplField = DatagramSocket.class.getDeclaredField("impl");
|
||||
socketImplField.setAccessible(true);
|
||||
Object socketImpl = socketImplField.get(s);
|
||||
if (!usePlainDatagramSocketImpl()) {
|
||||
// MulticastSocket using DatagramSocketAdaptor
|
||||
Object MulticastSocket = datagramSocketField.get(s);
|
||||
|
||||
Field fileDescriptorField = DatagramSocketImpl.class.getDeclaredField("fd");
|
||||
fileDescriptorField.setAccessible(true);
|
||||
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(socketImpl);
|
||||
extractRefs(fileDescriptor, name);
|
||||
Method m = DatagramSocket.class.getDeclaredMethod("getChannel");
|
||||
m.setAccessible(true);
|
||||
DatagramChannel datagramChannel = (DatagramChannel) m.invoke(MulticastSocket);
|
||||
|
||||
Class<?> socketImplClass = socketImpl.getClass();
|
||||
System.out.printf("socketImplClass: %s%n", socketImplClass);
|
||||
if (socketImplClass.getName().equals("java.net.TwoStacksPlainDatagramSocketImpl")) {
|
||||
Field fileDescriptor1Field = socketImplClass.getDeclaredField("fd1");
|
||||
fileDescriptor1Field.setAccessible(true);
|
||||
FileDescriptor fileDescriptor1 = (FileDescriptor) fileDescriptor1Field.get(socketImpl);
|
||||
extractRefs(fileDescriptor1, name + "::twoStacksFd1");
|
||||
assert datagramChannel.getClass() == Class.forName("sun.nio.ch.DatagramChannelImpl");
|
||||
|
||||
Field fileDescriptorField = datagramChannel.getClass().getDeclaredField("fd");
|
||||
fileDescriptorField.setAccessible(true);
|
||||
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(datagramChannel);
|
||||
extractRefs(fileDescriptor, name);
|
||||
|
||||
} else {
|
||||
System.out.printf("socketImpl class name not matched: %s != %s%n",
|
||||
socketImplClass.getName(), "java.net.TwoStacksPlainDatagramSocketImpl");
|
||||
// MulticastSocket using PlainDatagramSocketImpl
|
||||
Object MulticastSocket = datagramSocketField.get(s);
|
||||
assert MulticastSocket.getClass() == Class.forName("java.net.NetMulticastSocket");
|
||||
|
||||
Method m = MulticastSocket.getClass().getDeclaredMethod("getImpl");
|
||||
m.setAccessible(true);
|
||||
DatagramSocketImpl datagramSocketImpl = (DatagramSocketImpl) m.invoke(MulticastSocket);
|
||||
|
||||
Field fileDescriptorField = DatagramSocketImpl.class.getDeclaredField("fd");
|
||||
fileDescriptorField.setAccessible(true);
|
||||
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(datagramSocketImpl);
|
||||
extractRefs(fileDescriptor, name);
|
||||
|
||||
Class<?> socketImplClass = datagramSocketImpl.getClass();
|
||||
System.out.printf("socketImplClass: %s%n", socketImplClass);
|
||||
if (socketImplClass.getName().equals("java.net.TwoStacksPlainDatagramSocketImpl")) {
|
||||
Field fileDescriptor1Field = socketImplClass.getDeclaredField("fd1");
|
||||
fileDescriptor1Field.setAccessible(true);
|
||||
FileDescriptor fileDescriptor1 = (FileDescriptor) fileDescriptor1Field.get(datagramSocketImpl);
|
||||
extractRefs(fileDescriptor1, name + "::twoStacksFd1");
|
||||
|
||||
} else {
|
||||
System.out.printf("socketImpl class name not matched: %s != %s%n",
|
||||
socketImplClass.getName(), "java.net.TwoStacksPlainDatagramSocketImpl");
|
||||
}
|
||||
}
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
throw new AssertionError("missing field", ex);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
* SocketAddress
|
||||
* @run main AddressTest
|
||||
* @run main/othervm -Djava.net.preferIPv4Stack=true AddressTest
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl AddressTest
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
|
@ -27,6 +27,7 @@
|
||||
* @summary Ensures that IOException is thrown after the socket is closed
|
||||
* @run testng AfterClose
|
||||
* @run testng/othervm -Djdk.net.usePlainSocketImpl AfterClose
|
||||
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl AfterClose
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
@ -48,6 +49,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
import static java.lang.Boolean.*;
|
||||
|
@ -28,6 +28,7 @@
|
||||
* @requires !vm.graal.enabled
|
||||
* @run main/othervm -Xcheck:jni OptionsTest
|
||||
* @run main/othervm -Djdk.net.usePlainSocketImpl OptionsTest
|
||||
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl OptionsTest
|
||||
* @run main/othervm -Xcheck:jni -Djava.net.preferIPv4Stack=true OptionsTest
|
||||
* @run main/othervm --limit-modules=java.base OptionsTest
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user