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.BindException; 31 import java.net.InetSocketAddress; 32 import java.net.ProtocolFamily; 33 import java.net.ServerSocket; 34 import java.net.SocketAddress; 35 import java.net.SocketOption; 36 import java.net.SocketTimeoutException; 37 import java.net.StandardSocketOptions; 38 import java.net.UnixDomainSocketAddress; 39 import java.nio.channels.AlreadyBoundException; 40 import java.nio.channels.AsynchronousCloseException; 41 import java.nio.channels.ClosedChannelException; 42 import java.nio.channels.IllegalBlockingModeException; 43 import java.nio.channels.NotYetBoundException; 44 import java.nio.channels.SelectionKey; 45 import java.nio.channels.ServerSocketChannel; 46 import java.nio.channels.SocketChannel; 47 import java.nio.channels.spi.SelectorProvider; 48 import java.nio.file.Path; 49 import java.util.Collections; 50 import java.util.HashSet; 51 import java.util.Set; 52 import java.util.Objects; 53 import java.util.concurrent.locks.ReentrantLock; 54 import static java.net.StandardProtocolFamily.INET; 55 import static java.net.StandardProtocolFamily.INET6; 56 import static java.net.StandardProtocolFamily.UNIX; 57 58 import sun.net.NetHooks; 59 import sun.net.ext.ExtendedSocketOptions; 60 61 /** 62 * An implementation of ServerSocketChannels 63 */ 64 65 class ServerSocketChannelImpl 66 extends ServerSocketChannel 67 implements SelChImpl 68 { 69 // Used to make native close and configure calls 70 private static final NativeDispatcher nd = new SocketDispatcher(); 71 72 // The protocol family of the socket 73 private final ProtocolFamily family; 74 75 // Our file descriptor 76 private final FileDescriptor fd; 77 private final int fdVal; 78 79 // Lock held by thread currently blocked on this channel 80 private final ReentrantLock acceptLock = new ReentrantLock(); 81 82 // Lock held by any thread that modifies the state fields declared below 83 // DO NOT invoke a blocking I/O operation while holding this lock! 84 private final Object stateLock = new Object(); 85 86 // -- The following fields are protected by stateLock 87 88 // Channel state, increases monotonically 89 private static final int ST_INUSE = 0; 90 private static final int ST_CLOSING = 1; 91 private static final int ST_CLOSED = 2; 92 private int state; 93 94 // ID of native thread currently blocked in this channel, for signalling 95 private NativeThread thread; 96 97 // Binding 98 private SocketAddress localAddress; // null => unbound 99 100 // set true when exclusive binding is on and SO_REUSEADDR is emulated 101 private boolean isReuseAddress; 102 103 // Our socket adaptor, if any 104 private ServerSocket socket; 105 106 // True if the channel's socket has been forced into non-blocking mode 107 // by a virtual thread. It cannot be reset. When the channel is in 108 // blocking mode and the channel's socket is in non-blocking mode then 109 // operations that don't complete immediately will poll the socket and 110 // preserve the semantics of blocking operations. 111 private volatile boolean forcedNonBlocking; 112 113 // -- End of fields protected by stateLock 114 115 ServerSocketChannelImpl(SelectorProvider sp) throws IOException { 116 this(sp, Net.isIPv6Available() ? INET6 : INET); 117 } 118 119 ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family) 120 throws IOException 121 { 122 super(sp); 123 Objects.requireNonNull(family, "'family' is null"); 124 if ((family != INET) && (family != INET6) && (family != UNIX)) { 125 throw new UnsupportedOperationException("Protocol family not supported"); 126 } 127 if (family == INET6 && !Net.isIPv6Available()) { 128 throw new UnsupportedOperationException("IPv6 not available"); 129 } 130 131 this.family = family; 132 if (family == UNIX) { 133 this.fd = UnixDomainSockets.socket(); 134 } else { 135 this.fd = Net.serverSocket(family); 136 } 137 this.fdVal = IOUtil.fdVal(fd); 138 } 139 140 ServerSocketChannelImpl(SelectorProvider sp, 141 ProtocolFamily family, 142 FileDescriptor fd, 143 boolean bound) 144 throws IOException 145 { 146 super(sp); 147 148 if (family == UNIX) { 149 this.family = UNIX; 150 } else { 151 this.family = Net.isIPv6Available() ? INET6 : INET; 152 } 153 this.fd = fd; 154 this.fdVal = IOUtil.fdVal(fd); 155 156 if (bound) { 157 synchronized (stateLock) { 158 if (family == UNIX) { 159 localAddress = UnixDomainSockets.localAddress(fd); 160 } else { 161 localAddress = Net.localAddress(fd); 162 } 163 } 164 } 165 } 166 167 /** 168 * Returns true if this channel is to a INET or INET6 socket. 169 */ 170 private boolean isNetSocket() { 171 return (family == INET) || (family == INET6); 172 } 173 174 /** 175 * Returns true if this channel is to a UNIX socket. 176 */ 177 boolean isUnixSocket() { 178 return (family == UNIX); 179 } 180 181 // @throws ClosedChannelException if channel is closed 182 private void ensureOpen() throws ClosedChannelException { 183 if (!isOpen()) 184 throw new ClosedChannelException(); 185 } 186 187 @Override 188 public ServerSocket socket() { 189 synchronized (stateLock) { 190 if (socket == null) { 191 if (isNetSocket()) { 192 socket = ServerSocketAdaptor.create(this); 193 } else { 194 throw new UnsupportedOperationException("Not supported"); 195 } 196 } 197 return socket; 198 } 199 } 200 201 @Override 202 public SocketAddress getLocalAddress() throws IOException { 203 synchronized (stateLock) { 204 ensureOpen(); 205 return localAddress; 206 } 207 } 208 209 @Override 210 public <T> ServerSocketChannel setOption(SocketOption<T> name, T value) 211 throws IOException 212 { 213 Objects.requireNonNull(name); 214 if (!supportedOptions().contains(name)) 215 throw new UnsupportedOperationException("'" + name + "' not supported"); 216 if (!name.type().isInstance(value)) 217 throw new IllegalArgumentException("Invalid value '" + value + "'"); 218 219 synchronized (stateLock) { 220 ensureOpen(); 221 if (isNetSocket() 222 && name == StandardSocketOptions.SO_REUSEADDR 223 && Net.useExclusiveBind()) { 224 // SO_REUSEADDR emulated when using exclusive bind 225 isReuseAddress = (Boolean) value; 226 } else { 227 // no options that require special handling 228 Net.setSocketOption(fd, Net.UNSPEC, name, value); 229 } 230 return this; 231 } 232 } 233 234 @Override 235 @SuppressWarnings("unchecked") 236 public <T> T getOption(SocketOption<T> name) 237 throws IOException 238 { 239 Objects.requireNonNull(name); 240 if (!supportedOptions().contains(name)) 241 throw new UnsupportedOperationException("'" + name + "' not supported"); 242 243 synchronized (stateLock) { 244 ensureOpen(); 245 if (isNetSocket() 246 && name == StandardSocketOptions.SO_REUSEADDR 247 && Net.useExclusiveBind()) { 248 // SO_REUSEADDR emulated when using exclusive bind 249 return (T) Boolean.valueOf(isReuseAddress); 250 } else { 251 // no options that require special handling 252 return (T) Net.getSocketOption(fd, Net.UNSPEC, name); 253 } 254 } 255 } 256 257 private static class DefaultOptionsHolder { 258 static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions(); 259 static final Set<SocketOption<?>> defaultUnixDomainOptions = defaultUnixDomainOptions(); 260 261 private static Set<SocketOption<?>> defaultInetOptions() { 262 HashSet<SocketOption<?>> set = new HashSet<>(); 263 set.add(StandardSocketOptions.SO_RCVBUF); 264 set.add(StandardSocketOptions.SO_REUSEADDR); 265 if (Net.isReusePortAvailable()) { 266 set.add(StandardSocketOptions.SO_REUSEPORT); 267 } 268 set.addAll(ExtendedSocketOptions.serverSocketOptions()); 269 return Collections.unmodifiableSet(set); 270 } 271 272 private static Set<SocketOption<?>> defaultUnixDomainOptions() { 273 HashSet<SocketOption<?>> set = new HashSet<>(); 274 set.add(StandardSocketOptions.SO_RCVBUF); 275 return Collections.unmodifiableSet(set); 276 } 277 } 278 279 @Override 280 public final Set<SocketOption<?>> supportedOptions() { 281 if (isUnixSocket()) { 282 return DefaultOptionsHolder.defaultUnixDomainOptions; 283 } else { 284 return DefaultOptionsHolder.defaultInetOptions; 285 } 286 } 287 288 @Override 289 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { 290 synchronized (stateLock) { 291 ensureOpen(); 292 if (localAddress != null) 293 throw new AlreadyBoundException(); 294 if (isUnixSocket()) { 295 localAddress = unixBind(local, backlog); 296 } else { 297 localAddress = netBind(local, backlog); 298 } 299 } 300 return this; 301 } 302 303 private SocketAddress unixBind(SocketAddress local, int backlog) throws IOException { 304 if (local == null) { 305 // Attempt up to 10 times to find an unused name in temp directory. 306 // If local address supplied then bind called only once 307 boolean bound = false; 308 int attempts = 0; 309 while (attempts < 10 && !bound) { 310 try { 311 Path path = UnixDomainSockets.generateTempName().getPath(); 312 UnixDomainSockets.bind(fd, path); 313 bound = true; 314 } catch (BindException e) { } 315 attempts++; 316 } 317 if (!bound) 318 throw new BindException("Could not bind to temporary name"); 319 } else { 320 Path path = UnixDomainSockets.checkAddress(local).getPath(); 321 UnixDomainSockets.bind(fd, path); 322 } 323 Net.listen(fd, backlog < 1 ? 50 : backlog); 324 return UnixDomainSockets.localAddress(fd); 325 } 326 327 private SocketAddress netBind(SocketAddress local, int backlog) throws IOException { 328 InetSocketAddress isa; 329 if (local == null) { 330 isa = new InetSocketAddress(Net.anyLocalAddress(family), 0); 331 } else { 332 isa = Net.checkAddress(local, family); 333 } 334 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); 335 Net.bind(family, fd, isa.getAddress(), isa.getPort()); 336 Net.listen(fd, backlog < 1 ? 50 : backlog); 337 return Net.localAddress(fd); 338 } 339 340 /** 341 * Marks the beginning of an I/O operation that might block. 342 * 343 * @throws ClosedChannelException if the channel is closed 344 * @throws NotYetBoundException if the channel's socket has not been bound yet 345 */ 346 private void begin(boolean blocking) throws ClosedChannelException { 347 if (blocking) 348 begin(); // set blocker to close channel if interrupted 349 synchronized (stateLock) { 350 ensureOpen(); 351 if (localAddress == null) 352 throw new NotYetBoundException(); 353 if (blocking) 354 thread = NativeThread.current(); 355 } 356 } 357 358 /** 359 * Marks the end of an I/O operation that may have blocked. 360 * 361 * @throws AsynchronousCloseException if the channel was closed due to this 362 * thread being interrupted on a blocking I/O operation. 363 */ 364 private void end(boolean blocking, boolean completed) 365 throws AsynchronousCloseException 366 { 367 if (blocking) { 368 synchronized (stateLock) { 369 thread = null; 370 if (state == ST_CLOSING) { 371 tryFinishClose(); 372 } 373 } 374 end(completed); 375 } 376 } 377 378 @Override 379 public SocketChannel accept() throws IOException { 380 int n = 0; 381 FileDescriptor newfd = new FileDescriptor(); 382 SocketAddress[] saa = new SocketAddress[1]; 383 384 acceptLock.lock(); 385 try { 386 ensureOpen(); 387 boolean blocking = isBlocking(); 388 try { 389 begin(blocking); 390 configureSocketNonBlockingIfVirtualThread(); 391 n = implAccept(this.fd, newfd, saa); 392 if (blocking) { 393 while (IOStatus.okayToRetry(n) && isOpen()) { 394 park(Net.POLLIN); 395 n = implAccept(this.fd, newfd, saa); 396 } 397 } 398 } finally { 399 end(blocking, n > 0); 400 assert IOStatus.check(n); 401 } 402 } finally { 403 acceptLock.unlock(); 404 } 405 406 if (n > 0) { 407 return finishAccept(newfd, saa[0]); 408 } else { 409 return null; 410 } 411 } 412 413 private int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] saa) 414 throws IOException 415 { 416 if (isUnixSocket()) { 417 String[] pa = new String[1]; 418 int n = UnixDomainSockets.accept(fd, newfd, pa); 419 if (n > 0) 420 saa[0] = UnixDomainSocketAddress.of(pa[0]); 421 return n; 422 } else { 423 InetSocketAddress[] issa = new InetSocketAddress[1]; 424 int n = Net.accept(fd, newfd, issa); 425 if (n > 0) 426 saa[0] = issa[0]; 427 return n; 428 } 429 } 430 431 /** 432 * Accepts a new connection with a given timeout. This method requires the 433 * channel to be configured in blocking mode. 434 * 435 * @apiNote This method is for use by the socket adaptor. 436 * 437 * @param nanos the timeout, in nanoseconds 438 * @throws IllegalBlockingModeException if the channel is configured non-blocking 439 * @throws SocketTimeoutException if the timeout expires 440 */ 441 SocketChannel blockingAccept(long nanos) throws IOException { 442 int n = 0; 443 FileDescriptor newfd = new FileDescriptor(); 444 SocketAddress[] saa = new SocketAddress[1]; 445 446 acceptLock.lock(); 447 try { 448 // check that channel is configured blocking 449 if (!isBlocking()) 450 throw new IllegalBlockingModeException(); 451 452 try { 453 begin(true); 454 // change socket to non-blocking 455 lockedConfigureBlocking(false); 456 try { 457 long startNanos = System.nanoTime(); 458 n = implAccept(fd, newfd, saa); 459 while (n == IOStatus.UNAVAILABLE && isOpen()) { 460 long remainingNanos = nanos - (System.nanoTime() - startNanos); 461 if (remainingNanos <= 0) { 462 throw new SocketTimeoutException("Accept timed out"); 463 } 464 park(Net.POLLIN, remainingNanos); 465 n = implAccept(fd, newfd, saa); 466 } 467 } finally { 468 // restore socket to blocking mode (if channel is open) 469 tryLockedConfigureBlocking(true); 470 } 471 } finally { 472 end(true, n > 0); 473 } 474 } finally { 475 acceptLock.unlock(); 476 } 477 478 assert n > 0; 479 return finishAccept(newfd, saa[0]); 480 } 481 482 private SocketChannel finishAccept(FileDescriptor newfd, SocketAddress sa) 483 throws IOException 484 { 485 try { 486 // newly accepted socket is initially in blocking mode 487 IOUtil.configureBlocking(newfd, true); 488 return new SocketChannelImpl(provider(), family, newfd, sa); 489 } catch (Exception e) { 490 nd.close(newfd); 491 throw e; 492 } 493 } 494 495 @Override 496 protected void implConfigureBlocking(boolean block) throws IOException { 497 acceptLock.lock(); 498 try { 499 lockedConfigureBlocking(block); 500 } finally { 501 acceptLock.unlock(); 502 } 503 } 504 505 /** 506 * Adjusts the blocking mode. 507 */ 508 private void lockedConfigureBlocking(boolean block) throws IOException { 509 assert acceptLock.isHeldByCurrentThread(); 510 synchronized (stateLock) { 511 ensureOpen(); 512 // do nothing if virtual thread has forced the socket to be non-blocking 513 if (!forcedNonBlocking) { 514 IOUtil.configureBlocking(fd, block); 515 } 516 } 517 } 518 519 /** 520 * Attempts to adjust the blocking mode if the channel is open. 521 * @return {@code true} if the blocking mode was adjusted 522 */ 523 private boolean tryLockedConfigureBlocking(boolean block) throws IOException { 524 assert acceptLock.isHeldByCurrentThread(); 525 synchronized (stateLock) { 526 // do nothing if virtual thread has forced the socket to be non-blocking 527 if (!forcedNonBlocking && isOpen()) { 528 IOUtil.configureBlocking(fd, block); 529 return true; 530 } else { 531 return false; 532 } 533 } 534 } 535 536 /** 537 * Ensures that the socket is configured non-blocking when on a virtual thread. 538 */ 539 private void configureSocketNonBlockingIfVirtualThread() throws IOException { 540 assert acceptLock.isHeldByCurrentThread(); 541 if (!forcedNonBlocking && Thread.currentThread().isVirtual()) { 542 synchronized (stateLock) { 543 ensureOpen(); 544 IOUtil.configureBlocking(fd, false); 545 forcedNonBlocking = true; 546 } 547 } 548 } 549 550 /** 551 * Closes the socket if there are no accept in progress and the channel is 552 * not registered with a Selector. 553 */ 554 private boolean tryClose() throws IOException { 555 assert Thread.holdsLock(stateLock) && state == ST_CLOSING; 556 if ((thread == null) && !isRegistered()) { 557 state = ST_CLOSED; 558 nd.close(fd); 559 return true; 560 } else { 561 return false; 562 } 563 } 564 565 /** 566 * Invokes tryClose to attempt to close the socket. 567 * 568 * This method is used for deferred closing by I/O and Selector operations. 569 */ 570 private void tryFinishClose() { 571 try { 572 tryClose(); 573 } catch (IOException ignore) { } 574 } 575 576 /** 577 * Closes this channel when configured in blocking mode. 578 * 579 * If there is an accept in progress then the socket is pre-closed and the 580 * accept thread is signalled, in which case the final close is deferred 581 * until the accept aborts. 582 */ 583 private void implCloseBlockingMode() throws IOException { 584 synchronized (stateLock) { 585 assert state < ST_CLOSING; 586 state = ST_CLOSING; 587 if (!tryClose()) { 588 nd.preClose(fd, thread, null); 589 } 590 } 591 } 592 593 /** 594 * Closes this channel when configured in non-blocking mode. 595 * 596 * If the channel is registered with a Selector then the close is deferred 597 * until the channel is flushed from all Selectors. 598 */ 599 private void implCloseNonBlockingMode() throws IOException { 600 synchronized (stateLock) { 601 assert state < ST_CLOSING; 602 state = ST_CLOSING; 603 } 604 // wait for any accept to complete before trying to close 605 acceptLock.lock(); 606 acceptLock.unlock(); 607 synchronized (stateLock) { 608 if (state == ST_CLOSING) { 609 tryClose(); 610 } 611 } 612 } 613 614 /** 615 * Invoked by implCloseChannel to close the channel. 616 */ 617 @Override 618 protected void implCloseSelectableChannel() throws IOException { 619 assert !isOpen(); 620 if (isBlocking()) { 621 implCloseBlockingMode(); 622 } else { 623 implCloseNonBlockingMode(); 624 } 625 } 626 627 @Override 628 public void kill() { 629 // wait for any accept operation to complete before trying to close 630 acceptLock.lock(); 631 acceptLock.unlock(); 632 synchronized (stateLock) { 633 if (state == ST_CLOSING) { 634 tryFinishClose(); 635 } 636 } 637 } 638 639 /** 640 * Returns true if channel's socket is bound 641 */ 642 boolean isBound() { 643 synchronized (stateLock) { 644 return localAddress != null; 645 } 646 } 647 648 /** 649 * Returns the local address, or null if not bound 650 */ 651 SocketAddress localAddress() { 652 synchronized (stateLock) { 653 return localAddress; 654 } 655 } 656 657 /** 658 * Translates native poll revent set into a ready operation set 659 */ 660 public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) { 661 int intOps = ski.nioInterestOps(); 662 int oldOps = ski.nioReadyOps(); 663 int newOps = initialOps; 664 665 if ((ops & Net.POLLNVAL) != 0) { 666 // This should only happen if this channel is pre-closed while a 667 // selection operation is in progress 668 // ## Throw an error if this channel has not been pre-closed 669 return false; 670 } 671 672 if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) { 673 newOps = intOps; 674 ski.nioReadyOps(newOps); 675 return (newOps & ~oldOps) != 0; 676 } 677 678 if (((ops & Net.POLLIN) != 0) && 679 ((intOps & SelectionKey.OP_ACCEPT) != 0)) 680 newOps |= SelectionKey.OP_ACCEPT; 681 682 ski.nioReadyOps(newOps); 683 return (newOps & ~oldOps) != 0; 684 } 685 686 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) { 687 return translateReadyOps(ops, ski.nioReadyOps(), ski); 688 } 689 690 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) { 691 return translateReadyOps(ops, 0, ski); 692 } 693 694 /** 695 * Translates an interest operation set into a native poll event set 696 */ 697 public int translateInterestOps(int ops) { 698 int newOps = 0; 699 if ((ops & SelectionKey.OP_ACCEPT) != 0) 700 newOps |= Net.POLLIN; 701 return newOps; 702 } 703 704 public FileDescriptor getFD() { 705 return fd; 706 } 707 708 public int getFDVal() { 709 return fdVal; 710 } 711 712 public String toString() { 713 StringBuilder sb = new StringBuilder(); 714 sb.append(this.getClass().getName()); 715 sb.append('['); 716 if (!isOpen()) { 717 sb.append("closed"); 718 } else { 719 synchronized (stateLock) { 720 SocketAddress addr = localAddress; 721 if (addr == null) { 722 sb.append("unbound"); 723 } else if (isUnixSocket()) { 724 sb.append(addr); 725 } 726 } 727 } 728 sb.append(']'); 729 return sb.toString(); 730 } 731 }