1 /*
   2  * Copyright (c) 2000, 2018, 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.InetAddress;
  31 import java.net.InetSocketAddress;
  32 import java.net.ProtocolFamily;
  33 import java.net.Socket;
  34 import java.net.SocketAddress;
  35 import java.net.SocketOption;
  36 import java.net.StandardProtocolFamily;
  37 import java.net.StandardSocketOptions;
  38 import java.nio.ByteBuffer;
  39 import java.nio.channels.AlreadyBoundException;
  40 import java.nio.channels.AlreadyConnectedException;
  41 import java.nio.channels.AsynchronousCloseException;
  42 import java.nio.channels.ClosedChannelException;
  43 import java.nio.channels.ConnectionPendingException;
  44 import java.nio.channels.NoConnectionPendingException;
  45 import java.nio.channels.NotYetConnectedException;
  46 import java.nio.channels.SelectionKey;
  47 import java.nio.channels.SocketChannel;
  48 import java.nio.channels.spi.SelectorProvider;
  49 import java.util.Collections;
  50 import java.util.HashSet;
  51 import java.util.Objects;
  52 import java.util.Set;
  53 import java.util.concurrent.locks.ReentrantLock;
  54 
  55 import sun.net.NetHooks;
  56 import sun.net.ext.ExtendedSocketOptions;
  57 
  58 /**
  59  * An implementation of SocketChannels
  60  */
  61 
  62 class SocketChannelImpl
  63     extends SocketChannel
  64     implements SelChImpl
  65 {
  66     // Used to make native read and write calls
  67     private static NativeDispatcher nd;
  68 
  69     // Our file descriptor object
  70     private final FileDescriptor fd;
  71     private final int fdVal;
  72 
  73     // Lock held by current reading or connecting thread
  74     private final ReentrantLock readLock = new ReentrantLock();
  75 
  76     // Lock held by current writing or connecting thread
  77     private final ReentrantLock writeLock = new ReentrantLock();
  78 
  79     // Lock held by any thread that modifies the state fields declared below
  80     // DO NOT invoke a blocking I/O operation while holding this lock!
  81     private final Object stateLock = new Object();
  82 
  83     // Input/Output closed
  84     private volatile boolean isInputClosed;
  85     private volatile boolean isOutputClosed;
  86 
  87     // -- The following fields are protected by stateLock
  88 
  89     // set true when exclusive binding is on and SO_REUSEADDR is emulated
  90     private boolean isReuseAddress;
  91 
  92     // State, increases monotonically
  93     private static final int ST_UNCONNECTED = 0;
  94     private static final int ST_CONNECTIONPENDING = 1;
  95     private static final int ST_CONNECTED = 2;
  96     private static final int ST_CLOSING = 3;
  97     private static final int ST_KILLPENDING = 4;
  98     private static final int ST_KILLED = 5;
  99     private volatile int state;  // need stateLock to change
 100 
 101     // IDs of native threads doing reads and writes, for signalling
 102     private long readerThread;
 103     private long writerThread;
 104 
 105     // Binding
 106     private InetSocketAddress localAddress;
 107     private InetSocketAddress remoteAddress;
 108 
 109     // Socket adaptor, created on demand
 110     private Socket socket;
 111 
 112     // -- End of fields protected by stateLock
 113 
 114 
 115     // Constructor for normal connecting sockets
 116     //
 117     SocketChannelImpl(SelectorProvider sp) throws IOException {
 118         super(sp);
 119         this.fd = Net.socket(true);
 120         this.fdVal = IOUtil.fdVal(fd);
 121     }
 122 
 123     SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
 124         throws IOException
 125     {
 126         super(sp);
 127         this.fd = fd;
 128         this.fdVal = IOUtil.fdVal(fd);
 129         if (bound) {
 130             synchronized (stateLock) {
 131                 this.localAddress = Net.localAddress(fd);
 132             }
 133         }
 134     }
 135 
 136     // Constructor for sockets obtained from server sockets
 137     //
 138     SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, InetSocketAddress isa)
 139         throws IOException
 140     {
 141         super(sp);
 142         this.fd = fd;
 143         this.fdVal = IOUtil.fdVal(fd);
 144         synchronized (stateLock) {
 145             this.localAddress = Net.localAddress(fd);
 146             this.remoteAddress = isa;
 147             this.state = ST_CONNECTED;
 148         }
 149     }
 150 









 151     /**
 152      * Checks that the channel is open.
 153      *
 154      * @throws ClosedChannelException if channel is closed (or closing)
 155      */
 156     private void ensureOpen() throws ClosedChannelException {
 157         if (!isOpen())
 158             throw new ClosedChannelException();
 159     }
 160 
 161     /**
 162      * Checks that the channel is open and connected.
 163      *
 164      * @apiNote This method uses the "state" field to check if the channel is
 165      * open. It should never be used in conjuncion with isOpen or ensureOpen
 166      * as these methods check AbstractInterruptibleChannel's closed field - that
 167      * field is set before implCloseSelectableChannel is called and so before
 168      * the state is changed.
 169      *
 170      * @throws ClosedChannelException if channel is closed (or closing)
 171      * @throws NotYetConnectedException if open and not connected
 172      */
 173     private void ensureOpenAndConnected() throws ClosedChannelException {
 174         int state = this.state;
 175         if (state < ST_CONNECTED) {
 176             throw new NotYetConnectedException();
 177         } else if (state > ST_CONNECTED) {
 178             throw new ClosedChannelException();
 179         }
 180     }
 181 
 182     @Override
 183     public Socket socket() {
 184         synchronized (stateLock) {
 185             if (socket == null)
 186                 socket = SocketAdaptor.create(this);
 187             return socket;
 188         }
 189     }
 190 
 191     @Override
 192     public SocketAddress getLocalAddress() throws IOException {
 193         synchronized (stateLock) {
 194             ensureOpen();
 195             return Net.getRevealedLocalAddress(localAddress);
 196         }
 197     }
 198 
 199     @Override
 200     public SocketAddress getRemoteAddress() throws IOException {
 201         synchronized (stateLock) {
 202             ensureOpen();
 203             return remoteAddress;
 204         }
 205     }
 206 
 207     @Override
 208     public <T> SocketChannel setOption(SocketOption<T> name, T value)
 209         throws IOException
 210     {
 211         Objects.requireNonNull(name);
 212         if (!supportedOptions().contains(name))
 213             throw new UnsupportedOperationException("'" + name + "' not supported");
 214 
 215         synchronized (stateLock) {
 216             ensureOpen();
 217 
 218             if (name == StandardSocketOptions.IP_TOS) {
 219                 ProtocolFamily family = Net.isIPv6Available() ?
 220                     StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
 221                 Net.setSocketOption(fd, family, name, value);
 222                 return this;
 223             }
 224 
 225             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 226                 // SO_REUSEADDR emulated when using exclusive bind
 227                 isReuseAddress = (Boolean)value;
 228                 return this;
 229             }
 230 
 231             // no options that require special handling
 232             Net.setSocketOption(fd, Net.UNSPEC, name, value);
 233             return this;
 234         }
 235     }
 236 
 237     @Override
 238     @SuppressWarnings("unchecked")
 239     public <T> T getOption(SocketOption<T> name)
 240         throws IOException
 241     {
 242         Objects.requireNonNull(name);
 243         if (!supportedOptions().contains(name))
 244             throw new UnsupportedOperationException("'" + name + "' not supported");
 245 
 246         synchronized (stateLock) {
 247             ensureOpen();
 248 
 249             if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
 250                 // SO_REUSEADDR emulated when using exclusive bind
 251                 return (T)Boolean.valueOf(isReuseAddress);
 252             }
 253 
 254             // special handling for IP_TOS: always return 0 when IPv6
 255             if (name == StandardSocketOptions.IP_TOS) {
 256                 ProtocolFamily family = Net.isIPv6Available() ?
 257                     StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
 258                 return (T) Net.getSocketOption(fd, family, name);
 259             }
 260 
 261             // no options that require special handling
 262             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
 263         }
 264     }
 265 
 266     private static class DefaultOptionsHolder {
 267         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
 268 
 269         private static Set<SocketOption<?>> defaultOptions() {
 270             HashSet<SocketOption<?>> set = new HashSet<>();
 271             set.add(StandardSocketOptions.SO_SNDBUF);
 272             set.add(StandardSocketOptions.SO_RCVBUF);
 273             set.add(StandardSocketOptions.SO_KEEPALIVE);
 274             set.add(StandardSocketOptions.SO_REUSEADDR);
 275             if (Net.isReusePortAvailable()) {
 276                 set.add(StandardSocketOptions.SO_REUSEPORT);
 277             }
 278             set.add(StandardSocketOptions.SO_LINGER);
 279             set.add(StandardSocketOptions.TCP_NODELAY);
 280             // additional options required by socket adaptor
 281             set.add(StandardSocketOptions.IP_TOS);
 282             set.add(ExtendedSocketOption.SO_OOBINLINE);
 283             set.addAll(ExtendedSocketOptions.getInstance().options());
 284             return Collections.unmodifiableSet(set);
 285         }
 286     }
 287 
 288     @Override
 289     public final Set<SocketOption<?>> supportedOptions() {
 290         return DefaultOptionsHolder.defaultOptions;
 291     }
 292 
 293     /**
 294      * Marks the beginning of a read operation that might block.
 295      *
 296      * @throws ClosedChannelException if the channel is closed
 297      * @throws NotYetConnectedException if the channel is not yet connected
 298      */
 299     private void beginRead(boolean blocking) throws ClosedChannelException {
 300         if (blocking) {
 301             // set hook for Thread.interrupt
 302             begin();
 303 
 304             synchronized (stateLock) {
 305                 ensureOpenAndConnected();
 306                 // record thread so it can be signalled if needed
 307                 readerThread = NativeThread.current();
 308             }
 309         } else {
 310             ensureOpenAndConnected();
 311         }
 312     }
 313 
 314     /**
 315      * Marks the end of a read operation that may have blocked.
 316      *
 317      * @throws AsynchronousCloseException if the channel was closed due to this
 318      * thread being interrupted on a blocking read operation.
 319      */
 320     private void endRead(boolean blocking, boolean completed)
 321         throws AsynchronousCloseException
 322     {
 323         if (blocking) {
 324             synchronized (stateLock) {
 325                 readerThread = 0;
 326                 // notify any thread waiting in implCloseSelectableChannel
 327                 if (state == ST_CLOSING) {
 328                     stateLock.notifyAll();
 329                 }
 330             }
 331             // remove hook for Thread.interrupt
 332             end(completed);
 333         }
 334     }
 335 
 336     @Override
 337     public int read(ByteBuffer buf) throws IOException {
 338         Objects.requireNonNull(buf);
 339 
 340         readLock.lock();
 341         try {
 342             boolean blocking = isBlocking();
 343             int n = 0;
 344             try {
 345                 beginRead(blocking);
 346 
 347                 // check if input is shutdown
 348                 if (isInputClosed)
 349                     return IOStatus.EOF;
 350 
 351                 if (blocking) {
 352                     do {
 353                         n = IOUtil.read(fd, buf, -1, nd);
 354                     } while (n == IOStatus.INTERRUPTED && isOpen());
 355                 } else {
 356                     n = IOUtil.read(fd, buf, -1, nd);
 357                 }
 358             } finally {
 359                 endRead(blocking, n > 0);
 360                 if (n <= 0 && isInputClosed)
 361                     return IOStatus.EOF;
 362             }
 363             return IOStatus.normalize(n);
 364         } finally {
 365             readLock.unlock();
 366         }
 367     }
 368 
 369     @Override
 370     public long read(ByteBuffer[] dsts, int offset, int length)
 371         throws IOException
 372     {
 373         Objects.checkFromIndexSize(offset, length, dsts.length);
 374 
 375         readLock.lock();
 376         try {
 377             boolean blocking = isBlocking();
 378             long n = 0;
 379             try {
 380                 beginRead(blocking);
 381 
 382                 // check if input is shutdown
 383                 if (isInputClosed)
 384                     return IOStatus.EOF;
 385 
 386                 if (blocking) {
 387                     do {
 388                         n = IOUtil.read(fd, dsts, offset, length, nd);
 389                     } while (n == IOStatus.INTERRUPTED && isOpen());
 390                 } else {
 391                     n = IOUtil.read(fd, dsts, offset, length, nd);
 392                 }
 393             } finally {
 394                 endRead(blocking, n > 0);
 395                 if (n <= 0 && isInputClosed)
 396                     return IOStatus.EOF;
 397             }
 398             return IOStatus.normalize(n);
 399         } finally {
 400             readLock.unlock();
 401         }
 402     }
 403 
 404     /**
 405      * Marks the beginning of a write operation that might block.
 406      *
 407      * @throws ClosedChannelException if the channel is closed or output shutdown
 408      * @throws NotYetConnectedException if the channel is not yet connected
 409      */
 410     private void beginWrite(boolean blocking) throws ClosedChannelException {
 411         if (blocking) {
 412             // set hook for Thread.interrupt
 413             begin();
 414 
 415             synchronized (stateLock) {
 416                 ensureOpenAndConnected();
 417                 if (isOutputClosed)
 418                     throw new ClosedChannelException();
 419                 // record thread so it can be signalled if needed
 420                 writerThread = NativeThread.current();
 421             }
 422         } else {
 423             ensureOpenAndConnected();
 424         }
 425     }
 426 
 427     /**
 428      * Marks the end of a write operation that may have blocked.
 429      *
 430      * @throws AsynchronousCloseException if the channel was closed due to this
 431      * thread being interrupted on a blocking write operation.
 432      */
 433     private void endWrite(boolean blocking, boolean completed)
 434         throws AsynchronousCloseException
 435     {
 436         if (blocking) {
 437             synchronized (stateLock) {
 438                 writerThread = 0;
 439                 // notify any thread waiting in implCloseSelectableChannel
 440                 if (state == ST_CLOSING) {
 441                     stateLock.notifyAll();
 442                 }
 443             }
 444             // remove hook for Thread.interrupt
 445             end(completed);
 446         }
 447     }
 448 
 449     @Override
 450     public int write(ByteBuffer buf) throws IOException {
 451         Objects.requireNonNull(buf);
 452 
 453         writeLock.lock();
 454         try {
 455             boolean blocking = isBlocking();
 456             int n = 0;
 457             try {
 458                 beginWrite(blocking);
 459                 if (blocking) {
 460                     do {
 461                         n = IOUtil.write(fd, buf, -1, nd);
 462                     } while (n == IOStatus.INTERRUPTED && isOpen());
 463                 } else {
 464                     n = IOUtil.write(fd, buf, -1, nd);
 465                 }
 466             } finally {
 467                 endWrite(blocking, n > 0);
 468                 if (n <= 0 && isOutputClosed)
 469                     throw new AsynchronousCloseException();
 470             }
 471             return IOStatus.normalize(n);
 472         } finally {
 473             writeLock.unlock();
 474         }
 475     }
 476 
 477     @Override
 478     public long write(ByteBuffer[] srcs, int offset, int length)
 479         throws IOException
 480     {
 481         Objects.checkFromIndexSize(offset, length, srcs.length);
 482 
 483         writeLock.lock();
 484         try {
 485             boolean blocking = isBlocking();
 486             long n = 0;
 487             try {
 488                 beginWrite(blocking);
 489                 if (blocking) {
 490                     do {
 491                         n = IOUtil.write(fd, srcs, offset, length, nd);
 492                     } while (n == IOStatus.INTERRUPTED && isOpen());
 493                 } else {
 494                     n = IOUtil.write(fd, srcs, offset, length, nd);
 495                 }
 496             } finally {
 497                 endWrite(blocking, n > 0);
 498                 if (n <= 0 && isOutputClosed)
 499                     throw new AsynchronousCloseException();
 500             }
 501             return IOStatus.normalize(n);
 502         } finally {
 503             writeLock.unlock();
 504         }
 505     }
 506 
 507     /**
 508      * Writes a byte of out of band data.
 509      */
 510     int sendOutOfBandData(byte b) throws IOException {
 511         writeLock.lock();
 512         try {
 513             boolean blocking = isBlocking();
 514             int n = 0;
 515             try {
 516                 beginWrite(blocking);
 517                 if (blocking) {
 518                     do {
 519                         n = sendOutOfBandData(fd, b);
 520                     } while (n == IOStatus.INTERRUPTED && isOpen());
 521                 } else {
 522                     n = sendOutOfBandData(fd, b);
 523                 }
 524             } finally {
 525                 endWrite(blocking, n > 0);
 526                 if (n <= 0 && isOutputClosed)
 527                     throw new AsynchronousCloseException();
 528             }
 529             return IOStatus.normalize(n);
 530         } finally {
 531             writeLock.unlock();
 532         }
 533     }
 534 
 535     @Override
 536     protected void implConfigureBlocking(boolean block) throws IOException {
 537         readLock.lock();
 538         try {
 539             writeLock.lock();
 540             try {
 541                 synchronized (stateLock) {
 542                     ensureOpen();
 543                     IOUtil.configureBlocking(fd, block);
 544                 }
 545             } finally {
 546                 writeLock.unlock();
 547             }
 548         } finally {
 549             readLock.unlock();
 550         }
 551     }
 552 
 553     /**
 554      * Returns the local address, or null if not bound
 555      */
 556     InetSocketAddress localAddress() {
 557         synchronized (stateLock) {
 558             return localAddress;
 559         }
 560     }
 561 
 562     /**
 563      * Returns the remote address, or null if not connected
 564      */
 565     InetSocketAddress remoteAddress() {
 566         synchronized (stateLock) {
 567             return remoteAddress;
 568         }
 569     }
 570 
 571     @Override
 572     public SocketChannel bind(SocketAddress local) throws IOException {
 573         readLock.lock();
 574         try {
 575             writeLock.lock();
 576             try {
 577                 synchronized (stateLock) {
 578                     ensureOpen();
 579                     if (state == ST_CONNECTIONPENDING)
 580                         throw new ConnectionPendingException();
 581                     if (localAddress != null)
 582                         throw new AlreadyBoundException();
 583                     InetSocketAddress isa = (local == null) ?
 584                         new InetSocketAddress(0) : Net.checkAddress(local);
 585                     SecurityManager sm = System.getSecurityManager();
 586                     if (sm != null) {
 587                         sm.checkListen(isa.getPort());
 588                     }
 589                     NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
 590                     Net.bind(fd, isa.getAddress(), isa.getPort());
 591                     localAddress = Net.localAddress(fd);
 592                 }
 593             } finally {
 594                 writeLock.unlock();
 595             }
 596         } finally {
 597             readLock.unlock();
 598         }
 599         return this;
 600     }
 601 
 602     @Override
 603     public boolean isConnected() {
 604         return (state == ST_CONNECTED);
 605     }
 606 
 607     @Override
 608     public boolean isConnectionPending() {
 609         return (state == ST_CONNECTIONPENDING);
 610     }
 611 
 612     /**
 613      * Marks the beginning of a connect operation that might block.
 614      * @param blocking true if configured blocking
 615      * @param isa the remote address
 616      * @throws ClosedChannelException if the channel is closed
 617      * @throws AlreadyConnectedException if already connected
 618      * @throws ConnectionPendingException is a connection is pending
 619      * @throws IOException if the pre-connect hook fails
 620      */
 621     private void beginConnect(boolean blocking, InetSocketAddress isa)
 622         throws IOException
 623     {
 624         if (blocking) {
 625             // set hook for Thread.interrupt
 626             begin();
 627         }
 628         synchronized (stateLock) {
 629             ensureOpen();
 630             int state = this.state;
 631             if (state == ST_CONNECTED)
 632                 throw new AlreadyConnectedException();
 633             if (state == ST_CONNECTIONPENDING)
 634                 throw new ConnectionPendingException();
 635             assert state == ST_UNCONNECTED;
 636             this.state = ST_CONNECTIONPENDING;
 637 
 638             if (localAddress == null)
 639                 NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
 640             remoteAddress = isa;
 641 
 642             if (blocking) {
 643                 // record thread so it can be signalled if needed
 644                 readerThread = NativeThread.current();
 645             }
 646         }
 647     }
 648 
 649     /**
 650      * Marks the end of a connect operation that may have blocked.
 651      *
 652      * @throws AsynchronousCloseException if the channel was closed due to this
 653      * thread being interrupted on a blocking connect operation.
 654      * @throws IOException if completed and unable to obtain the local address
 655      */
 656     private void endConnect(boolean blocking, boolean completed)
 657         throws IOException
 658     {
 659         endRead(blocking, completed);
 660 
 661         if (completed) {
 662             synchronized (stateLock) {
 663                 if (state == ST_CONNECTIONPENDING) {
 664                     localAddress = Net.localAddress(fd);
 665                     state = ST_CONNECTED;
 666                 }
 667             }
 668         }
 669     }
 670 
 671     @Override
 672     public boolean connect(SocketAddress sa) throws IOException {
 673         InetSocketAddress isa = Net.checkAddress(sa);
 674         SecurityManager sm = System.getSecurityManager();
 675         if (sm != null)
 676             sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
 677 
 678         InetAddress ia = isa.getAddress();
 679         if (ia.isAnyLocalAddress())
 680             ia = InetAddress.getLocalHost();
 681 
 682         try {
 683             readLock.lock();
 684             try {
 685                 writeLock.lock();
 686                 try {
 687                     int n = 0;
 688                     boolean blocking = isBlocking();
 689                     try {
 690                         beginConnect(blocking, isa);
 691                         do {
 692                             n = Net.connect(fd, ia, isa.getPort());
 693                         } while (n == IOStatus.INTERRUPTED && isOpen());
 694                     } finally {
 695                         endConnect(blocking, (n > 0));
 696                     }
 697                     assert IOStatus.check(n);
 698                     return n > 0;
 699                 } finally {
 700                     writeLock.unlock();
 701                 }
 702             } finally {
 703                 readLock.unlock();
 704             }
 705         } catch (IOException ioe) {
 706             // connect failed, close the channel
 707             close();
 708             throw ioe;
 709         }
 710     }
 711 
 712     /**
 713      * Marks the beginning of a finishConnect operation that might block.
 714      *
 715      * @throws ClosedChannelException if the channel is closed
 716      * @throws NoConnectionPendingException if no connection is pending
 717      */
 718     private void beginFinishConnect(boolean blocking) throws ClosedChannelException {
 719         if (blocking) {
 720             // set hook for Thread.interrupt
 721             begin();
 722         }
 723         synchronized (stateLock) {
 724             ensureOpen();
 725             if (state != ST_CONNECTIONPENDING)
 726                 throw new NoConnectionPendingException();
 727             if (blocking) {
 728                 // record thread so it can be signalled if needed
 729                 readerThread = NativeThread.current();
 730             }
 731         }
 732     }
 733 
 734     /**
 735      * Marks the end of a finishConnect operation that may have blocked.
 736      *
 737      * @throws AsynchronousCloseException if the channel was closed due to this
 738      * thread being interrupted on a blocking connect operation.
 739      * @throws IOException if completed and unable to obtain the local address
 740      */
 741     private void endFinishConnect(boolean blocking, boolean completed)
 742         throws IOException
 743     {
 744         endRead(blocking, completed);
 745 
 746         if (completed) {
 747             synchronized (stateLock) {
 748                 if (state == ST_CONNECTIONPENDING) {
 749                     localAddress = Net.localAddress(fd);
 750                     state = ST_CONNECTED;
 751                 }
 752             }
 753         }
 754     }
 755 
 756     @Override
 757     public boolean finishConnect() throws IOException {
 758         try {
 759             readLock.lock();
 760             try {
 761                 writeLock.lock();
 762                 try {
 763                     // no-op if already connected
 764                     if (isConnected())
 765                         return true;
 766 
 767                     boolean blocking = isBlocking();
 768                     boolean connected = false;
 769                     try {
 770                         beginFinishConnect(blocking);
 771                         int n = 0;
 772                         if (blocking) {
 773                             do {
 774                                 n = checkConnect(fd, true);
 775                             } while ((n == 0 || n == IOStatus.INTERRUPTED) && isOpen());
 776                         } else {
 777                             n = checkConnect(fd, false);
 778                         }
 779                         connected = (n > 0);
 780                     } finally {
 781                         endFinishConnect(blocking, connected);
 782                     }
 783                     assert (blocking && connected) ^ !blocking;
 784                     return connected;
 785                 } finally {
 786                     writeLock.unlock();
 787                 }
 788             } finally {
 789                 readLock.unlock();
 790             }
 791         } catch (IOException ioe) {
 792             // connect failed, close the channel
 793             close();
 794             throw ioe;
 795         }
 796     }
 797 
 798     /**
 799      * Invoked by implCloseChannel to close the channel.
 800      *
 801      * This method waits for outstanding I/O operations to complete. When in
 802      * blocking mode, the socket is pre-closed and the threads in blocking I/O
 803      * operations are signalled to ensure that the outstanding I/O operations
 804      * complete quickly.
 805      *
 806      * If the socket is connected then it is shutdown by this method. The
 807      * shutdown ensures that the peer reads EOF for the case that the socket is
 808      * not pre-closed or closed by this method.
 809      *
 810      * The socket is closed by this method when it is not registered with a
 811      * Selector. Note that a channel configured blocking may be registered with
 812      * a Selector. This arises when a key is canceled and the channel configured
 813      * to blocking mode before the key is flushed from the Selector.
 814      */
 815     @Override
 816     protected void implCloseSelectableChannel() throws IOException {
 817         assert !isOpen();
 818 
 819         boolean blocking;
 820         boolean connected;
 821         boolean interrupted = false;
 822 
 823         // set state to ST_CLOSING
 824         synchronized (stateLock) {
 825             assert state < ST_CLOSING;
 826             blocking = isBlocking();
 827             connected = (state == ST_CONNECTED);
 828             state = ST_CLOSING;
 829         }
 830 
 831         // wait for any outstanding I/O operations to complete
 832         if (blocking) {
 833             synchronized (stateLock) {
 834                 assert state == ST_CLOSING;
 835                 long reader = readerThread;
 836                 long writer = writerThread;
 837                 if (reader != 0 || writer != 0) {
 838                     nd.preClose(fd);
 839                     connected = false; // fd is no longer connected socket
 840 
 841                     if (reader != 0)
 842                         NativeThread.signal(reader);
 843                     if (writer != 0)
 844                         NativeThread.signal(writer);
 845 
 846                     // wait for blocking I/O operations to end
 847                     while (readerThread != 0 || writerThread != 0) {
 848                         try {
 849                             stateLock.wait();
 850                         } catch (InterruptedException e) {
 851                             interrupted = true;
 852                         }
 853                     }
 854                 }
 855             }
 856         } else {
 857             // non-blocking mode: wait for read/write to complete
 858             readLock.lock();
 859             try {
 860                 writeLock.lock();
 861                 writeLock.unlock();
 862             } finally {
 863                 readLock.unlock();
 864             }
 865         }
 866 
 867         // set state to ST_KILLPENDING
 868         synchronized (stateLock) {
 869             assert state == ST_CLOSING;
 870             // if connected, and the channel is registered with a Selector, we
 871             // shutdown the output so that the peer reads EOF
 872             if (connected && isRegistered()) {
 873                 try {
 874                     Net.shutdown(fd, Net.SHUT_WR);
 875                 } catch (IOException ignore) { }
 876             }
 877             state = ST_KILLPENDING;
 878         }
 879 
 880         // close socket if not registered with Selector
 881         if (!isRegistered())
 882             kill();
 883 
 884         // restore interrupt status
 885         if (interrupted)
 886             Thread.currentThread().interrupt();
 887     }
 888 
 889     @Override
 890     public void kill() throws IOException {
 891         synchronized (stateLock) {
 892             if (state == ST_KILLPENDING) {
 893                 state = ST_KILLED;
 894                 nd.close(fd);
 895             }
 896         }
 897     }
 898 
 899     @Override
 900     public SocketChannel shutdownInput() throws IOException {
 901         synchronized (stateLock) {
 902             ensureOpen();
 903             if (!isConnected())
 904                 throw new NotYetConnectedException();
 905             if (!isInputClosed) {
 906                 Net.shutdown(fd, Net.SHUT_RD);
 907                 long thread = readerThread;
 908                 if (thread != 0)
 909                     NativeThread.signal(thread);
 910                 isInputClosed = true;
 911             }
 912             return this;
 913         }
 914     }
 915 
 916     @Override
 917     public SocketChannel shutdownOutput() throws IOException {
 918         synchronized (stateLock) {
 919             ensureOpen();
 920             if (!isConnected())
 921                 throw new NotYetConnectedException();
 922             if (!isOutputClosed) {
 923                 Net.shutdown(fd, Net.SHUT_WR);
 924                 long thread = writerThread;
 925                 if (thread != 0)
 926                     NativeThread.signal(thread);
 927                 isOutputClosed = true;
 928             }
 929             return this;
 930         }
 931     }
 932 
 933     boolean isInputOpen() {
 934         return !isInputClosed;
 935     }
 936 
 937     boolean isOutputOpen() {
 938         return !isOutputClosed;
 939     }
 940 
 941     /**
 942      * Poll this channel's socket for reading up to the given timeout.
 943      * @return {@code true} if the socket is polled
 944      */
 945     boolean pollRead(long timeout) throws IOException {
 946         boolean blocking = isBlocking();
 947         assert Thread.holdsLock(blockingLock()) && blocking;
 948 
 949         readLock.lock();
 950         try {
 951             boolean polled = false;
 952             try {
 953                 beginRead(blocking);
 954                 int events = Net.poll(fd, Net.POLLIN, timeout);
 955                 polled = (events != 0);
 956             } finally {
 957                 endRead(blocking, polled);
 958             }
 959             return polled;
 960         } finally {
 961             readLock.unlock();
 962         }
 963     }
 964 
 965     /**
 966      * Poll this channel's socket for a connection, up to the given timeout.
 967      * @return {@code true} if the socket is polled
 968      */
 969     boolean pollConnected(long timeout) throws IOException {
 970         boolean blocking = isBlocking();
 971         assert Thread.holdsLock(blockingLock()) && blocking;
 972 
 973         readLock.lock();
 974         try {
 975             writeLock.lock();
 976             try {
 977                 boolean polled = false;
 978                 try {
 979                     beginFinishConnect(blocking);
 980                     int events = Net.poll(fd, Net.POLLCONN, timeout);
 981                     polled = (events != 0);
 982                 } finally {
 983                     // invoke endFinishConnect with completed = false so that
 984                     // the state is not changed to ST_CONNECTED. The socket
 985                     // adaptor will use finishConnect to finish.
 986                     endFinishConnect(blocking, /*completed*/false);
 987                 }
 988                 return polled;
 989             } finally {
 990                 writeLock.unlock();
 991             }
 992         } finally {
 993             readLock.unlock();
 994         }
 995     }
 996 
 997     /**
 998      * Translates native poll revent ops into a ready operation ops
 999      */
1000     public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
1001         int intOps = ski.nioInterestOps();
1002         int oldOps = ski.nioReadyOps();
1003         int newOps = initialOps;
1004 
1005         if ((ops & Net.POLLNVAL) != 0) {
1006             // This should only happen if this channel is pre-closed while a
1007             // selection operation is in progress
1008             // ## Throw an error if this channel has not been pre-closed
1009             return false;
1010         }
1011 
1012         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
1013             newOps = intOps;
1014             ski.nioReadyOps(newOps);
1015             return (newOps & ~oldOps) != 0;
1016         }
1017 
1018         boolean connected = isConnected();
1019         if (((ops & Net.POLLIN) != 0) &&
1020             ((intOps & SelectionKey.OP_READ) != 0) && connected)
1021             newOps |= SelectionKey.OP_READ;
1022 
1023         if (((ops & Net.POLLCONN) != 0) &&
1024             ((intOps & SelectionKey.OP_CONNECT) != 0) && isConnectionPending())
1025             newOps |= SelectionKey.OP_CONNECT;
1026 
1027         if (((ops & Net.POLLOUT) != 0) &&
1028             ((intOps & SelectionKey.OP_WRITE) != 0) && connected)
1029             newOps |= SelectionKey.OP_WRITE;
1030 
1031         ski.nioReadyOps(newOps);
1032         return (newOps & ~oldOps) != 0;
1033     }
1034 
1035     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
1036         return translateReadyOps(ops, ski.nioReadyOps(), ski);
1037     }
1038 
1039     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
1040         return translateReadyOps(ops, 0, ski);
1041     }
1042 
1043     /**
1044      * Translates an interest operation set into a native poll event set
1045      */
1046     public int translateInterestOps(int ops) {
1047         int newOps = 0;
1048         if ((ops & SelectionKey.OP_READ) != 0)
1049             newOps |= Net.POLLIN;
1050         if ((ops & SelectionKey.OP_WRITE) != 0)
1051             newOps |= Net.POLLOUT;
1052         if ((ops & SelectionKey.OP_CONNECT) != 0)
1053             newOps |= Net.POLLCONN;
1054         return newOps;
1055     }
1056 
1057     public FileDescriptor getFD() {
1058         return fd;
1059     }
1060 
1061     public int getFDVal() {
1062         return fdVal;
1063     }
1064 
1065     @Override
1066     public String toString() {
1067         StringBuilder sb = new StringBuilder();
1068         sb.append(this.getClass().getSuperclass().getName());
1069         sb.append('[');
1070         if (!isOpen())
1071             sb.append("closed");
1072         else {
1073             synchronized (stateLock) {
1074                 switch (state) {
1075                 case ST_UNCONNECTED:
1076                     sb.append("unconnected");
1077                     break;
1078                 case ST_CONNECTIONPENDING:
1079                     sb.append("connection-pending");
1080                     break;
1081                 case ST_CONNECTED:
1082                     sb.append("connected");
1083                     if (isInputClosed)
1084                         sb.append(" ishut");
1085                     if (isOutputClosed)
1086                         sb.append(" oshut");
1087                     break;
1088                 }
1089                 InetSocketAddress addr = localAddress();
1090                 if (addr != null) {
1091                     sb.append(" local=");
1092                     sb.append(Net.getRevealedLocalAddressAsString(addr));
1093                 }
1094                 if (remoteAddress() != null) {
1095                     sb.append(" remote=");
1096                     sb.append(remoteAddress().toString());
1097                 }
1098             }
1099         }
1100         sb.append(']');
1101         return sb.toString();
1102     }
1103 
1104 
1105     // -- Native methods --
1106 
1107     private static native int checkConnect(FileDescriptor fd, boolean block)
1108         throws IOException;
1109 
1110     private static native int sendOutOfBandData(FileDescriptor fd, byte data)
1111         throws IOException;
1112 
1113     static {
1114         IOUtil.load();
1115         nd = new SocketDispatcher();
1116     }
1117 
1118 }
--- EOF ---