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