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