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 }