diff -r f280911d3427 -r 289000934908 src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java --- 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(); } }