diff options
Diffstat (limited to 'framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AcceptorLoop.java')
-rw-r--r-- | framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AcceptorLoop.java | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AcceptorLoop.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AcceptorLoop.java new file mode 100644 index 00000000..e416f3be --- /dev/null +++ b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AcceptorLoop.java @@ -0,0 +1,123 @@ +/* + * Copyright 2014 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.nio; + +import java.io.IOException; +import java.net.SocketAddress; +import java.net.StandardSocketOptions; +import java.nio.channels.SelectionKey; +import java.nio.channels.ServerSocketChannel; +import java.util.Iterator; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Selector loop derivative tailored to acceptConnection inbound connections. + */ +public abstract class AcceptorLoop extends SelectorLoop { + + private SocketAddress listenAddress; + private ServerSocketChannel socketChannel; + + /** + * Creates an acceptor loop with the specified selection timeout and + * accepting connections on the the given address. + * + * @param selectTimeout selection timeout; specified in millis + * @param listenAddress socket address where to listen for connections + * @throws IOException if the backing selector cannot be opened + */ + public AcceptorLoop(long selectTimeout, SocketAddress listenAddress) + throws IOException { + super(selectTimeout); + this.listenAddress = checkNotNull(listenAddress, "Address cannot be null"); + } + + /** + * Hook to accept an inbound connection on the specified socket channel. + * + * @param channel socketChannel where an accept operation awaits + * @throws IOException if the accept operation cannot be processed + */ + protected abstract void acceptConnection(ServerSocketChannel channel) throws IOException; + + /** + * Opens a new server socket channel configured in non-blocking mode and + * bound to the loop's listen address. + * + * @throws IOException if unable to open or configure the socket channel + */ + protected synchronized void openChannel() throws IOException { + socketChannel = ServerSocketChannel.open(); + socketChannel.configureBlocking(false); + socketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); + socketChannel.register(selector, SelectionKey.OP_ACCEPT); + socketChannel.bind(listenAddress); + } + + /** + * Closes the server socket channel. + * + * @throws IOException if unable to close the socketChannel + */ + protected synchronized void closechannel() throws IOException { + if (socketChannel != null) { + socketChannel.close(); + socketChannel = null; + } + } + + @Override + public void shutdown() { + try { + closechannel(); + } catch (IOException e) { + log.warn("Unable to close the socketChannel", e); + } + super.shutdown(); + } + + @Override + protected void loop() throws IOException { + openChannel(); + notifyReady(); + + // Keep looping until told otherwise. + while (isRunning()) { + // Attempt a selection; if no operations selected or if signalled + // to shutdown, spin through. + int count = selector.select(selectTimeout); + if (count == 0 || !isRunning()) { + continue; + } + + // Iterate over all keys selected for an operation and process them. + Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); + while (keys.hasNext()) { + // Fetch the key and remove it from the pending list. + SelectionKey key = keys.next(); + keys.remove(); + + // If the key has a pending acceptConnection operation, process it. + if (key.isAcceptable()) { + acceptConnection((ServerSocketChannel) key.channel()); + } + } + } + } + +} + |