1 /*
2 * Copyright (c) 2000, 2019, 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.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
58 */
59
60 class ServerSocketChannelImpl
61 extends ServerSocketChannel
62 implements SelChImpl
63 {
64 // Used to make native close and configure calls
65 private static final NativeDispatcher nd = new SocketDispatcher();
66
67 // Our file descriptor
68 private final FileDescriptor fd;
69 private final int fdVal;
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 {
168 // no options that require special handling
169 Net.setSocketOption(fd, Net.UNSPEC, name, value);
170 }
171 return this;
172 }
173 }
174
175 @Override
176 @SuppressWarnings("unchecked")
177 public <T> T getOption(SocketOption<T> name)
178 throws IOException
179 {
180 Objects.requireNonNull(name);
181 if (!supportedOptions().contains(name))
182 throw new UnsupportedOperationException("'" + name + "' not supported");
183
184 synchronized (stateLock) {
185 ensureOpen();
186 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
187 // SO_REUSEADDR emulated when using exclusive bind
188 return (T)Boolean.valueOf(isReuseAddress);
189 }
190 // no options that require special handling
191 return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
192 }
193 }
194
195 private static class DefaultOptionsHolder {
196 static final Set<SocketOption<?>> defaultOptions = defaultOptions();
197
198 private static Set<SocketOption<?>> defaultOptions() {
199 HashSet<SocketOption<?>> set = new HashSet<>();
200 set.add(StandardSocketOptions.SO_RCVBUF);
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 }
259
260 /**
261 * Marks the end of an I/O operation that may have blocked.
262 *
263 * @throws AsynchronousCloseException if the channel was closed due to this
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 }
305
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.
395 */
396 private void lockedConfigureBlocking(boolean block) throws IOException {
397 assert acceptLock.isHeldByCurrentThread();
398 synchronized (stateLock) {
399 ensureOpen();
400 IOUtil.configureBlocking(fd, block);
401 }
402 }
403
404 /**
405 * Closes the socket if there are no accept in progress and the channel is
406 * not registered with a Selector.
407 */
408 private boolean tryClose() throws IOException {
409 assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
410 if ((thread == 0) && !isRegistered()) {
411 state = ST_CLOSED;
412 nd.close(fd);
413 return true;
414 } else {
415 return false;
416 }
417 }
418
419 /**
420 * Invokes tryClose to attempt to close the socket.
421 *
422 * This method is used for deferred closing by I/O and Selector operations.
423 */
424 private void tryFinishClose() {
425 try {
426 tryClose();
427 } catch (IOException ignore) { }
428 }
429
430 /**
431 * Closes this channel when configured in blocking mode.
432 *
433 * If there is an accept in progress then the socket is pre-closed and the
434 * accept thread is signalled, in which case the final close is deferred
435 * until the accept aborts.
436 */
437 private void implCloseBlockingMode() throws IOException {
438 synchronized (stateLock) {
439 assert state < ST_CLOSING;
440 state = ST_CLOSING;
441 if (!tryClose()) {
442 long th = thread;
443 if (th != 0) {
444 nd.preClose(fd);
445 NativeThread.signal(th);
446 }
447 }
448 }
449 }
450
451 /**
452 * Closes this channel when configured in non-blocking mode.
453 *
454 * If the channel is registered with a Selector then the close is deferred
455 * until the channel is flushed from all Selectors.
456 */
457 private void implCloseNonBlockingMode() throws IOException {
458 synchronized (stateLock) {
459 assert state < ST_CLOSING;
460 state = ST_CLOSING;
461 }
462 // wait for any accept to complete before trying to close
463 acceptLock.lock();
464 acceptLock.unlock();
465 synchronized (stateLock) {
466 if (state == ST_CLOSING) {
467 tryClose();
468 }
469 }
470 }
471
472 /**
473 * Invoked by implCloseChannel to close the channel.
474 */
475 @Override
476 protected void implCloseSelectableChannel() throws IOException {
477 assert !isOpen();
478 if (isBlocking()) {
479 implCloseBlockingMode();
480 } else {
481 implCloseNonBlockingMode();
482 }
483 }
484
485 @Override
486 public void kill() {
487 synchronized (stateLock) {
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;
529 ski.nioReadyOps(newOps);
530 return (newOps & ~oldOps) != 0;
531 }
532
533 if (((ops & Net.POLLIN) != 0) &&
534 ((intOps & SelectionKey.OP_ACCEPT) != 0))
535 newOps |= SelectionKey.OP_ACCEPT;
536
537 ski.nioReadyOps(newOps);
538 return (newOps & ~oldOps) != 0;
539 }
540
541 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
542 return translateReadyOps(ops, ski.nioReadyOps(), ski);
543 }
544
545 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
546 return translateReadyOps(ops, 0, ski);
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 }