1 /* 2 * Copyright (c) 2000, 2025, 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.Inet4Address; 32 import java.net.InetSocketAddress; 33 import java.net.ProtocolFamily; 34 import java.net.Socket; 35 import java.net.SocketAddress; 36 import java.net.SocketException; 37 import java.net.SocketOption; 38 import java.net.SocketTimeoutException; 39 import java.net.StandardSocketOptions; 40 import java.nio.ByteBuffer; 41 import java.nio.channels.AlreadyBoundException; 42 import java.nio.channels.AlreadyConnectedException; 43 import java.nio.channels.AsynchronousCloseException; 44 import java.nio.channels.ClosedChannelException; 45 import java.nio.channels.ConnectionPendingException; 46 import java.nio.channels.IllegalBlockingModeException; 47 import java.nio.channels.NoConnectionPendingException; 48 import java.nio.channels.NotYetConnectedException; 49 import java.nio.channels.SelectionKey; 50 import java.nio.channels.SocketChannel; 51 import java.nio.channels.spi.SelectorProvider; 52 import java.nio.file.Path; 53 import java.util.Collections; 54 import java.util.HashSet; 55 import java.util.Set; 56 import java.util.Objects; 57 import java.util.concurrent.locks.ReentrantLock; 58 import static java.net.StandardProtocolFamily.INET; 59 import static java.net.StandardProtocolFamily.INET6; 60 import static java.net.StandardProtocolFamily.UNIX; 61 62 import jdk.internal.event.SocketReadEvent; 63 import jdk.internal.event.SocketWriteEvent; 64 import sun.net.ConnectionResetException; 65 import sun.net.NetHooks; 66 import sun.net.ext.ExtendedSocketOptions; 67 import jdk.internal.util.Exceptions; 68 69 /** 70 * An implementation of SocketChannels 71 */ 72 73 class SocketChannelImpl 74 extends SocketChannel 75 implements SelChImpl 76 { 77 // Used to make native read and write calls 78 private static final NativeDispatcher nd = new SocketDispatcher(); 79 80 // The protocol family of the socket 81 private final ProtocolFamily family; 82 83 // Our file descriptor object 84 private final FileDescriptor fd; 85 private final int fdVal; 86 87 // Lock held by current reading or connecting thread 88 private final ReentrantLock readLock = new ReentrantLock(); 89 90 // Lock held by current writing or connecting thread 91 private final ReentrantLock writeLock = new ReentrantLock(); 92 93 // Lock held by any thread that modifies the state fields declared below 94 // DO NOT invoke a blocking I/O operation while holding this lock! 95 private final Object stateLock = new Object(); 96 97 // Input/Output closed 98 private volatile boolean isInputClosed; 99 private volatile boolean isOutputClosed; 100 101 // Connection reset protected by readLock 102 private boolean connectionReset; 103 104 // -- The following fields are protected by stateLock 105 106 // set true when exclusive binding is on and SO_REUSEADDR is emulated 107 private boolean isReuseAddress; 108 109 // State, increases monotonically 110 private static final int ST_UNCONNECTED = 0; 111 private static final int ST_CONNECTIONPENDING = 1; 112 private static final int ST_CONNECTED = 2; 113 private static final int ST_CLOSING = 3; 114 private static final int ST_CLOSED = 4; 115 private volatile int state; // need stateLock to change 116 117 // IDs of native threads doing reads and writes, for signalling 118 private NativeThread readerThread; 119 private NativeThread writerThread; 120 121 // Binding 122 private SocketAddress localAddress; 123 private SocketAddress remoteAddress; 124 125 // Socket adaptor, created on demand 126 private Socket socket; 127 128 // True if the channel's socket has been forced into non-blocking mode 129 // by a virtual thread. It cannot be reset. When the channel is in 130 // blocking mode and the channel's socket is in non-blocking mode then 131 // operations that don't complete immediately will poll the socket and 132 // preserve the semantics of blocking operations. 133 private volatile boolean forcedNonBlocking; 134 135 // -- End of fields protected by stateLock 136 137 SocketChannelImpl(SelectorProvider sp) throws IOException { 138 this(sp, Net.isIPv6Available() ? INET6 : INET); 139 } 140 141 SocketChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException { 142 super(sp); 143 Objects.requireNonNull(family, "'family' is null"); 144 if ((family != INET) && (family != INET6) && (family != UNIX)) { 145 throw new UnsupportedOperationException("Protocol family not supported"); 146 } 147 if (family == INET6 && !Net.isIPv6Available()) { 148 throw new UnsupportedOperationException("IPv6 not available"); 149 } 150 151 this.family = family; 152 if (family == UNIX) { 153 this.fd = UnixDomainSockets.socket(); 154 } else { 155 this.fd = Net.socket(family, true); 156 } 157 this.fdVal = IOUtil.fdVal(fd); 158 } 159 160 // Constructor for sockets obtained from server sockets 161 // 162 SocketChannelImpl(SelectorProvider sp, 163 ProtocolFamily family, 164 FileDescriptor fd, 165 SocketAddress remoteAddress) 166 throws IOException 167 { 168 super(sp); 169 this.family = family; 170 this.fd = fd; 171 this.fdVal = IOUtil.fdVal(fd); 172 synchronized (stateLock) { 173 if (family == UNIX) { 174 this.localAddress = UnixDomainSockets.localAddress(fd); 175 } else { 176 this.localAddress = Net.localAddress(fd); 177 } 178 this.remoteAddress = remoteAddress; 179 this.state = ST_CONNECTED; 180 } 181 } 182 183 /** 184 * Returns true if this channel is to a INET or INET6 socket. 185 */ 186 boolean isNetSocket() { 187 return (family == INET) || (family == INET6); 188 } 189 190 /** 191 * Returns true if this channel is to a UNIX socket. 192 */ 193 boolean isUnixSocket() { 194 return (family == UNIX); 195 } 196 197 /** 198 * Checks that the channel is open. 199 * 200 * @throws ClosedChannelException if channel is closed (or closing) 201 */ 202 private void ensureOpen() throws ClosedChannelException { 203 if (!isOpen()) 204 throw new ClosedChannelException(); 205 } 206 207 /** 208 * Checks that the channel is open and connected. 209 * 210 * @apiNote This method uses the "state" field to check if the channel is 211 * open. It should never be used in conjunction with isOpen or ensureOpen 212 * as these methods check AbstractInterruptibleChannel's closed field - that 213 * field is set before implCloseSelectableChannel is called and so before 214 * the state is changed. 215 * 216 * @throws ClosedChannelException if channel is closed (or closing) 217 * @throws NotYetConnectedException if open and not connected 218 */ 219 private void ensureOpenAndConnected() throws ClosedChannelException { 220 int state = this.state; 221 if (state < ST_CONNECTED) { 222 throw new NotYetConnectedException(); 223 } else if (state > ST_CONNECTED) { 224 throw new ClosedChannelException(); 225 } 226 } 227 228 @Override 229 public Socket socket() { 230 synchronized (stateLock) { 231 if (socket == null) { 232 if (isNetSocket()) { 233 socket = SocketAdaptor.create(this); 234 } else { 235 throw new UnsupportedOperationException("Not supported"); 236 } 237 } 238 return socket; 239 } 240 } 241 242 @Override 243 public SocketAddress getLocalAddress() throws IOException { 244 synchronized (stateLock) { 245 ensureOpen(); 246 return localAddress; 247 } 248 } 249 250 @Override 251 public SocketAddress getRemoteAddress() throws IOException { 252 synchronized (stateLock) { 253 ensureOpen(); 254 return remoteAddress; 255 } 256 } 257 258 @Override 259 public <T> SocketChannel setOption(SocketOption<T> name, T value) 260 throws IOException 261 { 262 Objects.requireNonNull(name); 263 if (!supportedOptions().contains(name)) 264 throw new UnsupportedOperationException("'" + name + "' not supported"); 265 if (!name.type().isInstance(value)) 266 throw new IllegalArgumentException("Invalid value '" + value + "'"); 267 268 synchronized (stateLock) { 269 ensureOpen(); 270 271 if (isNetSocket()) { 272 if (name == StandardSocketOptions.IP_TOS) { 273 // maps to IPV6_TCLASS and/or IP_TOS 274 Net.setIpSocketOption(fd, family, name, value); 275 return this; 276 } 277 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { 278 // SO_REUSEADDR emulated when using exclusive bind 279 isReuseAddress = (Boolean) value; 280 return this; 281 } 282 } 283 284 // no options that require special handling 285 Net.setSocketOption(fd, name, value); 286 return this; 287 } 288 } 289 290 @Override 291 @SuppressWarnings("unchecked") 292 public <T> T getOption(SocketOption<T> name) 293 throws IOException 294 { 295 Objects.requireNonNull(name); 296 if (!supportedOptions().contains(name)) 297 throw new UnsupportedOperationException("'" + name + "' not supported"); 298 299 synchronized (stateLock) { 300 ensureOpen(); 301 302 if (isNetSocket()) { 303 if (name == StandardSocketOptions.IP_TOS) { 304 // special handling for IP_TOS 305 return (T) Net.getSocketOption(fd, family, name); 306 } 307 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { 308 // SO_REUSEADDR emulated when using exclusive bind 309 return (T) Boolean.valueOf(isReuseAddress); 310 } 311 } 312 313 // no options that require special handling 314 return (T) Net.getSocketOption(fd, name); 315 } 316 } 317 318 private static class DefaultOptionsHolder { 319 static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions(); 320 static final Set<SocketOption<?>> defaultUnixOptions = defaultUnixOptions(); 321 322 private static Set<SocketOption<?>> defaultInetOptions() { 323 HashSet<SocketOption<?>> set = new HashSet<>(); 324 set.add(StandardSocketOptions.SO_SNDBUF); 325 set.add(StandardSocketOptions.SO_RCVBUF); 326 set.add(StandardSocketOptions.SO_KEEPALIVE); 327 set.add(StandardSocketOptions.SO_REUSEADDR); 328 if (Net.isReusePortAvailable()) { 329 set.add(StandardSocketOptions.SO_REUSEPORT); 330 } 331 set.add(StandardSocketOptions.SO_LINGER); 332 set.add(StandardSocketOptions.TCP_NODELAY); 333 // additional options required by socket adaptor 334 set.add(StandardSocketOptions.IP_TOS); 335 set.add(ExtendedSocketOption.SO_OOBINLINE); 336 set.addAll(ExtendedSocketOptions.clientSocketOptions()); 337 return Collections.unmodifiableSet(set); 338 } 339 340 private static Set<SocketOption<?>> defaultUnixOptions() { 341 HashSet<SocketOption<?>> set = new HashSet<>(); 342 set.add(StandardSocketOptions.SO_SNDBUF); 343 set.add(StandardSocketOptions.SO_RCVBUF); 344 set.add(StandardSocketOptions.SO_LINGER); 345 set.addAll(ExtendedSocketOptions.unixDomainSocketOptions()); 346 return Collections.unmodifiableSet(set); 347 } 348 } 349 350 @Override 351 public final Set<SocketOption<?>> supportedOptions() { 352 if (isUnixSocket()) { 353 return DefaultOptionsHolder.defaultUnixOptions; 354 } else { 355 return DefaultOptionsHolder.defaultInetOptions; 356 } 357 } 358 359 /** 360 * Marks the beginning of a read operation that might block. 361 * 362 * @throws ClosedChannelException if blocking and the channel is closed 363 */ 364 private void beginRead(boolean blocking) throws ClosedChannelException { 365 if (blocking) { 366 // set hook for Thread.interrupt 367 begin(); 368 369 synchronized (stateLock) { 370 ensureOpen(); 371 // record thread so it can be signalled if needed 372 readerThread = NativeThread.current(); 373 } 374 } 375 } 376 377 /** 378 * Marks the end of a read operation that may have blocked. 379 * 380 * @throws AsynchronousCloseException if the channel was closed due to this 381 * thread being interrupted on a blocking read operation. 382 */ 383 private void endRead(boolean blocking, boolean completed) 384 throws AsynchronousCloseException 385 { 386 if (blocking) { 387 synchronized (stateLock) { 388 readerThread = null; 389 if (state == ST_CLOSING) { 390 tryFinishClose(); 391 } 392 } 393 // remove hook for Thread.interrupt 394 end(completed); 395 } 396 } 397 398 private void throwConnectionReset() throws SocketException { 399 throw new SocketException("Connection reset"); 400 } 401 402 private int implRead(ByteBuffer buf) throws IOException { 403 Objects.requireNonNull(buf); 404 405 readLock.lock(); 406 try { 407 ensureOpenAndConnected(); 408 boolean blocking = isBlocking(); 409 int n = 0; 410 try { 411 beginRead(blocking); 412 413 // check if connection has been reset 414 if (connectionReset) 415 throwConnectionReset(); 416 417 // check if input is shutdown 418 if (isInputClosed) 419 return IOStatus.EOF; 420 421 configureSocketNonBlockingIfVirtualThread(); 422 n = IOUtil.read(fd, buf, -1, nd); 423 if (blocking) { 424 while (IOStatus.okayToRetry(n) && isOpen()) { 425 park(Net.POLLIN); 426 n = IOUtil.read(fd, buf, -1, nd); 427 } 428 } 429 } catch (ConnectionResetException e) { 430 connectionReset = true; 431 throwConnectionReset(); 432 } finally { 433 endRead(blocking, n > 0); 434 if (n <= 0 && isInputClosed) 435 return IOStatus.EOF; 436 } 437 return IOStatus.normalize(n); 438 } finally { 439 readLock.unlock(); 440 } 441 } 442 443 private long implRead(ByteBuffer[] dsts, int offset, int length) 444 throws IOException 445 { 446 Objects.checkFromIndexSize(offset, length, dsts.length); 447 448 readLock.lock(); 449 try { 450 ensureOpenAndConnected(); 451 boolean blocking = isBlocking(); 452 long n = 0; 453 try { 454 beginRead(blocking); 455 456 // check if connection has been reset 457 if (connectionReset) 458 throwConnectionReset(); 459 460 // check if input is shutdown 461 if (isInputClosed) 462 return IOStatus.EOF; 463 464 configureSocketNonBlockingIfVirtualThread(); 465 n = IOUtil.read(fd, dsts, offset, length, nd); 466 if (blocking) { 467 while (IOStatus.okayToRetry(n) && isOpen()) { 468 park(Net.POLLIN); 469 n = IOUtil.read(fd, dsts, offset, length, nd); 470 } 471 } 472 } catch (ConnectionResetException e) { 473 connectionReset = true; 474 throwConnectionReset(); 475 } finally { 476 endRead(blocking, n > 0); 477 if (n <= 0 && isInputClosed) 478 return IOStatus.EOF; 479 } 480 return IOStatus.normalize(n); 481 } finally { 482 readLock.unlock(); 483 } 484 } 485 486 @Override 487 public int read(ByteBuffer buf) throws IOException { 488 if (!SocketReadEvent.enabled()) { 489 return implRead(buf); 490 } 491 long start = SocketReadEvent.timestamp(); 492 int nbytes = implRead(buf); 493 SocketReadEvent.offer(start, nbytes, remoteAddress(), 0); 494 return nbytes; 495 } 496 497 498 @Override 499 public long read(ByteBuffer[] dsts, int offset, int length) 500 throws IOException 501 { 502 if (!SocketReadEvent.enabled()) { 503 return implRead(dsts, offset, length); 504 } 505 long start = SocketReadEvent.timestamp(); 506 long nbytes = implRead(dsts, offset, length); 507 SocketReadEvent.offer(start, nbytes, remoteAddress(), 0); 508 return nbytes; 509 } 510 511 /** 512 * Marks the beginning of a write operation that might block. 513 * 514 * @throws ClosedChannelException if blocking and the channel is closed 515 */ 516 private void beginWrite(boolean blocking) throws ClosedChannelException { 517 if (blocking) { 518 // set hook for Thread.interrupt 519 begin(); 520 521 synchronized (stateLock) { 522 ensureOpen(); 523 if (isOutputClosed) 524 throw new ClosedChannelException(); 525 // record thread so it can be signalled if needed 526 writerThread = NativeThread.current(); 527 } 528 } 529 } 530 531 /** 532 * Marks the end of a write operation that may have blocked. 533 * 534 * @throws AsynchronousCloseException if the channel was closed due to this 535 * thread being interrupted on a blocking write operation. 536 */ 537 private void endWrite(boolean blocking, boolean completed) 538 throws AsynchronousCloseException 539 { 540 if (blocking) { 541 synchronized (stateLock) { 542 writerThread = null; 543 if (state == ST_CLOSING) { 544 tryFinishClose(); 545 } 546 } 547 // remove hook for Thread.interrupt 548 end(completed); 549 } 550 } 551 552 private int implWrite(ByteBuffer buf) throws IOException { 553 Objects.requireNonNull(buf); 554 writeLock.lock(); 555 try { 556 ensureOpenAndConnected(); 557 boolean blocking = isBlocking(); 558 int n = 0; 559 try { 560 beginWrite(blocking); 561 configureSocketNonBlockingIfVirtualThread(); 562 n = IOUtil.write(fd, buf, -1, nd); 563 if (blocking) { 564 while (IOStatus.okayToRetry(n) && isOpen()) { 565 park(Net.POLLOUT); 566 n = IOUtil.write(fd, buf, -1, nd); 567 } 568 } 569 } finally { 570 endWrite(blocking, n > 0); 571 if (n <= 0 && isOutputClosed) 572 throw new AsynchronousCloseException(); 573 } 574 return IOStatus.normalize(n); 575 } finally { 576 writeLock.unlock(); 577 } 578 } 579 580 private long implWrite(ByteBuffer[] srcs, int offset, int length) 581 throws IOException 582 { 583 Objects.checkFromIndexSize(offset, length, srcs.length); 584 585 writeLock.lock(); 586 try { 587 ensureOpenAndConnected(); 588 boolean blocking = isBlocking(); 589 long n = 0; 590 try { 591 beginWrite(blocking); 592 configureSocketNonBlockingIfVirtualThread(); 593 n = IOUtil.write(fd, srcs, offset, length, nd); 594 if (blocking) { 595 while (IOStatus.okayToRetry(n) && isOpen()) { 596 park(Net.POLLOUT); 597 n = IOUtil.write(fd, srcs, offset, length, nd); 598 } 599 } 600 } finally { 601 endWrite(blocking, n > 0); 602 if (n <= 0 && isOutputClosed) 603 throw new AsynchronousCloseException(); 604 } 605 return IOStatus.normalize(n); 606 } finally { 607 writeLock.unlock(); 608 } 609 } 610 611 @Override 612 public int write(ByteBuffer buf) throws IOException { 613 if (!SocketWriteEvent.enabled()) { 614 return implWrite(buf); 615 } 616 long start = SocketWriteEvent.timestamp(); 617 int nbytes = implWrite(buf); 618 SocketWriteEvent.offer(start, nbytes, remoteAddress()); 619 return nbytes; 620 } 621 622 @Override 623 public long write(ByteBuffer[] srcs, int offset, int length) 624 throws IOException 625 { 626 if (!SocketWriteEvent.enabled()) { 627 return implWrite(srcs, offset, length); 628 } 629 long start = SocketWriteEvent.timestamp(); 630 long nbytes = implWrite(srcs, offset, length); 631 SocketWriteEvent.offer(start, nbytes, remoteAddress()); 632 return nbytes; 633 } 634 635 /** 636 * Writes a byte of out of band data. 637 */ 638 int sendOutOfBandData(byte b) throws IOException { 639 writeLock.lock(); 640 try { 641 ensureOpenAndConnected(); 642 boolean blocking = isBlocking(); 643 int n = 0; 644 try { 645 beginWrite(blocking); 646 configureSocketNonBlockingIfVirtualThread(); 647 do { 648 n = Net.sendOOB(fd, b); 649 } while (n == IOStatus.INTERRUPTED && isOpen()); 650 if (blocking && n == IOStatus.UNAVAILABLE) { 651 throw new SocketException("No buffer space available"); 652 } 653 } finally { 654 endWrite(blocking, n > 0); 655 if (n <= 0 && isOutputClosed) 656 throw new AsynchronousCloseException(); 657 } 658 return IOStatus.normalize(n); 659 } finally { 660 writeLock.unlock(); 661 } 662 } 663 664 /** 665 * Marks the beginning of a transfer to this channel. 666 * @throws ClosedChannelException if channel is closed or the output is shutdown 667 * @throws NotYetConnectedException if open and not connected 668 */ 669 void beforeTransferTo() throws ClosedChannelException { 670 boolean completed = false; 671 writeLock.lock(); 672 try { 673 synchronized (stateLock) { 674 ensureOpenAndConnected(); 675 if (isOutputClosed) 676 throw new ClosedChannelException(); 677 writerThread = NativeThread.current(); 678 completed = true; 679 } 680 } finally { 681 if (!completed) { 682 writeLock.unlock(); 683 } 684 } 685 } 686 687 /** 688 * Marks the end of a transfer to this channel. 689 * @throws AsynchronousCloseException if not completed and the channel is closed 690 */ 691 void afterTransferTo(boolean completed) throws AsynchronousCloseException { 692 synchronized (stateLock) { 693 writerThread = null; 694 if (state == ST_CLOSING) { 695 tryFinishClose(); 696 } 697 } 698 writeLock.unlock(); 699 if (!completed && !isOpen()) { 700 throw new AsynchronousCloseException(); 701 } 702 } 703 704 @Override 705 protected void implConfigureBlocking(boolean block) throws IOException { 706 readLock.lock(); 707 try { 708 writeLock.lock(); 709 try { 710 lockedConfigureBlocking(block); 711 } finally { 712 writeLock.unlock(); 713 } 714 } finally { 715 readLock.unlock(); 716 } 717 } 718 719 /** 720 * Adjust the blocking mode while holding readLock or writeLock. 721 */ 722 private void lockedConfigureBlocking(boolean block) throws IOException { 723 assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread(); 724 synchronized (stateLock) { 725 ensureOpen(); 726 // do nothing if virtual thread has forced the socket to be non-blocking 727 if (!forcedNonBlocking) { 728 IOUtil.configureBlocking(fd, block); 729 } 730 } 731 } 732 733 /** 734 * Attempts to adjust the blocking mode if the channel is open. 735 * @return {@code true} if the blocking mode was adjusted 736 */ 737 private boolean tryLockedConfigureBlocking(boolean block) throws IOException { 738 assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread(); 739 synchronized (stateLock) { 740 // do nothing if virtual thread has forced the socket to be non-blocking 741 if (!forcedNonBlocking && isOpen()) { 742 IOUtil.configureBlocking(fd, block); 743 return true; 744 } else { 745 return false; 746 } 747 } 748 } 749 750 /** 751 * Ensures that the socket is configured non-blocking when on a virtual thread. 752 */ 753 private void configureSocketNonBlockingIfVirtualThread() throws IOException { 754 assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread(); 755 if (!forcedNonBlocking && Thread.currentThread().isVirtual()) { 756 synchronized (stateLock) { 757 ensureOpen(); 758 IOUtil.configureBlocking(fd, false); 759 forcedNonBlocking = true; 760 } 761 } 762 } 763 764 /** 765 * Returns the local address, or null if not bound 766 */ 767 SocketAddress localAddress() { 768 synchronized (stateLock) { 769 return localAddress; 770 } 771 } 772 773 /** 774 * Returns the remote address, or null if not connected 775 */ 776 SocketAddress remoteAddress() { 777 synchronized (stateLock) { 778 return remoteAddress; 779 } 780 } 781 782 @Override 783 public SocketChannel bind(SocketAddress local) throws IOException { 784 readLock.lock(); 785 try { 786 writeLock.lock(); 787 try { 788 synchronized (stateLock) { 789 ensureOpen(); 790 if (state == ST_CONNECTIONPENDING) 791 throw new ConnectionPendingException(); 792 if (localAddress != null) 793 throw new AlreadyBoundException(); 794 if (isUnixSocket()) { 795 localAddress = unixBind(local); 796 } else { 797 localAddress = netBind(local); 798 } 799 } 800 } finally { 801 writeLock.unlock(); 802 } 803 } finally { 804 readLock.unlock(); 805 } 806 return this; 807 } 808 809 private SocketAddress unixBind(SocketAddress local) throws IOException { 810 if (local == null) { 811 return UnixDomainSockets.unnamed(); 812 } else { 813 Path path = UnixDomainSockets.checkAddress(local).getPath(); 814 if (path.toString().isEmpty()) { 815 return UnixDomainSockets.unnamed(); 816 } else { 817 // bind to non-empty path 818 UnixDomainSockets.bind(fd, path); 819 return UnixDomainSockets.localAddress(fd); 820 } 821 } 822 } 823 824 private SocketAddress netBind(SocketAddress local) throws IOException { 825 InetSocketAddress isa; 826 if (local == null) { 827 isa = new InetSocketAddress(Net.anyLocalAddress(family), 0); 828 } else { 829 isa = Net.checkAddress(local, family); 830 } 831 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); 832 Net.bind(family, fd, isa.getAddress(), isa.getPort()); 833 return Net.localAddress(fd); 834 } 835 836 @Override 837 public boolean isConnected() { 838 return (state == ST_CONNECTED); 839 } 840 841 @Override 842 public boolean isConnectionPending() { 843 return (state == ST_CONNECTIONPENDING); 844 } 845 846 /** 847 * Marks the beginning of a connect operation that might block. 848 * @param blocking true if configured blocking 849 * @param sa the remote socket address 850 * @throws ClosedChannelException if the channel is closed 851 * @throws AlreadyConnectedException if already connected 852 * @throws ConnectionPendingException is a connection is pending 853 * @throws IOException if the pre-connect hook fails 854 */ 855 private void beginConnect(boolean blocking, SocketAddress sa) 856 throws IOException 857 { 858 if (blocking) { 859 // set hook for Thread.interrupt 860 begin(); 861 } 862 synchronized (stateLock) { 863 ensureOpen(); 864 int state = this.state; 865 if (state == ST_CONNECTED) 866 throw new AlreadyConnectedException(); 867 if (state == ST_CONNECTIONPENDING) 868 throw new ConnectionPendingException(); 869 assert state == ST_UNCONNECTED; 870 this.state = ST_CONNECTIONPENDING; 871 872 if (isNetSocket() && (localAddress == null)) { 873 InetSocketAddress isa = (InetSocketAddress) sa; 874 NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort()); 875 } 876 remoteAddress = sa; 877 878 if (blocking) { 879 // record thread so it can be signalled if needed 880 readerThread = NativeThread.current(); 881 } 882 } 883 } 884 885 /** 886 * Marks the end of a connect operation that may have blocked. 887 * 888 * @throws AsynchronousCloseException if the channel was closed due to this 889 * thread being interrupted on a blocking connect operation. 890 * @throws IOException if completed and unable to obtain the local address 891 */ 892 private void endConnect(boolean blocking, boolean completed) 893 throws IOException 894 { 895 endRead(blocking, completed); 896 897 if (completed) { 898 synchronized (stateLock) { 899 if (state == ST_CONNECTIONPENDING) { 900 if (isUnixSocket()) { 901 localAddress = UnixDomainSockets.localAddress(fd); 902 } else { 903 localAddress = Net.localAddress(fd); 904 } 905 state = ST_CONNECTED; 906 } 907 } 908 } 909 } 910 911 /** 912 * Checks the remote address to which this channel is to be connected. 913 */ 914 private SocketAddress checkRemote(SocketAddress sa) { 915 if (isUnixSocket()) { 916 return UnixDomainSockets.checkAddress(sa); 917 } else { 918 InetSocketAddress isa = Net.checkAddress(sa, family); 919 InetAddress address = isa.getAddress(); 920 if (address.isAnyLocalAddress()) { 921 int port = isa.getPort(); 922 if (address instanceof Inet4Address) { 923 return new InetSocketAddress(Net.inet4LoopbackAddress(), port); 924 } else { 925 assert family == INET6; 926 return new InetSocketAddress(Net.inet6LoopbackAddress(), port); 927 } 928 } else { 929 return isa; 930 } 931 } 932 } 933 934 @Override 935 public boolean connect(SocketAddress remote) throws IOException { 936 SocketAddress sa = checkRemote(remote); 937 try { 938 readLock.lock(); 939 try { 940 writeLock.lock(); 941 try { 942 ensureOpen(); 943 boolean blocking = isBlocking(); 944 boolean connected = false; 945 try { 946 beginConnect(blocking, sa); 947 configureSocketNonBlockingIfVirtualThread(); 948 int n; 949 if (isUnixSocket()) { 950 n = UnixDomainSockets.connect(fd, sa); 951 } else { 952 n = Net.connect(family, fd, sa); 953 } 954 if (n > 0) { 955 connected = true; 956 } else if (blocking) { 957 assert IOStatus.okayToRetry(n); 958 boolean polled = false; 959 while (!polled && isOpen()) { 960 park(Net.POLLOUT); 961 polled = Net.pollConnectNow(fd); 962 } 963 connected = polled && isOpen(); 964 } 965 } finally { 966 endConnect(blocking, connected); 967 } 968 return connected; 969 } finally { 970 writeLock.unlock(); 971 } 972 } finally { 973 readLock.unlock(); 974 } 975 } catch (IOException ioe) { 976 // connect failed, close the channel 977 close(); 978 throw Exceptions.ioException(ioe, sa); 979 } 980 } 981 982 /** 983 * Marks the beginning of a finishConnect operation that might block. 984 * 985 * @throws ClosedChannelException if the channel is closed 986 * @throws NoConnectionPendingException if no connection is pending 987 */ 988 private void beginFinishConnect(boolean blocking) throws ClosedChannelException { 989 if (blocking) { 990 // set hook for Thread.interrupt 991 begin(); 992 } 993 synchronized (stateLock) { 994 ensureOpen(); 995 if (state != ST_CONNECTIONPENDING) 996 throw new NoConnectionPendingException(); 997 if (blocking) { 998 // record thread so it can be signalled if needed 999 readerThread = NativeThread.current(); 1000 } 1001 } 1002 } 1003 1004 /** 1005 * Marks the end of a finishConnect operation that may have blocked. 1006 * 1007 * @throws AsynchronousCloseException if the channel was closed due to this 1008 * thread being interrupted on a blocking connect operation. 1009 * @throws IOException if completed and unable to obtain the local address 1010 */ 1011 private void endFinishConnect(boolean blocking, boolean completed) 1012 throws IOException 1013 { 1014 endRead(blocking, completed); 1015 1016 if (completed) { 1017 synchronized (stateLock) { 1018 if (state == ST_CONNECTIONPENDING) { 1019 if (isUnixSocket()) { 1020 localAddress = UnixDomainSockets.localAddress(fd); 1021 } else { 1022 localAddress = Net.localAddress(fd); 1023 } 1024 state = ST_CONNECTED; 1025 } 1026 } 1027 } 1028 } 1029 1030 @Override 1031 public boolean finishConnect() throws IOException { 1032 try { 1033 readLock.lock(); 1034 try { 1035 writeLock.lock(); 1036 try { 1037 // no-op if already connected 1038 if (isConnected()) 1039 return true; 1040 1041 ensureOpen(); 1042 boolean blocking = isBlocking(); 1043 boolean connected = false; 1044 try { 1045 beginFinishConnect(blocking); 1046 boolean polled = Net.pollConnectNow(fd); 1047 if (blocking) { 1048 while (!polled && isOpen()) { 1049 park(Net.POLLOUT); 1050 polled = Net.pollConnectNow(fd); 1051 } 1052 } 1053 connected = polled && isOpen(); 1054 } finally { 1055 endFinishConnect(blocking, connected); 1056 } 1057 assert (blocking && connected) ^ !blocking; 1058 return connected; 1059 } finally { 1060 writeLock.unlock(); 1061 } 1062 } finally { 1063 readLock.unlock(); 1064 } 1065 } catch (IOException ioe) { 1066 // connect failed, close the channel 1067 close(); 1068 throw Exceptions.ioException(ioe, remoteAddress); 1069 } 1070 } 1071 1072 /** 1073 * Closes the socket if there are no I/O operations in progress (or no I/O 1074 * operations tracked), and the channel is not registered with a Selector. 1075 */ 1076 private boolean tryClose() throws IOException { 1077 assert Thread.holdsLock(stateLock) && state == ST_CLOSING; 1078 if ((readerThread == null) && (writerThread == null) && !isRegistered()) { 1079 state = ST_CLOSED; 1080 nd.close(fd); 1081 return true; 1082 } else { 1083 return false; 1084 } 1085 } 1086 1087 /** 1088 * Invokes tryClose to attempt to close the socket. 1089 * 1090 * This method is used for deferred closing by I/O and Selector operations. 1091 */ 1092 private void tryFinishClose() { 1093 try { 1094 tryClose(); 1095 } catch (IOException ignore) { } 1096 } 1097 1098 /** 1099 * Closes this channel when configured in blocking mode. If there are no I/O 1100 * operations in progress (or tracked), then the channel's socket is closed. If 1101 * there are I/O operations in progress then the behavior is platform specific. 1102 * 1103 * On Unix systems, the channel's socket is pre-closed. This unparks any virtual 1104 * threads that are blocked in I/O operations on this channel. If there are 1105 * platform threads blocked on the channel's socket then the socket is dup'ed 1106 * and the platform threads signalled. The final close is deferred until all I/O 1107 * operations complete. 1108 * 1109 * On Windows, the channel's socket is pre-closed. This unparks any virtual 1110 * threads that are blocked in I/O operations on this channel. If there are no 1111 * virtual threads blocked in I/O operations on this channel then the channel's 1112 * socket is closed. If there are virtual threads in I/O then the final close is 1113 * deferred until all I/O operations on virtual threads complete. 1114 * 1115 * Note that a channel configured blocking may be registered with a Selector 1116 * This arises when a key is canceled and the channel configured to blocking 1117 * mode before the key is flushed from the Selector. 1118 */ 1119 private void implCloseBlockingMode() throws IOException { 1120 synchronized (stateLock) { 1121 assert state < ST_CLOSING; 1122 boolean connected = (state == ST_CONNECTED); 1123 state = ST_CLOSING; 1124 1125 if (connected && Net.shouldShutdownWriteBeforeClose()) { 1126 // shutdown output when linger interval not set to 0 1127 try { 1128 var SO_LINGER = StandardSocketOptions.SO_LINGER; 1129 if ((int) Net.getSocketOption(fd, SO_LINGER) != 0) { 1130 Net.shutdown(fd, Net.SHUT_WR); 1131 } 1132 } catch (IOException ignore) { } 1133 } 1134 1135 if (!tryClose()) { 1136 // prepare file descriptor for closing 1137 nd.preClose(fd, readerThread, writerThread); 1138 } 1139 } 1140 } 1141 1142 /** 1143 * Closes this channel when configured in non-blocking mode. 1144 * 1145 * If the channel is registered with a Selector then the close is deferred 1146 * until the channel is flushed from all Selectors. 1147 * 1148 * If the socket is connected and the channel is registered with a Selector 1149 * then the socket is shutdown for writing so that the peer reads EOF. In 1150 * addition, if SO_LINGER is set to a non-zero value then it is disabled so 1151 * that the deferred close does not wait. 1152 */ 1153 private void implCloseNonBlockingMode() throws IOException { 1154 boolean connected; 1155 synchronized (stateLock) { 1156 assert state < ST_CLOSING; 1157 connected = (state == ST_CONNECTED); 1158 state = ST_CLOSING; 1159 } 1160 1161 // wait for any read/write operations to complete 1162 readLock.lock(); 1163 readLock.unlock(); 1164 writeLock.lock(); 1165 writeLock.unlock(); 1166 1167 // if the socket cannot be closed because it's registered with a Selector 1168 // then shutdown the socket for writing. 1169 synchronized (stateLock) { 1170 if (state == ST_CLOSING && !tryClose() && connected && isRegistered()) { 1171 try { 1172 SocketOption<Integer> opt = StandardSocketOptions.SO_LINGER; 1173 int interval = (int) Net.getSocketOption(fd, Net.UNSPEC, opt); 1174 if (interval != 0) { 1175 if (interval > 0) { 1176 // disable SO_LINGER 1177 Net.setSocketOption(fd, Net.UNSPEC, opt, -1); 1178 } 1179 Net.shutdown(fd, Net.SHUT_WR); 1180 } 1181 } catch (IOException ignore) { } 1182 } 1183 } 1184 } 1185 1186 /** 1187 * Invoked by implCloseChannel to close the channel. 1188 */ 1189 @Override 1190 protected void implCloseSelectableChannel() throws IOException { 1191 assert !isOpen(); 1192 if (isBlocking()) { 1193 implCloseBlockingMode(); 1194 } else { 1195 implCloseNonBlockingMode(); 1196 } 1197 } 1198 1199 @Override 1200 public void kill() { 1201 // wait for any read/write operations to complete before trying to close 1202 readLock.lock(); 1203 readLock.unlock(); 1204 writeLock.lock(); 1205 writeLock.unlock(); 1206 synchronized (stateLock) { 1207 if (state == ST_CLOSING) { 1208 tryFinishClose(); 1209 } 1210 } 1211 } 1212 1213 @Override 1214 public SocketChannel shutdownInput() throws IOException { 1215 synchronized (stateLock) { 1216 ensureOpen(); 1217 if (!isConnected()) 1218 throw new NotYetConnectedException(); 1219 if (!isInputClosed) { 1220 Net.shutdown(fd, Net.SHUT_RD); 1221 if (NativeThread.isVirtualThread(readerThread)) { 1222 Poller.stopPoll(readerThread.thread()); 1223 } 1224 isInputClosed = true; 1225 } 1226 return this; 1227 } 1228 } 1229 1230 @Override 1231 public SocketChannel shutdownOutput() throws IOException { 1232 synchronized (stateLock) { 1233 ensureOpen(); 1234 if (!isConnected()) 1235 throw new NotYetConnectedException(); 1236 if (!isOutputClosed) { 1237 Net.shutdown(fd, Net.SHUT_WR); 1238 if (NativeThread.isVirtualThread(writerThread)) { 1239 Poller.stopPoll(writerThread.thread()); 1240 } 1241 isOutputClosed = true; 1242 } 1243 return this; 1244 } 1245 } 1246 1247 boolean isInputOpen() { 1248 return !isInputClosed; 1249 } 1250 1251 boolean isOutputOpen() { 1252 return !isOutputClosed; 1253 } 1254 1255 /** 1256 * Waits for a connection attempt to finish with a timeout 1257 * @throws SocketTimeoutException if the connect timeout elapses 1258 */ 1259 private boolean finishTimedConnect(long nanos) throws IOException { 1260 long startNanos = System.nanoTime(); 1261 boolean polled = Net.pollConnectNow(fd); 1262 while (!polled && isOpen()) { 1263 long remainingNanos = nanos - (System.nanoTime() - startNanos); 1264 if (remainingNanos <= 0) { 1265 throw new SocketTimeoutException("Connect timed out"); 1266 } 1267 park(Net.POLLOUT, remainingNanos); 1268 polled = Net.pollConnectNow(fd); 1269 } 1270 return polled && isOpen(); 1271 } 1272 1273 /** 1274 * Attempts to establish a connection to the given socket address with a 1275 * timeout. Closes the socket if connection cannot be established. 1276 * 1277 * @apiNote This method is for use by the socket adaptor. 1278 * 1279 * @throws IllegalBlockingModeException if the channel is non-blocking 1280 * @throws SocketTimeoutException if the read timeout elapses 1281 */ 1282 void blockingConnect(SocketAddress remote, long nanos) throws IOException { 1283 SocketAddress sa = checkRemote(remote); 1284 try { 1285 readLock.lock(); 1286 try { 1287 writeLock.lock(); 1288 try { 1289 if (!isBlocking()) 1290 throw new IllegalBlockingModeException(); 1291 boolean connected = false; 1292 try { 1293 beginConnect(true, sa); 1294 // change socket to non-blocking 1295 lockedConfigureBlocking(false); 1296 try { 1297 int n; 1298 if (isUnixSocket()) { 1299 n = UnixDomainSockets.connect(fd, sa); 1300 } else { 1301 n = Net.connect(family, fd, sa); 1302 } 1303 connected = (n > 0) ? true : finishTimedConnect(nanos); 1304 } finally { 1305 // restore socket to blocking mode (if channel is open) 1306 tryLockedConfigureBlocking(true); 1307 } 1308 } finally { 1309 endConnect(true, connected); 1310 } 1311 } finally { 1312 writeLock.unlock(); 1313 } 1314 } finally { 1315 readLock.unlock(); 1316 } 1317 } catch (IOException ioe) { 1318 // connect failed, close the channel 1319 close(); 1320 throw Exceptions.ioException(ioe, sa); 1321 } 1322 } 1323 1324 /** 1325 * Attempts to read bytes from the socket into the given byte array. 1326 */ 1327 private int tryRead(byte[] b, int off, int len) throws IOException { 1328 ByteBuffer dst = Util.getTemporaryDirectBuffer(len); 1329 assert dst.position() == 0; 1330 try { 1331 int n = nd.read(fd, ((DirectBuffer)dst).address(), len); 1332 if (n > 0) { 1333 dst.get(b, off, n); 1334 } 1335 return n; 1336 } finally{ 1337 Util.offerFirstTemporaryDirectBuffer(dst); 1338 } 1339 } 1340 1341 /** 1342 * Reads bytes from the socket into the given byte array with a timeout. 1343 * @throws SocketTimeoutException if the read timeout elapses 1344 */ 1345 private int timedRead(byte[] b, int off, int len, long nanos) throws IOException { 1346 long startNanos = System.nanoTime(); 1347 int n = tryRead(b, off, len); 1348 while (n == IOStatus.UNAVAILABLE && isOpen()) { 1349 long remainingNanos = nanos - (System.nanoTime() - startNanos); 1350 if (remainingNanos <= 0) { 1351 throw new SocketTimeoutException("Read timed out"); 1352 } 1353 park(Net.POLLIN, remainingNanos); 1354 n = tryRead(b, off, len); 1355 } 1356 return n; 1357 } 1358 1359 /** 1360 * Reads bytes from the socket into the given byte array. 1361 * 1362 * @apiNote This method is for use by the socket adaptor. 1363 * 1364 * @throws IllegalBlockingModeException if the channel is non-blocking 1365 * @throws SocketTimeoutException if the read timeout elapses 1366 */ 1367 int blockingRead(byte[] b, int off, int len, long nanos) throws IOException { 1368 Objects.checkFromIndexSize(off, len, b.length); 1369 if (len == 0) { 1370 // nothing to do 1371 return 0; 1372 } 1373 1374 readLock.lock(); 1375 try { 1376 ensureOpenAndConnected(); 1377 1378 // check that channel is configured blocking 1379 if (!isBlocking()) 1380 throw new IllegalBlockingModeException(); 1381 1382 int n = 0; 1383 try { 1384 beginRead(true); 1385 1386 // check if connection has been reset 1387 if (connectionReset) 1388 throwConnectionReset(); 1389 1390 // check if input is shutdown 1391 if (isInputClosed) 1392 return IOStatus.EOF; 1393 1394 if (nanos > 0) { 1395 // change socket to non-blocking 1396 lockedConfigureBlocking(false); 1397 try { 1398 n = timedRead(b, off, len, nanos); 1399 } finally { 1400 // restore socket to blocking mode (if channel is open) 1401 tryLockedConfigureBlocking(true); 1402 } 1403 } else { 1404 // read, no timeout 1405 configureSocketNonBlockingIfVirtualThread(); 1406 n = tryRead(b, off, len); 1407 while (IOStatus.okayToRetry(n) && isOpen()) { 1408 park(Net.POLLIN); 1409 n = tryRead(b, off, len); 1410 } 1411 } 1412 } catch (ConnectionResetException e) { 1413 connectionReset = true; 1414 throwConnectionReset(); 1415 } finally { 1416 endRead(true, n > 0); 1417 if (n <= 0 && isInputClosed) 1418 return IOStatus.EOF; 1419 } 1420 assert n > 0 || n == -1; 1421 return n; 1422 } finally { 1423 readLock.unlock(); 1424 } 1425 } 1426 1427 /** 1428 * Attempts to write a sequence of bytes to the socket from the given 1429 * byte array. 1430 */ 1431 private int tryWrite(byte[] b, int off, int len) throws IOException { 1432 ByteBuffer src = Util.getTemporaryDirectBuffer(len); 1433 assert src.position() == 0; 1434 try { 1435 src.put(b, off, len); 1436 return nd.write(fd, ((DirectBuffer)src).address(), len); 1437 } finally { 1438 Util.offerFirstTemporaryDirectBuffer(src); 1439 } 1440 } 1441 1442 /** 1443 * Writes a sequence of bytes to the socket from the given byte array. 1444 * 1445 * @apiNote This method is for use by the socket adaptor. 1446 */ 1447 void blockingWriteFully(byte[] b, int off, int len) throws IOException { 1448 Objects.checkFromIndexSize(off, len, b.length); 1449 if (len == 0) { 1450 // nothing to do 1451 return; 1452 } 1453 1454 writeLock.lock(); 1455 try { 1456 ensureOpenAndConnected(); 1457 1458 // check that channel is configured blocking 1459 if (!isBlocking()) 1460 throw new IllegalBlockingModeException(); 1461 1462 // loop until all bytes have been written 1463 int pos = off; 1464 int end = off + len; 1465 try { 1466 beginWrite(true); 1467 configureSocketNonBlockingIfVirtualThread(); 1468 while (pos < end && isOpen()) { 1469 int size = end - pos; 1470 int n = tryWrite(b, pos, size); 1471 while (IOStatus.okayToRetry(n) && isOpen()) { 1472 park(Net.POLLOUT); 1473 n = tryWrite(b, pos, size); 1474 } 1475 if (n > 0) { 1476 pos += n; 1477 } 1478 } 1479 } finally { 1480 endWrite(true, pos >= end); 1481 } 1482 } finally { 1483 writeLock.unlock(); 1484 } 1485 } 1486 1487 /** 1488 * Return the number of bytes in the socket input buffer. 1489 */ 1490 int available() throws IOException { 1491 synchronized (stateLock) { 1492 ensureOpenAndConnected(); 1493 if (isInputClosed) { 1494 return 0; 1495 } else { 1496 return Net.available(fd); 1497 } 1498 } 1499 } 1500 1501 /** 1502 * Translates native poll revent ops into a ready operation ops 1503 */ 1504 public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) { 1505 int intOps = ski.nioInterestOps(); 1506 int oldOps = ski.nioReadyOps(); 1507 int newOps = initialOps; 1508 1509 if ((ops & Net.POLLNVAL) != 0) { 1510 // This should only happen if this channel is pre-closed while a 1511 // selection operation is in progress 1512 // ## Throw an error if this channel has not been pre-closed 1513 return false; 1514 } 1515 1516 if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) { 1517 newOps = intOps; 1518 ski.nioReadyOps(newOps); 1519 return (newOps & ~oldOps) != 0; 1520 } 1521 1522 boolean connected = isConnected(); 1523 if (((ops & Net.POLLIN) != 0) && 1524 ((intOps & SelectionKey.OP_READ) != 0) && connected) 1525 newOps |= SelectionKey.OP_READ; 1526 1527 if (((ops & Net.POLLCONN) != 0) && 1528 ((intOps & SelectionKey.OP_CONNECT) != 0) && isConnectionPending()) 1529 newOps |= SelectionKey.OP_CONNECT; 1530 1531 if (((ops & Net.POLLOUT) != 0) && 1532 ((intOps & SelectionKey.OP_WRITE) != 0) && connected) 1533 newOps |= SelectionKey.OP_WRITE; 1534 1535 ski.nioReadyOps(newOps); 1536 return (newOps & ~oldOps) != 0; 1537 } 1538 1539 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) { 1540 return translateReadyOps(ops, ski.nioReadyOps(), ski); 1541 } 1542 1543 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) { 1544 return translateReadyOps(ops, 0, ski); 1545 } 1546 1547 /** 1548 * Translates an interest operation set into a native poll event set 1549 */ 1550 public int translateInterestOps(int ops) { 1551 int newOps = 0; 1552 if ((ops & SelectionKey.OP_READ) != 0) 1553 newOps |= Net.POLLIN; 1554 if ((ops & SelectionKey.OP_WRITE) != 0) 1555 newOps |= Net.POLLOUT; 1556 if ((ops & SelectionKey.OP_CONNECT) != 0) 1557 newOps |= Net.POLLCONN; 1558 return newOps; 1559 } 1560 1561 public FileDescriptor getFD() { 1562 return fd; 1563 } 1564 1565 public int getFDVal() { 1566 return fdVal; 1567 } 1568 1569 @Override 1570 public String toString() { 1571 StringBuilder sb = new StringBuilder(); 1572 sb.append(this.getClass().getSuperclass().getName()); 1573 sb.append('['); 1574 if (!isOpen()) 1575 sb.append("closed"); 1576 else { 1577 synchronized (stateLock) { 1578 switch (state) { 1579 case ST_UNCONNECTED: 1580 sb.append("unconnected"); 1581 break; 1582 case ST_CONNECTIONPENDING: 1583 sb.append("connection-pending"); 1584 break; 1585 case ST_CONNECTED: 1586 sb.append("connected"); 1587 if (isInputClosed) 1588 sb.append(" ishut"); 1589 if (isOutputClosed) 1590 sb.append(" oshut"); 1591 break; 1592 } 1593 SocketAddress addr = localAddress(); 1594 if (addr != null) { 1595 sb.append(" local="); 1596 sb.append(addr); 1597 } 1598 if (remoteAddress() != null) { 1599 sb.append(" remote="); 1600 sb.append(remoteAddress()); 1601 } 1602 } 1603 } 1604 sb.append(']'); 1605 return sb.toString(); 1606 } 1607 }