src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
changeset 55102 59567035d279
child 58679 9c3209ff7550
child 58808 9261ad32cba9
equal deleted inserted replaced
55101:c41783eb76eb 55102:59567035d279
       
     1 /*
       
     2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.nio.ch;
       
    27 
       
    28 import java.io.FileDescriptor;
       
    29 import java.io.IOException;
       
    30 import java.io.InputStream;
       
    31 import java.io.OutputStream;
       
    32 import java.io.UncheckedIOException;
       
    33 import java.lang.invoke.MethodHandles;
       
    34 import java.lang.invoke.VarHandle;
       
    35 import java.net.InetAddress;
       
    36 import java.net.InetSocketAddress;
       
    37 import java.net.ProtocolFamily;
       
    38 import java.net.SocketAddress;
       
    39 import java.net.SocketException;
       
    40 import java.net.SocketImpl;
       
    41 import java.net.SocketOption;
       
    42 import java.net.SocketTimeoutException;
       
    43 import java.net.StandardProtocolFamily;
       
    44 import java.net.StandardSocketOptions;
       
    45 import java.net.UnknownHostException;
       
    46 import java.nio.ByteBuffer;
       
    47 import java.util.Collections;
       
    48 import java.util.HashSet;
       
    49 import java.util.Objects;
       
    50 import java.util.Set;
       
    51 import java.util.concurrent.TimeUnit;
       
    52 import java.util.concurrent.locks.ReentrantLock;
       
    53 
       
    54 import jdk.internal.ref.CleanerFactory;
       
    55 import sun.net.ConnectionResetException;
       
    56 import sun.net.NetHooks;
       
    57 import sun.net.PlatformSocketImpl;
       
    58 import sun.net.ResourceManager;
       
    59 import sun.net.ext.ExtendedSocketOptions;
       
    60 import sun.net.util.SocketExceptions;
       
    61 
       
    62 import static java.util.concurrent.TimeUnit.MILLISECONDS;
       
    63 import static java.util.concurrent.TimeUnit.NANOSECONDS;
       
    64 
       
    65 /**
       
    66  * NIO based SocketImpl.
       
    67  *
       
    68  * This implementation attempts to be compatible with legacy PlainSocketImpl,
       
    69  * including behavior and exceptions that are not specified by SocketImpl.
       
    70  *
       
    71  * The underlying socket used by this SocketImpl is initially configured
       
    72  * blocking. If the connect method is used to establish a connection with a
       
    73  * timeout then the socket is configured non-blocking for the connect attempt,
       
    74  * and then restored to blocking mode when the connection is established.
       
    75  * If the accept or read methods are used with a timeout then the socket is
       
    76  * configured non-blocking and is never restored. When in non-blocking mode,
       
    77  * operations that don't complete immediately will poll the socket and preserve
       
    78  * the semantics of blocking operations.
       
    79  */
       
    80 
       
    81 public final class NioSocketImpl extends SocketImpl implements PlatformSocketImpl {
       
    82     private static final NativeDispatcher nd = new SocketDispatcher();
       
    83 
       
    84     // The maximum number of bytes to read/write per syscall to avoid needing
       
    85     // a huge buffer from the temporary buffer cache
       
    86     private static final int MAX_BUFFER_SIZE = 128 * 1024;
       
    87 
       
    88     // true if this is a SocketImpl for a ServerSocket
       
    89     private final boolean server;
       
    90 
       
    91     // Lock held when reading (also used when accepting or connecting)
       
    92     private final ReentrantLock readLock = new ReentrantLock();
       
    93 
       
    94     // Lock held when writing
       
    95     private final ReentrantLock writeLock = new ReentrantLock();
       
    96 
       
    97     // The stateLock for read/changing state
       
    98     private final Object stateLock = new Object();
       
    99     private static final int ST_NEW = 0;
       
   100     private static final int ST_UNCONNECTED = 1;
       
   101     private static final int ST_CONNECTING = 2;
       
   102     private static final int ST_CONNECTED = 3;
       
   103     private static final int ST_CLOSING = 4;
       
   104     private static final int ST_CLOSED = 5;
       
   105     private volatile int state;  // need stateLock to change
       
   106 
       
   107     // set by SocketImpl.create, protected by stateLock
       
   108     private boolean stream;
       
   109     private FileDescriptorCloser closer;
       
   110 
       
   111     // set to true when the socket is in non-blocking mode
       
   112     private volatile boolean nonBlocking;
       
   113 
       
   114     // used by connect/read/write/accept, protected by stateLock
       
   115     private long readerThread;
       
   116     private long writerThread;
       
   117 
       
   118     // used when SO_REUSEADDR is emulated, protected by stateLock
       
   119     private boolean isReuseAddress;
       
   120 
       
   121     // read or accept timeout in millis
       
   122     private volatile int timeout;
       
   123 
       
   124     // flags to indicate if the connection is shutdown for input and output
       
   125     private volatile boolean isInputClosed;
       
   126     private volatile boolean isOutputClosed;
       
   127 
       
   128     // used by read to emulate legacy behavior, protected by readLock
       
   129     private boolean readEOF;
       
   130     private boolean connectionReset;
       
   131 
       
   132     /**
       
   133      * Creates an instance of this SocketImpl.
       
   134      * @param server true if this is a SocketImpl for a ServerSocket
       
   135      */
       
   136     public NioSocketImpl(boolean server) {
       
   137         this.server = server;
       
   138     }
       
   139 
       
   140     /**
       
   141      * Returns true if the socket is open.
       
   142      */
       
   143     private boolean isOpen() {
       
   144         return state < ST_CLOSING;
       
   145     }
       
   146 
       
   147     /**
       
   148      * Throws SocketException if the socket is not open.
       
   149      */
       
   150     private void ensureOpen() throws SocketException {
       
   151         int state = this.state;
       
   152         if (state == ST_NEW)
       
   153             throw new SocketException("Socket not created");
       
   154         if (state >= ST_CLOSING)
       
   155             throw new SocketException("Socket closed");
       
   156     }
       
   157 
       
   158     /**
       
   159      * Throws SocketException if the socket is not open and connected.
       
   160      */
       
   161     private void ensureOpenAndConnected() throws SocketException {
       
   162         int state = this.state;
       
   163         if (state < ST_CONNECTED)
       
   164             throw new SocketException("Not connected");
       
   165         if (state > ST_CONNECTED)
       
   166             throw new SocketException("Socket closed");
       
   167     }
       
   168 
       
   169     /**
       
   170      * Disables the current thread for scheduling purposes until the socket is
       
   171      * ready for I/O, or is asynchronously closed, for up to the specified
       
   172      * waiting time.
       
   173      * @throws IOException if an I/O error occurs
       
   174      */
       
   175     private void park(FileDescriptor fd, int event, long nanos) throws IOException {
       
   176         long millis;
       
   177         if (nanos == 0) {
       
   178             millis = -1;
       
   179         } else {
       
   180             millis = NANOSECONDS.toMillis(nanos);
       
   181         }
       
   182         Net.poll(fd, event, millis);
       
   183     }
       
   184 
       
   185     /**
       
   186      * Disables the current thread for scheduling purposes until the socket is
       
   187      * ready for I/O or is asynchronously closed.
       
   188      * @throws IOException if an I/O error occurs
       
   189      */
       
   190     private void park(FileDescriptor fd, int event) throws IOException {
       
   191         park(fd, event, 0);
       
   192     }
       
   193 
       
   194     /**
       
   195      * Configures the socket to blocking mode. This method is a no-op if the
       
   196      * socket is already in blocking mode.
       
   197      * @throws IOException if closed or there is an I/O error changing the mode
       
   198      */
       
   199     private void configureBlocking(FileDescriptor fd) throws IOException {
       
   200         assert readLock.isHeldByCurrentThread();
       
   201         if (nonBlocking) {
       
   202             synchronized (stateLock) {
       
   203                 ensureOpen();
       
   204                 IOUtil.configureBlocking(fd, true);
       
   205                 nonBlocking = false;
       
   206             }
       
   207         }
       
   208     }
       
   209 
       
   210     /**
       
   211      * Configures the socket to non-blocking mode. This method is a no-op if the
       
   212      * socket is already in non-blocking mode.
       
   213      * @throws IOException if closed or there is an I/O error changing the mode
       
   214      */
       
   215     private void configureNonBlocking(FileDescriptor fd) throws IOException {
       
   216         assert readLock.isHeldByCurrentThread();
       
   217         if (!nonBlocking) {
       
   218             synchronized (stateLock) {
       
   219                 ensureOpen();
       
   220                 IOUtil.configureBlocking(fd, false);
       
   221                 nonBlocking = true;
       
   222             }
       
   223         }
       
   224     }
       
   225 
       
   226     /**
       
   227      * Marks the beginning of a read operation that might block.
       
   228      * @throws SocketException if the socket is closed or not connected
       
   229      */
       
   230     private FileDescriptor beginRead() throws SocketException {
       
   231         synchronized (stateLock) {
       
   232             ensureOpenAndConnected();
       
   233             readerThread = NativeThread.current();
       
   234             return fd;
       
   235         }
       
   236     }
       
   237 
       
   238     /**
       
   239      * Marks the end of a read operation that may have blocked.
       
   240      * @throws SocketException is the socket is closed
       
   241      */
       
   242     private void endRead(boolean completed) throws SocketException {
       
   243         synchronized (stateLock) {
       
   244             readerThread = 0;
       
   245             int state = this.state;
       
   246             if (state == ST_CLOSING)
       
   247                 tryFinishClose();
       
   248             if (!completed && state >= ST_CLOSING)
       
   249                 throw new SocketException("Socket closed");
       
   250         }
       
   251     }
       
   252 
       
   253     /**
       
   254      * Attempts to read bytes from the socket into the given byte array.
       
   255      */
       
   256     private int tryRead(FileDescriptor fd, byte[] b, int off, int len)
       
   257         throws IOException
       
   258     {
       
   259         ByteBuffer dst = Util.getTemporaryDirectBuffer(len);
       
   260         assert dst.position() == 0;
       
   261         try {
       
   262             int n = nd.read(fd, ((DirectBuffer)dst).address(), len);
       
   263             if (n > 0) {
       
   264                 dst.get(b, off, n);
       
   265             }
       
   266             return n;
       
   267         } finally {
       
   268             Util.offerFirstTemporaryDirectBuffer(dst);
       
   269         }
       
   270     }
       
   271 
       
   272     /**
       
   273      * Reads bytes from the socket into the given byte array with a timeout.
       
   274      * @throws SocketTimeoutException if the read timeout elapses
       
   275      */
       
   276     private int timedRead(FileDescriptor fd, byte[] b, int off, int len, long nanos)
       
   277         throws IOException
       
   278     {
       
   279         long startNanos = System.nanoTime();
       
   280         int n = tryRead(fd, b, off, len);
       
   281         while (n == IOStatus.UNAVAILABLE && isOpen()) {
       
   282             long remainingNanos = nanos - (System.nanoTime() - startNanos);
       
   283             if (remainingNanos <= 0) {
       
   284                 throw new SocketTimeoutException("Read timed out");
       
   285             }
       
   286             park(fd, Net.POLLIN, remainingNanos);
       
   287             n = tryRead(fd, b, off, len);
       
   288         }
       
   289         return n;
       
   290     }
       
   291 
       
   292     /**
       
   293      * Reads bytes from the socket into the given byte array.
       
   294      * @return the number of bytes read or -1 at EOF
       
   295      * @throws SocketException if the socket is closed or a socket I/O error occurs
       
   296      * @throws SocketTimeoutException if the read timeout elapses
       
   297      */
       
   298     private int implRead(byte[] b, int off, int len) throws IOException {
       
   299         int n = 0;
       
   300         FileDescriptor fd = beginRead();
       
   301         try {
       
   302             if (connectionReset)
       
   303                 throw new SocketException("Connection reset");
       
   304             if (isInputClosed)
       
   305                 return -1;
       
   306             int timeout = this.timeout;
       
   307             if (timeout > 0) {
       
   308                 // read with timeout
       
   309                 configureNonBlocking(fd);
       
   310                 n = timedRead(fd, b, off, len, MILLISECONDS.toNanos(timeout));
       
   311             } else {
       
   312                 // read, no timeout
       
   313                 n = tryRead(fd, b, off, len);
       
   314                 while (IOStatus.okayToRetry(n) && isOpen()) {
       
   315                     park(fd, Net.POLLIN);
       
   316                     n = tryRead(fd, b, off, len);
       
   317                 }
       
   318             }
       
   319             return n;
       
   320         } catch (SocketTimeoutException e) {
       
   321             throw e;
       
   322         } catch (ConnectionResetException e) {
       
   323             connectionReset = true;
       
   324             throw new SocketException("Connection reset");
       
   325         } catch (IOException ioe) {
       
   326             throw new SocketException(ioe.getMessage());
       
   327         } finally {
       
   328             endRead(n > 0);
       
   329         }
       
   330     }
       
   331 
       
   332     /**
       
   333      * Reads bytes from the socket into the given byte array.
       
   334      * @return the number of bytes read or -1 at EOF
       
   335      * @throws IndexOutOfBoundsException if the bound checks fail
       
   336      * @throws SocketException if the socket is closed or a socket I/O error occurs
       
   337      * @throws SocketTimeoutException if the read timeout elapses
       
   338      */
       
   339     private int read(byte[] b, int off, int len) throws IOException {
       
   340         Objects.checkFromIndexSize(off, len, b.length);
       
   341         if (len == 0) {
       
   342             return 0;
       
   343         } else {
       
   344             readLock.lock();
       
   345             try {
       
   346                 // emulate legacy behavior to return -1, even if socket is closed
       
   347                 if (readEOF)
       
   348                     return -1;
       
   349                 // read up to MAX_BUFFER_SIZE bytes
       
   350                 int size = Math.min(len, MAX_BUFFER_SIZE);
       
   351                 int n = implRead(b, off, size);
       
   352                 if (n == -1)
       
   353                     readEOF = true;
       
   354                 return n;
       
   355             } finally {
       
   356                 readLock.unlock();
       
   357             }
       
   358         }
       
   359     }
       
   360 
       
   361     /**
       
   362      * Marks the beginning of a write operation that might block.
       
   363      * @throws SocketException if the socket is closed or not connected
       
   364      */
       
   365     private FileDescriptor beginWrite() throws SocketException {
       
   366         synchronized (stateLock) {
       
   367             ensureOpenAndConnected();
       
   368             writerThread = NativeThread.current();
       
   369             return fd;
       
   370         }
       
   371     }
       
   372 
       
   373     /**
       
   374      * Marks the end of a write operation that may have blocked.
       
   375      * @throws SocketException is the socket is closed
       
   376      */
       
   377     private void endWrite(boolean completed) throws SocketException {
       
   378         synchronized (stateLock) {
       
   379             writerThread = 0;
       
   380             int state = this.state;
       
   381             if (state == ST_CLOSING)
       
   382                 tryFinishClose();
       
   383             if (!completed && state >= ST_CLOSING)
       
   384                 throw new SocketException("Socket closed");
       
   385         }
       
   386     }
       
   387 
       
   388     /**
       
   389      * Attempts to write a sequence of bytes to the socket from the given
       
   390      * byte array.
       
   391      */
       
   392     private int tryWrite(FileDescriptor fd, byte[] b, int off, int len)
       
   393         throws IOException
       
   394     {
       
   395         ByteBuffer src = Util.getTemporaryDirectBuffer(len);
       
   396         assert src.position() == 0;
       
   397         try {
       
   398             src.put(b, off, len);
       
   399             return nd.write(fd, ((DirectBuffer)src).address(), len);
       
   400         } finally {
       
   401             Util.offerFirstTemporaryDirectBuffer(src);
       
   402         }
       
   403     }
       
   404 
       
   405     /**
       
   406      * Writes a sequence of bytes to the socket from the given byte array.
       
   407      * @return the number of bytes written
       
   408      * @throws SocketException if the socket is closed or a socket I/O error occurs
       
   409      */
       
   410     private int implWrite(byte[] b, int off, int len) throws IOException {
       
   411         int n = 0;
       
   412         FileDescriptor fd = beginWrite();
       
   413         try {
       
   414             n = tryWrite(fd, b, off, len);
       
   415             while (IOStatus.okayToRetry(n) && isOpen()) {
       
   416                 park(fd, Net.POLLOUT);
       
   417                 n = tryWrite(fd, b, off, len);
       
   418             }
       
   419             return n;
       
   420         } catch (IOException ioe) {
       
   421             throw new SocketException(ioe.getMessage());
       
   422         } finally {
       
   423             endWrite(n > 0);
       
   424         }
       
   425     }
       
   426 
       
   427     /**
       
   428      * Writes a sequence of bytes to the socket from the given byte array.
       
   429      * @throws SocketException if the socket is closed or a socket I/O error occurs
       
   430      */
       
   431     private void write(byte[] b, int off, int len) throws IOException {
       
   432         Objects.checkFromIndexSize(off, len, b.length);
       
   433         if (len > 0) {
       
   434             writeLock.lock();
       
   435             try {
       
   436                 int pos = off;
       
   437                 int end = off + len;
       
   438                 while (pos < end) {
       
   439                     // write up to MAX_BUFFER_SIZE bytes
       
   440                     int size = Math.min((end - pos), MAX_BUFFER_SIZE);
       
   441                     int n = implWrite(b, pos, size);
       
   442                     pos += n;
       
   443                 }
       
   444             } finally {
       
   445                 writeLock.unlock();
       
   446             }
       
   447         }
       
   448     }
       
   449 
       
   450     /**
       
   451      * Creates the socket.
       
   452      * @param stream {@code true} for a streams socket
       
   453      */
       
   454     @Override
       
   455     protected void create(boolean stream) throws IOException {
       
   456         synchronized (stateLock) {
       
   457             if (state != ST_NEW)
       
   458                 throw new IOException("Already created");
       
   459             if (!stream)
       
   460                 ResourceManager.beforeUdpCreate();
       
   461             FileDescriptor fd;
       
   462             try {
       
   463                 if (server) {
       
   464                     assert stream;
       
   465                     fd = Net.serverSocket(true);
       
   466                 } else {
       
   467                     fd = Net.socket(stream);
       
   468                 }
       
   469             } catch (IOException ioe) {
       
   470                 if (!stream)
       
   471                     ResourceManager.afterUdpClose();
       
   472                 throw ioe;
       
   473             }
       
   474             this.fd = fd;
       
   475             this.stream = stream;
       
   476             this.closer = FileDescriptorCloser.create(this);
       
   477             this.state = ST_UNCONNECTED;
       
   478         }
       
   479     }
       
   480 
       
   481     /**
       
   482      * Marks the beginning of a connect operation that might block.
       
   483      * @throws SocketException if the socket is closed or already connected
       
   484      */
       
   485     private FileDescriptor beginConnect(InetAddress address, int port)
       
   486         throws IOException
       
   487     {
       
   488         synchronized (stateLock) {
       
   489             int state = this.state;
       
   490             if (state != ST_UNCONNECTED) {
       
   491                 if (state == ST_NEW)
       
   492                     throw new SocketException("Not created");
       
   493                 if (state == ST_CONNECTING)
       
   494                     throw new SocketException("Connection in progress");
       
   495                 if (state == ST_CONNECTED)
       
   496                     throw new SocketException("Already connected");
       
   497                 if (state >= ST_CLOSING)
       
   498                     throw new SocketException("Socket closed");
       
   499                 assert false;
       
   500             }
       
   501             this.state = ST_CONNECTING;
       
   502 
       
   503             // invoke beforeTcpConnect hook if not already bound
       
   504             if (localport == 0) {
       
   505                 NetHooks.beforeTcpConnect(fd, address, port);
       
   506             }
       
   507 
       
   508             // save the remote address/port
       
   509             this.address = address;
       
   510             this.port = port;
       
   511 
       
   512             readerThread = NativeThread.current();
       
   513             return fd;
       
   514         }
       
   515     }
       
   516 
       
   517     /**
       
   518      * Marks the end of a connect operation that may have blocked.
       
   519      * @throws SocketException is the socket is closed
       
   520      */
       
   521     private void endConnect(FileDescriptor fd, boolean completed) throws IOException {
       
   522         synchronized (stateLock) {
       
   523             readerThread = 0;
       
   524             int state = this.state;
       
   525             if (state == ST_CLOSING)
       
   526                 tryFinishClose();
       
   527             if (completed && state == ST_CONNECTING) {
       
   528                 this.state = ST_CONNECTED;
       
   529                 localport = Net.localAddress(fd).getPort();
       
   530             } else if (!completed && state >= ST_CLOSING) {
       
   531                 throw new SocketException("Socket closed");
       
   532             }
       
   533         }
       
   534     }
       
   535 
       
   536     /**
       
   537      * Waits for a connection attempt to finish with a timeout
       
   538      * @throws SocketTimeoutException if the connect timeout elapses
       
   539      */
       
   540     private boolean timedFinishConnect(FileDescriptor fd, long nanos) throws IOException {
       
   541         long startNanos = System.nanoTime();
       
   542         boolean polled = Net.pollConnectNow(fd);
       
   543         while (!polled && isOpen()) {
       
   544             long remainingNanos = nanos - (System.nanoTime() - startNanos);
       
   545             if (remainingNanos <= 0) {
       
   546                 throw new SocketTimeoutException("Connect timed out");
       
   547             }
       
   548             park(fd, Net.POLLOUT, remainingNanos);
       
   549             polled = Net.pollConnectNow(fd);
       
   550         }
       
   551         return polled && isOpen();
       
   552     }
       
   553 
       
   554     /**
       
   555      * Attempts to establish a connection to the given socket address with a
       
   556      * timeout. Closes the socket if connection cannot be established.
       
   557      * @throws IOException if the address is not a resolved InetSocketAddress or
       
   558      *         the connection cannot be established
       
   559      */
       
   560     @Override
       
   561     protected void connect(SocketAddress remote, int millis) throws IOException {
       
   562         // SocketImpl connect only specifies IOException
       
   563         if (!(remote instanceof InetSocketAddress))
       
   564             throw new IOException("Unsupported address type");
       
   565         InetSocketAddress isa = (InetSocketAddress) remote;
       
   566         if (isa.isUnresolved()) {
       
   567             throw new UnknownHostException(isa.getHostName());
       
   568         }
       
   569 
       
   570         InetAddress address = isa.getAddress();
       
   571         if (address.isAnyLocalAddress())
       
   572             address = InetAddress.getLocalHost();
       
   573         int port = isa.getPort();
       
   574 
       
   575         ReentrantLock connectLock = readLock;
       
   576         try {
       
   577             connectLock.lock();
       
   578             try {
       
   579                 boolean connected = false;
       
   580                 FileDescriptor fd = beginConnect(address, port);
       
   581                 try {
       
   582 
       
   583                     // configure socket to non-blocking mode when there is a timeout
       
   584                     if (millis > 0) {
       
   585                         configureNonBlocking(fd);
       
   586                     }
       
   587 
       
   588                     int n = Net.connect(fd, address, port);
       
   589                     if (n > 0) {
       
   590                         // connection established
       
   591                         connected = true;
       
   592                     } else {
       
   593                         assert IOStatus.okayToRetry(n);
       
   594                         if (millis > 0) {
       
   595                             // finish connect with timeout
       
   596                             long nanos = MILLISECONDS.toNanos(millis);
       
   597                             connected = timedFinishConnect(fd, nanos);
       
   598                         } else {
       
   599                             // finish connect, no timeout
       
   600                             boolean polled = false;
       
   601                             while (!polled && isOpen()) {
       
   602                                 park(fd, Net.POLLOUT);
       
   603                                 polled = Net.pollConnectNow(fd);
       
   604                             }
       
   605                             connected = polled && isOpen();
       
   606                         }
       
   607                     }
       
   608 
       
   609                     // restore socket to blocking mode
       
   610                     if (connected && millis > 0) {
       
   611                         configureBlocking(fd);
       
   612                     }
       
   613 
       
   614                 } finally {
       
   615                     endConnect(fd, connected);
       
   616                 }
       
   617             } finally {
       
   618                 connectLock.unlock();
       
   619             }
       
   620         } catch (IOException ioe) {
       
   621             close();
       
   622             throw SocketExceptions.of(ioe, isa);
       
   623         }
       
   624     }
       
   625 
       
   626     @Override
       
   627     protected void connect(String host, int port) throws IOException {
       
   628         connect(new InetSocketAddress(host, port), 0);
       
   629     }
       
   630 
       
   631     @Override
       
   632     protected void connect(InetAddress address, int port) throws IOException {
       
   633         connect(new InetSocketAddress(address, port), 0);
       
   634     }
       
   635 
       
   636     @Override
       
   637     protected void bind(InetAddress host, int port) throws IOException {
       
   638         synchronized (stateLock) {
       
   639             ensureOpen();
       
   640             if (localport != 0)
       
   641                 throw new SocketException("Already bound");
       
   642             NetHooks.beforeTcpBind(fd, host, port);
       
   643             Net.bind(fd, host, port);
       
   644             // set the address field to the given host address to keep
       
   645             // compatibility with PlainSocketImpl. When binding to 0.0.0.0
       
   646             // then the actual local address will be ::0 when IPv6 is enabled.
       
   647             address = host;
       
   648             localport = Net.localAddress(fd).getPort();
       
   649         }
       
   650     }
       
   651 
       
   652     @Override
       
   653     protected void listen(int backlog) throws IOException {
       
   654         synchronized (stateLock) {
       
   655             ensureOpen();
       
   656             if (localport == 0)
       
   657                 throw new SocketException("Not bound");
       
   658             Net.listen(fd, backlog < 1 ? 50 : backlog);
       
   659         }
       
   660     }
       
   661 
       
   662     /**
       
   663      * Marks the beginning of an accept operation that might block.
       
   664      * @throws SocketException if the socket is closed
       
   665      */
       
   666     private FileDescriptor beginAccept() throws SocketException {
       
   667         synchronized (stateLock) {
       
   668             ensureOpen();
       
   669             if (!stream)
       
   670                 throw new SocketException("Not a stream socket");
       
   671             if (localport == 0)
       
   672                 throw new SocketException("Not bound");
       
   673             readerThread = NativeThread.current();
       
   674             return fd;
       
   675         }
       
   676     }
       
   677 
       
   678     /**
       
   679      * Marks the end of an accept operation that may have blocked.
       
   680      * @throws SocketException is the socket is closed
       
   681      */
       
   682     private void endAccept(boolean completed) throws SocketException {
       
   683         synchronized (stateLock) {
       
   684             int state = this.state;
       
   685             readerThread = 0;
       
   686             if (state == ST_CLOSING)
       
   687                 tryFinishClose();
       
   688             if (!completed && state >= ST_CLOSING)
       
   689                 throw new SocketException("Socket closed");
       
   690         }
       
   691     }
       
   692 
       
   693     /**
       
   694      * Accepts a new connection with a timeout.
       
   695      * @throws SocketTimeoutException if the accept timeout elapses
       
   696      */
       
   697     private int timedAccept(FileDescriptor fd,
       
   698                             FileDescriptor newfd,
       
   699                             InetSocketAddress[] isaa,
       
   700                             long nanos)
       
   701         throws IOException
       
   702     {
       
   703         long startNanos = System.nanoTime();
       
   704         int n = Net.accept(fd, newfd, isaa);
       
   705         while (n == IOStatus.UNAVAILABLE && isOpen()) {
       
   706             long remainingNanos = nanos - (System.nanoTime() - startNanos);
       
   707             if (remainingNanos <= 0) {
       
   708                 throw new SocketTimeoutException("Accept timed out");
       
   709             }
       
   710             park(fd, Net.POLLIN, remainingNanos);
       
   711             n = Net.accept(fd, newfd, isaa);
       
   712         }
       
   713         return n;
       
   714     }
       
   715 
       
   716     /**
       
   717      * Accepts a new connection so that the given SocketImpl is connected to
       
   718      * the peer. The SocketImpl must be a newly created NioSocketImpl.
       
   719      */
       
   720     @Override
       
   721     protected void accept(SocketImpl si) throws IOException {
       
   722         NioSocketImpl nsi = (NioSocketImpl) si;
       
   723         if (nsi.state != ST_NEW)
       
   724             throw new SocketException("Not a newly created SocketImpl");
       
   725 
       
   726         FileDescriptor newfd = new FileDescriptor();
       
   727         InetSocketAddress[] isaa = new InetSocketAddress[1];
       
   728 
       
   729         // acquire the lock, adjusting the timeout for cases where several
       
   730         // threads are accepting connections and there is a timeout set
       
   731         ReentrantLock acceptLock = readLock;
       
   732         int timeout = this.timeout;
       
   733         long remainingNanos = 0;
       
   734         if (timeout > 0) {
       
   735             remainingNanos = tryLock(acceptLock, timeout, MILLISECONDS);
       
   736             if (remainingNanos <= 0) {
       
   737                 assert !acceptLock.isHeldByCurrentThread();
       
   738                 throw new SocketTimeoutException("Accept timed out");
       
   739             }
       
   740         } else {
       
   741             acceptLock.lock();
       
   742         }
       
   743 
       
   744         // accept a connection
       
   745         try {
       
   746             int n = 0;
       
   747             FileDescriptor fd = beginAccept();
       
   748             try {
       
   749                 if (remainingNanos > 0) {
       
   750                     // accept with timeout
       
   751                     configureNonBlocking(fd);
       
   752                     n = timedAccept(fd, newfd, isaa, remainingNanos);
       
   753                 } else {
       
   754                     // accept, no timeout
       
   755                     n = Net.accept(fd, newfd, isaa);
       
   756                     while (IOStatus.okayToRetry(n) && isOpen()) {
       
   757                         park(fd, Net.POLLIN);
       
   758                         n = Net.accept(fd, newfd, isaa);
       
   759                     }
       
   760                 }
       
   761             } finally {
       
   762                 endAccept(n > 0);
       
   763                 assert IOStatus.check(n);
       
   764             }
       
   765         } finally {
       
   766             acceptLock.unlock();
       
   767         }
       
   768 
       
   769         // get local address and configure accepted socket to blocking mode
       
   770         InetSocketAddress localAddress;
       
   771         try {
       
   772             localAddress = Net.localAddress(newfd);
       
   773             IOUtil.configureBlocking(newfd, true);
       
   774         } catch (IOException ioe) {
       
   775             nd.close(newfd);
       
   776             throw ioe;
       
   777         }
       
   778 
       
   779         // set the fields
       
   780         synchronized (nsi.stateLock) {
       
   781             nsi.fd = newfd;
       
   782             nsi.stream = true;
       
   783             nsi.closer = FileDescriptorCloser.create(nsi);
       
   784             nsi.localport = localAddress.getPort();
       
   785             nsi.address = isaa[0].getAddress();
       
   786             nsi.port = isaa[0].getPort();
       
   787             nsi.state = ST_CONNECTED;
       
   788         }
       
   789     }
       
   790 
       
   791     @Override
       
   792     protected InputStream getInputStream() {
       
   793         return new InputStream() {
       
   794             @Override
       
   795             public int read() throws IOException {
       
   796                 byte[] a = new byte[1];
       
   797                 int n = read(a, 0, 1);
       
   798                 return (n > 0) ? (a[0] & 0xff) : -1;
       
   799             }
       
   800             @Override
       
   801             public int read(byte[] b, int off, int len) throws IOException {
       
   802                 return NioSocketImpl.this.read(b, off, len);
       
   803             }
       
   804             @Override
       
   805             public int available() throws IOException {
       
   806                 return NioSocketImpl.this.available();
       
   807             }
       
   808             @Override
       
   809             public void close() throws IOException {
       
   810                 NioSocketImpl.this.close();
       
   811             }
       
   812         };
       
   813     }
       
   814 
       
   815     @Override
       
   816     protected OutputStream getOutputStream() {
       
   817         return new OutputStream() {
       
   818             @Override
       
   819             public void write(int b) throws IOException {
       
   820                 byte[] a = new byte[]{(byte) b};
       
   821                 write(a, 0, 1);
       
   822             }
       
   823             @Override
       
   824             public void write(byte[] b, int off, int len) throws IOException {
       
   825                 NioSocketImpl.this.write(b, off, len);
       
   826             }
       
   827             @Override
       
   828             public void close() throws IOException {
       
   829                 NioSocketImpl.this.close();
       
   830             }
       
   831         };
       
   832     }
       
   833 
       
   834     @Override
       
   835     protected int available() throws IOException {
       
   836         synchronized (stateLock) {
       
   837             ensureOpenAndConnected();
       
   838             if (isInputClosed) {
       
   839                 return 0;
       
   840             } else {
       
   841                 return Net.available(fd);
       
   842             }
       
   843         }
       
   844     }
       
   845 
       
   846     /**
       
   847      * Closes the socket if there are no I/O operations in progress.
       
   848      */
       
   849     private boolean tryClose() throws IOException {
       
   850         assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
       
   851         if (readerThread == 0 && writerThread == 0) {
       
   852             try {
       
   853                 closer.run();
       
   854             } catch (UncheckedIOException ioe) {
       
   855                 throw ioe.getCause();
       
   856             } finally {
       
   857                 state = ST_CLOSED;
       
   858             }
       
   859             return true;
       
   860         } else {
       
   861             return false;
       
   862         }
       
   863     }
       
   864 
       
   865     /**
       
   866      * Invokes tryClose to attempt to close the socket.
       
   867      *
       
   868      * This method is used for deferred closing by I/O operations.
       
   869      */
       
   870     private void tryFinishClose() {
       
   871         try {
       
   872             tryClose();
       
   873         } catch (IOException ignore) { }
       
   874     }
       
   875 
       
   876     /**
       
   877      * Closes the socket. If there are I/O operations in progress then the
       
   878      * socket is pre-closed and the threads are signalled. The socket will be
       
   879      * closed when the last I/O operation aborts.
       
   880      */
       
   881     @Override
       
   882     protected void close() throws IOException {
       
   883         synchronized (stateLock) {
       
   884             int state = this.state;
       
   885             if (state >= ST_CLOSING)
       
   886                 return;
       
   887             if (state == ST_NEW) {
       
   888                 // stillborn
       
   889                 this.state = ST_CLOSED;
       
   890                 return;
       
   891             }
       
   892             this.state = ST_CLOSING;
       
   893 
       
   894             // shutdown output when linger interval not set to 0
       
   895             try {
       
   896                 var SO_LINGER = StandardSocketOptions.SO_LINGER;
       
   897                 if ((int) Net.getSocketOption(fd, SO_LINGER) != 0) {
       
   898                     Net.shutdown(fd, Net.SHUT_WR);
       
   899                 }
       
   900             } catch (IOException ignore) { }
       
   901 
       
   902             // attempt to close the socket. If there are I/O operations in progress
       
   903             // then the socket is pre-closed and the thread(s) signalled. The
       
   904             // last thread will close the file descriptor.
       
   905             if (!tryClose()) {
       
   906                 nd.preClose(fd);
       
   907                 long reader = readerThread;
       
   908                 if (reader != 0)
       
   909                     NativeThread.signal(reader);
       
   910                 long writer = writerThread;
       
   911                 if (writer != 0)
       
   912                     NativeThread.signal(writer);
       
   913             }
       
   914         }
       
   915     }
       
   916 
       
   917     // the socket options supported by client and server sockets
       
   918     private static volatile Set<SocketOption<?>> clientSocketOptions;
       
   919     private static volatile Set<SocketOption<?>> serverSocketOptions;
       
   920 
       
   921     @Override
       
   922     protected Set<SocketOption<?>> supportedOptions() {
       
   923         Set<SocketOption<?>> options = (server) ? serverSocketOptions : clientSocketOptions;
       
   924         if (options == null) {
       
   925             options = new HashSet<>();
       
   926             options.add(StandardSocketOptions.SO_RCVBUF);
       
   927             options.add(StandardSocketOptions.SO_REUSEADDR);
       
   928             if (server) {
       
   929                 // IP_TOS added for server socket to maintain compatibility
       
   930                 options.add(StandardSocketOptions.IP_TOS);
       
   931                 options.addAll(ExtendedSocketOptions.serverSocketOptions());
       
   932             } else {
       
   933                 options.add(StandardSocketOptions.IP_TOS);
       
   934                 options.add(StandardSocketOptions.SO_KEEPALIVE);
       
   935                 options.add(StandardSocketOptions.SO_SNDBUF);
       
   936                 options.add(StandardSocketOptions.SO_LINGER);
       
   937                 options.add(StandardSocketOptions.TCP_NODELAY);
       
   938                 options.addAll(ExtendedSocketOptions.clientSocketOptions());
       
   939             }
       
   940             if (Net.isReusePortAvailable())
       
   941                 options.add(StandardSocketOptions.SO_REUSEPORT);
       
   942             options = Collections.unmodifiableSet(options);
       
   943             if (server) {
       
   944                 serverSocketOptions = options;
       
   945             } else {
       
   946                 clientSocketOptions = options;
       
   947             }
       
   948         }
       
   949         return options;
       
   950     }
       
   951 
       
   952     @Override
       
   953     protected <T> void setOption(SocketOption<T> opt, T value) throws IOException {
       
   954         if (!supportedOptions().contains(opt))
       
   955             throw new UnsupportedOperationException("'" + opt + "' not supported");
       
   956         if (!opt.type().isInstance(value))
       
   957             throw new IllegalArgumentException("Invalid value '" + value + "'");
       
   958         synchronized (stateLock) {
       
   959             ensureOpen();
       
   960             if (opt == StandardSocketOptions.IP_TOS) {
       
   961                 // maps to IP_TOS or IPV6_TCLASS
       
   962                 Net.setSocketOption(fd, family(), opt, value);
       
   963             } else if (opt == StandardSocketOptions.SO_REUSEADDR) {
       
   964                 boolean b = (boolean) value;
       
   965                 if (Net.useExclusiveBind()) {
       
   966                     isReuseAddress = b;
       
   967                 } else {
       
   968                     Net.setSocketOption(fd, opt, b);
       
   969                 }
       
   970             } else {
       
   971                 // option does not need special handling
       
   972                 Net.setSocketOption(fd, opt, value);
       
   973             }
       
   974         }
       
   975     }
       
   976 
       
   977     @SuppressWarnings("unchecked")
       
   978     protected <T> T getOption(SocketOption<T> opt) throws IOException {
       
   979         if (!supportedOptions().contains(opt))
       
   980             throw new UnsupportedOperationException("'" + opt + "' not supported");
       
   981         synchronized (stateLock) {
       
   982             ensureOpen();
       
   983             if (opt == StandardSocketOptions.IP_TOS) {
       
   984                 return (T) Net.getSocketOption(fd, family(), opt);
       
   985             } else if (opt == StandardSocketOptions.SO_REUSEADDR) {
       
   986                 if (Net.useExclusiveBind()) {
       
   987                     return (T) Boolean.valueOf(isReuseAddress);
       
   988                 } else {
       
   989                     return (T) Net.getSocketOption(fd, opt);
       
   990                 }
       
   991             } else {
       
   992                 // option does not need special handling
       
   993                 return (T) Net.getSocketOption(fd, opt);
       
   994             }
       
   995         }
       
   996     }
       
   997 
       
   998     private boolean booleanValue(Object value, String desc) throws SocketException {
       
   999         if (!(value instanceof Boolean))
       
  1000             throw new SocketException("Bad value for " + desc);
       
  1001         return (boolean) value;
       
  1002     }
       
  1003 
       
  1004     private int intValue(Object value, String desc) throws SocketException {
       
  1005         if (!(value instanceof Integer))
       
  1006             throw new SocketException("Bad value for " + desc);
       
  1007         return (int) value;
       
  1008     }
       
  1009 
       
  1010     @Override
       
  1011     public void setOption(int opt, Object value) throws SocketException {
       
  1012         synchronized (stateLock) {
       
  1013             ensureOpen();
       
  1014             try {
       
  1015                 switch (opt) {
       
  1016                 case SO_LINGER: {
       
  1017                     // the value is "false" to disable, or linger interval to enable
       
  1018                     int i;
       
  1019                     if (value instanceof Boolean && ((boolean) value) == false) {
       
  1020                         i = -1;
       
  1021                     } else {
       
  1022                         i = intValue(value, "SO_LINGER");
       
  1023                     }
       
  1024                     Net.setSocketOption(fd, StandardSocketOptions.SO_LINGER, i);
       
  1025                     break;
       
  1026                 }
       
  1027                 case SO_TIMEOUT: {
       
  1028                     int i = intValue(value, "SO_TIMEOUT");
       
  1029                     if (i < 0)
       
  1030                         throw new IllegalArgumentException("timeout < 0");
       
  1031                     timeout = i;
       
  1032                     break;
       
  1033                 }
       
  1034                 case IP_TOS: {
       
  1035                     int i = intValue(value, "IP_TOS");
       
  1036                     Net.setSocketOption(fd, family(), StandardSocketOptions.IP_TOS, i);
       
  1037                     break;
       
  1038                 }
       
  1039                 case TCP_NODELAY: {
       
  1040                     boolean b = booleanValue(value, "TCP_NODELAY");
       
  1041                     Net.setSocketOption(fd, StandardSocketOptions.TCP_NODELAY, b);
       
  1042                     break;
       
  1043                 }
       
  1044                 case SO_SNDBUF: {
       
  1045                     int i = intValue(value, "SO_SNDBUF");
       
  1046                     if (i <= 0)
       
  1047                         throw new SocketException("SO_SNDBUF <= 0");
       
  1048                     Net.setSocketOption(fd, StandardSocketOptions.SO_SNDBUF, i);
       
  1049                     break;
       
  1050                 }
       
  1051                 case SO_RCVBUF: {
       
  1052                     int i = intValue(value, "SO_RCVBUF");
       
  1053                     if (i <= 0)
       
  1054                         throw new SocketException("SO_RCVBUF <= 0");
       
  1055                     Net.setSocketOption(fd, StandardSocketOptions.SO_RCVBUF, i);
       
  1056                     break;
       
  1057                 }
       
  1058                 case SO_KEEPALIVE: {
       
  1059                     boolean b = booleanValue(value, "SO_KEEPALIVE");
       
  1060                     Net.setSocketOption(fd, StandardSocketOptions.SO_KEEPALIVE, b);
       
  1061                     break;
       
  1062                 }
       
  1063                 case SO_OOBINLINE: {
       
  1064                     boolean b = booleanValue(value, "SO_OOBINLINE");
       
  1065                     Net.setSocketOption(fd, ExtendedSocketOption.SO_OOBINLINE, b);
       
  1066                     break;
       
  1067                 }
       
  1068                 case SO_REUSEADDR: {
       
  1069                     boolean b = booleanValue(value, "SO_REUSEADDR");
       
  1070                     if (Net.useExclusiveBind()) {
       
  1071                         isReuseAddress = b;
       
  1072                     } else {
       
  1073                         Net.setSocketOption(fd, StandardSocketOptions.SO_REUSEADDR, b);
       
  1074                     }
       
  1075                     break;
       
  1076                 }
       
  1077                 case SO_REUSEPORT: {
       
  1078                     if (!Net.isReusePortAvailable())
       
  1079                         throw new SocketException("SO_REUSEPORT not supported");
       
  1080                     boolean b = booleanValue(value, "SO_REUSEPORT");
       
  1081                     Net.setSocketOption(fd, StandardSocketOptions.SO_REUSEPORT, b);
       
  1082                     break;
       
  1083                 }
       
  1084                 default:
       
  1085                     throw new SocketException("Unknown option " + opt);
       
  1086                 }
       
  1087             } catch (SocketException e) {
       
  1088                 throw e;
       
  1089             } catch (IllegalArgumentException | IOException e) {
       
  1090                 throw new SocketException(e.getMessage());
       
  1091             }
       
  1092         }
       
  1093     }
       
  1094 
       
  1095     @Override
       
  1096     public Object getOption(int opt) throws SocketException {
       
  1097         synchronized (stateLock) {
       
  1098             ensureOpen();
       
  1099             try {
       
  1100                 switch (opt) {
       
  1101                 case SO_TIMEOUT:
       
  1102                     return timeout;
       
  1103                 case TCP_NODELAY:
       
  1104                     return Net.getSocketOption(fd, StandardSocketOptions.TCP_NODELAY);
       
  1105                 case SO_OOBINLINE:
       
  1106                     return Net.getSocketOption(fd, ExtendedSocketOption.SO_OOBINLINE);
       
  1107                 case SO_LINGER: {
       
  1108                     // return "false" when disabled, linger interval when enabled
       
  1109                     int i = (int) Net.getSocketOption(fd, StandardSocketOptions.SO_LINGER);
       
  1110                     if (i == -1) {
       
  1111                         return Boolean.FALSE;
       
  1112                     } else {
       
  1113                         return i;
       
  1114                     }
       
  1115                 }
       
  1116                 case SO_REUSEADDR:
       
  1117                     if (Net.useExclusiveBind()) {
       
  1118                         return isReuseAddress;
       
  1119                     } else {
       
  1120                         return Net.getSocketOption(fd, StandardSocketOptions.SO_REUSEADDR);
       
  1121                     }
       
  1122                 case SO_BINDADDR:
       
  1123                     return Net.localAddress(fd).getAddress();
       
  1124                 case SO_SNDBUF:
       
  1125                     return Net.getSocketOption(fd, StandardSocketOptions.SO_SNDBUF);
       
  1126                 case SO_RCVBUF:
       
  1127                     return Net.getSocketOption(fd, StandardSocketOptions.SO_RCVBUF);
       
  1128                 case IP_TOS:
       
  1129                     return Net.getSocketOption(fd, family(), StandardSocketOptions.IP_TOS);
       
  1130                 case SO_KEEPALIVE:
       
  1131                     return Net.getSocketOption(fd, StandardSocketOptions.SO_KEEPALIVE);
       
  1132                 case SO_REUSEPORT:
       
  1133                     if (!Net.isReusePortAvailable())
       
  1134                         throw new SocketException("SO_REUSEPORT not supported");
       
  1135                     return Net.getSocketOption(fd, StandardSocketOptions.SO_REUSEPORT);
       
  1136                 default:
       
  1137                     throw new SocketException("Unknown option " + opt);
       
  1138                 }
       
  1139             } catch (SocketException e) {
       
  1140                 throw e;
       
  1141             } catch (IllegalArgumentException | IOException e) {
       
  1142                 throw new SocketException(e.getMessage());
       
  1143             }
       
  1144         }
       
  1145     }
       
  1146 
       
  1147     @Override
       
  1148     protected void shutdownInput() throws IOException {
       
  1149         synchronized (stateLock) {
       
  1150             ensureOpenAndConnected();
       
  1151             if (!isInputClosed) {
       
  1152                 Net.shutdown(fd, Net.SHUT_RD);
       
  1153                 isInputClosed = true;
       
  1154             }
       
  1155         }
       
  1156     }
       
  1157 
       
  1158     @Override
       
  1159     protected void shutdownOutput() throws IOException {
       
  1160         synchronized (stateLock) {
       
  1161             ensureOpenAndConnected();
       
  1162             if (!isOutputClosed) {
       
  1163                 Net.shutdown(fd, Net.SHUT_WR);
       
  1164                 isOutputClosed = true;
       
  1165             }
       
  1166         }
       
  1167     }
       
  1168 
       
  1169     @Override
       
  1170     protected boolean supportsUrgentData() {
       
  1171         return true;
       
  1172     }
       
  1173 
       
  1174     @Override
       
  1175     protected void sendUrgentData(int data) throws IOException {
       
  1176         writeLock.lock();
       
  1177         try {
       
  1178             int n = 0;
       
  1179             FileDescriptor fd = beginWrite();
       
  1180             try {
       
  1181                 do {
       
  1182                     n = Net.sendOOB(fd, (byte) data);
       
  1183                 } while (n == IOStatus.INTERRUPTED && isOpen());
       
  1184                 if (n == IOStatus.UNAVAILABLE) {
       
  1185                     throw new SocketException("No buffer space available");
       
  1186                 }
       
  1187             } finally {
       
  1188                 endWrite(n > 0);
       
  1189             }
       
  1190         } finally {
       
  1191             writeLock.unlock();
       
  1192         }
       
  1193     }
       
  1194 
       
  1195     /**
       
  1196      * A task that closes a SocketImpl's file descriptor. The task runs when the
       
  1197      * SocketImpl is explicitly closed and when the SocketImpl becomes phantom
       
  1198      * reachable.
       
  1199      */
       
  1200     private static class FileDescriptorCloser implements Runnable {
       
  1201         private static final VarHandle CLOSED;
       
  1202         static {
       
  1203             try {
       
  1204                 MethodHandles.Lookup l = MethodHandles.lookup();
       
  1205                 CLOSED = l.findVarHandle(FileDescriptorCloser.class,
       
  1206                                          "closed",
       
  1207                                          boolean.class);
       
  1208             } catch (Exception e) {
       
  1209                 throw new InternalError(e);
       
  1210             }
       
  1211         }
       
  1212 
       
  1213         private final FileDescriptor fd;
       
  1214         private final boolean stream;
       
  1215         private volatile boolean closed;
       
  1216 
       
  1217         FileDescriptorCloser(FileDescriptor fd, boolean stream) {
       
  1218             this.fd = fd;
       
  1219             this.stream = stream;
       
  1220         }
       
  1221 
       
  1222         static FileDescriptorCloser create(NioSocketImpl impl) {
       
  1223             assert Thread.holdsLock(impl.stateLock);
       
  1224             var closer = new FileDescriptorCloser(impl.fd, impl.stream);
       
  1225             CleanerFactory.cleaner().register(impl, closer);
       
  1226             return closer;
       
  1227         }
       
  1228 
       
  1229         @Override
       
  1230         public void run() {
       
  1231             if (CLOSED.compareAndSet(this, false, true)) {
       
  1232                 try {
       
  1233                     nd.close(fd);
       
  1234                 } catch (IOException ioe) {
       
  1235                     throw new UncheckedIOException(ioe);
       
  1236                 } finally {
       
  1237                     if (!stream) {
       
  1238                         // decrement
       
  1239                         ResourceManager.afterUdpClose();
       
  1240                     }
       
  1241                 }
       
  1242             }
       
  1243         }
       
  1244     }
       
  1245 
       
  1246     /**
       
  1247      * Attempts to acquire the given lock within the given waiting time.
       
  1248      * @return the remaining time in nanoseconds when the lock is acquired, zero
       
  1249      *         or less if the lock was not acquired before the timeout expired
       
  1250      */
       
  1251     private static long tryLock(ReentrantLock lock, long timeout, TimeUnit unit) {
       
  1252         assert timeout > 0;
       
  1253         boolean interrupted = false;
       
  1254         long nanos = NANOSECONDS.convert(timeout, unit);
       
  1255         long remainingNanos = nanos;
       
  1256         long startNanos = System.nanoTime();
       
  1257         boolean acquired = false;
       
  1258         while (!acquired && (remainingNanos > 0)) {
       
  1259             try {
       
  1260                 acquired = lock.tryLock(remainingNanos, NANOSECONDS);
       
  1261             } catch (InterruptedException e) {
       
  1262                 interrupted = true;
       
  1263             }
       
  1264             remainingNanos = nanos - (System.nanoTime() - startNanos);
       
  1265         }
       
  1266         if (acquired && remainingNanos <= 0L)
       
  1267             lock.unlock();  // release lock if timeout has expired
       
  1268         if (interrupted)
       
  1269             Thread.currentThread().interrupt();
       
  1270         return remainingNanos;
       
  1271     }
       
  1272 
       
  1273     /**
       
  1274      * Returns the socket protocol family.
       
  1275      */
       
  1276     private static ProtocolFamily family() {
       
  1277         if (Net.isIPv6Available()) {
       
  1278             return StandardProtocolFamily.INET6;
       
  1279         } else {
       
  1280             return StandardProtocolFamily.INET;
       
  1281         }
       
  1282     }
       
  1283 }