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 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 SocketAddress localAddress; 84 private SocketAddress 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 int n = 0; 282 try { 283 284 // Set up the interruption machinery; see 285 // AbstractInterruptibleChannel for details 286 // 287 begin(); 288 289 synchronized (stateLock) { 290 if (!isOpen()) { 291 // Either the current thread is already interrupted, so 292 // begin() closed the channel, or another thread closed the 293 // channel since we checked it a few bytecodes ago. In 294 // either case the value returned here is irrelevant since 295 // the invocation of end() in the finally block will throw 296 // an appropriate exception. 297 // 298 return 0; 299 300 } 301 302 // Save this thread so that it can be signalled on those 303 // platforms that require it 304 // 305 readerThread = NativeThread.current(); 306 } 307 308 // Between the previous test of isOpen() and the return of the 309 // IOUtil.read invocation below, this channel might be closed 310 // or this thread might be interrupted. We rely upon the 311 // implicit synchronization point in the kernel read() call to 312 // make sure that the right thing happens. In either case the 313 // implCloseSelectableChannel method is ultimately invoked in 314 // some other thread, so there are three possibilities: 315 // 316 // - implCloseSelectableChannel() invokes nd.preClose() 317 // before this thread invokes read(), in which case the 318 // read returns immediately with either EOF or an error, 319 // the latter of which will cause an IOException to be 320 // thrown. 321 // 322 // - implCloseSelectableChannel() invokes nd.preClose() after 323 // this thread is blocked in read(). On some operating 324 // systems (e.g., Solaris and Windows) this causes the read 325 // to return immediately with either EOF or an error 326 // indication. 327 // 328 // - implCloseSelectableChannel() invokes nd.preClose() after 329 // this thread is blocked in read() but the operating 330 // system (e.g., Linux) doesn't support preemptive close, 331 // so implCloseSelectableChannel() proceeds to signal this 332 // thread, thereby causing the read to return immediately 333 // with IOStatus.INTERRUPTED. 334 // 335 // In all three cases the invocation of end() in the finally 336 // clause will notice that the channel has been closed and 337 // throw an appropriate exception (AsynchronousCloseException 338 // or ClosedByInterruptException) if necessary. 339 // 340 // *There is A fourth possibility. implCloseSelectableChannel() 341 // invokes nd.preClose(), signals reader/writer thred and quickly 342 // moves on to nd.close() in kill(), which does a real close. 343 // Then a third thread accepts a new connection, opens file or 344 // whatever that causes the released "fd" to be recycled. All 345 // above happens just between our last isOpen() check and the 346 // next kernel read reached, with the recycled "fd". The solution 347 // is to postpone the real kill() if there is a reader or/and 348 // writer thread(s) over there "waiting", leave the cleanup/kill 349 // to the reader or writer thread. (the preClose() still happens 350 // so the connection gets cut off as usual). 351 // 352 // For socket channels there is the additional wrinkle that 353 // asynchronous shutdown works much like asynchronous close, 354 // except that the channel is shutdown rather than completely 355 // closed. This is analogous to the first two cases above, 356 // except that the shutdown operation plays the role of 357 // nd.preClose(). 358 for (;;) { 359 n = IOUtil.read(fd, buf, -1, nd, readLock); 360 if ((n == IOStatus.INTERRUPTED) && isOpen()) { 361 // The system call was interrupted but the channel 362 // is still open, so retry 363 continue; 364 } 365 return IOStatus.normalize(n); 366 } 367 368 } finally { 369 readerCleanup(); // Clear reader thread 370 // The end method, which is defined in our superclass 371 // AbstractInterruptibleChannel, resets the interruption 372 // machinery. If its argument is true then it returns 373 // normally; otherwise it checks the interrupt and open state 374 // of this channel and throws an appropriate exception if 375 // necessary. 376 // 377 // So, if we actually managed to do any I/O in the above try 378 // block then we pass true to the end method. We also pass 379 // true if the channel was in non-blocking mode when the I/O 380 // operation was initiated but no data could be transferred; 381 // this prevents spurious exceptions from being thrown in the 382 // rare event that a channel is closed or a thread is 383 // interrupted at the exact moment that a non-blocking I/O 384 // request is made. 385 // 386 end(n > 0 || (n == IOStatus.UNAVAILABLE)); 387 388 // Extra case for socket channels: Asynchronous shutdown 389 // 390 synchronized (stateLock) { 391 if ((n <= 0) && (!isInputOpen)) 392 return IOStatus.EOF; 393 } 394 395 assert IOStatus.check(n); 396 397 } 398 } 399 } 400 401 public long read(ByteBuffer[] dsts, int offset, int length) 402 throws IOException 403 { 404 if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) 405 throw new IndexOutOfBoundsException(); 406 synchronized (readLock) { 407 if (!ensureReadOpen()) 408 return -1; 409 long n = 0; 410 try { 411 begin(); 412 synchronized (stateLock) { 413 if (!isOpen()) 414 return 0; 415 readerThread = NativeThread.current(); 416 } 417 418 for (;;) { 419 n = IOUtil.read(fd, dsts, offset, length, nd); 420 if ((n == IOStatus.INTERRUPTED) && isOpen()) 421 continue; 422 return IOStatus.normalize(n); 423 } 424 } finally { 425 readerCleanup(); 426 end(n > 0 || (n == IOStatus.UNAVAILABLE)); 427 synchronized (stateLock) { 428 if ((n <= 0) && (!isInputOpen)) 429 return IOStatus.EOF; 430 } 431 assert IOStatus.check(n); 432 } 433 } 434 } 435 436 public int write(ByteBuffer buf) throws IOException { 437 if (buf == null) 438 throw new NullPointerException(); 439 synchronized (writeLock) { 440 ensureWriteOpen(); 441 int n = 0; 442 try { 443 begin(); 444 synchronized (stateLock) { 445 if (!isOpen()) 446 return 0; 447 writerThread = NativeThread.current(); 448 } 449 for (;;) { 450 n = IOUtil.write(fd, buf, -1, nd, writeLock); 451 if ((n == IOStatus.INTERRUPTED) && isOpen()) 452 continue; 453 return IOStatus.normalize(n); 454 } 455 } finally { 456 writerCleanup(); 457 end(n > 0 || (n == IOStatus.UNAVAILABLE)); 458 synchronized (stateLock) { 459 if ((n <= 0) && (!isOutputOpen)) 460 throw new AsynchronousCloseException(); 461 } 462 assert IOStatus.check(n); 463 } 464 } 465 } 466 467 public long write(ByteBuffer[] srcs, int offset, int length) 468 throws IOException 469 { 470 if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) 471 throw new IndexOutOfBoundsException(); 472 synchronized (writeLock) { 473 ensureWriteOpen(); 474 long n = 0; 475 try { 476 begin(); 477 synchronized (stateLock) { 478 if (!isOpen()) 479 return 0; 480 writerThread = NativeThread.current(); 481 } 482 for (;;) { 483 n = IOUtil.write(fd, srcs, offset, length, nd); 484 if ((n == IOStatus.INTERRUPTED) && isOpen()) 485 continue; 486 return IOStatus.normalize(n); 487 } 488 } finally { 489 writerCleanup(); 490 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 491 synchronized (stateLock) { 492 if ((n <= 0) && (!isOutputOpen)) 493 throw new AsynchronousCloseException(); 494 } 495 assert IOStatus.check(n); 496 } 497 } 498 } 499 500 // package-private 501 int sendOutOfBandData(byte b) throws IOException { 502 synchronized (writeLock) { 503 ensureWriteOpen(); 504 int n = 0; 505 try { 506 begin(); 507 synchronized (stateLock) { 508 if (!isOpen()) 509 return 0; 510 writerThread = NativeThread.current(); 511 } 512 for (;;) { 513 n = sendOutOfBandData(fd, b); 514 if ((n == IOStatus.INTERRUPTED) && isOpen()) 515 continue; 516 return IOStatus.normalize(n); 517 } 518 } finally { 519 writerCleanup(); 520 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 521 synchronized (stateLock) { 522 if ((n <= 0) && (!isOutputOpen)) 523 throw new AsynchronousCloseException(); 524 } 525 assert IOStatus.check(n); 526 } 527 } 528 } 529 530 protected void implConfigureBlocking(boolean block) throws IOException { 531 IOUtil.configureBlocking(fd, block); 532 } 533 534 public SocketAddress localAddress() { 535 synchronized (stateLock) { 536 return localAddress; 537 } 538 } 539 540 public SocketAddress remoteAddress() { 541 synchronized (stateLock) { 542 return remoteAddress; 543 } 544 } 545 546 @Override 547 public SocketChannel bind(SocketAddress local) throws IOException { 548 synchronized (readLock) { 549 synchronized (writeLock) { 550 synchronized (stateLock) { 551 if (!isOpen()) 552 throw new ClosedChannelException(); 553 if (state == ST_PENDING) 554 throw new ConnectionPendingException(); 555 if (localAddress != null) 556 throw new AlreadyBoundException(); 557 InetSocketAddress isa = (local == null) ? 558 new InetSocketAddress(0) : Net.checkAddress(local); 559 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); 560 Net.bind(fd, isa.getAddress(), isa.getPort()); 561 localAddress = Net.localAddress(fd); 562 } 563 } 564 } 565 return this; 566 } 567 568 public boolean isConnected() { 569 synchronized (stateLock) { 570 return (state == ST_CONNECTED); 571 } 572 } 573 574 public boolean isConnectionPending() { 575 synchronized (stateLock) { 576 return (state == ST_PENDING); 577 } 578 } 579 580 void ensureOpenAndUnconnected() throws IOException { // package-private 581 synchronized (stateLock) { 582 if (!isOpen()) 583 throw new ClosedChannelException(); 584 if (state == ST_CONNECTED) 585 throw new AlreadyConnectedException(); 586 if (state == ST_PENDING) 587 throw new ConnectionPendingException(); 588 } 589 } 590 591 public boolean connect(SocketAddress sa) throws IOException { 592 int localPort = 0; 593 594 synchronized (readLock) { 595 synchronized (writeLock) { 596 ensureOpenAndUnconnected(); 597 InetSocketAddress isa = Net.checkAddress(sa); 598 SecurityManager sm = System.getSecurityManager(); 599 if (sm != null) 600 sm.checkConnect(isa.getAddress().getHostAddress(), 601 isa.getPort()); 602 synchronized (blockingLock()) { 603 int n = 0; 604 try { 605 try { 606 begin(); 607 synchronized (stateLock) { 608 if (!isOpen()) { 609 return false; 610 } 611 // notify hook only if unbound 612 if (localAddress == null) { 613 NetHooks.beforeTcpConnect(fd, 614 isa.getAddress(), 615 isa.getPort()); 616 } 617 readerThread = NativeThread.current(); 618 } 619 for (;;) { 620 InetAddress ia = isa.getAddress(); 621 if (ia.isAnyLocalAddress()) 622 ia = InetAddress.getLocalHost(); 623 n = Net.connect(fd, 624 ia, 625 isa.getPort()); 626 if ( (n == IOStatus.INTERRUPTED) 627 && isOpen()) 628 continue; 629 break; 630 } 631 632 } finally { 633 readerCleanup(); 634 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 635 assert IOStatus.check(n); 636 } 637 } catch (IOException x) { 638 // If an exception was thrown, close the channel after 639 // invoking end() so as to avoid bogus 640 // AsynchronousCloseExceptions 641 close(); 642 throw x; 643 } 644 synchronized (stateLock) { 645 remoteAddress = isa; 646 if (n > 0) { 647 648 // Connection succeeded; disallow further 649 // invocation 650 state = ST_CONNECTED; 651 if (isOpen()) 652 localAddress = Net.localAddress(fd); 653 return true; 654 } 655 // If nonblocking and no exception then connection 656 // pending; disallow another invocation 657 if (!isBlocking()) 658 state = ST_PENDING; 659 else 660 assert false; 661 } 662 } 663 return false; 664 } 665 } 666 } 667 668 public boolean finishConnect() throws IOException { 669 synchronized (readLock) { 670 synchronized (writeLock) { 671 synchronized (stateLock) { 672 if (!isOpen()) 673 throw new ClosedChannelException(); 674 if (state == ST_CONNECTED) 675 return true; 676 if (state != ST_PENDING) 677 throw new NoConnectionPendingException(); 678 } 679 int n = 0; 680 try { 681 try { 682 begin(); 683 synchronized (blockingLock()) { 684 synchronized (stateLock) { 685 if (!isOpen()) { 686 return false; 687 } 688 readerThread = NativeThread.current(); 689 } 690 if (!isBlocking()) { 691 for (;;) { 692 n = checkConnect(fd, false, 693 readyToConnect); 694 if ( (n == IOStatus.INTERRUPTED) 695 && isOpen()) 696 continue; 697 break; 698 } 699 } else { 700 for (;;) { 701 n = checkConnect(fd, true, 702 readyToConnect); 703 if (n == 0) { 704 // Loop in case of 705 // spurious notifications 706 continue; 707 } 708 if ( (n == IOStatus.INTERRUPTED) 709 && isOpen()) 710 continue; 711 break; 712 } 713 } 714 } 715 } finally { 716 synchronized (stateLock) { 717 readerThread = 0; 718 if (state == ST_KILLPENDING) { 719 kill(); 720 // poll()/getsockopt() does not report 721 // error (throws exception, with n = 0) 722 // on Linux platform after dup2 and 723 // signal-wakeup. Force n to 0 so the 724 // end() can throw appropriate exception 725 n = 0; 726 } 727 } 728 end((n > 0) || (n == IOStatus.UNAVAILABLE)); 729 assert IOStatus.check(n); 730 } 731 } catch (IOException x) { 732 // If an exception was thrown, close the channel after 733 // invoking end() so as to avoid bogus 734 // AsynchronousCloseExceptions 735 close(); 736 throw x; 737 } 738 if (n > 0) { 739 synchronized (stateLock) { 740 state = ST_CONNECTED; 741 if (isOpen()) 742 localAddress = Net.localAddress(fd); 743 } 744 return true; 745 } 746 return false; 747 } 748 } 749 } 750 751 @Override 752 public SocketChannel shutdownInput() throws IOException { 753 synchronized (stateLock) { 754 if (!isOpen()) 755 throw new ClosedChannelException(); 756 if (!isConnected()) 757 throw new NotYetConnectedException(); 758 if (isInputOpen) { 759 Net.shutdown(fd, Net.SHUT_RD); 760 if (readerThread != 0) 761 NativeThread.signal(readerThread); 762 isInputOpen = false; 763 } 764 return this; 765 } 766 } 767 768 @Override 769 public SocketChannel shutdownOutput() throws IOException { 770 synchronized (stateLock) { 771 if (!isOpen()) 772 throw new ClosedChannelException(); 773 if (!isConnected()) 774 throw new NotYetConnectedException(); 775 if (isOutputOpen) { 776 Net.shutdown(fd, Net.SHUT_WR); 777 if (writerThread != 0) 778 NativeThread.signal(writerThread); 779 isOutputOpen = false; 780 } 781 return this; 782 } 783 } 784 785 public boolean isInputOpen() { 786 synchronized (stateLock) { 787 return isInputOpen; 788 } 789 } 790 791 public boolean isOutputOpen() { 792 synchronized (stateLock) { 793 return isOutputOpen; 794 } 795 } 796 797 // AbstractInterruptibleChannel synchronizes invocations of this method 798 // using AbstractInterruptibleChannel.closeLock, and also ensures that this 799 // method is only ever invoked once. Before we get to this method, isOpen 800 // (which is volatile) will have been set to false. 801 // 802 protected void implCloseSelectableChannel() throws IOException { 803 synchronized (stateLock) { 804 isInputOpen = false; 805 isOutputOpen = false; 806 807 // Close the underlying file descriptor and dup it to a known fd 808 // that's already closed. This prevents other operations on this 809 // channel from using the old fd, which might be recycled in the 810 // meantime and allocated to an entirely different channel. 811 // 812 if (state != ST_KILLED) 813 nd.preClose(fd); 814 815 // Signal native threads, if needed. If a target thread is not 816 // currently blocked in an I/O operation then no harm is done since 817 // the signal handler doesn't actually do anything. 818 // 819 if (readerThread != 0) 820 NativeThread.signal(readerThread); 821 822 if (writerThread != 0) 823 NativeThread.signal(writerThread); 824 825 // If this channel is not registered then it's safe to close the fd 826 // immediately since we know at this point that no thread is 827 // blocked in an I/O operation upon the channel and, since the 828 // channel is marked closed, no thread will start another such 829 // operation. If this channel is registered then we don't close 830 // the fd since it might be in use by a selector. In that case 831 // closing this channel caused its keys to be cancelled, so the 832 // last selector to deregister a key for this channel will invoke 833 // kill() to close the fd. 834 // 835 if (!isRegistered()) 836 kill(); 837 } 838 } 839 840 public void kill() throws IOException { 841 synchronized (stateLock) { 842 if (state == ST_KILLED) 843 return; 844 if (state == ST_UNINITIALIZED) { 845 state = ST_KILLED; 846 return; 847 } 848 assert !isOpen() && !isRegistered(); 849 850 // Postpone the kill if there is a waiting reader 851 // or writer thread. See the comments in read() for 852 // more detailed explanation. 853 if (readerThread == 0 && writerThread == 0) { 854 nd.close(fd); 855 state = ST_KILLED; 856 } else { 857 state = ST_KILLPENDING; 858 } 859 } 860 } 861 862 /** 863 * Translates native poll revent ops into a ready operation ops 864 */ 865 public boolean translateReadyOps(int ops, int initialOps, 866 SelectionKeyImpl sk) { 867 int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes 868 int oldOps = sk.nioReadyOps(); 869 int newOps = initialOps; 870 871 if ((ops & PollArrayWrapper.POLLNVAL) != 0) { 872 // This should only happen if this channel is pre-closed while a 873 // selection operation is in progress 874 // ## Throw an error if this channel has not been pre-closed 875 return false; 876 } 877 878 if ((ops & (PollArrayWrapper.POLLERR 879 | PollArrayWrapper.POLLHUP)) != 0) { 880 newOps = intOps; 881 sk.nioReadyOps(newOps); 882 // No need to poll again in checkConnect, 883 // the error will be detected there 884 readyToConnect = true; 885 return (newOps & ~oldOps) != 0; 886 } 887 888 if (((ops & PollArrayWrapper.POLLIN) != 0) && 889 ((intOps & SelectionKey.OP_READ) != 0) && 890 (state == ST_CONNECTED)) 891 newOps |= SelectionKey.OP_READ; 892 893 if (((ops & PollArrayWrapper.POLLCONN) != 0) && 894 ((intOps & SelectionKey.OP_CONNECT) != 0) && 895 ((state == ST_UNCONNECTED) || (state == ST_PENDING))) { 896 newOps |= SelectionKey.OP_CONNECT; 897 readyToConnect = true; 898 } 899 900 if (((ops & PollArrayWrapper.POLLOUT) != 0) && 901 ((intOps & SelectionKey.OP_WRITE) != 0) && 902 (state == ST_CONNECTED)) 903 newOps |= SelectionKey.OP_WRITE; 904 905 sk.nioReadyOps(newOps); 906 return (newOps & ~oldOps) != 0; 907 } 908 909 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) { 910 return translateReadyOps(ops, sk.nioReadyOps(), sk); 911 } 912 913 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) { 914 return translateReadyOps(ops, 0, sk); 915 } 916 917 // package-private 918 int poll(int events, long timeout) throws IOException { 919 assert Thread.holdsLock(blockingLock()) && !isBlocking(); 920 921 synchronized (readLock) { 922 int n = 0; 923 try { 924 begin(); 925 synchronized (stateLock) { 926 if (!isOpen()) 927 return 0; 928 readerThread = NativeThread.current(); 929 } 930 n = Net.poll(fd, events, timeout); 931 } finally { 932 readerCleanup(); 933 end(n > 0); 934 } 935 return n; 936 } 937 } 938 939 /** 940 * Translates an interest operation set into a native poll event set 941 */ 942 public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) { 943 int newOps = 0; 944 if ((ops & SelectionKey.OP_READ) != 0) 945 newOps |= PollArrayWrapper.POLLIN; 946 if ((ops & SelectionKey.OP_WRITE) != 0) 947 newOps |= PollArrayWrapper.POLLOUT; 948 if ((ops & SelectionKey.OP_CONNECT) != 0) 949 newOps |= PollArrayWrapper.POLLCONN; 950 sk.selector.putEventOps(sk, newOps); 951 } 952 953 public FileDescriptor getFD() { 954 return fd; 955 } 956 957 public int getFDVal() { 958 return fdVal; 959 } 960 961 public String toString() { 962 StringBuffer sb = new StringBuffer(); 963 sb.append(this.getClass().getSuperclass().getName()); 964 sb.append('['); 965 if (!isOpen()) 966 sb.append("closed"); 967 else { 968 synchronized (stateLock) { 969 switch (state) { 970 case ST_UNCONNECTED: 971 sb.append("unconnected"); 972 break; 973 case ST_PENDING: 974 sb.append("connection-pending"); 975 break; 976 case ST_CONNECTED: 977 sb.append("connected"); 978 if (!isInputOpen) 979 sb.append(" ishut"); 980 if (!isOutputOpen) 981 sb.append(" oshut"); 982 break; 983 } 984 if (localAddress() != null) { 985 sb.append(" local="); 986 sb.append(localAddress().toString()); 987 } 988 if (remoteAddress() != null) { 989 sb.append(" remote="); 990 sb.append(remoteAddress().toString()); 991 } 992 } 993 } 994 sb.append(']'); 995 return sb.toString(); 996 } 997 998 999 // -- Native methods -- 1000 1001 private static native int checkConnect(FileDescriptor fd, 1002 boolean block, boolean ready) 1003 throws IOException; 1004 1005 private static native int sendOutOfBandData(FileDescriptor fd, byte data) 1006 throws IOException; 1007 1008 static { 1009 Util.load(); 1010 nd = new SocketDispatcher(); 1011 } 1012 1013 }