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