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