--- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java Fri Nov 29 14:11:50 2019 -0800
+++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java Sat Nov 30 16:21:19 2019 +0000
@@ -90,12 +90,12 @@
// Our file descriptor
private final FileDescriptor fd;
private final int fdVal;
- private final Cleanable cleaner;
- // Cached InetAddress and port for unconnected DatagramChannels
- // used by receive0
- private InetAddress cachedSenderInetAddress;
- private int cachedSenderPort;
+ // Native buffer for socket address used by receive0, protected by readLock
+ private final NativeSocketAddress socketAddress;
+
+ // Cleaner to close file descriptor and free native socket address
+ private final Cleanable cleaner;
// Lock held by current reading or connecting thread
private final ReentrantLock readLock = new ReentrantLock();
@@ -154,6 +154,9 @@
throws IOException
{
super(sp);
+
+ this.socketAddress = new NativeSocketAddress();
+
ResourceManager.beforeUdpCreate();
try {
this.family = Net.isIPv6Available()
@@ -163,9 +166,12 @@
this.fdVal = IOUtil.fdVal(fd);
} catch (IOException ioe) {
ResourceManager.afterUdpClose();
+ socketAddress.free();
throw ioe;
}
- this.cleaner = CleanerFactory.cleaner().register(this, closerFor(fd));
+
+ Runnable releaser = releaserFor(fd, socketAddress);
+ this.cleaner = CleanerFactory.cleaner().register(this, releaser);
}
public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family)
@@ -183,6 +189,8 @@
}
}
+ this.socketAddress = new NativeSocketAddress();
+
ResourceManager.beforeUdpCreate();
try {
this.family = family;
@@ -190,9 +198,12 @@
this.fdVal = IOUtil.fdVal(fd);
} catch (IOException ioe) {
ResourceManager.afterUdpClose();
+ socketAddress.free();
throw ioe;
}
- this.cleaner = CleanerFactory.cleaner().register(this, closerFor(fd));
+
+ Runnable releaser = releaserFor(fd, socketAddress);
+ this.cleaner = CleanerFactory.cleaner().register(this, releaser);
}
public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
@@ -200,6 +211,13 @@
{
super(sp);
+ try {
+ this.socketAddress = new NativeSocketAddress();
+ } catch (OutOfMemoryError e) {
+ nd.close(fd);
+ throw e;
+ }
+
// increment UDP count to match decrement when closing
ResourceManager.beforeUdpCreate();
@@ -208,7 +226,10 @@
: StandardProtocolFamily.INET;
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
- this.cleaner = CleanerFactory.cleaner().register(this, closerFor(fd));
+
+ Runnable releaser = releaserFor(fd, socketAddress);
+ this.cleaner = CleanerFactory.cleaner().register(this, releaser);
+
synchronized (stateLock) {
this.localAddress = Net.localAddress(fd);
}
@@ -450,8 +471,6 @@
}
}
- private SocketAddress sender; // Set by receive0 (## ugh)
-
@Override
public SocketAddress receive(ByteBuffer dst) throws IOException {
if (dst.isReadOnly())
@@ -459,33 +478,31 @@
readLock.lock();
try {
boolean blocking = isBlocking();
- boolean completed = false;
- int n = 0;
+ SocketAddress sender = null;
try {
SocketAddress remote = beginRead(blocking, false);
boolean connected = (remote != null);
SecurityManager sm = System.getSecurityManager();
-
if (connected || (sm == null)) {
// connected or no security manager
- n = receive(dst, connected);
+ int n = receive(dst, connected);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = receive(dst, connected);
}
}
+ if (n >= 0) {
+ // sender address is in socket address buffer
+ sender = socketAddress.toInetSocketAddress();
+ }
} else {
// security manager and unconnected
- n = untrustedReceive(dst);
+ sender = untrustedReceive(dst);
}
- if (n == IOStatus.UNAVAILABLE)
- return null;
- completed = (n > 0) || (n == 0 && isOpen());
return sender;
} finally {
- endRead(blocking, completed);
- assert IOStatus.check(n);
+ endRead(blocking, (sender != null));
}
} finally {
readLock.unlock();
@@ -498,10 +515,8 @@
* 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 {
+ private SocketAddress untrustedReceive(ByteBuffer dst) throws IOException {
SecurityManager sm = System.getSecurityManager();
assert readLock.isHeldByCurrentThread()
&& sm != null && remoteAddress == null;
@@ -516,18 +531,21 @@
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();
+ if (n >= 0) {
+ // sender address is in socket address buffer
+ InetSocketAddress isa = socketAddress.toInetSocketAddress();
+ try {
+ sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
+ bb.flip();
+ dst.put(bb);
+ return isa;
+ } catch (SecurityException se) {
+ // ignore datagram
+ bb.clear();
+ }
+ } else {
+ return null;
}
}
} finally {
@@ -584,21 +602,22 @@
throws IOException
{
assert readLock.isHeldByCurrentThread() && isBlocking();
- boolean completed = false;
- int n = 0;
+ SocketAddress sender = null;
try {
SocketAddress remote = beginRead(true, false);
boolean connected = (remote != null);
- n = receive(dst, connected);
- while (n == IOStatus.UNAVAILABLE && isOpen()) {
+ int n = receive(dst, connected);
+ while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = receive(dst, connected);
}
- completed = (n > 0) || (n == 0 && isOpen());
+ if (n >= 0) {
+ // sender address is in socket address buffer
+ sender = socketAddress.toInetSocketAddress();
+ }
return sender;
} finally {
- endRead(true, completed);
- assert IOStatus.check(n);
+ endRead(true, (sender != null));
}
}
@@ -611,8 +630,7 @@
throws IOException
{
assert readLock.isHeldByCurrentThread() && isBlocking();
- boolean completed = false;
- int n = 0;
+ SocketAddress sender = null;
try {
SocketAddress remote = beginRead(true, false);
boolean connected = (remote != null);
@@ -621,7 +639,7 @@
lockedConfigureBlocking(false);
try {
long startNanos = System.nanoTime();
- n = receive(dst, connected);
+ int n = receive(dst, connected);
while (n == IOStatus.UNAVAILABLE && isOpen()) {
long remainingNanos = nanos - (System.nanoTime() - startNanos);
if (remainingNanos <= 0) {
@@ -630,16 +648,17 @@
park(Net.POLLIN, remainingNanos);
n = receive(dst, connected);
}
- completed = (n > 0) || (n == 0 && isOpen());
+ if (n >= 0) {
+ // sender address is in socket address buffer
+ sender = socketAddress.toInetSocketAddress();
+ }
return sender;
} finally {
// restore socket to blocking mode (if channel is open)
tryLockedConfigureBlocking(true);
}
-
} finally {
- endRead(true, completed);
- assert IOStatus.check(n);
+ endRead(true, (sender != null));
}
}
@@ -671,7 +690,10 @@
boolean connected)
throws IOException
{
- int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem, connected);
+ int n = receive0(fd,
+ ((DirectBuffer)bb).address() + pos, rem,
+ socketAddress.address(),
+ connected);
if (n > 0)
bb.position(pos + n);
return n;
@@ -1709,38 +1731,37 @@
}
/**
- * Returns an action to close the given file descriptor.
+ * Returns an action to release a the given file descriptor and free the
+ * given native socket address.
*/
- private static Runnable closerFor(FileDescriptor fd) {
+ private static Runnable releaserFor(FileDescriptor fd, NativeSocketAddress sa) {
return () -> {
try {
nd.close(fd);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
} finally {
- // decrement
+ // decrement socket count and release memory
ResourceManager.afterUdpClose();
+ sa.free();
}
};
}
// -- Native methods --
- private static native void initIDs();
-
private static native void disconnect0(FileDescriptor fd, boolean isIPv6)
throws IOException;
- private native int receive0(FileDescriptor fd, long address, int len,
- boolean connected)
+ private static native int receive0(FileDescriptor fd, long address, int len,
+ long senderAddress, boolean connected)
throws IOException;
- private native int send0(boolean preferIPv6, FileDescriptor fd, long address,
- int len, InetAddress addr, int port)
+ private static native int send0(boolean preferIPv6, FileDescriptor fd,
+ long address, int len, InetAddress addr, int port)
throws IOException;
static {
IOUtil.load();
- initIDs();
}
}