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