1 /*
   2  * Copyright (c) 2000, 2012, 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.misc.IoTrace;
  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 InetSocketAddress localAddress;
  84     private InetSocketAddress 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             Object traceContext = null;
 282             if (isBlocking()) {
 283                 traceContext = IoTrace.socketReadBegin(remoteAddress.getAddress(),
 284                                                       remoteAddress.getPort(), 0);
 285             }
 286             int n = 0;
 287             try {
 288 
 289                 // Set up the interruption machinery; see
 290                 // AbstractInterruptibleChannel for details
 291                 //
 292                 begin();
 293 
 294                 synchronized (stateLock) {
 295                     if (!isOpen()) {
 296                     // Either the current thread is already interrupted, so
 297                     // begin() closed the channel, or another thread closed the
 298                     // channel since we checked it a few bytecodes ago.  In
 299                     // either case the value returned here is irrelevant since
 300                     // the invocation of end() in the finally block will throw
 301                     // an appropriate exception.
 302                     //
 303                         return 0;
 304 
 305                     }
 306 
 307                     // Save this thread so that it can be signalled on those
 308                     // platforms that require it
 309                     //
 310                     readerThread = NativeThread.current();
 311                 }
 312 
 313                 // Between the previous test of isOpen() and the return of the
 314                 // IOUtil.read invocation below, this channel might be closed
 315                 // or this thread might be interrupted.  We rely upon the
 316                 // implicit synchronization point in the kernel read() call to
 317                 // make sure that the right thing happens.  In either case the
 318                 // implCloseSelectableChannel method is ultimately invoked in
 319                 // some other thread, so there are three possibilities:
 320                 //
 321                 //   - implCloseSelectableChannel() invokes nd.preClose()
 322                 //     before this thread invokes read(), in which case the
 323                 //     read returns immediately with either EOF or an error,
 324                 //     the latter of which will cause an IOException to be
 325                 //     thrown.
 326                 //
 327                 //   - implCloseSelectableChannel() invokes nd.preClose() after
 328                 //     this thread is blocked in read().  On some operating
 329                 //     systems (e.g., Solaris and Windows) this causes the read
 330                 //     to return immediately with either EOF or an error
 331                 //     indication.
 332                 //
 333                 //   - implCloseSelectableChannel() invokes nd.preClose() after
 334                 //     this thread is blocked in read() but the operating
 335                 //     system (e.g., Linux) doesn't support preemptive close,
 336                 //     so implCloseSelectableChannel() proceeds to signal this
 337                 //     thread, thereby causing the read to return immediately
 338                 //     with IOStatus.INTERRUPTED.
 339                 //
 340                 // In all three cases the invocation of end() in the finally
 341                 // clause will notice that the channel has been closed and
 342                 // throw an appropriate exception (AsynchronousCloseException
 343                 // or ClosedByInterruptException) if necessary.
 344                 //
 345                 // *There is A fourth possibility. implCloseSelectableChannel()
 346                 // invokes nd.preClose(), signals reader/writer thred and quickly
 347                 // moves on to nd.close() in kill(), which does a real close.
 348                 // Then a third thread accepts a new connection, opens file or
 349                 // whatever that causes the released "fd" to be recycled. All
 350                 // above happens just between our last isOpen() check and the
 351                 // next kernel read reached, with the recycled "fd". The solution
 352                 // is to postpone the real kill() if there is a reader or/and
 353                 // writer thread(s) over there "waiting", leave the cleanup/kill
 354                 // to the reader or writer thread. (the preClose() still happens
 355                 // so the connection gets cut off as usual).
 356                 //
 357                 // For socket channels there is the additional wrinkle that
 358                 // asynchronous shutdown works much like asynchronous close,
 359                 // except that the channel is shutdown rather than completely
 360                 // closed.  This is analogous to the first two cases above,
 361                 // except that the shutdown operation plays the role of
 362                 // nd.preClose().
 363                 for (;;) {
 364                     n = IOUtil.read(fd, buf, -1, nd, readLock);
 365                     if ((n == IOStatus.INTERRUPTED) && isOpen()) {
 366                         // The system call was interrupted but the channel
 367                         // is still open, so retry
 368                         continue;
 369                     }
 370                     return IOStatus.normalize(n);
 371                 }
 372 
 373             } finally {
 374                 readerCleanup();        // Clear reader thread
 375 
 376                 if (isBlocking()) {
 377                     IoTrace.socketReadEnd(traceContext, n > 0 ? n : 0);
 378                 }
 379 
 380                 // The end method, which is defined in our superclass
 381                 // AbstractInterruptibleChannel, resets the interruption
 382                 // machinery.  If its argument is true then it returns
 383                 // normally; otherwise it checks the interrupt and open state
 384                 // of this channel and throws an appropriate exception if
 385                 // necessary.
 386                 //
 387                 // So, if we actually managed to do any I/O in the above try
 388                 // block then we pass true to the end method.  We also pass
 389                 // true if the channel was in non-blocking mode when the I/O
 390                 // operation was initiated but no data could be transferred;
 391                 // this prevents spurious exceptions from being thrown in the
 392                 // rare event that a channel is closed or a thread is
 393                 // interrupted at the exact moment that a non-blocking I/O
 394                 // request is made.
 395                 //
 396                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
 397 
 398                 // Extra case for socket channels: Asynchronous shutdown
 399                 //
 400                 synchronized (stateLock) {
 401                     if ((n <= 0) && (!isInputOpen))
 402                         return IOStatus.EOF;
 403                 }
 404 
 405                 assert IOStatus.check(n);
 406 
 407             }
 408         }
 409     }
 410 
 411     public long read(ByteBuffer[] dsts, int offset, int length)
 412         throws IOException
 413     {
 414         if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
 415             throw new IndexOutOfBoundsException();
 416         synchronized (readLock) {
 417             if (!ensureReadOpen())
 418                 return -1;
 419             long n = 0;
 420             Object traceContext = null;
 421             if (isBlocking()) {
 422                 traceContext = IoTrace.socketReadBegin(remoteAddress.getAddress(),
 423                                                       remoteAddress.getPort(), 0);
 424             }
 425             try {
 426                 begin();
 427                 synchronized (stateLock) {
 428                     if (!isOpen())
 429                         return 0;
 430                     readerThread = NativeThread.current();
 431                 }
 432 
 433                 for (;;) {
 434                     n = IOUtil.read(fd, dsts, offset, length, nd);
 435                     if ((n == IOStatus.INTERRUPTED) && isOpen())
 436                         continue;
 437                     return IOStatus.normalize(n);
 438                 }
 439             } finally {
 440                 readerCleanup();
 441                 if (isBlocking()) {
 442                     IoTrace.socketReadEnd(traceContext, n > 0 ? n : 0);
 443                 }
 444                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
 445                 synchronized (stateLock) {
 446                     if ((n <= 0) && (!isInputOpen))
 447                         return IOStatus.EOF;
 448                 }
 449                 assert IOStatus.check(n);
 450             }
 451         }
 452     }
 453 
 454     public int write(ByteBuffer buf) throws IOException {
 455         if (buf == null)
 456             throw new NullPointerException();
 457         synchronized (writeLock) {
 458             ensureWriteOpen();
 459             int n = 0;
 460             Object traceContext =
 461                 IoTrace.socketWriteBegin(remoteAddress.getAddress(),
 462                                          remoteAddress.getPort());
 463 
 464             try {
 465                 begin();
 466                 synchronized (stateLock) {
 467                     if (!isOpen())
 468                         return 0;
 469                     writerThread = NativeThread.current();
 470                 }
 471                 for (;;) {
 472                     n = IOUtil.write(fd, buf, -1, nd, writeLock);
 473                     if ((n == IOStatus.INTERRUPTED) && isOpen())
 474                         continue;
 475                     return IOStatus.normalize(n);
 476                 }
 477             } finally {
 478                 writerCleanup();
 479                 IoTrace.socketWriteEnd(traceContext, n > 0 ? n : 0);
 480                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
 481                 synchronized (stateLock) {
 482                     if ((n <= 0) && (!isOutputOpen))
 483                         throw new AsynchronousCloseException();
 484                 }
 485                 assert IOStatus.check(n);
 486             }
 487         }
 488     }
 489 
 490     public long write(ByteBuffer[] srcs, int offset, int length)
 491         throws IOException
 492     {
 493         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
 494             throw new IndexOutOfBoundsException();
 495         synchronized (writeLock) {
 496             ensureWriteOpen();
 497             long n = 0;
 498             Object traceContext =
 499                 IoTrace.socketWriteBegin(remoteAddress.getAddress(),
 500                                          remoteAddress.getPort());
 501             try {
 502                 begin();
 503                 synchronized (stateLock) {
 504                     if (!isOpen())
 505                         return 0;
 506                     writerThread = NativeThread.current();
 507                 }
 508                 for (;;) {
 509                     n = IOUtil.write(fd, srcs, offset, length, nd);
 510                     if ((n == IOStatus.INTERRUPTED) && isOpen())
 511                         continue;
 512                     return IOStatus.normalize(n);
 513                 }
 514             } finally {
 515                 writerCleanup();
 516                 IoTrace.socketWriteEnd(traceContext, n > 0 ? n : 0);
 517                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 518                 synchronized (stateLock) {
 519                     if ((n <= 0) && (!isOutputOpen))
 520                         throw new AsynchronousCloseException();
 521                 }
 522                 assert IOStatus.check(n);
 523             }
 524         }
 525     }
 526 
 527     // package-private
 528     int sendOutOfBandData(byte b) throws IOException {
 529         synchronized (writeLock) {
 530             ensureWriteOpen();
 531             int n = 0;
 532             try {
 533                 begin();
 534                 synchronized (stateLock) {
 535                     if (!isOpen())
 536                         return 0;
 537                     writerThread = NativeThread.current();
 538                 }
 539                 for (;;) {
 540                     n = sendOutOfBandData(fd, b);
 541                     if ((n == IOStatus.INTERRUPTED) && isOpen())
 542                         continue;
 543                     return IOStatus.normalize(n);
 544                 }
 545             } finally {
 546                 writerCleanup();
 547                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 548                 synchronized (stateLock) {
 549                     if ((n <= 0) && (!isOutputOpen))
 550                         throw new AsynchronousCloseException();
 551                 }
 552                 assert IOStatus.check(n);
 553             }
 554         }
 555     }
 556 
 557     protected void implConfigureBlocking(boolean block) throws IOException {
 558         IOUtil.configureBlocking(fd, block);
 559     }
 560 
 561     public SocketAddress localAddress() {
 562         synchronized (stateLock) {
 563             return localAddress;
 564         }
 565     }
 566 
 567     public SocketAddress remoteAddress() {
 568         synchronized (stateLock) {
 569             return remoteAddress;
 570         }
 571     }
 572 
 573     @Override
 574     public SocketChannel bind(SocketAddress local) throws IOException {
 575         synchronized (readLock) {
 576             synchronized (writeLock) {
 577                 synchronized (stateLock) {
 578                     if (!isOpen())
 579                         throw new ClosedChannelException();
 580                     if (state == ST_PENDING)
 581                         throw new ConnectionPendingException();
 582                     if (localAddress != null)
 583                         throw new AlreadyBoundException();
 584                     InetSocketAddress isa = (local == null) ?
 585                         new InetSocketAddress(0) : Net.checkAddress(local);
 586                     NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
 587                     Net.bind(fd, isa.getAddress(), isa.getPort());
 588                     localAddress = Net.localAddress(fd);
 589                 }
 590             }
 591         }
 592         return this;
 593     }
 594 
 595     public boolean isConnected() {
 596         synchronized (stateLock) {
 597             return (state == ST_CONNECTED);
 598         }
 599     }
 600 
 601     public boolean isConnectionPending() {
 602         synchronized (stateLock) {
 603             return (state == ST_PENDING);
 604         }
 605     }
 606 
 607     void ensureOpenAndUnconnected() throws IOException { // package-private
 608         synchronized (stateLock) {
 609             if (!isOpen())
 610                 throw new ClosedChannelException();
 611             if (state == ST_CONNECTED)
 612                 throw new AlreadyConnectedException();
 613             if (state == ST_PENDING)
 614                 throw new ConnectionPendingException();
 615         }
 616     }
 617 
 618     public boolean connect(SocketAddress sa) throws IOException {
 619         int localPort = 0;
 620 
 621         synchronized (readLock) {
 622             synchronized (writeLock) {
 623                 ensureOpenAndUnconnected();
 624                 InetSocketAddress isa = Net.checkAddress(sa);
 625                 SecurityManager sm = System.getSecurityManager();
 626                 if (sm != null)
 627                     sm.checkConnect(isa.getAddress().getHostAddress(),
 628                                     isa.getPort());
 629                 synchronized (blockingLock()) {
 630                     int n = 0;
 631                     try {
 632                         try {
 633                             begin();
 634                             synchronized (stateLock) {
 635                                 if (!isOpen()) {
 636                                     return false;
 637                                 }
 638                                 // notify hook only if unbound
 639                                 if (localAddress == null) {
 640                                     NetHooks.beforeTcpConnect(fd,
 641                                                            isa.getAddress(),
 642                                                            isa.getPort());
 643                                 }
 644                                 readerThread = NativeThread.current();
 645                             }
 646                             for (;;) {
 647                                 InetAddress ia = isa.getAddress();
 648                                 if (ia.isAnyLocalAddress())
 649                                     ia = InetAddress.getLocalHost();
 650                                 n = Net.connect(fd,
 651                                                 ia,
 652                                                 isa.getPort());
 653                                 if (  (n == IOStatus.INTERRUPTED)
 654                                       && isOpen())
 655                                     continue;
 656                                 break;
 657                             }
 658 
 659                         } finally {
 660                             readerCleanup();
 661                             end((n > 0) || (n == IOStatus.UNAVAILABLE));
 662                             assert IOStatus.check(n);
 663                         }
 664                     } catch (IOException x) {
 665                         // If an exception was thrown, close the channel after
 666                         // invoking end() so as to avoid bogus
 667                         // AsynchronousCloseExceptions
 668                         close();
 669                         throw x;
 670                     }
 671                     synchronized (stateLock) {
 672                         remoteAddress = isa;
 673                         if (n > 0) {
 674 
 675                             // Connection succeeded; disallow further
 676                             // invocation
 677                             state = ST_CONNECTED;
 678                             if (isOpen())
 679                                 localAddress = Net.localAddress(fd);
 680                             return true;
 681                         }
 682                         // If nonblocking and no exception then connection
 683                         // pending; disallow another invocation
 684                         if (!isBlocking())
 685                             state = ST_PENDING;
 686                         else
 687                             assert false;
 688                     }
 689                 }
 690                 return false;
 691             }
 692         }
 693     }
 694 
 695     public boolean finishConnect() throws IOException {
 696         synchronized (readLock) {
 697             synchronized (writeLock) {
 698                 synchronized (stateLock) {
 699                     if (!isOpen())
 700                         throw new ClosedChannelException();
 701                     if (state == ST_CONNECTED)
 702                         return true;
 703                     if (state != ST_PENDING)
 704                         throw new NoConnectionPendingException();
 705                 }
 706                 int n = 0;
 707                 try {
 708                     try {
 709                         begin();
 710                         synchronized (blockingLock()) {
 711                             synchronized (stateLock) {
 712                                 if (!isOpen()) {
 713                                     return false;
 714                                 }
 715                                 readerThread = NativeThread.current();
 716                             }
 717                             if (!isBlocking()) {
 718                                 for (;;) {
 719                                     n = checkConnect(fd, false,
 720                                                      readyToConnect);
 721                                     if (  (n == IOStatus.INTERRUPTED)
 722                                           && isOpen())
 723                                         continue;
 724                                     break;
 725                                 }
 726                             } else {
 727                                 for (;;) {
 728                                     n = checkConnect(fd, true,
 729                                                      readyToConnect);
 730                                     if (n == 0) {
 731                                         // Loop in case of
 732                                         // spurious notifications
 733                                         continue;
 734                                     }
 735                                     if (  (n == IOStatus.INTERRUPTED)
 736                                           && isOpen())
 737                                         continue;
 738                                     break;
 739                                 }
 740                             }
 741                         }
 742                     } finally {
 743                         synchronized (stateLock) {
 744                             readerThread = 0;
 745                             if (state == ST_KILLPENDING) {
 746                                 kill();
 747                                 // poll()/getsockopt() does not report
 748                                 // error (throws exception, with n = 0)
 749                                 // on Linux platform after dup2 and
 750                                 // signal-wakeup. Force n to 0 so the
 751                                 // end() can throw appropriate exception
 752                                 n = 0;
 753                             }
 754                         }
 755                         end((n > 0) || (n == IOStatus.UNAVAILABLE));
 756                         assert IOStatus.check(n);
 757                     }
 758                 } catch (IOException x) {
 759                     // If an exception was thrown, close the channel after
 760                     // invoking end() so as to avoid bogus
 761                     // AsynchronousCloseExceptions
 762                     close();
 763                     throw x;
 764                 }
 765                 if (n > 0) {
 766                     synchronized (stateLock) {
 767                         state = ST_CONNECTED;
 768                         if (isOpen())
 769                             localAddress = Net.localAddress(fd);
 770                     }
 771                     return true;
 772                 }
 773                 return false;
 774             }
 775         }
 776     }
 777 
 778     @Override
 779     public SocketChannel shutdownInput() throws IOException {
 780         synchronized (stateLock) {
 781             if (!isOpen())
 782                 throw new ClosedChannelException();
 783             if (!isConnected())
 784                 throw new NotYetConnectedException();
 785             if (isInputOpen) {
 786                 Net.shutdown(fd, Net.SHUT_RD);
 787                 if (readerThread != 0)
 788                     NativeThread.signal(readerThread);
 789                 isInputOpen = false;
 790             }
 791             return this;
 792         }
 793     }
 794 
 795     @Override
 796     public SocketChannel shutdownOutput() throws IOException {
 797         synchronized (stateLock) {
 798             if (!isOpen())
 799                 throw new ClosedChannelException();
 800             if (!isConnected())
 801                 throw new NotYetConnectedException();
 802             if (isOutputOpen) {
 803                 Net.shutdown(fd, Net.SHUT_WR);
 804                 if (writerThread != 0)
 805                     NativeThread.signal(writerThread);
 806                 isOutputOpen = false;
 807             }
 808             return this;
 809         }
 810     }
 811 
 812     public boolean isInputOpen() {
 813         synchronized (stateLock) {
 814             return isInputOpen;
 815         }
 816     }
 817 
 818     public boolean isOutputOpen() {
 819         synchronized (stateLock) {
 820             return isOutputOpen;
 821         }
 822     }
 823 
 824     // AbstractInterruptibleChannel synchronizes invocations of this method
 825     // using AbstractInterruptibleChannel.closeLock, and also ensures that this
 826     // method is only ever invoked once.  Before we get to this method, isOpen
 827     // (which is volatile) will have been set to false.
 828     //
 829     protected void implCloseSelectableChannel() throws IOException {
 830         synchronized (stateLock) {
 831             isInputOpen = false;
 832             isOutputOpen = false;
 833 
 834             // Close the underlying file descriptor and dup it to a known fd
 835             // that's already closed.  This prevents other operations on this
 836             // channel from using the old fd, which might be recycled in the
 837             // meantime and allocated to an entirely different channel.
 838             //
 839             if (state != ST_KILLED)
 840                 nd.preClose(fd);
 841 
 842             // Signal native threads, if needed.  If a target thread is not
 843             // currently blocked in an I/O operation then no harm is done since
 844             // the signal handler doesn't actually do anything.
 845             //
 846             if (readerThread != 0)
 847                 NativeThread.signal(readerThread);
 848 
 849             if (writerThread != 0)
 850                 NativeThread.signal(writerThread);
 851 
 852             // If this channel is not registered then it's safe to close the fd
 853             // immediately since we know at this point that no thread is
 854             // blocked in an I/O operation upon the channel and, since the
 855             // channel is marked closed, no thread will start another such
 856             // operation.  If this channel is registered then we don't close
 857             // the fd since it might be in use by a selector.  In that case
 858             // closing this channel caused its keys to be cancelled, so the
 859             // last selector to deregister a key for this channel will invoke
 860             // kill() to close the fd.
 861             //
 862             if (!isRegistered())
 863                 kill();
 864         }
 865     }
 866 
 867     public void kill() throws IOException {
 868         synchronized (stateLock) {
 869             if (state == ST_KILLED)
 870                 return;
 871             if (state == ST_UNINITIALIZED) {
 872                 state = ST_KILLED;
 873                 return;
 874             }
 875             assert !isOpen() && !isRegistered();
 876 
 877             // Postpone the kill if there is a waiting reader
 878             // or writer thread. See the comments in read() for
 879             // more detailed explanation.
 880             if (readerThread == 0 && writerThread == 0) {
 881                 nd.close(fd);
 882                 state = ST_KILLED;
 883             } else {
 884                 state = ST_KILLPENDING;
 885             }
 886         }
 887     }
 888 
 889     /**
 890      * Translates native poll revent ops into a ready operation ops
 891      */
 892     public boolean translateReadyOps(int ops, int initialOps,
 893                                      SelectionKeyImpl sk) {
 894         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
 895         int oldOps = sk.nioReadyOps();
 896         int newOps = initialOps;
 897 
 898         if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
 899             // This should only happen if this channel is pre-closed while a
 900             // selection operation is in progress
 901             // ## Throw an error if this channel has not been pre-closed
 902             return false;
 903         }
 904 
 905         if ((ops & (PollArrayWrapper.POLLERR
 906                     | PollArrayWrapper.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 & PollArrayWrapper.POLLIN) != 0) &&
 916             ((intOps & SelectionKey.OP_READ) != 0) &&
 917             (state == ST_CONNECTED))
 918             newOps |= SelectionKey.OP_READ;
 919 
 920         if (((ops & PollArrayWrapper.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 & PollArrayWrapper.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     /**
 945      * Translates an interest operation set into a native poll event set
 946      */
 947     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
 948         int newOps = 0;
 949         if ((ops & SelectionKey.OP_READ) != 0)
 950             newOps |= PollArrayWrapper.POLLIN;
 951         if ((ops & SelectionKey.OP_WRITE) != 0)
 952             newOps |= PollArrayWrapper.POLLOUT;
 953         if ((ops & SelectionKey.OP_CONNECT) != 0)
 954             newOps |= PollArrayWrapper.POLLCONN;
 955         sk.selector.putEventOps(sk, newOps);
 956     }
 957 
 958     public FileDescriptor getFD() {
 959         return fd;
 960     }
 961 
 962     public int getFDVal() {
 963         return fdVal;
 964     }
 965 
 966     public String toString() {
 967         StringBuffer sb = new StringBuffer();
 968         sb.append(this.getClass().getSuperclass().getName());
 969         sb.append('[');
 970         if (!isOpen())
 971             sb.append("closed");
 972         else {
 973             synchronized (stateLock) {
 974                 switch (state) {
 975                 case ST_UNCONNECTED:
 976                     sb.append("unconnected");
 977                     break;
 978                 case ST_PENDING:
 979                     sb.append("connection-pending");
 980                     break;
 981                 case ST_CONNECTED:
 982                     sb.append("connected");
 983                     if (!isInputOpen)
 984                         sb.append(" ishut");
 985                     if (!isOutputOpen)
 986                         sb.append(" oshut");
 987                     break;
 988                 }
 989                 if (localAddress() != null) {
 990                     sb.append(" local=");
 991                     sb.append(localAddress().toString());
 992                 }
 993                 if (remoteAddress() != null) {
 994                     sb.append(" remote=");
 995                     sb.append(remoteAddress().toString());
 996                 }
 997             }
 998         }
 999         sb.append(']');
1000         return sb.toString();
1001     }
1002 
1003 
1004     // -- Native methods --
1005 
1006     private static native int checkConnect(FileDescriptor fd,
1007                                            boolean block, boolean ready)
1008         throws IOException;
1009 
1010     private static native int sendOutOfBandData(FileDescriptor fd, byte data)
1011         throws IOException;
1012 
1013     static {
1014         Util.load();
1015         nd = new SocketDispatcher();
1016     }
1017 
1018 }