X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fnetconf-ssh%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fnetconf%2Fssh%2FNetconfSSHServer.java;h=86206a7d5cad932c3b8510a7c2518d36c06c4f51;hb=99a0b01f27126a17ec2af165cf3fd9e53c977d2b;hp=dad149fd60b762704fbf4c5f4d79882c51b8b676;hpb=d82b96055d2c0d471c85c2b2b3cb30e52fff1c69;p=controller.git diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java index dad149fd60..86206a7d5c 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java @@ -1,32 +1,134 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.netconf.ssh; +import com.google.common.base.Preconditions; +import java.io.IOException; +import java.net.InetSocketAddress; import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicLong; -public class NetconfSSHServer { +import javax.annotation.concurrent.ThreadSafe; - private static boolean acceptMore = true; - private static final int SERVER_PORT = 830; - private ServerSocket ss = null; +import org.opendaylight.controller.netconf.auth.AuthProvider; +import org.opendaylight.controller.netconf.ssh.threads.Handshaker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; - private NetconfSSHServer() throws Exception{ - this.ss = new ServerSocket(SERVER_PORT); - while (acceptMore) { - SocketThread.start(ss.accept()); +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; + +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; + +/** + * Thread that accepts client connections. Accepted socket is forwarded to {@link org.opendaylight.controller.netconf.ssh.threads.Handshaker}, + * which is executed in {@link #handshakeExecutor}. + */ +@ThreadSafe +public final class NetconfSSHServer extends Thread implements AutoCloseable { + + private static final Logger logger = LoggerFactory.getLogger(NetconfSSHServer.class); + private static final AtomicLong sessionIdCounter = new AtomicLong(); + + private final ServerSocket serverSocket; + private final LocalAddress localAddress; + private final EventLoopGroup bossGroup; + private Optional authProvider = Optional.absent(); + private final ExecutorService handshakeExecutor; + private final char[] pem; + private volatile boolean up; + + private NetconfSSHServer(final int serverPort, final LocalAddress localAddress, final EventLoopGroup bossGroup, final char[] pem) throws IOException { + super(NetconfSSHServer.class.getSimpleName()); + this.bossGroup = bossGroup; + this.pem = pem; + logger.trace("Creating SSH server socket on port {}", serverPort); + this.serverSocket = new ServerSocket(serverPort); + if (serverSocket.isBound() == false) { + throw new IllegalStateException("Socket can't be bound to requested port :" + serverPort); + } + logger.trace("Server socket created."); + this.localAddress = localAddress; + this.up = true; + handshakeExecutor = Executors.newFixedThreadPool(10); + } + + public static NetconfSSHServer start(final int serverPort, final LocalAddress localAddress, final EventLoopGroup bossGroup, final char[] pemArray) throws IOException { + final NetconfSSHServer netconfSSHServer = new NetconfSSHServer(serverPort, localAddress, bossGroup, pemArray); + netconfSSHServer.start(); + return netconfSSHServer; + } + + public synchronized AuthProvider getAuthProvider() { + Preconditions.checkState(authProvider.isPresent(), "AuthenticationProvider is not set up, cannot authenticate user"); + return authProvider.get(); + } + + public synchronized void setAuthProvider(final AuthProvider authProvider) { + if(this.authProvider != null) { + logger.debug("Changing auth provider to {}", authProvider); } + this.authProvider = Optional.fromNullable(authProvider); + } + + @Override + public void close() throws IOException { + up = false; + logger.trace("Closing SSH server socket."); + serverSocket.close(); + bossGroup.shutdownGracefully(); + logger.trace("SSH server socket closed."); } - public static NetconfSSHServer start() throws Exception { - return new NetconfSSHServer(); + + @VisibleForTesting + public InetSocketAddress getLocalSocketAddress() { + return (InetSocketAddress) serverSocket.getLocalSocketAddress(); } - public void stop() throws Exception { - ss.close(); + @Override + public void run() { + while (up) { + Socket acceptedSocket = null; + try { + acceptedSocket = serverSocket.accept(); + } catch (final IOException e) { + if (up == false) { + logger.trace("Exiting server thread", e); + } else { + logger.warn("Exception occurred during socket.accept", e); + } + } + if (acceptedSocket != null) { + try { + final Handshaker task = new Handshaker(acceptedSocket, localAddress, sessionIdCounter.incrementAndGet(), getAuthProvider(), bossGroup, pem); + handshakeExecutor.submit(task); + } catch (final IOException e) { + logger.warn("Cannot set PEMHostKey, closing connection", e); + closeSocket(acceptedSocket); + } catch (final IllegalStateException e) { + logger.warn("Cannot accept connection, closing", e); + closeSocket(acceptedSocket); + } + } + } + logger.debug("Server thread is exiting"); + } + + private void closeSocket(final Socket acceptedSocket) { + try { + acceptedSocket.close(); + } catch (final IOException e) { + logger.warn("Ignoring exception while closing socket", e); + } } }