1 /* 2 * Copyright (c) 2019, 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.io.InputStream; 31 import java.io.InterruptedIOException; 32 import java.io.OutputStream; 33 import java.io.UncheckedIOException; 34 import java.lang.ref.Cleaner.Cleanable; 35 import java.net.InetAddress; 36 import java.net.InetSocketAddress; 37 import java.net.ProtocolFamily; 38 import java.net.SocketAddress; 39 import java.net.SocketException; 40 import java.net.SocketImpl; 41 import java.net.SocketOption; 42 import java.net.SocketTimeoutException; 43 import java.net.StandardProtocolFamily; 44 import java.net.StandardSocketOptions; 45 import java.net.UnknownHostException; 46 import java.nio.ByteBuffer; 47 import java.util.Collections; 48 import java.util.HashSet; 49 import java.util.Objects; 50 import java.util.Set; 51 import java.util.concurrent.TimeUnit; 52 import java.util.concurrent.locks.ReentrantLock; 53 54 import jdk.internal.access.JavaIOFileDescriptorAccess; 55 import jdk.internal.access.SharedSecrets; 56 import jdk.internal.ref.CleanerFactory; 57 import sun.net.ConnectionResetException; 58 import sun.net.NetHooks; 59 import sun.net.PlatformSocketImpl; 60 import sun.net.ext.ExtendedSocketOptions; 61 import jdk.internal.util.Exceptions; 62 63 import static java.util.concurrent.TimeUnit.MILLISECONDS; 64 import static java.util.concurrent.TimeUnit.NANOSECONDS; 65 import static jdk.internal.util.Exceptions.filterNonSocketInfo; 66 import static jdk.internal.util.Exceptions.formatMsg; 67 68 /** 69 * NIO based SocketImpl. 70 * 71 * The underlying socket used by this SocketImpl is initially configured blocking. 72 * If a connect, accept or read is attempted with a timeout, or a virtual 73 * thread invokes a blocking operation, then the socket is changed to non-blocking 74 * When in non-blocking mode, operations that don't complete immediately will 75 * poll the socket (or park when invoked on a virtual thread) and preserve 76 * the semantics of blocking operations. 77 */ 78 79 public final class NioSocketImpl extends SocketImpl implements PlatformSocketImpl { 80 private static final NativeDispatcher nd = new SocketDispatcher(); 81 82 // The maximum number of bytes to read/write per syscall to avoid needing 83 // a huge buffer from the temporary buffer cache 84 private static final int MAX_BUFFER_SIZE = 128 * 1024; 85 86 // true if this is a SocketImpl for a ServerSocket 87 private final boolean server; 88 89 // Lock held when reading (also used when accepting or connecting) 90 private final ReentrantLock readLock = new ReentrantLock(); 91 92 // Lock held when writing 93 private final ReentrantLock writeLock = new ReentrantLock(); 94 95 // The stateLock for read/changing state 96 private final Object stateLock = new Object(); 97 private static final int ST_NEW = 0; 98 private static final int ST_UNCONNECTED = 1; 99 private static final int ST_CONNECTING = 2; 100 private static final int ST_CONNECTED = 3; 101 private static final int ST_CLOSING = 4; 102 private static final int ST_CLOSED = 5; 103 private volatile int state; // need stateLock to change 104 105 private Cleanable cleaner; 106 107 // set to true when the socket is in non-blocking mode 108 private volatile boolean nonBlocking; 109 110 // used by connect/read/write/accept, protected by stateLock 111 private long readerThread; 112 private long writerThread; 113 114 // used when SO_REUSEADDR is emulated, protected by stateLock 115 private boolean isReuseAddress; 116 117 // read or accept timeout in millis 118 private volatile int timeout; 119 120 // flags to indicate if the connection is shutdown for input and output 121 private volatile boolean isInputClosed; 122 private volatile boolean isOutputClosed; 123 124 // used by read to emulate legacy behavior, protected by readLock 125 private boolean readEOF; 126 private boolean connectionReset; 127 128 /** 129 * Creates an instance of this SocketImpl. 130 * @param server true if this is a SocketImpl for a ServerSocket 131 */ 132 public NioSocketImpl(boolean server) { 133 this.server = server; 134 } 135 136 /** 137 * Returns true if the socket is open. 138 */ 139 private boolean isOpen() { 140 return state < ST_CLOSING; 141 } 142 143 /** 144 * Throws SocketException if the socket is not open. 145 */ 146 private void ensureOpen() throws SocketException { 147 int state = this.state; 148 if (state == ST_NEW) 149 throw new SocketException("Socket not created"); 150 if (state >= ST_CLOSING) 151 throw new SocketException("Socket closed"); 152 } 153 154 /** 155 * Throws SocketException if the socket is not open and connected. 156 */ 157 private void ensureOpenAndConnected() throws SocketException { 158 int state = this.state; 159 if (state < ST_CONNECTED) 160 throw new SocketException("Not connected"); 161 if (state > ST_CONNECTED) 162 throw new SocketException("Socket closed"); 163 } 164 165 /** 166 * Disables the current thread for scheduling purposes until the 167 * socket is ready for I/O or is asynchronously closed, for up to the 168 * specified waiting time. 169 * @throws IOException if an I/O error occurs 170 */ 171 private void park(FileDescriptor fd, int event, long nanos) throws IOException { 172 Thread t = Thread.currentThread(); 173 if (t.isVirtual()) { 174 Poller.poll(fdVal(fd), event, nanos, this::isOpen); 175 if (t.isInterrupted()) { 176 throw new InterruptedIOException(); 177 } 178 } else { 179 long millis; 180 if (nanos == 0) { 181 millis = -1; 182 } else { 183 millis = NANOSECONDS.toMillis(nanos); 184 if (nanos > MILLISECONDS.toNanos(millis)) { 185 // Round up any excess nanos to the nearest millisecond to 186 // avoid parking for less than requested. 187 millis++; 188 } 189 } 190 Net.poll(fd, event, millis); 191 } 192 } 193 194 /** 195 * Disables the current thread for scheduling purposes until the socket is 196 * ready for I/O or is asynchronously closed. 197 * @throws IOException if an I/O error occurs 198 */ 199 private void park(FileDescriptor fd, int event) throws IOException { 200 park(fd, event, 0); 201 } 202 203 /** 204 * Ensures that the socket is configured non-blocking invoked on a virtual 205 * thread or the operation has a timeout 206 * @throws IOException if there is an I/O error changing the blocking mode 207 */ 208 private void configureNonBlockingIfNeeded(FileDescriptor fd, boolean timed) 209 throws IOException 210 { 211 if (!nonBlocking 212 && (timed || Thread.currentThread().isVirtual())) { 213 assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread(); 214 IOUtil.configureBlocking(fd, false); 215 nonBlocking = true; 216 } 217 } 218 219 /** 220 * Marks the beginning of a read operation that might block. 221 * @throws SocketException if the socket is closed or not connected 222 */ 223 private FileDescriptor beginRead() throws SocketException { 224 synchronized (stateLock) { 225 ensureOpenAndConnected(); 226 readerThread = NativeThread.current(); 227 return fd; 228 } 229 } 230 231 /** 232 * Marks the end of a read operation that may have blocked. 233 * @throws SocketException is the socket is closed 234 */ 235 private void endRead(boolean completed) throws SocketException { 236 synchronized (stateLock) { 237 readerThread = 0; 238 int state = this.state; 239 if (state == ST_CLOSING) 240 tryFinishClose(); 241 if (!completed && state >= ST_CLOSING) 242 throw new SocketException("Socket closed"); 243 } 244 } 245 246 /** 247 * Attempts to read bytes from the socket into the given byte array. 248 */ 249 private int tryRead(FileDescriptor fd, byte[] b, int off, int len) 250 throws IOException 251 { 252 ByteBuffer dst = Util.getTemporaryDirectBuffer(len); 253 assert dst.position() == 0; 254 try { 255 int n = nd.read(fd, ((DirectBuffer)dst).address(), len); 256 if (n > 0) { 257 dst.get(b, off, n); 258 } 259 return n; 260 } finally { 261 Util.offerFirstTemporaryDirectBuffer(dst); 262 } 263 } 264 265 /** 266 * Reads bytes from the socket into the given byte array with a timeout. 267 * @throws SocketTimeoutException if the read timeout elapses 268 */ 269 private int timedRead(FileDescriptor fd, byte[] b, int off, int len, long nanos) 270 throws IOException 271 { 272 long startNanos = System.nanoTime(); 273 int n = tryRead(fd, b, off, len); 274 while (n == IOStatus.UNAVAILABLE && isOpen()) { 275 long remainingNanos = nanos - (System.nanoTime() - startNanos); 276 if (remainingNanos <= 0) { 277 throw new SocketTimeoutException("Read timed out"); 278 } 279 park(fd, Net.POLLIN, remainingNanos); 280 n = tryRead(fd, b, off, len); 281 } 282 return n; 283 } 284 285 /** 286 * Reads bytes from the socket into the given byte array. 287 * @return the number of bytes read or -1 at EOF 288 * @throws SocketException if the socket is closed or a socket I/O error occurs 289 * @throws SocketTimeoutException if the read timeout elapses 290 */ 291 private int implRead(byte[] b, int off, int len, long remainingNanos) throws IOException { 292 int n = 0; 293 FileDescriptor fd = beginRead(); 294 try { 295 if (connectionReset) 296 throw new SocketException("Connection reset"); 297 if (isInputClosed) 298 return -1; 299 configureNonBlockingIfNeeded(fd, remainingNanos > 0); 300 if (remainingNanos > 0) { 301 // read with timeout 302 n = timedRead(fd, b, off, len, remainingNanos); 303 } else { 304 // read, no timeout 305 n = tryRead(fd, b, off, len); 306 while (IOStatus.okayToRetry(n) && isOpen()) { 307 park(fd, Net.POLLIN); 308 n = tryRead(fd, b, off, len); 309 } 310 } 311 return n; 312 } catch (InterruptedIOException e) { 313 throw e; 314 } catch (ConnectionResetException e) { 315 connectionReset = true; 316 throw new SocketException("Connection reset"); 317 } catch (IOException ioe) { 318 // throw SocketException to maintain compatibility 319 throw asSocketException(ioe); 320 } finally { 321 endRead(n > 0); 322 } 323 } 324 325 /** 326 * Reads bytes from the socket into the given byte array. 327 * @return the number of bytes read or -1 at EOF 328 * @throws IndexOutOfBoundsException if the bound checks fail 329 * @throws SocketException if the socket is closed or a socket I/O error occurs 330 * @throws SocketTimeoutException if the read timeout elapses 331 */ 332 private int read(byte[] b, int off, int len) throws IOException { 333 Objects.checkFromIndexSize(off, len, b.length); 334 if (len == 0) { 335 return 0; 336 } else { 337 long remainingNanos = 0; 338 int timeout = this.timeout; 339 if (timeout > 0) { 340 remainingNanos = tryLock(readLock, timeout, MILLISECONDS); 341 if (remainingNanos <= 0) { 342 assert !readLock.isHeldByCurrentThread(); 343 throw new SocketTimeoutException("Read timed out"); 344 } 345 } else { 346 readLock.lock(); 347 } 348 try { 349 // emulate legacy behavior to return -1, even if socket is closed 350 if (readEOF) 351 return -1; 352 // read up to MAX_BUFFER_SIZE bytes 353 int size = Math.min(len, MAX_BUFFER_SIZE); 354 int n = implRead(b, off, size, remainingNanos); 355 if (n == -1) 356 readEOF = true; 357 return n; 358 } finally { 359 readLock.unlock(); 360 } 361 } 362 } 363 364 /** 365 * Marks the beginning of a write operation that might block. 366 * @throws SocketException if the socket is closed or not connected 367 */ 368 private FileDescriptor beginWrite() throws SocketException { 369 synchronized (stateLock) { 370 ensureOpenAndConnected(); 371 writerThread = NativeThread.current(); 372 return fd; 373 } 374 } 375 376 /** 377 * Marks the end of a write operation that may have blocked. 378 * @throws SocketException is the socket is closed 379 */ 380 private void endWrite(boolean completed) throws SocketException { 381 synchronized (stateLock) { 382 writerThread = 0; 383 int state = this.state; 384 if (state == ST_CLOSING) 385 tryFinishClose(); 386 if (!completed && state >= ST_CLOSING) 387 throw new SocketException("Socket closed"); 388 } 389 } 390 391 /** 392 * Attempts to write a sequence of bytes to the socket from the given 393 * byte array. 394 */ 395 private int tryWrite(FileDescriptor fd, byte[] b, int off, int len) 396 throws IOException 397 { 398 ByteBuffer src = Util.getTemporaryDirectBuffer(len); 399 assert src.position() == 0; 400 try { 401 src.put(b, off, len); 402 return nd.write(fd, ((DirectBuffer)src).address(), len); 403 } finally { 404 Util.offerFirstTemporaryDirectBuffer(src); 405 } 406 } 407 408 /** 409 * Writes a sequence of bytes to the socket from the given byte array. 410 * @return the number of bytes written 411 * @throws SocketException if the socket is closed or a socket I/O error occurs 412 */ 413 private int implWrite(byte[] b, int off, int len) throws IOException { 414 int n = 0; 415 FileDescriptor fd = beginWrite(); 416 try { 417 configureNonBlockingIfNeeded(fd, false); 418 n = tryWrite(fd, b, off, len); 419 while (IOStatus.okayToRetry(n) && isOpen()) { 420 park(fd, Net.POLLOUT); 421 n = tryWrite(fd, b, off, len); 422 } 423 return n; 424 } catch (InterruptedIOException e) { 425 throw e; 426 } catch (IOException ioe) { 427 // throw SocketException to maintain compatibility 428 throw asSocketException(ioe); 429 } finally { 430 endWrite(n > 0); 431 } 432 } 433 434 /** 435 * Writes a sequence of bytes to the socket from the given byte array. 436 * @throws SocketException if the socket is closed or a socket I/O error occurs 437 */ 438 private void write(byte[] b, int off, int len) throws IOException { 439 Objects.checkFromIndexSize(off, len, b.length); 440 if (len > 0) { 441 writeLock.lock(); 442 try { 443 int pos = off; 444 int end = off + len; 445 while (pos < end) { 446 // write up to MAX_BUFFER_SIZE bytes 447 int size = Math.min((end - pos), MAX_BUFFER_SIZE); 448 int n = implWrite(b, pos, size); 449 pos += n; 450 } 451 } finally { 452 writeLock.unlock(); 453 } 454 } 455 } 456 457 /** 458 * Creates the socket. 459 * @param stream {@code true} for a streams socket 460 */ 461 @Override 462 protected void create(boolean stream) throws IOException { 463 if (!stream) { 464 throw new IOException("Datagram socket creation not supported"); 465 } 466 synchronized (stateLock) { 467 if (state != ST_NEW) 468 throw new IOException("Already created"); 469 FileDescriptor fd; 470 if (server) { 471 fd = Net.serverSocket(); 472 } else { 473 fd = Net.socket(); 474 } 475 Runnable closer = closerFor(fd); 476 this.fd = fd; 477 this.cleaner = CleanerFactory.cleaner().register(this, closer); 478 this.state = ST_UNCONNECTED; 479 } 480 } 481 482 /** 483 * Marks the beginning of a connect operation that might block. 484 * @throws SocketException if the socket is closed or already connected 485 */ 486 private FileDescriptor beginConnect(InetAddress address, int port) 487 throws IOException 488 { 489 synchronized (stateLock) { 490 int state = this.state; 491 if (state != ST_UNCONNECTED) { 492 if (state == ST_NEW) 493 throw new SocketException("Not created"); 494 if (state == ST_CONNECTING) 495 throw new SocketException("Connection in progress"); 496 if (state == ST_CONNECTED) 497 throw new SocketException("Already connected"); 498 if (state >= ST_CLOSING) 499 throw new SocketException("Socket closed"); 500 assert false; 501 } 502 this.state = ST_CONNECTING; 503 504 // invoke beforeTcpConnect hook if not already bound 505 if (localport == 0) { 506 NetHooks.beforeTcpConnect(fd, address, port); 507 } 508 509 // save the remote address/port 510 this.address = address; 511 this.port = port; 512 513 readerThread = NativeThread.current(); 514 return fd; 515 } 516 } 517 518 /** 519 * Marks the end of a connect operation that may have blocked. 520 * @throws SocketException is the socket is closed 521 */ 522 private void endConnect(FileDescriptor fd, boolean completed) throws IOException { 523 synchronized (stateLock) { 524 readerThread = 0; 525 int state = this.state; 526 if (state == ST_CLOSING) 527 tryFinishClose(); 528 if (completed && state == ST_CONNECTING) { 529 this.state = ST_CONNECTED; 530 localport = Net.localAddress(fd).getPort(); 531 } else if (!completed && state >= ST_CLOSING) { 532 throw new SocketException("Socket closed"); 533 } 534 } 535 } 536 537 /** 538 * Waits for a connection attempt to finish with a timeout 539 * @throws SocketTimeoutException if the connect timeout elapses 540 */ 541 private boolean timedFinishConnect(FileDescriptor fd, long nanos) throws IOException { 542 long startNanos = System.nanoTime(); 543 boolean polled = Net.pollConnectNow(fd); 544 while (!polled && isOpen()) { 545 long remainingNanos = nanos - (System.nanoTime() - startNanos); 546 if (remainingNanos <= 0) { 547 throw new SocketTimeoutException("Connect timed out"); 548 } 549 park(fd, Net.POLLOUT, remainingNanos); 550 polled = Net.pollConnectNow(fd); 551 } 552 return polled && isOpen(); 553 } 554 555 /** 556 * Attempts to establish a connection to the given socket address with a 557 * timeout. Closes the socket if connection cannot be established. 558 * @throws IOException if the address is not a resolved InetSocketAddress or 559 * the connection cannot be established 560 */ 561 @Override 562 protected void connect(SocketAddress remote, int millis) throws IOException { 563 // SocketImpl connect only specifies IOException 564 if (!(remote instanceof InetSocketAddress)) 565 throw new IOException("Unsupported address type"); 566 InetSocketAddress isa = (InetSocketAddress) remote; 567 if (isa.isUnresolved()) { 568 throw new UnknownHostException( 569 formatMsg(filterNonSocketInfo(isa.getHostName()))); 570 } 571 572 InetAddress address = isa.getAddress(); 573 if (address.isAnyLocalAddress()) 574 address = InetAddress.getLocalHost(); 575 int port = isa.getPort(); 576 577 ReentrantLock connectLock = readLock; 578 try { 579 connectLock.lock(); 580 try { 581 boolean connected = false; 582 FileDescriptor fd = beginConnect(address, port); 583 try { 584 configureNonBlockingIfNeeded(fd, millis > 0); 585 int n = Net.connect(fd, address, port); 586 if (n > 0) { 587 // connection established 588 connected = true; 589 } else { 590 assert IOStatus.okayToRetry(n); 591 if (millis > 0) { 592 // finish connect with timeout 593 long nanos = MILLISECONDS.toNanos(millis); 594 connected = timedFinishConnect(fd, nanos); 595 } else { 596 // finish connect, no timeout 597 boolean polled = false; 598 while (!polled && isOpen()) { 599 park(fd, Net.POLLOUT); 600 polled = Net.pollConnectNow(fd); 601 } 602 connected = polled && isOpen(); 603 } 604 } 605 } finally { 606 endConnect(fd, connected); 607 } 608 } finally { 609 connectLock.unlock(); 610 } 611 } catch (IOException ioe) { 612 close(); 613 if (ioe instanceof SocketTimeoutException) { 614 throw ioe; 615 } else if (ioe instanceof InterruptedIOException) { 616 assert Thread.currentThread().isVirtual(); 617 throw new SocketException("Closed by interrupt"); 618 } else { 619 throw Exceptions.ioException(ioe, isa); 620 } 621 } 622 } 623 624 @Override 625 protected void connect(String host, int port) throws IOException { 626 connect(new InetSocketAddress(host, port), 0); 627 } 628 629 @Override 630 protected void connect(InetAddress address, int port) throws IOException { 631 connect(new InetSocketAddress(address, port), 0); 632 } 633 634 @Override 635 protected void bind(InetAddress host, int port) throws IOException { 636 synchronized (stateLock) { 637 ensureOpen(); 638 if (localport != 0) 639 throw new SocketException("Already bound"); 640 NetHooks.beforeTcpBind(fd, host, port); 641 Net.bind(fd, host, port); 642 // set the address field to the given host address to 643 // maintain long standing behavior. When binding to 0.0.0.0 644 // then the actual local address will be ::0 when IPv6 is enabled. 645 address = host; 646 localport = Net.localAddress(fd).getPort(); 647 } 648 } 649 650 @Override 651 protected void listen(int backlog) throws IOException { 652 synchronized (stateLock) { 653 ensureOpen(); 654 if (localport == 0) 655 throw new SocketException("Not bound"); 656 Net.listen(fd, backlog < 1 ? 50 : backlog); 657 } 658 } 659 660 /** 661 * Marks the beginning of an accept operation that might block. 662 * @throws SocketException if the socket is closed 663 */ 664 private FileDescriptor beginAccept() throws SocketException { 665 synchronized (stateLock) { 666 ensureOpen(); 667 if (localport == 0) 668 throw new SocketException("Not bound"); 669 readerThread = NativeThread.current(); 670 return fd; 671 } 672 } 673 674 /** 675 * Marks the end of an accept operation that may have blocked. 676 * @throws SocketException is the socket is closed 677 */ 678 private void endAccept(boolean completed) throws SocketException { 679 synchronized (stateLock) { 680 int state = this.state; 681 readerThread = 0; 682 if (state == ST_CLOSING) 683 tryFinishClose(); 684 if (!completed && state >= ST_CLOSING) 685 throw new SocketException("Socket closed"); 686 } 687 } 688 689 /** 690 * Accepts a new connection with a timeout. 691 * @throws SocketTimeoutException if the accept timeout elapses 692 */ 693 private int timedAccept(FileDescriptor fd, 694 FileDescriptor newfd, 695 InetSocketAddress[] isaa, 696 long nanos) 697 throws IOException 698 { 699 long startNanos = System.nanoTime(); 700 int n = Net.accept(fd, newfd, isaa); 701 while (n == IOStatus.UNAVAILABLE && isOpen()) { 702 long remainingNanos = nanos - (System.nanoTime() - startNanos); 703 if (remainingNanos <= 0) { 704 throw new SocketTimeoutException("Accept timed out"); 705 } 706 park(fd, Net.POLLIN, remainingNanos); 707 n = Net.accept(fd, newfd, isaa); 708 } 709 return n; 710 } 711 712 /** 713 * Accepts a new connection so that the given SocketImpl is connected to 714 * the peer. The SocketImpl must be a newly created NioSocketImpl. 715 */ 716 @Override 717 protected void accept(SocketImpl si) throws IOException { 718 NioSocketImpl nsi = (NioSocketImpl) si; 719 if (nsi.state != ST_NEW) 720 throw new SocketException("Not a newly created SocketImpl"); 721 722 FileDescriptor newfd = new FileDescriptor(); 723 InetSocketAddress[] isaa = new InetSocketAddress[1]; 724 725 // acquire the lock, adjusting the timeout for cases where several 726 // threads are accepting connections and there is a timeout set 727 ReentrantLock acceptLock = readLock; 728 int timeout = this.timeout; 729 long remainingNanos = 0; 730 if (timeout > 0) { 731 remainingNanos = tryLock(acceptLock, timeout, MILLISECONDS); 732 if (remainingNanos <= 0) { 733 assert !acceptLock.isHeldByCurrentThread(); 734 throw new SocketTimeoutException("Accept timed out"); 735 } 736 } else { 737 acceptLock.lock(); 738 } 739 740 // accept a connection 741 try { 742 int n = 0; 743 FileDescriptor fd = beginAccept(); 744 try { 745 configureNonBlockingIfNeeded(fd, remainingNanos > 0); 746 if (remainingNanos > 0) { 747 // accept with timeout 748 n = timedAccept(fd, newfd, isaa, remainingNanos); 749 } else { 750 // accept, no timeout 751 n = Net.accept(fd, newfd, isaa); 752 while (IOStatus.okayToRetry(n) && isOpen()) { 753 park(fd, Net.POLLIN); 754 n = Net.accept(fd, newfd, isaa); 755 } 756 } 757 } finally { 758 endAccept(n > 0); 759 assert IOStatus.check(n); 760 } 761 } finally { 762 acceptLock.unlock(); 763 } 764 765 // get local address and configure accepted socket to blocking mode 766 InetSocketAddress localAddress; 767 try { 768 localAddress = Net.localAddress(newfd); 769 IOUtil.configureBlocking(newfd, true); 770 } catch (IOException ioe) { 771 nd.close(newfd); 772 throw ioe; 773 } 774 775 // set the fields 776 Runnable closer = closerFor(newfd); 777 synchronized (nsi.stateLock) { 778 nsi.fd = newfd; 779 nsi.cleaner = CleanerFactory.cleaner().register(nsi, closer); 780 nsi.localport = localAddress.getPort(); 781 nsi.address = isaa[0].getAddress(); 782 nsi.port = isaa[0].getPort(); 783 nsi.state = ST_CONNECTED; 784 } 785 } 786 787 @Override 788 protected InputStream getInputStream() { 789 return new InputStream() { 790 @Override 791 public int read() throws IOException { 792 byte[] a = new byte[1]; 793 int n = read(a, 0, 1); 794 return (n > 0) ? (a[0] & 0xff) : -1; 795 } 796 @Override 797 public int read(byte[] b, int off, int len) throws IOException { 798 return NioSocketImpl.this.read(b, off, len); 799 } 800 @Override 801 public int available() throws IOException { 802 return NioSocketImpl.this.available(); 803 } 804 @Override 805 public void close() throws IOException { 806 NioSocketImpl.this.close(); 807 } 808 }; 809 } 810 811 @Override 812 protected OutputStream getOutputStream() { 813 return new OutputStream() { 814 @Override 815 public void write(int b) throws IOException { 816 byte[] a = new byte[]{(byte) b}; 817 write(a, 0, 1); 818 } 819 @Override 820 public void write(byte[] b, int off, int len) throws IOException { 821 NioSocketImpl.this.write(b, off, len); 822 } 823 @Override 824 public void close() throws IOException { 825 NioSocketImpl.this.close(); 826 } 827 }; 828 } 829 830 @Override 831 protected int available() throws IOException { 832 synchronized (stateLock) { 833 ensureOpenAndConnected(); 834 if (isInputClosed) { 835 return 0; 836 } else { 837 return Net.available(fd); 838 } 839 } 840 } 841 842 /** 843 * Closes the socket if there are no I/O operations in progress. 844 */ 845 private boolean tryClose() throws IOException { 846 assert Thread.holdsLock(stateLock) && state == ST_CLOSING; 847 if (readerThread == 0 && writerThread == 0) { 848 try { 849 cleaner.clean(); 850 } catch (UncheckedIOException ioe) { 851 throw ioe.getCause(); 852 } finally { 853 state = ST_CLOSED; 854 } 855 return true; 856 } else { 857 return false; 858 } 859 } 860 861 /** 862 * Invokes tryClose to attempt to close the socket. 863 * 864 * This method is used for deferred closing by I/O operations. 865 */ 866 private void tryFinishClose() { 867 try { 868 tryClose(); 869 } catch (IOException ignore) { } 870 } 871 872 /** 873 * Closes the socket. If there are I/O operations in progress then the 874 * socket is pre-closed and the threads are signalled. The socket will be 875 * closed when the last I/O operation aborts. 876 */ 877 @Override 878 protected void close() throws IOException { 879 synchronized (stateLock) { 880 int state = this.state; 881 if (state >= ST_CLOSING) 882 return; 883 if (state == ST_NEW) { 884 // stillborn 885 this.state = ST_CLOSED; 886 return; 887 } 888 boolean connected = (state == ST_CONNECTED); 889 this.state = ST_CLOSING; 890 891 // shutdown output when linger interval not set to 0 892 if (connected) { 893 try { 894 var SO_LINGER = StandardSocketOptions.SO_LINGER; 895 if ((int) Net.getSocketOption(fd, SO_LINGER) != 0) { 896 Net.shutdown(fd, Net.SHUT_WR); 897 } 898 } catch (IOException ignore) { } 899 } 900 901 // attempt to close the socket. If there are I/O operations in progress 902 // then the socket is pre-closed and the thread(s) signalled. The 903 // last thread will close the file descriptor. 904 if (!tryClose()) { 905 nd.preClose(fd, readerThread, writerThread); 906 } 907 } 908 } 909 910 // the socket options supported by client and server sockets 911 private static volatile Set<SocketOption<?>> clientSocketOptions; 912 private static volatile Set<SocketOption<?>> serverSocketOptions; 913 914 @Override 915 protected Set<SocketOption<?>> supportedOptions() { 916 Set<SocketOption<?>> options = (server) ? serverSocketOptions : clientSocketOptions; 917 if (options == null) { 918 options = new HashSet<>(); 919 options.add(StandardSocketOptions.SO_RCVBUF); 920 options.add(StandardSocketOptions.SO_REUSEADDR); 921 if (server) { 922 // IP_TOS added for server socket to maintain compatibility 923 options.add(StandardSocketOptions.IP_TOS); 924 options.addAll(ExtendedSocketOptions.serverSocketOptions()); 925 } else { 926 options.add(StandardSocketOptions.IP_TOS); 927 options.add(StandardSocketOptions.SO_KEEPALIVE); 928 options.add(StandardSocketOptions.SO_SNDBUF); 929 options.add(StandardSocketOptions.SO_LINGER); 930 options.add(StandardSocketOptions.TCP_NODELAY); 931 options.addAll(ExtendedSocketOptions.clientSocketOptions()); 932 } 933 if (Net.isReusePortAvailable()) 934 options.add(StandardSocketOptions.SO_REUSEPORT); 935 options = Collections.unmodifiableSet(options); 936 if (server) { 937 serverSocketOptions = options; 938 } else { 939 clientSocketOptions = options; 940 } 941 } 942 return options; 943 } 944 945 @Override 946 protected <T> void setOption(SocketOption<T> opt, T value) throws IOException { 947 if (!supportedOptions().contains(opt)) 948 throw new UnsupportedOperationException("'" + opt + "' not supported"); 949 if (!opt.type().isInstance(value)) 950 throw new IllegalArgumentException("Invalid value '" + value + "'"); 951 synchronized (stateLock) { 952 ensureOpen(); 953 if (opt == StandardSocketOptions.IP_TOS) { 954 // maps to IPV6_TCLASS and/or IP_TOS 955 Net.setIpSocketOption(fd, family(), opt, value); 956 } else if (opt == StandardSocketOptions.SO_REUSEADDR) { 957 boolean b = (boolean) value; 958 if (Net.useExclusiveBind()) { 959 isReuseAddress = b; 960 } else { 961 Net.setSocketOption(fd, opt, b); 962 } 963 } else { 964 // option does not need special handling 965 Net.setSocketOption(fd, opt, value); 966 } 967 } 968 } 969 970 @SuppressWarnings("unchecked") 971 protected <T> T getOption(SocketOption<T> opt) throws IOException { 972 if (!supportedOptions().contains(opt)) 973 throw new UnsupportedOperationException("'" + opt + "' not supported"); 974 synchronized (stateLock) { 975 ensureOpen(); 976 if (opt == StandardSocketOptions.IP_TOS) { 977 return (T) Net.getSocketOption(fd, family(), opt); 978 } else if (opt == StandardSocketOptions.SO_REUSEADDR) { 979 if (Net.useExclusiveBind()) { 980 return (T) Boolean.valueOf(isReuseAddress); 981 } else { 982 return (T) Net.getSocketOption(fd, opt); 983 } 984 } else { 985 // option does not need special handling 986 return (T) Net.getSocketOption(fd, opt); 987 } 988 } 989 } 990 991 private boolean booleanValue(Object value, String desc) throws SocketException { 992 if (!(value instanceof Boolean)) 993 throw new SocketException("Bad value for " + desc); 994 return (boolean) value; 995 } 996 997 private int intValue(Object value, String desc) throws SocketException { 998 if (!(value instanceof Integer)) 999 throw new SocketException("Bad value for " + desc); 1000 return (int) value; 1001 } 1002 1003 @Override 1004 public void setOption(int opt, Object value) throws SocketException { 1005 synchronized (stateLock) { 1006 ensureOpen(); 1007 try { 1008 switch (opt) { 1009 case SO_LINGER: { 1010 // the value is "false" to disable, or linger interval to enable 1011 int i; 1012 if (value instanceof Boolean && ((boolean) value) == false) { 1013 i = -1; 1014 } else { 1015 i = intValue(value, "SO_LINGER"); 1016 } 1017 Net.setSocketOption(fd, StandardSocketOptions.SO_LINGER, i); 1018 break; 1019 } 1020 case SO_TIMEOUT: { 1021 int i = intValue(value, "SO_TIMEOUT"); 1022 if (i < 0) 1023 throw new IllegalArgumentException("timeout < 0"); 1024 timeout = i; 1025 break; 1026 } 1027 case IP_TOS: { 1028 int i = intValue(value, "IP_TOS"); 1029 Net.setIpSocketOption(fd, family(), StandardSocketOptions.IP_TOS, i); 1030 break; 1031 } 1032 case TCP_NODELAY: { 1033 boolean b = booleanValue(value, "TCP_NODELAY"); 1034 Net.setSocketOption(fd, StandardSocketOptions.TCP_NODELAY, b); 1035 break; 1036 } 1037 case SO_SNDBUF: { 1038 int i = intValue(value, "SO_SNDBUF"); 1039 if (i <= 0) 1040 throw new SocketException("SO_SNDBUF <= 0"); 1041 Net.setSocketOption(fd, StandardSocketOptions.SO_SNDBUF, i); 1042 break; 1043 } 1044 case SO_RCVBUF: { 1045 int i = intValue(value, "SO_RCVBUF"); 1046 if (i <= 0) 1047 throw new SocketException("SO_RCVBUF <= 0"); 1048 Net.setSocketOption(fd, StandardSocketOptions.SO_RCVBUF, i); 1049 break; 1050 } 1051 case SO_KEEPALIVE: { 1052 boolean b = booleanValue(value, "SO_KEEPALIVE"); 1053 Net.setSocketOption(fd, StandardSocketOptions.SO_KEEPALIVE, b); 1054 break; 1055 } 1056 case SO_OOBINLINE: { 1057 boolean b = booleanValue(value, "SO_OOBINLINE"); 1058 Net.setSocketOption(fd, ExtendedSocketOption.SO_OOBINLINE, b); 1059 break; 1060 } 1061 case SO_REUSEADDR: { 1062 boolean b = booleanValue(value, "SO_REUSEADDR"); 1063 if (Net.useExclusiveBind()) { 1064 isReuseAddress = b; 1065 } else { 1066 Net.setSocketOption(fd, StandardSocketOptions.SO_REUSEADDR, b); 1067 } 1068 break; 1069 } 1070 case SO_REUSEPORT: { 1071 if (!Net.isReusePortAvailable()) 1072 throw new SocketException("SO_REUSEPORT not supported"); 1073 boolean b = booleanValue(value, "SO_REUSEPORT"); 1074 Net.setSocketOption(fd, StandardSocketOptions.SO_REUSEPORT, b); 1075 break; 1076 } 1077 default: 1078 throw new SocketException("Unknown option " + opt); 1079 } 1080 } catch (SocketException e) { 1081 throw e; 1082 } catch (IllegalArgumentException | IOException e) { 1083 throw asSocketException(e); 1084 } 1085 } 1086 } 1087 1088 @Override 1089 public Object getOption(int opt) throws SocketException { 1090 synchronized (stateLock) { 1091 ensureOpen(); 1092 try { 1093 switch (opt) { 1094 case SO_TIMEOUT: 1095 return timeout; 1096 case TCP_NODELAY: 1097 return Net.getSocketOption(fd, StandardSocketOptions.TCP_NODELAY); 1098 case SO_OOBINLINE: 1099 return Net.getSocketOption(fd, ExtendedSocketOption.SO_OOBINLINE); 1100 case SO_LINGER: { 1101 // return "false" when disabled, linger interval when enabled 1102 int i = (int) Net.getSocketOption(fd, StandardSocketOptions.SO_LINGER); 1103 if (i == -1) { 1104 return Boolean.FALSE; 1105 } else { 1106 return i; 1107 } 1108 } 1109 case SO_REUSEADDR: 1110 if (Net.useExclusiveBind()) { 1111 return isReuseAddress; 1112 } else { 1113 return Net.getSocketOption(fd, StandardSocketOptions.SO_REUSEADDR); 1114 } 1115 case SO_BINDADDR: 1116 return Net.localAddress(fd).getAddress(); 1117 case SO_SNDBUF: 1118 return Net.getSocketOption(fd, StandardSocketOptions.SO_SNDBUF); 1119 case SO_RCVBUF: 1120 return Net.getSocketOption(fd, StandardSocketOptions.SO_RCVBUF); 1121 case IP_TOS: 1122 return Net.getSocketOption(fd, family(), StandardSocketOptions.IP_TOS); 1123 case SO_KEEPALIVE: 1124 return Net.getSocketOption(fd, StandardSocketOptions.SO_KEEPALIVE); 1125 case SO_REUSEPORT: 1126 if (!Net.isReusePortAvailable()) 1127 throw new SocketException("SO_REUSEPORT not supported"); 1128 return Net.getSocketOption(fd, StandardSocketOptions.SO_REUSEPORT); 1129 default: 1130 throw new SocketException("Unknown option " + opt); 1131 } 1132 } catch (SocketException e) { 1133 throw e; 1134 } catch (IllegalArgumentException | IOException e) { 1135 throw asSocketException(e); 1136 } 1137 } 1138 } 1139 1140 @Override 1141 protected void shutdownInput() throws IOException { 1142 synchronized (stateLock) { 1143 ensureOpenAndConnected(); 1144 if (!isInputClosed) { 1145 Net.shutdown(fd, Net.SHUT_RD); 1146 if (NativeThread.isVirtualThread(readerThread)) { 1147 Poller.stopPoll(fdVal(fd), Net.POLLIN); 1148 } 1149 isInputClosed = true; 1150 } 1151 } 1152 } 1153 1154 @Override 1155 protected void shutdownOutput() throws IOException { 1156 synchronized (stateLock) { 1157 ensureOpenAndConnected(); 1158 if (!isOutputClosed) { 1159 Net.shutdown(fd, Net.SHUT_WR); 1160 if (NativeThread.isVirtualThread(writerThread)) { 1161 Poller.stopPoll(fdVal(fd), Net.POLLOUT); 1162 } 1163 isOutputClosed = true; 1164 } 1165 } 1166 } 1167 1168 @Override 1169 protected boolean supportsUrgentData() { 1170 return true; 1171 } 1172 1173 @Override 1174 protected void sendUrgentData(int data) throws IOException { 1175 writeLock.lock(); 1176 try { 1177 int n = 0; 1178 FileDescriptor fd = beginWrite(); 1179 try { 1180 configureNonBlockingIfNeeded(fd, false); 1181 do { 1182 n = Net.sendOOB(fd, (byte) data); 1183 } while (n == IOStatus.INTERRUPTED && isOpen()); 1184 if (n == IOStatus.UNAVAILABLE) { 1185 throw new SocketException("No buffer space available"); 1186 } 1187 } finally { 1188 endWrite(n > 0); 1189 } 1190 } finally { 1191 writeLock.unlock(); 1192 } 1193 } 1194 1195 /** 1196 * Returns an action to close the given file descriptor. 1197 */ 1198 private static Runnable closerFor(FileDescriptor fd) { 1199 return () -> { 1200 try { 1201 nd.close(fd); 1202 } catch (IOException ioe) { 1203 throw new UncheckedIOException(ioe); 1204 } 1205 }; 1206 } 1207 1208 /** 1209 * Attempts to acquire the given lock within the given waiting time. 1210 * @return the remaining time in nanoseconds when the lock is acquired, zero 1211 * or less if the lock was not acquired before the timeout expired 1212 */ 1213 private static long tryLock(ReentrantLock lock, long timeout, TimeUnit unit) { 1214 assert timeout > 0; 1215 boolean interrupted = false; 1216 long nanos = unit.toNanos(timeout); 1217 long remainingNanos = nanos; 1218 long startNanos = System.nanoTime(); 1219 boolean acquired = false; 1220 while (!acquired && (remainingNanos > 0)) { 1221 try { 1222 acquired = lock.tryLock(remainingNanos, NANOSECONDS); 1223 } catch (InterruptedException e) { 1224 interrupted = true; 1225 } 1226 remainingNanos = nanos - (System.nanoTime() - startNanos); 1227 } 1228 if (acquired && remainingNanos <= 0L) 1229 lock.unlock(); // release lock if timeout has expired 1230 if (interrupted) 1231 Thread.currentThread().interrupt(); 1232 return remainingNanos; 1233 } 1234 1235 /** 1236 * Creates a SocketException from the given exception. 1237 */ 1238 private static SocketException asSocketException(Exception e) { 1239 if (e instanceof SocketException se) { 1240 return se; 1241 } else { 1242 var se = new SocketException(e.getMessage()); 1243 se.setStackTrace(e.getStackTrace()); 1244 return se; 1245 } 1246 } 1247 1248 /** 1249 * Returns the socket protocol family. 1250 */ 1251 private static ProtocolFamily family() { 1252 if (Net.isIPv6Available()) { 1253 return StandardProtocolFamily.INET6; 1254 } else { 1255 return StandardProtocolFamily.INET; 1256 } 1257 } 1258 1259 /** 1260 * Return the file descriptor value. 1261 */ 1262 private static int fdVal(FileDescriptor fd) { 1263 return JIOFDA.get(fd); 1264 } 1265 1266 private static final JavaIOFileDescriptorAccess JIOFDA = SharedSecrets.getJavaIOFileDescriptorAccess(); 1267 }