Merge "BUG-1612 Implement mina ssh netconf server endpoint"
[controller.git] / opendaylight / netconf / netconf-ssh / src / main / java / org / opendaylight / controller / netconf / ssh / SshProxyServer.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.netconf.ssh;
10
11 import com.google.common.collect.Lists;
12 import io.netty.channel.EventLoopGroup;
13 import io.netty.channel.local.LocalAddress;
14 import java.io.IOException;
15 import java.net.InetSocketAddress;
16 import java.nio.channels.AsynchronousChannelGroup;
17 import java.util.concurrent.ExecutorService;
18 import java.util.concurrent.ScheduledExecutorService;
19 import java.util.concurrent.TimeUnit;
20 import org.apache.sshd.SshServer;
21 import org.apache.sshd.common.FactoryManager;
22 import org.apache.sshd.common.KeyPairProvider;
23 import org.apache.sshd.common.NamedFactory;
24 import org.apache.sshd.common.RuntimeSshException;
25 import org.apache.sshd.common.io.IoAcceptor;
26 import org.apache.sshd.common.io.IoConnector;
27 import org.apache.sshd.common.io.IoHandler;
28 import org.apache.sshd.common.io.IoServiceFactory;
29 import org.apache.sshd.common.io.IoServiceFactoryFactory;
30 import org.apache.sshd.common.io.nio2.Nio2Acceptor;
31 import org.apache.sshd.common.io.nio2.Nio2Connector;
32 import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
33 import org.apache.sshd.common.util.CloseableUtils;
34 import org.apache.sshd.server.Command;
35 import org.apache.sshd.server.PasswordAuthenticator;
36
37 /**
38  * Proxy SSH server that just delegates decrypted content to a delegate server within same VM.
39  * Implemented using Apache Mina SSH lib.
40  */
41 public class SshProxyServer implements AutoCloseable {
42
43     private final SshServer sshServer;
44     private final ScheduledExecutorService minaTimerExecutor;
45     private final EventLoopGroup clientGroup;
46     private final IoServiceFactoryFactory nioServiceWithPoolFactoryFactory;
47
48     public SshProxyServer(final ScheduledExecutorService minaTimerExecutor, final EventLoopGroup clientGroup, final ExecutorService nioExecutor) {
49         this.minaTimerExecutor = minaTimerExecutor;
50         this.clientGroup = clientGroup;
51         this.nioServiceWithPoolFactoryFactory = new NioServiceWithPoolFactory.NioServiceWithPoolFactoryFactory(nioExecutor);
52         this.sshServer = SshServer.setUpDefaultServer();
53     }
54
55     public void bind(final InetSocketAddress bindingAddress, final LocalAddress localAddress, final PasswordAuthenticator authenticator, final KeyPairProvider keyPairProvider) throws IOException {
56         sshServer.setHost(bindingAddress.getHostString());
57         sshServer.setPort(bindingAddress.getPort());
58
59         sshServer.setPasswordAuthenticator(authenticator);
60         sshServer.setKeyPairProvider(keyPairProvider);
61
62         sshServer.setIoServiceFactoryFactory(nioServiceWithPoolFactoryFactory);
63         sshServer.setScheduledExecutorService(minaTimerExecutor);
64
65         final RemoteNetconfCommand.NetconfCommandFactory netconfCommandFactory =
66                 new RemoteNetconfCommand.NetconfCommandFactory(clientGroup, localAddress);
67         sshServer.setSubsystemFactories(Lists.<NamedFactory<Command>>newArrayList(netconfCommandFactory));
68         sshServer.start();
69     }
70
71     @Override
72     public void close() {
73         try {
74             sshServer.stop(true);
75         } catch (final InterruptedException e) {
76             throw new RuntimeException("Interrupted while stopping sshServer", e);
77         } finally {
78             sshServer.close(true);
79         }
80     }
81
82     /**
83      * Based on Nio2ServiceFactory with one addition: injectable executor
84      */
85     private static final class NioServiceWithPoolFactory extends CloseableUtils.AbstractCloseable implements IoServiceFactory {
86
87         private final FactoryManager manager;
88         private final AsynchronousChannelGroup group;
89
90         public NioServiceWithPoolFactory(final FactoryManager manager, final ExecutorService executor) {
91             this.manager = manager;
92             try {
93                 group = AsynchronousChannelGroup.withThreadPool(executor);
94             } catch (final IOException e) {
95                 throw new RuntimeSshException(e);
96             }
97         }
98
99         public IoConnector createConnector(final IoHandler handler) {
100             return new Nio2Connector(manager, handler, group);
101         }
102
103         public IoAcceptor createAcceptor(final IoHandler handler) {
104             return new Nio2Acceptor(manager, handler, group);
105         }
106
107         @Override
108         protected void doCloseImmediately() {
109             try {
110                 group.shutdownNow();
111                 group.awaitTermination(5, TimeUnit.SECONDS);
112             } catch (final Exception e) {
113                 log.debug("Exception caught while closing channel group", e);
114             } finally {
115                 super.doCloseImmediately();
116             }
117         }
118
119         private static final class NioServiceWithPoolFactoryFactory extends Nio2ServiceFactoryFactory {
120
121             private final ExecutorService nioExecutor;
122
123             private NioServiceWithPoolFactoryFactory(final ExecutorService nioExecutor) {
124                 this.nioExecutor = nioExecutor;
125             }
126
127             @Override
128             public IoServiceFactory create(final FactoryManager manager) {
129                 return new NioServiceWithPoolFactory(manager, nioExecutor);
130             }
131         }
132     }
133
134 }