1 /*
   2  * Copyright (c) 2000, 2018, 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.SocketOption;
  36 import java.net.StandardProtocolFamily;
  37 import java.net.StandardSocketOptions;
  38 import java.nio.ByteBuffer;
  39 import java.nio.channels.AlreadyBoundException;
  40 import java.nio.channels.AlreadyConnectedException;
  41 import java.nio.channels.AsynchronousCloseException;
  42 import java.nio.channels.ClosedChannelException;
  43 import java.nio.channels.ConnectionPendingException;
  44 import java.nio.channels.NoConnectionPendingException;
  45 import java.nio.channels.NotYetConnectedException;
  46 import java.nio.channels.SelectionKey;
  47 import java.nio.channels.SocketChannel;
  48 import java.nio.channels.spi.SelectorProvider;
  49 import java.util.Collections;
  50 import java.util.HashSet;
  51 import java.util.Objects;
  52 import java.util.Set;
  53 import java.util.concurrent.locks.ReentrantLock;
  54 
  55 import sun.net.NetHooks;
  56 import sun.net.ext.ExtendedSocketOptions;
  57 
  58 /**
  59  * An implementation of SocketChannels
  60  */
  61 
  62 public class SocketChannelImpl
  63     extends SocketChannel
  64     implements SelChImpl
  65 {
  66     // Used to make native read and write calls
  67     protected static NativeDispatcher nd;
  68 
  69     // Our file descriptor object
  70     protected FileDescriptor fd;
  71     protected final int fdVal;
  72 
  73     // Lock held by current reading or connecting thread
  74     protected final ReentrantLock readLock = new ReentrantLock();
  75 
  76     // Lock held by current writing or connecting thread
  77     protected final ReentrantLock writeLock = new ReentrantLock();
  78 
  79     // Lock held by any thread that modifies the state fields declared below
  80     // DO NOT invoke a blocking I/O operation while holding this lock!
  81     protected final Object stateLock = new Object();
  82 
  83     // Input/Output closed
  84     protected volatile boolean isInputClosed;
  85     protected volatile boolean isOutputClosed;
  86 
  87     // -- The following fields are protected by stateLock
  88 
  89     // set true when exclusive binding is on and SO_REUSEADDR is emulated
  90     protected boolean isReuseAddress;
  91 
  92     // State, increases monotonically
  93     protected static final int ST_UNCONNECTED = 0;
  94     protected static final int ST_CONNECTIONPENDING = 1;
  95     protected static final int ST_CONNECTED = 2;
  96     protected static final int ST_CLOSING = 3;
  97     protected static final int ST_KILLPENDING = 4;
  98     protected static final int ST_KILLED = 5;
  99     protected volatile int state;  // need stateLock to change
 100 
 101     // IDs of native threads doing reads and writes, for signalling
 102     protected long readerThread;
 103     protected long writerThread;
 104 
 105     // Binding
 106     protected InetSocketAddress localAddress;
 107     protected InetSocketAddress remoteAddress;
 108 
 109     // Socket adaptor, created on demand
 110     protected Socket socket;
 111 
 112     // -- End of fields protected by stateLock
 113 
 114 
 115     // Constructor for normal connecting sockets
 116     //
 117     protected SocketChannelImpl(SelectorProvider sp) throws IOException {
 118         super(sp);
 119         this.fd = createFD();
 120         this.fdVal = IOUtil.fdVal(fd);
 121     }
 122 
 123     protected SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
 124         throws IOException
 125     {
 126         super(sp);
 127         this.fd = fd;
 128         this.fdVal = IOUtil.fdVal(fd);
 129         if (bound) {
 130             synchronized (stateLock) {
 131                 this.localAddress = createLocalAddress(fd);
 132             }
 133         }
 134     }
 135 
 136     // Constructor for sockets obtained from server sockets
 137     //
 138     protected SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, InetSocketAddress isa)
 139         throws IOException
 140     {
 141         super(sp);
 142         this.fd = fd;
 143         this.fdVal = IOUtil.fdVal(fd);
 144         synchronized (stateLock) {
 145             this.localAddress = createLocalAddress(fd);
 146             this.remoteAddress = isa;
 147             this.state = ST_CONNECTED;
 148         }
 149     }
 150 
 151     protected FileDescriptor createFD() throws IOException {
 152         return Net.socket(true);
 153     }
 154 
 155     protected InetSocketAddress createLocalAddress(FileDescriptor fd)
 156         throws IOException {
 157         return Net.localAddress(fd);
 158     }
 159 
 160     /**
 161      * Checks that the channel is open.
 162      *
 163      * @throws ClosedChannelException if channel is closed (or closing)
 164      */
 165     protected void ensureOpen() throws ClosedChannelException {
 166         if (!isOpen())
 167             throw new ClosedChannelException();
 168     }
 169 
 170     /**
 171      * Checks that the channel is open and connected.
 172      *
 173      * @apiNote This method uses the "state" field to check if the channel is
 174      * open. It should never be used in conjuncion with isOpen or ensureOpen
 175      * as these methods check AbstractInterruptibleChannel's closed field - that
 176      * field is set before implCloseSelectableChannel is called and so before
 177      * the state is changed.
 178      *
 179      * @throws ClosedChannelException if channel is closed (or closing)
 180      * @throws NotYetConnectedException if open and not connected
 181      */
 182     private void ensureOpenAndConnected() throws ClosedChannelException {
 183         int state = this.state;
 184         if (state < ST_CONNECTED) {
 185             throw new NotYetConnectedException();
 186         } else if (state > ST_CONNECTED) {
 187             throw new ClosedChannelException();
 188         }
 189     }
 190 
 191     @Override
 192     public Socket socket() {
 193         synchronized (stateLock) {
 194             if (socket == null)
 195                 socket = SocketAdaptor.create(this);
 196             return socket;
 197         }
 198     }
 199 
 200     @Override
 201     public SocketAddress getLocalAddress() throws IOException {
 202         synchronized (stateLock) {
 203             ensureOpen();
 204             return Net.getRevealedLocalAddress(localAddress);
 205         }
 206     }
 207 
 208     @Override
 209     public SocketAddress getRemoteAddress() throws IOException {
 210         synchronized (stateLock) {
 211             ensureOpen();
 212             return remoteAddress;
 213         }
 214     }
 215 
 216     @Override
 217     public <T> SocketChannel setOption(SocketOption<T> name, T value)
 218         throws IOException
 219     {
 220         Objects.requireNonNull(name);
 221         if (!supportedOptions().contains(name))
 222             throw new UnsupportedOperationException("'" + name + "' not supported");
 223 
 224         synchronized (stateLock) {
 225             ensureOpen();
 226 
 227             if (name == StandardSocketOptions.IP_TOS) {
 228                 ProtocolFamily family = Net.isIPv6Available() ?
 229                     StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
 230                 Net.setSocketOption(fd, family, name, value);
 231                 return this;
 232             }
 233 
 234             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 235                 // SO_REUSEADDR emulated when using exclusive bind
 236                 isReuseAddress = (Boolean)value;
 237                 return this;
 238             }
 239 
 240             // no options that require special handling
 241             Net.setSocketOption(fd, Net.UNSPEC, name, value);
 242             return this;
 243         }
 244     }
 245 
 246     @Override
 247     @SuppressWarnings("unchecked")
 248     public <T> T getOption(SocketOption<T> name)
 249         throws IOException
 250     {
 251         Objects.requireNonNull(name);
 252         if (!supportedOptions().contains(name))
 253             throw new UnsupportedOperationException("'" + name + "' not supported");
 254 
 255         synchronized (stateLock) {
 256             ensureOpen();
 257 
 258             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 259                 // SO_REUSEADDR emulated when using exclusive bind
 260                 return (T)Boolean.valueOf(isReuseAddress);
 261             }
 262 
 263             // special handling for IP_TOS: always return 0 when IPv6
 264             if (name == StandardSocketOptions.IP_TOS) {
 265                 ProtocolFamily family = Net.isIPv6Available() ?
 266                     StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
 267                 return (T) Net.getSocketOption(fd, family, name);
 268             }
 269 
 270             // no options that require special handling
 271             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
 272         }
 273     }
 274 
 275     private static class DefaultOptionsHolder {
 276         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
 277 
 278         private static Set<SocketOption<?>> defaultOptions() {
 279             HashSet<SocketOption<?>> set = new HashSet<>();
 280             set.add(StandardSocketOptions.SO_SNDBUF);
 281             set.add(StandardSocketOptions.SO_RCVBUF);
 282             set.add(StandardSocketOptions.SO_KEEPALIVE);
 283             set.add(StandardSocketOptions.SO_REUSEADDR);
 284             if (Net.isReusePortAvailable()) {
 285                 set.add(StandardSocketOptions.SO_REUSEPORT);
 286             }
 287             set.add(StandardSocketOptions.SO_LINGER);
 288             set.add(StandardSocketOptions.TCP_NODELAY);
 289             // additional options required by socket adaptor
 290             set.add(StandardSocketOptions.IP_TOS);
 291             set.add(ExtendedSocketOption.SO_OOBINLINE);
 292             set.addAll(ExtendedSocketOptions.getInstance().options());
 293             return Collections.unmodifiableSet(set);
 294         }
 295     }
 296 
 297     @Override
 298     public Set<SocketOption<?>> supportedOptions() {
 299         return DefaultOptionsHolder.defaultOptions;
 300     }
 301 
 302     /**
 303      * Marks the beginning of a read operation that might block.
 304      *
 305      * @throws ClosedChannelException if the channel is closed
 306      * @throws NotYetConnectedException if the channel is not yet connected
 307      */
 308     protected void beginRead(boolean blocking) throws ClosedChannelException {
 309         if (blocking) {
 310             // set hook for Thread.interrupt
 311             begin();
 312 
 313             synchronized (stateLock) {
 314                 ensureOpenAndConnected();
 315                 // record thread so it can be signalled if needed
 316                 readerThread = NativeThread.current();
 317             }
 318         } else {
 319             ensureOpenAndConnected();
 320         }
 321     }
 322 
 323     /**
 324      * Marks the end of a read operation that may have blocked.
 325      *
 326      * @throws AsynchronousCloseException if the channel was closed due to this
 327      * thread being interrupted on a blocking read operation.
 328      */
 329     protected void endRead(boolean blocking, boolean completed)
 330         throws AsynchronousCloseException
 331     {
 332         if (blocking) {
 333             synchronized (stateLock) {
 334                 readerThread = 0;
 335                 // notify any thread waiting in implCloseSelectableChannel
 336                 if (state == ST_CLOSING) {
 337                     stateLock.notifyAll();
 338                 }
 339             }
 340             // remove hook for Thread.interrupt
 341             end(completed);
 342         }
 343     }
 344 
 345     @Override
 346     public int read(ByteBuffer buf) throws IOException {
 347         Objects.requireNonNull(buf);
 348 
 349         readLock.lock();
 350         try {
 351             boolean blocking = isBlocking();
 352             int n = 0;
 353             try {
 354                 beginRead(blocking);
 355 
 356                 // check if input is shutdown
 357                 if (isInputClosed)
 358                     return IOStatus.EOF;
 359 
 360                 if (blocking) {
 361                     do {
 362                         n = IOUtil.read(fd, buf, -1, nd);
 363                     } while (n == IOStatus.INTERRUPTED && isOpen());
 364                 } else {
 365                     n = IOUtil.read(fd, buf, -1, nd);
 366                 }
 367             } finally {
 368                 endRead(blocking, n > 0);
 369                 if (n <= 0 && isInputClosed)
 370                     return IOStatus.EOF;
 371             }
 372             return IOStatus.normalize(n);
 373         } finally {
 374             readLock.unlock();
 375         }
 376     }
 377 
 378     @Override
 379     public long read(ByteBuffer[] dsts, int offset, int length)
 380         throws IOException
 381     {
 382         Objects.checkFromIndexSize(offset, length, dsts.length);
 383 
 384         readLock.lock();
 385         try {
 386             boolean blocking = isBlocking();
 387             long n = 0;
 388             try {
 389                 beginRead(blocking);
 390 
 391                 // check if input is shutdown
 392                 if (isInputClosed)
 393                     return IOStatus.EOF;
 394 
 395                 if (blocking) {
 396                     do {
 397                         n = IOUtil.read(fd, dsts, offset, length, nd);
 398                     } while (n == IOStatus.INTERRUPTED && isOpen());
 399                 } else {
 400                     n = IOUtil.read(fd, dsts, offset, length, nd);
 401                 }
 402             } finally {
 403                 endRead(blocking, n > 0);
 404                 if (n <= 0 && isInputClosed)
 405                     return IOStatus.EOF;
 406             }
 407             return IOStatus.normalize(n);
 408         } finally {
 409             readLock.unlock();
 410         }
 411     }
 412 
 413     /**
 414      * Marks the beginning of a write operation that might block.
 415      *
 416      * @throws ClosedChannelException if the channel is closed or output shutdown
 417      * @throws NotYetConnectedException if the channel is not yet connected
 418      */
 419     protected void beginWrite(boolean blocking) throws ClosedChannelException {
 420         if (blocking) {
 421             // set hook for Thread.interrupt
 422             begin();
 423 
 424             synchronized (stateLock) {
 425                 ensureOpenAndConnected();
 426                 if (isOutputClosed)
 427                     throw new ClosedChannelException();
 428                 // record thread so it can be signalled if needed
 429                 writerThread = NativeThread.current();
 430             }
 431         } else {
 432             ensureOpenAndConnected();
 433         }
 434     }
 435 
 436     /**
 437      * Marks the end of a write operation that may have blocked.
 438      *
 439      * @throws AsynchronousCloseException if the channel was closed due to this
 440      * thread being interrupted on a blocking write operation.
 441      */
 442     protected void endWrite(boolean blocking, boolean completed)
 443         throws AsynchronousCloseException
 444     {
 445         if (blocking) {
 446             synchronized (stateLock) {
 447                 writerThread = 0;
 448                 // notify any thread waiting in implCloseSelectableChannel
 449                 if (state == ST_CLOSING) {
 450                     stateLock.notifyAll();
 451                 }
 452             }
 453             // remove hook for Thread.interrupt
 454             end(completed);
 455         }
 456     }
 457 
 458     @Override
 459     public int write(ByteBuffer buf) throws IOException {
 460         Objects.requireNonNull(buf);
 461 
 462         writeLock.lock();
 463         try {
 464             boolean blocking = isBlocking();
 465             int n = 0;
 466             try {
 467                 beginWrite(blocking);
 468                 if (blocking) {
 469                     do {
 470                         n = IOUtil.write(fd, buf, -1, nd);
 471                     } while (n == IOStatus.INTERRUPTED && isOpen());
 472                 } else {
 473                     n = IOUtil.write(fd, buf, -1, nd);
 474                 }
 475             } finally {
 476                 endWrite(blocking, n > 0);
 477                 if (n <= 0 && isOutputClosed)
 478                     throw new AsynchronousCloseException();
 479             }
 480             return IOStatus.normalize(n);
 481         } finally {
 482             writeLock.unlock();
 483         }
 484     }
 485 
 486     @Override
 487     public long write(ByteBuffer[] srcs, int offset, int length)
 488         throws IOException
 489     {
 490         Objects.checkFromIndexSize(offset, length, srcs.length);
 491 
 492         writeLock.lock();
 493         try {
 494             boolean blocking = isBlocking();
 495             long n = 0;
 496             try {
 497                 beginWrite(blocking);
 498                 if (blocking) {
 499                     do {
 500                         n = IOUtil.write(fd, srcs, offset, length, nd);
 501                     } while (n == IOStatus.INTERRUPTED && isOpen());
 502                 } else {
 503                     n = IOUtil.write(fd, srcs, offset, length, nd);
 504                 }
 505             } finally {
 506                 endWrite(blocking, n > 0);
 507                 if (n <= 0 && isOutputClosed)
 508                     throw new AsynchronousCloseException();
 509             }
 510             return IOStatus.normalize(n);
 511         } finally {
 512             writeLock.unlock();
 513         }
 514     }
 515 
 516     /**
 517      * Writes a byte of out of band data.
 518      */
 519     protected int sendOutOfBandData(byte b) throws IOException {
 520         writeLock.lock();
 521         try {
 522             boolean blocking = isBlocking();
 523             int n = 0;
 524             try {
 525                 beginWrite(blocking);
 526                 if (blocking) {
 527                     do {
 528                         n = sendOutOfBandData(fd, b);
 529                     } while (n == IOStatus.INTERRUPTED && isOpen());
 530                 } else {
 531                     n = sendOutOfBandData(fd, b);
 532                 }
 533             } finally {
 534                 endWrite(blocking, n > 0);
 535                 if (n <= 0 && isOutputClosed)
 536                     throw new AsynchronousCloseException();
 537             }
 538             return IOStatus.normalize(n);
 539         } finally {
 540             writeLock.unlock();
 541         }
 542     }
 543 
 544     @Override
 545     protected void implConfigureBlocking(boolean block) throws IOException {
 546         readLock.lock();
 547         try {
 548             writeLock.lock();
 549             try {
 550                 synchronized (stateLock) {
 551                     ensureOpen();
 552                     IOUtil.configureBlocking(fd, block);
 553                 }
 554             } finally {
 555                 writeLock.unlock();
 556             }
 557         } finally {
 558             readLock.unlock();
 559         }
 560     }
 561 
 562     /**
 563      * Returns the local address, or null if not bound
 564      */
 565     protected InetSocketAddress localAddress() {
 566         synchronized (stateLock) {
 567             return localAddress;
 568         }
 569     }
 570 
 571     /**
 572      * Returns the remote address, or null if not connected
 573      */
 574     protected InetSocketAddress remoteAddress() {
 575         synchronized (stateLock) {
 576             return remoteAddress;
 577         }
 578     }
 579 
 580     @Override
 581     public SocketChannel bind(SocketAddress local) throws IOException {
 582         readLock.lock();
 583         try {
 584             writeLock.lock();
 585             try {
 586                 synchronized (stateLock) {
 587                     ensureOpen();
 588                     if (state == ST_CONNECTIONPENDING)
 589                         throw new ConnectionPendingException();
 590                     if (localAddress != null)
 591                         throw new AlreadyBoundException();
 592                     InetSocketAddress isa = (local == null) ?
 593                         new InetSocketAddress(0) : Net.checkAddress(local);
 594                     SecurityManager sm = System.getSecurityManager();
 595                     if (sm != null) {
 596                         sm.checkListen(isa.getPort());
 597                     }
 598                     NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
 599                     Net.bind(fd, isa.getAddress(), isa.getPort());
 600                     localAddress = Net.localAddress(fd);
 601                 }
 602             } finally {
 603                 writeLock.unlock();
 604             }
 605         } finally {
 606             readLock.unlock();
 607         }
 608         return this;
 609     }
 610 
 611     @Override
 612     public boolean isConnected() {
 613         return (state == ST_CONNECTED);
 614     }
 615 
 616     @Override
 617     public boolean isConnectionPending() {
 618         return (state == ST_CONNECTIONPENDING);
 619     }
 620 
 621     /**
 622      * Marks the beginning of a connect operation that might block.
 623      * @param blocking true if configured blocking
 624      * @param isa the remote address
 625      * @throws ClosedChannelException if the channel is closed
 626      * @throws AlreadyConnectedException if already connected
 627      * @throws ConnectionPendingException is a connection is pending
 628      * @throws IOException if the pre-connect hook fails
 629      */
 630     protected void beginConnect(boolean blocking, InetSocketAddress isa)
 631         throws IOException
 632     {
 633         if (blocking) {
 634             // set hook for Thread.interrupt
 635             begin();
 636         }
 637         synchronized (stateLock) {
 638             ensureOpen();
 639             int state = this.state;
 640             if (state == ST_CONNECTED)
 641                 throw new AlreadyConnectedException();
 642             if (state == ST_CONNECTIONPENDING)
 643                 throw new ConnectionPendingException();
 644             assert state == ST_UNCONNECTED;
 645             this.state = ST_CONNECTIONPENDING;
 646 
 647             if (localAddress == null)
 648                 NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
 649             remoteAddress = isa;
 650 
 651             if (blocking) {
 652                 // record thread so it can be signalled if needed
 653                 readerThread = NativeThread.current();
 654             }
 655         }
 656     }
 657 
 658     /**
 659      * Marks the end of a connect operation that may have blocked.
 660      *
 661      * @throws AsynchronousCloseException if the channel was closed due to this
 662      * thread being interrupted on a blocking connect operation.
 663      * @throws IOException if completed and unable to obtain the local address
 664      */
 665     protected void endConnect(boolean blocking, boolean completed)
 666         throws IOException
 667     {
 668         endRead(blocking, completed);
 669 
 670         if (completed) {
 671             synchronized (stateLock) {
 672                 if (state == ST_CONNECTIONPENDING) {
 673                     localAddress = Net.localAddress(fd);
 674                     state = ST_CONNECTED;
 675                 }
 676             }
 677         }
 678     }
 679 
 680     @Override
 681     public boolean connect(SocketAddress sa) throws IOException {
 682         InetSocketAddress isa = Net.checkAddress(sa);
 683         SecurityManager sm = System.getSecurityManager();
 684         if (sm != null)
 685             sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
 686 
 687         InetAddress ia = isa.getAddress();
 688         if (ia.isAnyLocalAddress())
 689             ia = InetAddress.getLocalHost();
 690 
 691         try {
 692             readLock.lock();
 693             try {
 694                 writeLock.lock();
 695                 try {
 696                     int n = 0;
 697                     boolean blocking = isBlocking();
 698                     try {
 699                         beginConnect(blocking, isa);
 700                         do {
 701                             n = Net.connect(fd, ia, isa.getPort());
 702                         } while (n == IOStatus.INTERRUPTED && isOpen());
 703                     } finally {
 704                         endConnect(blocking, (n > 0));
 705                     }
 706                     assert IOStatus.check(n);
 707                     return n > 0;
 708                 } finally {
 709                     writeLock.unlock();
 710                 }
 711             } finally {
 712                 readLock.unlock();
 713             }
 714         } catch (IOException ioe) {
 715             // connect failed, close the channel
 716             close();
 717             throw ioe;
 718         }
 719     }
 720 
 721     /**
 722      * Marks the beginning of a finishConnect operation that might block.
 723      *
 724      * @throws ClosedChannelException if the channel is closed
 725      * @throws NoConnectionPendingException if no connection is pending
 726      */
 727     protected void beginFinishConnect(boolean blocking) throws ClosedChannelException {
 728         if (blocking) {
 729             // set hook for Thread.interrupt
 730             begin();
 731         }
 732         synchronized (stateLock) {
 733             ensureOpen();
 734             if (state != ST_CONNECTIONPENDING)
 735                 throw new NoConnectionPendingException();
 736             if (blocking) {
 737                 // record thread so it can be signalled if needed
 738                 readerThread = NativeThread.current();
 739             }
 740         }
 741     }
 742 
 743     /**
 744      * Marks the end of a finishConnect operation that may have blocked.
 745      *
 746      * @throws AsynchronousCloseException if the channel was closed due to this
 747      * thread being interrupted on a blocking connect operation.
 748      * @throws IOException if completed and unable to obtain the local address
 749      */
 750     protected void endFinishConnect(boolean blocking, boolean completed)
 751         throws IOException
 752     {
 753         endRead(blocking, completed);
 754 
 755         if (completed) {
 756             synchronized (stateLock) {
 757                 if (state == ST_CONNECTIONPENDING) {
 758                     localAddress = Net.localAddress(fd);
 759                     state = ST_CONNECTED;
 760                 }
 761             }
 762         }
 763     }
 764 
 765     @Override
 766     public boolean finishConnect() throws IOException {
 767         try {
 768             readLock.lock();
 769             try {
 770                 writeLock.lock();
 771                 try {
 772                     // no-op if already connected
 773                     if (isConnected())
 774                         return true;
 775 
 776                     boolean blocking = isBlocking();
 777                     boolean connected = false;
 778                     try {
 779                         beginFinishConnect(blocking);
 780                         int n = 0;
 781                         if (blocking) {
 782                             do {
 783                                 n = checkConnect(fd, true);
 784                             } while ((n == 0 || n == IOStatus.INTERRUPTED) && isOpen());
 785                         } else {
 786                             n = checkConnect(fd, false);
 787                         }
 788                         connected = (n > 0);
 789                     } finally {
 790                         endFinishConnect(blocking, connected);
 791                     }
 792                     assert (blocking && connected) ^ !blocking;
 793                     return connected;
 794                 } finally {
 795                     writeLock.unlock();
 796                 }
 797             } finally {
 798                 readLock.unlock();
 799             }
 800         } catch (IOException ioe) {
 801             // connect failed, close the channel
 802             close();
 803             throw ioe;
 804         }
 805     }
 806 
 807     /**
 808      * Invoked by implCloseChannel to close the channel.
 809      *
 810      * This method waits for outstanding I/O operations to complete. When in
 811      * blocking mode, the socket is pre-closed and the threads in blocking I/O
 812      * operations are signalled to ensure that the outstanding I/O operations
 813      * complete quickly.
 814      *
 815      * If the socket is connected then it is shutdown by this method. The
 816      * shutdown ensures that the peer reads EOF for the case that the socket is
 817      * not pre-closed or closed by this method.
 818      *
 819      * The socket is closed by this method when it is not registered with a
 820      * Selector. Note that a channel configured blocking may be registered with
 821      * a Selector. This arises when a key is canceled and the channel configured
 822      * to blocking mode before the key is flushed from the Selector.
 823      */
 824     @Override
 825     protected void implCloseSelectableChannel() throws IOException {
 826         assert !isOpen();
 827 
 828         boolean blocking;
 829         boolean connected;
 830         boolean interrupted = false;
 831 
 832         // set state to ST_CLOSING
 833         synchronized (stateLock) {
 834             assert state < ST_CLOSING;
 835             blocking = isBlocking();
 836             connected = (state == ST_CONNECTED);
 837             state = ST_CLOSING;
 838         }
 839 
 840         // wait for any outstanding I/O operations to complete
 841         if (blocking) {
 842             synchronized (stateLock) {
 843                 assert state == ST_CLOSING;
 844                 long reader = readerThread;
 845                 long writer = writerThread;
 846                 if (reader != 0 || writer != 0) {
 847                     nd.preClose(fd);
 848                     connected = false; // fd is no longer connected socket
 849 
 850                     if (reader != 0)
 851                         NativeThread.signal(reader);
 852                     if (writer != 0)
 853                         NativeThread.signal(writer);
 854 
 855                     // wait for blocking I/O operations to end
 856                     while (readerThread != 0 || writerThread != 0) {
 857                         try {
 858                             stateLock.wait();
 859                         } catch (InterruptedException e) {
 860                             interrupted = true;
 861                         }
 862                     }
 863                 }
 864             }
 865         } else {
 866             // non-blocking mode: wait for read/write to complete
 867             readLock.lock();
 868             try {
 869                 writeLock.lock();
 870                 writeLock.unlock();
 871             } finally {
 872                 readLock.unlock();
 873             }
 874         }
 875 
 876         // set state to ST_KILLPENDING
 877         synchronized (stateLock) {
 878             assert state == ST_CLOSING;
 879             // if connected, and the channel is registered with a Selector, we
 880             // shutdown the output so that the peer reads EOF
 881             if (connected && isRegistered()) {
 882                 try {
 883                     Net.shutdown(fd, Net.SHUT_WR);
 884                 } catch (IOException ignore) { }
 885             }
 886             state = ST_KILLPENDING;
 887         }
 888 
 889         // close socket if not registered with Selector
 890         if (!isRegistered())
 891             kill();
 892 
 893         // restore interrupt status
 894         if (interrupted)
 895             Thread.currentThread().interrupt();
 896     }
 897 
 898     @Override
 899     public void kill() throws IOException {
 900         synchronized (stateLock) {
 901             if (state == ST_KILLPENDING) {
 902                 state = ST_KILLED;
 903                 nd.close(fd);
 904             }
 905         }
 906     }
 907 
 908     @Override
 909     public SocketChannel shutdownInput() throws IOException {
 910         synchronized (stateLock) {
 911             ensureOpen();
 912             if (!isConnected())
 913                 throw new NotYetConnectedException();
 914             if (!isInputClosed) {
 915                 Net.shutdown(fd, Net.SHUT_RD);
 916                 long thread = readerThread;
 917                 if (thread != 0)
 918                     NativeThread.signal(thread);
 919                 isInputClosed = true;
 920             }
 921             return this;
 922         }
 923     }
 924 
 925     @Override
 926     public SocketChannel shutdownOutput() throws IOException {
 927         synchronized (stateLock) {
 928             ensureOpen();
 929             if (!isConnected())
 930                 throw new NotYetConnectedException();
 931             if (!isOutputClosed) {
 932                 Net.shutdown(fd, Net.SHUT_WR);
 933                 long thread = writerThread;
 934                 if (thread != 0)
 935                     NativeThread.signal(thread);
 936                 isOutputClosed = true;
 937             }
 938             return this;
 939         }
 940     }
 941 
 942     protected boolean isInputOpen() {
 943         return !isInputClosed;
 944     }
 945 
 946     protected boolean isOutputOpen() {
 947         return !isOutputClosed;
 948     }
 949 
 950     /**
 951      * Poll this channel's socket for reading up to the given timeout.
 952      * @return {@code true} if the socket is polled
 953      */
 954     boolean pollRead(long timeout) throws IOException {
 955         boolean blocking = isBlocking();
 956         assert Thread.holdsLock(blockingLock()) && blocking;
 957 
 958         readLock.lock();
 959         try {
 960             boolean polled = false;
 961             try {
 962                 beginRead(blocking);
 963                 int events = Net.poll(fd, Net.POLLIN, timeout);
 964                 polled = (events != 0);
 965             } finally {
 966                 endRead(blocking, polled);
 967             }
 968             return polled;
 969         } finally {
 970             readLock.unlock();
 971         }
 972     }
 973 
 974     /**
 975      * Poll this channel's socket for a connection, up to the given timeout.
 976      * @return {@code true} if the socket is polled
 977      */
 978     boolean pollConnected(long timeout) throws IOException {
 979         boolean blocking = isBlocking();
 980         assert Thread.holdsLock(blockingLock()) && blocking;
 981 
 982         readLock.lock();
 983         try {
 984             writeLock.lock();
 985             try {
 986                 boolean polled = false;
 987                 try {
 988                     beginFinishConnect(blocking);
 989                     int events = Net.poll(fd, Net.POLLCONN, timeout);
 990                     polled = (events != 0);
 991                 } finally {
 992                     // invoke endFinishConnect with completed = false so that
 993                     // the state is not changed to ST_CONNECTED. The socket
 994                     // adaptor will use finishConnect to finish.
 995                     endFinishConnect(blocking, /*completed*/false);
 996                 }
 997                 return polled;
 998             } finally {
 999                 writeLock.unlock();
1000             }
1001         } finally {
1002             readLock.unlock();
1003         }
1004     }
1005 
1006     /**
1007      * Translates native poll revent ops into a ready operation ops
1008      */
1009     public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
1010         int intOps = ski.nioInterestOps();
1011         int oldOps = ski.nioReadyOps();
1012         int newOps = initialOps;
1013 
1014         if ((ops & Net.POLLNVAL) != 0) {
1015             // This should only happen if this channel is pre-closed while a
1016             // selection operation is in progress
1017             // ## Throw an error if this channel has not been pre-closed
1018             return false;
1019         }
1020 
1021         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
1022             newOps = intOps;
1023             ski.nioReadyOps(newOps);
1024             return (newOps & ~oldOps) != 0;
1025         }
1026 
1027         boolean connected = isConnected();
1028         if (((ops & Net.POLLIN) != 0) &&
1029             ((intOps & SelectionKey.OP_READ) != 0) && connected)
1030             newOps |= SelectionKey.OP_READ;
1031 
1032         if (((ops & Net.POLLCONN) != 0) &&
1033             ((intOps & SelectionKey.OP_CONNECT) != 0) && isConnectionPending())
1034             newOps |= SelectionKey.OP_CONNECT;
1035 
1036         if (((ops & Net.POLLOUT) != 0) &&
1037             ((intOps & SelectionKey.OP_WRITE) != 0) && connected)
1038             newOps |= SelectionKey.OP_WRITE;
1039 
1040         ski.nioReadyOps(newOps);
1041         return (newOps & ~oldOps) != 0;
1042     }
1043 
1044     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
1045         return translateReadyOps(ops, ski.nioReadyOps(), ski);
1046     }
1047 
1048     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
1049         return translateReadyOps(ops, 0, ski);
1050     }
1051 
1052     /**
1053      * Translates an interest operation set into a native poll event set
1054      */
1055     public int translateInterestOps(int ops) {
1056         int newOps = 0;
1057         if ((ops & SelectionKey.OP_READ) != 0)
1058             newOps |= Net.POLLIN;
1059         if ((ops & SelectionKey.OP_WRITE) != 0)
1060             newOps |= Net.POLLOUT;
1061         if ((ops & SelectionKey.OP_CONNECT) != 0)
1062             newOps |= Net.POLLCONN;
1063         return newOps;
1064     }
1065 
1066     public FileDescriptor getFD() {
1067         return fd;
1068     }
1069 
1070     public int getFDVal() {
1071         return fdVal;
1072     }
1073 
1074     @Override
1075     public String toString() {
1076         StringBuilder sb = new StringBuilder();
1077         sb.append(this.getClass().getSuperclass().getName());
1078         sb.append('[');
1079         if (!isOpen())
1080             sb.append("closed");
1081         else {
1082             synchronized (stateLock) {
1083                 switch (state) {
1084                 case ST_UNCONNECTED:
1085                     sb.append("unconnected");
1086                     break;
1087                 case ST_CONNECTIONPENDING:
1088                     sb.append("connection-pending");
1089                     break;
1090                 case ST_CONNECTED:
1091                     sb.append("connected");
1092                     if (isInputClosed)
1093                         sb.append(" ishut");
1094                     if (isOutputClosed)
1095                         sb.append(" oshut");
1096                     break;
1097                 }
1098                 InetSocketAddress addr = localAddress();
1099                 if (addr != null) {
1100                     sb.append(" local=");
1101                     sb.append(Net.getRevealedLocalAddressAsString(addr));
1102                 }
1103                 if (remoteAddress() != null) {
1104                     sb.append(" remote=");
1105                     sb.append(remoteAddress().toString());
1106                 }
1107             }
1108         }
1109         sb.append(']');
1110         return sb.toString();
1111     }
1112 
1113 
1114     // -- Native methods --
1115 
1116     private static native int checkConnect(FileDescriptor fd, boolean block)
1117         throws IOException;
1118 
1119     private static native int sendOutOfBandData(FileDescriptor fd, byte data)
1120         throws IOException;
1121 
1122     static {
1123         IOUtil.load();
1124         nd = new SocketDispatcher();
1125     }
1126 
1127 }
--- EOF ---