mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
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
34 changed files with 1478 additions and 909 deletions
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue