1 /*
   2  * Copyright (c) 2000, 2025, 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.net.InetAddress;
  31 import java.net.Inet4Address;
  32 import java.net.InetSocketAddress;
  33 import java.net.ProtocolFamily;
  34 import java.net.Socket;
  35 import java.net.SocketAddress;
  36 import java.net.SocketException;
  37 import java.net.SocketOption;
  38 import java.net.SocketTimeoutException;
  39 import java.net.StandardSocketOptions;
  40 import java.nio.ByteBuffer;
  41 import java.nio.channels.AlreadyBoundException;
  42 import java.nio.channels.AlreadyConnectedException;
  43 import java.nio.channels.AsynchronousCloseException;
  44 import java.nio.channels.ClosedChannelException;
  45 import java.nio.channels.ConnectionPendingException;
  46 import java.nio.channels.IllegalBlockingModeException;
  47 import java.nio.channels.NoConnectionPendingException;
  48 import java.nio.channels.NotYetConnectedException;
  49 import java.nio.channels.SelectionKey;
  50 import java.nio.channels.SocketChannel;
  51 import java.nio.channels.spi.SelectorProvider;
  52 import java.nio.file.Path;
  53 import java.util.Collections;
  54 import java.util.HashSet;
  55 import java.util.Set;
  56 import java.util.Objects;
  57 import java.util.concurrent.locks.ReentrantLock;
  58 import static java.net.StandardProtocolFamily.INET;
  59 import static java.net.StandardProtocolFamily.INET6;
  60 import static java.net.StandardProtocolFamily.UNIX;
  61 
  62 import jdk.internal.event.SocketReadEvent;
  63 import jdk.internal.event.SocketWriteEvent;
  64 import sun.net.ConnectionResetException;
  65 import sun.net.NetHooks;
  66 import sun.net.ext.ExtendedSocketOptions;
  67 import jdk.internal.util.Exceptions;
  68 
  69 /**
  70  * An implementation of SocketChannels
  71  */
  72 
  73 class SocketChannelImpl
  74     extends SocketChannel
  75     implements SelChImpl
  76 {
  77     // Used to make native read and write calls
  78     private static final NativeDispatcher nd = new SocketDispatcher();
  79 
  80     // The protocol family of the socket
  81     private final ProtocolFamily family;
  82 
  83     // Our file descriptor object
  84     private final FileDescriptor fd;
  85     private final int fdVal;
  86 
  87     // Lock held by current reading or connecting thread
  88     private final ReentrantLock readLock = new ReentrantLock();
  89 
  90     // Lock held by current writing or connecting thread
  91     private final ReentrantLock writeLock = new ReentrantLock();
  92 
  93     // Lock held by any thread that modifies the state fields declared below
  94     // DO NOT invoke a blocking I/O operation while holding this lock!
  95     private final Object stateLock = new Object();
  96 
  97     // Input/Output closed
  98     private volatile boolean isInputClosed;
  99     private volatile boolean isOutputClosed;
 100 
 101     // Connection reset protected by readLock
 102     private boolean connectionReset;
 103 
 104     // -- The following fields are protected by stateLock
 105 
 106     // set true when exclusive binding is on and SO_REUSEADDR is emulated
 107     private boolean isReuseAddress;
 108 
 109     // State, increases monotonically
 110     private static final int ST_UNCONNECTED = 0;
 111     private static final int ST_CONNECTIONPENDING = 1;
 112     private static final int ST_CONNECTED = 2;
 113     private static final int ST_CLOSING = 3;
 114     private static final int ST_CLOSED = 4;
 115     private volatile int state;  // need stateLock to change
 116 
 117     // IDs of native threads doing reads and writes, for signalling
 118     private NativeThread readerThread;
 119     private NativeThread writerThread;
 120 
 121     // Binding
 122     private SocketAddress localAddress;
 123     private SocketAddress remoteAddress;
 124 
 125     // Socket adaptor, created on demand
 126     private Socket socket;
 127 
 128     // True if the channel's socket has been forced into non-blocking mode
 129     // by a virtual thread. It cannot be reset. When the channel is in
 130     // blocking mode and the channel's socket is in non-blocking mode then
 131     // operations that don't complete immediately will poll the socket and
 132     // preserve the semantics of blocking operations.
 133     private volatile boolean forcedNonBlocking;
 134 
 135     // -- End of fields protected by stateLock
 136 
 137     SocketChannelImpl(SelectorProvider sp) throws IOException {
 138         this(sp, Net.isIPv6Available() ? INET6 : INET);
 139     }
 140 
 141     SocketChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException {
 142         super(sp);
 143         Objects.requireNonNull(family, "'family' is null");
 144         if ((family != INET) && (family != INET6) && (family != UNIX)) {
 145             throw new UnsupportedOperationException("Protocol family not supported");
 146         }
 147         if (family == INET6 && !Net.isIPv6Available()) {
 148             throw new UnsupportedOperationException("IPv6 not available");
 149         }
 150 
 151         this.family = family;
 152         if (family == UNIX) {
 153             this.fd = UnixDomainSockets.socket();
 154         } else {
 155             this.fd = Net.socket(family, true);
 156         }
 157         this.fdVal = IOUtil.fdVal(fd);
 158     }
 159 
 160     // Constructor for sockets obtained from server sockets
 161     //
 162     SocketChannelImpl(SelectorProvider sp,
 163                       ProtocolFamily family,
 164                       FileDescriptor fd,
 165                       SocketAddress remoteAddress)
 166         throws IOException
 167     {
 168         super(sp);
 169         this.family = family;
 170         this.fd = fd;
 171         this.fdVal = IOUtil.fdVal(fd);
 172         synchronized (stateLock) {
 173             if (family == UNIX) {
 174                 this.localAddress = UnixDomainSockets.localAddress(fd);
 175             } else {
 176                 this.localAddress = Net.localAddress(fd);
 177             }
 178             this.remoteAddress = remoteAddress;
 179             this.state = ST_CONNECTED;
 180         }
 181     }
 182 
 183     /**
 184      * Returns true if this channel is to a INET or INET6 socket.
 185      */
 186     boolean isNetSocket() {
 187         return (family == INET) || (family == INET6);
 188     }
 189 
 190     /**
 191      * Returns true if this channel is to a UNIX socket.
 192      */
 193     boolean isUnixSocket() {
 194         return (family == UNIX);
 195     }
 196 
 197     /**
 198      * Checks that the channel is open.
 199      *
 200      * @throws ClosedChannelException if channel is closed (or closing)
 201      */
 202     private void ensureOpen() throws ClosedChannelException {
 203         if (!isOpen())
 204             throw new ClosedChannelException();
 205     }
 206 
 207     /**
 208      * Checks that the channel is open and connected.
 209      *
 210      * @apiNote This method uses the "state" field to check if the channel is
 211      * open. It should never be used in conjunction with isOpen or ensureOpen
 212      * as these methods check AbstractInterruptibleChannel's closed field - that
 213      * field is set before implCloseSelectableChannel is called and so before
 214      * the state is changed.
 215      *
 216      * @throws ClosedChannelException if channel is closed (or closing)
 217      * @throws NotYetConnectedException if open and not connected
 218      */
 219     private void ensureOpenAndConnected() throws ClosedChannelException {
 220         int state = this.state;
 221         if (state < ST_CONNECTED) {
 222             throw new NotYetConnectedException();
 223         } else if (state > ST_CONNECTED) {
 224             throw new ClosedChannelException();
 225         }
 226     }
 227 
 228     @Override
 229     public Socket socket() {
 230         synchronized (stateLock) {
 231             if (socket == null) {
 232                 if (isNetSocket()) {
 233                     socket = SocketAdaptor.create(this);
 234                 } else {
 235                     throw new UnsupportedOperationException("Not supported");
 236                 }
 237             }
 238             return socket;
 239         }
 240     }
 241 
 242     @Override
 243     public SocketAddress getLocalAddress() throws IOException {
 244         synchronized (stateLock) {
 245             ensureOpen();
 246             return localAddress;
 247         }
 248     }
 249 
 250     @Override
 251     public SocketAddress getRemoteAddress() throws IOException {
 252         synchronized (stateLock) {
 253             ensureOpen();
 254             return remoteAddress;
 255         }
 256     }
 257 
 258     @Override
 259     public <T> SocketChannel setOption(SocketOption<T> name, T value)
 260         throws IOException
 261     {
 262         Objects.requireNonNull(name);
 263         if (!supportedOptions().contains(name))
 264             throw new UnsupportedOperationException("'" + name + "' not supported");
 265         if (!name.type().isInstance(value))
 266             throw new IllegalArgumentException("Invalid value '" + value + "'");
 267 
 268         synchronized (stateLock) {
 269             ensureOpen();
 270 
 271             if (isNetSocket()) {
 272                 if (name == StandardSocketOptions.IP_TOS) {
 273                     // maps to IPV6_TCLASS and/or IP_TOS
 274                     Net.setIpSocketOption(fd, family, name, value);
 275                     return this;
 276                 }
 277                 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 278                     // SO_REUSEADDR emulated when using exclusive bind
 279                     isReuseAddress = (Boolean) value;
 280                     return this;
 281                 }
 282             }
 283 
 284             // no options that require special handling
 285             Net.setSocketOption(fd, name, value);
 286             return this;
 287         }
 288     }
 289 
 290     @Override
 291     @SuppressWarnings("unchecked")
 292     public <T> T getOption(SocketOption<T> name)
 293         throws IOException
 294     {
 295         Objects.requireNonNull(name);
 296         if (!supportedOptions().contains(name))
 297             throw new UnsupportedOperationException("'" + name + "' not supported");
 298 
 299         synchronized (stateLock) {
 300             ensureOpen();
 301 
 302             if (isNetSocket()) {
 303                 if (name == StandardSocketOptions.IP_TOS) {
 304                     // special handling for IP_TOS
 305                     return (T) Net.getSocketOption(fd, family, name);
 306                 }
 307                 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 308                     // SO_REUSEADDR emulated when using exclusive bind
 309                     return (T) Boolean.valueOf(isReuseAddress);
 310                 }
 311             }
 312 
 313             // no options that require special handling
 314             return (T) Net.getSocketOption(fd, name);
 315         }
 316     }
 317 
 318     private static class DefaultOptionsHolder {
 319         static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions();
 320         static final Set<SocketOption<?>> defaultUnixOptions = defaultUnixOptions();
 321 
 322         private static Set<SocketOption<?>> defaultInetOptions() {
 323             HashSet<SocketOption<?>> set = new HashSet<>();
 324             set.add(StandardSocketOptions.SO_SNDBUF);
 325             set.add(StandardSocketOptions.SO_RCVBUF);
 326             set.add(StandardSocketOptions.SO_KEEPALIVE);
 327             set.add(StandardSocketOptions.SO_REUSEADDR);
 328             if (Net.isReusePortAvailable()) {
 329                 set.add(StandardSocketOptions.SO_REUSEPORT);
 330             }
 331             set.add(StandardSocketOptions.SO_LINGER);
 332             set.add(StandardSocketOptions.TCP_NODELAY);
 333             // additional options required by socket adaptor
 334             set.add(StandardSocketOptions.IP_TOS);
 335             set.add(ExtendedSocketOption.SO_OOBINLINE);
 336             set.addAll(ExtendedSocketOptions.clientSocketOptions());
 337             return Collections.unmodifiableSet(set);
 338         }
 339 
 340         private static Set<SocketOption<?>> defaultUnixOptions() {
 341             HashSet<SocketOption<?>> set = new HashSet<>();
 342             set.add(StandardSocketOptions.SO_SNDBUF);
 343             set.add(StandardSocketOptions.SO_RCVBUF);
 344             set.add(StandardSocketOptions.SO_LINGER);
 345             set.addAll(ExtendedSocketOptions.unixDomainSocketOptions());
 346             return Collections.unmodifiableSet(set);
 347         }
 348     }
 349 
 350     @Override
 351     public final Set<SocketOption<?>> supportedOptions() {
 352         if (isUnixSocket()) {
 353             return DefaultOptionsHolder.defaultUnixOptions;
 354         } else {
 355             return DefaultOptionsHolder.defaultInetOptions;
 356         }
 357     }
 358 
 359     /**
 360      * Marks the beginning of a read operation that might block.
 361      *
 362      * @throws ClosedChannelException if blocking and the channel is closed
 363      */
 364     private void beginRead(boolean blocking) throws ClosedChannelException {
 365         if (blocking) {
 366             // set hook for Thread.interrupt
 367             begin();
 368 
 369             synchronized (stateLock) {
 370                 ensureOpen();
 371                 // record thread so it can be signalled if needed
 372                 readerThread = NativeThread.current();
 373             }
 374         }
 375     }
 376 
 377     /**
 378      * Marks the end of a read operation that may have blocked.
 379      *
 380      * @throws AsynchronousCloseException if the channel was closed due to this
 381      * thread being interrupted on a blocking read operation.
 382      */
 383     private void endRead(boolean blocking, boolean completed)
 384         throws AsynchronousCloseException
 385     {
 386         if (blocking) {
 387             synchronized (stateLock) {
 388                 readerThread = null;
 389                 if (state == ST_CLOSING) {
 390                     tryFinishClose();
 391                 }
 392             }
 393             // remove hook for Thread.interrupt
 394             end(completed);
 395         }
 396     }
 397 
 398     private void throwConnectionReset() throws SocketException {
 399         throw new SocketException("Connection reset");
 400     }
 401 
 402     private int implRead(ByteBuffer buf) throws IOException {
 403         Objects.requireNonNull(buf);
 404 
 405         readLock.lock();
 406         try {
 407             ensureOpenAndConnected();
 408             boolean blocking = isBlocking();
 409             int n = 0;
 410             try {
 411                 beginRead(blocking);
 412 
 413                 // check if connection has been reset
 414                 if (connectionReset)
 415                     throwConnectionReset();
 416 
 417                 // check if input is shutdown
 418                 if (isInputClosed)
 419                     return IOStatus.EOF;
 420 
 421                 configureSocketNonBlockingIfVirtualThread();
 422                 n = IOUtil.read(fd, buf, -1, nd);
 423                 if (blocking) {
 424                     while (IOStatus.okayToRetry(n) && isOpen()) {
 425                         park(Net.POLLIN);
 426                         n = IOUtil.read(fd, buf, -1, nd);
 427                     }
 428                 }
 429             } catch (ConnectionResetException e) {
 430                 connectionReset = true;
 431                 throwConnectionReset();
 432             } finally {
 433                 endRead(blocking, n > 0);
 434                 if (n <= 0 && isInputClosed)
 435                     return IOStatus.EOF;
 436             }
 437             return IOStatus.normalize(n);
 438         } finally {
 439             readLock.unlock();
 440         }
 441     }
 442 
 443     private long implRead(ByteBuffer[] dsts, int offset, int length)
 444         throws IOException
 445     {
 446         Objects.checkFromIndexSize(offset, length, dsts.length);
 447 
 448         readLock.lock();
 449         try {
 450             ensureOpenAndConnected();
 451             boolean blocking = isBlocking();
 452             long n = 0;
 453             try {
 454                 beginRead(blocking);
 455 
 456                 // check if connection has been reset
 457                 if (connectionReset)
 458                     throwConnectionReset();
 459 
 460                 // check if input is shutdown
 461                 if (isInputClosed)
 462                     return IOStatus.EOF;
 463 
 464                 configureSocketNonBlockingIfVirtualThread();
 465                 n = IOUtil.read(fd, dsts, offset, length, nd);
 466                 if (blocking) {
 467                     while (IOStatus.okayToRetry(n) && isOpen()) {
 468                         park(Net.POLLIN);
 469                         n = IOUtil.read(fd, dsts, offset, length, nd);
 470                     }
 471                 }
 472             } catch (ConnectionResetException e) {
 473                 connectionReset = true;
 474                 throwConnectionReset();
 475             } finally {
 476                 endRead(blocking, n > 0);
 477                 if (n <= 0 && isInputClosed)
 478                     return IOStatus.EOF;
 479             }
 480             return IOStatus.normalize(n);
 481         } finally {
 482             readLock.unlock();
 483         }
 484     }
 485 
 486     @Override
 487     public int read(ByteBuffer buf) throws IOException {
 488         if (!SocketReadEvent.enabled()) {
 489             return implRead(buf);
 490         }
 491         long start = SocketReadEvent.timestamp();
 492         int nbytes = implRead(buf);
 493         SocketReadEvent.offer(start, nbytes, remoteAddress(), 0);
 494         return nbytes;
 495     }
 496 
 497 
 498     @Override
 499     public long read(ByteBuffer[] dsts, int offset, int length)
 500         throws IOException
 501     {
 502         if (!SocketReadEvent.enabled()) {
 503             return implRead(dsts, offset, length);
 504         }
 505         long start = SocketReadEvent.timestamp();
 506         long nbytes = implRead(dsts, offset, length);
 507         SocketReadEvent.offer(start, nbytes, remoteAddress(), 0);
 508         return nbytes;
 509     }
 510 
 511     /**
 512      * Marks the beginning of a write operation that might block.
 513      *
 514      * @throws ClosedChannelException if blocking and the channel is closed
 515      */
 516     private void beginWrite(boolean blocking) throws ClosedChannelException {
 517         if (blocking) {
 518             // set hook for Thread.interrupt
 519             begin();
 520 
 521             synchronized (stateLock) {
 522                 ensureOpen();
 523                 if (isOutputClosed)
 524                     throw new ClosedChannelException();
 525                 // record thread so it can be signalled if needed
 526                 writerThread = NativeThread.current();
 527             }
 528         }
 529     }
 530 
 531     /**
 532      * Marks the end of a write operation that may have blocked.
 533      *
 534      * @throws AsynchronousCloseException if the channel was closed due to this
 535      * thread being interrupted on a blocking write operation.
 536      */
 537     private void endWrite(boolean blocking, boolean completed)
 538         throws AsynchronousCloseException
 539     {
 540         if (blocking) {
 541             synchronized (stateLock) {
 542                 writerThread = null;
 543                 if (state == ST_CLOSING) {
 544                     tryFinishClose();
 545                 }
 546             }
 547             // remove hook for Thread.interrupt
 548             end(completed);
 549         }
 550     }
 551 
 552     private int implWrite(ByteBuffer buf) throws IOException {
 553         Objects.requireNonNull(buf);
 554         writeLock.lock();
 555         try {
 556             ensureOpenAndConnected();
 557             boolean blocking = isBlocking();
 558             int n = 0;
 559             try {
 560                 beginWrite(blocking);
 561                 configureSocketNonBlockingIfVirtualThread();
 562                 n = IOUtil.write(fd, buf, -1, nd);
 563                 if (blocking) {
 564                     while (IOStatus.okayToRetry(n) && isOpen()) {
 565                         park(Net.POLLOUT);
 566                         n = IOUtil.write(fd, buf, -1, nd);
 567                     }
 568                 }
 569             } finally {
 570                 endWrite(blocking, n > 0);
 571                 if (n <= 0 && isOutputClosed)
 572                     throw new AsynchronousCloseException();
 573             }
 574             return IOStatus.normalize(n);
 575         } finally {
 576             writeLock.unlock();
 577         }
 578     }
 579 
 580     private long implWrite(ByteBuffer[] srcs, int offset, int length)
 581         throws IOException
 582     {
 583         Objects.checkFromIndexSize(offset, length, srcs.length);
 584 
 585         writeLock.lock();
 586         try {
 587             ensureOpenAndConnected();
 588             boolean blocking = isBlocking();
 589             long n = 0;
 590             try {
 591                 beginWrite(blocking);
 592                 configureSocketNonBlockingIfVirtualThread();
 593                 n = IOUtil.write(fd, srcs, offset, length, nd);
 594                 if (blocking) {
 595                     while (IOStatus.okayToRetry(n) && isOpen()) {
 596                         park(Net.POLLOUT);
 597                         n = IOUtil.write(fd, srcs, offset, length, nd);
 598                     }
 599                 }
 600             } finally {
 601                 endWrite(blocking, n > 0);
 602                 if (n <= 0 && isOutputClosed)
 603                     throw new AsynchronousCloseException();
 604             }
 605             return IOStatus.normalize(n);
 606         } finally {
 607             writeLock.unlock();
 608         }
 609     }
 610 
 611     @Override
 612     public int write(ByteBuffer buf) throws IOException {
 613         if (!SocketWriteEvent.enabled()) {
 614             return implWrite(buf);
 615         }
 616         long start = SocketWriteEvent.timestamp();
 617         int nbytes = implWrite(buf);
 618         SocketWriteEvent.offer(start, nbytes, remoteAddress());
 619         return nbytes;
 620     }
 621 
 622     @Override
 623     public long write(ByteBuffer[] srcs, int offset, int length)
 624         throws IOException
 625     {
 626         if (!SocketWriteEvent.enabled()) {
 627             return implWrite(srcs, offset, length);
 628         }
 629         long start = SocketWriteEvent.timestamp();
 630         long nbytes = implWrite(srcs, offset, length);
 631         SocketWriteEvent.offer(start, nbytes, remoteAddress());
 632         return nbytes;
 633     }
 634 
 635     /**
 636      * Writes a byte of out of band data.
 637      */
 638     int sendOutOfBandData(byte b) throws IOException {
 639         writeLock.lock();
 640         try {
 641             ensureOpenAndConnected();
 642             boolean blocking = isBlocking();
 643             int n = 0;
 644             try {
 645                 beginWrite(blocking);
 646                 configureSocketNonBlockingIfVirtualThread();
 647                 do {
 648                     n = Net.sendOOB(fd, b);
 649                 } while (n == IOStatus.INTERRUPTED && isOpen());
 650                 if (blocking && n == IOStatus.UNAVAILABLE) {
 651                     throw new SocketException("No buffer space available");
 652                 }
 653             } finally {
 654                 endWrite(blocking, n > 0);
 655                 if (n <= 0 && isOutputClosed)
 656                     throw new AsynchronousCloseException();
 657             }
 658             return IOStatus.normalize(n);
 659         } finally {
 660             writeLock.unlock();
 661         }
 662     }
 663 
 664     /**
 665      * Marks the beginning of a transfer to this channel.
 666      * @throws ClosedChannelException if channel is closed or the output is shutdown
 667      * @throws NotYetConnectedException if open and not connected
 668      */
 669     void beforeTransferTo() throws ClosedChannelException {
 670         boolean completed = false;
 671         writeLock.lock();
 672         try {
 673             synchronized (stateLock) {
 674                 ensureOpenAndConnected();
 675                 if (isOutputClosed)
 676                     throw new ClosedChannelException();
 677                 writerThread = NativeThread.current();
 678                 completed = true;
 679             }
 680         } finally {
 681             if (!completed) {
 682                 writeLock.unlock();
 683             }
 684         }
 685     }
 686 
 687     /**
 688      * Marks the end of a transfer to this channel.
 689      * @throws AsynchronousCloseException if not completed and the channel is closed
 690      */
 691     void afterTransferTo(boolean completed) throws AsynchronousCloseException {
 692         synchronized (stateLock) {
 693             writerThread = null;
 694             if (state == ST_CLOSING) {
 695                 tryFinishClose();
 696             }
 697         }
 698         writeLock.unlock();
 699         if (!completed && !isOpen()) {
 700             throw new AsynchronousCloseException();
 701         }
 702     }
 703 
 704     @Override
 705     protected void implConfigureBlocking(boolean block) throws IOException {
 706         readLock.lock();
 707         try {
 708             writeLock.lock();
 709             try {
 710                 lockedConfigureBlocking(block);
 711             } finally {
 712                 writeLock.unlock();
 713             }
 714         } finally {
 715             readLock.unlock();
 716         }
 717     }
 718 
 719     /**
 720      * Adjust the blocking mode while holding readLock or writeLock.
 721      */
 722     private void lockedConfigureBlocking(boolean block) throws IOException {
 723         assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
 724         synchronized (stateLock) {
 725             ensureOpen();
 726             // do nothing if virtual thread has forced the socket to be non-blocking
 727             if (!forcedNonBlocking) {
 728                 IOUtil.configureBlocking(fd, block);
 729             }
 730         }
 731     }
 732 
 733     /**
 734      * Attempts to adjust the blocking mode if the channel is open.
 735      * @return {@code true} if the blocking mode was adjusted
 736      */
 737     private boolean tryLockedConfigureBlocking(boolean block) throws IOException {
 738         assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
 739         synchronized (stateLock) {
 740             // do nothing if virtual thread has forced the socket to be non-blocking
 741             if (!forcedNonBlocking && isOpen()) {
 742                 IOUtil.configureBlocking(fd, block);
 743                 return true;
 744             } else {
 745                 return false;
 746             }
 747         }
 748     }
 749 
 750     /**
 751      * Ensures that the socket is configured non-blocking when on a virtual thread.
 752      */
 753     private void configureSocketNonBlockingIfVirtualThread() throws IOException {
 754         assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
 755         if (!forcedNonBlocking && Thread.currentThread().isVirtual()) {
 756             synchronized (stateLock) {
 757                 ensureOpen();
 758                 IOUtil.configureBlocking(fd, false);
 759                 forcedNonBlocking = true;
 760             }
 761         }
 762     }
 763 
 764     /**
 765      * Returns the local address, or null if not bound
 766      */
 767     SocketAddress localAddress() {
 768         synchronized (stateLock) {
 769             return localAddress;
 770         }
 771     }
 772 
 773     /**
 774      * Returns the remote address, or null if not connected
 775      */
 776     SocketAddress remoteAddress() {
 777         synchronized (stateLock) {
 778             return remoteAddress;
 779         }
 780     }
 781 
 782     @Override
 783     public SocketChannel bind(SocketAddress local) throws IOException {
 784         readLock.lock();
 785         try {
 786             writeLock.lock();
 787             try {
 788                 synchronized (stateLock) {
 789                     ensureOpen();
 790                     if (state == ST_CONNECTIONPENDING)
 791                         throw new ConnectionPendingException();
 792                     if (localAddress != null)
 793                         throw new AlreadyBoundException();
 794                     if (isUnixSocket()) {
 795                         localAddress = unixBind(local);
 796                     } else {
 797                         localAddress = netBind(local);
 798                     }
 799                 }
 800             } finally {
 801                 writeLock.unlock();
 802             }
 803         } finally {
 804             readLock.unlock();
 805         }
 806         return this;
 807     }
 808 
 809     private SocketAddress unixBind(SocketAddress local) throws IOException {
 810         if (local == null) {
 811             return UnixDomainSockets.unnamed();
 812         } else {
 813             Path path = UnixDomainSockets.checkAddress(local).getPath();
 814             if (path.toString().isEmpty()) {
 815                 return UnixDomainSockets.unnamed();
 816             } else {
 817                 // bind to non-empty path
 818                 UnixDomainSockets.bind(fd, path);
 819                 return UnixDomainSockets.localAddress(fd);
 820             }
 821         }
 822     }
 823 
 824     private SocketAddress netBind(SocketAddress local) throws IOException {
 825         InetSocketAddress isa;
 826         if (local == null) {
 827             isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
 828         } else {
 829             isa = Net.checkAddress(local, family);
 830         }
 831         NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
 832         Net.bind(family, fd, isa.getAddress(), isa.getPort());
 833         return Net.localAddress(fd);
 834     }
 835 
 836     @Override
 837     public boolean isConnected() {
 838         return (state == ST_CONNECTED);
 839     }
 840 
 841     @Override
 842     public boolean isConnectionPending() {
 843         return (state == ST_CONNECTIONPENDING);
 844     }
 845 
 846     /**
 847      * Marks the beginning of a connect operation that might block.
 848      * @param blocking true if configured blocking
 849      * @param sa the remote socket address
 850      * @throws ClosedChannelException if the channel is closed
 851      * @throws AlreadyConnectedException if already connected
 852      * @throws ConnectionPendingException is a connection is pending
 853      * @throws IOException if the pre-connect hook fails
 854      */
 855     private void beginConnect(boolean blocking, SocketAddress sa)
 856         throws IOException
 857     {
 858         if (blocking) {
 859             // set hook for Thread.interrupt
 860             begin();
 861         }
 862         synchronized (stateLock) {
 863             ensureOpen();
 864             int state = this.state;
 865             if (state == ST_CONNECTED)
 866                 throw new AlreadyConnectedException();
 867             if (state == ST_CONNECTIONPENDING)
 868                 throw new ConnectionPendingException();
 869             assert state == ST_UNCONNECTED;
 870             this.state = ST_CONNECTIONPENDING;
 871 
 872             if (isNetSocket() && (localAddress == null)) {
 873                 InetSocketAddress isa = (InetSocketAddress) sa;
 874                 NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
 875             }
 876             remoteAddress = sa;
 877 
 878             if (blocking) {
 879                 // record thread so it can be signalled if needed
 880                 readerThread = NativeThread.current();
 881             }
 882         }
 883     }
 884 
 885     /**
 886      * Marks the end of a connect operation that may have blocked.
 887      *
 888      * @throws AsynchronousCloseException if the channel was closed due to this
 889      * thread being interrupted on a blocking connect operation.
 890      * @throws IOException if completed and unable to obtain the local address
 891      */
 892     private void endConnect(boolean blocking, boolean completed)
 893         throws IOException
 894     {
 895         endRead(blocking, completed);
 896 
 897         if (completed) {
 898             synchronized (stateLock) {
 899                 if (state == ST_CONNECTIONPENDING) {
 900                     if (isUnixSocket()) {
 901                         localAddress = UnixDomainSockets.localAddress(fd);
 902                     } else {
 903                         localAddress = Net.localAddress(fd);
 904                     }
 905                     state = ST_CONNECTED;
 906                 }
 907             }
 908         }
 909     }
 910 
 911     /**
 912      * Checks the remote address to which this channel is to be connected.
 913      */
 914     private SocketAddress checkRemote(SocketAddress sa) {
 915         if (isUnixSocket()) {
 916             return UnixDomainSockets.checkAddress(sa);
 917         } else {
 918             InetSocketAddress isa = Net.checkAddress(sa, family);
 919             InetAddress address = isa.getAddress();
 920             if (address.isAnyLocalAddress()) {
 921                 int port = isa.getPort();
 922                 if (address instanceof Inet4Address) {
 923                     return new InetSocketAddress(Net.inet4LoopbackAddress(), port);
 924                 } else {
 925                     assert family == INET6;
 926                     return new InetSocketAddress(Net.inet6LoopbackAddress(), port);
 927                 }
 928             } else {
 929                 return isa;
 930             }
 931         }
 932     }
 933 
 934     @Override
 935     public boolean connect(SocketAddress remote) throws IOException {
 936         SocketAddress sa = checkRemote(remote);
 937         try {
 938             readLock.lock();
 939             try {
 940                 writeLock.lock();
 941                 try {
 942                     ensureOpen();
 943                     boolean blocking = isBlocking();
 944                     boolean connected = false;
 945                     try {
 946                         beginConnect(blocking, sa);
 947                         configureSocketNonBlockingIfVirtualThread();
 948                         int n;
 949                         if (isUnixSocket()) {
 950                             n = UnixDomainSockets.connect(fd, sa);
 951                         } else {
 952                             n = Net.connect(family, fd, sa);
 953                         }
 954                         if (n > 0) {
 955                             connected = true;
 956                         } else if (blocking) {
 957                             assert IOStatus.okayToRetry(n);
 958                             boolean polled = false;
 959                             while (!polled && isOpen()) {
 960                                 park(Net.POLLOUT);
 961                                 polled = Net.pollConnectNow(fd);
 962                             }
 963                             connected = polled && isOpen();
 964                         }
 965                     } finally {
 966                         endConnect(blocking, connected);
 967                     }
 968                     return connected;
 969                 } finally {
 970                     writeLock.unlock();
 971                 }
 972             } finally {
 973                 readLock.unlock();
 974             }
 975         } catch (IOException ioe) {
 976             // connect failed, close the channel
 977             close();
 978             throw Exceptions.ioException(ioe, sa);
 979         }
 980     }
 981 
 982     /**
 983      * Marks the beginning of a finishConnect operation that might block.
 984      *
 985      * @throws ClosedChannelException if the channel is closed
 986      * @throws NoConnectionPendingException if no connection is pending
 987      */
 988     private void beginFinishConnect(boolean blocking) throws ClosedChannelException {
 989         if (blocking) {
 990             // set hook for Thread.interrupt
 991             begin();
 992         }
 993         synchronized (stateLock) {
 994             ensureOpen();
 995             if (state != ST_CONNECTIONPENDING)
 996                 throw new NoConnectionPendingException();
 997             if (blocking) {
 998                 // record thread so it can be signalled if needed
 999                 readerThread = NativeThread.current();
1000             }
1001         }
1002     }
1003 
1004     /**
1005      * Marks the end of a finishConnect operation that may have blocked.
1006      *
1007      * @throws AsynchronousCloseException if the channel was closed due to this
1008      * thread being interrupted on a blocking connect operation.
1009      * @throws IOException if completed and unable to obtain the local address
1010      */
1011     private void endFinishConnect(boolean blocking, boolean completed)
1012         throws IOException
1013     {
1014         endRead(blocking, completed);
1015 
1016         if (completed) {
1017             synchronized (stateLock) {
1018                 if (state == ST_CONNECTIONPENDING) {
1019                     if (isUnixSocket()) {
1020                         localAddress = UnixDomainSockets.localAddress(fd);
1021                     } else {
1022                         localAddress = Net.localAddress(fd);
1023                     }
1024                     state = ST_CONNECTED;
1025                 }
1026             }
1027         }
1028     }
1029 
1030     @Override
1031     public boolean finishConnect() throws IOException {
1032         try {
1033             readLock.lock();
1034             try {
1035                 writeLock.lock();
1036                 try {
1037                     // no-op if already connected
1038                     if (isConnected())
1039                         return true;
1040 
1041                     ensureOpen();
1042                     boolean blocking = isBlocking();
1043                     boolean connected = false;
1044                     try {
1045                         beginFinishConnect(blocking);
1046                         boolean polled = Net.pollConnectNow(fd);
1047                         if (blocking) {
1048                             while (!polled && isOpen()) {
1049                                 park(Net.POLLOUT);
1050                                 polled = Net.pollConnectNow(fd);
1051                             }
1052                         }
1053                         connected = polled && isOpen();
1054                     } finally {
1055                         endFinishConnect(blocking, connected);
1056                     }
1057                     assert (blocking && connected) ^ !blocking;
1058                     return connected;
1059                 } finally {
1060                     writeLock.unlock();
1061                 }
1062             } finally {
1063                 readLock.unlock();
1064             }
1065         } catch (IOException ioe) {
1066             // connect failed, close the channel
1067             close();
1068             throw Exceptions.ioException(ioe, remoteAddress);
1069         }
1070     }
1071 
1072     /**
1073      * Closes the socket if there are no I/O operations in progress (or no I/O
1074      * operations tracked), and the channel is not registered with a Selector.
1075      */
1076     private boolean tryClose() throws IOException {
1077         assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
1078         if ((readerThread == null) && (writerThread == null) && !isRegistered()) {
1079             state = ST_CLOSED;
1080             nd.close(fd);
1081             return true;
1082         } else {
1083             return false;
1084         }
1085     }
1086 
1087     /**
1088      * Invokes tryClose to attempt to close the socket.
1089      *
1090      * This method is used for deferred closing by I/O and Selector operations.
1091      */
1092     private void tryFinishClose() {
1093         try {
1094             tryClose();
1095         } catch (IOException ignore) { }
1096     }
1097 
1098     /**
1099      * Closes this channel when configured in blocking mode. If there are no I/O
1100      * operations in progress (or tracked), then the channel's socket is closed. If
1101      * there are I/O operations in progress then the behavior is platform specific.
1102      *
1103      * On Unix systems, the channel's socket is pre-closed. This unparks any virtual
1104      * threads that are blocked in I/O operations on this channel. If there are
1105      * platform threads blocked on the channel's socket then the socket is dup'ed
1106      * and the platform threads signalled. The final close is deferred until all I/O
1107      * operations complete.
1108      *
1109      * On Windows, the channel's socket is pre-closed. This unparks any virtual
1110      * threads that are blocked in I/O operations on this channel. If there are no
1111      * virtual threads blocked in I/O operations on this channel then the channel's
1112      * socket is closed. If there are virtual threads in I/O then the final close is
1113      * deferred until all I/O operations on virtual threads complete.
1114      *
1115      * Note that a channel configured blocking may be registered with a Selector
1116      * This arises when a key is canceled and the channel configured to blocking
1117      * mode before the key is flushed from the Selector.
1118      */
1119     private void implCloseBlockingMode() throws IOException {
1120         synchronized (stateLock) {
1121             assert state < ST_CLOSING;
1122             boolean connected = (state == ST_CONNECTED);
1123             state = ST_CLOSING;
1124 
1125             if (connected && Net.shouldShutdownWriteBeforeClose()) {
1126                 // shutdown output when linger interval not set to 0
1127                 try {
1128                     var SO_LINGER = StandardSocketOptions.SO_LINGER;
1129                     if ((int) Net.getSocketOption(fd, SO_LINGER) != 0) {
1130                         Net.shutdown(fd, Net.SHUT_WR);
1131                     }
1132                 } catch (IOException ignore) { }
1133             }
1134 
1135             if (!tryClose()) {
1136                 // prepare file descriptor for closing
1137                 nd.preClose(fd, readerThread, writerThread);
1138             }
1139         }
1140     }
1141 
1142     /**
1143      * Closes this channel when configured in non-blocking mode.
1144      *
1145      * If the channel is registered with a Selector then the close is deferred
1146      * until the channel is flushed from all Selectors.
1147      *
1148      * If the socket is connected and the channel is registered with a Selector
1149      * then the socket is shutdown for writing so that the peer reads EOF. In
1150      * addition, if SO_LINGER is set to a non-zero value then it is disabled so
1151      * that the deferred close does not wait.
1152      */
1153     private void implCloseNonBlockingMode() throws IOException {
1154         boolean connected;
1155         synchronized (stateLock) {
1156             assert state < ST_CLOSING;
1157             connected = (state == ST_CONNECTED);
1158             state = ST_CLOSING;
1159         }
1160 
1161         // wait for any read/write operations to complete
1162         readLock.lock();
1163         readLock.unlock();
1164         writeLock.lock();
1165         writeLock.unlock();
1166 
1167         // if the socket cannot be closed because it's registered with a Selector
1168         // then shutdown the socket for writing.
1169         synchronized (stateLock) {
1170             if (state == ST_CLOSING && !tryClose() && connected && isRegistered()) {
1171                 try {
1172                     SocketOption<Integer> opt = StandardSocketOptions.SO_LINGER;
1173                     int interval = (int) Net.getSocketOption(fd, Net.UNSPEC, opt);
1174                     if (interval != 0) {
1175                         if (interval > 0) {
1176                             // disable SO_LINGER
1177                             Net.setSocketOption(fd, Net.UNSPEC, opt, -1);
1178                         }
1179                         Net.shutdown(fd, Net.SHUT_WR);
1180                     }
1181                 } catch (IOException ignore) { }
1182             }
1183         }
1184     }
1185 
1186     /**
1187      * Invoked by implCloseChannel to close the channel.
1188      */
1189     @Override
1190     protected void implCloseSelectableChannel() throws IOException {
1191         assert !isOpen();
1192         if (isBlocking()) {
1193             implCloseBlockingMode();
1194         } else {
1195             implCloseNonBlockingMode();
1196         }
1197     }
1198 
1199     @Override
1200     public void kill() {
1201         // wait for any read/write operations to complete before trying to close
1202         readLock.lock();
1203         readLock.unlock();
1204         writeLock.lock();
1205         writeLock.unlock();
1206         synchronized (stateLock) {
1207             if (state == ST_CLOSING) {
1208                 tryFinishClose();
1209             }
1210         }
1211     }
1212 
1213     @Override
1214     public SocketChannel shutdownInput() throws IOException {
1215         synchronized (stateLock) {
1216             ensureOpen();
1217             if (!isConnected())
1218                 throw new NotYetConnectedException();
1219             if (!isInputClosed) {
1220                 Net.shutdown(fd, Net.SHUT_RD);
1221                 if (NativeThread.isVirtualThread(readerThread)) {
1222                     Poller.stopPoll(readerThread.thread());
1223                 }
1224                 isInputClosed = true;
1225             }
1226             return this;
1227         }
1228     }
1229 
1230     @Override
1231     public SocketChannel shutdownOutput() throws IOException {
1232         synchronized (stateLock) {
1233             ensureOpen();
1234             if (!isConnected())
1235                 throw new NotYetConnectedException();
1236             if (!isOutputClosed) {
1237                 Net.shutdown(fd, Net.SHUT_WR);
1238                 if (NativeThread.isVirtualThread(writerThread)) {
1239                     Poller.stopPoll(writerThread.thread());
1240                 }
1241                 isOutputClosed = true;
1242             }
1243             return this;
1244         }
1245     }
1246 
1247     boolean isInputOpen() {
1248         return !isInputClosed;
1249     }
1250 
1251     boolean isOutputOpen() {
1252         return !isOutputClosed;
1253     }
1254 
1255     /**
1256      * Waits for a connection attempt to finish with a timeout
1257      * @throws SocketTimeoutException if the connect timeout elapses
1258      */
1259     private boolean finishTimedConnect(long nanos) throws IOException {
1260         long startNanos = System.nanoTime();
1261         boolean polled = Net.pollConnectNow(fd);
1262         while (!polled && isOpen()) {
1263             long remainingNanos = nanos - (System.nanoTime() - startNanos);
1264             if (remainingNanos <= 0) {
1265                 throw new SocketTimeoutException("Connect timed out");
1266             }
1267             park(Net.POLLOUT, remainingNanos);
1268             polled = Net.pollConnectNow(fd);
1269         }
1270         return polled && isOpen();
1271     }
1272 
1273     /**
1274      * Attempts to establish a connection to the given socket address with a
1275      * timeout. Closes the socket if connection cannot be established.
1276      *
1277      * @apiNote This method is for use by the socket adaptor.
1278      *
1279      * @throws IllegalBlockingModeException if the channel is non-blocking
1280      * @throws SocketTimeoutException if the read timeout elapses
1281      */
1282     void blockingConnect(SocketAddress remote, long nanos) throws IOException {
1283         SocketAddress sa = checkRemote(remote);
1284         try {
1285             readLock.lock();
1286             try {
1287                 writeLock.lock();
1288                 try {
1289                     if (!isBlocking())
1290                         throw new IllegalBlockingModeException();
1291                     boolean connected = false;
1292                     try {
1293                         beginConnect(true, sa);
1294                         // change socket to non-blocking
1295                         lockedConfigureBlocking(false);
1296                         try {
1297                             int n;
1298                             if (isUnixSocket()) {
1299                                 n = UnixDomainSockets.connect(fd, sa);
1300                             } else {
1301                                 n = Net.connect(family, fd, sa);
1302                             }
1303                             connected = (n > 0) ? true : finishTimedConnect(nanos);
1304                         } finally {
1305                             // restore socket to blocking mode (if channel is open)
1306                             tryLockedConfigureBlocking(true);
1307                         }
1308                     } finally {
1309                         endConnect(true, connected);
1310                     }
1311                 } finally {
1312                     writeLock.unlock();
1313                 }
1314             } finally {
1315                 readLock.unlock();
1316             }
1317         } catch (IOException ioe) {
1318             // connect failed, close the channel
1319             close();
1320             throw Exceptions.ioException(ioe, sa);
1321         }
1322     }
1323 
1324     /**
1325      * Attempts to read bytes from the socket into the given byte array.
1326      */
1327     private int tryRead(byte[] b, int off, int len) throws IOException {
1328         ByteBuffer dst = Util.getTemporaryDirectBuffer(len);
1329         assert dst.position() == 0;
1330         try {
1331             int n = nd.read(fd, ((DirectBuffer)dst).address(), len);
1332             if (n > 0) {
1333                 dst.get(b, off, n);
1334             }
1335             return n;
1336         } finally{
1337             Util.offerFirstTemporaryDirectBuffer(dst);
1338         }
1339     }
1340 
1341     /**
1342      * Reads bytes from the socket into the given byte array with a timeout.
1343      * @throws SocketTimeoutException if the read timeout elapses
1344      */
1345     private int timedRead(byte[] b, int off, int len, long nanos) throws IOException {
1346         long startNanos = System.nanoTime();
1347         int n = tryRead(b, off, len);
1348         while (n == IOStatus.UNAVAILABLE && isOpen()) {
1349             long remainingNanos = nanos - (System.nanoTime() - startNanos);
1350             if (remainingNanos <= 0) {
1351                 throw new SocketTimeoutException("Read timed out");
1352             }
1353             park(Net.POLLIN, remainingNanos);
1354             n = tryRead(b, off, len);
1355         }
1356         return n;
1357     }
1358 
1359     /**
1360      * Reads bytes from the socket into the given byte array.
1361      *
1362      * @apiNote This method is for use by the socket adaptor.
1363      *
1364      * @throws IllegalBlockingModeException if the channel is non-blocking
1365      * @throws SocketTimeoutException if the read timeout elapses
1366      */
1367     int blockingRead(byte[] b, int off, int len, long nanos) throws IOException {
1368         Objects.checkFromIndexSize(off, len, b.length);
1369         if (len == 0) {
1370             // nothing to do
1371             return 0;
1372         }
1373 
1374         readLock.lock();
1375         try {
1376             ensureOpenAndConnected();
1377 
1378             // check that channel is configured blocking
1379             if (!isBlocking())
1380                 throw new IllegalBlockingModeException();
1381 
1382             int n = 0;
1383             try {
1384                 beginRead(true);
1385 
1386                 // check if connection has been reset
1387                 if (connectionReset)
1388                     throwConnectionReset();
1389 
1390                 // check if input is shutdown
1391                 if (isInputClosed)
1392                     return IOStatus.EOF;
1393 
1394                 if (nanos > 0) {
1395                     // change socket to non-blocking
1396                     lockedConfigureBlocking(false);
1397                     try {
1398                         n = timedRead(b, off, len, nanos);
1399                     } finally {
1400                         // restore socket to blocking mode (if channel is open)
1401                         tryLockedConfigureBlocking(true);
1402                     }
1403                 } else {
1404                     // read, no timeout
1405                     configureSocketNonBlockingIfVirtualThread();
1406                     n = tryRead(b, off, len);
1407                     while (IOStatus.okayToRetry(n) && isOpen()) {
1408                         park(Net.POLLIN);
1409                         n = tryRead(b, off, len);
1410                     }
1411                 }
1412             } catch (ConnectionResetException e) {
1413                 connectionReset = true;
1414                 throwConnectionReset();
1415             } finally {
1416                 endRead(true, n > 0);
1417                 if (n <= 0 && isInputClosed)
1418                     return IOStatus.EOF;
1419             }
1420             assert n > 0 || n == -1;
1421             return n;
1422         } finally {
1423             readLock.unlock();
1424         }
1425     }
1426 
1427     /**
1428      * Attempts to write a sequence of bytes to the socket from the given
1429      * byte array.
1430      */
1431     private int tryWrite(byte[] b, int off, int len) throws IOException {
1432         ByteBuffer src = Util.getTemporaryDirectBuffer(len);
1433         assert src.position() == 0;
1434         try {
1435             src.put(b, off, len);
1436             return nd.write(fd, ((DirectBuffer)src).address(), len);
1437         } finally {
1438             Util.offerFirstTemporaryDirectBuffer(src);
1439         }
1440     }
1441 
1442     /**
1443      * Writes a sequence of bytes to the socket from the given byte array.
1444      *
1445      * @apiNote This method is for use by the socket adaptor.
1446      */
1447     void blockingWriteFully(byte[] b, int off, int len) throws IOException {
1448         Objects.checkFromIndexSize(off, len, b.length);
1449         if (len == 0) {
1450             // nothing to do
1451             return;
1452         }
1453 
1454         writeLock.lock();
1455         try {
1456             ensureOpenAndConnected();
1457 
1458             // check that channel is configured blocking
1459             if (!isBlocking())
1460                 throw new IllegalBlockingModeException();
1461 
1462             // loop until all bytes have been written
1463             int pos = off;
1464             int end = off + len;
1465             try {
1466                 beginWrite(true);
1467                 configureSocketNonBlockingIfVirtualThread();
1468                 while (pos < end && isOpen()) {
1469                     int size = end - pos;
1470                     int n = tryWrite(b, pos, size);
1471                     while (IOStatus.okayToRetry(n) && isOpen()) {
1472                         park(Net.POLLOUT);
1473                         n = tryWrite(b, pos, size);
1474                     }
1475                     if (n > 0) {
1476                         pos += n;
1477                     }
1478                 }
1479             } finally {
1480                 endWrite(true, pos >= end);
1481             }
1482         } finally {
1483             writeLock.unlock();
1484         }
1485     }
1486 
1487     /**
1488      * Return the number of bytes in the socket input buffer.
1489      */
1490     int available() throws IOException {
1491         synchronized (stateLock) {
1492             ensureOpenAndConnected();
1493             if (isInputClosed) {
1494                 return 0;
1495             } else {
1496                 return Net.available(fd);
1497             }
1498         }
1499     }
1500 
1501     /**
1502      * Translates native poll revent ops into a ready operation ops
1503      */
1504     public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
1505         int intOps = ski.nioInterestOps();
1506         int oldOps = ski.nioReadyOps();
1507         int newOps = initialOps;
1508 
1509         if ((ops & Net.POLLNVAL) != 0) {
1510             // This should only happen if this channel is pre-closed while a
1511             // selection operation is in progress
1512             // ## Throw an error if this channel has not been pre-closed
1513             return false;
1514         }
1515 
1516         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
1517             newOps = intOps;
1518             ski.nioReadyOps(newOps);
1519             return (newOps & ~oldOps) != 0;
1520         }
1521 
1522         boolean connected = isConnected();
1523         if (((ops & Net.POLLIN) != 0) &&
1524             ((intOps & SelectionKey.OP_READ) != 0) && connected)
1525             newOps |= SelectionKey.OP_READ;
1526 
1527         if (((ops & Net.POLLCONN) != 0) &&
1528             ((intOps & SelectionKey.OP_CONNECT) != 0) && isConnectionPending())
1529             newOps |= SelectionKey.OP_CONNECT;
1530 
1531         if (((ops & Net.POLLOUT) != 0) &&
1532             ((intOps & SelectionKey.OP_WRITE) != 0) && connected)
1533             newOps |= SelectionKey.OP_WRITE;
1534 
1535         ski.nioReadyOps(newOps);
1536         return (newOps & ~oldOps) != 0;
1537     }
1538 
1539     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
1540         return translateReadyOps(ops, ski.nioReadyOps(), ski);
1541     }
1542 
1543     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
1544         return translateReadyOps(ops, 0, ski);
1545     }
1546 
1547     /**
1548      * Translates an interest operation set into a native poll event set
1549      */
1550     public int translateInterestOps(int ops) {
1551         int newOps = 0;
1552         if ((ops & SelectionKey.OP_READ) != 0)
1553             newOps |= Net.POLLIN;
1554         if ((ops & SelectionKey.OP_WRITE) != 0)
1555             newOps |= Net.POLLOUT;
1556         if ((ops & SelectionKey.OP_CONNECT) != 0)
1557             newOps |= Net.POLLCONN;
1558         return newOps;
1559     }
1560 
1561     public FileDescriptor getFD() {
1562         return fd;
1563     }
1564 
1565     public int getFDVal() {
1566         return fdVal;
1567     }
1568 
1569     @Override
1570     public String toString() {
1571         StringBuilder sb = new StringBuilder();
1572         sb.append(this.getClass().getSuperclass().getName());
1573         sb.append('[');
1574         if (!isOpen())
1575             sb.append("closed");
1576         else {
1577             synchronized (stateLock) {
1578                 switch (state) {
1579                 case ST_UNCONNECTED:
1580                     sb.append("unconnected");
1581                     break;
1582                 case ST_CONNECTIONPENDING:
1583                     sb.append("connection-pending");
1584                     break;
1585                 case ST_CONNECTED:
1586                     sb.append("connected");
1587                     if (isInputClosed)
1588                         sb.append(" ishut");
1589                     if (isOutputClosed)
1590                         sb.append(" oshut");
1591                     break;
1592                 }
1593                 SocketAddress addr = localAddress();
1594                 if (addr != null) {
1595                     sb.append(" local=");
1596                     sb.append(addr);
1597                 }
1598                 if (remoteAddress() != null) {
1599                     sb.append(" remote=");
1600                     sb.append(remoteAddress());
1601                 }
1602             }
1603         }
1604         sb.append(']');
1605         return sb.toString();
1606     }
1607 }