diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -64,7 +64,7 @@ * An implementation of SocketChannels */ -class SocketChannelImpl +public abstract class SocketChannelImpl extends SocketChannel implements SelChImpl { @@ -72,87 +72,64 @@ private static final NativeDispatcher nd = new SocketDispatcher(); // Our file descriptor object - private final FileDescriptor fd; + final FileDescriptor fd; private final int fdVal; // Lock held by current reading or connecting thread - private final ReentrantLock readLock = new ReentrantLock(); + final ReentrantLock readLock = new ReentrantLock(); // Lock held by current writing or connecting thread - private final ReentrantLock writeLock = new ReentrantLock(); + final ReentrantLock writeLock = new ReentrantLock(); // Lock held by any thread that modifies the state fields declared below // DO NOT invoke a blocking I/O operation while holding this lock! - private final Object stateLock = new Object(); + final Object stateLock = new Object(); // Input/Output closed - private volatile boolean isInputClosed; - private volatile boolean isOutputClosed; + volatile boolean isInputClosed; + volatile boolean isOutputClosed; // Connection reset protected by readLock private boolean connectionReset; // -- The following fields are protected by stateLock - // set true when exclusive binding is on and SO_REUSEADDR is emulated - private boolean isReuseAddress; - // State, increases monotonically - private static final int ST_UNCONNECTED = 0; - private static final int ST_CONNECTIONPENDING = 1; - private static final int ST_CONNECTED = 2; - private static final int ST_CLOSING = 3; - private static final int ST_CLOSED = 4; - private volatile int state; // need stateLock to change + static final int ST_UNCONNECTED = 0; + static final int ST_CONNECTIONPENDING = 1; + static final int ST_CONNECTED = 2; + static final int ST_CLOSING = 3; + static final int ST_CLOSED = 4; + volatile int state; // need stateLock to change // IDs of native threads doing reads and writes, for signalling private long readerThread; private long writerThread; // Binding - private InetSocketAddress localAddress; - private InetSocketAddress remoteAddress; + SocketAddress localAddress; + SocketAddress remoteAddress; // Socket adaptor, created on demand - private Socket socket; + Socket socket; // -- End of fields protected by stateLock // Constructor for normal connecting sockets // - SocketChannelImpl(SelectorProvider sp) throws IOException { + public SocketChannelImpl(SelectorProvider sp) throws IOException { super(sp); this.fd = Net.socket(true); this.fdVal = IOUtil.fdVal(fd); } - SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) + public SocketChannelImpl(SelectorProvider sp, FileDescriptor fd) throws IOException { super(sp); this.fd = fd; this.fdVal = IOUtil.fdVal(fd); - if (bound) { - synchronized (stateLock) { - this.localAddress = Net.localAddress(fd); - } - } - } - - // Constructor for sockets obtained from server sockets - // - SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, InetSocketAddress isa) - throws IOException - { - super(sp); - this.fd = fd; - this.fdVal = IOUtil.fdVal(fd); - synchronized (stateLock) { - this.localAddress = Net.localAddress(fd); - this.remoteAddress = isa; - this.state = ST_CONNECTED; - } } /** @@ -160,7 +137,7 @@ * * @throws ClosedChannelException if channel is closed (or closing) */ - private void ensureOpen() throws ClosedChannelException { + void ensureOpen() throws ClosedChannelException { if (!isOpen()) throw new ClosedChannelException(); } @@ -186,119 +163,6 @@ } } - @Override - public Socket socket() { - synchronized (stateLock) { - if (socket == null) - socket = SocketAdaptor.create(this); - return socket; - } - } - - @Override - public SocketAddress getLocalAddress() throws IOException { - synchronized (stateLock) { - ensureOpen(); - return Net.getRevealedLocalAddress(localAddress); - } - } - - @Override - public SocketAddress getRemoteAddress() throws IOException { - synchronized (stateLock) { - ensureOpen(); - return remoteAddress; - } - } - - @Override - public SocketChannel setOption(SocketOption name, T value) - throws IOException - { - Objects.requireNonNull(name); - if (!supportedOptions().contains(name)) - throw new UnsupportedOperationException("'" + name + "' not supported"); - if (!name.type().isInstance(value)) - throw new IllegalArgumentException("Invalid value '" + value + "'"); - - synchronized (stateLock) { - ensureOpen(); - - if (name == StandardSocketOptions.IP_TOS) { - ProtocolFamily family = Net.isIPv6Available() ? - StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; - Net.setSocketOption(fd, family, name, value); - return this; - } - - if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { - // SO_REUSEADDR emulated when using exclusive bind - isReuseAddress = (Boolean)value; - return this; - } - - // no options that require special handling - Net.setSocketOption(fd, name, value); - return this; - } - } - - @Override - @SuppressWarnings("unchecked") - public T getOption(SocketOption name) - throws IOException - { - Objects.requireNonNull(name); - if (!supportedOptions().contains(name)) - throw new UnsupportedOperationException("'" + name + "' not supported"); - - synchronized (stateLock) { - ensureOpen(); - - if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { - // SO_REUSEADDR emulated when using exclusive bind - return (T)Boolean.valueOf(isReuseAddress); - } - - // special handling for IP_TOS: always return 0 when IPv6 - if (name == StandardSocketOptions.IP_TOS) { - ProtocolFamily family = Net.isIPv6Available() ? - StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; - return (T) Net.getSocketOption(fd, family, name); - } - - // no options that require special handling - return (T) Net.getSocketOption(fd, name); - } - } - - private static class DefaultOptionsHolder { - static final Set> defaultOptions = defaultOptions(); - - private static Set> defaultOptions() { - HashSet> set = new HashSet<>(); - set.add(StandardSocketOptions.SO_SNDBUF); - set.add(StandardSocketOptions.SO_RCVBUF); - set.add(StandardSocketOptions.SO_KEEPALIVE); - set.add(StandardSocketOptions.SO_REUSEADDR); - if (Net.isReusePortAvailable()) { - set.add(StandardSocketOptions.SO_REUSEPORT); - } - set.add(StandardSocketOptions.SO_LINGER); - set.add(StandardSocketOptions.TCP_NODELAY); - // additional options required by socket adaptor - set.add(StandardSocketOptions.IP_TOS); - set.add(ExtendedSocketOption.SO_OOBINLINE); - set.addAll(ExtendedSocketOptions.clientSocketOptions()); - return Collections.unmodifiableSet(set); - } - } - - @Override - public final Set> supportedOptions() { - return DefaultOptionsHolder.defaultOptions; - } - /** * Marks the beginning of a read operation that might block. * @@ -433,7 +297,7 @@ * @throws ClosedChannelException if the channel is closed or output shutdown * @throws NotYetConnectedException if the channel is not yet connected */ - private void beginWrite(boolean blocking) throws ClosedChannelException { + void beginWrite(boolean blocking) throws ClosedChannelException { if (blocking) { // set hook for Thread.interrupt begin(); @@ -456,7 +320,7 @@ * @throws AsynchronousCloseException if the channel was closed due to this * thread being interrupted on a blocking write operation. */ - private void endWrite(boolean blocking, boolean completed) + void endWrite(boolean blocking, boolean completed) throws AsynchronousCloseException { if (blocking) { @@ -529,34 +393,6 @@ } } - /** - * Writes a byte of out of band data. - */ - int sendOutOfBandData(byte b) throws IOException { - writeLock.lock(); - try { - boolean blocking = isBlocking(); - int n = 0; - try { - beginWrite(blocking); - if (blocking) { - do { - n = Net.sendOOB(fd, b); - } while (n == IOStatus.INTERRUPTED && isOpen()); - } else { - n = Net.sendOOB(fd, b); - } - } finally { - endWrite(blocking, n > 0); - if (n <= 0 && isOutputClosed) - throw new AsynchronousCloseException(); - } - return IOStatus.normalize(n); - } finally { - writeLock.unlock(); - } - } - @Override protected void implConfigureBlocking(boolean block) throws IOException { readLock.lock(); @@ -586,7 +422,7 @@ /** * Returns the local address, or null if not bound */ - InetSocketAddress localAddress() { + SocketAddress localAddress() { synchronized (stateLock) { return localAddress; } @@ -595,44 +431,13 @@ /** * Returns the remote address, or null if not connected */ - InetSocketAddress remoteAddress() { + SocketAddress remoteAddress() { synchronized (stateLock) { return remoteAddress; } } @Override - public SocketChannel bind(SocketAddress local) throws IOException { - readLock.lock(); - try { - writeLock.lock(); - try { - synchronized (stateLock) { - ensureOpen(); - if (state == ST_CONNECTIONPENDING) - throw new ConnectionPendingException(); - if (localAddress != null) - throw new AlreadyBoundException(); - InetSocketAddress isa = (local == null) ? - new InetSocketAddress(0) : Net.checkAddress(local); - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkListen(isa.getPort()); - } - NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); - Net.bind(fd, isa.getAddress(), isa.getPort()); - localAddress = Net.localAddress(fd); - } - } finally { - writeLock.unlock(); - } - } finally { - readLock.unlock(); - } - return this; - } - - @Override public boolean isConnected() { return (state == ST_CONNECTED); } @@ -651,7 +456,7 @@ * @throws ConnectionPendingException is a connection is pending * @throws IOException if the pre-connect hook fails */ - private void beginConnect(boolean blocking, InetSocketAddress isa) + private void beginConnect(boolean blocking, SocketAddress sa) throws IOException { if (blocking) { @@ -668,9 +473,11 @@ assert state == ST_UNCONNECTED; this.state = ST_CONNECTIONPENDING; - if (localAddress == null) + if (localAddress == null && sa instanceof InetSocketAddress) { + InetSocketAddress isa = (InetSocketAddress)sa; NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort()); - remoteAddress = isa; + } + remoteAddress = sa; if (blocking) { // record thread so it can be signalled if needed @@ -686,7 +493,7 @@ * thread being interrupted on a blocking connect operation. * @throws IOException if completed and unable to obtain the local address */ - private void endConnect(boolean blocking, boolean completed) + void endConnect(boolean blocking, boolean completed) throws IOException { endRead(blocking, completed); @@ -694,7 +501,7 @@ if (completed) { synchronized (stateLock) { if (state == ST_CONNECTIONPENDING) { - localAddress = Net.localAddress(fd); + localAddress = localAddressImpl(fd); state = ST_CONNECTED; } } @@ -704,22 +511,13 @@ /** * Checks the remote address to which this channel is to be connected. */ - private InetSocketAddress checkRemote(SocketAddress sa) throws IOException { - InetSocketAddress isa = Net.checkAddress(sa); - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); - } - if (isa.getAddress().isAnyLocalAddress()) { - return new InetSocketAddress(InetAddress.getLocalHost(), isa.getPort()); - } else { - return isa; - } - } + abstract SocketAddress checkRemote(SocketAddress sa) throws IOException; + + abstract int connectImpl(FileDescriptor fd,SocketAddress sa) throws IOException; @Override public boolean connect(SocketAddress remote) throws IOException { - InetSocketAddress isa = checkRemote(remote); + SocketAddress sa = checkRemote(remote); try { readLock.lock(); try { @@ -728,8 +526,8 @@ boolean blocking = isBlocking(); boolean connected = false; try { - beginConnect(blocking, isa); - int n = Net.connect(fd, isa.getAddress(), isa.getPort()); + beginConnect(blocking, sa); + int n = connectImpl(fd, sa); if (n > 0) { connected = true; } else if (blocking) { @@ -754,7 +552,7 @@ } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, isa); + throw SocketExceptions.of(ioe, sa); } } @@ -780,6 +578,9 @@ } } + abstract SocketAddress localAddressImpl(FileDescriptor fd) + throws IOException; + /** * Marks the end of a finishConnect operation that may have blocked. * @@ -795,7 +596,7 @@ if (completed) { synchronized (stateLock) { if (state == ST_CONNECTIONPENDING) { - localAddress = Net.localAddress(fd); + localAddress = localAddressImpl(fd); state = ST_CONNECTED; } } @@ -964,6 +765,13 @@ } } + /** + * Package private version called from InheritedChannel + */ + void localImplCloseSelectableChannel() throws IOException { + implCloseSelectableChannel(); + } + @Override public SocketChannel shutdownInput() throws IOException { synchronized (stateLock) { @@ -1034,7 +842,7 @@ * @throws SocketTimeoutException if the read timeout elapses */ void blockingConnect(SocketAddress remote, long nanos) throws IOException { - InetSocketAddress isa = checkRemote(remote); + SocketAddress sa = checkRemote(remote); try { readLock.lock(); try { @@ -1044,11 +852,11 @@ throw new IllegalBlockingModeException(); boolean connected = false; try { - beginConnect(true, isa); + beginConnect(true, sa); // change socket to non-blocking lockedConfigureBlocking(false); try { - int n = Net.connect(fd, isa.getAddress(), isa.getPort()); + int n = connectImpl(fd, sa); connected = (n > 0) ? true : finishTimedConnect(nanos); } finally { // restore socket to blocking mode @@ -1066,7 +874,7 @@ } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, isa); + throw SocketExceptions.of(ioe, sa); } } @@ -1309,6 +1117,8 @@ return fdVal; } + abstract String getRevealedLocalAddressAsString(SocketAddress sa); + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -1333,10 +1143,10 @@ sb.append(" oshut"); break; } - InetSocketAddress addr = localAddress(); + SocketAddress addr = localAddress(); if (addr != null) { sb.append(" local="); - sb.append(Net.getRevealedLocalAddressAsString(addr)); + sb.append(getRevealedLocalAddressAsString(addr)); } if (remoteAddress() != null) { sb.append(" remote=");