Path: blob/master/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
41159 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.io.FileDescriptor;28import java.io.IOException;29import java.io.InputStream;30import java.io.OutputStream;31import java.io.UncheckedIOException;32import java.lang.ref.Cleaner.Cleanable;33import java.net.InetAddress;34import java.net.InetSocketAddress;35import java.net.ProtocolFamily;36import java.net.SocketAddress;37import java.net.SocketException;38import java.net.SocketImpl;39import java.net.SocketOption;40import java.net.SocketTimeoutException;41import java.net.StandardProtocolFamily;42import java.net.StandardSocketOptions;43import java.net.UnknownHostException;44import java.nio.ByteBuffer;45import java.util.Collections;46import java.util.HashSet;47import java.util.Objects;48import java.util.Set;49import java.util.concurrent.TimeUnit;50import java.util.concurrent.locks.ReentrantLock;5152import jdk.internal.ref.CleanerFactory;53import sun.net.ConnectionResetException;54import sun.net.NetHooks;55import sun.net.PlatformSocketImpl;56import sun.net.ResourceManager;57import sun.net.ext.ExtendedSocketOptions;58import sun.net.util.SocketExceptions;5960import static java.util.concurrent.TimeUnit.MILLISECONDS;61import static java.util.concurrent.TimeUnit.NANOSECONDS;6263/**64* NIO based SocketImpl.65*66* This implementation attempts to be compatible with legacy PlainSocketImpl,67* including behavior and exceptions that are not specified by SocketImpl.68*69* The underlying socket used by this SocketImpl is initially configured70* blocking. If the connect method is used to establish a connection with a71* timeout then the socket is configured non-blocking for the connect attempt,72* and then restored to blocking mode when the connection is established.73* If the accept or read methods are used with a timeout then the socket is74* configured non-blocking and is never restored. When in non-blocking mode,75* operations that don't complete immediately will poll the socket and preserve76* the semantics of blocking operations.77*/7879public final class NioSocketImpl extends SocketImpl implements PlatformSocketImpl {80private static final NativeDispatcher nd = new SocketDispatcher();8182// The maximum number of bytes to read/write per syscall to avoid needing83// a huge buffer from the temporary buffer cache84private static final int MAX_BUFFER_SIZE = 128 * 1024;8586// true if this is a SocketImpl for a ServerSocket87private final boolean server;8889// Lock held when reading (also used when accepting or connecting)90private final ReentrantLock readLock = new ReentrantLock();9192// Lock held when writing93private final ReentrantLock writeLock = new ReentrantLock();9495// The stateLock for read/changing state96private final Object stateLock = new Object();97private static final int ST_NEW = 0;98private static final int ST_UNCONNECTED = 1;99private static final int ST_CONNECTING = 2;100private static final int ST_CONNECTED = 3;101private static final int ST_CLOSING = 4;102private static final int ST_CLOSED = 5;103private volatile int state; // need stateLock to change104105// set by SocketImpl.create, protected by stateLock106private boolean stream;107private Cleanable cleaner;108109// set to true when the socket is in non-blocking mode110private volatile boolean nonBlocking;111112// used by connect/read/write/accept, protected by stateLock113private long readerThread;114private long writerThread;115116// used when SO_REUSEADDR is emulated, protected by stateLock117private boolean isReuseAddress;118119// read or accept timeout in millis120private volatile int timeout;121122// flags to indicate if the connection is shutdown for input and output123private volatile boolean isInputClosed;124private volatile boolean isOutputClosed;125126// used by read to emulate legacy behavior, protected by readLock127private boolean readEOF;128private boolean connectionReset;129130/**131* Creates an instance of this SocketImpl.132* @param server true if this is a SocketImpl for a ServerSocket133*/134public NioSocketImpl(boolean server) {135this.server = server;136}137138/**139* Returns true if the socket is open.140*/141private boolean isOpen() {142return state < ST_CLOSING;143}144145/**146* Throws SocketException if the socket is not open.147*/148private void ensureOpen() throws SocketException {149int state = this.state;150if (state == ST_NEW)151throw new SocketException("Socket not created");152if (state >= ST_CLOSING)153throw new SocketException("Socket closed");154}155156/**157* Throws SocketException if the socket is not open and connected.158*/159private void ensureOpenAndConnected() throws SocketException {160int state = this.state;161if (state < ST_CONNECTED)162throw new SocketException("Not connected");163if (state > ST_CONNECTED)164throw new SocketException("Socket closed");165}166167/**168* Disables the current thread for scheduling purposes until the socket is169* ready for I/O, or is asynchronously closed, for up to the specified170* waiting time.171* @throws IOException if an I/O error occurs172*/173private void park(FileDescriptor fd, int event, long nanos) throws IOException {174long millis;175if (nanos == 0) {176millis = -1;177} else {178millis = NANOSECONDS.toMillis(nanos);179}180Net.poll(fd, event, millis);181}182183/**184* Disables the current thread for scheduling purposes until the socket is185* ready for I/O or is asynchronously closed.186* @throws IOException if an I/O error occurs187*/188private void park(FileDescriptor fd, int event) throws IOException {189park(fd, event, 0);190}191192/**193* Configures the socket to blocking mode. This method is a no-op if the194* socket is already in blocking mode.195* @throws IOException if closed or there is an I/O error changing the mode196*/197private void configureBlocking(FileDescriptor fd) throws IOException {198assert readLock.isHeldByCurrentThread();199if (nonBlocking) {200synchronized (stateLock) {201ensureOpen();202IOUtil.configureBlocking(fd, true);203nonBlocking = false;204}205}206}207208/**209* Configures the socket to non-blocking mode. This method is a no-op if the210* socket is already in non-blocking mode.211* @throws IOException if closed or there is an I/O error changing the mode212*/213private void configureNonBlocking(FileDescriptor fd) throws IOException {214assert readLock.isHeldByCurrentThread();215if (!nonBlocking) {216synchronized (stateLock) {217ensureOpen();218IOUtil.configureBlocking(fd, false);219nonBlocking = true;220}221}222}223224/**225* Marks the beginning of a read operation that might block.226* @throws SocketException if the socket is closed or not connected227*/228private FileDescriptor beginRead() throws SocketException {229synchronized (stateLock) {230ensureOpenAndConnected();231readerThread = NativeThread.current();232return fd;233}234}235236/**237* Marks the end of a read operation that may have blocked.238* @throws SocketException is the socket is closed239*/240private void endRead(boolean completed) throws SocketException {241synchronized (stateLock) {242readerThread = 0;243int state = this.state;244if (state == ST_CLOSING)245tryFinishClose();246if (!completed && state >= ST_CLOSING)247throw new SocketException("Socket closed");248}249}250251/**252* Attempts to read bytes from the socket into the given byte array.253*/254private int tryRead(FileDescriptor fd, byte[] b, int off, int len)255throws IOException256{257ByteBuffer dst = Util.getTemporaryDirectBuffer(len);258assert dst.position() == 0;259try {260int n = nd.read(fd, ((DirectBuffer)dst).address(), len);261if (n > 0) {262dst.get(b, off, n);263}264return n;265} finally {266Util.offerFirstTemporaryDirectBuffer(dst);267}268}269270/**271* Reads bytes from the socket into the given byte array with a timeout.272* @throws SocketTimeoutException if the read timeout elapses273*/274private int timedRead(FileDescriptor fd, byte[] b, int off, int len, long nanos)275throws IOException276{277long startNanos = System.nanoTime();278int n = tryRead(fd, b, off, len);279while (n == IOStatus.UNAVAILABLE && isOpen()) {280long remainingNanos = nanos - (System.nanoTime() - startNanos);281if (remainingNanos <= 0) {282throw new SocketTimeoutException("Read timed out");283}284park(fd, Net.POLLIN, remainingNanos);285n = tryRead(fd, b, off, len);286}287return n;288}289290/**291* Reads bytes from the socket into the given byte array.292* @return the number of bytes read or -1 at EOF293* @throws SocketException if the socket is closed or a socket I/O error occurs294* @throws SocketTimeoutException if the read timeout elapses295*/296private int implRead(byte[] b, int off, int len) throws IOException {297int n = 0;298FileDescriptor fd = beginRead();299try {300if (connectionReset)301throw new SocketException("Connection reset");302if (isInputClosed)303return -1;304int timeout = this.timeout;305if (timeout > 0) {306// read with timeout307configureNonBlocking(fd);308n = timedRead(fd, b, off, len, MILLISECONDS.toNanos(timeout));309} else {310// read, no timeout311n = tryRead(fd, b, off, len);312while (IOStatus.okayToRetry(n) && isOpen()) {313park(fd, Net.POLLIN);314n = tryRead(fd, b, off, len);315}316}317return n;318} catch (SocketTimeoutException e) {319throw e;320} catch (ConnectionResetException e) {321connectionReset = true;322throw new SocketException("Connection reset");323} catch (IOException ioe) {324throw new SocketException(ioe.getMessage());325} finally {326endRead(n > 0);327}328}329330/**331* Reads bytes from the socket into the given byte array.332* @return the number of bytes read or -1 at EOF333* @throws IndexOutOfBoundsException if the bound checks fail334* @throws SocketException if the socket is closed or a socket I/O error occurs335* @throws SocketTimeoutException if the read timeout elapses336*/337private int read(byte[] b, int off, int len) throws IOException {338Objects.checkFromIndexSize(off, len, b.length);339if (len == 0) {340return 0;341} else {342readLock.lock();343try {344// emulate legacy behavior to return -1, even if socket is closed345if (readEOF)346return -1;347// read up to MAX_BUFFER_SIZE bytes348int size = Math.min(len, MAX_BUFFER_SIZE);349int n = implRead(b, off, size);350if (n == -1)351readEOF = true;352return n;353} finally {354readLock.unlock();355}356}357}358359/**360* Marks the beginning of a write operation that might block.361* @throws SocketException if the socket is closed or not connected362*/363private FileDescriptor beginWrite() throws SocketException {364synchronized (stateLock) {365ensureOpenAndConnected();366writerThread = NativeThread.current();367return fd;368}369}370371/**372* Marks the end of a write operation that may have blocked.373* @throws SocketException is the socket is closed374*/375private void endWrite(boolean completed) throws SocketException {376synchronized (stateLock) {377writerThread = 0;378int state = this.state;379if (state == ST_CLOSING)380tryFinishClose();381if (!completed && state >= ST_CLOSING)382throw new SocketException("Socket closed");383}384}385386/**387* Attempts to write a sequence of bytes to the socket from the given388* byte array.389*/390private int tryWrite(FileDescriptor fd, byte[] b, int off, int len)391throws IOException392{393ByteBuffer src = Util.getTemporaryDirectBuffer(len);394assert src.position() == 0;395try {396src.put(b, off, len);397return nd.write(fd, ((DirectBuffer)src).address(), len);398} finally {399Util.offerFirstTemporaryDirectBuffer(src);400}401}402403/**404* Writes a sequence of bytes to the socket from the given byte array.405* @return the number of bytes written406* @throws SocketException if the socket is closed or a socket I/O error occurs407*/408private int implWrite(byte[] b, int off, int len) throws IOException {409int n = 0;410FileDescriptor fd = beginWrite();411try {412n = tryWrite(fd, b, off, len);413while (IOStatus.okayToRetry(n) && isOpen()) {414park(fd, Net.POLLOUT);415n = tryWrite(fd, b, off, len);416}417return n;418} catch (IOException ioe) {419throw new SocketException(ioe.getMessage());420} finally {421endWrite(n > 0);422}423}424425/**426* Writes a sequence of bytes to the socket from the given byte array.427* @throws SocketException if the socket is closed or a socket I/O error occurs428*/429private void write(byte[] b, int off, int len) throws IOException {430Objects.checkFromIndexSize(off, len, b.length);431if (len > 0) {432writeLock.lock();433try {434int pos = off;435int end = off + len;436while (pos < end) {437// write up to MAX_BUFFER_SIZE bytes438int size = Math.min((end - pos), MAX_BUFFER_SIZE);439int n = implWrite(b, pos, size);440pos += n;441}442} finally {443writeLock.unlock();444}445}446}447448/**449* Creates the socket.450* @param stream {@code true} for a streams socket451*/452@Override453protected void create(boolean stream) throws IOException {454synchronized (stateLock) {455if (state != ST_NEW)456throw new IOException("Already created");457if (!stream)458ResourceManager.beforeUdpCreate();459FileDescriptor fd;460try {461if (server) {462assert stream;463fd = Net.serverSocket(true);464} else {465fd = Net.socket(stream);466}467} catch (IOException ioe) {468if (!stream)469ResourceManager.afterUdpClose();470throw ioe;471}472Runnable closer = closerFor(fd, stream);473this.fd = fd;474this.stream = stream;475this.cleaner = CleanerFactory.cleaner().register(this, closer);476this.state = ST_UNCONNECTED;477}478}479480/**481* Marks the beginning of a connect operation that might block.482* @throws SocketException if the socket is closed or already connected483*/484private FileDescriptor beginConnect(InetAddress address, int port)485throws IOException486{487synchronized (stateLock) {488int state = this.state;489if (state != ST_UNCONNECTED) {490if (state == ST_NEW)491throw new SocketException("Not created");492if (state == ST_CONNECTING)493throw new SocketException("Connection in progress");494if (state == ST_CONNECTED)495throw new SocketException("Already connected");496if (state >= ST_CLOSING)497throw new SocketException("Socket closed");498assert false;499}500this.state = ST_CONNECTING;501502// invoke beforeTcpConnect hook if not already bound503if (localport == 0) {504NetHooks.beforeTcpConnect(fd, address, port);505}506507// save the remote address/port508this.address = address;509this.port = port;510511readerThread = NativeThread.current();512return fd;513}514}515516/**517* Marks the end of a connect operation that may have blocked.518* @throws SocketException is the socket is closed519*/520private void endConnect(FileDescriptor fd, boolean completed) throws IOException {521synchronized (stateLock) {522readerThread = 0;523int state = this.state;524if (state == ST_CLOSING)525tryFinishClose();526if (completed && state == ST_CONNECTING) {527this.state = ST_CONNECTED;528localport = Net.localAddress(fd).getPort();529} else if (!completed && state >= ST_CLOSING) {530throw new SocketException("Socket closed");531}532}533}534535/**536* Waits for a connection attempt to finish with a timeout537* @throws SocketTimeoutException if the connect timeout elapses538*/539private boolean timedFinishConnect(FileDescriptor fd, long nanos) throws IOException {540long startNanos = System.nanoTime();541boolean polled = Net.pollConnectNow(fd);542while (!polled && isOpen()) {543long remainingNanos = nanos - (System.nanoTime() - startNanos);544if (remainingNanos <= 0) {545throw new SocketTimeoutException("Connect timed out");546}547park(fd, Net.POLLOUT, remainingNanos);548polled = Net.pollConnectNow(fd);549}550return polled && isOpen();551}552553/**554* Attempts to establish a connection to the given socket address with a555* timeout. Closes the socket if connection cannot be established.556* @throws IOException if the address is not a resolved InetSocketAddress or557* the connection cannot be established558*/559@Override560protected void connect(SocketAddress remote, int millis) throws IOException {561// SocketImpl connect only specifies IOException562if (!(remote instanceof InetSocketAddress))563throw new IOException("Unsupported address type");564InetSocketAddress isa = (InetSocketAddress) remote;565if (isa.isUnresolved()) {566throw new UnknownHostException(isa.getHostName());567}568569InetAddress address = isa.getAddress();570if (address.isAnyLocalAddress())571address = InetAddress.getLocalHost();572int port = isa.getPort();573574ReentrantLock connectLock = readLock;575try {576connectLock.lock();577try {578boolean connected = false;579FileDescriptor fd = beginConnect(address, port);580try {581582// configure socket to non-blocking mode when there is a timeout583if (millis > 0) {584configureNonBlocking(fd);585}586587int n = Net.connect(fd, address, port);588if (n > 0) {589// connection established590connected = true;591} else {592assert IOStatus.okayToRetry(n);593if (millis > 0) {594// finish connect with timeout595long nanos = MILLISECONDS.toNanos(millis);596connected = timedFinishConnect(fd, nanos);597} else {598// finish connect, no timeout599boolean polled = false;600while (!polled && isOpen()) {601park(fd, Net.POLLOUT);602polled = Net.pollConnectNow(fd);603}604connected = polled && isOpen();605}606}607608// restore socket to blocking mode609if (connected && millis > 0) {610configureBlocking(fd);611}612613} finally {614endConnect(fd, connected);615}616} finally {617connectLock.unlock();618}619} catch (IOException ioe) {620close();621throw SocketExceptions.of(ioe, isa);622}623}624625@Override626protected void connect(String host, int port) throws IOException {627connect(new InetSocketAddress(host, port), 0);628}629630@Override631protected void connect(InetAddress address, int port) throws IOException {632connect(new InetSocketAddress(address, port), 0);633}634635@Override636protected void bind(InetAddress host, int port) throws IOException {637synchronized (stateLock) {638ensureOpen();639if (localport != 0)640throw new SocketException("Already bound");641NetHooks.beforeTcpBind(fd, host, port);642Net.bind(fd, host, port);643// set the address field to the given host address to keep644// compatibility with PlainSocketImpl. When binding to 0.0.0.0645// then the actual local address will be ::0 when IPv6 is enabled.646address = host;647localport = Net.localAddress(fd).getPort();648}649}650651@Override652protected void listen(int backlog) throws IOException {653synchronized (stateLock) {654ensureOpen();655if (localport == 0)656throw new SocketException("Not bound");657Net.listen(fd, backlog < 1 ? 50 : backlog);658}659}660661/**662* Marks the beginning of an accept operation that might block.663* @throws SocketException if the socket is closed664*/665private FileDescriptor beginAccept() throws SocketException {666synchronized (stateLock) {667ensureOpen();668if (!stream)669throw new SocketException("Not a stream socket");670if (localport == 0)671throw new SocketException("Not bound");672readerThread = NativeThread.current();673return fd;674}675}676677/**678* Marks the end of an accept operation that may have blocked.679* @throws SocketException is the socket is closed680*/681private void endAccept(boolean completed) throws SocketException {682synchronized (stateLock) {683int state = this.state;684readerThread = 0;685if (state == ST_CLOSING)686tryFinishClose();687if (!completed && state >= ST_CLOSING)688throw new SocketException("Socket closed");689}690}691692/**693* Accepts a new connection with a timeout.694* @throws SocketTimeoutException if the accept timeout elapses695*/696private int timedAccept(FileDescriptor fd,697FileDescriptor newfd,698InetSocketAddress[] isaa,699long nanos)700throws IOException701{702long startNanos = System.nanoTime();703int n = Net.accept(fd, newfd, isaa);704while (n == IOStatus.UNAVAILABLE && isOpen()) {705long remainingNanos = nanos - (System.nanoTime() - startNanos);706if (remainingNanos <= 0) {707throw new SocketTimeoutException("Accept timed out");708}709park(fd, Net.POLLIN, remainingNanos);710n = Net.accept(fd, newfd, isaa);711}712return n;713}714715/**716* Accepts a new connection so that the given SocketImpl is connected to717* the peer. The SocketImpl must be a newly created NioSocketImpl.718*/719@Override720protected void accept(SocketImpl si) throws IOException {721NioSocketImpl nsi = (NioSocketImpl) si;722if (nsi.state != ST_NEW)723throw new SocketException("Not a newly created SocketImpl");724725FileDescriptor newfd = new FileDescriptor();726InetSocketAddress[] isaa = new InetSocketAddress[1];727728// acquire the lock, adjusting the timeout for cases where several729// threads are accepting connections and there is a timeout set730ReentrantLock acceptLock = readLock;731int timeout = this.timeout;732long remainingNanos = 0;733if (timeout > 0) {734remainingNanos = tryLock(acceptLock, timeout, MILLISECONDS);735if (remainingNanos <= 0) {736assert !acceptLock.isHeldByCurrentThread();737throw new SocketTimeoutException("Accept timed out");738}739} else {740acceptLock.lock();741}742743// accept a connection744try {745int n = 0;746FileDescriptor fd = beginAccept();747try {748if (remainingNanos > 0) {749// accept with timeout750configureNonBlocking(fd);751n = timedAccept(fd, newfd, isaa, remainingNanos);752} else {753// accept, no timeout754n = Net.accept(fd, newfd, isaa);755while (IOStatus.okayToRetry(n) && isOpen()) {756park(fd, Net.POLLIN);757n = Net.accept(fd, newfd, isaa);758}759}760} finally {761endAccept(n > 0);762assert IOStatus.check(n);763}764} finally {765acceptLock.unlock();766}767768// get local address and configure accepted socket to blocking mode769InetSocketAddress localAddress;770try {771localAddress = Net.localAddress(newfd);772IOUtil.configureBlocking(newfd, true);773} catch (IOException ioe) {774nd.close(newfd);775throw ioe;776}777778// set the fields779Runnable closer = closerFor(newfd, true);780synchronized (nsi.stateLock) {781nsi.fd = newfd;782nsi.stream = true;783nsi.cleaner = CleanerFactory.cleaner().register(nsi, closer);784nsi.localport = localAddress.getPort();785nsi.address = isaa[0].getAddress();786nsi.port = isaa[0].getPort();787nsi.state = ST_CONNECTED;788}789}790791@Override792protected InputStream getInputStream() {793return new InputStream() {794@Override795public int read() throws IOException {796byte[] a = new byte[1];797int n = read(a, 0, 1);798return (n > 0) ? (a[0] & 0xff) : -1;799}800@Override801public int read(byte[] b, int off, int len) throws IOException {802return NioSocketImpl.this.read(b, off, len);803}804@Override805public int available() throws IOException {806return NioSocketImpl.this.available();807}808@Override809public void close() throws IOException {810NioSocketImpl.this.close();811}812};813}814815@Override816protected OutputStream getOutputStream() {817return new OutputStream() {818@Override819public void write(int b) throws IOException {820byte[] a = new byte[]{(byte) b};821write(a, 0, 1);822}823@Override824public void write(byte[] b, int off, int len) throws IOException {825NioSocketImpl.this.write(b, off, len);826}827@Override828public void close() throws IOException {829NioSocketImpl.this.close();830}831};832}833834@Override835protected int available() throws IOException {836synchronized (stateLock) {837ensureOpenAndConnected();838if (isInputClosed) {839return 0;840} else {841return Net.available(fd);842}843}844}845846/**847* Closes the socket if there are no I/O operations in progress.848*/849private boolean tryClose() throws IOException {850assert Thread.holdsLock(stateLock) && state == ST_CLOSING;851if (readerThread == 0 && writerThread == 0) {852try {853cleaner.clean();854} catch (UncheckedIOException ioe) {855throw ioe.getCause();856} finally {857state = ST_CLOSED;858}859return true;860} else {861return false;862}863}864865/**866* Invokes tryClose to attempt to close the socket.867*868* This method is used for deferred closing by I/O operations.869*/870private void tryFinishClose() {871try {872tryClose();873} catch (IOException ignore) { }874}875876/**877* Closes the socket. If there are I/O operations in progress then the878* socket is pre-closed and the threads are signalled. The socket will be879* closed when the last I/O operation aborts.880*/881@Override882protected void close() throws IOException {883synchronized (stateLock) {884int state = this.state;885if (state >= ST_CLOSING)886return;887if (state == ST_NEW) {888// stillborn889this.state = ST_CLOSED;890return;891}892this.state = ST_CLOSING;893894// shutdown output when linger interval not set to 0895try {896var SO_LINGER = StandardSocketOptions.SO_LINGER;897if ((int) Net.getSocketOption(fd, SO_LINGER) != 0) {898Net.shutdown(fd, Net.SHUT_WR);899}900} catch (IOException ignore) { }901902// attempt to close the socket. If there are I/O operations in progress903// then the socket is pre-closed and the thread(s) signalled. The904// last thread will close the file descriptor.905if (!tryClose()) {906nd.preClose(fd);907long reader = readerThread;908if (reader != 0)909NativeThread.signal(reader);910long writer = writerThread;911if (writer != 0)912NativeThread.signal(writer);913}914}915}916917// the socket options supported by client and server sockets918private static volatile Set<SocketOption<?>> clientSocketOptions;919private static volatile Set<SocketOption<?>> serverSocketOptions;920921@Override922protected Set<SocketOption<?>> supportedOptions() {923Set<SocketOption<?>> options = (server) ? serverSocketOptions : clientSocketOptions;924if (options == null) {925options = new HashSet<>();926options.add(StandardSocketOptions.SO_RCVBUF);927options.add(StandardSocketOptions.SO_REUSEADDR);928if (server) {929// IP_TOS added for server socket to maintain compatibility930options.add(StandardSocketOptions.IP_TOS);931options.addAll(ExtendedSocketOptions.serverSocketOptions());932} else {933options.add(StandardSocketOptions.IP_TOS);934options.add(StandardSocketOptions.SO_KEEPALIVE);935options.add(StandardSocketOptions.SO_SNDBUF);936options.add(StandardSocketOptions.SO_LINGER);937options.add(StandardSocketOptions.TCP_NODELAY);938options.addAll(ExtendedSocketOptions.clientSocketOptions());939}940if (Net.isReusePortAvailable())941options.add(StandardSocketOptions.SO_REUSEPORT);942options = Collections.unmodifiableSet(options);943if (server) {944serverSocketOptions = options;945} else {946clientSocketOptions = options;947}948}949return options;950}951952@Override953protected <T> void setOption(SocketOption<T> opt, T value) throws IOException {954if (!supportedOptions().contains(opt))955throw new UnsupportedOperationException("'" + opt + "' not supported");956if (!opt.type().isInstance(value))957throw new IllegalArgumentException("Invalid value '" + value + "'");958synchronized (stateLock) {959ensureOpen();960if (opt == StandardSocketOptions.IP_TOS) {961// maps to IP_TOS or IPV6_TCLASS962Net.setSocketOption(fd, family(), opt, value);963} else if (opt == StandardSocketOptions.SO_REUSEADDR) {964boolean b = (boolean) value;965if (Net.useExclusiveBind()) {966isReuseAddress = b;967} else {968Net.setSocketOption(fd, opt, b);969}970} else {971// option does not need special handling972Net.setSocketOption(fd, opt, value);973}974}975}976977@SuppressWarnings("unchecked")978protected <T> T getOption(SocketOption<T> opt) throws IOException {979if (!supportedOptions().contains(opt))980throw new UnsupportedOperationException("'" + opt + "' not supported");981synchronized (stateLock) {982ensureOpen();983if (opt == StandardSocketOptions.IP_TOS) {984return (T) Net.getSocketOption(fd, family(), opt);985} else if (opt == StandardSocketOptions.SO_REUSEADDR) {986if (Net.useExclusiveBind()) {987return (T) Boolean.valueOf(isReuseAddress);988} else {989return (T) Net.getSocketOption(fd, opt);990}991} else {992// option does not need special handling993return (T) Net.getSocketOption(fd, opt);994}995}996}997998private boolean booleanValue(Object value, String desc) throws SocketException {999if (!(value instanceof Boolean))1000throw new SocketException("Bad value for " + desc);1001return (boolean) value;1002}10031004private int intValue(Object value, String desc) throws SocketException {1005if (!(value instanceof Integer))1006throw new SocketException("Bad value for " + desc);1007return (int) value;1008}10091010@Override1011public void setOption(int opt, Object value) throws SocketException {1012synchronized (stateLock) {1013ensureOpen();1014try {1015switch (opt) {1016case SO_LINGER: {1017// the value is "false" to disable, or linger interval to enable1018int i;1019if (value instanceof Boolean && ((boolean) value) == false) {1020i = -1;1021} else {1022i = intValue(value, "SO_LINGER");1023}1024Net.setSocketOption(fd, StandardSocketOptions.SO_LINGER, i);1025break;1026}1027case SO_TIMEOUT: {1028int i = intValue(value, "SO_TIMEOUT");1029if (i < 0)1030throw new IllegalArgumentException("timeout < 0");1031timeout = i;1032break;1033}1034case IP_TOS: {1035int i = intValue(value, "IP_TOS");1036Net.setSocketOption(fd, family(), StandardSocketOptions.IP_TOS, i);1037break;1038}1039case TCP_NODELAY: {1040boolean b = booleanValue(value, "TCP_NODELAY");1041Net.setSocketOption(fd, StandardSocketOptions.TCP_NODELAY, b);1042break;1043}1044case SO_SNDBUF: {1045int i = intValue(value, "SO_SNDBUF");1046if (i <= 0)1047throw new SocketException("SO_SNDBUF <= 0");1048Net.setSocketOption(fd, StandardSocketOptions.SO_SNDBUF, i);1049break;1050}1051case SO_RCVBUF: {1052int i = intValue(value, "SO_RCVBUF");1053if (i <= 0)1054throw new SocketException("SO_RCVBUF <= 0");1055Net.setSocketOption(fd, StandardSocketOptions.SO_RCVBUF, i);1056break;1057}1058case SO_KEEPALIVE: {1059boolean b = booleanValue(value, "SO_KEEPALIVE");1060Net.setSocketOption(fd, StandardSocketOptions.SO_KEEPALIVE, b);1061break;1062}1063case SO_OOBINLINE: {1064boolean b = booleanValue(value, "SO_OOBINLINE");1065Net.setSocketOption(fd, ExtendedSocketOption.SO_OOBINLINE, b);1066break;1067}1068case SO_REUSEADDR: {1069boolean b = booleanValue(value, "SO_REUSEADDR");1070if (Net.useExclusiveBind()) {1071isReuseAddress = b;1072} else {1073Net.setSocketOption(fd, StandardSocketOptions.SO_REUSEADDR, b);1074}1075break;1076}1077case SO_REUSEPORT: {1078if (!Net.isReusePortAvailable())1079throw new SocketException("SO_REUSEPORT not supported");1080boolean b = booleanValue(value, "SO_REUSEPORT");1081Net.setSocketOption(fd, StandardSocketOptions.SO_REUSEPORT, b);1082break;1083}1084default:1085throw new SocketException("Unknown option " + opt);1086}1087} catch (SocketException e) {1088throw e;1089} catch (IllegalArgumentException | IOException e) {1090throw new SocketException(e.getMessage());1091}1092}1093}10941095@Override1096public Object getOption(int opt) throws SocketException {1097synchronized (stateLock) {1098ensureOpen();1099try {1100switch (opt) {1101case SO_TIMEOUT:1102return timeout;1103case TCP_NODELAY:1104return Net.getSocketOption(fd, StandardSocketOptions.TCP_NODELAY);1105case SO_OOBINLINE:1106return Net.getSocketOption(fd, ExtendedSocketOption.SO_OOBINLINE);1107case SO_LINGER: {1108// return "false" when disabled, linger interval when enabled1109int i = (int) Net.getSocketOption(fd, StandardSocketOptions.SO_LINGER);1110if (i == -1) {1111return Boolean.FALSE;1112} else {1113return i;1114}1115}1116case SO_REUSEADDR:1117if (Net.useExclusiveBind()) {1118return isReuseAddress;1119} else {1120return Net.getSocketOption(fd, StandardSocketOptions.SO_REUSEADDR);1121}1122case SO_BINDADDR:1123return Net.localAddress(fd).getAddress();1124case SO_SNDBUF:1125return Net.getSocketOption(fd, StandardSocketOptions.SO_SNDBUF);1126case SO_RCVBUF:1127return Net.getSocketOption(fd, StandardSocketOptions.SO_RCVBUF);1128case IP_TOS:1129return Net.getSocketOption(fd, family(), StandardSocketOptions.IP_TOS);1130case SO_KEEPALIVE:1131return Net.getSocketOption(fd, StandardSocketOptions.SO_KEEPALIVE);1132case SO_REUSEPORT:1133if (!Net.isReusePortAvailable())1134throw new SocketException("SO_REUSEPORT not supported");1135return Net.getSocketOption(fd, StandardSocketOptions.SO_REUSEPORT);1136default:1137throw new SocketException("Unknown option " + opt);1138}1139} catch (SocketException e) {1140throw e;1141} catch (IllegalArgumentException | IOException e) {1142throw new SocketException(e.getMessage());1143}1144}1145}11461147@Override1148protected void shutdownInput() throws IOException {1149synchronized (stateLock) {1150ensureOpenAndConnected();1151if (!isInputClosed) {1152Net.shutdown(fd, Net.SHUT_RD);1153isInputClosed = true;1154}1155}1156}11571158@Override1159protected void shutdownOutput() throws IOException {1160synchronized (stateLock) {1161ensureOpenAndConnected();1162if (!isOutputClosed) {1163Net.shutdown(fd, Net.SHUT_WR);1164isOutputClosed = true;1165}1166}1167}11681169@Override1170protected boolean supportsUrgentData() {1171return true;1172}11731174@Override1175protected void sendUrgentData(int data) throws IOException {1176writeLock.lock();1177try {1178int n = 0;1179FileDescriptor fd = beginWrite();1180try {1181do {1182n = Net.sendOOB(fd, (byte) data);1183} while (n == IOStatus.INTERRUPTED && isOpen());1184if (n == IOStatus.UNAVAILABLE) {1185throw new SocketException("No buffer space available");1186}1187} finally {1188endWrite(n > 0);1189}1190} finally {1191writeLock.unlock();1192}1193}11941195/**1196* Returns an action to close the given file descriptor.1197*/1198private static Runnable closerFor(FileDescriptor fd, boolean stream) {1199if (stream) {1200return () -> {1201try {1202nd.close(fd);1203} catch (IOException ioe) {1204throw new UncheckedIOException(ioe);1205}1206};1207} else {1208return () -> {1209try {1210nd.close(fd);1211} catch (IOException ioe) {1212throw new UncheckedIOException(ioe);1213} finally {1214// decrement1215ResourceManager.afterUdpClose();1216}1217};1218}1219}12201221/**1222* Attempts to acquire the given lock within the given waiting time.1223* @return the remaining time in nanoseconds when the lock is acquired, zero1224* or less if the lock was not acquired before the timeout expired1225*/1226private static long tryLock(ReentrantLock lock, long timeout, TimeUnit unit) {1227assert timeout > 0;1228boolean interrupted = false;1229long nanos = NANOSECONDS.convert(timeout, unit);1230long remainingNanos = nanos;1231long startNanos = System.nanoTime();1232boolean acquired = false;1233while (!acquired && (remainingNanos > 0)) {1234try {1235acquired = lock.tryLock(remainingNanos, NANOSECONDS);1236} catch (InterruptedException e) {1237interrupted = true;1238}1239remainingNanos = nanos - (System.nanoTime() - startNanos);1240}1241if (acquired && remainingNanos <= 0L)1242lock.unlock(); // release lock if timeout has expired1243if (interrupted)1244Thread.currentThread().interrupt();1245return remainingNanos;1246}12471248/**1249* Returns the socket protocol family.1250*/1251private static ProtocolFamily family() {1252if (Net.isIPv6Available()) {1253return StandardProtocolFamily.INET6;1254} else {1255return StandardProtocolFamily.INET;1256}1257}1258}125912601261