using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Diagnostics.CodeAnalysis;
using Renci.SshNet.Common;
namespace Renci.SshNet
{
///
/// Provides client connection to SSH server.
///
public class SshClient : BaseClient
{
///
/// Holds the list of forwarded ports
///
private readonly List _forwardedPorts;
private Stream _inputStream;
///
/// Gets the list of forwarded ports.
///
public IEnumerable ForwardedPorts
{
get
{
return this._forwardedPorts.AsReadOnly();
}
}
#region Constructors
///
/// Initializes a new instance of the class.
///
/// The connection info.
///
///
///
///
///
///
/// is null.
public SshClient(ConnectionInfo connectionInfo)
: this(connectionInfo, false)
{
}
///
/// Initializes a new instance of the class.
///
/// Connection host.
/// Connection port.
/// Authentication username.
/// Authentication password.
/// is null.
/// is invalid, or is null or contains whitespace characters.
/// is not within and .
[SuppressMessage("Microsoft.Reliability", "C2A000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
public SshClient(string host, int port, string username, string password)
: this(new PasswordConnectionInfo(host, port, username, password), true)
{
}
///
/// Initializes a new instance of the class.
///
/// Connection host.
/// Authentication username.
/// Authentication password.
///
///
///
/// is null.
/// is invalid, or is null or contains whitespace characters.
public SshClient(string host, string username, string password)
: this(host, ConnectionInfo.DEFAULT_PORT, username, password)
{
}
///
/// Initializes a new instance of the class.
///
/// Connection host.
/// Connection port.
/// Authentication username.
/// Authentication private key file(s) .
///
///
///
///
/// is null.
/// is invalid, -or- is null or contains whitespace characters.
/// is not within and .
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
public SshClient(string host, int port, string username, params PrivateKeyFile[] keyFiles)
: this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true)
{
}
///
/// Initializes a new instance of the class.
///
/// Connection host.
/// Authentication username.
/// Authentication private key file(s) .
///
///
///
///
/// is null.
/// is invalid, -or- is null or contains whitespace characters.
public SshClient(string host, string username, params PrivateKeyFile[] keyFiles)
: this(host, ConnectionInfo.DEFAULT_PORT, username, keyFiles)
{
}
///
/// Initializes a new instance of the class.
///
/// The connection info.
/// Specified whether this instance owns the connection info.
/// is null.
///
/// If is true, then the
/// connection info will be disposed when this instance is disposed.
///
private SshClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo)
: base(connectionInfo, ownsConnectionInfo)
{
_forwardedPorts = new List();
}
#endregion
///
/// Called when client is disconnecting from the server.
///
protected override void OnDisconnecting()
{
base.OnDisconnecting();
foreach (var port in this._forwardedPorts)
{
port.Stop();
}
}
///
/// Adds the forwarded port.
///
/// The port.
///
///
///
///
/// Forwarded port is already added to a different client.
/// is null.
/// Client is not connected.
public void AddForwardedPort(ForwardedPort port)
{
if (port == null)
throw new ArgumentNullException("port");
if (port.Session != null && port.Session != this.Session)
throw new InvalidOperationException("Forwarded port is already added to a different client.");
port.Session = this.Session;
this._forwardedPorts.Add(port);
}
///
/// Stops and removes the forwarded port from the list.
///
/// Forwarded port.
/// is null.
public void RemoveForwardedPort(ForwardedPort port)
{
if (port == null)
throw new ArgumentNullException("port");
// Stop port forwarding before removing it
port.Stop();
port.Session = null;
this._forwardedPorts.Remove(port);
}
///
/// Creates the command to be executed.
///
/// The command text.
/// object.
/// Client is not connected.
public SshCommand CreateCommand(string commandText)
{
return this.CreateCommand(commandText, this.ConnectionInfo.Encoding);
}
///
/// Creates the command to be executed with specified encoding.
///
/// The command text.
/// The encoding to use for results.
/// object which uses specified encoding.
/// TThis method will change current default encoding.
/// Client is not connected.
/// or is null.
public SshCommand CreateCommand(string commandText, Encoding encoding)
{
this.ConnectionInfo.Encoding = encoding;
return new SshCommand(this.Session, commandText);
}
///
/// Creates and executes the command.
///
/// The command text.
/// Returns an instance of with execution results.
/// This method internally uses asynchronous calls.
///
///
///
///
/// CommandText property is empty.
/// Invalid Operation - An existing channel was used to execute this command.
/// Asynchronous operation is already in progress.
/// Client is not connected.
/// is null.
public SshCommand RunCommand(string commandText)
{
var cmd = this.CreateCommand(commandText);
cmd.Execute();
return cmd;
}
///
/// Creates the shell.
///
/// The input.
/// The output.
/// The extended output.
/// Name of the terminal.
/// The columns.
/// The rows.
/// The width.
/// The height.
/// The terminal mode.
/// Size of the internal read buffer.
///
/// Returns a representation of a object.
///
public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes, int bufferSize)
{
return new Shell(this.Session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize);
}
///
/// Creates the shell.
///
/// The input.
/// The output.
/// The extended output.
/// Name of the terminal.
/// The columns.
/// The rows.
/// The width.
/// The height.
/// The terminal mode.
///
/// Returns a representation of a object.
///
public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes)
{
return this.CreateShell(input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, 1024);
}
///
/// Creates the shell.
///
/// The input.
/// The output.
/// The extended output.
///
/// Returns a representation of a object.
///
public Shell CreateShell(Stream input, Stream output, Stream extendedOutput)
{
return this.CreateShell(input, output, extendedOutput, string.Empty, 0, 0, 0, 0, null, 1024);
}
///
/// Creates the shell.
///
/// The encoding to use to send the input.
/// The input.
/// The output.
/// The extended output.
/// Name of the terminal.
/// The columns.
/// The rows.
/// The width.
/// The height.
/// The terminal mode.
/// Size of the internal read buffer.
///
/// Returns a representation of a object.
///
public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes, int bufferSize)
{
this._inputStream = new MemoryStream();
var writer = new StreamWriter(this._inputStream, encoding);
writer.Write(input);
writer.Flush();
this._inputStream.Seek(0, SeekOrigin.Begin);
return this.CreateShell(this._inputStream, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize);
}
///
/// Creates the shell.
///
/// The encoding.
/// The input.
/// The output.
/// The extended output.
/// Name of the terminal.
/// The columns.
/// The rows.
/// The width.
/// The height.
/// The terminal modes.
///
/// Returns a representation of a object.
///
public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes)
{
return this.CreateShell(encoding, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, 1024);
}
///
/// Creates the shell.
///
/// The encoding.
/// The input.
/// The output.
/// The extended output.
///
/// Returns a representation of a object.
///
public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput)
{
return this.CreateShell(encoding, input, output, extendedOutput, string.Empty, 0, 0, 0, 0, null, 1024);
}
///
/// Creates the shell stream.
///
/// Name of the terminal.
/// The columns.
/// The rows.
/// The width.
/// The height.
/// Size of the buffer.
///
/// Reference to Created ShellStream object.
///
public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize)
{
return this.CreateShellStream(terminalName, columns, rows, width, height, bufferSize, null);
}
///
/// Creates the shell stream.
///
/// Name of the terminal.
/// The columns.
/// The rows.
/// The width.
/// The height.
/// Size of the buffer.
/// The terminal mode values.
///
/// Reference to Created ShellStream object.
///
public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, IDictionary terminalModeValues)
{
return new ShellStream(this.Session, terminalName, columns, rows, width, height, bufferSize, terminalModeValues);
}
///
/// Stops forwarded ports.
///
protected override void OnDisconnected()
{
base.OnDisconnected();
foreach (var forwardedPort in this._forwardedPorts.ToArray())
{
this.RemoveForwardedPort(forwardedPort);
}
}
///
/// Releases unmanaged and - optionally - managed resources
///
/// true to release both managed and unmanaged resources; false to release only unmanaged ResourceMessages.
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (this._inputStream != null)
{
this._inputStream.Dispose();
this._inputStream = null;
}
}
}
}