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