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 // Thread currently blocked in this channel, for signalling
95 private Thread 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.threadToSignal();
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 }