X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fnetconf-ssh%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fnetconf%2Fssh%2Fosgi%2FNetconfSSHActivator.java;h=fa87b73fad2b10bc977f0d88134c1fe21f5fb676;hp=503e764409e37d848ffeaf444c5e34e529bd6849;hb=f1ca77023bf3fc98df26214d32360136b196e464;hpb=63b36aa3537d77bd9be323e1113716ef2cd54098 diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java index 503e764409..fa87b73fad 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java @@ -10,18 +10,19 @@ package org.opendaylight.controller.netconf.ssh.osgi; import static com.google.common.base.Preconditions.checkState; import com.google.common.base.Optional; -import io.netty.channel.EventLoopGroup; +import com.google.common.base.Strings; import io.netty.channel.local.LocalAddress; import io.netty.channel.nio.NioEventLoopGroup; -import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang3.StringUtils; -import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; -import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; -import org.opendaylight.controller.netconf.ssh.authentication.AuthProviderImpl; -import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import org.apache.sshd.common.util.ThreadUtils; +import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider; +import org.opendaylight.controller.netconf.ssh.SshProxyServer; +import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil.InfixProp; import org.osgi.framework.BundleActivator; @@ -29,60 +30,87 @@ import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator - * starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket - * and listens for client connections. Each client connection creation is handled in separate - * {@link org.opendaylight.controller.netconf.ssh.threads.Handshaker} thread. - * This thread creates two additional threads {@link org.opendaylight.controller.netconf.ssh.threads.IOThread} - * forwarding data from/to client.IOThread closes servers session and server connection when it gets -1 on input stream. - * {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}'s run method waits for -1 on input stream to finish. - * All threads are daemons. - */ public class NetconfSSHActivator implements BundleActivator { - private static final Logger logger = LoggerFactory.getLogger(NetconfSSHActivator.class); + private static final Logger LOG = LoggerFactory.getLogger(NetconfSSHActivator.class); + + private static final java.lang.String ALGORITHM = "RSA"; + private static final int KEY_SIZE = 4096; + public static final int POOL_SIZE = 8; + private static final int DEFAULT_IDLE_TIMEOUT = Integer.MAX_VALUE; - private NetconfSSHServer server; + private ScheduledExecutorService minaTimerExecutor; + private NioEventLoopGroup clientGroup; + private ExecutorService nioExecutor; + private AuthProviderTracker authProviderTracker; + + private SshProxyServer server; @Override public void start(final BundleContext bundleContext) throws IOException { + minaTimerExecutor = Executors.newScheduledThreadPool(POOL_SIZE, new ThreadFactory() { + @Override + public Thread newThread(final Runnable r) { + return new Thread(r, "netconf-ssh-server-mina-timers"); + } + }); + clientGroup = new NioEventLoopGroup(); + nioExecutor = ThreadUtils.newFixedThreadPool("netconf-ssh-server-nio-group", POOL_SIZE); server = startSSHServer(bundleContext); } @Override - public void stop(BundleContext context) throws IOException { + public void stop(final BundleContext context) throws IOException { if (server != null) { server.close(); } + + if(authProviderTracker != null) { + authProviderTracker.stop(); + } + + if(nioExecutor!=null) { + nioExecutor.shutdownNow(); + } + + if(clientGroup != null) { + clientGroup.shutdownGracefully(); + } + + if(minaTimerExecutor != null) { + minaTimerExecutor.shutdownNow(); + } } - private static NetconfSSHServer startSSHServer(BundleContext bundleContext) throws IOException { - Optional maybeSshSocketAddress = NetconfConfigUtil.extractNetconfServerAddress(bundleContext, - InfixProp.ssh); + private SshProxyServer startSSHServer(final BundleContext bundleContext) throws IOException { + final Optional maybeSshSocketAddress = NetconfConfigUtil.extractNetconfServerAddress(bundleContext, InfixProp.ssh); - if (maybeSshSocketAddress.isPresent() == false) { - logger.trace("SSH bridge not configured"); + if (!maybeSshSocketAddress.isPresent()) { + LOG.trace("SSH bridge not configured"); return null; } - InetSocketAddress sshSocketAddress = maybeSshSocketAddress.get(); - logger.trace("Starting netconf SSH bridge at {}", sshSocketAddress); - LocalAddress localAddress = NetconfConfigUtil.getNetconfLocalAddress(); + final InetSocketAddress sshSocketAddress = maybeSshSocketAddress.get(); + LOG.trace("Starting netconf SSH bridge at {}", sshSocketAddress); - String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(bundleContext)); - checkState(StringUtils.isNotBlank(path), "Path to ssh private key is blank. Reconfigure %s", NetconfConfigUtil.getPrivateKeyKey()); - String privateKeyPEMString = PEMGenerator.readOrGeneratePK(new File(path)); + final LocalAddress localAddress = NetconfConfigUtil.getNetconfLocalAddress(); - final AuthProvider authProvider = new AuthProviderImpl(privateKeyPEMString, bundleContext); - EventLoopGroup bossGroup = new NioEventLoopGroup(); - NetconfSSHServer server = NetconfSSHServer.start(sshSocketAddress.getPort(), localAddress, authProvider, bossGroup); + authProviderTracker = new AuthProviderTracker(bundleContext); - final Thread serverThread = new Thread(server, "netconf SSH server thread"); - serverThread.setDaemon(true); - serverThread.start(); - logger.trace("Netconf SSH bridge up and running."); - return server; - } + final String path = NetconfConfigUtil.getPrivateKeyPath(bundleContext); + + checkState(!Strings.isNullOrEmpty(path), "Path to ssh private key is blank. Reconfigure %s", + NetconfConfigUtil.getPrivateKeyKey()); + final SshProxyServer sshProxyServer = new SshProxyServer(minaTimerExecutor, clientGroup, nioExecutor); + sshProxyServer.bind( + new SshProxyServerConfigurationBuilder() + .setBindingAddress(sshSocketAddress) + .setLocalAddress(localAddress) + .setAuthenticator(authProviderTracker) + .setKeyPairProvider(new PEMGeneratorHostKeyProvider(path, ALGORITHM, KEY_SIZE)) + .setIdleTimeout(DEFAULT_IDLE_TIMEOUT) + .createSshProxyServerConfiguration()); + return sshProxyServer; + } }