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:
Patrick Concannon 2020-05-12 21:51:53 +01:00
parent 3930460af5
commit fad2cf51ba
34 changed files with 1478 additions and 909 deletions

View File

@ -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;
}
}

View File

@ -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
*/

View File

@ -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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
}
}
}

View File

@ -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

View File

@ -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;

View File

@ -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());

View File

@ -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());
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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.*;

View File

@ -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);
}

View File

@ -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()");
}

View File

@ -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(),

View File

@ -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.*;

View File

@ -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;

View File

@ -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

View File

@ -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
*/

View File

@ -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 {

View File

@ -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());

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.*;

View File

@ -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.*;

View File

@ -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);
}

View File

@ -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.*;

View File

@ -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.*;

View File

@ -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
*/