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