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