diff --git a/README.md b/README.md
index f1382e365..c58cceee3 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ SSH.NET is a Secure Shell (SSH-2) library for .NET, optimized for parallelism.
using (var client = new SshClient("sftp.foo.com", "guest", new PrivateKeyFile("path/to/my/key")))
{
client.Connect();
- using SshCommand cmd = client.RunCommand("echo 'Hello World!'");
+ using ISshCommand cmd = client.RunCommand("echo 'Hello World!'");
Console.WriteLine(cmd.Result); // "Hello World!\n"
}
```
diff --git a/docfx/examples.md b/docfx/examples.md
index fd2ab53b1..306b27747 100644
--- a/docfx/examples.md
+++ b/docfx/examples.md
@@ -9,7 +9,7 @@ Getting Started
using (var client = new SshClient("sftp.foo.com", "guest", new PrivateKeyFile("path/to/my/key")))
{
client.Connect();
- using SshCommand cmd = client.RunCommand("echo 'Hello World!'");
+ using ISshCommand cmd = client.RunCommand("echo 'Hello World!'");
Console.WriteLine(cmd.Result); // "Hello World!\n"
}
```
@@ -134,7 +134,7 @@ using (var client = new SshClient("sftp.foo.com", "guest", "pwd"))
client.Connect();
// Make the server echo back the input file with "cat"
- using (SshCommand command = client.CreateCommand("cat"))
+ using (ISshCommand command = client.CreateCommand("cat"))
{
Task executeTask = command.ExecuteAsync(CancellationToken.None);
diff --git a/src/Renci.SshNet/ISshClient.cs b/src/Renci.SshNet/ISshClient.cs
index 4507c316b..df774d290 100644
--- a/src/Renci.SshNet/ISshClient.cs
+++ b/src/Renci.SshNet/ISshClient.cs
@@ -1,246 +1,19 @@
-#nullable enable
using System;
-using System.Collections.Generic;
-using System.IO;
using System.Text;
-using Renci.SshNet.Common;
-
namespace Renci.SshNet
{
- ///
- /// Provides client connection to SSH server.
- ///
- public interface ISshClient : IBaseClient
+ ///
+ [Obsolete($"Use {nameof(V2.ISshClient)} instead.")]
+ public interface ISshClient : V2.ISshClient
{
- ///
- /// Gets the list of forwarded ports.
- ///
- IEnumerable ForwardedPorts { get; }
-
- ///
- /// Adds the forwarded port.
- ///
- /// The port.
- /// Forwarded port is already added to a different client.
- /// is .
- /// Client is not connected.
- public void AddForwardedPort(ForwardedPort port);
-
- ///
- /// Stops and removes the forwarded port from the list.
- ///
- /// Forwarded port.
- /// is .
- public void RemoveForwardedPort(ForwardedPort port);
-
- ///
- /// Creates the command to be executed.
- ///
- /// The command text.
- /// object.
- /// Client is not connected.
- public SshCommand CreateCommand(string commandText);
-
- ///
- /// Creates the command to be executed with specified encoding.
- ///
- /// The command text.
- /// The encoding to use for results.
- /// object which uses specified encoding.
- /// This method will change current default encoding.
- /// Client is not connected.
- /// or is .
- public SshCommand CreateCommand(string commandText, Encoding encoding);
-
- ///
- /// 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 .
- public SshCommand RunCommand(string commandText);
-
- ///
- /// 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.
- ///
- /// Client is not connected.
- public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary? terminalModes, int 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.
- ///
- /// Client is not connected.
- public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes);
-
- ///
- /// Creates the shell.
- ///
- /// The input.
- /// The output.
- /// The extended output.
- ///
- /// Returns a representation of a object.
- ///
- /// Client is not connected.
- public Shell CreateShell(Stream input, Stream output, Stream extendedOutput);
-
- ///
- /// 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.
- ///
- /// Client is not connected.
- 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);
-
- ///
- /// 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.
- ///
- /// Client is not connected.
- public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes);
-
- ///
- /// Creates the shell.
- ///
- /// The encoding.
- /// The input.
- /// The output.
- /// The extended output.
- ///
- /// Returns a representation of a object.
- ///
- /// Client is not connected.
- public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput);
-
- ///
- /// Creates the shell without allocating a pseudo terminal,
- /// similar to the ssh -T option.
- ///
- /// The input.
- /// The output.
- /// The extended output.
- /// Size of the internal read buffer.
- ///
- /// Returns a representation of a object.
- ///
- /// Client is not connected.
- public Shell CreateShellNoTerminal(Stream input, Stream output, Stream extendedOutput, int bufferSize = -1);
-
- ///
- /// Creates the shell stream.
- ///
- /// The TERM environment variable.
- /// The terminal width in columns.
- /// The terminal height in rows.
- /// The terminal width in pixels.
- /// The terminal height in pixels.
- /// The size of the buffer.
- ///
- /// The created instance.
- ///
- /// Client is not connected.
- ///
- ///
- /// The TERM environment variable contains an identifier for the text window's capabilities.
- /// You can get a detailed list of these capabilities by using the ‘infocmp’ command.
- ///
- ///
- /// The column/row dimensions override the pixel dimensions (when nonzero). Pixel dimensions refer
- /// to the drawable area of the window.
- ///
- ///
- public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize);
+ ///
+ public new SshCommand CreateCommand(string commandText);
- ///
- /// Creates the shell stream.
- ///
- /// The TERM environment variable.
- /// The terminal width in columns.
- /// The terminal height in rows.
- /// The terminal width in pixels.
- /// The terminal height in pixels.
- /// The size of the buffer.
- /// The terminal mode values.
- ///
- /// The created instance.
- ///
- /// Client is not connected.
- ///
- ///
- /// The TERM environment variable contains an identifier for the text window's capabilities.
- /// You can get a detailed list of these capabilities by using the ‘infocmp’ command.
- ///
- ///
- /// The column/row dimensions override the pixel dimensions (when non-zero). Pixel dimensions refer
- /// to the drawable area of the window.
- ///
- ///
- public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, IDictionary? terminalModeValues);
+ ///
+ public new SshCommand CreateCommand(string commandText, Encoding encoding);
- ///
- /// Creates the shell stream without allocating a pseudo terminal,
- /// similar to the ssh -T option.
- ///
- /// The size of the buffer.
- ///
- /// The created instance.
- ///
- /// Client is not connected.
- public ShellStream CreateShellStreamNoTerminal(int bufferSize = -1);
+ ///
+ public new SshCommand RunCommand(string commandText);
}
}
diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs
index 331ccaf69..cbda3d5fc 100644
--- a/src/Renci.SshNet/SshClient.cs
+++ b/src/Renci.SshNet/SshClient.cs
@@ -1,339 +1,45 @@
-#nullable enable
using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Text;
-
-using Renci.SshNet.Common;
namespace Renci.SshNet
{
- ///
- public class SshClient : BaseClient, ISshClient
+ ///
+ [Obsolete($"Use {nameof(V2.SshClient)} instead.")]
+ public class SshClient : V2.SshClient
{
- ///
- /// Holds the list of forwarded ports.
- ///
- private readonly List _forwardedPorts;
-
- ///
- /// Holds a value indicating whether the current instance is disposed.
- ///
- ///
- /// if the current instance is disposed; otherwise, .
- ///
- private bool _isDisposed;
-
- private MemoryStream? _inputStream;
-
///
- public IEnumerable ForwardedPorts
- {
- get
- {
- return _forwardedPorts.AsReadOnly();
- }
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The connection info.
- /// is .
public SshClient(ConnectionInfo connectionInfo)
- : this(connectionInfo, ownsConnectionInfo: false)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Connection host.
- /// Connection port.
- /// Authentication username.
- /// Authentication password.
- /// is .
- /// is invalid, or is or contains only whitespace characters.
- /// is not within and .
- public SshClient(string host, int port, string username, string password)
- : this(new PasswordConnectionInfo(host, port, username, password), ownsConnectionInfo: true)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Connection host.
- /// Authentication username.
- /// Authentication password.
- /// is .
- /// is invalid, or is or contains only whitespace characters.
- public SshClient(string host, string username, string password)
- : this(host, ConnectionInfo.DefaultPort, username, password)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Connection host.
- /// Connection port.
- /// Authentication username.
- /// Authentication private key file(s) .
- /// is .
- /// is invalid, -or- is or contains only whitespace characters.
- /// is not within and .
- public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
- : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Connection host.
- /// Authentication username.
- /// Authentication private key file(s) .
- /// is .
- /// is invalid, -or- is or contains only whitespace characters.
- public SshClient(string host, string username, params IPrivateKeySource[] keyFiles)
- : this(host, ConnectionInfo.DefaultPort, username, keyFiles)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The connection info.
- /// Specified whether this instance owns the connection info.
- /// is .
- ///
- /// If is , then the
- /// connection info will be disposed when this instance is disposed.
- ///
- private SshClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo)
- : this(connectionInfo, ownsConnectionInfo, new ServiceFactory())
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The connection info.
- /// Specified whether this instance owns the connection info.
- /// The factory to use for creating new services.
- /// is .
- /// is .
- ///
- /// If is , then the
- /// connection info will be disposed when this instance is disposed.
- ///
- internal SshClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory)
- : base(connectionInfo, ownsConnectionInfo, serviceFactory)
- {
- _forwardedPorts = new List();
- }
-
- ///
- /// Called when client is disconnecting from the server.
- ///
- protected override void OnDisconnecting()
- {
- base.OnDisconnecting();
-
- foreach (var port in _forwardedPorts)
- {
- port.Stop();
- }
- }
-
- ///
- public void AddForwardedPort(ForwardedPort port)
- {
- ArgumentNullException.ThrowIfNull(port);
-
- EnsureSessionIsOpen();
-
- AttachForwardedPort(port);
- _forwardedPorts.Add(port);
- }
-
- ///
- public void RemoveForwardedPort(ForwardedPort port)
- {
- ArgumentNullException.ThrowIfNull(port);
-
- // Stop port forwarding before removing it
- port.Stop();
-
- DetachForwardedPort(port);
- _ = _forwardedPorts.Remove(port);
- }
-
- private void AttachForwardedPort(ForwardedPort port)
- {
- if (port.Session != null && port.Session != Session)
- {
- throw new InvalidOperationException("Forwarded port is already added to a different client.");
- }
-
- port.Session = Session;
- }
-
- private static void DetachForwardedPort(ForwardedPort port)
- {
- port.Session = null;
- }
-
- ///
- public SshCommand CreateCommand(string commandText)
- {
- return CreateCommand(commandText, ConnectionInfo.Encoding);
- }
-
- ///
- public SshCommand CreateCommand(string commandText, Encoding encoding)
+ : base(connectionInfo)
{
- EnsureSessionIsOpen();
-
- ConnectionInfo.Encoding = encoding;
- return new SshCommand(Session!, commandText, encoding);
- }
-
- ///
- public SshCommand RunCommand(string commandText)
- {
- var cmd = CreateCommand(commandText);
- _ = cmd.Execute();
- return cmd;
- }
-
- ///
- public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary? terminalModes, int bufferSize)
- {
- EnsureSessionIsOpen();
-
- return new Shell(Session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize);
}
///
- public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes)
- {
- return CreateShell(input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, 1024);
- }
-
- ///
- public Shell CreateShell(Stream input, Stream output, Stream extendedOutput)
- {
- return CreateShell(input, output, extendedOutput, string.Empty, 0, 0, 0, 0, terminalModes: null, 1024);
- }
-
- ///
- 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)
- {
- /*
- * TODO Issue #1224: let shell dispose of input stream when we own the stream!
- */
-
- _inputStream = new MemoryStream();
-
- using (var writer = new StreamWriter(_inputStream, encoding, bufferSize: 1024, leaveOpen: true))
- {
- writer.Write(input);
- writer.Flush();
- }
-
- _ = _inputStream.Seek(0, SeekOrigin.Begin);
-
- return CreateShell(_inputStream, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize);
- }
-
- ///
- public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes)
- {
- return CreateShell(encoding, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, 1024);
- }
-
- ///
- public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput)
+ public SshClient(string host, string username, string password)
+ : base(host, username, password)
{
- return CreateShell(encoding, input, output, extendedOutput, string.Empty, 0, 0, 0, 0, terminalModes: null, 1024);
}
///
- public Shell CreateShellNoTerminal(Stream input, Stream output, Stream extendedOutput, int bufferSize = -1)
+ public SshClient(string host, string username, params IPrivateKeySource[] keyFiles)
+ : base(host, username, keyFiles)
{
- EnsureSessionIsOpen();
-
- return new Shell(Session, input, output, extendedOutput, bufferSize);
}
///
- public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize)
+ public SshClient(string host, int port, string username, string password)
+ : base(host, port, username, password)
{
- return CreateShellStream(terminalName, columns, rows, width, height, bufferSize, terminalModeValues: null);
}
///
- public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, IDictionary? terminalModeValues)
+ public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
+ : base(host, port, username, keyFiles)
{
- EnsureSessionIsOpen();
-
- return ServiceFactory.CreateShellStream(Session, terminalName, columns, rows, width, height, terminalModeValues, bufferSize);
}
///
- public ShellStream CreateShellStreamNoTerminal(int bufferSize = -1)
- {
- EnsureSessionIsOpen();
-
- return ServiceFactory.CreateShellStreamNoTerminal(Session, bufferSize);
- }
-
- ///
- /// Stops forwarded ports.
- ///
- protected override void OnDisconnected()
- {
- base.OnDisconnected();
-
- for (var i = _forwardedPorts.Count - 1; i >= 0; i--)
- {
- var port = _forwardedPorts[i];
- DetachForwardedPort(port);
- _forwardedPorts.RemoveAt(i);
- }
- }
-
- ///
- /// Releases unmanaged and - optionally - managed resources.
- ///
- /// to release both managed and unmanaged resources; to release only unmanaged resources.
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
-
- if (_isDisposed)
- {
- return;
- }
-
- if (disposing)
- {
- _inputStream?.Dispose();
- _inputStream = null;
-
- _isDisposed = true;
- }
- }
-
- private void EnsureSessionIsOpen()
+ internal SshClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory)
+ : base(connectionInfo, ownsConnectionInfo, serviceFactory)
{
- if (Session is null)
- {
- throw new SshConnectionException("Client not connected.");
- }
}
}
}
diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs
index ce1042244..a11f00049 100644
--- a/src/Renci.SshNet/SshCommand.cs
+++ b/src/Renci.SshNet/SshCommand.cs
@@ -1,672 +1,164 @@
-#nullable enable
+#nullable enable
+
using System;
-using System.Diagnostics;
using System.IO;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using Renci.SshNet.Channels;
-using Renci.SshNet.Common;
-using Renci.SshNet.Messages.Connection;
-using Renci.SshNet.Messages.Transport;
-
namespace Renci.SshNet
{
- ///
- /// Represents an SSH command that can be executed.
- ///
- public sealed class SshCommand : IDisposable
+ ///
+ [Obsolete($"Use {nameof(V2.ISshCommand)} instead.")]
+ public sealed class SshCommand : V2.ISshCommand
{
- private readonly ISession _session;
- private readonly Encoding _encoding;
-
- private IChannelSession _channel;
- private TaskCompletionSource