Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package sun.nio.ch;
     28 
     29 import java.io.FileDescriptor;
     30 import java.io.IOException;
     31 import java.net.*;
     32 import java.nio.ByteBuffer;
     33 import java.nio.channels.*;
     34 import java.nio.channels.spi.*;
     35 import java.util.*;
     36 
     37 import dalvik.system.BlockGuard;
     38 import sun.net.NetHooks;
     39 import sun.misc.IoTrace;
     40 
     41 /**
     42  * An implementation of SocketChannels
     43  */
     44 
     45 class SocketChannelImpl
     46     extends SocketChannel
     47     implements SelChImpl
     48 {
     49 
     50     // Used to make native read and write calls
     51     private static NativeDispatcher nd;
     52 
     53     // Our file descriptor object
     54     private final FileDescriptor fd;
     55 
     56     // fd value needed for dev/poll. This value will remain valid
     57     // even after the value in the file descriptor object has been set to -1
     58     private final int fdVal;
     59 
     60     // IDs of native threads doing reads and writes, for signalling
     61     private volatile long readerThread = 0;
     62     private volatile long writerThread = 0;
     63 
     64     // Lock held by current reading or connecting thread
     65     private final Object readLock = new Object();
     66 
     67     // Lock held by current writing or connecting thread
     68     private final Object writeLock = new Object();
     69 
     70     // Lock held by any thread that modifies the state fields declared below
     71     // DO NOT invoke a blocking I/O operation while holding this lock!
     72     private final Object stateLock = new Object();
     73 
     74     // -- The following fields are protected by stateLock
     75 
     76     // set true when exclusive binding is on and SO_REUSEADDR is emulated
     77     private boolean isReuseAddress;
     78 
     79     // State, increases monotonically
     80     private static final int ST_UNINITIALIZED = -1;
     81     private static final int ST_UNCONNECTED = 0;
     82     private static final int ST_PENDING = 1;
     83     private static final int ST_CONNECTED = 2;
     84     private static final int ST_KILLPENDING = 3;
     85     private static final int ST_KILLED = 4;
     86     private int state = ST_UNINITIALIZED;
     87 
     88     // Binding
     89     private InetSocketAddress localAddress;
     90     private InetSocketAddress remoteAddress;
     91 
     92     // Input/Output open
     93     private boolean isInputOpen = true;
     94     private boolean isOutputOpen = true;
     95     private boolean readyToConnect = false;
     96 
     97     // Socket adaptor, created on demand
     98     private Socket socket;
     99 
    100     // -- End of fields protected by stateLock
    101 
    102 
    103     // Constructor for normal connecting sockets
    104     //
    105     SocketChannelImpl(SelectorProvider sp) throws IOException {
    106         super(sp);
    107         this.fd = Net.socket(true);
    108         this.fdVal = IOUtil.fdVal(fd);
    109         this.state = ST_UNCONNECTED;
    110     }
    111 
    112     SocketChannelImpl(SelectorProvider sp,
    113                       FileDescriptor fd,
    114                       boolean bound)
    115         throws IOException
    116     {
    117         super(sp);
    118         this.fd = fd;
    119         this.fdVal = IOUtil.fdVal(fd);
    120         this.state = ST_UNCONNECTED;
    121         if (bound)
    122             this.localAddress = Net.localAddress(fd);
    123     }
    124 
    125     // Constructor for sockets obtained from server sockets
    126     //
    127     SocketChannelImpl(SelectorProvider sp,
    128                       FileDescriptor fd, InetSocketAddress remote)
    129         throws IOException
    130     {
    131         super(sp);
    132         this.fd = fd;
    133         this.fdVal = IOUtil.fdVal(fd);
    134         this.state = ST_CONNECTED;
    135         this.localAddress = Net.localAddress(fd);
    136         this.remoteAddress = remote;
    137     }
    138 
    139     public Socket socket() {
    140         synchronized (stateLock) {
    141             if (socket == null)
    142                 socket = SocketAdaptor.create(this);
    143             return socket;
    144         }
    145     }
    146 
    147     @Override
    148     public SocketAddress getLocalAddress() throws IOException {
    149         synchronized (stateLock) {
    150             if (!isOpen())
    151                 throw new ClosedChannelException();
    152             return  Net.getRevealedLocalAddress(localAddress);
    153         }
    154     }
    155 
    156     @Override
    157     public SocketAddress getRemoteAddress() throws IOException {
    158         synchronized (stateLock) {
    159             if (!isOpen())
    160                 throw new ClosedChannelException();
    161             return remoteAddress;
    162         }
    163     }
    164 
    165     @Override
    166     public <T> SocketChannel setOption(SocketOption<T> name, T value)
    167         throws IOException
    168     {
    169         if (name == null)
    170             throw new NullPointerException();
    171         if (!supportedOptions().contains(name))
    172             throw new UnsupportedOperationException("'" + name + "' not supported");
    173 
    174         synchronized (stateLock) {
    175             if (!isOpen())
    176                 throw new ClosedChannelException();
    177 
    178             // special handling for IP_TOS: no-op when IPv6
    179             if (name == StandardSocketOptions.IP_TOS) {
    180                 if (!Net.isIPv6Available())
    181                     Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value);
    182                 return this;
    183             } else if (name == StandardSocketOptions.SO_REUSEADDR &&
    184                            Net.useExclusiveBind())
    185             {
    186                 // SO_REUSEADDR emulated when using exclusive bind
    187                 isReuseAddress = (Boolean)value;
    188                 return this;
    189             }
    190 
    191             // no options that require special handling
    192             Net.setSocketOption(fd, Net.UNSPEC, name, value);
    193             return this;
    194         }
    195     }
    196 
    197     @Override
    198     @SuppressWarnings("unchecked")
    199     public <T> T getOption(SocketOption<T> name)
    200         throws IOException
    201     {
    202         if (name == null)
    203             throw new NullPointerException();
    204         if (!supportedOptions().contains(name))
    205             throw new UnsupportedOperationException("'" + name + "' not supported");
    206 
    207         synchronized (stateLock) {
    208             if (!isOpen())
    209                 throw new ClosedChannelException();
    210 
    211             if (name == StandardSocketOptions.SO_REUSEADDR &&
    212                     Net.useExclusiveBind())
    213             {
    214                 // SO_REUSEADDR emulated when using exclusive bind
    215                 return (T)Boolean.valueOf(isReuseAddress);
    216             }
    217 
    218             // special handling for IP_TOS: always return 0 when IPv6
    219             if (name == StandardSocketOptions.IP_TOS) {
    220                 return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) :
    221                     (T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name);
    222             }
    223 
    224             // no options that require special handling
    225             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
    226         }
    227     }
    228 
    229     private static class DefaultOptionsHolder {
    230         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
    231 
    232         private static Set<SocketOption<?>> defaultOptions() {
    233             HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8);
    234             set.add(StandardSocketOptions.SO_SNDBUF);
    235             set.add(StandardSocketOptions.SO_RCVBUF);
    236             set.add(StandardSocketOptions.SO_KEEPALIVE);
    237             set.add(StandardSocketOptions.SO_REUSEADDR);
    238             set.add(StandardSocketOptions.SO_LINGER);
    239             set.add(StandardSocketOptions.TCP_NODELAY);
    240             // additional options required by socket adaptor
    241             set.add(StandardSocketOptions.IP_TOS);
    242             set.add(ExtendedSocketOption.SO_OOBINLINE);
    243             return Collections.unmodifiableSet(set);
    244         }
    245     }
    246 
    247     @Override
    248     public final Set<SocketOption<?>> supportedOptions() {
    249         return DefaultOptionsHolder.defaultOptions;
    250     }
    251 
    252     private boolean ensureReadOpen() throws ClosedChannelException {
    253         synchronized (stateLock) {
    254             if (!isOpen())
    255                 throw new ClosedChannelException();
    256             if (!isConnected())
    257                 throw new NotYetConnectedException();
    258             if (!isInputOpen)
    259                 return false;
    260             else
    261                 return true;
    262         }
    263     }
    264 
    265     private void ensureWriteOpen() throws ClosedChannelException {
    266         synchronized (stateLock) {
    267             if (!isOpen())
    268                 throw new ClosedChannelException();
    269             if (!isOutputOpen)
    270                 throw new ClosedChannelException();
    271             if (!isConnected())
    272                 throw new NotYetConnectedException();
    273         }
    274     }
    275 
    276     private void readerCleanup() throws IOException {
    277         synchronized (stateLock) {
    278             readerThread = 0;
    279             if (state == ST_KILLPENDING)
    280                 kill();
    281         }
    282     }
    283 
    284     private void writerCleanup() throws IOException {
    285         synchronized (stateLock) {
    286             writerThread = 0;
    287             if (state == ST_KILLPENDING)
    288                 kill();
    289         }
    290     }
    291 
    292     public int read(ByteBuffer buf) throws IOException {
    293 
    294         if (buf == null)
    295             throw new NullPointerException();
    296 
    297         synchronized (readLock) {
    298             if (!ensureReadOpen())
    299                 return -1;
    300             Object traceContext = null;
    301             if (isBlocking()) {
    302                 traceContext = IoTrace.socketReadBegin();
    303             }
    304             int n = 0;
    305             try {
    306 
    307                 // Set up the interruption machinery; see
    308                 // AbstractInterruptibleChannel for details
    309                 //
    310                 begin();
    311 
    312                 synchronized (stateLock) {
    313                     if (!isOpen()) {
    314                     // Either the current thread is already interrupted, so
    315                     // begin() closed the channel, or another thread closed the
    316                     // channel since we checked it a few bytecodes ago.  In
    317                     // either case the value returned here is irrelevant since
    318                     // the invocation of end() in the finally block will throw
    319                     // an appropriate exception.
    320                     //
    321                         return 0;
    322 
    323                     }
    324 
    325                     // Save this thread so that it can be signalled on those
    326                     // platforms that require it
    327                     //
    328                     readerThread = NativeThread.current();
    329                 }
    330 
    331                 // Between the previous test of isOpen() and the return of the
    332                 // IOUtil.read invocation below, this channel might be closed
    333                 // or this thread might be interrupted.  We rely upon the
    334                 // implicit synchronization point in the kernel read() call to
    335                 // make sure that the right thing happens.  In either case the
    336                 // implCloseSelectableChannel method is ultimately invoked in
    337                 // some other thread, so there are three possibilities:
    338                 //
    339                 //   - implCloseSelectableChannel() invokes nd.preClose()
    340                 //     before this thread invokes read(), in which case the
    341                 //     read returns immediately with either EOF or an error,
    342                 //     the latter of which will cause an IOException to be
    343                 //     thrown.
    344                 //
    345                 //   - implCloseSelectableChannel() invokes nd.preClose() after
    346                 //     this thread is blocked in read().  On some operating
    347                 //     systems (e.g., Solaris and Windows) this causes the read
    348                 //     to return immediately with either EOF or an error
    349                 //     indication.
    350                 //
    351                 //   - implCloseSelectableChannel() invokes nd.preClose() after
    352                 //     this thread is blocked in read() but the operating
    353                 //     system (e.g., Linux) doesn't support preemptive close,
    354                 //     so implCloseSelectableChannel() proceeds to signal this
    355                 //     thread, thereby causing the read to return immediately
    356                 //     with IOStatus.INTERRUPTED.
    357                 //
    358                 // In all three cases the invocation of end() in the finally
    359                 // clause will notice that the channel has been closed and
    360                 // throw an appropriate exception (AsynchronousCloseException
    361                 // or ClosedByInterruptException) if necessary.
    362                 //
    363                 // *There is A fourth possibility. implCloseSelectableChannel()
    364                 // invokes nd.preClose(), signals reader/writer thred and quickly
    365                 // moves on to nd.close() in kill(), which does a real close.
    366                 // Then a third thread accepts a new connection, opens file or
    367                 // whatever that causes the released "fd" to be recycled. All
    368                 // above happens just between our last isOpen() check and the
    369                 // next kernel read reached, with the recycled "fd". The solution
    370                 // is to postpone the real kill() if there is a reader or/and
    371                 // writer thread(s) over there "waiting", leave the cleanup/kill
    372                 // to the reader or writer thread. (the preClose() still happens
    373                 // so the connection gets cut off as usual).
    374                 //
    375                 // For socket channels there is the additional wrinkle that
    376                 // asynchronous shutdown works much like asynchronous close,
    377                 // except that the channel is shutdown rather than completely
    378                 // closed.  This is analogous to the first two cases above,
    379                 // except that the shutdown operation plays the role of
    380                 // nd.preClose().
    381                 for (;;) {
    382                     n = IOUtil.read(fd, buf, -1, nd);
    383                     if ((n == IOStatus.INTERRUPTED) && isOpen()) {
    384                         // The system call was interrupted but the channel
    385                         // is still open, so retry
    386                         continue;
    387                     }
    388                     return IOStatus.normalize(n);
    389                 }
    390 
    391             } finally {
    392                 readerCleanup();        // Clear reader thread
    393 
    394                 if (isBlocking()) {
    395                     IoTrace.socketReadEnd(traceContext, remoteAddress.getAddress(),
    396                                           remoteAddress.getPort(), 0, n > 0 ? n : 0);
    397                 }
    398 
    399                 // The end method, which is defined in our superclass
    400                 // AbstractInterruptibleChannel, resets the interruption
    401                 // machinery.  If its argument is true then it returns
    402                 // normally; otherwise it checks the interrupt and open state
    403                 // of this channel and throws an appropriate exception if
    404                 // necessary.
    405                 //
    406                 // So, if we actually managed to do any I/O in the above try
    407                 // block then we pass true to the end method.  We also pass
    408                 // true if the channel was in non-blocking mode when the I/O
    409                 // operation was initiated but no data could be transferred;
    410                 // this prevents spurious exceptions from being thrown in the
    411                 // rare event that a channel is closed or a thread is
    412                 // interrupted at the exact moment that a non-blocking I/O
    413                 // request is made.
    414                 //
    415                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
    416 
    417                 // Extra case for socket channels: Asynchronous shutdown
    418                 //
    419                 synchronized (stateLock) {
    420                     if ((n <= 0) && (!isInputOpen))
    421                         return IOStatus.EOF;
    422                 }
    423 
    424                 assert IOStatus.check(n);
    425 
    426             }
    427         }
    428     }
    429 
    430     public long read(ByteBuffer[] dsts, int offset, int length)
    431         throws IOException
    432     {
    433         if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
    434             throw new IndexOutOfBoundsException();
    435         synchronized (readLock) {
    436             if (!ensureReadOpen())
    437                 return -1;
    438             long n = 0;
    439             Object traceContext = null;
    440             if (isBlocking()) {
    441                 traceContext = IoTrace.socketReadBegin();
    442             }
    443             try {
    444                 begin();
    445                 synchronized (stateLock) {
    446                     if (!isOpen())
    447                         return 0;
    448                     readerThread = NativeThread.current();
    449                 }
    450 
    451                 for (;;) {
    452                     n = IOUtil.read(fd, dsts, offset, length, nd);
    453                     if ((n == IOStatus.INTERRUPTED) && isOpen())
    454                         continue;
    455                     return IOStatus.normalize(n);
    456                 }
    457             } finally {
    458                 readerCleanup();
    459                 if (isBlocking()) {
    460                     IoTrace.socketReadEnd(traceContext, remoteAddress.getAddress(),
    461                                           remoteAddress.getPort(), 0, n > 0 ? n : 0);
    462                 }
    463                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
    464                 synchronized (stateLock) {
    465                     if ((n <= 0) && (!isInputOpen))
    466                         return IOStatus.EOF;
    467                 }
    468                 assert IOStatus.check(n);
    469             }
    470         }
    471     }
    472 
    473     public int write(ByteBuffer buf) throws IOException {
    474         if (buf == null)
    475             throw new NullPointerException();
    476         synchronized (writeLock) {
    477             ensureWriteOpen();
    478             int n = 0;
    479             Object traceContext =
    480                 IoTrace.socketWriteBegin();
    481 
    482             try {
    483                 begin();
    484                 synchronized (stateLock) {
    485                     if (!isOpen())
    486                         return 0;
    487                     writerThread = NativeThread.current();
    488                 }
    489                 for (;;) {
    490                     n = IOUtil.write(fd, buf, -1, nd);
    491                     if ((n == IOStatus.INTERRUPTED) && isOpen())
    492                         continue;
    493                     return IOStatus.normalize(n);
    494                 }
    495             } finally {
    496                 writerCleanup();
    497                 IoTrace.socketWriteEnd(traceContext, remoteAddress.getAddress(),
    498                                        remoteAddress.getPort(), n > 0 ? n : 0);
    499                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
    500                 synchronized (stateLock) {
    501                     if ((n <= 0) && (!isOutputOpen))
    502                         throw new AsynchronousCloseException();
    503                 }
    504                 assert IOStatus.check(n);
    505             }
    506         }
    507     }
    508 
    509     public long write(ByteBuffer[] srcs, int offset, int length)
    510         throws IOException
    511     {
    512         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
    513             throw new IndexOutOfBoundsException();
    514         synchronized (writeLock) {
    515             ensureWriteOpen();
    516             long n = 0;
    517             Object traceContext =
    518                 IoTrace.socketWriteBegin();
    519             try {
    520                 begin();
    521                 synchronized (stateLock) {
    522                     if (!isOpen())
    523                         return 0;
    524                     writerThread = NativeThread.current();
    525                 }
    526                 for (;;) {
    527                     n = IOUtil.write(fd, srcs, offset, length, nd);
    528                     if ((n == IOStatus.INTERRUPTED) && isOpen())
    529                         continue;
    530                     return IOStatus.normalize(n);
    531                 }
    532             } finally {
    533                 writerCleanup();
    534                 IoTrace.socketWriteEnd(traceContext, remoteAddress.getAddress(),
    535                                        remoteAddress.getPort(), n > 0 ? n : 0);
    536                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    537                 synchronized (stateLock) {
    538                     if ((n <= 0) && (!isOutputOpen))
    539                         throw new AsynchronousCloseException();
    540                 }
    541                 assert IOStatus.check(n);
    542             }
    543         }
    544     }
    545 
    546     // package-private
    547     int sendOutOfBandData(byte b) throws IOException {
    548         synchronized (writeLock) {
    549             ensureWriteOpen();
    550             int n = 0;
    551             try {
    552                 begin();
    553                 synchronized (stateLock) {
    554                     if (!isOpen())
    555                         return 0;
    556                     writerThread = NativeThread.current();
    557                 }
    558                 for (;;) {
    559                     n = sendOutOfBandData(fd, b);
    560                     if ((n == IOStatus.INTERRUPTED) && isOpen())
    561                         continue;
    562                     return IOStatus.normalize(n);
    563                 }
    564             } finally {
    565                 writerCleanup();
    566                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
    567                 synchronized (stateLock) {
    568                     if ((n <= 0) && (!isOutputOpen))
    569                         throw new AsynchronousCloseException();
    570                 }
    571                 assert IOStatus.check(n);
    572             }
    573         }
    574     }
    575 
    576     protected void implConfigureBlocking(boolean block) throws IOException {
    577         IOUtil.configureBlocking(fd, block);
    578     }
    579 
    580     public InetSocketAddress localAddress() {
    581         synchronized (stateLock) {
    582             return localAddress;
    583         }
    584     }
    585 
    586     public SocketAddress remoteAddress() {
    587         synchronized (stateLock) {
    588             return remoteAddress;
    589         }
    590     }
    591 
    592     @Override
    593     public SocketChannel bind(SocketAddress local) throws IOException {
    594         synchronized (readLock) {
    595             synchronized (writeLock) {
    596                 synchronized (stateLock) {
    597                     if (!isOpen())
    598                         throw new ClosedChannelException();
    599                     if (state == ST_PENDING)
    600                         throw new ConnectionPendingException();
    601                     if (localAddress != null)
    602                         throw new AlreadyBoundException();
    603                     InetSocketAddress isa = (local == null) ?
    604                         new InetSocketAddress(0) : Net.checkAddress(local);
    605                     NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
    606                     Net.bind(fd, isa.getAddress(), isa.getPort());
    607                     localAddress = Net.localAddress(fd);
    608                 }
    609             }
    610         }
    611         return this;
    612     }
    613 
    614     public boolean isConnected() {
    615         synchronized (stateLock) {
    616             return (state == ST_CONNECTED);
    617         }
    618     }
    619 
    620     public boolean isConnectionPending() {
    621         synchronized (stateLock) {
    622             return (state == ST_PENDING);
    623         }
    624     }
    625 
    626     void ensureOpenAndUnconnected() throws IOException { // package-private
    627         synchronized (stateLock) {
    628             if (!isOpen())
    629                 throw new ClosedChannelException();
    630             if (state == ST_CONNECTED)
    631                 throw new AlreadyConnectedException();
    632             if (state == ST_PENDING)
    633                 throw new ConnectionPendingException();
    634         }
    635     }
    636 
    637     public boolean connect(SocketAddress sa) throws IOException {
    638         int localPort = 0;
    639 
    640         synchronized (readLock) {
    641             synchronized (writeLock) {
    642                 ensureOpenAndUnconnected();
    643                 InetSocketAddress isa = Net.checkAddress(sa);
    644                 SecurityManager sm = System.getSecurityManager();
    645                 if (sm != null)
    646                     sm.checkConnect(isa.getAddress().getHostAddress(),
    647                                     isa.getPort());
    648                 synchronized (blockingLock()) {
    649                     int n = 0;
    650                     try {
    651                         try {
    652                             begin();
    653                             synchronized (stateLock) {
    654                                 if (!isOpen()) {
    655                                     return false;
    656                                 }
    657                                 // notify hook only if unbound
    658                                 if (localAddress == null) {
    659                                     NetHooks.beforeTcpConnect(fd,
    660                                                            isa.getAddress(),
    661                                                            isa.getPort());
    662                                 }
    663                                 readerThread = NativeThread.current();
    664                             }
    665                             for (;;) {
    666                                 InetAddress ia = isa.getAddress();
    667                                 if (ia.isAnyLocalAddress())
    668                                     ia = InetAddress.getLocalHost();
    669                                 n = Net.connect(fd,
    670                                                 ia,
    671                                                 isa.getPort());
    672                                 if (  (n == IOStatus.INTERRUPTED)
    673                                       && isOpen())
    674                                     continue;
    675                                 break;
    676                             }
    677 
    678                         } finally {
    679                             readerCleanup();
    680                             end((n > 0) || (n == IOStatus.UNAVAILABLE));
    681                             assert IOStatus.check(n);
    682                         }
    683                     } catch (IOException x) {
    684                         // If an exception was thrown, close the channel after
    685                         // invoking end() so as to avoid bogus
    686                         // AsynchronousCloseExceptions
    687                         close();
    688                         throw x;
    689                     }
    690                     synchronized (stateLock) {
    691                         remoteAddress = isa;
    692                         if (n > 0) {
    693 
    694                             // Connection succeeded; disallow further
    695                             // invocation
    696                             state = ST_CONNECTED;
    697                             if (isOpen())
    698                                 localAddress = Net.localAddress(fd);
    699                             return true;
    700                         }
    701                         // If nonblocking and no exception then connection
    702                         // pending; disallow another invocation
    703                         if (!isBlocking()) {
    704                             state = ST_PENDING;
    705                             if (isOpen()) {
    706                                 localAddress = Net.localAddress(fd);
    707                             }
    708                         }
    709                     }
    710                 }
    711                 return false;
    712             }
    713         }
    714     }
    715 
    716     public boolean finishConnect() throws IOException {
    717         synchronized (readLock) {
    718             synchronized (writeLock) {
    719                 synchronized (stateLock) {
    720                     if (!isOpen())
    721                         throw new ClosedChannelException();
    722                     if (state == ST_CONNECTED)
    723                         return true;
    724                     if (state != ST_PENDING)
    725                         throw new NoConnectionPendingException();
    726                 }
    727                 int n = 0;
    728                 try {
    729                     try {
    730                         begin();
    731                         synchronized (blockingLock()) {
    732                             synchronized (stateLock) {
    733                                 if (!isOpen()) {
    734                                     return false;
    735                                 }
    736                                 readerThread = NativeThread.current();
    737                             }
    738 
    739                             BlockGuard.getThreadPolicy().onNetwork();
    740                             if (!isBlocking()) {
    741                                 for (;;) {
    742                                     n = checkConnect(fd, false,
    743                                                      readyToConnect);
    744                                     if (  (n == IOStatus.INTERRUPTED)
    745                                           && isOpen())
    746                                         continue;
    747                                     break;
    748                                 }
    749                             } else {
    750                                 for (;;) {
    751                                     n = checkConnect(fd, true,
    752                                                      readyToConnect);
    753                                     if (n == 0) {
    754                                         // Loop in case of
    755                                         // spurious notifications
    756                                         continue;
    757                                     }
    758                                     if (  (n == IOStatus.INTERRUPTED)
    759                                           && isOpen())
    760                                         continue;
    761                                     break;
    762                                 }
    763                             }
    764                         }
    765                     } finally {
    766                         synchronized (stateLock) {
    767                             readerThread = 0;
    768                             if (state == ST_KILLPENDING) {
    769                                 kill();
    770                                 // poll()/getsockopt() does not report
    771                                 // error (throws exception, with n = 0)
    772                                 // on Linux platform after dup2 and
    773                                 // signal-wakeup. Force n to 0 so the
    774                                 // end() can throw appropriate exception
    775                                 n = 0;
    776                             }
    777                         }
    778                         end((n > 0) || (n == IOStatus.UNAVAILABLE));
    779                         assert IOStatus.check(n);
    780                     }
    781                 } catch (IOException x) {
    782                     // If an exception was thrown, close the channel after
    783                     // invoking end() so as to avoid bogus
    784                     // AsynchronousCloseExceptions
    785                     close();
    786                     throw x;
    787                 }
    788                 if (n > 0) {
    789                     synchronized (stateLock) {
    790                         state = ST_CONNECTED;
    791                         if (isOpen())
    792                             localAddress = Net.localAddress(fd);
    793                     }
    794                     return true;
    795                 }
    796                 return false;
    797             }
    798         }
    799     }
    800 
    801     @Override
    802     public SocketChannel shutdownInput() throws IOException {
    803         synchronized (stateLock) {
    804             if (!isOpen())
    805                 throw new ClosedChannelException();
    806             if (!isConnected())
    807                 throw new NotYetConnectedException();
    808             if (isInputOpen) {
    809                 Net.shutdown(fd, Net.SHUT_RD);
    810                 if (readerThread != 0)
    811                     NativeThread.signal(readerThread);
    812                 isInputOpen = false;
    813             }
    814             return this;
    815         }
    816     }
    817 
    818     @Override
    819     public SocketChannel shutdownOutput() throws IOException {
    820         synchronized (stateLock) {
    821             if (!isOpen())
    822                 throw new ClosedChannelException();
    823             if (!isConnected())
    824                 throw new NotYetConnectedException();
    825             if (isOutputOpen) {
    826                 Net.shutdown(fd, Net.SHUT_WR);
    827                 if (writerThread != 0)
    828                     NativeThread.signal(writerThread);
    829                 isOutputOpen = false;
    830             }
    831             return this;
    832         }
    833     }
    834 
    835     public boolean isInputOpen() {
    836         synchronized (stateLock) {
    837             return isInputOpen;
    838         }
    839     }
    840 
    841     public boolean isOutputOpen() {
    842         synchronized (stateLock) {
    843             return isOutputOpen;
    844         }
    845     }
    846 
    847     // AbstractInterruptibleChannel synchronizes invocations of this method
    848     // using AbstractInterruptibleChannel.closeLock, and also ensures that this
    849     // method is only ever invoked once.  Before we get to this method, isOpen
    850     // (which is volatile) will have been set to false.
    851     //
    852     protected void implCloseSelectableChannel() throws IOException {
    853         synchronized (stateLock) {
    854             isInputOpen = false;
    855             isOutputOpen = false;
    856 
    857             // Close the underlying file descriptor and dup it to a known fd
    858             // that's already closed.  This prevents other operations on this
    859             // channel from using the old fd, which might be recycled in the
    860             // meantime and allocated to an entirely different channel.
    861             //
    862             if (state != ST_KILLED)
    863                 nd.preClose(fd);
    864 
    865             // Signal native threads, if needed.  If a target thread is not
    866             // currently blocked in an I/O operation then no harm is done since
    867             // the signal handler doesn't actually do anything.
    868             //
    869             if (readerThread != 0)
    870                 NativeThread.signal(readerThread);
    871 
    872             if (writerThread != 0)
    873                 NativeThread.signal(writerThread);
    874 
    875             // If this channel is not registered then it's safe to close the fd
    876             // immediately since we know at this point that no thread is
    877             // blocked in an I/O operation upon the channel and, since the
    878             // channel is marked closed, no thread will start another such
    879             // operation.  If this channel is registered then we don't close
    880             // the fd since it might be in use by a selector.  In that case
    881             // closing this channel caused its keys to be cancelled, so the
    882             // last selector to deregister a key for this channel will invoke
    883             // kill() to close the fd.
    884             //
    885             if (!isRegistered())
    886                 kill();
    887         }
    888     }
    889 
    890     public void kill() throws IOException {
    891         synchronized (stateLock) {
    892             if (state == ST_KILLED)
    893                 return;
    894             if (state == ST_UNINITIALIZED) {
    895                 state = ST_KILLED;
    896                 return;
    897             }
    898             assert !isOpen() && !isRegistered();
    899 
    900             // Postpone the kill if there is a waiting reader
    901             // or writer thread. See the comments in read() for
    902             // more detailed explanation.
    903             if (readerThread == 0 && writerThread == 0) {
    904                 nd.close(fd);
    905                 state = ST_KILLED;
    906             } else {
    907                 state = ST_KILLPENDING;
    908             }
    909         }
    910     }
    911 
    912     /**
    913      * Translates native poll revent ops into a ready operation ops
    914      */
    915     public boolean translateReadyOps(int ops, int initialOps,
    916                                      SelectionKeyImpl sk) {
    917         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
    918         int oldOps = sk.nioReadyOps();
    919         int newOps = initialOps;
    920 
    921         if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
    922             // This should only happen if this channel is pre-closed while a
    923             // selection operation is in progress
    924             // ## Throw an error if this channel has not been pre-closed
    925             return false;
    926         }
    927 
    928         if ((ops & (PollArrayWrapper.POLLERR
    929                     | PollArrayWrapper.POLLHUP)) != 0) {
    930             newOps = intOps;
    931             sk.nioReadyOps(newOps);
    932             // No need to poll again in checkConnect,
    933             // the error will be detected there
    934             readyToConnect = true;
    935             return (newOps & ~oldOps) != 0;
    936         }
    937 
    938         if (((ops & PollArrayWrapper.POLLIN) != 0) &&
    939             ((intOps & SelectionKey.OP_READ) != 0) &&
    940             (state == ST_CONNECTED))
    941             newOps |= SelectionKey.OP_READ;
    942 
    943         if (((ops & PollArrayWrapper.POLLCONN) != 0) &&
    944             ((intOps & SelectionKey.OP_CONNECT) != 0) &&
    945             ((state == ST_UNCONNECTED) || (state == ST_PENDING))) {
    946             newOps |= SelectionKey.OP_CONNECT;
    947             readyToConnect = true;
    948         }
    949 
    950         if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
    951             ((intOps & SelectionKey.OP_WRITE) != 0) &&
    952             (state == ST_CONNECTED))
    953             newOps |= SelectionKey.OP_WRITE;
    954 
    955         sk.nioReadyOps(newOps);
    956         return (newOps & ~oldOps) != 0;
    957     }
    958 
    959     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
    960         return translateReadyOps(ops, sk.nioReadyOps(), sk);
    961     }
    962 
    963     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
    964         return translateReadyOps(ops, 0, sk);
    965     }
    966 
    967     /**
    968      * Translates an interest operation set into a native poll event set
    969      */
    970     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
    971         int newOps = 0;
    972         if ((ops & SelectionKey.OP_READ) != 0)
    973             newOps |= PollArrayWrapper.POLLIN;
    974         if ((ops & SelectionKey.OP_WRITE) != 0)
    975             newOps |= PollArrayWrapper.POLLOUT;
    976         if ((ops & SelectionKey.OP_CONNECT) != 0)
    977             newOps |= PollArrayWrapper.POLLCONN;
    978         sk.selector.putEventOps(sk, newOps);
    979     }
    980 
    981     public FileDescriptor getFD() {
    982         return fd;
    983     }
    984 
    985     public int getFDVal() {
    986         return fdVal;
    987     }
    988 
    989     @Override
    990     public String toString() {
    991         StringBuffer sb = new StringBuffer();
    992         sb.append(this.getClass().getSuperclass().getName());
    993         sb.append('[');
    994         if (!isOpen())
    995             sb.append("closed");
    996         else {
    997             synchronized (stateLock) {
    998                 switch (state) {
    999                 case ST_UNCONNECTED:
   1000                     sb.append("unconnected");
   1001                     break;
   1002                 case ST_PENDING:
   1003                     sb.append("connection-pending");
   1004                     break;
   1005                 case ST_CONNECTED:
   1006                     sb.append("connected");
   1007                     if (!isInputOpen)
   1008                         sb.append(" ishut");
   1009                     if (!isOutputOpen)
   1010                         sb.append(" oshut");
   1011                     break;
   1012                 }
   1013                 InetSocketAddress addr = localAddress();
   1014                 if (addr != null) {
   1015                     sb.append(" local=");
   1016                     sb.append(Net.getRevealedLocalAddressAsString(addr));
   1017                 }
   1018                 if (remoteAddress() != null) {
   1019                     sb.append(" remote=");
   1020                     sb.append(remoteAddress().toString());
   1021                 }
   1022             }
   1023         }
   1024         sb.append(']');
   1025         return sb.toString();
   1026     }
   1027 
   1028 
   1029     // -- Native methods --
   1030 
   1031     private static native int checkConnect(FileDescriptor fd,
   1032                                            boolean block, boolean ready)
   1033         throws IOException;
   1034 
   1035     private static native int sendOutOfBandData(FileDescriptor fd, byte data)
   1036         throws IOException;
   1037 
   1038     static {
   1039         nd = new SocketDispatcher();
   1040     }
   1041 
   1042 }
   1043