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