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 }