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.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
56 */
57
58 class ServerSocketChannelImpl
59 extends ServerSocketChannel
60 implements SelChImpl
61 {
62 // Used to make native close and configure calls
63 private static final NativeDispatcher nd = new SocketDispatcher();
64
65 // Our file descriptor
66 private final FileDescriptor fd;
67 private final int fdVal;
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 {
160 // no options that require special handling
161 Net.setSocketOption(fd, Net.UNSPEC, name, value);
162 }
163 return this;
164 }
165 }
166
167 @Override
168 @SuppressWarnings("unchecked")
169 public <T> T getOption(SocketOption<T> name)
170 throws IOException
171 {
172 Objects.requireNonNull(name);
173 if (!supportedOptions().contains(name))
174 throw new UnsupportedOperationException("'" + name + "' not supported");
175
176 synchronized (stateLock) {
177 ensureOpen();
178 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
179 // SO_REUSEADDR emulated when using exclusive bind
180 return (T)Boolean.valueOf(isReuseAddress);
181 }
182 // no options that require special handling
183 return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
184 }
185 }
186
187 private static class DefaultOptionsHolder {
188 static final Set<SocketOption<?>> defaultOptions = defaultOptions();
189
190 private static Set<SocketOption<?>> defaultOptions() {
191 HashSet<SocketOption<?>> set = new HashSet<>();
192 set.add(StandardSocketOptions.SO_RCVBUF);
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 }
244
245 /**
246 * Marks the end of an I/O operation that may have blocked.
247 *
248 * @throws AsynchronousCloseException if the channel was closed due to this
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 }
290
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.
380 */
381 private void lockedConfigureBlocking(boolean block) throws IOException {
382 assert acceptLock.isHeldByCurrentThread();
383 synchronized (stateLock) {
384 ensureOpen();
385 IOUtil.configureBlocking(fd, block);
386 }
387 }
388
389 /**
390 * Closes the socket if there are no accept in progress and the channel is
391 * not registered with a Selector.
392 */
393 private boolean tryClose() throws IOException {
394 assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
395 if ((thread == 0) && !isRegistered()) {
396 state = ST_CLOSED;
397 nd.close(fd);
398 return true;
399 } else {
400 return false;
401 }
402 }
403
404 /**
405 * Invokes tryClose to attempt to close the socket.
406 *
407 * This method is used for deferred closing by I/O and Selector operations.
408 */
409 private void tryFinishClose() {
410 try {
411 tryClose();
412 } catch (IOException ignore) { }
413 }
414
415 /**
416 * Closes this channel when configured in blocking mode.
417 *
418 * If there is an accept in progress then the socket is pre-closed and the
419 * accept thread is signalled, in which case the final close is deferred
420 * until the accept aborts.
421 */
422 private void implCloseBlockingMode() throws IOException {
423 synchronized (stateLock) {
424 assert state < ST_CLOSING;
425 state = ST_CLOSING;
426 if (!tryClose()) {
427 long th = thread;
428 if (th != 0) {
429 nd.preClose(fd);
430 NativeThread.signal(th);
431 }
432 }
433 }
434 }
435
436 /**
437 * Closes this channel when configured in non-blocking mode.
438 *
439 * If the channel is registered with a Selector then the close is deferred
440 * until the channel is flushed from all Selectors.
441 */
442 private void implCloseNonBlockingMode() throws IOException {
443 synchronized (stateLock) {
444 assert state < ST_CLOSING;
445 state = ST_CLOSING;
446 }
447 // wait for any accept to complete before trying to close
448 acceptLock.lock();
449 acceptLock.unlock();
450 synchronized (stateLock) {
451 if (state == ST_CLOSING) {
452 tryClose();
453 }
454 }
455 }
456
457 /**
458 * Invoked by implCloseChannel to close the channel.
459 */
460 @Override
461 protected void implCloseSelectableChannel() throws IOException {
462 assert !isOpen();
463 if (isBlocking()) {
464 implCloseBlockingMode();
465 } else {
466 implCloseNonBlockingMode();
467 }
468 }
469
470 @Override
471 public void kill() {
472 synchronized (stateLock) {
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;
514 ski.nioReadyOps(newOps);
515 return (newOps & ~oldOps) != 0;
516 }
517
518 if (((ops & Net.POLLIN) != 0) &&
519 ((intOps & SelectionKey.OP_ACCEPT) != 0))
520 newOps |= SelectionKey.OP_ACCEPT;
521
522 ski.nioReadyOps(newOps);
523 return (newOps & ~oldOps) != 0;
524 }
525
526 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
527 return translateReadyOps(ops, ski.nioReadyOps(), ski);
528 }
529
530 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
531 return translateReadyOps(ops, 0, ski);
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 }