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