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.InetSocketAddress;
31 import java.net.ServerSocket;
32 import java.net.SocketAddress;
33 import java.net.SocketOption;
34 import java.net.SocketTimeoutException;
35 import java.net.StandardSocketOptions;
36 import java.nio.channels.AlreadyBoundException;
37 import java.nio.channels.AsynchronousCloseException;
38 import java.nio.channels.ClosedChannelException;
39 import java.nio.channels.IllegalBlockingModeException;
40 import java.nio.channels.NotYetBoundException;
41 import java.nio.channels.SelectionKey;
42 import java.nio.channels.ServerSocketChannel;
43 import java.nio.channels.SocketChannel;
44 import java.nio.channels.spi.SelectorProvider;
45 import java.util.Collections;
46 import java.util.HashSet;
47 import java.util.Objects;
48 import java.util.Set;
49 import java.util.concurrent.locks.ReentrantLock;
50
51 import sun.net.NetHooks;
52 import sun.net.ext.ExtendedSocketOptions;
53
54 /**
55 * An implementation of ServerSocketChannels
68
69 // Lock held by thread currently blocked on this channel
70 private final ReentrantLock acceptLock = new ReentrantLock();
71
72 // Lock held by any thread that modifies the state fields declared below
73 // DO NOT invoke a blocking I/O operation while holding this lock!
74 private final Object stateLock = new Object();
75
76 // -- The following fields are protected by stateLock
77
78 // Channel state, increases monotonically
79 private static final int ST_INUSE = 0;
80 private static final int ST_CLOSING = 1;
81 private static final int ST_CLOSED = 2;
82 private int state;
83
84 // ID of native thread currently blocked in this channel, for signalling
85 private long thread;
86
87 // Binding
88 private InetSocketAddress localAddress; // null => unbound
89
90 // set true when exclusive binding is on and SO_REUSEADDR is emulated
91 private boolean isReuseAddress;
92
93 // Our socket adaptor, if any
94 private ServerSocket socket;
95
96 // -- End of fields protected by stateLock
97
98
99 ServerSocketChannelImpl(SelectorProvider sp) {
100 super(sp);
101 this.fd = Net.serverSocket(true);
102 this.fdVal = IOUtil.fdVal(fd);
103 }
104
105 ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
106 throws IOException
107 {
108 super(sp);
109 this.fd = fd;
110 this.fdVal = IOUtil.fdVal(fd);
111 if (bound) {
112 synchronized (stateLock) {
113 localAddress = Net.localAddress(fd);
114 }
115 }
116 }
117
118 // @throws ClosedChannelException if channel is closed
119 private void ensureOpen() throws ClosedChannelException {
120 if (!isOpen())
121 throw new ClosedChannelException();
122 }
123
124 @Override
125 public ServerSocket socket() {
126 synchronized (stateLock) {
127 if (socket == null)
128 socket = ServerSocketAdaptor.create(this);
129 return socket;
130 }
131 }
132
133 @Override
134 public SocketAddress getLocalAddress() throws IOException {
135 synchronized (stateLock) {
136 ensureOpen();
137 return (localAddress == null)
138 ? null
139 : Net.getRevealedLocalAddress(localAddress);
140 }
141 }
142
143 @Override
144 public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
145 throws IOException
146 {
147 Objects.requireNonNull(name);
148 if (!supportedOptions().contains(name))
149 throw new UnsupportedOperationException("'" + name + "' not supported");
150 if (!name.type().isInstance(value))
151 throw new IllegalArgumentException("Invalid value '" + value + "'");
152
153 synchronized (stateLock) {
154 ensureOpen();
155
156 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
157 // SO_REUSEADDR emulated when using exclusive bind
158 isReuseAddress = (Boolean)value;
159 } else {
193 set.add(StandardSocketOptions.SO_REUSEADDR);
194 if (Net.isReusePortAvailable()) {
195 set.add(StandardSocketOptions.SO_REUSEPORT);
196 }
197 set.addAll(ExtendedSocketOptions.serverSocketOptions());
198 return Collections.unmodifiableSet(set);
199 }
200 }
201
202 @Override
203 public final Set<SocketOption<?>> supportedOptions() {
204 return DefaultOptionsHolder.defaultOptions;
205 }
206
207 @Override
208 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
209 synchronized (stateLock) {
210 ensureOpen();
211 if (localAddress != null)
212 throw new AlreadyBoundException();
213 InetSocketAddress isa = (local == null)
214 ? new InetSocketAddress(0)
215 : Net.checkAddress(local);
216 SecurityManager sm = System.getSecurityManager();
217 if (sm != null)
218 sm.checkListen(isa.getPort());
219 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
220 Net.bind(fd, isa.getAddress(), isa.getPort());
221 Net.listen(fd, backlog < 1 ? 50 : backlog);
222 localAddress = Net.localAddress(fd);
223 }
224 return this;
225 }
226
227 /**
228 * Marks the beginning of an I/O operation that might block.
229 *
230 * @throws ClosedChannelException if the channel is closed
231 * @throws NotYetBoundException if the channel's socket has not been bound yet
232 */
233 private void begin(boolean blocking) throws ClosedChannelException {
234 if (blocking)
235 begin(); // set blocker to close channel if interrupted
236 synchronized (stateLock) {
237 ensureOpen();
238 if (localAddress == null)
239 throw new NotYetBoundException();
240 if (blocking)
241 thread = NativeThread.current();
242 }
243 }
249 * thread being interrupted on a blocking I/O operation.
250 */
251 private void end(boolean blocking, boolean completed)
252 throws AsynchronousCloseException
253 {
254 if (blocking) {
255 synchronized (stateLock) {
256 thread = 0;
257 if (state == ST_CLOSING) {
258 tryFinishClose();
259 }
260 }
261 end(completed);
262 }
263 }
264
265 @Override
266 public SocketChannel accept() throws IOException {
267 int n = 0;
268 FileDescriptor newfd = new FileDescriptor();
269 InetSocketAddress[] isaa = new InetSocketAddress[1];
270
271 acceptLock.lock();
272 try {
273 boolean blocking = isBlocking();
274 try {
275 begin(blocking);
276 n = Net.accept(this.fd, newfd, isaa);
277 if (blocking) {
278 while (IOStatus.okayToRetry(n) && isOpen()) {
279 park(Net.POLLIN);
280 n = Net.accept(this.fd, newfd, isaa);
281 }
282 }
283 } finally {
284 end(blocking, n > 0);
285 assert IOStatus.check(n);
286 }
287 } finally {
288 acceptLock.unlock();
289 }
291 if (n > 0) {
292 return finishAccept(newfd, isaa[0]);
293 } else {
294 return null;
295 }
296 }
297
298 /**
299 * Accepts a new connection with a given timeout. This method requires the
300 * channel to be configured in blocking mode.
301 *
302 * @apiNote This method is for use by the socket adaptor.
303 *
304 * @param nanos the timeout, in nanoseconds
305 * @throws IllegalBlockingModeException if the channel is configured non-blocking
306 * @throws SocketTimeoutException if the timeout expires
307 */
308 SocketChannel blockingAccept(long nanos) throws IOException {
309 int n = 0;
310 FileDescriptor newfd = new FileDescriptor();
311 InetSocketAddress[] isaa = new InetSocketAddress[1];
312
313 acceptLock.lock();
314 try {
315 // check that channel is configured blocking
316 if (!isBlocking())
317 throw new IllegalBlockingModeException();
318
319 try {
320 begin(true);
321 // change socket to non-blocking
322 lockedConfigureBlocking(false);
323 try {
324 long startNanos = System.nanoTime();
325 n = Net.accept(fd, newfd, isaa);
326 while (n == IOStatus.UNAVAILABLE && isOpen()) {
327 long remainingNanos = nanos - (System.nanoTime() - startNanos);
328 if (remainingNanos <= 0) {
329 throw new SocketTimeoutException("Accept timed out");
330 }
331 park(Net.POLLIN, remainingNanos);
332 n = Net.accept(fd, newfd, isaa);
333 }
334 } finally {
335 // restore socket to blocking mode
336 lockedConfigureBlocking(true);
337 }
338 } finally {
339 end(true, n > 0);
340 }
341 } finally {
342 acceptLock.unlock();
343 }
344
345 assert n > 0;
346 return finishAccept(newfd, isaa[0]);
347 }
348
349 private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa)
350 throws IOException
351 {
352 try {
353 // newly accepted socket is initially in blocking mode
354 IOUtil.configureBlocking(newfd, true);
355
356 // check permitted to accept connections from the remote address
357 SecurityManager sm = System.getSecurityManager();
358 if (sm != null) {
359 sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
360 }
361 return new SocketChannelImpl(provider(), newfd, isa);
362 } catch (Exception e) {
363 nd.close(newfd);
364 throw e;
365 }
366 }
367
368 @Override
369 protected void implConfigureBlocking(boolean block) throws IOException {
370 acceptLock.lock();
371 try {
372 lockedConfigureBlocking(block);
373 } finally {
374 acceptLock.unlock();
375 }
376 }
377
378 /**
379 * Adjust the blocking mode while holding acceptLock.
473 if (state == ST_CLOSING) {
474 tryFinishClose();
475 }
476 }
477 }
478
479 /**
480 * Returns true if channel's socket is bound
481 */
482 boolean isBound() {
483 synchronized (stateLock) {
484 return localAddress != null;
485 }
486 }
487
488 /**
489 * Returns the local address, or null if not bound
490 */
491 InetSocketAddress localAddress() {
492 synchronized (stateLock) {
493 return localAddress;
494 }
495 }
496
497 /**
498 * Translates native poll revent set into a ready operation set
499 */
500 public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
501 int intOps = ski.nioInterestOps();
502 int oldOps = ski.nioReadyOps();
503 int newOps = initialOps;
504
505 if ((ops & Net.POLLNVAL) != 0) {
506 // This should only happen if this channel is pre-closed while a
507 // selection operation is in progress
508 // ## Throw an error if this channel has not been pre-closed
509 return false;
510 }
511
512 if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
513 newOps = intOps;
532 }
533
534 /**
535 * Translates an interest operation set into a native poll event set
536 */
537 public int translateInterestOps(int ops) {
538 int newOps = 0;
539 if ((ops & SelectionKey.OP_ACCEPT) != 0)
540 newOps |= Net.POLLIN;
541 return newOps;
542 }
543
544 public FileDescriptor getFD() {
545 return fd;
546 }
547
548 public int getFDVal() {
549 return fdVal;
550 }
551
552 public String toString() {
553 StringBuilder sb = new StringBuilder();
554 sb.append(this.getClass().getName());
555 sb.append('[');
556 if (!isOpen()) {
557 sb.append("closed");
558 } else {
559 synchronized (stateLock) {
560 InetSocketAddress addr = localAddress;
561 if (addr == null) {
562 sb.append("unbound");
563 } else {
564 sb.append(Net.getRevealedLocalAddressAsString(addr));
565 }
566 }
567 }
568 sb.append(']');
569 return sb.toString();
570 }
571 }
|
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.InetSocketAddress;
31 import java.net.ProtocolFamily;
32 import java.net.ServerSocket;
33 import java.net.SocketAddress;
34 import java.net.SocketOption;
35 import java.net.SocketTimeoutException;
36 import java.net.StandardSocketOptions;
37 import java.net.UnixSocketAddress;
38 import java.nio.channels.AlreadyBoundException;
39 import java.nio.channels.AsynchronousCloseException;
40 import java.nio.channels.ClosedChannelException;
41 import java.nio.channels.IllegalBlockingModeException;
42 import java.nio.channels.NotYetBoundException;
43 import java.nio.channels.SelectionKey;
44 import java.nio.channels.ServerSocketChannel;
45 import java.nio.channels.SocketChannel;
46 import java.nio.channels.spi.SelectorProvider;
47 import java.util.Collections;
48 import java.util.HashSet;
49 import java.util.Objects;
50 import java.util.Set;
51 import java.util.concurrent.locks.ReentrantLock;
52
53 import sun.net.NetHooks;
54 import sun.net.ext.ExtendedSocketOptions;
55
56 /**
57 * An implementation of ServerSocketChannels
70
71 // Lock held by thread currently blocked on this channel
72 private final ReentrantLock acceptLock = new ReentrantLock();
73
74 // Lock held by any thread that modifies the state fields declared below
75 // DO NOT invoke a blocking I/O operation while holding this lock!
76 private final Object stateLock = new Object();
77
78 // -- The following fields are protected by stateLock
79
80 // Channel state, increases monotonically
81 private static final int ST_INUSE = 0;
82 private static final int ST_CLOSING = 1;
83 private static final int ST_CLOSED = 2;
84 private int state;
85
86 // ID of native thread currently blocked in this channel, for signalling
87 private long thread;
88
89 // Binding
90 private SocketAddress localAddress; // null => unbound
91
92 // set true when exclusive binding is on and SO_REUSEADDR is emulated
93 private boolean isReuseAddress;
94
95 // Our socket adaptor, if any
96 private ServerSocket socket;
97
98 // -- End of fields protected by stateLock
99
100
101 ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family) {
102 super(sp);
103 this.fd = Net.serverSocket(true, family);
104 this.fdVal = IOUtil.fdVal(fd);
105 }
106
107 ServerSocketChannelImpl(SelectorProvider sp) {
108 super(sp);
109 this.fd = Net.serverSocket(true);
110 this.fdVal = IOUtil.fdVal(fd);
111 }
112
113 ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
114 throws IOException
115 {
116 super(sp);
117 this.fd = fd;
118 this.fdVal = IOUtil.fdVal(fd);
119 if (bound) {
120 synchronized (stateLock) {
121 localAddress = Net.localAddress(fd);
122 }
123 }
124 }
125
126 // @throws ClosedChannelException if channel is closed
127 private void ensureOpen() throws ClosedChannelException {
128 if (!isOpen())
129 throw new ClosedChannelException();
130 }
131
132 @Override
133 public ServerSocket socket() {
134 synchronized (stateLock) {
135 if (socket == null)
136 socket = ServerSocketAdaptor.create(this);
137 return socket;
138 }
139 }
140
141 @Override
142 public SocketAddress getLocalAddress() throws IOException {
143 synchronized (stateLock) {
144 ensureOpen();
145 return (localAddress == null)
146 ? null
147 : localAddress instanceof InetSocketAddress ? Net.getRevealedLocalAddress((InetSocketAddress)localAddress) : localAddress;
148 }
149 }
150
151 @Override
152 public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
153 throws IOException
154 {
155 Objects.requireNonNull(name);
156 if (!supportedOptions().contains(name))
157 throw new UnsupportedOperationException("'" + name + "' not supported");
158 if (!name.type().isInstance(value))
159 throw new IllegalArgumentException("Invalid value '" + value + "'");
160
161 synchronized (stateLock) {
162 ensureOpen();
163
164 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
165 // SO_REUSEADDR emulated when using exclusive bind
166 isReuseAddress = (Boolean)value;
167 } else {
201 set.add(StandardSocketOptions.SO_REUSEADDR);
202 if (Net.isReusePortAvailable()) {
203 set.add(StandardSocketOptions.SO_REUSEPORT);
204 }
205 set.addAll(ExtendedSocketOptions.serverSocketOptions());
206 return Collections.unmodifiableSet(set);
207 }
208 }
209
210 @Override
211 public final Set<SocketOption<?>> supportedOptions() {
212 return DefaultOptionsHolder.defaultOptions;
213 }
214
215 @Override
216 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
217 synchronized (stateLock) {
218 ensureOpen();
219 if (localAddress != null)
220 throw new AlreadyBoundException();
221 if (local instanceof UnixSocketAddress) {
222 // TODO: SecurityManager?
223 Net.bind(fd, (UnixSocketAddress)local);
224 Net.listen(fd, backlog < 1 ? 50 : backlog);
225 localAddress = local;
226 } else {
227 InetSocketAddress isa = (local == null)
228 ? new InetSocketAddress(0)
229 : Net.checkAddress(local);
230 SecurityManager sm = System.getSecurityManager();
231 if (sm != null)
232 sm.checkListen(isa.getPort());
233 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
234 Net.bind(fd, isa.getAddress(), isa.getPort());
235 Net.listen(fd, backlog < 1 ? 50 : backlog);
236 localAddress = Net.localAddress(fd);
237 }
238 }
239 return this;
240 }
241
242 /**
243 * Marks the beginning of an I/O operation that might block.
244 *
245 * @throws ClosedChannelException if the channel is closed
246 * @throws NotYetBoundException if the channel's socket has not been bound yet
247 */
248 private void begin(boolean blocking) throws ClosedChannelException {
249 if (blocking)
250 begin(); // set blocker to close channel if interrupted
251 synchronized (stateLock) {
252 ensureOpen();
253 if (localAddress == null)
254 throw new NotYetBoundException();
255 if (blocking)
256 thread = NativeThread.current();
257 }
258 }
264 * thread being interrupted on a blocking I/O operation.
265 */
266 private void end(boolean blocking, boolean completed)
267 throws AsynchronousCloseException
268 {
269 if (blocking) {
270 synchronized (stateLock) {
271 thread = 0;
272 if (state == ST_CLOSING) {
273 tryFinishClose();
274 }
275 }
276 end(completed);
277 }
278 }
279
280 @Override
281 public SocketChannel accept() throws IOException {
282 int n = 0;
283 FileDescriptor newfd = new FileDescriptor();
284 SocketAddress[] isaa = new SocketAddress[1];
285
286 acceptLock.lock();
287 try {
288 boolean blocking = isBlocking();
289 try {
290 begin(blocking);
291 n = Net.accept(this.fd, newfd, isaa);
292 if (blocking) {
293 while (IOStatus.okayToRetry(n) && isOpen()) {
294 park(Net.POLLIN);
295 n = Net.accept(this.fd, newfd, isaa);
296 }
297 }
298 } finally {
299 end(blocking, n > 0);
300 assert IOStatus.check(n);
301 }
302 } finally {
303 acceptLock.unlock();
304 }
306 if (n > 0) {
307 return finishAccept(newfd, isaa[0]);
308 } else {
309 return null;
310 }
311 }
312
313 /**
314 * Accepts a new connection with a given timeout. This method requires the
315 * channel to be configured in blocking mode.
316 *
317 * @apiNote This method is for use by the socket adaptor.
318 *
319 * @param nanos the timeout, in nanoseconds
320 * @throws IllegalBlockingModeException if the channel is configured non-blocking
321 * @throws SocketTimeoutException if the timeout expires
322 */
323 SocketChannel blockingAccept(long nanos) throws IOException {
324 int n = 0;
325 FileDescriptor newfd = new FileDescriptor();
326 SocketAddress[] isaa = new SocketAddress[1];
327
328 acceptLock.lock();
329 try {
330 // check that channel is configured blocking
331 if (!isBlocking())
332 throw new IllegalBlockingModeException();
333
334 try {
335 begin(true);
336 // change socket to non-blocking
337 lockedConfigureBlocking(false);
338 try {
339 long startNanos = System.nanoTime();
340 n = Net.accept(fd, newfd, isaa);
341 while (n == IOStatus.UNAVAILABLE && isOpen()) {
342 long remainingNanos = nanos - (System.nanoTime() - startNanos);
343 if (remainingNanos <= 0) {
344 throw new SocketTimeoutException("Accept timed out");
345 }
346 park(Net.POLLIN, remainingNanos);
347 n = Net.accept(fd, newfd, isaa);
348 }
349 } finally {
350 // restore socket to blocking mode
351 lockedConfigureBlocking(true);
352 }
353 } finally {
354 end(true, n > 0);
355 }
356 } finally {
357 acceptLock.unlock();
358 }
359
360 assert n > 0;
361 return finishAccept(newfd, isaa[0]);
362 }
363
364 private SocketChannel finishAccept(FileDescriptor newfd, SocketAddress isa)
365 throws IOException
366 {
367 try {
368 // newly accepted socket is initially in blocking mode
369 IOUtil.configureBlocking(newfd, true);
370
371 // check permitted to accept connections from the remote address
372 SecurityManager sm = System.getSecurityManager();
373 if (sm != null && isa instanceof InetSocketAddress) { // TODO: SecurityManager: permissions for UDS?
374 sm.checkAccept(((InetSocketAddress) isa).getAddress().getHostAddress(), ((InetSocketAddress) isa).getPort());
375 }
376 return new SocketChannelImpl(provider(), newfd, isa);
377 } catch (Exception e) {
378 nd.close(newfd);
379 throw e;
380 }
381 }
382
383 @Override
384 protected void implConfigureBlocking(boolean block) throws IOException {
385 acceptLock.lock();
386 try {
387 lockedConfigureBlocking(block);
388 } finally {
389 acceptLock.unlock();
390 }
391 }
392
393 /**
394 * Adjust the blocking mode while holding acceptLock.
488 if (state == ST_CLOSING) {
489 tryFinishClose();
490 }
491 }
492 }
493
494 /**
495 * Returns true if channel's socket is bound
496 */
497 boolean isBound() {
498 synchronized (stateLock) {
499 return localAddress != null;
500 }
501 }
502
503 /**
504 * Returns the local address, or null if not bound
505 */
506 InetSocketAddress localAddress() {
507 synchronized (stateLock) {
508 return localAddress instanceof InetSocketAddress ? (InetSocketAddress)localAddress : null; // TODO: refactoring/javadoc
509 }
510 }
511
512 /**
513 * Translates native poll revent set into a ready operation set
514 */
515 public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
516 int intOps = ski.nioInterestOps();
517 int oldOps = ski.nioReadyOps();
518 int newOps = initialOps;
519
520 if ((ops & Net.POLLNVAL) != 0) {
521 // This should only happen if this channel is pre-closed while a
522 // selection operation is in progress
523 // ## Throw an error if this channel has not been pre-closed
524 return false;
525 }
526
527 if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
528 newOps = intOps;
547 }
548
549 /**
550 * Translates an interest operation set into a native poll event set
551 */
552 public int translateInterestOps(int ops) {
553 int newOps = 0;
554 if ((ops & SelectionKey.OP_ACCEPT) != 0)
555 newOps |= Net.POLLIN;
556 return newOps;
557 }
558
559 public FileDescriptor getFD() {
560 return fd;
561 }
562
563 public int getFDVal() {
564 return fdVal;
565 }
566
567 @Override
568 public String toString() {
569 StringBuilder sb = new StringBuilder();
570 sb.append(this.getClass().getName());
571 sb.append('[');
572 if (!isOpen()) {
573 sb.append("closed");
574 } else {
575 synchronized (stateLock) {
576 if (localAddress == null) {
577 sb.append("unbound");
578 } else if (localAddress instanceof InetSocketAddress) {
579 sb.append(Net.getRevealedLocalAddressAsString((InetSocketAddress)localAddress));
580 } else {
581 sb.append(localAddress);
582 }
583 }
584 }
585 sb.append(']');
586 return sb.toString();
587 }
588 }
|