Move NetconfServerDispatcher to netconf.server.api
[netconf.git] / netconf / mdsal-netconf-ssh / src / main / java / org / opendaylight / netconf / ssh / NetconfNorthboundSshServer.java
1 /*
2  * Copyright (c) 2016 Inocybe Technologies 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 package org.opendaylight.netconf.ssh;
9
10 import io.netty.channel.ChannelFuture;
11 import io.netty.channel.EventLoopGroup;
12 import io.netty.channel.local.LocalAddress;
13 import io.netty.util.concurrent.EventExecutor;
14 import java.io.IOException;
15 import java.net.InetSocketAddress;
16 import java.util.concurrent.Executors;
17 import org.opendaylight.netconf.auth.AuthProvider;
18 import org.opendaylight.netconf.server.api.NetconfServerDispatcher;
19 import org.opendaylight.netconf.shaded.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
21 import org.osgi.service.component.annotations.Activate;
22 import org.osgi.service.component.annotations.Component;
23 import org.osgi.service.component.annotations.Deactivate;
24 import org.osgi.service.component.annotations.Reference;
25 import org.osgi.service.metatype.annotations.AttributeDefinition;
26 import org.osgi.service.metatype.annotations.Designate;
27 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * NETCONF server for MD-SAL (listening by default on port 2830).
33  */
34 @Component(service = { }, configurationPid = "org.opendaylight.netconf.ssh")
35 @Designate(ocd = NetconfNorthboundSshServer.Configuration.class)
36 public final class NetconfNorthboundSshServer implements AutoCloseable {
37     @ObjectClassDefinition
38     public @interface Configuration {
39         @AttributeDefinition
40         String bindingAddress() default "0.0.0.0";
41         @AttributeDefinition(min = "1", max = "65535")
42         int portNumber() default 2830;
43     }
44
45     private static final Logger LOG = LoggerFactory.getLogger(NetconfNorthboundSshServer.class);
46
47     private final ChannelFuture localServer;
48     private final SshProxyServer sshProxyServer;
49
50     @Activate
51     public NetconfNorthboundSshServer(
52             @Reference final NetconfServerDispatcher netconfServerDispatcher,
53             @Reference(target = "(type=global-worker-group)") final EventLoopGroup workerGroup,
54             @Reference(target = "(type=global-event-executor)") final EventExecutor eventExecutor,
55             @Reference(target = "(type=netconf-auth-provider)") final AuthProvider authProvider,
56             final Configuration configuration) {
57         this(netconfServerDispatcher, workerGroup, eventExecutor, authProvider, configuration.bindingAddress(),
58             configuration.portNumber());
59     }
60
61     public NetconfNorthboundSshServer(final NetconfServerDispatcher netconfServerDispatcher,
62             final EventLoopGroup workerGroup, final EventExecutor eventExecutor, final AuthProvider authProvider,
63             final String bindingAddress, final int portNumber) {
64         final LocalAddress localAddress = new LocalAddress(String.valueOf(portNumber));
65         final var sshProxyServerConfiguration = new SshProxyServerConfigurationBuilder()
66             .setBindingAddress(getInetAddress(bindingAddress, portNumber))
67             .setLocalAddress(localAddress)
68             .setAuthenticator(authProvider)
69             .setIdleTimeout(Integer.MAX_VALUE)
70             .setKeyPairProvider(new SimpleGeneratorHostKeyProvider())
71             .createSshProxyServerConfiguration();
72
73         localServer = netconfServerDispatcher.createLocalServer(localAddress);
74         sshProxyServer = new SshProxyServer(Executors.newScheduledThreadPool(1), workerGroup, eventExecutor);
75
76         localServer.addListener(future -> {
77             if (future.isDone() && !future.isCancelled()) {
78                 try {
79                     sshProxyServer.bind(sshProxyServerConfiguration);
80                 } catch (final IOException e) {
81                     throw new IllegalStateException("Unable to start SSH netconf server", e);
82                 }
83                 LOG.info("Netconf SSH endpoint started successfully at {}", bindingAddress);
84             } else {
85                 LOG.warn("Unable to start SSH netconf server at {}", bindingAddress, future.cause());
86                 throw new IllegalStateException("Unable to start SSH netconf server", future.cause());
87             }
88         });
89     }
90
91     @Deactivate
92     @Override
93     public void close() throws IOException {
94         sshProxyServer.close();
95
96         if (localServer.isDone()) {
97             localServer.channel().close();
98         } else {
99             localServer.cancel(true);
100         }
101     }
102
103     private static InetSocketAddress getInetAddress(final String bindingAddress, final int portNumber) {
104         final var ipAddress = IetfInetUtil.ipAddressFor(bindingAddress);
105         return new InetSocketAddress(IetfInetUtil.INSTANCE.inetAddressFor(ipAddress), portNumber);
106     }
107 }