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.InetAddress;
31 import java.net.Inet4Address;
32 import java.net.InetSocketAddress;
33 import java.net.ProtocolFamily;
34 import java.net.Socket;
35 import java.net.SocketAddress;
36 import java.net.SocketException;
37 import java.net.SocketOption;
38 import java.net.SocketTimeoutException;
39 import java.net.StandardSocketOptions;
40 import java.nio.ByteBuffer;
41 import java.nio.channels.AlreadyBoundException;
42 import java.nio.channels.AlreadyConnectedException;
43 import java.nio.channels.AsynchronousCloseException;
44 import java.nio.channels.ClosedChannelException;
45 import java.nio.channels.ConnectionPendingException;
46 import java.nio.channels.IllegalBlockingModeException;
47 import java.nio.channels.NoConnectionPendingException;
48 import java.nio.channels.NotYetConnectedException;
49 import java.nio.channels.SelectionKey;
50 import java.nio.channels.SocketChannel;
51 import java.nio.channels.spi.SelectorProvider;
52 import java.nio.file.Path;
53 import java.util.Collections;
54 import java.util.HashSet;
55 import java.util.Set;
56 import java.util.Objects;
57 import java.util.concurrent.locks.ReentrantLock;
58 import static java.net.StandardProtocolFamily.INET;
59 import static java.net.StandardProtocolFamily.INET6;
60 import static java.net.StandardProtocolFamily.UNIX;
61
62 import jdk.internal.event.SocketReadEvent;
63 import jdk.internal.event.SocketWriteEvent;
64 import sun.net.ConnectionResetException;
65 import sun.net.ext.ExtendedSocketOptions;
66 import jdk.internal.util.Exceptions;
67
68 /**
69 * An implementation of SocketChannels
70 */
71
72 class SocketChannelImpl
73 extends SocketChannel
74 implements SelChImpl
75 {
76 // Used to make native read and write calls
77 private static final NativeDispatcher nd = new SocketDispatcher();
78
79 // The protocol family of the socket
80 private final ProtocolFamily family;
81
82 // Our file descriptor object
83 private final FileDescriptor fd;
84 private final int fdVal;
85
86 // Lock held by current reading or connecting thread
87 private final ReentrantLock readLock = new ReentrantLock();
88
89 // Lock held by current writing or connecting thread
90 private final ReentrantLock writeLock = new ReentrantLock();
91
92 // Lock held by any thread that modifies the state fields declared below
93 // DO NOT invoke a blocking I/O operation while holding this lock!
94 private final Object stateLock = new Object();
95
96 // Input/Output closed
97 private volatile boolean isInputClosed;
98 private volatile boolean isOutputClosed;
99
100 // Connection reset protected by readLock
101 private boolean connectionReset;
102
103 // -- The following fields are protected by stateLock
104
105 // set true when exclusive binding is on and SO_REUSEADDR is emulated
106 private boolean isReuseAddress;
107
108 // State, increases monotonically
109 private static final int ST_UNCONNECTED = 0;
110 private static final int ST_CONNECTIONPENDING = 1;
111 private static final int ST_CONNECTED = 2;
112 private static final int ST_CLOSING = 3;
113 private static final int ST_CLOSED = 4;
114 private volatile int state; // need stateLock to change
115
116 // IDs of native threads doing reads and writes, for signalling
117 private long readerThread;
118 private long writerThread;
119
120 // Binding
121 private SocketAddress localAddress;
122 private SocketAddress remoteAddress;
123
124 // Socket adaptor, created on demand
125 private Socket socket;
126
127 // True if the channel's socket has been forced into non-blocking mode
128 // by a virtual thread. It cannot be reset. When the channel is in
129 // blocking mode and the channel's socket is in non-blocking mode then
130 // operations that don't complete immediately will poll the socket and
131 // preserve the semantics of blocking operations.
132 private volatile boolean forcedNonBlocking;
133
134 // -- End of fields protected by stateLock
135
136 SocketChannelImpl(SelectorProvider sp) throws IOException {
137 this(sp, Net.isIPv6Available() ? INET6 : INET);
138 }
139
140 SocketChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException {
141 super(sp);
142 Objects.requireNonNull(family, "'family' is null");
143 if ((family != INET) && (family != INET6) && (family != UNIX)) {
144 throw new UnsupportedOperationException("Protocol family not supported");
145 }
146 if (family == INET6 && !Net.isIPv6Available()) {
147 throw new UnsupportedOperationException("IPv6 not available");
148 }
149
150 this.family = family;
151 if (family == UNIX) {
152 this.fd = UnixDomainSockets.socket();
153 } else {
154 this.fd = Net.socket(family, true);
155 }
156 this.fdVal = IOUtil.fdVal(fd);
157 }
158
159 // Constructor for sockets obtained from server sockets
160 //
161 SocketChannelImpl(SelectorProvider sp,
162 ProtocolFamily family,
163 FileDescriptor fd,
164 SocketAddress remoteAddress)
165 throws IOException
166 {
167 super(sp);
168 this.family = family;
169 this.fd = fd;
170 this.fdVal = IOUtil.fdVal(fd);
171 synchronized (stateLock) {
172 if (family == UNIX) {
173 this.localAddress = UnixDomainSockets.localAddress(fd);
174 } else {
175 this.localAddress = Net.localAddress(fd);
176 }
177 this.remoteAddress = remoteAddress;
178 this.state = ST_CONNECTED;
179 }
180 }
181
182 /**
183 * Returns true if this channel is to a INET or INET6 socket.
184 */
185 boolean isNetSocket() {
186 return (family == INET) || (family == INET6);
187 }
188
189 /**
190 * Returns true if this channel is to a UNIX socket.
191 */
192 boolean isUnixSocket() {
193 return (family == UNIX);
194 }
195
196 /**
197 * Checks that the channel is open.
198 *
199 * @throws ClosedChannelException if channel is closed (or closing)
200 */
201 private void ensureOpen() throws ClosedChannelException {
202 if (!isOpen())
203 throw new ClosedChannelException();
204 }
205
206 /**
207 * Checks that the channel is open and connected.
208 *
209 * @apiNote This method uses the "state" field to check if the channel is
210 * open. It should never be used in conjunction with isOpen or ensureOpen
211 * as these methods check AbstractInterruptibleChannel's closed field - that
212 * field is set before implCloseSelectableChannel is called and so before
213 * the state is changed.
214 *
215 * @throws ClosedChannelException if channel is closed (or closing)
216 * @throws NotYetConnectedException if open and not connected
217 */
218 private void ensureOpenAndConnected() throws ClosedChannelException {
219 int state = this.state;
220 if (state < ST_CONNECTED) {
221 throw new NotYetConnectedException();
222 } else if (state > ST_CONNECTED) {
223 throw new ClosedChannelException();
224 }
225 }
226
227 @Override
228 public Socket socket() {
229 synchronized (stateLock) {
230 if (socket == null) {
231 if (isNetSocket()) {
232 socket = SocketAdaptor.create(this);
233 } else {
234 throw new UnsupportedOperationException("Not supported");
235 }
236 }
237 return socket;
238 }
239 }
240
241 @Override
242 public SocketAddress getLocalAddress() throws IOException {
243 synchronized (stateLock) {
244 ensureOpen();
245 return localAddress;
246 }
247 }
248
249 @Override
250 public SocketAddress getRemoteAddress() throws IOException {
251 synchronized (stateLock) {
252 ensureOpen();
253 return remoteAddress;
254 }
255 }
256
257 @Override
258 public <T> SocketChannel setOption(SocketOption<T> name, T value)
259 throws IOException
260 {
261 Objects.requireNonNull(name);
262 if (!supportedOptions().contains(name))
263 throw new UnsupportedOperationException("'" + name + "' not supported");
264 if (!name.type().isInstance(value))
265 throw new IllegalArgumentException("Invalid value '" + value + "'");
266
267 synchronized (stateLock) {
268 ensureOpen();
269
270 if (isNetSocket()) {
271 if (name == StandardSocketOptions.IP_TOS) {
272 // maps to IPV6_TCLASS and/or IP_TOS
273 Net.setIpSocketOption(fd, family, name, value);
274 return this;
275 }
276 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
277 // SO_REUSEADDR emulated when using exclusive bind
278 isReuseAddress = (Boolean) value;
279 return this;
280 }
281 }
282
283 // no options that require special handling
284 Net.setSocketOption(fd, name, value);
285 return this;
286 }
287 }
288
289 @Override
290 @SuppressWarnings("unchecked")
291 public <T> T getOption(SocketOption<T> name)
292 throws IOException
293 {
294 Objects.requireNonNull(name);
295 if (!supportedOptions().contains(name))
296 throw new UnsupportedOperationException("'" + name + "' not supported");
297
298 synchronized (stateLock) {
299 ensureOpen();
300
301 if (isNetSocket()) {
302 if (name == StandardSocketOptions.IP_TOS) {
303 // special handling for IP_TOS
304 return (T) Net.getSocketOption(fd, family, name);
305 }
306 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
307 // SO_REUSEADDR emulated when using exclusive bind
308 return (T) Boolean.valueOf(isReuseAddress);
309 }
310 }
311
312 // no options that require special handling
313 return (T) Net.getSocketOption(fd, name);
314 }
315 }
316
317 private static class DefaultOptionsHolder {
318 static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions();
319 static final Set<SocketOption<?>> defaultUnixOptions = defaultUnixOptions();
320
321 private static Set<SocketOption<?>> defaultInetOptions() {
322 HashSet<SocketOption<?>> set = new HashSet<>();
323 set.add(StandardSocketOptions.SO_SNDBUF);
324 set.add(StandardSocketOptions.SO_RCVBUF);
325 set.add(StandardSocketOptions.SO_KEEPALIVE);
326 set.add(StandardSocketOptions.SO_REUSEADDR);
327 if (Net.isReusePortAvailable()) {
328 set.add(StandardSocketOptions.SO_REUSEPORT);
329 }
330 set.add(StandardSocketOptions.SO_LINGER);
331 set.add(StandardSocketOptions.TCP_NODELAY);
332 // additional options required by socket adaptor
333 set.add(StandardSocketOptions.IP_TOS);
334 set.add(ExtendedSocketOption.SO_OOBINLINE);
335 set.addAll(ExtendedSocketOptions.clientSocketOptions());
336 return Collections.unmodifiableSet(set);
337 }
338
339 private static Set<SocketOption<?>> defaultUnixOptions() {
340 HashSet<SocketOption<?>> set = new HashSet<>();
341 set.add(StandardSocketOptions.SO_SNDBUF);
342 set.add(StandardSocketOptions.SO_RCVBUF);
343 set.add(StandardSocketOptions.SO_LINGER);
344 set.addAll(ExtendedSocketOptions.unixDomainSocketOptions());
345 return Collections.unmodifiableSet(set);
346 }
347 }
348
349 @Override
350 public final Set<SocketOption<?>> supportedOptions() {
351 if (isUnixSocket()) {
352 return DefaultOptionsHolder.defaultUnixOptions;
353 } else {
354 return DefaultOptionsHolder.defaultInetOptions;
355 }
356 }
357
358 /**
359 * Marks the beginning of a read operation that might block.
360 *
361 * @throws ClosedChannelException if blocking and the channel is closed
362 */
363 private void beginRead(boolean blocking) throws ClosedChannelException {
364 if (blocking) {
365 // set hook for Thread.interrupt
366 begin();
367
368 synchronized (stateLock) {
369 ensureOpen();
370 // record thread so it can be signalled if needed
371 readerThread = NativeThread.current();
372 }
373 }
374 }
375
376 /**
377 * Marks the end of a read operation that may have blocked.
378 *
379 * @throws AsynchronousCloseException if the channel was closed due to this
380 * thread being interrupted on a blocking read operation.
381 */
382 private void endRead(boolean blocking, boolean completed)
383 throws AsynchronousCloseException
384 {
385 if (blocking) {
386 synchronized (stateLock) {
387 readerThread = 0;
388 if (state == ST_CLOSING) {
389 tryFinishClose();
390 }
391 }
392 // remove hook for Thread.interrupt
393 end(completed);
394 }
395 }
396
397 private void throwConnectionReset() throws SocketException {
398 throw new SocketException("Connection reset");
399 }
400
401 private int implRead(ByteBuffer buf) throws IOException {
402 Objects.requireNonNull(buf);
403
404 readLock.lock();
405 try {
406 ensureOpenAndConnected();
407 boolean blocking = isBlocking();
408 int n = 0;
409 try {
410 beginRead(blocking);
411
412 // check if connection has been reset
413 if (connectionReset)
414 throwConnectionReset();
415
416 // check if input is shutdown
417 if (isInputClosed)
418 return IOStatus.EOF;
419
420 configureSocketNonBlockingIfVirtualThread();
421 n = IOUtil.read(fd, buf, -1, nd);
422 if (blocking) {
423 while (IOStatus.okayToRetry(n) && isOpen()) {
424 park(Net.POLLIN);
425 n = IOUtil.read(fd, buf, -1, nd);
426 }
427 }
428 } catch (ConnectionResetException e) {
429 connectionReset = true;
430 throwConnectionReset();
431 } finally {
432 endRead(blocking, n > 0);
433 if (n <= 0 && isInputClosed)
434 return IOStatus.EOF;
435 }
436 return IOStatus.normalize(n);
437 } finally {
438 readLock.unlock();
439 }
440 }
441
442 private long implRead(ByteBuffer[] dsts, int offset, int length)
443 throws IOException
444 {
445 Objects.checkFromIndexSize(offset, length, dsts.length);
446
447 readLock.lock();
448 try {
449 ensureOpenAndConnected();
450 boolean blocking = isBlocking();
451 long n = 0;
452 try {
453 beginRead(blocking);
454
455 // check if connection has been reset
456 if (connectionReset)
457 throwConnectionReset();
458
459 // check if input is shutdown
460 if (isInputClosed)
461 return IOStatus.EOF;
462
463 configureSocketNonBlockingIfVirtualThread();
464 n = IOUtil.read(fd, dsts, offset, length, nd);
465 if (blocking) {
466 while (IOStatus.okayToRetry(n) && isOpen()) {
467 park(Net.POLLIN);
468 n = IOUtil.read(fd, dsts, offset, length, nd);
469 }
470 }
471 } catch (ConnectionResetException e) {
472 connectionReset = true;
473 throwConnectionReset();
474 } finally {
475 endRead(blocking, n > 0);
476 if (n <= 0 && isInputClosed)
477 return IOStatus.EOF;
478 }
479 return IOStatus.normalize(n);
480 } finally {
481 readLock.unlock();
482 }
483 }
484
485 @Override
486 public int read(ByteBuffer buf) throws IOException {
487 if (!SocketReadEvent.enabled()) {
488 return implRead(buf);
489 }
490 long start = SocketReadEvent.timestamp();
491 int nbytes = implRead(buf);
492 SocketReadEvent.offer(start, nbytes, remoteAddress(), 0);
493 return nbytes;
494 }
495
496
497 @Override
498 public long read(ByteBuffer[] dsts, int offset, int length)
499 throws IOException
500 {
501 if (!SocketReadEvent.enabled()) {
502 return implRead(dsts, offset, length);
503 }
504 long start = SocketReadEvent.timestamp();
505 long nbytes = implRead(dsts, offset, length);
506 SocketReadEvent.offer(start, nbytes, remoteAddress(), 0);
507 return nbytes;
508 }
509
510 /**
511 * Marks the beginning of a write operation that might block.
512 *
513 * @throws ClosedChannelException if blocking and the channel is closed
514 */
515 private void beginWrite(boolean blocking) throws ClosedChannelException {
516 if (blocking) {
517 // set hook for Thread.interrupt
518 begin();
519
520 synchronized (stateLock) {
521 ensureOpen();
522 if (isOutputClosed)
523 throw new ClosedChannelException();
524 // record thread so it can be signalled if needed
525 writerThread = NativeThread.current();
526 }
527 }
528 }
529
530 /**
531 * Marks the end of a write operation that may have blocked.
532 *
533 * @throws AsynchronousCloseException if the channel was closed due to this
534 * thread being interrupted on a blocking write operation.
535 */
536 private void endWrite(boolean blocking, boolean completed)
537 throws AsynchronousCloseException
538 {
539 if (blocking) {
540 synchronized (stateLock) {
541 writerThread = 0;
542 if (state == ST_CLOSING) {
543 tryFinishClose();
544 }
545 }
546 // remove hook for Thread.interrupt
547 end(completed);
548 }
549 }
550
551 private int implWrite(ByteBuffer buf) throws IOException {
552 Objects.requireNonNull(buf);
553 writeLock.lock();
554 try {
555 ensureOpenAndConnected();
556 boolean blocking = isBlocking();
557 int n = 0;
558 try {
559 beginWrite(blocking);
560 configureSocketNonBlockingIfVirtualThread();
561 n = IOUtil.write(fd, buf, -1, nd);
562 if (blocking) {
563 while (IOStatus.okayToRetry(n) && isOpen()) {
564 park(Net.POLLOUT);
565 n = IOUtil.write(fd, buf, -1, nd);
566 }
567 }
568 } finally {
569 endWrite(blocking, n > 0);
570 if (n <= 0 && isOutputClosed)
571 throw new AsynchronousCloseException();
572 }
573 return IOStatus.normalize(n);
574 } finally {
575 writeLock.unlock();
576 }
577 }
578
579 private long implWrite(ByteBuffer[] srcs, int offset, int length)
580 throws IOException
581 {
582 Objects.checkFromIndexSize(offset, length, srcs.length);
583
584 writeLock.lock();
585 try {
586 ensureOpenAndConnected();
587 boolean blocking = isBlocking();
588 long n = 0;
589 try {
590 beginWrite(blocking);
591 configureSocketNonBlockingIfVirtualThread();
592 n = IOUtil.write(fd, srcs, offset, length, nd);
593 if (blocking) {
594 while (IOStatus.okayToRetry(n) && isOpen()) {
595 park(Net.POLLOUT);
596 n = IOUtil.write(fd, srcs, offset, length, nd);
597 }
598 }
599 } finally {
600 endWrite(blocking, n > 0);
601 if (n <= 0 && isOutputClosed)
602 throw new AsynchronousCloseException();
603 }
604 return IOStatus.normalize(n);
605 } finally {
606 writeLock.unlock();
607 }
608 }
609
610 @Override
611 public int write(ByteBuffer buf) throws IOException {
612 if (!SocketWriteEvent.enabled()) {
613 return implWrite(buf);
614 }
615 long start = SocketWriteEvent.timestamp();
616 int nbytes = implWrite(buf);
617 SocketWriteEvent.offer(start, nbytes, remoteAddress());
618 return nbytes;
619 }
620
621 @Override
622 public long write(ByteBuffer[] srcs, int offset, int length)
623 throws IOException
624 {
625 if (!SocketWriteEvent.enabled()) {
626 return implWrite(srcs, offset, length);
627 }
628 long start = SocketWriteEvent.timestamp();
629 long nbytes = implWrite(srcs, offset, length);
630 SocketWriteEvent.offer(start, nbytes, remoteAddress());
631 return nbytes;
632 }
633
634 /**
635 * Writes a byte of out of band data.
636 */
637 int sendOutOfBandData(byte b) throws IOException {
638 writeLock.lock();
639 try {
640 ensureOpenAndConnected();
641 boolean blocking = isBlocking();
642 int n = 0;
643 try {
644 beginWrite(blocking);
645 configureSocketNonBlockingIfVirtualThread();
646 do {
647 n = Net.sendOOB(fd, b);
648 } while (n == IOStatus.INTERRUPTED && isOpen());
649 if (blocking && n == IOStatus.UNAVAILABLE) {
650 throw new SocketException("No buffer space available");
651 }
652 } finally {
653 endWrite(blocking, n > 0);
654 if (n <= 0 && isOutputClosed)
655 throw new AsynchronousCloseException();
656 }
657 return IOStatus.normalize(n);
658 } finally {
659 writeLock.unlock();
660 }
661 }
662
663 /**
664 * Marks the beginning of a transfer to this channel.
665 * @throws ClosedChannelException if channel is closed or the output is shutdown
666 * @throws NotYetConnectedException if open and not connected
667 */
668 void beforeTransferTo() throws ClosedChannelException {
669 boolean completed = false;
670 writeLock.lock();
671 try {
672 synchronized (stateLock) {
673 ensureOpenAndConnected();
674 if (isOutputClosed)
675 throw new ClosedChannelException();
676 writerThread = NativeThread.current();
677 completed = true;
678 }
679 } finally {
680 if (!completed) {
681 writeLock.unlock();
682 }
683 }
684 }
685
686 /**
687 * Marks the end of a transfer to this channel.
688 * @throws AsynchronousCloseException if not completed and the channel is closed
689 */
690 void afterTransferTo(boolean completed) throws AsynchronousCloseException {
691 synchronized (stateLock) {
692 writerThread = 0;
693 if (state == ST_CLOSING) {
694 tryFinishClose();
695 }
696 }
697 writeLock.unlock();
698 if (!completed && !isOpen()) {
699 throw new AsynchronousCloseException();
700 }
701 }
702
703 @Override
704 protected void implConfigureBlocking(boolean block) throws IOException {
705 readLock.lock();
706 try {
707 writeLock.lock();
708 try {
709 lockedConfigureBlocking(block);
710 } finally {
711 writeLock.unlock();
712 }
713 } finally {
714 readLock.unlock();
715 }
716 }
717
718 /**
719 * Adjust the blocking mode while holding readLock or writeLock.
720 */
721 private void lockedConfigureBlocking(boolean block) throws IOException {
722 assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
723 synchronized (stateLock) {
724 ensureOpen();
725 // do nothing if virtual thread has forced the socket to be non-blocking
726 if (!forcedNonBlocking) {
727 IOUtil.configureBlocking(fd, block);
728 }
729 }
730 }
731
732 /**
733 * Attempts to adjust the blocking mode if the channel is open.
734 * @return {@code true} if the blocking mode was adjusted
735 */
736 private boolean tryLockedConfigureBlocking(boolean block) throws IOException {
737 assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
738 synchronized (stateLock) {
739 // do nothing if virtual thread has forced the socket to be non-blocking
740 if (!forcedNonBlocking && isOpen()) {
741 IOUtil.configureBlocking(fd, block);
742 return true;
743 } else {
744 return false;
745 }
746 }
747 }
748
749 /**
750 * Ensures that the socket is configured non-blocking when on a virtual thread.
751 */
752 private void configureSocketNonBlockingIfVirtualThread() throws IOException {
753 assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread();
754 if (!forcedNonBlocking && Thread.currentThread().isVirtual()) {
755 synchronized (stateLock) {
756 ensureOpen();
757 IOUtil.configureBlocking(fd, false);
758 forcedNonBlocking = true;
759 }
760 }
761 }
762
763 /**
764 * Returns the local address, or null if not bound
765 */
766 SocketAddress localAddress() {
767 synchronized (stateLock) {
768 return localAddress;
769 }
770 }
771
772 /**
773 * Returns the remote address, or null if not connected
774 */
775 SocketAddress remoteAddress() {
776 synchronized (stateLock) {
777 return remoteAddress;
778 }
779 }
780
781 @Override
782 public SocketChannel bind(SocketAddress local) throws IOException {
783 readLock.lock();
784 try {
785 writeLock.lock();
786 try {
787 synchronized (stateLock) {
788 ensureOpen();
789 if (state == ST_CONNECTIONPENDING)
790 throw new ConnectionPendingException();
791 if (localAddress != null)
792 throw new AlreadyBoundException();
793 if (isUnixSocket()) {
794 localAddress = unixBind(local);
795 } else {
796 localAddress = netBind(local);
797 }
798 }
799 } finally {
800 writeLock.unlock();
801 }
802 } finally {
803 readLock.unlock();
804 }
805 return this;
806 }
807
808 private SocketAddress unixBind(SocketAddress local) throws IOException {
809 if (local == null) {
810 return UnixDomainSockets.unnamed();
811 } else {
812 Path path = UnixDomainSockets.checkAddress(local).getPath();
813 if (path.toString().isEmpty()) {
814 return UnixDomainSockets.unnamed();
815 } else {
816 // bind to non-empty path
817 UnixDomainSockets.bind(fd, path);
818 return UnixDomainSockets.localAddress(fd);
819 }
820 }
821 }
822
823 private SocketAddress netBind(SocketAddress local) throws IOException {
824 InetSocketAddress isa;
825 if (local == null) {
826 isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
827 } else {
828 isa = Net.checkAddress(local, family);
829 }
830 Net.bind(family, fd, isa.getAddress(), isa.getPort());
831 return Net.localAddress(fd);
832 }
833
834 @Override
835 public boolean isConnected() {
836 return (state == ST_CONNECTED);
837 }
838
839 @Override
840 public boolean isConnectionPending() {
841 return (state == ST_CONNECTIONPENDING);
842 }
843
844 /**
845 * Marks the beginning of a connect operation that might block.
846 * @param blocking true if configured blocking
847 * @param sa the remote socket address
848 * @throws ClosedChannelException if the channel is closed
849 * @throws AlreadyConnectedException if already connected
850 * @throws ConnectionPendingException is a connection is pending
851 * @throws IOException if the pre-connect hook fails
852 */
853 private void beginConnect(boolean blocking, SocketAddress sa)
854 throws IOException
855 {
856 if (blocking) {
857 // set hook for Thread.interrupt
858 begin();
859 }
860 synchronized (stateLock) {
861 ensureOpen();
862 int state = this.state;
863 if (state == ST_CONNECTED)
864 throw new AlreadyConnectedException();
865 if (state == ST_CONNECTIONPENDING)
866 throw new ConnectionPendingException();
867 assert state == ST_UNCONNECTED;
868 this.state = ST_CONNECTIONPENDING;
869
870 if (isNetSocket() && (localAddress == null)) {
871 InetSocketAddress isa = (InetSocketAddress) sa;
872 }
873 remoteAddress = sa;
874
875 if (blocking) {
876 // record thread so it can be signalled if needed
877 readerThread = NativeThread.current();
878 }
879 }
880 }
881
882 /**
883 * Marks the end of a connect operation that may have blocked.
884 *
885 * @throws AsynchronousCloseException if the channel was closed due to this
886 * thread being interrupted on a blocking connect operation.
887 * @throws IOException if completed and unable to obtain the local address
888 */
889 private void endConnect(boolean blocking, boolean completed)
890 throws IOException
891 {
892 endRead(blocking, completed);
893
894 if (completed) {
895 synchronized (stateLock) {
896 if (state == ST_CONNECTIONPENDING) {
897 if (isUnixSocket()) {
898 localAddress = UnixDomainSockets.localAddress(fd);
899 } else {
900 localAddress = Net.localAddress(fd);
901 }
902 state = ST_CONNECTED;
903 }
904 }
905 }
906 }
907
908 /**
909 * Checks the remote address to which this channel is to be connected.
910 */
911 private SocketAddress checkRemote(SocketAddress sa) {
912 if (isUnixSocket()) {
913 return UnixDomainSockets.checkAddress(sa);
914 } else {
915 InetSocketAddress isa = Net.checkAddress(sa, family);
916 InetAddress address = isa.getAddress();
917 if (address.isAnyLocalAddress()) {
918 int port = isa.getPort();
919 if (address instanceof Inet4Address) {
920 return new InetSocketAddress(Net.inet4LoopbackAddress(), port);
921 } else {
922 assert family == INET6;
923 return new InetSocketAddress(Net.inet6LoopbackAddress(), port);
924 }
925 } else {
926 return isa;
927 }
928 }
929 }
930
931 @Override
932 public boolean connect(SocketAddress remote) throws IOException {
933 SocketAddress sa = checkRemote(remote);
934 try {
935 readLock.lock();
936 try {
937 writeLock.lock();
938 try {
939 ensureOpen();
940 boolean blocking = isBlocking();
941 boolean connected = false;
942 try {
943 beginConnect(blocking, sa);
944 configureSocketNonBlockingIfVirtualThread();
945 int n;
946 if (isUnixSocket()) {
947 n = UnixDomainSockets.connect(fd, sa);
948 } else {
949 n = Net.connect(family, fd, sa);
950 }
951 if (n > 0) {
952 connected = true;
953 } else if (blocking) {
954 assert IOStatus.okayToRetry(n);
955 boolean polled = false;
956 while (!polled && isOpen()) {
957 park(Net.POLLOUT);
958 polled = Net.pollConnectNow(fd);
959 }
960 connected = polled && isOpen();
961 }
962 } finally {
963 endConnect(blocking, connected);
964 }
965 return connected;
966 } finally {
967 writeLock.unlock();
968 }
969 } finally {
970 readLock.unlock();
971 }
972 } catch (IOException ioe) {
973 // connect failed, close the channel
974 close();
975 throw Exceptions.ioException(ioe, sa);
976 }
977 }
978
979 /**
980 * Marks the beginning of a finishConnect operation that might block.
981 *
982 * @throws ClosedChannelException if the channel is closed
983 * @throws NoConnectionPendingException if no connection is pending
984 */
985 private void beginFinishConnect(boolean blocking) throws ClosedChannelException {
986 if (blocking) {
987 // set hook for Thread.interrupt
988 begin();
989 }
990 synchronized (stateLock) {
991 ensureOpen();
992 if (state != ST_CONNECTIONPENDING)
993 throw new NoConnectionPendingException();
994 if (blocking) {
995 // record thread so it can be signalled if needed
996 readerThread = NativeThread.current();
997 }
998 }
999 }
1000
1001 /**
1002 * Marks the end of a finishConnect operation that may have blocked.
1003 *
1004 * @throws AsynchronousCloseException if the channel was closed due to this
1005 * thread being interrupted on a blocking connect operation.
1006 * @throws IOException if completed and unable to obtain the local address
1007 */
1008 private void endFinishConnect(boolean blocking, boolean completed)
1009 throws IOException
1010 {
1011 endRead(blocking, completed);
1012
1013 if (completed) {
1014 synchronized (stateLock) {
1015 if (state == ST_CONNECTIONPENDING) {
1016 if (isUnixSocket()) {
1017 localAddress = UnixDomainSockets.localAddress(fd);
1018 } else {
1019 localAddress = Net.localAddress(fd);
1020 }
1021 state = ST_CONNECTED;
1022 }
1023 }
1024 }
1025 }
1026
1027 @Override
1028 public boolean finishConnect() throws IOException {
1029 try {
1030 readLock.lock();
1031 try {
1032 writeLock.lock();
1033 try {
1034 // no-op if already connected
1035 if (isConnected())
1036 return true;
1037
1038 ensureOpen();
1039 boolean blocking = isBlocking();
1040 boolean connected = false;
1041 try {
1042 beginFinishConnect(blocking);
1043 boolean polled = Net.pollConnectNow(fd);
1044 if (blocking) {
1045 while (!polled && isOpen()) {
1046 park(Net.POLLOUT);
1047 polled = Net.pollConnectNow(fd);
1048 }
1049 }
1050 connected = polled && isOpen();
1051 } finally {
1052 endFinishConnect(blocking, connected);
1053 }
1054 assert (blocking && connected) ^ !blocking;
1055 return connected;
1056 } finally {
1057 writeLock.unlock();
1058 }
1059 } finally {
1060 readLock.unlock();
1061 }
1062 } catch (IOException ioe) {
1063 // connect failed, close the channel
1064 close();
1065 throw Exceptions.ioException(ioe, remoteAddress);
1066 }
1067 }
1068
1069 /**
1070 * Closes the socket if there are no I/O operations in progress (or no I/O
1071 * operations tracked), and the channel is not registered with a Selector.
1072 */
1073 private boolean tryClose() throws IOException {
1074 assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
1075 if ((readerThread == 0) && (writerThread == 0) && !isRegistered()) {
1076 state = ST_CLOSED;
1077 nd.close(fd);
1078 return true;
1079 } else {
1080 return false;
1081 }
1082 }
1083
1084 /**
1085 * Invokes tryClose to attempt to close the socket.
1086 *
1087 * This method is used for deferred closing by I/O and Selector operations.
1088 */
1089 private void tryFinishClose() {
1090 try {
1091 tryClose();
1092 } catch (IOException ignore) { }
1093 }
1094
1095 /**
1096 * Closes this channel when configured in blocking mode. If there are no I/O
1097 * operations in progress (or tracked), then the channel's socket is closed. If
1098 * there are I/O operations in progress then the behavior is platform specific.
1099 *
1100 * On Unix systems, the channel's socket is pre-closed. This unparks any virtual
1101 * threads that are blocked in I/O operations on this channel. If there are
1102 * platform threads blocked on the channel's socket then the socket is dup'ed
1103 * and the platform threads signalled. The final close is deferred until all I/O
1104 * operations complete.
1105 *
1106 * On Windows, the channel's socket is pre-closed. This unparks any virtual
1107 * threads that are blocked in I/O operations on this channel. If there are no
1108 * virtual threads blocked in I/O operations on this channel then the channel's
1109 * socket is closed. If there are virtual threads in I/O then the final close is
1110 * deferred until all I/O operations on virtual threads complete.
1111 *
1112 * Note that a channel configured blocking may be registered with a Selector
1113 * This arises when a key is canceled and the channel configured to blocking
1114 * mode before the key is flushed from the Selector.
1115 */
1116 private void implCloseBlockingMode() throws IOException {
1117 synchronized (stateLock) {
1118 assert state < ST_CLOSING;
1119 boolean connected = (state == ST_CONNECTED);
1120 state = ST_CLOSING;
1121
1122 if (connected && Net.shouldShutdownWriteBeforeClose()) {
1123 // shutdown output when linger interval not set to 0
1124 try {
1125 var SO_LINGER = StandardSocketOptions.SO_LINGER;
1126 if ((int) Net.getSocketOption(fd, SO_LINGER) != 0) {
1127 Net.shutdown(fd, Net.SHUT_WR);
1128 }
1129 } catch (IOException ignore) { }
1130 }
1131
1132 if (!tryClose()) {
1133 // prepare file descriptor for closing
1134 nd.preClose(fd, readerThread, writerThread);
1135 }
1136 }
1137 }
1138
1139 /**
1140 * Closes this channel when configured in non-blocking mode.
1141 *
1142 * If the channel is registered with a Selector then the close is deferred
1143 * until the channel is flushed from all Selectors.
1144 *
1145 * If the socket is connected and the channel is registered with a Selector
1146 * then the socket is shutdown for writing so that the peer reads EOF. In
1147 * addition, if SO_LINGER is set to a non-zero value then it is disabled so
1148 * that the deferred close does not wait.
1149 */
1150 private void implCloseNonBlockingMode() throws IOException {
1151 boolean connected;
1152 synchronized (stateLock) {
1153 assert state < ST_CLOSING;
1154 connected = (state == ST_CONNECTED);
1155 state = ST_CLOSING;
1156 }
1157
1158 // wait for any read/write operations to complete
1159 readLock.lock();
1160 readLock.unlock();
1161 writeLock.lock();
1162 writeLock.unlock();
1163
1164 // if the socket cannot be closed because it's registered with a Selector
1165 // then shutdown the socket for writing.
1166 synchronized (stateLock) {
1167 if (state == ST_CLOSING && !tryClose() && connected && isRegistered()) {
1168 try {
1169 SocketOption<Integer> opt = StandardSocketOptions.SO_LINGER;
1170 int interval = (int) Net.getSocketOption(fd, Net.UNSPEC, opt);
1171 if (interval != 0) {
1172 if (interval > 0) {
1173 // disable SO_LINGER
1174 Net.setSocketOption(fd, Net.UNSPEC, opt, -1);
1175 }
1176 Net.shutdown(fd, Net.SHUT_WR);
1177 }
1178 } catch (IOException ignore) { }
1179 }
1180 }
1181 }
1182
1183 /**
1184 * Invoked by implCloseChannel to close the channel.
1185 */
1186 @Override
1187 protected void implCloseSelectableChannel() throws IOException {
1188 assert !isOpen();
1189 if (isBlocking()) {
1190 implCloseBlockingMode();
1191 } else {
1192 implCloseNonBlockingMode();
1193 }
1194 }
1195
1196 @Override
1197 public void kill() {
1198 // wait for any read/write operations to complete before trying to close
1199 readLock.lock();
1200 readLock.unlock();
1201 writeLock.lock();
1202 writeLock.unlock();
1203 synchronized (stateLock) {
1204 if (state == ST_CLOSING) {
1205 tryFinishClose();
1206 }
1207 }
1208 }
1209
1210 @Override
1211 public SocketChannel shutdownInput() throws IOException {
1212 synchronized (stateLock) {
1213 ensureOpen();
1214 if (!isConnected())
1215 throw new NotYetConnectedException();
1216 if (!isInputClosed) {
1217 Net.shutdown(fd, Net.SHUT_RD);
1218 long reader = readerThread;
1219 if (NativeThread.isVirtualThread(reader)) {
1220 Poller.stopPoll(fdVal, Net.POLLIN);
1221 } else if (NativeThread.isNativeThread(reader)) {
1222 NativeThread.signal(reader);
1223 }
1224 isInputClosed = true;
1225 }
1226 return this;
1227 }
1228 }
1229
1230 @Override
1231 public SocketChannel shutdownOutput() throws IOException {
1232 synchronized (stateLock) {
1233 ensureOpen();
1234 if (!isConnected())
1235 throw new NotYetConnectedException();
1236 if (!isOutputClosed) {
1237 Net.shutdown(fd, Net.SHUT_WR);
1238 long writer = writerThread;
1239 if (NativeThread.isVirtualThread(writer)) {
1240 Poller.stopPoll(fdVal, Net.POLLOUT);
1241 } else if (NativeThread.isNativeThread(writer)) {
1242 NativeThread.signal(writer);
1243 }
1244 isOutputClosed = true;
1245 }
1246 return this;
1247 }
1248 }
1249
1250 boolean isInputOpen() {
1251 return !isInputClosed;
1252 }
1253
1254 boolean isOutputOpen() {
1255 return !isOutputClosed;
1256 }
1257
1258 /**
1259 * Waits for a connection attempt to finish with a timeout
1260 * @throws SocketTimeoutException if the connect timeout elapses
1261 */
1262 private boolean finishTimedConnect(long nanos) throws IOException {
1263 long startNanos = System.nanoTime();
1264 boolean polled = Net.pollConnectNow(fd);
1265 while (!polled && isOpen()) {
1266 long remainingNanos = nanos - (System.nanoTime() - startNanos);
1267 if (remainingNanos <= 0) {
1268 throw new SocketTimeoutException("Connect timed out");
1269 }
1270 park(Net.POLLOUT, remainingNanos);
1271 polled = Net.pollConnectNow(fd);
1272 }
1273 return polled && isOpen();
1274 }
1275
1276 /**
1277 * Attempts to establish a connection to the given socket address with a
1278 * timeout. Closes the socket if connection cannot be established.
1279 *
1280 * @apiNote This method is for use by the socket adaptor.
1281 *
1282 * @throws IllegalBlockingModeException if the channel is non-blocking
1283 * @throws SocketTimeoutException if the read timeout elapses
1284 */
1285 void blockingConnect(SocketAddress remote, long nanos) throws IOException {
1286 SocketAddress sa = checkRemote(remote);
1287 try {
1288 readLock.lock();
1289 try {
1290 writeLock.lock();
1291 try {
1292 if (!isBlocking())
1293 throw new IllegalBlockingModeException();
1294 boolean connected = false;
1295 try {
1296 beginConnect(true, sa);
1297 // change socket to non-blocking
1298 lockedConfigureBlocking(false);
1299 try {
1300 int n;
1301 if (isUnixSocket()) {
1302 n = UnixDomainSockets.connect(fd, sa);
1303 } else {
1304 n = Net.connect(family, fd, sa);
1305 }
1306 connected = (n > 0) ? true : finishTimedConnect(nanos);
1307 } finally {
1308 // restore socket to blocking mode (if channel is open)
1309 tryLockedConfigureBlocking(true);
1310 }
1311 } finally {
1312 endConnect(true, connected);
1313 }
1314 } finally {
1315 writeLock.unlock();
1316 }
1317 } finally {
1318 readLock.unlock();
1319 }
1320 } catch (IOException ioe) {
1321 // connect failed, close the channel
1322 close();
1323 throw Exceptions.ioException(ioe, sa);
1324 }
1325 }
1326
1327 /**
1328 * Attempts to read bytes from the socket into the given byte array.
1329 */
1330 private int tryRead(byte[] b, int off, int len) throws IOException {
1331 ByteBuffer dst = Util.getTemporaryDirectBuffer(len);
1332 assert dst.position() == 0;
1333 try {
1334 int n = nd.read(fd, ((DirectBuffer)dst).address(), len);
1335 if (n > 0) {
1336 dst.get(b, off, n);
1337 }
1338 return n;
1339 } finally{
1340 Util.offerFirstTemporaryDirectBuffer(dst);
1341 }
1342 }
1343
1344 /**
1345 * Reads bytes from the socket into the given byte array with a timeout.
1346 * @throws SocketTimeoutException if the read timeout elapses
1347 */
1348 private int timedRead(byte[] b, int off, int len, long nanos) throws IOException {
1349 long startNanos = System.nanoTime();
1350 int n = tryRead(b, off, len);
1351 while (n == IOStatus.UNAVAILABLE && isOpen()) {
1352 long remainingNanos = nanos - (System.nanoTime() - startNanos);
1353 if (remainingNanos <= 0) {
1354 throw new SocketTimeoutException("Read timed out");
1355 }
1356 park(Net.POLLIN, remainingNanos);
1357 n = tryRead(b, off, len);
1358 }
1359 return n;
1360 }
1361
1362 /**
1363 * Reads bytes from the socket into the given byte array.
1364 *
1365 * @apiNote This method is for use by the socket adaptor.
1366 *
1367 * @throws IllegalBlockingModeException if the channel is non-blocking
1368 * @throws SocketTimeoutException if the read timeout elapses
1369 */
1370 int blockingRead(byte[] b, int off, int len, long nanos) throws IOException {
1371 Objects.checkFromIndexSize(off, len, b.length);
1372 if (len == 0) {
1373 // nothing to do
1374 return 0;
1375 }
1376
1377 readLock.lock();
1378 try {
1379 ensureOpenAndConnected();
1380
1381 // check that channel is configured blocking
1382 if (!isBlocking())
1383 throw new IllegalBlockingModeException();
1384
1385 int n = 0;
1386 try {
1387 beginRead(true);
1388
1389 // check if connection has been reset
1390 if (connectionReset)
1391 throwConnectionReset();
1392
1393 // check if input is shutdown
1394 if (isInputClosed)
1395 return IOStatus.EOF;
1396
1397 if (nanos > 0) {
1398 // change socket to non-blocking
1399 lockedConfigureBlocking(false);
1400 try {
1401 n = timedRead(b, off, len, nanos);
1402 } finally {
1403 // restore socket to blocking mode (if channel is open)
1404 tryLockedConfigureBlocking(true);
1405 }
1406 } else {
1407 // read, no timeout
1408 configureSocketNonBlockingIfVirtualThread();
1409 n = tryRead(b, off, len);
1410 while (IOStatus.okayToRetry(n) && isOpen()) {
1411 park(Net.POLLIN);
1412 n = tryRead(b, off, len);
1413 }
1414 }
1415 } catch (ConnectionResetException e) {
1416 connectionReset = true;
1417 throwConnectionReset();
1418 } finally {
1419 endRead(true, n > 0);
1420 if (n <= 0 && isInputClosed)
1421 return IOStatus.EOF;
1422 }
1423 assert n > 0 || n == -1;
1424 return n;
1425 } finally {
1426 readLock.unlock();
1427 }
1428 }
1429
1430 /**
1431 * Attempts to write a sequence of bytes to the socket from the given
1432 * byte array.
1433 */
1434 private int tryWrite(byte[] b, int off, int len) throws IOException {
1435 ByteBuffer src = Util.getTemporaryDirectBuffer(len);
1436 assert src.position() == 0;
1437 try {
1438 src.put(b, off, len);
1439 return nd.write(fd, ((DirectBuffer)src).address(), len);
1440 } finally {
1441 Util.offerFirstTemporaryDirectBuffer(src);
1442 }
1443 }
1444
1445 /**
1446 * Writes a sequence of bytes to the socket from the given byte array.
1447 *
1448 * @apiNote This method is for use by the socket adaptor.
1449 */
1450 void blockingWriteFully(byte[] b, int off, int len) throws IOException {
1451 Objects.checkFromIndexSize(off, len, b.length);
1452 if (len == 0) {
1453 // nothing to do
1454 return;
1455 }
1456
1457 writeLock.lock();
1458 try {
1459 ensureOpenAndConnected();
1460
1461 // check that channel is configured blocking
1462 if (!isBlocking())
1463 throw new IllegalBlockingModeException();
1464
1465 // loop until all bytes have been written
1466 int pos = off;
1467 int end = off + len;
1468 try {
1469 beginWrite(true);
1470 configureSocketNonBlockingIfVirtualThread();
1471 while (pos < end && isOpen()) {
1472 int size = end - pos;
1473 int n = tryWrite(b, pos, size);
1474 while (IOStatus.okayToRetry(n) && isOpen()) {
1475 park(Net.POLLOUT);
1476 n = tryWrite(b, pos, size);
1477 }
1478 if (n > 0) {
1479 pos += n;
1480 }
1481 }
1482 } finally {
1483 endWrite(true, pos >= end);
1484 }
1485 } finally {
1486 writeLock.unlock();
1487 }
1488 }
1489
1490 /**
1491 * Return the number of bytes in the socket input buffer.
1492 */
1493 int available() throws IOException {
1494 synchronized (stateLock) {
1495 ensureOpenAndConnected();
1496 if (isInputClosed) {
1497 return 0;
1498 } else {
1499 return Net.available(fd);
1500 }
1501 }
1502 }
1503
1504 /**
1505 * Translates native poll revent ops into a ready operation ops
1506 */
1507 public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
1508 int intOps = ski.nioInterestOps();
1509 int oldOps = ski.nioReadyOps();
1510 int newOps = initialOps;
1511
1512 if ((ops & Net.POLLNVAL) != 0) {
1513 // This should only happen if this channel is pre-closed while a
1514 // selection operation is in progress
1515 // ## Throw an error if this channel has not been pre-closed
1516 return false;
1517 }
1518
1519 if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
1520 newOps = intOps;
1521 ski.nioReadyOps(newOps);
1522 return (newOps & ~oldOps) != 0;
1523 }
1524
1525 boolean connected = isConnected();
1526 if (((ops & Net.POLLIN) != 0) &&
1527 ((intOps & SelectionKey.OP_READ) != 0) && connected)
1528 newOps |= SelectionKey.OP_READ;
1529
1530 if (((ops & Net.POLLCONN) != 0) &&
1531 ((intOps & SelectionKey.OP_CONNECT) != 0) && isConnectionPending())
1532 newOps |= SelectionKey.OP_CONNECT;
1533
1534 if (((ops & Net.POLLOUT) != 0) &&
1535 ((intOps & SelectionKey.OP_WRITE) != 0) && connected)
1536 newOps |= SelectionKey.OP_WRITE;
1537
1538 ski.nioReadyOps(newOps);
1539 return (newOps & ~oldOps) != 0;
1540 }
1541
1542 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
1543 return translateReadyOps(ops, ski.nioReadyOps(), ski);
1544 }
1545
1546 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
1547 return translateReadyOps(ops, 0, ski);
1548 }
1549
1550 /**
1551 * Translates an interest operation set into a native poll event set
1552 */
1553 public int translateInterestOps(int ops) {
1554 int newOps = 0;
1555 if ((ops & SelectionKey.OP_READ) != 0)
1556 newOps |= Net.POLLIN;
1557 if ((ops & SelectionKey.OP_WRITE) != 0)
1558 newOps |= Net.POLLOUT;
1559 if ((ops & SelectionKey.OP_CONNECT) != 0)
1560 newOps |= Net.POLLCONN;
1561 return newOps;
1562 }
1563
1564 public FileDescriptor getFD() {
1565 return fd;
1566 }
1567
1568 public int getFDVal() {
1569 return fdVal;
1570 }
1571
1572 @Override
1573 public String toString() {
1574 StringBuilder sb = new StringBuilder();
1575 sb.append(this.getClass().getSuperclass().getName());
1576 sb.append('[');
1577 if (!isOpen())
1578 sb.append("closed");
1579 else {
1580 synchronized (stateLock) {
1581 switch (state) {
1582 case ST_UNCONNECTED:
1583 sb.append("unconnected");
1584 break;
1585 case ST_CONNECTIONPENDING:
1586 sb.append("connection-pending");
1587 break;
1588 case ST_CONNECTED:
1589 sb.append("connected");
1590 if (isInputClosed)
1591 sb.append(" ishut");
1592 if (isOutputClosed)
1593 sb.append(" oshut");
1594 break;
1595 }
1596 SocketAddress addr = localAddress();
1597 if (addr != null) {
1598 sb.append(" local=");
1599 sb.append(addr);
1600 }
1601 if (remoteAddress() != null) {
1602 sb.append(" remote=");
1603 sb.append(remoteAddress());
1604 }
1605 }
1606 }
1607 sb.append(']');
1608 return sb.toString();
1609 }
1610 }