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 // Threads doing reads and writes, for signalling
117 private Thread readerThread;
118 private Thread 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.threadToSignal();
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 = null;
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.threadToSignal();
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 = null;
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.threadToSignal();
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 = null;
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.threadToSignal();
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.threadToSignal();
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 == null) && (writerThread == null) && !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 if (readerThread != null && readerThread.isVirtual()) {
1219 Poller.stopPoll(readerThread);
1220 }
1221 isInputClosed = true;
1222 }
1223 return this;
1224 }
1225 }
1226
1227 @Override
1228 public SocketChannel shutdownOutput() throws IOException {
1229 synchronized (stateLock) {
1230 ensureOpen();
1231 if (!isConnected())
1232 throw new NotYetConnectedException();
1233 if (!isOutputClosed) {
1234 Net.shutdown(fd, Net.SHUT_WR);
1235 if (writerThread != null && writerThread.isVirtual()) {
1236 Poller.stopPoll(writerThread);
1237 }
1238 isOutputClosed = true;
1239 }
1240 return this;
1241 }
1242 }
1243
1244 boolean isInputOpen() {
1245 return !isInputClosed;
1246 }
1247
1248 boolean isOutputOpen() {
1249 return !isOutputClosed;
1250 }
1251
1252 /**
1253 * Waits for a connection attempt to finish with a timeout
1254 * @throws SocketTimeoutException if the connect timeout elapses
1255 */
1256 private boolean finishTimedConnect(long nanos) throws IOException {
1257 long startNanos = System.nanoTime();
1258 boolean polled = Net.pollConnectNow(fd);
1259 while (!polled && isOpen()) {
1260 long remainingNanos = nanos - (System.nanoTime() - startNanos);
1261 if (remainingNanos <= 0) {
1262 throw new SocketTimeoutException("Connect timed out");
1263 }
1264 park(Net.POLLOUT, remainingNanos);
1265 polled = Net.pollConnectNow(fd);
1266 }
1267 return polled && isOpen();
1268 }
1269
1270 /**
1271 * Attempts to establish a connection to the given socket address with a
1272 * timeout. Closes the socket if connection cannot be established.
1273 *
1274 * @apiNote This method is for use by the socket adaptor.
1275 *
1276 * @throws IllegalBlockingModeException if the channel is non-blocking
1277 * @throws SocketTimeoutException if the read timeout elapses
1278 */
1279 void blockingConnect(SocketAddress remote, long nanos) throws IOException {
1280 SocketAddress sa = checkRemote(remote);
1281 try {
1282 readLock.lock();
1283 try {
1284 writeLock.lock();
1285 try {
1286 if (!isBlocking())
1287 throw new IllegalBlockingModeException();
1288 boolean connected = false;
1289 try {
1290 beginConnect(true, sa);
1291 // change socket to non-blocking
1292 lockedConfigureBlocking(false);
1293 try {
1294 int n;
1295 if (isUnixSocket()) {
1296 n = UnixDomainSockets.connect(fd, sa);
1297 } else {
1298 n = Net.connect(family, fd, sa);
1299 }
1300 connected = (n > 0) ? true : finishTimedConnect(nanos);
1301 } finally {
1302 // restore socket to blocking mode (if channel is open)
1303 tryLockedConfigureBlocking(true);
1304 }
1305 } finally {
1306 endConnect(true, connected);
1307 }
1308 } finally {
1309 writeLock.unlock();
1310 }
1311 } finally {
1312 readLock.unlock();
1313 }
1314 } catch (IOException ioe) {
1315 // connect failed, close the channel
1316 close();
1317 throw Exceptions.ioException(ioe, sa);
1318 }
1319 }
1320
1321 /**
1322 * Attempts to read bytes from the socket into the given byte array.
1323 */
1324 private int tryRead(byte[] b, int off, int len) throws IOException {
1325 ByteBuffer dst = Util.getTemporaryDirectBuffer(len);
1326 assert dst.position() == 0;
1327 try {
1328 int n = nd.read(fd, ((DirectBuffer)dst).address(), len);
1329 if (n > 0) {
1330 dst.get(b, off, n);
1331 }
1332 return n;
1333 } finally{
1334 Util.offerFirstTemporaryDirectBuffer(dst);
1335 }
1336 }
1337
1338 /**
1339 * Reads bytes from the socket into the given byte array with a timeout.
1340 * @throws SocketTimeoutException if the read timeout elapses
1341 */
1342 private int timedRead(byte[] b, int off, int len, long nanos) throws IOException {
1343 long startNanos = System.nanoTime();
1344 int n = tryRead(b, off, len);
1345 while (n == IOStatus.UNAVAILABLE && isOpen()) {
1346 long remainingNanos = nanos - (System.nanoTime() - startNanos);
1347 if (remainingNanos <= 0) {
1348 throw new SocketTimeoutException("Read timed out");
1349 }
1350 park(Net.POLLIN, remainingNanos);
1351 n = tryRead(b, off, len);
1352 }
1353 return n;
1354 }
1355
1356 /**
1357 * Reads bytes from the socket into the given byte array.
1358 *
1359 * @apiNote This method is for use by the socket adaptor.
1360 *
1361 * @throws IllegalBlockingModeException if the channel is non-blocking
1362 * @throws SocketTimeoutException if the read timeout elapses
1363 */
1364 int blockingRead(byte[] b, int off, int len, long nanos) throws IOException {
1365 Objects.checkFromIndexSize(off, len, b.length);
1366 if (len == 0) {
1367 // nothing to do
1368 return 0;
1369 }
1370
1371 readLock.lock();
1372 try {
1373 ensureOpenAndConnected();
1374
1375 // check that channel is configured blocking
1376 if (!isBlocking())
1377 throw new IllegalBlockingModeException();
1378
1379 int n = 0;
1380 try {
1381 beginRead(true);
1382
1383 // check if connection has been reset
1384 if (connectionReset)
1385 throwConnectionReset();
1386
1387 // check if input is shutdown
1388 if (isInputClosed)
1389 return IOStatus.EOF;
1390
1391 if (nanos > 0) {
1392 // change socket to non-blocking
1393 lockedConfigureBlocking(false);
1394 try {
1395 n = timedRead(b, off, len, nanos);
1396 } finally {
1397 // restore socket to blocking mode (if channel is open)
1398 tryLockedConfigureBlocking(true);
1399 }
1400 } else {
1401 // read, no timeout
1402 configureSocketNonBlockingIfVirtualThread();
1403 n = tryRead(b, off, len);
1404 while (IOStatus.okayToRetry(n) && isOpen()) {
1405 park(Net.POLLIN);
1406 n = tryRead(b, off, len);
1407 }
1408 }
1409 } catch (ConnectionResetException e) {
1410 connectionReset = true;
1411 throwConnectionReset();
1412 } finally {
1413 endRead(true, n > 0);
1414 if (n <= 0 && isInputClosed)
1415 return IOStatus.EOF;
1416 }
1417 assert n > 0 || n == -1;
1418 return n;
1419 } finally {
1420 readLock.unlock();
1421 }
1422 }
1423
1424 /**
1425 * Attempts to write a sequence of bytes to the socket from the given
1426 * byte array.
1427 */
1428 private int tryWrite(byte[] b, int off, int len) throws IOException {
1429 ByteBuffer src = Util.getTemporaryDirectBuffer(len);
1430 assert src.position() == 0;
1431 try {
1432 src.put(b, off, len);
1433 return nd.write(fd, ((DirectBuffer)src).address(), len);
1434 } finally {
1435 Util.offerFirstTemporaryDirectBuffer(src);
1436 }
1437 }
1438
1439 /**
1440 * Writes a sequence of bytes to the socket from the given byte array.
1441 *
1442 * @apiNote This method is for use by the socket adaptor.
1443 */
1444 void blockingWriteFully(byte[] b, int off, int len) throws IOException {
1445 Objects.checkFromIndexSize(off, len, b.length);
1446 if (len == 0) {
1447 // nothing to do
1448 return;
1449 }
1450
1451 writeLock.lock();
1452 try {
1453 ensureOpenAndConnected();
1454
1455 // check that channel is configured blocking
1456 if (!isBlocking())
1457 throw new IllegalBlockingModeException();
1458
1459 // loop until all bytes have been written
1460 int pos = off;
1461 int end = off + len;
1462 try {
1463 beginWrite(true);
1464 configureSocketNonBlockingIfVirtualThread();
1465 while (pos < end && isOpen()) {
1466 int size = end - pos;
1467 int n = tryWrite(b, pos, size);
1468 while (IOStatus.okayToRetry(n) && isOpen()) {
1469 park(Net.POLLOUT);
1470 n = tryWrite(b, pos, size);
1471 }
1472 if (n > 0) {
1473 pos += n;
1474 }
1475 }
1476 } finally {
1477 endWrite(true, pos >= end);
1478 }
1479 } finally {
1480 writeLock.unlock();
1481 }
1482 }
1483
1484 /**
1485 * Return the number of bytes in the socket input buffer.
1486 */
1487 int available() throws IOException {
1488 synchronized (stateLock) {
1489 ensureOpenAndConnected();
1490 if (isInputClosed) {
1491 return 0;
1492 } else {
1493 return Net.available(fd);
1494 }
1495 }
1496 }
1497
1498 /**
1499 * Translates native poll revent ops into a ready operation ops
1500 */
1501 public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
1502 int intOps = ski.nioInterestOps();
1503 int oldOps = ski.nioReadyOps();
1504 int newOps = initialOps;
1505
1506 if ((ops & Net.POLLNVAL) != 0) {
1507 // This should only happen if this channel is pre-closed while a
1508 // selection operation is in progress
1509 // ## Throw an error if this channel has not been pre-closed
1510 return false;
1511 }
1512
1513 if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
1514 newOps = intOps;
1515 ski.nioReadyOps(newOps);
1516 return (newOps & ~oldOps) != 0;
1517 }
1518
1519 boolean connected = isConnected();
1520 if (((ops & Net.POLLIN) != 0) &&
1521 ((intOps & SelectionKey.OP_READ) != 0) && connected)
1522 newOps |= SelectionKey.OP_READ;
1523
1524 if (((ops & Net.POLLCONN) != 0) &&
1525 ((intOps & SelectionKey.OP_CONNECT) != 0) && isConnectionPending())
1526 newOps |= SelectionKey.OP_CONNECT;
1527
1528 if (((ops & Net.POLLOUT) != 0) &&
1529 ((intOps & SelectionKey.OP_WRITE) != 0) && connected)
1530 newOps |= SelectionKey.OP_WRITE;
1531
1532 ski.nioReadyOps(newOps);
1533 return (newOps & ~oldOps) != 0;
1534 }
1535
1536 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
1537 return translateReadyOps(ops, ski.nioReadyOps(), ski);
1538 }
1539
1540 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
1541 return translateReadyOps(ops, 0, ski);
1542 }
1543
1544 /**
1545 * Translates an interest operation set into a native poll event set
1546 */
1547 public int translateInterestOps(int ops) {
1548 int newOps = 0;
1549 if ((ops & SelectionKey.OP_READ) != 0)
1550 newOps |= Net.POLLIN;
1551 if ((ops & SelectionKey.OP_WRITE) != 0)
1552 newOps |= Net.POLLOUT;
1553 if ((ops & SelectionKey.OP_CONNECT) != 0)
1554 newOps |= Net.POLLCONN;
1555 return newOps;
1556 }
1557
1558 public FileDescriptor getFD() {
1559 return fd;
1560 }
1561
1562 public int getFDVal() {
1563 return fdVal;
1564 }
1565
1566 @Override
1567 public String toString() {
1568 StringBuilder sb = new StringBuilder();
1569 sb.append(this.getClass().getSuperclass().getName());
1570 sb.append('[');
1571 if (!isOpen())
1572 sb.append("closed");
1573 else {
1574 synchronized (stateLock) {
1575 switch (state) {
1576 case ST_UNCONNECTED:
1577 sb.append("unconnected");
1578 break;
1579 case ST_CONNECTIONPENDING:
1580 sb.append("connection-pending");
1581 break;
1582 case ST_CONNECTED:
1583 sb.append("connected");
1584 if (isInputClosed)
1585 sb.append(" ishut");
1586 if (isOutputClosed)
1587 sb.append(" oshut");
1588 break;
1589 }
1590 SocketAddress addr = localAddress();
1591 if (addr != null) {
1592 sb.append(" local=");
1593 sb.append(addr);
1594 }
1595 if (remoteAddress() != null) {
1596 sb.append(" remote=");
1597 sb.append(remoteAddress());
1598 }
1599 }
1600 }
1601 sb.append(']');
1602 return sb.toString();
1603 }
1604 }