Managing SSH connections with C#

A new business requirement discussed recently was to connect and retrieve some data from a database hosted in an external network.

Deep in dive on the preconditions I discover that the only way to connect to the database was to establish an SSH connection, so I started to ask about the parameters to be used to activate the connection.

Another precondition was that the connection had to be resilience and reliable because the application that would have used this database would have executed many searchs on that database (about thousands per day); this was an important aspect, because create and shutdown the connection every time the application made the search would be very inefficient in terms of performance.

So what I had to do was managing the creation of the connection, the live and the reinitialization when something gone wrong.

What we’ll see in this topic is create and manage an SSH connection using the common library SSH.NET.

Initialization

We need to implement a class, for example Connector, that in the constructor accept a string with the parameters of the SSH connection:

public class Connector : IDisposable
{
private string _server;
private string _port;
private string _uid;
private string _password;
private string _database;

private string _sshhost;
private string _sshport;
private string _sshdbport;
private string _sshusername;
private string _sshpassword;

private ForwardedPortLocal _forwardedPortLocal;

public Connector(string parameters)
{
ParametersInitialization(parameters);
}
private void ParametersInitialization(string parameters)
{
if (string.IsNullOrEmpty(parameters))
throw new ArgumentNullException("Missing parameters");
var list = parameters.Split(';');
foreach (var parameter in list)
{
var values = parameter.Split('=');
if (values.Length != 2) continue;
switch (values[0].ToLower())
{
case "server":
_server = values[1];
break;
case "port":
_port = values[1];
break;
.....
}
}
if (string.IsNullOrEmpty(_server))
throw new ArgumentNullException("Missing 'server' parameter.");
.....

ForwardedPortInitialization();
}

private void ForwardedPortInitialization()
{
_forwardedPortLocal = new ForwardedPortLocal(_server, uint.Parse(_port), _server, uint.Parse(_sshdbport));
}
}

In order to retrieve the connection string parameters the class parse the input string and check if the format is good.

In this phase the SSH forwarded local port is initialized as well.

Another property that we can add is the SSH connetion info, that will be useful later in the creation of the SSH client.

In the connection info we specify the host, port, username and password; we can setup the timeout of the connection as well:


private PasswordConnectionInfo _sshConnectionInfo;
private PasswordConnectionInfo sshConnectionInfo
{
get
{
if (_sshConnectionInfo == null)
{
_sshConnectionInfo = new PasswordConnectionInfo(_sshhost, int.Parse(_sshport), _sshusername, _sshpassword);
_sshConnectionInfo.Timeout = TimeSpan.FromSeconds(5000);
}

return _sshConnectionInfo;
}
}

Now we can create a new connector and pass the connection string in the constructor like this:


public class Service
{
private readonly Connector _connector;

public Service()
{
_connector = new Connector("Server=127.0.0.1;Port=5431;Database=database name;Uid=username;Password=password;sshHost=ip address;sshPort=2022;sshDbPort=5432;sshUsername=sshUsername;sshPassword=sshPassword");
}
}

Connection management

Now that the parameters are initialized we can implements the methods for connection and disconnection.

Assuming that we know the SSH.NET library, the connection method is pretty simple:


public void Connect()
{
try
{
if (_client == null)
{
_client = new SshClient(sshConnectionInfo);
_client.KeepAliveInterval = new TimeSpan(0, 0, 20);
}

if (_forwardedPortLocal == null)
{
ForwardedPortInitialization();
}

if (!_client.IsConnected)
{
_client.Connect();
_client.AddForwardedPort(_forwardedPortLocal);
_forwardedPortLocal.Start();
}
}
catch (Exception ex)
{
Disconnect();
throw;
}
}

In order to mantain the session alive between two different calls, we define the KeepAliveInterval property to 20 seconds.

We inizialize the forwarded local port if is necessary and if is not connected we connect the client and startup the local port.

In the catch statement we cleanup all the resources with the Disconnect method:


private void Disconnect()
{
if (_client != null)
{
if (_forwardedPortLocal.IsStarted)
{
_forwardedPortLocal.Stop();
}

if (_client.IsConnected)
{
_client.Disconnect();
}

_forwardedPortLocal.Dispose();
_client.Dispose();

_forwardedPortLocal = null;
_client = null;
}
}

We stop the forwarded local port and disconnect the client; then we dispose all the objects involved in the process.

In order to complete the implementation, we need to implement the dispose and the finalizer methods:


~Connector()
{
Dispose();
}

public void Dispose()
{
Disconnect();
GC.SuppressFinalize(false);
}

This is a safe finalization, beyond to implement the connector as disposable and expose the dispose method to the caller, we implement the finalizer in order to make sure that if the caller forgot to dispose the connector, we’ll do that with the finalizer.

You can find the source code here.

 

One thought on “Managing SSH connections with C#

Add yours

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at WordPress.com

Up ↑

%d bloggers like this: