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 traceHandle = null;
 282             if (isBlocking()) {
 283                 traceHandle = 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                 // The end method, which is defined in our superclass
 376                 // AbstractInterruptibleChannel, resets the interruption
 377                 // machinery.  If its argument is true then it returns
 378                 // normally; otherwise it checks the interrupt and open state
 379                 // of this channel and throws an appropriate exception if
 380                 // necessary.
 381                 //
 382                 // So, if we actually managed to do any I/O in the above try
 383                 // block then we pass true to the end method.  We also pass
 384                 // true if the channel was in non-blocking mode when the I/O
 385                 // operation was initiated but no data could be transferred;
 386                 // this prevents spurious exceptions from being thrown in the
 387                 // rare event that a channel is closed or a thread is
 388                 // interrupted at the exact moment that a non-blocking I/O
 389                 // request is made.
 390                 //
 391                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
 392 
 393                 IoTrace.socketReadEnd(traceHandle, IOStatus.normalize(n));
 394 
 395                 // Extra case for socket channels: Asynchronous shutdown
 396                 //
 397                 synchronized (stateLock) {
 398                     if ((n <= 0) && (!isInputOpen))
 399                         return IOStatus.EOF;
 400                 }
 401 
 402                 assert IOStatus.check(n);
 403 
 404             }
 405         }
 406     }
 407 
 408     public long read(ByteBuffer[] dsts, int offset, int length)
 409         throws IOException
 410     {
 411         if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
 412             throw new IndexOutOfBoundsException();
 413         synchronized (readLock) {
 414             if (!ensureReadOpen())
 415                 return -1;
 416             long n = 0;
 417             Object traceHandle = null;
 418             if (isBlocking()) {
 419                 traceHandle = IoTrace.socketReadBegin(remoteAddress.getAddress(),
 420                                                       remoteAddress.getPort(), 0);
 421             }
 422             try {
 423                 begin();
 424                 synchronized (stateLock) {
 425                     if (!isOpen())
 426                         return 0;
 427                     readerThread = NativeThread.current();
 428                 }
 429 
 430                 for (;;) {
 431                     n = IOUtil.read(fd, dsts, offset, length, nd);
 432                     if ((n == IOStatus.INTERRUPTED) && isOpen())
 433                         continue;
 434                     return IOStatus.normalize(n);
 435                 }
 436             } finally {
 437                 readerCleanup();
 438                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
 439                 IoTrace.socketReadEnd(traceHandle, IOStatus.normalize(n));
 440                 synchronized (stateLock) {
 441                     if ((n <= 0) && (!isInputOpen))
 442                         return IOStatus.EOF;
 443                 }
 444                 assert IOStatus.check(n);
 445             }
 446         }
 447     }
 448 
 449     public int write(ByteBuffer buf) throws IOException {
 450         if (buf == null)
 451             throw new NullPointerException();
 452         synchronized (writeLock) {
 453             ensureWriteOpen();
 454             int n = 0;
 455             Object traceHandle =
 456                 IoTrace.socketWriteBegin(remoteAddress.getAddress(),
 457                                          remoteAddress.getPort());
 458 
 459             try {
 460                 begin();
 461                 synchronized (stateLock) {
 462                     if (!isOpen())
 463                         return 0;
 464                     writerThread = NativeThread.current();
 465                 }
 466                 for (;;) {
 467                     n = IOUtil.write(fd, buf, -1, nd, writeLock);
 468                     if ((n == IOStatus.INTERRUPTED) && isOpen())
 469                         continue;
 470                     return IOStatus.normalize(n);
 471                 }
 472             } finally {
 473                 writerCleanup();
 474                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
 475                 IoTrace.socketWriteEnd(traceHandle, IOStatus.normalize(n));
 476                 synchronized (stateLock) {
 477                     if ((n <= 0) && (!isOutputOpen))
 478                         throw new AsynchronousCloseException();
 479                 }
 480                 assert IOStatus.check(n);
 481             }
 482         }
 483     }
 484 
 485     public long write(ByteBuffer[] srcs, int offset, int length)
 486         throws IOException
 487     {
 488         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
 489             throw new IndexOutOfBoundsException();
 490         synchronized (writeLock) {
 491             ensureWriteOpen();
 492             long n = 0;
 493             Object traceHandle =
 494                 IoTrace.socketWriteBegin(remoteAddress.getAddress(),
 495                                          remoteAddress.getPort());
 496             try {
 497                 begin();
 498                 synchronized (stateLock) {
 499                     if (!isOpen())
 500                         return 0;
 501                     writerThread = NativeThread.current();
 502                 }
 503                 for (;;) {
 504                     n = IOUtil.write(fd, srcs, offset, length, nd);
 505                     if ((n == IOStatus.INTERRUPTED) && isOpen())
 506                         continue;
 507                     return IOStatus.normalize(n);
 508                 }
 509             } finally {
 510                 writerCleanup();
 511                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 512                 IoTrace.socketWriteEnd(traceHandle, IOStatus.normalize(n));
 513                 synchronized (stateLock) {
 514                     if ((n <= 0) && (!isOutputOpen))
 515                         throw new AsynchronousCloseException();
 516                 }
 517                 assert IOStatus.check(n);
 518             }
 519         }
 520     }
 521 
 522     // package-private
 523     int sendOutOfBandData(byte b) throws IOException {
 524         synchronized (writeLock) {
 525             ensureWriteOpen();
 526             int n = 0;
 527             try {
 528                 begin();
 529                 synchronized (stateLock) {
 530                     if (!isOpen())
 531                         return 0;
 532                     writerThread = NativeThread.current();
 533                 }
 534                 for (;;) {
 535                     n = sendOutOfBandData(fd, b);
 536                     if ((n == IOStatus.INTERRUPTED) && isOpen())
 537                         continue;
 538                     return IOStatus.normalize(n);
 539                 }
 540             } finally {
 541                 writerCleanup();
 542                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
 543                 synchronized (stateLock) {
 544                     if ((n <= 0) && (!isOutputOpen))
 545                         throw new AsynchronousCloseException();
 546                 }
 547                 assert IOStatus.check(n);
 548             }
 549         }
 550     }
 551 
 552     protected void implConfigureBlocking(boolean block) throws IOException {
 553         IOUtil.configureBlocking(fd, block);
 554     }
 555 
 556     public SocketAddress localAddress() {
 557         synchronized (stateLock) {
 558             return localAddress;
 559         }
 560     }
 561 
 562     public SocketAddress remoteAddress() {
 563         synchronized (stateLock) {
 564             return remoteAddress;
 565         }
 566     }
 567 
 568     @Override
 569     public SocketChannel bind(SocketAddress local) throws IOException {
 570         synchronized (readLock) {
 571             synchronized (writeLock) {
 572                 synchronized (stateLock) {
 573                     if (!isOpen())
 574                         throw new ClosedChannelException();
 575                     if (state == ST_PENDING)
 576                         throw new ConnectionPendingException();
 577                     if (localAddress != null)
 578                         throw new AlreadyBoundException();
 579                     InetSocketAddress isa = (local == null) ?
 580                         new InetSocketAddress(0) : Net.checkAddress(local);
 581                     NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
 582                     Net.bind(fd, isa.getAddress(), isa.getPort());
 583                     localAddress = Net.localAddress(fd);
 584                 }
 585             }
 586         }
 587         return this;
 588     }
 589 
 590     public boolean isConnected() {
 591         synchronized (stateLock) {
 592             return (state == ST_CONNECTED);
 593         }
 594     }
 595 
 596     public boolean isConnectionPending() {
 597         synchronized (stateLock) {
 598             return (state == ST_PENDING);
 599         }
 600     }
 601 
 602     void ensureOpenAndUnconnected() throws IOException { // package-private
 603         synchronized (stateLock) {
 604             if (!isOpen())
 605                 throw new ClosedChannelException();
 606             if (state == ST_CONNECTED)
 607                 throw new AlreadyConnectedException();
 608             if (state == ST_PENDING)
 609                 throw new ConnectionPendingException();
 610         }
 611     }
 612 
 613     public boolean connect(SocketAddress sa) throws IOException {
 614         int localPort = 0;
 615 
 616         synchronized (readLock) {
 617             synchronized (writeLock) {
 618                 ensureOpenAndUnconnected();
 619                 InetSocketAddress isa = Net.checkAddress(sa);
 620                 SecurityManager sm = System.getSecurityManager();
 621                 if (sm != null)
 622                     sm.checkConnect(isa.getAddress().getHostAddress(),
 623                                     isa.getPort());
 624                 synchronized (blockingLock()) {
 625                     int n = 0;
 626                     try {
 627                         try {
 628                             begin();
 629                             synchronized (stateLock) {
 630                                 if (!isOpen()) {
 631                                     return false;
 632                                 }
 633                                 // notify hook only if unbound
 634                                 if (localAddress == null) {
 635                                     NetHooks.beforeTcpConnect(fd,
 636                                                            isa.getAddress(),
 637                                                            isa.getPort());
 638                                 }
 639                                 readerThread = NativeThread.current();
 640                             }
 641                             for (;;) {
 642                                 InetAddress ia = isa.getAddress();
 643                                 if (ia.isAnyLocalAddress())
 644                                     ia = InetAddress.getLocalHost();
 645                                 n = Net.connect(fd,
 646                                                 ia,
 647                                                 isa.getPort());
 648                                 if (  (n == IOStatus.INTERRUPTED)
 649                                       && isOpen())
 650                                     continue;
 651                                 break;
 652                             }
 653 
 654                         } finally {
 655                             readerCleanup();
 656                             end((n > 0) || (n == IOStatus.UNAVAILABLE));
 657                             assert IOStatus.check(n);
 658                         }
 659                     } catch (IOException x) {
 660                         // If an exception was thrown, close the channel after
 661                         // invoking end() so as to avoid bogus
 662                         // AsynchronousCloseExceptions
 663                         close();
 664                         throw x;
 665                     }
 666                     synchronized (stateLock) {
 667                         remoteAddress = isa;
 668                         if (n > 0) {
 669 
 670                             // Connection succeeded; disallow further
 671                             // invocation
 672                             state = ST_CONNECTED;
 673                             if (isOpen())
 674                                 localAddress = Net.localAddress(fd);
 675                             return true;
 676                         }
 677                         // If nonblocking and no exception then connection
 678                         // pending; disallow another invocation
 679                         if (!isBlocking())
 680                             state = ST_PENDING;
 681                         else
 682                             assert false;
 683                     }
 684                 }
 685                 return false;
 686             }
 687         }
 688     }
 689 
 690     public boolean finishConnect() throws IOException {
 691         synchronized (readLock) {
 692             synchronized (writeLock) {
 693                 synchronized (stateLock) {
 694                     if (!isOpen())
 695                         throw new ClosedChannelException();
 696                     if (state == ST_CONNECTED)
 697                         return true;
 698                     if (state != ST_PENDING)
 699                         throw new NoConnectionPendingException();
 700                 }
 701                 int n = 0;
 702                 try {
 703                     try {
 704                         begin();
 705                         synchronized (blockingLock()) {
 706                             synchronized (stateLock) {
 707                                 if (!isOpen()) {
 708                                     return false;
 709                                 }
 710                                 readerThread = NativeThread.current();
 711                             }
 712                             if (!isBlocking()) {
 713                                 for (;;) {
 714                                     n = checkConnect(fd, false,
 715                                                      readyToConnect);
 716                                     if (  (n == IOStatus.INTERRUPTED)
 717                                           && isOpen())
 718                                         continue;
 719                                     break;
 720                                 }
 721                             } else {
 722                                 for (;;) {
 723                                     n = checkConnect(fd, true,
 724                                                      readyToConnect);
 725                                     if (n == 0) {
 726                                         // Loop in case of
 727                                         // spurious notifications
 728                                         continue;
 729                                     }
 730                                     if (  (n == IOStatus.INTERRUPTED)
 731                                           && isOpen())
 732                                         continue;
 733                                     break;
 734                                 }
 735                             }
 736                         }
 737                     } finally {
 738                         synchronized (stateLock) {
 739                             readerThread = 0;
 740                             if (state == ST_KILLPENDING) {
 741                                 kill();
 742                                 // poll()/getsockopt() does not report
 743                                 // error (throws exception, with n = 0)
 744                                 // on Linux platform after dup2 and
 745                                 // signal-wakeup. Force n to 0 so the
 746                                 // end() can throw appropriate exception
 747                                 n = 0;
 748                             }
 749                         }
 750                         end((n > 0) || (n == IOStatus.UNAVAILABLE));
 751                         assert IOStatus.check(n);
 752                     }
 753                 } catch (IOException x) {
 754                     // If an exception was thrown, close the channel after
 755                     // invoking end() so as to avoid bogus
 756                     // AsynchronousCloseExceptions
 757                     close();
 758                     throw x;
 759                 }
 760                 if (n > 0) {
 761                     synchronized (stateLock) {
 762                         state = ST_CONNECTED;
 763                         if (isOpen())
 764                             localAddress = Net.localAddress(fd);
 765                     }
 766                     return true;
 767                 }
 768                 return false;
 769             }
 770         }
 771     }
 772 
 773     @Override
 774     public SocketChannel shutdownInput() throws IOException {
 775         synchronized (stateLock) {
 776             if (!isOpen())
 777                 throw new ClosedChannelException();
 778             if (!isConnected())
 779                 throw new NotYetConnectedException();
 780             if (isInputOpen) {
 781                 Net.shutdown(fd, Net.SHUT_RD);
 782                 if (readerThread != 0)
 783                     NativeThread.signal(readerThread);
 784                 isInputOpen = false;
 785             }
 786             return this;
 787         }
 788     }
 789 
 790     @Override
 791     public SocketChannel shutdownOutput() throws IOException {
 792         synchronized (stateLock) {
 793             if (!isOpen())
 794                 throw new ClosedChannelException();
 795             if (!isConnected())
 796                 throw new NotYetConnectedException();
 797             if (isOutputOpen) {
 798                 Net.shutdown(fd, Net.SHUT_WR);
 799                 if (writerThread != 0)
 800                     NativeThread.signal(writerThread);
 801                 isOutputOpen = false;
 802             }
 803             return this;
 804         }
 805     }
 806 
 807     public boolean isInputOpen() {
 808         synchronized (stateLock) {
 809             return isInputOpen;
 810         }
 811     }
 812 
 813     public boolean isOutputOpen() {
 814         synchronized (stateLock) {
 815             return isOutputOpen;
 816         }
 817     }
 818 
 819     // AbstractInterruptibleChannel synchronizes invocations of this method
 820     // using AbstractInterruptibleChannel.closeLock, and also ensures that this
 821     // method is only ever invoked once.  Before we get to this method, isOpen
 822     // (which is volatile) will have been set to false.
 823     //
 824     protected void implCloseSelectableChannel() throws IOException {
 825         synchronized (stateLock) {
 826             isInputOpen = false;
 827             isOutputOpen = false;
 828 
 829             // Close the underlying file descriptor and dup it to a known fd
 830             // that's already closed.  This prevents other operations on this
 831             // channel from using the old fd, which might be recycled in the
 832             // meantime and allocated to an entirely different channel.
 833             //
 834             if (state != ST_KILLED)
 835                 nd.preClose(fd);
 836 
 837             // Signal native threads, if needed.  If a target thread is not
 838             // currently blocked in an I/O operation then no harm is done since
 839             // the signal handler doesn't actually do anything.
 840             //
 841             if (readerThread != 0)
 842                 NativeThread.signal(readerThread);
 843 
 844             if (writerThread != 0)
 845                 NativeThread.signal(writerThread);
 846 
 847             // If this channel is not registered then it's safe to close the fd
 848             // immediately since we know at this point that no thread is
 849             // blocked in an I/O operation upon the channel and, since the
 850             // channel is marked closed, no thread will start another such
 851             // operation.  If this channel is registered then we don't close
 852             // the fd since it might be in use by a selector.  In that case
 853             // closing this channel caused its keys to be cancelled, so the
 854             // last selector to deregister a key for this channel will invoke
 855             // kill() to close the fd.
 856             //
 857             if (!isRegistered())
 858                 kill();
 859         }
 860     }
 861 
 862     public void kill() throws IOException {
 863         synchronized (stateLock) {
 864             if (state == ST_KILLED)
 865                 return;
 866             if (state == ST_UNINITIALIZED) {
 867                 state = ST_KILLED;
 868                 return;
 869             }
 870             assert !isOpen() && !isRegistered();
 871 
 872             // Postpone the kill if there is a waiting reader
 873             // or writer thread. See the comments in read() for
 874             // more detailed explanation.
 875             if (readerThread == 0 && writerThread == 0) {
 876                 nd.close(fd);
 877                 state = ST_KILLED;
 878             } else {
 879                 state = ST_KILLPENDING;
 880             }
 881         }
 882     }
 883 
 884     /**
 885      * Translates native poll revent ops into a ready operation ops
 886      */
 887     public boolean translateReadyOps(int ops, int initialOps,
 888                                      SelectionKeyImpl sk) {
 889         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
 890         int oldOps = sk.nioReadyOps();
 891         int newOps = initialOps;
 892 
 893         if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
 894             // This should only happen if this channel is pre-closed while a
 895             // selection operation is in progress
 896             // ## Throw an error if this channel has not been pre-closed
 897             return false;
 898         }
 899 
 900         if ((ops & (PollArrayWrapper.POLLERR
 901                     | PollArrayWrapper.POLLHUP)) != 0) {
 902             newOps = intOps;
 903             sk.nioReadyOps(newOps);
 904             // No need to poll again in checkConnect,
 905             // the error will be detected there
 906             readyToConnect = true;
 907             return (newOps & ~oldOps) != 0;
 908         }
 909 
 910         if (((ops & PollArrayWrapper.POLLIN) != 0) &&
 911             ((intOps & SelectionKey.OP_READ) != 0) &&
 912             (state == ST_CONNECTED))
 913             newOps |= SelectionKey.OP_READ;
 914 
 915         if (((ops & PollArrayWrapper.POLLCONN) != 0) &&
 916             ((intOps & SelectionKey.OP_CONNECT) != 0) &&
 917             ((state == ST_UNCONNECTED) || (state == ST_PENDING))) {
 918             newOps |= SelectionKey.OP_CONNECT;
 919             readyToConnect = true;
 920         }
 921 
 922         if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
 923             ((intOps & SelectionKey.OP_WRITE) != 0) &&
 924             (state == ST_CONNECTED))
 925             newOps |= SelectionKey.OP_WRITE;
 926 
 927         sk.nioReadyOps(newOps);
 928         return (newOps & ~oldOps) != 0;
 929     }
 930 
 931     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
 932         return translateReadyOps(ops, sk.nioReadyOps(), sk);
 933     }
 934 
 935     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
 936         return translateReadyOps(ops, 0, sk);
 937     }
 938 
 939     // package-private
 940     int poll(int events, long timeout) throws IOException {
 941         assert Thread.holdsLock(blockingLock()) && !isBlocking();
 942 
 943         synchronized (readLock) {
 944             int n = 0;
 945             try {
 946                 begin();
 947                 synchronized (stateLock) {
 948                     if (!isOpen())
 949                         return 0;
 950                     readerThread = NativeThread.current();
 951                 }
 952                 n = Net.poll(fd, events, timeout);
 953             } finally {
 954                 readerCleanup();
 955                 end(n > 0);
 956             }
 957             return n;
 958         }
 959     }
 960 
 961     /**
 962      * Translates an interest operation set into a native poll event set
 963      */
 964     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
 965         int newOps = 0;
 966         if ((ops & SelectionKey.OP_READ) != 0)
 967             newOps |= PollArrayWrapper.POLLIN;
 968         if ((ops & SelectionKey.OP_WRITE) != 0)
 969             newOps |= PollArrayWrapper.POLLOUT;
 970         if ((ops & SelectionKey.OP_CONNECT) != 0)
 971             newOps |= PollArrayWrapper.POLLCONN;
 972         sk.selector.putEventOps(sk, newOps);
 973     }
 974 
 975     public FileDescriptor getFD() {
 976         return fd;
 977     }
 978 
 979     public int getFDVal() {
 980         return fdVal;
 981     }
 982 
 983     public String toString() {
 984         StringBuffer sb = new StringBuffer();
 985         sb.append(this.getClass().getSuperclass().getName());
 986         sb.append('[');
 987         if (!isOpen())
 988             sb.append("closed");
 989         else {
 990             synchronized (stateLock) {
 991                 switch (state) {
 992                 case ST_UNCONNECTED:
 993                     sb.append("unconnected");
 994                     break;
 995                 case ST_PENDING:
 996                     sb.append("connection-pending");
 997                     break;
 998                 case ST_CONNECTED:
 999                     sb.append("connected");
1000                     if (!isInputOpen)
1001                         sb.append(" ishut");
1002                     if (!isOutputOpen)
1003                         sb.append(" oshut");
1004                     break;
1005                 }
1006                 if (localAddress() != null) {
1007                     sb.append(" local=");
1008                     sb.append(localAddress().toString());
1009                 }
1010                 if (remoteAddress() != null) {
1011                     sb.append(" remote=");
1012                     sb.append(remoteAddress().toString());
1013                 }
1014             }
1015         }
1016         sb.append(']');
1017         return sb.toString();
1018     }
1019 
1020 
1021     // -- Native methods --
1022 
1023     private static native int checkConnect(FileDescriptor fd,
1024                                            boolean block, boolean ready)
1025         throws IOException;
1026 
1027     private static native int sendOutOfBandData(FileDescriptor fd, byte data)
1028         throws IOException;
1029 
1030     static {
1031         Util.load();
1032         nd = new SocketDispatcher();
1033     }
1034 
1035 }