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 }