Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpServerChannelImpl.java
32300 views
/*1* Copyright (c) 2009, 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*/24package sun.nio.ch.sctp;2526import java.net.SocketAddress;27import java.net.InetSocketAddress;28import java.net.InetAddress;29import java.io.FileDescriptor;30import java.io.IOException;31import java.util.Collections;32import java.util.Set;33import java.util.HashSet;34import java.nio.channels.SelectionKey;35import java.nio.channels.ClosedChannelException;36import java.nio.channels.NotYetBoundException;37import java.nio.channels.spi.SelectorProvider;38import com.sun.nio.sctp.IllegalUnbindException;39import com.sun.nio.sctp.SctpChannel;40import com.sun.nio.sctp.SctpServerChannel;41import com.sun.nio.sctp.SctpSocketOption;42import com.sun.nio.sctp.SctpStandardSocketOptions;43import sun.nio.ch.DirectBuffer;44import sun.nio.ch.NativeThread;45import sun.nio.ch.IOStatus;46import sun.nio.ch.IOUtil;47import sun.nio.ch.Net;48import sun.nio.ch.PollArrayWrapper;49import sun.nio.ch.SelChImpl;50import sun.nio.ch.SelectionKeyImpl;51import sun.nio.ch.Util;5253/**54* An implementation of SctpServerChannel55*/56public class SctpServerChannelImpl extends SctpServerChannel57implements SelChImpl58{59private final FileDescriptor fd;6061private final int fdVal;6263/* IDs of native thread doing accept, for signalling */64private volatile long thread = 0;6566/* Lock held by thread currently blocked in this channel */67private final Object lock = new Object();6869/* Lock held by any thread that modifies the state fields declared below70* DO NOT invoke a blocking I/O operation while holding this lock! */71private final Object stateLock = new Object();7273private enum ChannelState {74UNINITIALIZED,75INUSE,76KILLPENDING,77KILLED,78}79/* -- The following fields are protected by stateLock -- */80private ChannelState state = ChannelState.UNINITIALIZED;8182/* Binding: Once bound the port will remain constant. */83int port = -1;84private HashSet<InetSocketAddress> localAddresses = new HashSet<InetSocketAddress>();85/* Has the channel been bound to the wildcard address */86private boolean wildcard; /* false */8788/* -- End of fields protected by stateLock -- */8990/**91* Initializes a new instance of this class.92*/93public SctpServerChannelImpl(SelectorProvider provider)94throws IOException {95//TODO: update provider remove public modifier96super(provider);97this.fd = SctpNet.socket(true);98this.fdVal = IOUtil.fdVal(fd);99this.state = ChannelState.INUSE;100}101102@Override103public SctpServerChannel bind(SocketAddress local, int backlog)104throws IOException {105synchronized (lock) {106synchronized (stateLock) {107if (!isOpen())108throw new ClosedChannelException();109if (isBound())110SctpNet.throwAlreadyBoundException();111112InetSocketAddress isa = (local == null) ?113new InetSocketAddress(0) : Net.checkAddress(local);114SecurityManager sm = System.getSecurityManager();115if (sm != null)116sm.checkListen(isa.getPort());117Net.bind(fd, isa.getAddress(), isa.getPort());118119InetSocketAddress boundIsa = Net.localAddress(fd);120port = boundIsa.getPort();121localAddresses.add(isa);122if (isa.getAddress().isAnyLocalAddress())123wildcard = true;124125SctpNet.listen(fdVal, backlog < 1 ? 50 : backlog);126}127}128return this;129}130131@Override132public SctpServerChannel bindAddress(InetAddress address)133throws IOException {134return bindUnbindAddress(address, true);135}136137@Override138public SctpServerChannel unbindAddress(InetAddress address)139throws IOException {140return bindUnbindAddress(address, false);141}142143private SctpServerChannel bindUnbindAddress(InetAddress address, boolean add)144throws IOException {145if (address == null)146throw new IllegalArgumentException();147148synchronized (lock) {149synchronized (stateLock) {150if (!isOpen())151throw new ClosedChannelException();152if (!isBound())153throw new NotYetBoundException();154if (wildcard)155throw new IllegalStateException(156"Cannot add or remove addresses from a channel that is bound to the wildcard address");157if (address.isAnyLocalAddress())158throw new IllegalArgumentException(159"Cannot add or remove the wildcard address");160if (add) {161for (InetSocketAddress addr : localAddresses) {162if (addr.getAddress().equals(address)) {163SctpNet.throwAlreadyBoundException();164}165}166} else { /*removing */167/* Verify that there is more than one address168* and that address is already bound */169if (localAddresses.size() <= 1)170throw new IllegalUnbindException("Cannot remove address from a channel with only one address bound");171boolean foundAddress = false;172for (InetSocketAddress addr : localAddresses) {173if (addr.getAddress().equals(address)) {174foundAddress = true;175break;176}177}178if (!foundAddress )179throw new IllegalUnbindException("Cannot remove address from a channel that is not bound to that address");180}181182SctpNet.bindx(fdVal, new InetAddress[]{address}, port, add);183184/* Update our internal Set to reflect the addition/removal */185if (add)186localAddresses.add(new InetSocketAddress(address, port));187else {188for (InetSocketAddress addr : localAddresses) {189if (addr.getAddress().equals(address)) {190localAddresses.remove(addr);191break;192}193}194}195}196}197return this;198}199200private boolean isBound() {201synchronized (stateLock) {202return port == -1 ? false : true;203}204}205206private void acceptCleanup() throws IOException {207synchronized (stateLock) {208thread = 0;209if (state == ChannelState.KILLPENDING)210kill();211}212}213214@Override215public SctpChannel accept() throws IOException {216synchronized (lock) {217if (!isOpen())218throw new ClosedChannelException();219if (!isBound())220throw new NotYetBoundException();221SctpChannel sc = null;222223int n = 0;224FileDescriptor newfd = new FileDescriptor();225InetSocketAddress[] isaa = new InetSocketAddress[1];226227try {228begin();229if (!isOpen())230return null;231thread = NativeThread.current();232for (;;) {233n = accept0(fd, newfd, isaa);234if ((n == IOStatus.INTERRUPTED) && isOpen())235continue;236break;237}238} finally {239acceptCleanup();240end(n > 0);241assert IOStatus.check(n);242}243244if (n < 1)245return null;246247IOUtil.configureBlocking(newfd, true);248InetSocketAddress isa = isaa[0];249sc = new SctpChannelImpl(provider(), newfd);250251SecurityManager sm = System.getSecurityManager();252if (sm != null)253sm.checkAccept(isa.getAddress().getHostAddress(),254isa.getPort());255256return sc;257}258}259260@Override261protected void implConfigureBlocking(boolean block) throws IOException {262IOUtil.configureBlocking(fd, block);263}264265@Override266public void implCloseSelectableChannel() throws IOException {267synchronized (stateLock) {268SctpNet.preClose(fdVal);269if (thread != 0)270NativeThread.signal(thread);271if (!isRegistered())272kill();273}274}275276@Override277public void kill() throws IOException {278synchronized (stateLock) {279if (state == ChannelState.KILLED)280return;281if (state == ChannelState.UNINITIALIZED) {282state = ChannelState.KILLED;283return;284}285assert !isOpen() && !isRegistered();286287// Postpone the kill if there is a thread in accept288if (thread == 0) {289SctpNet.close(fdVal);290state = ChannelState.KILLED;291} else {292state = ChannelState.KILLPENDING;293}294}295}296297@Override298public FileDescriptor getFD() {299return fd;300}301302@Override303public int getFDVal() {304return fdVal;305}306307/**308* Translates native poll revent ops into a ready operation ops309*/310private boolean translateReadyOps(int ops, int initialOps,311SelectionKeyImpl sk) {312int intOps = sk.nioInterestOps();313int oldOps = sk.nioReadyOps();314int newOps = initialOps;315316if ((ops & Net.POLLNVAL) != 0) {317/* This should only happen if this channel is pre-closed while a318* selection operation is in progress319* ## Throw an error if this channel has not been pre-closed */320return false;321}322323if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {324newOps = intOps;325sk.nioReadyOps(newOps);326return (newOps & ~oldOps) != 0;327}328329if (((ops & Net.POLLIN) != 0) &&330((intOps & SelectionKey.OP_ACCEPT) != 0))331newOps |= SelectionKey.OP_ACCEPT;332333sk.nioReadyOps(newOps);334return (newOps & ~oldOps) != 0;335}336337@Override338public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {339return translateReadyOps(ops, sk.nioReadyOps(), sk);340}341342@Override343public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {344return translateReadyOps(ops, 0, sk);345}346347@Override348public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {349int newOps = 0;350351/* Translate ops */352if ((ops & SelectionKey.OP_ACCEPT) != 0)353newOps |= Net.POLLIN;354/* Place ops into pollfd array */355sk.selector.putEventOps(sk, newOps);356357}358359@Override360public <T> SctpServerChannel setOption(SctpSocketOption<T> name, T value)361throws IOException {362if (name == null)363throw new NullPointerException();364if (!supportedOptions().contains(name))365throw new UnsupportedOperationException("'" + name + "' not supported");366367synchronized (stateLock) {368if (!isOpen())369throw new ClosedChannelException();370371SctpNet.setSocketOption(fdVal, name, value, 0 /*oneToOne*/);372return this;373}374}375376@Override377@SuppressWarnings("unchecked")378public <T> T getOption(SctpSocketOption<T> name) throws IOException {379if (name == null)380throw new NullPointerException();381if (!supportedOptions().contains(name))382throw new UnsupportedOperationException("'" + name + "' not supported");383384synchronized (stateLock) {385if (!isOpen())386throw new ClosedChannelException();387388return (T) SctpNet.getSocketOption(fdVal, name, 0 /*oneToOne*/);389}390}391392private static class DefaultOptionsHolder {393static final Set<SctpSocketOption<?>> defaultOptions = defaultOptions();394395private static Set<SctpSocketOption<?>> defaultOptions() {396HashSet<SctpSocketOption<?>> set = new HashSet<SctpSocketOption<?>>(1);397set.add(SctpStandardSocketOptions.SCTP_INIT_MAXSTREAMS);398return Collections.unmodifiableSet(set);399}400}401402@Override403public final Set<SctpSocketOption<?>> supportedOptions() {404return DefaultOptionsHolder.defaultOptions;405}406407@Override408public Set<SocketAddress> getAllLocalAddresses()409throws IOException {410synchronized (stateLock) {411if (!isOpen())412throw new ClosedChannelException();413if (!isBound())414return Collections.emptySet();415416return SctpNet.getLocalAddresses(fdVal);417}418}419420/* Native */421private static native void initIDs();422423private static native int accept0(FileDescriptor ssfd,424FileDescriptor newfd, InetSocketAddress[] isaa) throws IOException;425426static {427IOUtil.load(); // loads nio & net native libraries428java.security.AccessController.doPrivileged(429new java.security.PrivilegedAction<Void>() {430public Void run() {431System.loadLibrary("sctp");432return null;433}434});435initIDs();436}437}438439440