Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
38918 views
/*1* Copyright (c) 2000, 2013, 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.io.FileDescriptor;28import java.io.IOException;29import java.net.*;30import java.nio.channels.*;31import java.nio.channels.spi.*;32import java.util.*;33import sun.net.NetHooks;34import sun.net.ExtendedOptionsHelper;353637/**38* An implementation of ServerSocketChannels39*/4041class ServerSocketChannelImpl42extends ServerSocketChannel43implements SelChImpl44{4546// Used to make native close and configure calls47private static NativeDispatcher nd;4849// Our file descriptor50private final FileDescriptor fd;51private final int fdVal;5253// ID of native thread currently blocked in this channel, for signalling54private volatile long thread = 0;5556// Lock held by thread currently blocked in this channel57private final Object lock = new Object();5859// Lock held by any thread that modifies the state fields declared below60// DO NOT invoke a blocking I/O operation while holding this lock!61private final Object stateLock = new Object();6263// -- The following fields are protected by stateLock6465// Channel state, increases monotonically66private static final int ST_UNINITIALIZED = -1;67private static final int ST_INUSE = 0;68private static final int ST_KILLED = 1;69private int state = ST_UNINITIALIZED;7071// Binding72private InetSocketAddress localAddress; // null => unbound7374// set true when exclusive binding is on and SO_REUSEADDR is emulated75private boolean isReuseAddress;7677// Our socket adaptor, if any78ServerSocket socket;7980// -- End of fields protected by stateLock818283ServerSocketChannelImpl(SelectorProvider sp) throws IOException {84super(sp);85this.fd = Net.serverSocket(true);86this.fdVal = IOUtil.fdVal(fd);87this.state = ST_INUSE;88}8990ServerSocketChannelImpl(SelectorProvider sp,91FileDescriptor fd,92boolean bound)93throws IOException94{95super(sp);96this.fd = fd;97this.fdVal = IOUtil.fdVal(fd);98this.state = ST_INUSE;99if (bound)100localAddress = Net.localAddress(fd);101}102103public ServerSocket socket() {104synchronized (stateLock) {105if (socket == null)106socket = ServerSocketAdaptor.create(this);107return socket;108}109}110111@Override112public SocketAddress getLocalAddress() throws IOException {113synchronized (stateLock) {114if (!isOpen())115throw new ClosedChannelException();116return localAddress == null ? localAddress117: Net.getRevealedLocalAddress(118Net.asInetSocketAddress(localAddress));119}120}121122@Override123public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)124throws IOException125{126if (name == null)127throw new NullPointerException();128if (!supportedOptions().contains(name))129throw new UnsupportedOperationException("'" + name + "' not supported");130synchronized (stateLock) {131if (!isOpen())132throw new ClosedChannelException();133134if (name == StandardSocketOptions.IP_TOS) {135ProtocolFamily family = Net.isIPv6Available() ?136StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;137Net.setSocketOption(fd, family, name, value);138return this;139}140141if (name == StandardSocketOptions.SO_REUSEADDR &&142Net.useExclusiveBind())143{144// SO_REUSEADDR emulated when using exclusive bind145isReuseAddress = (Boolean)value;146} else {147// no options that require special handling148Net.setSocketOption(fd, Net.UNSPEC, name, value);149}150return this;151}152}153154@Override155@SuppressWarnings("unchecked")156public <T> T getOption(SocketOption<T> name)157throws IOException158{159if (name == null)160throw new NullPointerException();161if (!supportedOptions().contains(name))162throw new UnsupportedOperationException("'" + name + "' not supported");163164synchronized (stateLock) {165if (!isOpen())166throw new ClosedChannelException();167if (name == StandardSocketOptions.SO_REUSEADDR &&168Net.useExclusiveBind())169{170// SO_REUSEADDR emulated when using exclusive bind171return (T)Boolean.valueOf(isReuseAddress);172}173// no options that require special handling174return (T) Net.getSocketOption(fd, Net.UNSPEC, name);175}176}177178private static class DefaultOptionsHolder {179static final Set<SocketOption<?>> defaultOptions = defaultOptions();180181private static Set<SocketOption<?>> defaultOptions() {182HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);183set.add(StandardSocketOptions.SO_RCVBUF);184set.add(StandardSocketOptions.SO_REUSEADDR);185set.add(StandardSocketOptions.IP_TOS);186set.addAll(ExtendedOptionsHelper.keepAliveOptions());187return Collections.unmodifiableSet(set);188}189}190191@Override192public final Set<SocketOption<?>> supportedOptions() {193return DefaultOptionsHolder.defaultOptions;194}195196public boolean isBound() {197synchronized (stateLock) {198return localAddress != null;199}200}201202public InetSocketAddress localAddress() {203synchronized (stateLock) {204return localAddress;205}206}207208@Override209public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {210synchronized (lock) {211if (!isOpen())212throw new ClosedChannelException();213if (isBound())214throw new AlreadyBoundException();215InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :216Net.checkAddress(local);217SecurityManager sm = System.getSecurityManager();218if (sm != null)219sm.checkListen(isa.getPort());220NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());221Net.bind(fd, isa.getAddress(), isa.getPort());222Net.listen(fd, backlog < 1 ? 50 : backlog);223synchronized (stateLock) {224localAddress = Net.localAddress(fd);225}226}227return this;228}229230public SocketChannel accept() throws IOException {231synchronized (lock) {232if (!isOpen())233throw new ClosedChannelException();234if (!isBound())235throw new NotYetBoundException();236SocketChannel sc = null;237238int n = 0;239FileDescriptor newfd = new FileDescriptor();240InetSocketAddress[] isaa = new InetSocketAddress[1];241242try {243begin();244if (!isOpen())245return null;246thread = NativeThread.current();247for (;;) {248n = accept(this.fd, newfd, isaa);249if ((n == IOStatus.INTERRUPTED) && isOpen())250continue;251break;252}253} finally {254thread = 0;255end(n > 0);256assert IOStatus.check(n);257}258259if (n < 1)260return null;261262IOUtil.configureBlocking(newfd, true);263InetSocketAddress isa = isaa[0];264sc = new SocketChannelImpl(provider(), newfd, isa);265SecurityManager sm = System.getSecurityManager();266if (sm != null) {267try {268sm.checkAccept(isa.getAddress().getHostAddress(),269isa.getPort());270} catch (SecurityException x) {271sc.close();272throw x;273}274}275return sc;276277}278}279280protected void implConfigureBlocking(boolean block) throws IOException {281IOUtil.configureBlocking(fd, block);282}283284protected void implCloseSelectableChannel() throws IOException {285synchronized (stateLock) {286if (state != ST_KILLED)287nd.preClose(fd);288long th = thread;289if (th != 0)290NativeThread.signal(th);291if (!isRegistered())292kill();293}294}295296public void kill() throws IOException {297synchronized (stateLock) {298if (state == ST_KILLED)299return;300if (state == ST_UNINITIALIZED) {301state = ST_KILLED;302return;303}304assert !isOpen() && !isRegistered();305nd.close(fd);306state = ST_KILLED;307}308}309310/**311* Translates native poll revent set into a ready operation set312*/313public boolean translateReadyOps(int ops, int initialOps,314SelectionKeyImpl sk) {315int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes316int oldOps = sk.nioReadyOps();317int newOps = initialOps;318319if ((ops & Net.POLLNVAL) != 0) {320// This should only happen if this channel is pre-closed while a321// selection operation is in progress322// ## Throw an error if this channel has not been pre-closed323return false;324}325326if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {327newOps = intOps;328sk.nioReadyOps(newOps);329return (newOps & ~oldOps) != 0;330}331332if (((ops & Net.POLLIN) != 0) &&333((intOps & SelectionKey.OP_ACCEPT) != 0))334newOps |= SelectionKey.OP_ACCEPT;335336sk.nioReadyOps(newOps);337return (newOps & ~oldOps) != 0;338}339340public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {341return translateReadyOps(ops, sk.nioReadyOps(), sk);342}343344public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {345return translateReadyOps(ops, 0, sk);346}347348// package-private349int poll(int events, long timeout) throws IOException {350assert Thread.holdsLock(blockingLock()) && !isBlocking();351352synchronized (lock) {353int n = 0;354try {355begin();356synchronized (stateLock) {357if (!isOpen())358return 0;359thread = NativeThread.current();360}361n = Net.poll(fd, events, timeout);362} finally {363thread = 0;364end(n > 0);365}366return n;367}368}369370/**371* Translates an interest operation set into a native poll event set372*/373public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {374int newOps = 0;375376// Translate ops377if ((ops & SelectionKey.OP_ACCEPT) != 0)378newOps |= Net.POLLIN;379// Place ops into pollfd array380sk.selector.putEventOps(sk, newOps);381}382383public FileDescriptor getFD() {384return fd;385}386387public int getFDVal() {388return fdVal;389}390391public String toString() {392StringBuffer sb = new StringBuffer();393sb.append(this.getClass().getName());394sb.append('[');395if (!isOpen()) {396sb.append("closed");397} else {398synchronized (stateLock) {399InetSocketAddress addr = localAddress();400if (addr == null) {401sb.append("unbound");402} else {403sb.append(Net.getRevealedLocalAddressAsString(addr));404}405}406}407sb.append(']');408return sb.toString();409}410411/**412* Accept a connection on a socket.413*414* @implNote Wrap native call to allow instrumentation.415*/416private int accept(FileDescriptor ssfd, FileDescriptor newfd,417InetSocketAddress[] isaa)418throws IOException419{420return accept0(ssfd, newfd, isaa);421}422423// -- Native methods --424425// Accepts a new connection, setting the given file descriptor to refer to426// the new socket and setting isaa[0] to the socket's remote address.427// Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no428// connections are pending) or IOStatus.INTERRUPTED.429//430private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,431InetSocketAddress[] isaa)432throws IOException;433434private static native void initIDs();435436static {437IOUtil.load();438initIDs();439nd = new SocketDispatcher();440}441442}443444445