2 * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.netconf.transport.ssh;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
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;
29 * A factory capable of instantiating {@link SSHClient}s and {@link SSHServer}s.
31 public final class SSHTransportStackFactory implements AutoCloseable {
32 private final EventLoopGroup group;
33 private final EventLoopGroup parentGroup;
34 private final NettyIoServiceFactoryFactory ioServiceFactory;
36 private SSHTransportStackFactory(final EventLoopGroup group, final EventLoopGroup parentGroup) {
37 this.group = requireNonNull(group);
38 this.parentGroup = parentGroup;
39 ioServiceFactory = new NettyIoServiceFactoryFactory(group);
42 public SSHTransportStackFactory(final @NonNull String groupName, final int groupThreads) {
43 this(NettyTransportSupport.newEventLoopGroup(groupName, groupThreads), null);
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));
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);
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);
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);
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);
78 * Builds and starts SSH Server.
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
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);
101 * Create a new {@link Bootstrap} based on this factory's {@link EventLoopGroup}s.
103 * @return A new {@link Bootstrap}
105 public @NonNull Bootstrap newBootstrap() {
106 return NettyTransportSupport.newBootstrap().group(group);
110 * Create a new {@link ServerBootstrap} based on this factory's {@link EventLoopGroup}s.
112 * @return A new {@link ServerBootstrap}
114 public @NonNull ServerBootstrap newServerBootstrap() {
115 return NettyTransportSupport.newServerBootstrap().group(parentGroup != null ? parentGroup : group, group);
119 public void close() {
120 if (parentGroup != null) {
121 parentGroup.shutdownGracefully();
123 group.shutdownGracefully();