mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8232673: (dc) DatagramChannel socket adaptor issues
Reviewed-by: dfuchs, chegar
This commit is contained in:
parent
5dafc279a7
commit
db4909bf99
8 changed files with 948 additions and 245 deletions
|
@ -606,7 +606,6 @@ class DatagramSocket implements java.io.Closeable {
|
||||||
* @see #bind(SocketAddress)
|
* @see #bind(SocketAddress)
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public SocketAddress getLocalSocketAddress() {
|
public SocketAddress getLocalSocketAddress() {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
return null;
|
return null;
|
||||||
|
@ -853,7 +852,7 @@ class DatagramSocket implements java.io.Closeable {
|
||||||
public InetAddress getLocalAddress() {
|
public InetAddress getLocalAddress() {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
return null;
|
return null;
|
||||||
InetAddress in = null;
|
InetAddress in;
|
||||||
try {
|
try {
|
||||||
in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
|
in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
|
||||||
if (in.isAnyLocalAddress()) {
|
if (in.isAnyLocalAddress()) {
|
||||||
|
@ -874,8 +873,8 @@ class DatagramSocket implements java.io.Closeable {
|
||||||
* is bound.
|
* is bound.
|
||||||
*
|
*
|
||||||
* @return the port number on the local host to which this socket is bound,
|
* @return the port number on the local host to which this socket is bound,
|
||||||
{@code -1} if the socket is closed, or
|
* {@code -1} if the socket is closed, or
|
||||||
{@code 0} if it is not bound yet.
|
* {@code 0} if it is not bound yet.
|
||||||
*/
|
*/
|
||||||
public int getLocalPort() {
|
public int getLocalPort() {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
|
@ -887,15 +886,16 @@ class DatagramSocket implements java.io.Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Enable/disable SO_TIMEOUT with the specified timeout, in
|
/**
|
||||||
* milliseconds. With this option set to a positive timeout value,
|
* Enable/disable SO_TIMEOUT with the specified timeout, in
|
||||||
* a call to receive() for this DatagramSocket
|
* milliseconds. With this option set to a positive timeout value,
|
||||||
* will block for only this amount of time. If the timeout expires,
|
* a call to receive() for this DatagramSocket
|
||||||
* a <B>java.net.SocketTimeoutException</B> is raised, though the
|
* will block for only this amount of time. If the timeout expires,
|
||||||
* DatagramSocket is still valid. A timeout of zero is interpreted
|
* a <B>java.net.SocketTimeoutException</B> is raised, though the
|
||||||
* as an infinite timeout.
|
* DatagramSocket is still valid. A timeout of zero is interpreted
|
||||||
* The option <B>must</B> be enabled prior to entering the blocking
|
* as an infinite timeout.
|
||||||
* operation to have effect.
|
* The option <B>must</B> be enabled prior to entering the blocking
|
||||||
|
* operation to have effect.
|
||||||
*
|
*
|
||||||
* @param timeout the specified timeout in milliseconds.
|
* @param timeout the specified timeout in milliseconds.
|
||||||
* @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
|
* @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
|
||||||
|
@ -963,8 +963,7 @@ class DatagramSocket implements java.io.Closeable {
|
||||||
* negative.
|
* negative.
|
||||||
* @see #getSendBufferSize()
|
* @see #getSendBufferSize()
|
||||||
*/
|
*/
|
||||||
public synchronized void setSendBufferSize(int size)
|
public synchronized void setSendBufferSize(int size) throws SocketException {
|
||||||
throws SocketException{
|
|
||||||
if (!(size > 0)) {
|
if (!(size > 0)) {
|
||||||
throw new IllegalArgumentException("negative send size");
|
throw new IllegalArgumentException("negative send size");
|
||||||
}
|
}
|
||||||
|
@ -1021,8 +1020,7 @@ class DatagramSocket implements java.io.Closeable {
|
||||||
* negative.
|
* negative.
|
||||||
* @see #getReceiveBufferSize()
|
* @see #getReceiveBufferSize()
|
||||||
*/
|
*/
|
||||||
public synchronized void setReceiveBufferSize(int size)
|
public synchronized void setReceiveBufferSize(int size) throws SocketException {
|
||||||
throws SocketException{
|
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
throw new IllegalArgumentException("invalid receive size");
|
throw new IllegalArgumentException("invalid receive size");
|
||||||
}
|
}
|
||||||
|
@ -1039,8 +1037,7 @@ class DatagramSocket implements java.io.Closeable {
|
||||||
* @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
|
* @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
|
||||||
* @see #setReceiveBufferSize(int)
|
* @see #setReceiveBufferSize(int)
|
||||||
*/
|
*/
|
||||||
public synchronized int getReceiveBufferSize()
|
public synchronized int getReceiveBufferSize() throws SocketException {
|
||||||
throws SocketException{
|
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw new SocketException("Socket is closed");
|
throw new SocketException("Socket is closed");
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
|
@ -28,6 +28,8 @@ package sun.nio.ch;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.VarHandle;
|
||||||
import java.lang.ref.Cleaner.Cleanable;
|
import java.lang.ref.Cleaner.Cleanable;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
|
@ -39,6 +41,7 @@ import java.net.PortUnreachableException;
|
||||||
import java.net.ProtocolFamily;
|
import java.net.ProtocolFamily;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.SocketOption;
|
import java.net.SocketOption;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.StandardProtocolFamily;
|
import java.net.StandardProtocolFamily;
|
||||||
import java.net.StandardSocketOptions;
|
import java.net.StandardSocketOptions;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
@ -47,6 +50,7 @@ import java.nio.channels.AlreadyConnectedException;
|
||||||
import java.nio.channels.AsynchronousCloseException;
|
import java.nio.channels.AsynchronousCloseException;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.nio.channels.DatagramChannel;
|
import java.nio.channels.DatagramChannel;
|
||||||
|
import java.nio.channels.IllegalBlockingModeException;
|
||||||
import java.nio.channels.MembershipKey;
|
import java.nio.channels.MembershipKey;
|
||||||
import java.nio.channels.NotYetConnectedException;
|
import java.nio.channels.NotYetConnectedException;
|
||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
|
@ -113,8 +117,17 @@ class DatagramChannelImpl
|
||||||
private InetSocketAddress localAddress;
|
private InetSocketAddress localAddress;
|
||||||
private InetSocketAddress remoteAddress;
|
private InetSocketAddress remoteAddress;
|
||||||
|
|
||||||
// Our socket adaptor, if any
|
// Socket adaptor, created lazily
|
||||||
private DatagramSocket socket;
|
private static final VarHandle SOCKET;
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
MethodHandles.Lookup l = MethodHandles.lookup();
|
||||||
|
SOCKET = l.findVarHandle(DatagramChannelImpl.class, "socket", DatagramSocket.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InternalError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private volatile DatagramSocket socket;
|
||||||
|
|
||||||
// Multicast support
|
// Multicast support
|
||||||
private MembershipRegistry registry;
|
private MembershipRegistry registry;
|
||||||
|
@ -199,11 +212,14 @@ class DatagramChannelImpl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DatagramSocket socket() {
|
public DatagramSocket socket() {
|
||||||
synchronized (stateLock) {
|
DatagramSocket socket = this.socket;
|
||||||
if (socket == null)
|
if (socket == null) {
|
||||||
socket = DatagramSocketAdaptor.create(this);
|
socket = DatagramSocketAdaptor.create(this);
|
||||||
return socket;
|
if (!SOCKET.compareAndSet(this, null, socket)) {
|
||||||
|
socket = this.socket;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -408,62 +424,35 @@ class DatagramChannelImpl
|
||||||
public SocketAddress receive(ByteBuffer dst) throws IOException {
|
public SocketAddress receive(ByteBuffer dst) throws IOException {
|
||||||
if (dst.isReadOnly())
|
if (dst.isReadOnly())
|
||||||
throw new IllegalArgumentException("Read-only buffer");
|
throw new IllegalArgumentException("Read-only buffer");
|
||||||
|
|
||||||
readLock.lock();
|
readLock.lock();
|
||||||
try {
|
try {
|
||||||
boolean blocking = isBlocking();
|
boolean blocking = isBlocking();
|
||||||
|
boolean completed = false;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
ByteBuffer bb = null;
|
|
||||||
try {
|
try {
|
||||||
SocketAddress remote = beginRead(blocking, false);
|
SocketAddress remote = beginRead(blocking, false);
|
||||||
boolean connected = (remote != null);
|
boolean connected = (remote != null);
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
|
||||||
if (connected || (sm == null)) {
|
if (connected || (sm == null)) {
|
||||||
// connected or no security manager
|
// connected or no security manager
|
||||||
n = receive(fd, dst, connected);
|
n = receive(dst, connected);
|
||||||
if (blocking) {
|
if (blocking) {
|
||||||
while (IOStatus.okayToRetry(n) && isOpen()) {
|
while (IOStatus.okayToRetry(n) && isOpen()) {
|
||||||
park(Net.POLLIN);
|
park(Net.POLLIN);
|
||||||
n = receive(fd, dst, connected);
|
n = receive(dst, connected);
|
||||||
}
|
}
|
||||||
} else if (n == IOStatus.UNAVAILABLE) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Cannot receive into user's buffer when running with a
|
// security manager and unconnected
|
||||||
// security manager and not connected
|
n = untrustedReceive(dst);
|
||||||
bb = Util.getTemporaryDirectBuffer(dst.remaining());
|
|
||||||
for (;;) {
|
|
||||||
n = receive(fd, bb, connected);
|
|
||||||
if (blocking) {
|
|
||||||
while (IOStatus.okayToRetry(n) && isOpen()) {
|
|
||||||
park(Net.POLLIN);
|
|
||||||
n = receive(fd, bb, connected);
|
|
||||||
}
|
|
||||||
} else if (n == IOStatus.UNAVAILABLE) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
InetSocketAddress isa = (InetSocketAddress)sender;
|
|
||||||
try {
|
|
||||||
sm.checkAccept(isa.getAddress().getHostAddress(),
|
|
||||||
isa.getPort());
|
|
||||||
} catch (SecurityException se) {
|
|
||||||
// Ignore packet
|
|
||||||
bb.clear();
|
|
||||||
n = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bb.flip();
|
|
||||||
dst.put(bb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert sender != null;
|
if (n == IOStatus.UNAVAILABLE)
|
||||||
|
return null;
|
||||||
|
completed = (n > 0) || (n == 0 && isOpen());
|
||||||
return sender;
|
return sender;
|
||||||
} finally {
|
} finally {
|
||||||
if (bb != null)
|
endRead(blocking, completed);
|
||||||
Util.releaseTemporaryDirectBuffer(bb);
|
|
||||||
endRead(blocking, n > 0);
|
|
||||||
assert IOStatus.check(n);
|
assert IOStatus.check(n);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -471,15 +460,164 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int receive(FileDescriptor fd, ByteBuffer dst, boolean connected)
|
/**
|
||||||
|
* Receives a datagram into an untrusted buffer. When there is a security
|
||||||
|
* manager set, and the socket is not connected, datagrams have to be received
|
||||||
|
* into a buffer that is not accessible to the user. The datagram is copied
|
||||||
|
* into the user's buffer when the sender address is accepted by the security
|
||||||
|
* manager.
|
||||||
|
*
|
||||||
|
* @return the size of the datagram or IOStatus.UNAVAILABLE
|
||||||
|
*/
|
||||||
|
private int untrustedReceive(ByteBuffer dst) throws IOException {
|
||||||
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
assert readLock.isHeldByCurrentThread()
|
||||||
|
&& sm != null && remoteAddress == null;
|
||||||
|
|
||||||
|
ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());
|
||||||
|
try {
|
||||||
|
boolean blocking = isBlocking();
|
||||||
|
for (;;) {
|
||||||
|
int n = receive(bb, false);
|
||||||
|
if (blocking) {
|
||||||
|
while (IOStatus.okayToRetry(n) && isOpen()) {
|
||||||
|
park(Net.POLLIN);
|
||||||
|
n = receive(bb, false);
|
||||||
|
}
|
||||||
|
} else if (n == IOStatus.UNAVAILABLE) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
InetSocketAddress isa = (InetSocketAddress) sender;
|
||||||
|
try {
|
||||||
|
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
|
||||||
|
bb.flip();
|
||||||
|
dst.put(bb);
|
||||||
|
return n;
|
||||||
|
} catch (SecurityException se) {
|
||||||
|
// ignore datagram
|
||||||
|
bb.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Util.releaseTemporaryDirectBuffer(bb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives a datagram into the given buffer.
|
||||||
|
*
|
||||||
|
* @apiNote This method is for use by the socket adaptor. The buffer is
|
||||||
|
* assumed to be trusted, meaning it is not accessible to user code.
|
||||||
|
*
|
||||||
|
* @throws IllegalBlockingModeException if the channel is non-blocking
|
||||||
|
* @throws SocketTimeoutException if the timeout elapses
|
||||||
|
*/
|
||||||
|
SocketAddress blockingReceive(ByteBuffer dst, long nanos) throws IOException {
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
ensureOpen();
|
||||||
|
if (!isBlocking())
|
||||||
|
throw new IllegalBlockingModeException();
|
||||||
|
SecurityManager sm = System.getSecurityManager();
|
||||||
|
boolean connected = isConnected();
|
||||||
|
SocketAddress sender;
|
||||||
|
do {
|
||||||
|
if (nanos > 0) {
|
||||||
|
sender = trustedBlockingReceive(dst, nanos);
|
||||||
|
} else {
|
||||||
|
sender = trustedBlockingReceive(dst);
|
||||||
|
}
|
||||||
|
// check sender when security manager set and not connected
|
||||||
|
if (sm != null && !connected) {
|
||||||
|
InetSocketAddress isa = (InetSocketAddress) sender;
|
||||||
|
try {
|
||||||
|
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
sender = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (sender == null);
|
||||||
|
return sender;
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives a datagram into given buffer. This method is used to support
|
||||||
|
* the socket adaptor. The buffer is assumed to be trusted.
|
||||||
|
* @throws SocketTimeoutException if the timeout elapses
|
||||||
|
*/
|
||||||
|
private SocketAddress trustedBlockingReceive(ByteBuffer dst)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
assert readLock.isHeldByCurrentThread() && isBlocking();
|
||||||
|
boolean completed = false;
|
||||||
|
int n = 0;
|
||||||
|
try {
|
||||||
|
SocketAddress remote = beginRead(true, false);
|
||||||
|
boolean connected = (remote != null);
|
||||||
|
n = receive(dst, connected);
|
||||||
|
while (n == IOStatus.UNAVAILABLE && isOpen()) {
|
||||||
|
park(Net.POLLIN);
|
||||||
|
n = receive(dst, connected);
|
||||||
|
}
|
||||||
|
completed = (n > 0) || (n == 0 && isOpen());
|
||||||
|
return sender;
|
||||||
|
} finally {
|
||||||
|
endRead(true, completed);
|
||||||
|
assert IOStatus.check(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives a datagram into given buffer with a timeout. This method is
|
||||||
|
* used to support the socket adaptor. The buffer is assumed to be trusted.
|
||||||
|
* @throws SocketTimeoutException if the timeout elapses
|
||||||
|
*/
|
||||||
|
private SocketAddress trustedBlockingReceive(ByteBuffer dst, long nanos)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
assert readLock.isHeldByCurrentThread() && isBlocking();
|
||||||
|
boolean completed = false;
|
||||||
|
int n = 0;
|
||||||
|
try {
|
||||||
|
SocketAddress remote = beginRead(true, false);
|
||||||
|
boolean connected = (remote != null);
|
||||||
|
|
||||||
|
// change socket to non-blocking
|
||||||
|
lockedConfigureBlocking(false);
|
||||||
|
try {
|
||||||
|
long startNanos = System.nanoTime();
|
||||||
|
n = receive(dst, connected);
|
||||||
|
while (n == IOStatus.UNAVAILABLE && isOpen()) {
|
||||||
|
long remainingNanos = nanos - (System.nanoTime() - startNanos);
|
||||||
|
if (remainingNanos <= 0) {
|
||||||
|
throw new SocketTimeoutException("Receive timed out");
|
||||||
|
}
|
||||||
|
park(Net.POLLIN, remainingNanos);
|
||||||
|
n = receive(dst, connected);
|
||||||
|
}
|
||||||
|
completed = (n > 0) || (n == 0 && isOpen());
|
||||||
|
return sender;
|
||||||
|
} finally {
|
||||||
|
// restore socket to blocking mode (if channel is open)
|
||||||
|
tryLockedConfigureBlocking(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
endRead(true, completed);
|
||||||
|
assert IOStatus.check(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int receive(ByteBuffer dst, boolean connected) throws IOException {
|
||||||
int pos = dst.position();
|
int pos = dst.position();
|
||||||
int lim = dst.limit();
|
int lim = dst.limit();
|
||||||
assert (pos <= lim);
|
assert (pos <= lim);
|
||||||
int rem = (pos <= lim ? lim - pos : 0);
|
int rem = (pos <= lim ? lim - pos : 0);
|
||||||
if (dst instanceof DirectBuffer && rem > 0)
|
if (dst instanceof DirectBuffer && rem > 0)
|
||||||
return receiveIntoNativeBuffer(fd, dst, rem, pos, connected);
|
return receiveIntoNativeBuffer(dst, rem, pos, connected);
|
||||||
|
|
||||||
// Substitute a native buffer. If the supplied buffer is empty
|
// Substitute a native buffer. If the supplied buffer is empty
|
||||||
// we must instead use a nonempty buffer, otherwise the call
|
// we must instead use a nonempty buffer, otherwise the call
|
||||||
|
@ -487,7 +625,7 @@ class DatagramChannelImpl
|
||||||
int newSize = Math.max(rem, 1);
|
int newSize = Math.max(rem, 1);
|
||||||
ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);
|
ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);
|
||||||
try {
|
try {
|
||||||
int n = receiveIntoNativeBuffer(fd, bb, newSize, 0, connected);
|
int n = receiveIntoNativeBuffer(bb, newSize, 0, connected);
|
||||||
bb.flip();
|
bb.flip();
|
||||||
if (n > 0 && rem > 0)
|
if (n > 0 && rem > 0)
|
||||||
dst.put(bb);
|
dst.put(bb);
|
||||||
|
@ -497,8 +635,8 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int receiveIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
|
private int receiveIntoNativeBuffer(ByteBuffer bb, int rem, int pos,
|
||||||
int rem, int pos, boolean connected)
|
boolean connected)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem, connected);
|
int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem, connected);
|
||||||
|
@ -563,6 +701,25 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a datagram from the bytes in given buffer.
|
||||||
|
*
|
||||||
|
* @apiNote This method is for use by the socket adaptor.
|
||||||
|
*
|
||||||
|
* @throws IllegalBlockingModeException if the channel is non-blocking
|
||||||
|
*/
|
||||||
|
void blockingSend(ByteBuffer src, SocketAddress target) throws IOException {
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
ensureOpen();
|
||||||
|
if (!isBlocking())
|
||||||
|
throw new IllegalBlockingModeException();
|
||||||
|
send(src, target);
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target)
|
private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
@ -785,10 +942,7 @@ class DatagramChannelImpl
|
||||||
try {
|
try {
|
||||||
writeLock.lock();
|
writeLock.lock();
|
||||||
try {
|
try {
|
||||||
synchronized (stateLock) {
|
lockedConfigureBlocking(block);
|
||||||
ensureOpen();
|
|
||||||
IOUtil.configureBlocking(fd, block);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
writeLock.unlock();
|
writeLock.unlock();
|
||||||
}
|
}
|
||||||
|
@ -797,6 +951,36 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the blocking mode. readLock or writeLock must already be held.
|
||||||
|
*/
|
||||||
|
private void lockedConfigureBlocking(boolean block) throws IOException {
|
||||||
|
assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
|
||||||
|
synchronized (stateLock) {
|
||||||
|
ensureOpen();
|
||||||
|
IOUtil.configureBlocking(fd, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the blocking mode if the channel is open. readLock or writeLock
|
||||||
|
* must already be held.
|
||||||
|
*
|
||||||
|
* @return {@code true} if the blocking mode was adjusted, {@code false} if
|
||||||
|
* the blocking mode was not adjusted because the channel is closed
|
||||||
|
*/
|
||||||
|
private boolean tryLockedConfigureBlocking(boolean block) throws IOException {
|
||||||
|
assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
|
||||||
|
synchronized (stateLock) {
|
||||||
|
if (isOpen()) {
|
||||||
|
IOUtil.configureBlocking(fd, block);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InetSocketAddress localAddress() {
|
InetSocketAddress localAddress() {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
return localAddress;
|
return localAddress;
|
||||||
|
@ -861,6 +1045,16 @@ class DatagramChannelImpl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DatagramChannel connect(SocketAddress sa) throws IOException {
|
public DatagramChannel connect(SocketAddress sa) throws IOException {
|
||||||
|
return connect(sa, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects the channel's socket.
|
||||||
|
*
|
||||||
|
* @param sa the remote address to which this channel is to be connected
|
||||||
|
* @param check true to check if the channel is already connected.
|
||||||
|
*/
|
||||||
|
DatagramChannel connect(SocketAddress sa, boolean check) throws IOException {
|
||||||
InetSocketAddress isa = Net.checkAddress(sa, family);
|
InetSocketAddress isa = Net.checkAddress(sa, family);
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
|
@ -879,7 +1073,7 @@ class DatagramChannelImpl
|
||||||
try {
|
try {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
if (state == ST_CONNECTED)
|
if (check && state == ST_CONNECTED)
|
||||||
throw new AlreadyConnectedException();
|
throw new AlreadyConnectedException();
|
||||||
|
|
||||||
// ensure that the socket is bound
|
// ensure that the socket is bound
|
||||||
|
@ -908,7 +1102,7 @@ class DatagramChannelImpl
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ByteBuffer buf = ByteBuffer.allocate(100);
|
ByteBuffer buf = ByteBuffer.allocate(100);
|
||||||
while (receive(fd, buf, false) > 0) {
|
while (receive(buf, false) >= 0) {
|
||||||
buf.clear();
|
buf.clear();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -1331,30 +1525,6 @@ class DatagramChannelImpl
|
||||||
return translateReadyOps(ops, 0, ski);
|
return translateReadyOps(ops, 0, ski);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Poll this channel's socket for reading up to the given timeout.
|
|
||||||
* @return {@code true} if the socket is polled
|
|
||||||
*/
|
|
||||||
boolean pollRead(long timeout) throws IOException {
|
|
||||||
boolean blocking = isBlocking();
|
|
||||||
assert Thread.holdsLock(blockingLock()) && blocking;
|
|
||||||
|
|
||||||
readLock.lock();
|
|
||||||
try {
|
|
||||||
boolean polled = false;
|
|
||||||
try {
|
|
||||||
beginRead(blocking, false);
|
|
||||||
int events = Net.poll(fd, Net.POLLIN, timeout);
|
|
||||||
polled = (events != 0);
|
|
||||||
} finally {
|
|
||||||
endRead(blocking, polled);
|
|
||||||
}
|
|
||||||
return polled;
|
|
||||||
} finally {
|
|
||||||
readLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates an interest operation set into a native poll event set
|
* Translates an interest operation set into a native poll event set
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
package sun.nio.ch;
|
package sun.nio.ch;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodHandles.Lookup;
|
||||||
|
import java.lang.invoke.VarHandle;
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
import java.net.DatagramSocketImpl;
|
import java.net.DatagramSocketImpl;
|
||||||
|
@ -35,15 +38,16 @@ import java.net.NetworkInterface;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.SocketOption;
|
import java.net.SocketOption;
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.net.StandardSocketOptions;
|
import java.net.StandardSocketOptions;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.AlreadyConnectedException;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.nio.channels.DatagramChannel;
|
import java.nio.channels.DatagramChannel;
|
||||||
import java.nio.channels.IllegalBlockingModeException;
|
import java.security.AccessController;
|
||||||
import java.util.Objects;
|
import java.security.PrivilegedAction;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
// Make a datagram-socket channel look like a datagram socket.
|
// Make a datagram-socket channel look like a datagram socket.
|
||||||
//
|
//
|
||||||
|
@ -61,13 +65,9 @@ class DatagramSocketAdaptor
|
||||||
// Timeout "option" value for receives
|
// Timeout "option" value for receives
|
||||||
private volatile int timeout;
|
private volatile int timeout;
|
||||||
|
|
||||||
// ## super will create a useless impl
|
// create DatagramSocket with useless impl
|
||||||
private DatagramSocketAdaptor(DatagramChannelImpl dc) {
|
private DatagramSocketAdaptor(DatagramChannelImpl dc) {
|
||||||
// Invoke the DatagramSocketAdaptor(SocketAddress) constructor,
|
super(new DummyDatagramSocketImpl());
|
||||||
// passing a dummy DatagramSocketImpl object to avoid any native
|
|
||||||
// resource allocation in super class and invoking our bind method
|
|
||||||
// before the dc field is initialized.
|
|
||||||
super(dummyDatagramSocket);
|
|
||||||
this.dc = dc;
|
this.dc = dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,17 +75,9 @@ class DatagramSocketAdaptor
|
||||||
return new DatagramSocketAdaptor(dc);
|
return new DatagramSocketAdaptor(dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectInternal(SocketAddress remote)
|
private void connectInternal(SocketAddress remote) throws SocketException {
|
||||||
throws SocketException
|
|
||||||
{
|
|
||||||
InetSocketAddress isa = Net.asInetSocketAddress(remote);
|
|
||||||
int port = isa.getPort();
|
|
||||||
if (port < 0 || port > 0xFFFF)
|
|
||||||
throw new IllegalArgumentException("connect: " + port);
|
|
||||||
if (remote == null)
|
|
||||||
throw new IllegalArgumentException("connect: null address");
|
|
||||||
try {
|
try {
|
||||||
dc.connect(remote);
|
dc.connect(remote, false); // skips check for already connected
|
||||||
} catch (ClosedChannelException e) {
|
} catch (ClosedChannelException e) {
|
||||||
// ignore
|
// ignore
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
|
@ -95,9 +87,12 @@ class DatagramSocketAdaptor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind(SocketAddress local) throws SocketException {
|
public void bind(SocketAddress local) throws SocketException {
|
||||||
|
if (local != null) {
|
||||||
|
local = Net.asInetSocketAddress(local);
|
||||||
|
} else {
|
||||||
|
local = new InetSocketAddress(0);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (local == null)
|
|
||||||
local = new InetSocketAddress(0);
|
|
||||||
dc.bind(local);
|
dc.bind(local);
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
Net.translateToSocketException(x);
|
Net.translateToSocketException(x);
|
||||||
|
@ -106,17 +101,20 @@ class DatagramSocketAdaptor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connect(InetAddress address, int port) {
|
public void connect(InetAddress address, int port) {
|
||||||
|
if (address == null)
|
||||||
|
throw new IllegalArgumentException("Address can't be null");
|
||||||
try {
|
try {
|
||||||
connectInternal(new InetSocketAddress(address, port));
|
connectInternal(new InetSocketAddress(address, port));
|
||||||
} catch (SocketException x) {
|
} catch (SocketException x) {
|
||||||
// Yes, j.n.DatagramSocket really does this
|
throw new Error(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connect(SocketAddress remote) throws SocketException {
|
public void connect(SocketAddress remote) throws SocketException {
|
||||||
Objects.requireNonNull(remote, "Address can't be null");
|
if (remote == null)
|
||||||
connectInternal(remote);
|
throw new IllegalArgumentException("Address can't be null");
|
||||||
|
connectInternal(Net.asInetSocketAddress(remote));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -157,80 +155,84 @@ class DatagramSocketAdaptor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SocketAddress getLocalSocketAddress() {
|
public SocketAddress getLocalSocketAddress() {
|
||||||
return dc.localAddress();
|
try {
|
||||||
|
return dc.getLocalAddress();
|
||||||
|
} catch (ClosedChannelException e) {
|
||||||
|
return null;
|
||||||
|
} catch (Exception x) {
|
||||||
|
throw new Error(x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(DatagramPacket p) throws IOException {
|
public void send(DatagramPacket p) throws IOException {
|
||||||
synchronized (dc.blockingLock()) {
|
ByteBuffer bb = null;
|
||||||
if (!dc.isBlocking())
|
try {
|
||||||
throw new IllegalBlockingModeException();
|
InetSocketAddress target;
|
||||||
try {
|
synchronized (p) {
|
||||||
synchronized (p) {
|
// copy bytes to temporary direct buffer
|
||||||
ByteBuffer bb = ByteBuffer.wrap(p.getData(),
|
int len = p.getLength();
|
||||||
p.getOffset(),
|
bb = Util.getTemporaryDirectBuffer(len);
|
||||||
p.getLength());
|
bb.put(p.getData(), p.getOffset(), len);
|
||||||
if (dc.isConnected()) {
|
bb.flip();
|
||||||
if (p.getAddress() == null) {
|
|
||||||
// Legacy DatagramSocket will send in this case
|
// target address
|
||||||
// and set address and port of the packet
|
if (p.getAddress() == null) {
|
||||||
InetSocketAddress isa = dc.remoteAddress();
|
InetSocketAddress remote = dc.remoteAddress();
|
||||||
p.setPort(isa.getPort());
|
if (remote == null) {
|
||||||
p.setAddress(isa.getAddress());
|
// not specified by DatagramSocket
|
||||||
dc.write(bb);
|
throw new IllegalArgumentException("Address not set");
|
||||||
} else {
|
|
||||||
// Target address may not match connected address
|
|
||||||
dc.send(bb, p.getSocketAddress());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Not connected so address must be valid or throw
|
|
||||||
dc.send(bb, p.getSocketAddress());
|
|
||||||
}
|
}
|
||||||
|
// set address/port to maintain compatibility with DatagramSocket
|
||||||
|
p.setAddress(remote.getAddress());
|
||||||
|
p.setPort(remote.getPort());
|
||||||
|
target = remote;
|
||||||
|
} else {
|
||||||
|
// throws IllegalArgumentException if port not set
|
||||||
|
target = (InetSocketAddress) p.getSocketAddress();
|
||||||
}
|
}
|
||||||
} catch (IOException x) {
|
|
||||||
Net.translateException(x);
|
|
||||||
}
|
}
|
||||||
}
|
// send datagram
|
||||||
}
|
try {
|
||||||
|
dc.blockingSend(bb, target);
|
||||||
private SocketAddress receive(ByteBuffer bb) throws IOException {
|
} catch (AlreadyConnectedException e) {
|
||||||
assert Thread.holdsLock(dc.blockingLock()) && dc.isBlocking();
|
throw new IllegalArgumentException("Connected and packet address differ");
|
||||||
|
} catch (ClosedChannelException e) {
|
||||||
long to = this.timeout;
|
var exc = new SocketException("Socket closed");
|
||||||
if (to == 0) {
|
exc.initCause(e);
|
||||||
return dc.receive(bb);
|
throw exc;
|
||||||
} else {
|
}
|
||||||
for (;;) {
|
} finally {
|
||||||
if (!dc.isOpen())
|
if (bb != null) {
|
||||||
throw new ClosedChannelException();
|
Util.offerFirstTemporaryDirectBuffer(bb);
|
||||||
long st = System.currentTimeMillis();
|
|
||||||
if (dc.pollRead(to)) {
|
|
||||||
return dc.receive(bb);
|
|
||||||
}
|
|
||||||
to -= System.currentTimeMillis() - st;
|
|
||||||
if (to <= 0)
|
|
||||||
throw new SocketTimeoutException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void receive(DatagramPacket p) throws IOException {
|
public void receive(DatagramPacket p) throws IOException {
|
||||||
synchronized (dc.blockingLock()) {
|
// get temporary direct buffer with a capacity of p.bufLength
|
||||||
if (!dc.isBlocking())
|
int bufLength = DatagramPackets.getBufLength(p);
|
||||||
throw new IllegalBlockingModeException();
|
ByteBuffer bb = Util.getTemporaryDirectBuffer(bufLength);
|
||||||
try {
|
try {
|
||||||
synchronized (p) {
|
long nanos = MILLISECONDS.toNanos(timeout);
|
||||||
ByteBuffer bb = ByteBuffer.wrap(p.getData(),
|
SocketAddress sender = dc.blockingReceive(bb, nanos);
|
||||||
p.getOffset(),
|
bb.flip();
|
||||||
p.getLength());
|
synchronized (p) {
|
||||||
SocketAddress sender = receive(bb);
|
// copy bytes to the DatagramPacket and set length
|
||||||
p.setSocketAddress(sender);
|
int len = Math.min(bb.limit(), DatagramPackets.getBufLength(p));
|
||||||
p.setLength(bb.position() - p.getOffset());
|
bb.get(p.getData(), p.getOffset(), len);
|
||||||
}
|
DatagramPackets.setLength(p, len);
|
||||||
} catch (IOException x) {
|
|
||||||
Net.translateException(x);
|
// sender address
|
||||||
|
p.setSocketAddress(sender);
|
||||||
}
|
}
|
||||||
|
} catch (ClosedChannelException e) {
|
||||||
|
var exc = new SocketException("Socket closed");
|
||||||
|
exc.initCause(e);
|
||||||
|
throw exc;
|
||||||
|
} finally {
|
||||||
|
Util.offerFirstTemporaryDirectBuffer(bb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,19 +259,16 @@ class DatagramSocketAdaptor
|
||||||
public int getLocalPort() {
|
public int getLocalPort() {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
return -1;
|
return -1;
|
||||||
try {
|
InetSocketAddress local = dc.localAddress();
|
||||||
InetSocketAddress local = dc.localAddress();
|
if (local != null) {
|
||||||
if (local != null) {
|
return local.getPort();
|
||||||
return local.getPort();
|
|
||||||
}
|
|
||||||
} catch (Exception x) {
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSoTimeout(int timeout) throws SocketException {
|
public void setSoTimeout(int timeout) throws SocketException {
|
||||||
if (!dc.isOpen())
|
if (isClosed())
|
||||||
throw new SocketException("Socket is closed");
|
throw new SocketException("Socket is closed");
|
||||||
if (timeout < 0)
|
if (timeout < 0)
|
||||||
throw new IllegalArgumentException("timeout < 0");
|
throw new IllegalArgumentException("timeout < 0");
|
||||||
|
@ -278,7 +277,7 @@ class DatagramSocketAdaptor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSoTimeout() throws SocketException {
|
public int getSoTimeout() throws SocketException {
|
||||||
if (!dc.isOpen())
|
if (isClosed())
|
||||||
throw new SocketException("Socket is closed");
|
throw new SocketException("Socket is closed");
|
||||||
return timeout;
|
return timeout;
|
||||||
}
|
}
|
||||||
|
@ -353,7 +352,6 @@ class DatagramSocketAdaptor
|
||||||
@Override
|
@Override
|
||||||
public boolean getReuseAddress() throws SocketException {
|
public boolean getReuseAddress() throws SocketException {
|
||||||
return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
|
return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -411,50 +409,157 @@ class DatagramSocketAdaptor
|
||||||
return dc.supportedOptions();
|
return dc.supportedOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* A dummy implementation of DatagramSocketImpl that can be passed to the
|
|
||||||
* DatagramSocket constructor so that no native resources are allocated in
|
|
||||||
* super class.
|
|
||||||
*/
|
|
||||||
private static final DatagramSocketImpl dummyDatagramSocket
|
|
||||||
= new DatagramSocketImpl()
|
|
||||||
{
|
|
||||||
protected void create() throws SocketException {}
|
|
||||||
|
|
||||||
protected void bind(int lport, InetAddress laddr) throws SocketException {}
|
/**
|
||||||
|
* DatagramSocketImpl implementation where all methods throw an error.
|
||||||
|
*/
|
||||||
|
private static class DummyDatagramSocketImpl extends DatagramSocketImpl {
|
||||||
|
private static <T> T shouldNotGetHere() {
|
||||||
|
throw new InternalError("Should not get here");
|
||||||
|
}
|
||||||
|
|
||||||
protected void send(DatagramPacket p) throws IOException {}
|
@Override
|
||||||
|
protected void create() {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected int peek(InetAddress i) throws IOException { return 0; }
|
@Override
|
||||||
|
protected void bind(int lport, InetAddress laddr) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected int peekData(DatagramPacket p) throws IOException { return 0; }
|
@Override
|
||||||
|
protected void send(DatagramPacket p) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected void receive(DatagramPacket p) throws IOException {}
|
@Override
|
||||||
|
protected int peek(InetAddress address) {
|
||||||
|
return shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Override
|
||||||
protected void setTTL(byte ttl) throws IOException {}
|
protected int peekData(DatagramPacket p) {
|
||||||
|
return shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Override
|
||||||
protected byte getTTL() throws IOException { return 0; }
|
protected void receive(DatagramPacket p) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected void setTimeToLive(int ttl) throws IOException {}
|
@Deprecated
|
||||||
|
protected void setTTL(byte ttl) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected int getTimeToLive() throws IOException { return 0;}
|
@Deprecated
|
||||||
|
protected byte getTTL() {
|
||||||
|
return shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected void join(InetAddress inetaddr) throws IOException {}
|
@Override
|
||||||
|
protected void setTimeToLive(int ttl) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected void leave(InetAddress inetaddr) throws IOException {}
|
@Override
|
||||||
|
protected int getTimeToLive() {
|
||||||
|
return shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected void joinGroup(SocketAddress mcastaddr,
|
@Override
|
||||||
NetworkInterface netIf) throws IOException {}
|
protected void join(InetAddress group) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected void leaveGroup(SocketAddress mcastaddr,
|
@Override
|
||||||
NetworkInterface netIf) throws IOException {}
|
protected void leave(InetAddress inetaddr) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
protected void close() {}
|
@Override
|
||||||
|
protected void joinGroup(SocketAddress group, NetworkInterface netIf) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
public Object getOption(int optID) throws SocketException { return null;}
|
@Override
|
||||||
|
protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
public void setOption(int optID, Object value) throws SocketException {}
|
@Override
|
||||||
};
|
protected void close() {
|
||||||
}
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getOption(int optID) {
|
||||||
|
return shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOption(int optID, Object value) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> void setOption(SocketOption<T> name, T value) {
|
||||||
|
shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> T getOption(SocketOption<T> name) {
|
||||||
|
return shouldNotGetHere();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Set<SocketOption<?>> supportedOptions() {
|
||||||
|
return shouldNotGetHere();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines static methods to get/set DatagramPacket fields and workaround
|
||||||
|
* DatagramPacket deficiencies.
|
||||||
|
*/
|
||||||
|
private static class DatagramPackets {
|
||||||
|
private static final VarHandle LENGTH;
|
||||||
|
private static final VarHandle BUF_LENGTH;
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
PrivilegedAction<Lookup> pa = () -> {
|
||||||
|
try {
|
||||||
|
return MethodHandles.privateLookupIn(DatagramPacket.class, MethodHandles.lookup());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ExceptionInInitializerError(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MethodHandles.Lookup l = AccessController.doPrivileged(pa);
|
||||||
|
LENGTH = l.findVarHandle(DatagramPacket.class, "length", int.class);
|
||||||
|
BUF_LENGTH = l.findVarHandle(DatagramPacket.class, "bufLength", int.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ExceptionInInitializerError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the DatagramPacket.length field. DatagramPacket.setLength cannot be
|
||||||
|
* used at this time because it sets both the length and bufLength fields.
|
||||||
|
*/
|
||||||
|
static void setLength(DatagramPacket p, int value) {
|
||||||
|
synchronized (p) {
|
||||||
|
LENGTH.set(p, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the DatagramPacket.bufLength field.
|
||||||
|
*/
|
||||||
|
static int getBufLength(DatagramPacket p) {
|
||||||
|
synchronized (p) {
|
||||||
|
return (int) BUF_LENGTH.get(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -22,20 +22,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* @test
|
/* @test
|
||||||
* @bug 4313882 4981129 8143610
|
* @bug 4313882 4981129 8143610 8232673
|
||||||
* @summary Unit test for datagram-socket-channel adaptors
|
* @summary Unit test for datagram-socket-channel adaptors
|
||||||
|
* @modules java.base/java.net:+open
|
||||||
* @library .. /test/lib
|
* @library .. /test/lib
|
||||||
* @build jdk.test.lib.Utils TestServers
|
* @build jdk.test.lib.Utils TestServers
|
||||||
* @run main AdaptDatagramSocket
|
* @run main AdaptorBasic
|
||||||
* @key randomness
|
* @key randomness
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
|
||||||
public class AdaptDatagramSocket {
|
public class AdaptorBasic {
|
||||||
|
|
||||||
static java.io.PrintStream out = System.out;
|
static java.io.PrintStream out = System.out;
|
||||||
static Random rand = new Random();
|
static Random rand = new Random();
|
||||||
|
@ -46,13 +48,19 @@ public class AdaptDatagramSocket {
|
||||||
+ "]");
|
+ "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test(DatagramSocket ds, InetSocketAddress dst,
|
static int getBufLength(DatagramPacket p) throws Exception {
|
||||||
boolean shouldTimeout)
|
Field f = DatagramPacket.class.getDeclaredField("bufLength");
|
||||||
|
f.setAccessible(true);
|
||||||
|
return (int) f.get(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test(DatagramSocket ds, InetSocketAddress dst, boolean shouldTimeout)
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
DatagramPacket op = new DatagramPacket(new byte[100], 13, 42, dst);
|
DatagramPacket op = new DatagramPacket(new byte[100], 13, 42, dst);
|
||||||
rand.nextBytes(op.getData());
|
rand.nextBytes(op.getData());
|
||||||
DatagramPacket ip = new DatagramPacket(new byte[100], 19, 100 - 19);
|
int bufLength = 100 - 19;
|
||||||
|
DatagramPacket ip = new DatagramPacket(new byte[100], 19, bufLength);
|
||||||
out.println("pre op: " + toString(op) + " ip: " + toString(ip));
|
out.println("pre op: " + toString(op) + " ip: " + toString(ip));
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
@ -61,10 +69,6 @@ public class AdaptDatagramSocket {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
try {
|
||||||
ds.receive(ip);
|
ds.receive(ip);
|
||||||
if (ip.getLength() == 0) { // ## Not sure why this happens
|
|
||||||
ip.setLength(100 - 19);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch (SocketTimeoutException x) {
|
} catch (SocketTimeoutException x) {
|
||||||
if (shouldTimeout) {
|
if (shouldTimeout) {
|
||||||
out.println("Receive timed out, as expected");
|
out.println("Receive timed out, as expected");
|
||||||
|
@ -88,6 +92,10 @@ public class AdaptDatagramSocket {
|
||||||
throw new Exception("Incorrect sender address, expected: " + dst
|
throw new Exception("Incorrect sender address, expected: " + dst
|
||||||
+ " actual: " + ip.getSocketAddress());
|
+ " actual: " + ip.getSocketAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getBufLength(ip) != bufLength) {
|
||||||
|
throw new Exception("DatagramPacket bufLength changed by receive!!!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test(InetSocketAddress dst,
|
static void test(InetSocketAddress dst,
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @bug 8232673
|
||||||
|
* @summary Test DatagramChannel socket adaptor with concurrent send/receive
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.channels.DatagramChannel;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
public class AdaptorConcurrentIO {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
testConcurrentSendReceive(0);
|
||||||
|
testConcurrentSendReceive(60_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a task that blocks in the adaptor's receive method, then invokes
|
||||||
|
* the adaptor's send method to send a datagram. If the adaptor were using
|
||||||
|
* the channel's blockingLock then send without be blocked waiting for
|
||||||
|
* the receive to complete.
|
||||||
|
*/
|
||||||
|
static void testConcurrentSendReceive(int timeout) throws Exception {
|
||||||
|
try (DatagramChannel dc = DatagramChannel.open()) {
|
||||||
|
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||||
|
dc.bind(new InetSocketAddress(lb, 0));
|
||||||
|
DatagramSocket s = dc.socket();
|
||||||
|
s.setSoTimeout(timeout);
|
||||||
|
|
||||||
|
ExecutorService pool = Executors.newSingleThreadExecutor();
|
||||||
|
try {
|
||||||
|
Future<String> result = pool.submit(() -> {
|
||||||
|
byte[] data = new byte[100];
|
||||||
|
DatagramPacket p = new DatagramPacket(data, 0, data.length);
|
||||||
|
s.receive(p);
|
||||||
|
return new String(p.getData(), p.getOffset(), p.getLength(), "UTF-8");
|
||||||
|
});
|
||||||
|
|
||||||
|
Thread.sleep(200); // give chance for thread to block
|
||||||
|
|
||||||
|
byte[] data = "hello".getBytes("UTF-8");
|
||||||
|
DatagramPacket p = new DatagramPacket(data, 0, data.length);
|
||||||
|
p.setSocketAddress(s.getLocalSocketAddress());
|
||||||
|
s.send(p);
|
||||||
|
|
||||||
|
String msg = result.get();
|
||||||
|
if (!msg.equals("hello"))
|
||||||
|
throw new RuntimeException("Unexpected message: " + msg);
|
||||||
|
} finally {
|
||||||
|
pool.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
117
test/jdk/java/nio/channels/DatagramChannel/AdaptorConnect.java
Normal file
117
test/jdk/java/nio/channels/DatagramChannel/AdaptorConnect.java
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @bug 8232673
|
||||||
|
* @summary Test DatagramChannel socket adaptor connect method with illegal args
|
||||||
|
* @run testng AdaptorConnect
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.nio.channels.DatagramChannel;
|
||||||
|
import static java.net.InetAddress.getLoopbackAddress;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public class AdaptorConnect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke the given socket's connect method with illegal arguments.
|
||||||
|
*/
|
||||||
|
private void testConnectWithIllegalArguments(DatagramSocket s) {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> s.connect(null));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> s.connect(null, 7000));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> s.connect(getLoopbackAddress(), -1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> s.connect(getLoopbackAddress(), 100_000));
|
||||||
|
|
||||||
|
SocketAddress sillyAddress = new SocketAddress() { };
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> s.connect(sillyAddress));
|
||||||
|
|
||||||
|
SocketAddress unresolved = InetSocketAddress.createUnresolved("foo", 7777);
|
||||||
|
assertThrows(SocketException.class, () -> s.connect(unresolved));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test connect method with an open socket.
|
||||||
|
*/
|
||||||
|
public void testOpenSocket() throws Exception {
|
||||||
|
try (DatagramChannel dc = DatagramChannel.open()) {
|
||||||
|
DatagramSocket s = dc.socket();
|
||||||
|
|
||||||
|
testConnectWithIllegalArguments(s);
|
||||||
|
|
||||||
|
// should not be bound or connected
|
||||||
|
assertTrue(s.getLocalSocketAddress() == null);
|
||||||
|
assertTrue(s.getRemoteSocketAddress() == null);
|
||||||
|
|
||||||
|
// connect(SocketAddress)
|
||||||
|
var remote1 = new InetSocketAddress(getLoopbackAddress(), 7001);
|
||||||
|
s.connect(remote1);
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remote1);
|
||||||
|
testConnectWithIllegalArguments(s);
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remote1);
|
||||||
|
|
||||||
|
// connect(SocketAddress)
|
||||||
|
var remote2 = new InetSocketAddress(getLoopbackAddress(), 7002);
|
||||||
|
s.connect(remote2);
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remote2);
|
||||||
|
testConnectWithIllegalArguments(s);
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remote2);
|
||||||
|
|
||||||
|
// connect(InetAddress, int)
|
||||||
|
var remote3 = new InetSocketAddress(getLoopbackAddress(), 7003);
|
||||||
|
s.connect(remote3.getAddress(), remote3.getPort());
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remote3);
|
||||||
|
testConnectWithIllegalArguments(s);
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remote3);
|
||||||
|
|
||||||
|
// connect(InetAddress, int)
|
||||||
|
var remote4 = new InetSocketAddress(getLoopbackAddress(), 7004);
|
||||||
|
s.connect(remote4.getAddress(), remote4.getPort());
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remote4);
|
||||||
|
testConnectWithIllegalArguments(s);
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remote4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test connect method with a closed socket.
|
||||||
|
*/
|
||||||
|
public void testClosedSocket() throws Exception {
|
||||||
|
DatagramChannel dc = DatagramChannel.open();
|
||||||
|
DatagramSocket s = dc.socket();
|
||||||
|
dc.close();
|
||||||
|
|
||||||
|
testConnectWithIllegalArguments(s);
|
||||||
|
|
||||||
|
// connect does not throw an exception when closed
|
||||||
|
var remote = new InetSocketAddress(getLoopbackAddress(), 7001);
|
||||||
|
s.connect(remote);
|
||||||
|
s.connect(remote.getAddress(), remote.getPort());
|
||||||
|
}
|
||||||
|
}
|
223
test/jdk/java/nio/channels/DatagramChannel/AdaptorGetters.java
Normal file
223
test/jdk/java/nio/channels/DatagramChannel/AdaptorGetters.java
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @bug 8232673
|
||||||
|
* @summary Test the DatagramChannel socket adaptor getter methods
|
||||||
|
* @run testng AdaptorGetters
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.channels.DatagramChannel;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public class AdaptorGetters {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getters on unbound socket, before and after it is closed.
|
||||||
|
*/
|
||||||
|
public void testUnboundSocket() throws Exception {
|
||||||
|
DatagramChannel dc = DatagramChannel.open();
|
||||||
|
DatagramSocket s = dc.socket();
|
||||||
|
try {
|
||||||
|
|
||||||
|
// state
|
||||||
|
assertFalse(s.isBound());
|
||||||
|
assertFalse(s.isConnected());
|
||||||
|
assertFalse(s.isClosed());
|
||||||
|
|
||||||
|
// local address
|
||||||
|
assertTrue(s.getLocalAddress().isAnyLocalAddress());
|
||||||
|
assertTrue(s.getLocalPort() == 0);
|
||||||
|
assertTrue(s.getLocalSocketAddress() == null);
|
||||||
|
|
||||||
|
// remote address
|
||||||
|
assertTrue(s.getInetAddress() == null);
|
||||||
|
assertTrue(s.getPort() == -1);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
dc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// state
|
||||||
|
assertFalse(s.isBound());
|
||||||
|
assertFalse(s.isConnected());
|
||||||
|
assertTrue(s.isClosed());
|
||||||
|
|
||||||
|
// local address
|
||||||
|
assertTrue(s.getLocalAddress() == null);
|
||||||
|
assertTrue(s.getLocalPort() == -1);
|
||||||
|
assertTrue(s.getLocalSocketAddress() == null);
|
||||||
|
|
||||||
|
// remote address
|
||||||
|
assertTrue(s.getInetAddress() == null);
|
||||||
|
assertTrue(s.getPort() == -1);
|
||||||
|
assertTrue((s.getRemoteSocketAddress() == null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getters on bound socket, before and after it is closed.
|
||||||
|
*/
|
||||||
|
public void testBoundSocket() throws Exception {
|
||||||
|
DatagramChannel dc = DatagramChannel.open();
|
||||||
|
DatagramSocket s = dc.socket();
|
||||||
|
try {
|
||||||
|
dc.bind(new InetSocketAddress(0));
|
||||||
|
var localAddress = (InetSocketAddress) dc.getLocalAddress();
|
||||||
|
|
||||||
|
// state
|
||||||
|
assertTrue(s.isBound());
|
||||||
|
assertFalse(s.isConnected());
|
||||||
|
assertFalse(s.isClosed());
|
||||||
|
|
||||||
|
// local address
|
||||||
|
assertEquals(s.getLocalAddress(), localAddress.getAddress());
|
||||||
|
assertTrue(s.getLocalPort() == localAddress.getPort());
|
||||||
|
assertEquals(s.getLocalSocketAddress(), localAddress);
|
||||||
|
|
||||||
|
// remote address
|
||||||
|
assertTrue(s.getInetAddress() == null);
|
||||||
|
assertTrue(s.getPort() == -1);
|
||||||
|
assertTrue((s.getRemoteSocketAddress() == null));
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
dc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// state
|
||||||
|
assertTrue(s.isBound());
|
||||||
|
assertFalse(s.isConnected());
|
||||||
|
assertTrue(s.isClosed());
|
||||||
|
|
||||||
|
// local address
|
||||||
|
assertTrue(s.getLocalAddress() == null);
|
||||||
|
assertTrue(s.getLocalPort() == -1);
|
||||||
|
assertTrue(s.getLocalSocketAddress() == null);
|
||||||
|
|
||||||
|
// remote address
|
||||||
|
assertTrue(s.getInetAddress() == null);
|
||||||
|
assertTrue(s.getPort() == -1);
|
||||||
|
assertTrue((s.getRemoteSocketAddress() == null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getters on connected socket, before and after it is closed.
|
||||||
|
*/
|
||||||
|
public void testConnectedSocket() throws Exception {
|
||||||
|
var loopback = InetAddress.getLoopbackAddress();
|
||||||
|
var remoteAddress = new InetSocketAddress(loopback, 7777);
|
||||||
|
DatagramChannel dc = DatagramChannel.open();
|
||||||
|
DatagramSocket s = dc.socket();
|
||||||
|
try {
|
||||||
|
dc.connect(remoteAddress);
|
||||||
|
var localAddress = (InetSocketAddress) dc.getLocalAddress();
|
||||||
|
|
||||||
|
// state
|
||||||
|
assertTrue(s.isBound());
|
||||||
|
assertTrue(s.isConnected());
|
||||||
|
assertFalse(s.isClosed());
|
||||||
|
|
||||||
|
// local address
|
||||||
|
assertEquals(s.getLocalAddress(), localAddress.getAddress());
|
||||||
|
assertTrue(s.getLocalPort() == localAddress.getPort());
|
||||||
|
assertEquals(s.getLocalSocketAddress(), localAddress);
|
||||||
|
|
||||||
|
// remote address
|
||||||
|
assertEquals(s.getInetAddress(), remoteAddress.getAddress());
|
||||||
|
assertTrue(s.getPort() == remoteAddress.getPort());
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remoteAddress);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
dc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// state
|
||||||
|
assertTrue(s.isBound());
|
||||||
|
assertTrue(s.isConnected());
|
||||||
|
assertTrue(s.isClosed());
|
||||||
|
|
||||||
|
// local address
|
||||||
|
assertTrue(s.getLocalAddress() == null);
|
||||||
|
assertTrue(s.getLocalPort() == -1);
|
||||||
|
assertTrue(s.getLocalSocketAddress() == null);
|
||||||
|
|
||||||
|
// remote address
|
||||||
|
assertEquals(s.getInetAddress(), remoteAddress.getAddress());
|
||||||
|
assertTrue(s.getPort() == remoteAddress.getPort());
|
||||||
|
assertEquals(s.getRemoteSocketAddress(), remoteAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getters on disconnected socket, before and after it is closed.
|
||||||
|
*/
|
||||||
|
public void testDisconnectedSocket() throws Exception {
|
||||||
|
DatagramChannel dc = DatagramChannel.open();
|
||||||
|
DatagramSocket s = dc.socket();
|
||||||
|
try {
|
||||||
|
var loopback = InetAddress.getLoopbackAddress();
|
||||||
|
dc.connect(new InetSocketAddress(loopback, 7777));
|
||||||
|
dc.disconnect();
|
||||||
|
|
||||||
|
var localAddress = (InetSocketAddress) dc.getLocalAddress();
|
||||||
|
|
||||||
|
// state
|
||||||
|
assertTrue(s.isBound());
|
||||||
|
assertFalse(s.isConnected());
|
||||||
|
assertFalse(s.isClosed());
|
||||||
|
|
||||||
|
// local address
|
||||||
|
assertEquals(s.getLocalAddress(), localAddress.getAddress());
|
||||||
|
assertTrue(s.getLocalPort() == localAddress.getPort());
|
||||||
|
assertEquals(s.getLocalSocketAddress(), localAddress);
|
||||||
|
|
||||||
|
// remote address
|
||||||
|
assertTrue(s.getInetAddress() == null);
|
||||||
|
assertTrue(s.getPort() == -1);
|
||||||
|
assertTrue((s.getRemoteSocketAddress() == null));
|
||||||
|
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
dc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// state
|
||||||
|
assertTrue(s.isBound());
|
||||||
|
assertFalse(s.isConnected());
|
||||||
|
assertTrue(s.isClosed());
|
||||||
|
|
||||||
|
// local address
|
||||||
|
assertTrue(s.getLocalAddress() == null);
|
||||||
|
assertTrue(s.getLocalPort() == -1);
|
||||||
|
assertTrue(s.getLocalSocketAddress() == null);
|
||||||
|
|
||||||
|
// remote address
|
||||||
|
assertTrue(s.getInetAddress() == null);
|
||||||
|
assertTrue(s.getPort() == -1);
|
||||||
|
assertTrue((s.getRemoteSocketAddress() == null));
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* @test
|
/* @test
|
||||||
* @bug 7184932
|
* @bug 7184932 8232673
|
||||||
* @summary Test asynchronous close and interrupt of timed socket adapter methods
|
* @summary Test asynchronous close and interrupt of timed socket adapter methods
|
||||||
* @key randomness intermittent
|
* @key randomness intermittent
|
||||||
*/
|
*/
|
||||||
|
@ -78,8 +78,10 @@ public class AdaptorCloseAndInterrupt {
|
||||||
|
|
||||||
try (DatagramChannel peer = DatagramChannel.open()) {
|
try (DatagramChannel peer = DatagramChannel.open()) {
|
||||||
peer.socket().bind(null);
|
peer.socket().bind(null);
|
||||||
new AdaptorCloseAndInterrupt(peer).dcReceiveAsyncClose();
|
new AdaptorCloseAndInterrupt(peer).dcReceiveAsyncClose(0);
|
||||||
new AdaptorCloseAndInterrupt(peer).dcReceiveAsyncInterrupt();
|
new AdaptorCloseAndInterrupt(peer).dcReceiveAsyncClose(30_000);
|
||||||
|
new AdaptorCloseAndInterrupt(peer).dcReceiveAsyncInterrupt(0);
|
||||||
|
new AdaptorCloseAndInterrupt(peer).dcReceiveAsyncInterrupt(30_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
new AdaptorCloseAndInterrupt().ssAcceptAsyncClose();
|
new AdaptorCloseAndInterrupt().ssAcceptAsyncClose();
|
||||||
|
@ -138,11 +140,10 @@ public class AdaptorCloseAndInterrupt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dcReceiveAsyncClose() throws IOException {
|
void dcReceiveAsyncClose(int timeout) throws IOException {
|
||||||
DatagramChannel dc = DatagramChannel.open();
|
DatagramChannel dc = DatagramChannel.open();
|
||||||
dc.connect(new InetSocketAddress(
|
dc.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), port));
|
||||||
InetAddress.getLoopbackAddress(), port));
|
dc.socket().setSoTimeout(timeout);
|
||||||
dc.socket().setSoTimeout(30*1000);
|
|
||||||
|
|
||||||
doAsyncClose(dc);
|
doAsyncClose(dc);
|
||||||
|
|
||||||
|
@ -150,24 +151,23 @@ public class AdaptorCloseAndInterrupt {
|
||||||
dc.socket().receive(new DatagramPacket(new byte[100], 100));
|
dc.socket().receive(new DatagramPacket(new byte[100], 100));
|
||||||
System.err.format("close() was invoked: %s%n", isClosed.get());
|
System.err.format("close() was invoked: %s%n", isClosed.get());
|
||||||
throw new RuntimeException("receive should not have completed");
|
throw new RuntimeException("receive should not have completed");
|
||||||
} catch (ClosedChannelException expected) {}
|
} catch (SocketException expected) { }
|
||||||
|
|
||||||
if (!dc.socket().isClosed())
|
if (!dc.socket().isClosed())
|
||||||
throw new RuntimeException("socket is not closed");
|
throw new RuntimeException("socket is not closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void dcReceiveAsyncInterrupt() throws IOException {
|
void dcReceiveAsyncInterrupt(int timeout) throws IOException {
|
||||||
DatagramChannel dc = DatagramChannel.open();
|
DatagramChannel dc = DatagramChannel.open();
|
||||||
dc.connect(new InetSocketAddress(
|
dc.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), port));
|
||||||
InetAddress.getLoopbackAddress(), port));
|
dc.socket().setSoTimeout(timeout);
|
||||||
dc.socket().setSoTimeout(30*1000);
|
|
||||||
|
|
||||||
doAsyncInterrupt();
|
doAsyncInterrupt();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dc.socket().receive(new DatagramPacket(new byte[100], 100));
|
dc.socket().receive(new DatagramPacket(new byte[100], 100));
|
||||||
throw new RuntimeException("receive should not have completed");
|
throw new RuntimeException("receive should not have completed");
|
||||||
} catch (ClosedByInterruptException expected) {
|
} catch (SocketException expected) {
|
||||||
System.out.format("interrupt() was invoked: %s%n",
|
System.out.format("interrupt() was invoked: %s%n",
|
||||||
isInterrupted.get());
|
isInterrupted.get());
|
||||||
System.out.format("dcReceiveAsyncInterrupt was interrupted: %s%n",
|
System.out.format("dcReceiveAsyncInterrupt was interrupted: %s%n",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue