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.server.subsystem.SubsystemFactory;
19 import org.opendaylight.netconf.transport.api.TransportChannelListener;
20 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
21 import org.opendaylight.netconf.transport.tcp.NettyTransportSupport;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.client.rev230417.SshClientGrouping;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.server.rev230417.SshServerGrouping;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.client.rev230417.TcpClientGrouping;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.server.rev230417.TcpServerGrouping;
28 * A factory capable of instantiating {@link SSHClient}s and {@link SSHServer}s.
30 public final class SSHTransportStackFactory implements AutoCloseable {
31 private final EventLoopGroup group;
32 private final EventLoopGroup parentGroup;
34 private SSHTransportStackFactory(final EventLoopGroup group, final EventLoopGroup parentGroup) {
35 this.group = requireNonNull(group);
36 this.parentGroup = parentGroup;
37 // FIXME: factoryFactory = new NettyIoServiceFactoryFactory(group);
40 public SSHTransportStackFactory(final @NonNull String groupName, final int groupThreads) {
41 this(NettyTransportSupport.newEventLoopGroup(groupName, groupThreads), null);
44 public SSHTransportStackFactory(final @NonNull String groupName, final int groupThreads,
45 final @NonNull String parentGroupName, final int parentGroupThreads) {
46 this(NettyTransportSupport.newEventLoopGroup(groupName, groupThreads),
47 NettyTransportSupport.newEventLoopGroup(parentGroupName, parentGroupThreads));
50 public @NonNull ListenableFuture<SSHClient> connectClient(final TransportChannelListener listener,
51 final TcpClientGrouping connectParams, final SshClientGrouping clientParams)
52 throws UnsupportedConfigurationException {
53 return SSHClient.of(group, listener, clientParams).connect(newBootstrap(), connectParams);
56 public @NonNull ListenableFuture<SSHClient> listenClient(final TransportChannelListener listener,
57 final TcpServerGrouping listenParams, final SshClientGrouping clientParams)
58 throws UnsupportedConfigurationException {
59 return SSHClient.of(group, listener, clientParams).listen(newServerBootstrap(), listenParams);
62 public @NonNull ListenableFuture<SSHServer> connectServer(final TransportChannelListener listener,
63 final SubsystemFactory subsystemFactory, final TcpClientGrouping connectParams,
64 final SshServerGrouping serverParams) throws UnsupportedConfigurationException {
65 return SSHServer.of(group, listener, subsystemFactory, requireNonNull(serverParams), null)
66 .connect(newBootstrap(), connectParams);
69 public @NonNull ListenableFuture<SSHServer> listenServer(final TransportChannelListener listener,
70 final SubsystemFactory subsystemFactory, final TcpServerGrouping connectParams,
71 final SshServerGrouping serverParams) throws UnsupportedConfigurationException {
72 return listenServer(listener, subsystemFactory, connectParams, requireNonNull(serverParams), null);
76 * Builds and starts SSH Server.
78 * @param listener server channel listener, required
79 * @param subsystemFactory A {@link SubsystemFactory} for the hosted subsystem
80 * @param listenParams TCP transport configuration, required
81 * @param serverParams SSH overlay configuration, optional if configurator is defined, required otherwise
82 * @param configurator server factory manager configurator, optional if serverParams is defined, required otherwise
83 * @return server instance as listenable future
84 * @throws UnsupportedConfigurationException if any of configurations is invalid or incomplete
85 * @throws NullPointerException if any of required parameters is null
86 * @throws IllegalArgumentException if both configurator and serverParams are null
88 public @NonNull ListenableFuture<SSHServer> listenServer(final TransportChannelListener listener,
89 final SubsystemFactory subsystemFactory, final TcpServerGrouping listenParams,
90 final SshServerGrouping serverParams, final ServerFactoryManagerConfigurator configurator)
91 throws UnsupportedConfigurationException {
92 checkArgument(serverParams != null || configurator != null,
93 "Neither server parameters nor factory configurator is defined");
94 return SSHServer.of(group, listener, subsystemFactory, serverParams, configurator)
95 .listen(newServerBootstrap(), listenParams);
99 * Create a new {@link Bootstrap} based on this factory's {@link EventLoopGroup}s.
101 * @return A new {@link Bootstrap}
103 public @NonNull Bootstrap newBootstrap() {
104 return NettyTransportSupport.newBootstrap().group(group);
108 * Create a new {@link ServerBootstrap} based on this factory's {@link EventLoopGroup}s.
110 * @return A new {@link ServerBootstrap}
112 public @NonNull ServerBootstrap newServerBootstrap() {
113 return NettyTransportSupport.newServerBootstrap().group(parentGroup != null ? parentGroup : group, group);
117 public void close() {
118 if (parentGroup != null) {
119 parentGroup.shutdownGracefully();
121 group.shutdownGracefully();