Bind SshClient/SshServer to NettyIoServiceFactoryFactory
[netconf.git] / transport / transport-ssh / src / main / java / org / opendaylight / netconf / transport / ssh / SSHTransportStackFactory.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech, s.r.o. 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.transport.ssh;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.util.concurrent.ListenableFuture;
14 import io.netty.bootstrap.Bootstrap;
15 import io.netty.bootstrap.ServerBootstrap;
16 import io.netty.channel.EventLoopGroup;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.netconf.shaded.sshd.netty.NettyIoServiceFactoryFactory;
19 import org.opendaylight.netconf.shaded.sshd.server.subsystem.SubsystemFactory;
20 import org.opendaylight.netconf.transport.api.TransportChannelListener;
21 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
22 import org.opendaylight.netconf.transport.tcp.NettyTransportSupport;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.client.rev230417.SshClientGrouping;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.server.rev230417.SshServerGrouping;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.client.rev230417.TcpClientGrouping;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.server.rev230417.TcpServerGrouping;
27
28 /**
29  * A factory capable of instantiating {@link SSHClient}s and {@link SSHServer}s.
30  */
31 public final class SSHTransportStackFactory implements AutoCloseable {
32     private final EventLoopGroup group;
33     private final EventLoopGroup parentGroup;
34     private final NettyIoServiceFactoryFactory ioServiceFactory;
35
36     private SSHTransportStackFactory(final EventLoopGroup group, final EventLoopGroup parentGroup) {
37         this.group = requireNonNull(group);
38         this.parentGroup = parentGroup;
39         ioServiceFactory = new NettyIoServiceFactoryFactory(group);
40     }
41
42     public SSHTransportStackFactory(final @NonNull String groupName, final int groupThreads) {
43         this(NettyTransportSupport.newEventLoopGroup(groupName, groupThreads), null);
44     }
45
46     public SSHTransportStackFactory(final @NonNull String groupName, final int groupThreads,
47             final @NonNull String parentGroupName, final int parentGroupThreads) {
48         this(NettyTransportSupport.newEventLoopGroup(groupName, groupThreads),
49             NettyTransportSupport.newEventLoopGroup(parentGroupName, parentGroupThreads));
50     }
51
52     public @NonNull ListenableFuture<SSHClient> connectClient(final TransportChannelListener listener,
53             final TcpClientGrouping connectParams, final SshClientGrouping clientParams)
54                 throws UnsupportedConfigurationException {
55         return SSHClient.of(ioServiceFactory, group, listener, clientParams).connect(newBootstrap(), connectParams);
56     }
57
58     public @NonNull ListenableFuture<SSHClient> listenClient(final TransportChannelListener listener,
59             final TcpServerGrouping listenParams, final SshClientGrouping clientParams)
60                 throws UnsupportedConfigurationException {
61         return SSHClient.of(ioServiceFactory, group, listener, clientParams).listen(newServerBootstrap(), listenParams);
62     }
63
64     public @NonNull ListenableFuture<SSHServer> connectServer(final TransportChannelListener listener,
65             final SubsystemFactory subsystemFactory, final TcpClientGrouping connectParams,
66             final SshServerGrouping serverParams) throws UnsupportedConfigurationException {
67         return SSHServer.of(ioServiceFactory, group, listener, subsystemFactory, requireNonNull(serverParams), null)
68             .connect(newBootstrap(), connectParams);
69     }
70
71     public @NonNull ListenableFuture<SSHServer> listenServer(final TransportChannelListener listener,
72             final SubsystemFactory subsystemFactory, final TcpServerGrouping connectParams,
73             final SshServerGrouping serverParams) throws UnsupportedConfigurationException {
74         return listenServer(listener, subsystemFactory, connectParams, requireNonNull(serverParams), null);
75     }
76
77     /**
78      * Builds and starts SSH Server.
79      *
80      * @param listener server channel listener, required
81      * @param subsystemFactory A {@link SubsystemFactory} for the hosted subsystem
82      * @param listenParams TCP transport configuration, required
83      * @param serverParams SSH overlay configuration, optional if configurator is defined, required otherwise
84      * @param configurator server factory manager configurator, optional if serverParams is defined, required otherwise
85      * @return server instance as listenable future
86      * @throws UnsupportedConfigurationException if any of configurations is invalid or incomplete
87      * @throws NullPointerException if any of required parameters is null
88      * @throws IllegalArgumentException if both configurator and serverParams are null
89      */
90     public @NonNull ListenableFuture<SSHServer> listenServer(final TransportChannelListener listener,
91             final SubsystemFactory subsystemFactory, final TcpServerGrouping listenParams,
92             final SshServerGrouping serverParams, final ServerFactoryManagerConfigurator configurator)
93                     throws UnsupportedConfigurationException {
94         checkArgument(serverParams != null || configurator != null,
95             "Neither server parameters nor factory configurator is defined");
96         return SSHServer.of(ioServiceFactory, group, listener, subsystemFactory, serverParams, configurator)
97             .listen(newServerBootstrap(), listenParams);
98     }
99
100     /**
101      * Create a new {@link Bootstrap} based on this factory's {@link EventLoopGroup}s.
102      *
103      * @return A new {@link Bootstrap}
104      */
105     public @NonNull Bootstrap newBootstrap() {
106         return NettyTransportSupport.newBootstrap().group(group);
107     }
108
109     /**
110      * Create a new {@link ServerBootstrap} based on this factory's {@link EventLoopGroup}s.
111      *
112      * @return A new {@link ServerBootstrap}
113      */
114     public @NonNull ServerBootstrap newServerBootstrap() {
115         return NettyTransportSupport.newServerBootstrap().group(parentGroup != null ? parentGroup : group, group);
116     }
117
118     @Override
119     public void close() {
120         if (parentGroup != null) {
121             parentGroup.shutdownGracefully();
122         }
123         group.shutdownGracefully();
124     }
125 }