Path: blob/master/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
41159 views
/*1* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.nio.channels.*;28import java.net.SocketAddress;29import java.net.SocketOption;30import java.net.StandardSocketOptions;31import java.net.InetSocketAddress;32import java.io.FileDescriptor;33import java.io.IOException;34import java.util.Set;35import java.util.HashSet;36import java.util.Collections;37import java.util.concurrent.Future;38import java.util.concurrent.locks.ReadWriteLock;39import java.util.concurrent.locks.ReentrantReadWriteLock;40import sun.net.NetHooks;41import sun.net.ext.ExtendedSocketOptions;4243/**44* Base implementation of AsynchronousServerSocketChannel.45*/4647abstract class AsynchronousServerSocketChannelImpl48extends AsynchronousServerSocketChannel49implements Cancellable, Groupable50{51protected final FileDescriptor fd;5253// the local address to which the channel's socket is bound54protected volatile InetSocketAddress localAddress;5556// need this lock to set local address57private final Object stateLock = new Object();5859// close support60private ReadWriteLock closeLock = new ReentrantReadWriteLock();61private volatile boolean closed;6263// set true when accept operation is cancelled64private volatile boolean acceptKilled;6566// set true when exclusive binding is on and SO_REUSEADDR is emulated67private boolean isReuseAddress;6869AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) {70super(group.provider());71this.fd = Net.serverSocket(true);72}7374@Override75public final boolean isOpen() {76return !closed;77}7879/**80* Marks beginning of access to file descriptor/handle81*/82final void begin() throws IOException {83closeLock.readLock().lock();84if (!isOpen())85throw new ClosedChannelException();86}8788/**89* Marks end of access to file descriptor/handle90*/91final void end() {92closeLock.readLock().unlock();93}9495/**96* Invoked to close file descriptor/handle.97*/98abstract void implClose() throws IOException;99100@Override101public final void close() throws IOException {102// synchronize with any threads using file descriptor/handle103closeLock.writeLock().lock();104try {105if (closed)106return; // already closed107closed = true;108} finally {109closeLock.writeLock().unlock();110}111implClose();112}113114/**115* Invoked by accept to accept connection116*/117abstract Future<AsynchronousSocketChannel>118implAccept(Object attachment,119CompletionHandler<AsynchronousSocketChannel,Object> handler);120121122@Override123public final Future<AsynchronousSocketChannel> accept() {124return implAccept(null, null);125}126127@Override128@SuppressWarnings("unchecked")129public final <A> void accept(A attachment,130CompletionHandler<AsynchronousSocketChannel,? super A> handler)131{132if (handler == null)133throw new NullPointerException("'handler' is null");134implAccept(attachment, (CompletionHandler<AsynchronousSocketChannel,Object>)handler);135}136137final boolean isAcceptKilled() {138return acceptKilled;139}140141@Override142public final void onCancel(PendingFuture<?,?> task) {143acceptKilled = true;144}145146@Override147public final AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)148throws IOException149{150InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :151Net.checkAddress(local);152@SuppressWarnings("removal")153SecurityManager sm = System.getSecurityManager();154if (sm != null)155sm.checkListen(isa.getPort());156157try {158begin();159synchronized (stateLock) {160if (localAddress != null)161throw new AlreadyBoundException();162NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());163Net.bind(fd, isa.getAddress(), isa.getPort());164Net.listen(fd, backlog < 1 ? 50 : backlog);165localAddress = Net.localAddress(fd);166}167} finally {168end();169}170return this;171}172173@Override174public final SocketAddress getLocalAddress() throws IOException {175if (!isOpen())176throw new ClosedChannelException();177return Net.getRevealedLocalAddress(localAddress);178}179180@Override181public final <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name,182T value)183throws IOException184{185if (name == null)186throw new NullPointerException();187if (!supportedOptions().contains(name))188throw new UnsupportedOperationException("'" + name + "' not supported");189190try {191begin();192if (name == StandardSocketOptions.SO_REUSEADDR &&193Net.useExclusiveBind())194{195// SO_REUSEADDR emulated when using exclusive bind196isReuseAddress = (Boolean)value;197} else {198Net.setSocketOption(fd, Net.UNSPEC, name, value);199}200return this;201} finally {202end();203}204}205206@Override207@SuppressWarnings("unchecked")208public final <T> T getOption(SocketOption<T> name) throws IOException {209if (name == null)210throw new NullPointerException();211if (!supportedOptions().contains(name))212throw new UnsupportedOperationException("'" + name + "' not supported");213214try {215begin();216if (name == StandardSocketOptions.SO_REUSEADDR &&217Net.useExclusiveBind())218{219// SO_REUSEADDR emulated when using exclusive bind220return (T)Boolean.valueOf(isReuseAddress);221}222return (T) Net.getSocketOption(fd, Net.UNSPEC, name);223} finally {224end();225}226}227228private static class DefaultOptionsHolder {229static final Set<SocketOption<?>> defaultOptions = defaultOptions();230231private static Set<SocketOption<?>> defaultOptions() {232HashSet<SocketOption<?>> set = new HashSet<>(2);233set.add(StandardSocketOptions.SO_RCVBUF);234set.add(StandardSocketOptions.SO_REUSEADDR);235if (Net.isReusePortAvailable()) {236set.add(StandardSocketOptions.SO_REUSEPORT);237}238set.addAll(ExtendedSocketOptions.serverSocketOptions());239return Collections.unmodifiableSet(set);240}241}242243@Override244public final Set<SocketOption<?>> supportedOptions() {245return DefaultOptionsHolder.defaultOptions;246}247248@Override249public final String toString() {250StringBuilder sb = new StringBuilder();251sb.append(this.getClass().getName());252sb.append('[');253if (!isOpen())254sb.append("closed");255else {256if (localAddress == null) {257sb.append("unbound");258} else {259sb.append(Net.getRevealedLocalAddressAsString(localAddress));260}261}262sb.append(']');263return sb.toString();264}265}266267268