1096N/A/*
3261N/A * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
1096N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1096N/A *
1096N/A * This code is free software; you can redistribute it and/or modify it
1096N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
1096N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
1096N/A *
1096N/A * This code is distributed in the hope that it will be useful, but WITHOUT
1096N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1096N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1096N/A * version 2 for more details (a copy is included in the LICENSE file that
1096N/A * accompanied this code).
1096N/A *
1096N/A * You should have received a copy of the GNU General Public License version
1096N/A * 2 along with this work; if not, write to the Free Software Foundation,
1096N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1096N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
1096N/A */
1096N/Apackage sun.nio.ch;
1096N/A
1096N/Aimport java.net.SocketAddress;
1096N/Aimport java.net.InetSocketAddress;
1096N/Aimport java.net.InetAddress;
1096N/Aimport java.io.FileDescriptor;
1096N/Aimport java.io.IOException;
1096N/Aimport java.util.Collections;
1096N/Aimport java.util.Set;
1096N/Aimport java.util.HashSet;
1096N/Aimport java.nio.channels.SelectionKey;
1096N/Aimport java.nio.channels.ClosedChannelException;
1096N/Aimport java.nio.channels.NotYetBoundException;
1096N/Aimport java.nio.channels.spi.SelectorProvider;
1096N/Aimport com.sun.nio.sctp.IllegalUnbindException;
1096N/Aimport com.sun.nio.sctp.SctpChannel;
1096N/Aimport com.sun.nio.sctp.SctpServerChannel;
1096N/Aimport com.sun.nio.sctp.SctpSocketOption;
4216N/Aimport com.sun.nio.sctp.SctpStandardSocketOptions;
1096N/A
1096N/A/**
1096N/A * An implementation of SctpServerChannel
1096N/A */
1096N/Apublic class SctpServerChannelImpl extends SctpServerChannel
1096N/A implements SelChImpl
1096N/A{
1096N/A private final FileDescriptor fd;
1096N/A
1096N/A private final int fdVal;
1096N/A
1096N/A /* IDs of native thread doing accept, for signalling */
1096N/A private volatile long thread = 0;
1096N/A
1096N/A /* Lock held by thread currently blocked in this channel */
1096N/A private final Object lock = new Object();
1096N/A
1096N/A /* Lock held by any thread that modifies the state fields declared below
1096N/A * DO NOT invoke a blocking I/O operation while holding this lock! */
1096N/A private final Object stateLock = new Object();
1096N/A
1096N/A private enum ChannelState {
1096N/A UNINITIALIZED,
1096N/A INUSE,
1096N/A KILLPENDING,
1096N/A KILLED,
1096N/A }
1096N/A /* -- The following fields are protected by stateLock -- */
1096N/A private ChannelState state = ChannelState.UNINITIALIZED;
1096N/A
1096N/A /* Binding: Once bound the port will remain constant. */
1096N/A int port = -1;
1096N/A private HashSet<InetSocketAddress> localAddresses = new HashSet<InetSocketAddress>();
1096N/A /* Has the channel been bound to the wildcard address */
1096N/A private boolean wildcard; /* false */
1096N/A
1096N/A /* -- End of fields protected by stateLock -- */
1096N/A
1096N/A /**
1096N/A * Initializes a new instance of this class.
1096N/A */
1096N/A public SctpServerChannelImpl(SelectorProvider provider)
1096N/A throws IOException {
1096N/A //TODO: update provider remove public modifier
1096N/A super(provider);
1096N/A this.fd = SctpNet.socket(true);
1096N/A this.fdVal = IOUtil.fdVal(fd);
1096N/A this.state = ChannelState.INUSE;
1096N/A }
1096N/A
1096N/A @Override
1096N/A public SctpServerChannel bind(SocketAddress local, int backlog)
1096N/A throws IOException {
1096N/A synchronized (lock) {
1096N/A synchronized (stateLock) {
1096N/A if (!isOpen())
1096N/A throw new ClosedChannelException();
1096N/A if (isBound())
2084N/A SctpNet.throwAlreadyBoundException();
1096N/A
1096N/A InetSocketAddress isa = (local == null) ?
1096N/A new InetSocketAddress(0) : Net.checkAddress(local);
1096N/A SecurityManager sm = System.getSecurityManager();
1096N/A if (sm != null)
1096N/A sm.checkListen(isa.getPort());
1096N/A Net.bind(fd, isa.getAddress(), isa.getPort());
1096N/A
1096N/A InetSocketAddress boundIsa = Net.localAddress(fd);
1096N/A port = boundIsa.getPort();
1096N/A localAddresses.add(isa);
1096N/A if (isa.getAddress().isAnyLocalAddress())
1096N/A wildcard = true;
1096N/A
2084N/A SctpNet.listen(fdVal, backlog < 1 ? 50 : backlog);
1096N/A }
1096N/A }
1096N/A return this;
1096N/A }
1096N/A
1096N/A @Override
1096N/A public SctpServerChannel bindAddress(InetAddress address)
1096N/A throws IOException {
1096N/A return bindUnbindAddress(address, true);
1096N/A }
1096N/A
1096N/A @Override
1096N/A public SctpServerChannel unbindAddress(InetAddress address)
1096N/A throws IOException {
1096N/A return bindUnbindAddress(address, false);
1096N/A }
1096N/A
1096N/A private SctpServerChannel bindUnbindAddress(InetAddress address, boolean add)
1096N/A throws IOException {
1096N/A if (address == null)
1096N/A throw new IllegalArgumentException();
1096N/A
1096N/A synchronized (lock) {
1096N/A synchronized (stateLock) {
1096N/A if (!isOpen())
1096N/A throw new ClosedChannelException();
1096N/A if (!isBound())
1096N/A throw new NotYetBoundException();
1096N/A if (wildcard)
1096N/A throw new IllegalStateException(
1096N/A "Cannot add or remove addresses from a channel that is bound to the wildcard address");
1096N/A if (address.isAnyLocalAddress())
1096N/A throw new IllegalArgumentException(
1096N/A "Cannot add or remove the wildcard address");
1096N/A if (add) {
1096N/A for (InetSocketAddress addr : localAddresses) {
1096N/A if (addr.getAddress().equals(address)) {
2084N/A SctpNet.throwAlreadyBoundException();
1096N/A }
1096N/A }
1096N/A } else { /*removing */
1096N/A /* Verify that there is more than one address
1096N/A * and that address is already bound */
1096N/A if (localAddresses.size() <= 1)
1096N/A throw new IllegalUnbindException("Cannot remove address from a channel with only one address bound");
1096N/A boolean foundAddress = false;
1096N/A for (InetSocketAddress addr : localAddresses) {
1096N/A if (addr.getAddress().equals(address)) {
1096N/A foundAddress = true;
1096N/A break;
1096N/A }
1096N/A }
1096N/A if (!foundAddress )
1096N/A throw new IllegalUnbindException("Cannot remove address from a channel that is not bound to that address");
1096N/A }
1096N/A
1096N/A SctpNet.bindx(fdVal, new InetAddress[]{address}, port, add);
1096N/A
1096N/A /* Update our internal Set to reflect the addition/removal */
1096N/A if (add)
1096N/A localAddresses.add(new InetSocketAddress(address, port));
1096N/A else {
1096N/A for (InetSocketAddress addr : localAddresses) {
1096N/A if (addr.getAddress().equals(address)) {
1096N/A localAddresses.remove(addr);
1096N/A break;
1096N/A }
1096N/A }
1096N/A }
1096N/A }
1096N/A }
1096N/A return this;
1096N/A }
1096N/A
1096N/A private boolean isBound() {
1096N/A synchronized (stateLock) {
1096N/A return port == -1 ? false : true;
1096N/A }
1096N/A }
1096N/A
1096N/A private void acceptCleanup() throws IOException {
1096N/A synchronized (stateLock) {
1096N/A thread = 0;
1096N/A if (state == ChannelState.KILLPENDING)
1096N/A kill();
1096N/A }
1096N/A }
1096N/A
1096N/A @Override
1096N/A public SctpChannel accept() throws IOException {
1096N/A synchronized (lock) {
1096N/A if (!isOpen())
1096N/A throw new ClosedChannelException();
1096N/A if (!isBound())
1096N/A throw new NotYetBoundException();
1096N/A SctpChannel sc = null;
1096N/A
1096N/A int n = 0;
1096N/A FileDescriptor newfd = new FileDescriptor();
1096N/A InetSocketAddress[] isaa = new InetSocketAddress[1];
1096N/A
1096N/A try {
1096N/A begin();
1096N/A if (!isOpen())
1096N/A return null;
1096N/A thread = NativeThread.current();
1096N/A for (;;) {
1096N/A n = accept0(fd, newfd, isaa);
1096N/A if ((n == IOStatus.INTERRUPTED) && isOpen())
1096N/A continue;
1096N/A break;
1096N/A }
1096N/A } finally {
1096N/A acceptCleanup();
1096N/A end(n > 0);
1096N/A assert IOStatus.check(n);
1096N/A }
1096N/A
1096N/A if (n < 1)
1096N/A return null;
1096N/A
1096N/A IOUtil.configureBlocking(newfd, true);
1096N/A InetSocketAddress isa = isaa[0];
1096N/A sc = new SctpChannelImpl(provider(), newfd);
1096N/A
1096N/A SecurityManager sm = System.getSecurityManager();
1096N/A if (sm != null)
1096N/A sm.checkAccept(isa.getAddress().getHostAddress(),
1096N/A isa.getPort());
1096N/A
1096N/A return sc;
1096N/A }
1096N/A }
1096N/A
1096N/A @Override
1096N/A protected void implConfigureBlocking(boolean block) throws IOException {
1096N/A IOUtil.configureBlocking(fd, block);
1096N/A }
1096N/A
1096N/A @Override
1096N/A public void implCloseSelectableChannel() throws IOException {
1096N/A synchronized (stateLock) {
2084N/A SctpNet.preClose(fdVal);
1096N/A if (thread != 0)
1096N/A NativeThread.signal(thread);
1096N/A if (!isRegistered())
1096N/A kill();
1096N/A }
1096N/A }
1096N/A
1096N/A @Override
1096N/A public void kill() throws IOException {
1096N/A synchronized (stateLock) {
1096N/A if (state == ChannelState.KILLED)
1096N/A return;
1096N/A if (state == ChannelState.UNINITIALIZED) {
1096N/A state = ChannelState.KILLED;
1096N/A return;
1096N/A }
1096N/A assert !isOpen() && !isRegistered();
1096N/A
1096N/A // Postpone the kill if there is a thread in accept
1096N/A if (thread == 0) {
2084N/A SctpNet.close(fdVal);
1096N/A state = ChannelState.KILLED;
1096N/A } else {
1096N/A state = ChannelState.KILLPENDING;
1096N/A }
1096N/A }
1096N/A }
1096N/A
1096N/A @Override
1096N/A public FileDescriptor getFD() {
1096N/A return fd;
1096N/A }
1096N/A
1096N/A @Override
1096N/A public int getFDVal() {
1096N/A return fdVal;
1096N/A }
1096N/A
1096N/A /**
1096N/A * Translates native poll revent ops into a ready operation ops
1096N/A */
1096N/A private boolean translateReadyOps(int ops, int initialOps,
1096N/A SelectionKeyImpl sk) {
1096N/A int intOps = sk.nioInterestOps();
1096N/A int oldOps = sk.nioReadyOps();
1096N/A int newOps = initialOps;
1096N/A
1096N/A if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
1096N/A /* This should only happen if this channel is pre-closed while a
1096N/A * selection operation is in progress
1096N/A * ## Throw an error if this channel has not been pre-closed */
1096N/A return false;
1096N/A }
1096N/A
1096N/A if ((ops & (PollArrayWrapper.POLLERR
1096N/A | PollArrayWrapper.POLLHUP)) != 0) {
1096N/A newOps = intOps;
1096N/A sk.nioReadyOps(newOps);
1096N/A return (newOps & ~oldOps) != 0;
1096N/A }
1096N/A
1096N/A if (((ops & PollArrayWrapper.POLLIN) != 0) &&
1096N/A ((intOps & SelectionKey.OP_ACCEPT) != 0))
1096N/A newOps |= SelectionKey.OP_ACCEPT;
1096N/A
1096N/A sk.nioReadyOps(newOps);
1096N/A return (newOps & ~oldOps) != 0;
1096N/A }
1096N/A
1096N/A @Override
1096N/A public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
1096N/A return translateReadyOps(ops, sk.nioReadyOps(), sk);
1096N/A }
1096N/A
1096N/A @Override
1096N/A public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
1096N/A return translateReadyOps(ops, 0, sk);
1096N/A }
1096N/A
1096N/A @Override
1096N/A public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
1096N/A int newOps = 0;
1096N/A
1096N/A /* Translate ops */
1096N/A if ((ops & SelectionKey.OP_ACCEPT) != 0)
1096N/A newOps |= PollArrayWrapper.POLLIN;
1096N/A /* Place ops into pollfd array */
1096N/A sk.selector.putEventOps(sk, newOps);
1096N/A
1096N/A }
1096N/A
1096N/A @Override
1096N/A public <T> SctpServerChannel setOption(SctpSocketOption<T> name, T value)
1096N/A throws IOException {
1096N/A if (name == null)
1096N/A throw new NullPointerException();
1096N/A if (!supportedOptions().contains(name))
1096N/A throw new UnsupportedOperationException("'" + name + "' not supported");
1096N/A
1096N/A synchronized (stateLock) {
1096N/A if (!isOpen())
1096N/A throw new ClosedChannelException();
1096N/A
1096N/A SctpNet.setSocketOption(fdVal, name, value, 0 /*oneToOne*/);
1096N/A return this;
1096N/A }
1096N/A }
1096N/A
1096N/A @Override
1096N/A public <T> T getOption(SctpSocketOption<T> name) throws IOException {
1096N/A if (name == null)
1096N/A throw new NullPointerException();
1096N/A if (!supportedOptions().contains(name))
1096N/A throw new UnsupportedOperationException("'" + name + "' not supported");
1096N/A
1096N/A synchronized (stateLock) {
1096N/A if (!isOpen())
1096N/A throw new ClosedChannelException();
1096N/A
1096N/A return (T) SctpNet.getSocketOption(fdVal, name, 0 /*oneToOne*/);
1096N/A }
1096N/A }
1096N/A
1096N/A private static class DefaultOptionsHolder {
1096N/A static final Set<SctpSocketOption<?>> defaultOptions = defaultOptions();
1096N/A
1096N/A private static Set<SctpSocketOption<?>> defaultOptions() {
1096N/A HashSet<SctpSocketOption<?>> set = new HashSet<SctpSocketOption<?>>(1);
4216N/A set.add(SctpStandardSocketOptions.SCTP_INIT_MAXSTREAMS);
1096N/A return Collections.unmodifiableSet(set);
1096N/A }
1096N/A }
1096N/A
1096N/A @Override
1096N/A public final Set<SctpSocketOption<?>> supportedOptions() {
1096N/A return DefaultOptionsHolder.defaultOptions;
1096N/A }
1096N/A
1096N/A @Override
1096N/A public Set<SocketAddress> getAllLocalAddresses()
1096N/A throws IOException {
1096N/A synchronized (stateLock) {
1096N/A if (!isOpen())
1096N/A throw new ClosedChannelException();
1096N/A if (!isBound())
1326N/A return Collections.EMPTY_SET;
1096N/A
1096N/A return SctpNet.getLocalAddresses(fdVal);
1096N/A }
1096N/A }
1096N/A
1096N/A /* Native */
1096N/A private static native void initIDs();
1096N/A
1096N/A private static native int accept0(FileDescriptor ssfd,
1096N/A FileDescriptor newfd, InetSocketAddress[] isaa) throws IOException;
1096N/A
1096N/A static {
1096N/A Util.load(); // loads nio & net native libraries
1096N/A java.security.AccessController.doPrivileged(
1096N/A new sun.security.action.LoadLibraryAction("sctp"));
1096N/A initIDs();
1096N/A }
1096N/A}