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