OpenJDK / loom / loom
changeset 53339:cca90c36707e fibers
Fix corner cases with SO_REUSEADDR and SO_LINGER socket options
author | alanb |
---|---|
date | Wed, 16 Jan 2019 18:15:25 +0000 |
parents | f28d2ea795b3 |
children | bb0fa35e3427 |
files | src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java |
diffstat | 1 files changed, 41 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java Mon Jan 14 19:19:10 2019 +0000 +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java Wed Jan 16 18:15:25 2019 +0000 @@ -120,8 +120,11 @@ private long readerThread; private long writerThread; - // read or accept timeout in millis, protected by stateLock - private int timeout; + // true is SO_REUSEADDR is emulated + private boolean isReuseAddress; + + // read or accept timeout in millis + private volatile int timeout; // flags to indicate if the connection is shutdown for input and output private volatile boolean isInputClosed; @@ -590,10 +593,11 @@ throw new SocketException("Already bound"); NetHooks.beforeTcpBind(fd, host, port); Net.bind(fd, host, port); - InetSocketAddress localAddress = Net.localAddress(fd); - - address = localAddress.getAddress(); - localport = localAddress.getPort(); + // set the address field to the address specified to the method to + // keep compatibility with PlainSocketImpl. When binding to 0.0.0.0 + // then the actual local address will be ::0 when IPv6 is enabled. + address = host; + localport = Net.localAddress(fd).getPort(); } } @@ -812,6 +816,14 @@ this.state = ST_CLOSING; assert fd != null && closer != null; + // shutdown output when linger interval not set + try { + var SO_LINGER = StandardSocketOptions.SO_LINGER; + if ((int) Net.getSocketOption(fd, Net.UNSPEC, SO_LINGER) != 0) { + Net.shutdown(fd, Net.SHUT_WR); + } + } catch (IOException ignore) { } + // unpark and wait for fibers to complete I/O operations if (NativeThread.isFiber(readerThread) || NativeThread.isFiber(writerThread)) { @@ -894,8 +906,11 @@ case SO_LINGER: { int i; if (value instanceof Boolean) { - // maintain compatibility with PlainSocketImpl - i = 0; + boolean b = booleanValue(value, "SO_LINGER"); + if (b) { + throw new IllegalArgumentException("SO_LINGER not be set to true"); + } + i = -1; } else { i = intValue(value, "SO_LINGER"); } @@ -941,7 +956,11 @@ } case SO_REUSEADDR: { boolean b = booleanValue(value, "SO_REUSEADDR"); - Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_REUSEADDR, b); + if (Net.useExclusiveBind()) { + isReuseAddress = b; + } else { + Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_REUSEADDR, b); + } break; } case SO_REUSEPORT: { @@ -972,10 +991,20 @@ return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.TCP_NODELAY); case SO_OOBINLINE: return Net.getSocketOption(fd, Net.UNSPEC, ExtendedSocketOption.SO_OOBINLINE); - case SO_LINGER: - return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_LINGER); + case SO_LINGER: { + int i = (int) Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_LINGER); + if (i == -1) { + return Boolean.FALSE; + } else { + return i; + } + } case SO_REUSEADDR: - return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_REUSEADDR); + if (Net.useExclusiveBind()) { + return isReuseAddress; + } else { + return Net.getSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_REUSEADDR); + } case SO_BINDADDR: return Net.localAddress(fd).getAddress(); case SO_SNDBUF: