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