| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 | using System;using System.Collections.Generic;using System.IO;using System.Text;using System.Diagnostics.CodeAnalysis;using Renci.SshNet.Common;namespace Renci.SshNet{    /// <summary>    /// Provides client connection to SSH server.    /// </summary>    public class SshClient : BaseClient    {        /// <summary>        /// Holds the list of forwarded ports        /// </summary>        private readonly List<ForwardedPort> _forwardedPorts;        private Stream _inputStream;        /// <summary>        /// Gets the list of forwarded ports.        /// </summary>        public IEnumerable<ForwardedPort> ForwardedPorts        {            get            {                return this._forwardedPorts.AsReadOnly();            }        }        #region Constructors        /// <summary>        /// Initializes a new instance of the <see cref="SshClient" /> class.        /// </summary>        /// <param name="connectionInfo">The connection info.</param>        /// <example>        ///     <code source="..\..\Renci.SshNet.Tests\Classes\PasswordConnectionInfoTest.cs" region="Example PasswordConnectionInfo" language="C#" title="Connect using PasswordConnectionInfo object" />        ///     <code source="..\..\Renci.SshNet.Tests\Classes\PasswordConnectionInfoTest.cs" region="Example PasswordConnectionInfo PasswordExpired" language="C#" title="Connect using PasswordConnectionInfo object with passwod change option" />        ///     <code source="..\..\Renci.SshNet.Tests\Classes\PrivateKeyConnectionInfoTest.cs" region="Example PrivateKeyConnectionInfo PrivateKeyFile" language="C#" title="Connect using PrivateKeyConnectionInfo" />        ///     <code source="..\..\Renci.SshNet.Tests\Classes\SshClientTest.cs" region="Example SshClient Connect Timeout" language="C#" title="Specify connection timeout when connecting" />        /// </example>        /// <exception cref="ArgumentNullException"><paramref name="connectionInfo"/> is null.</exception>        public SshClient(ConnectionInfo connectionInfo)            : this(connectionInfo, false)        {        }        /// <summary>        /// Initializes a new instance of the <see cref="SshClient"/> class.        /// </summary>        /// <param name="host">Connection host.</param>        /// <param name="port">Connection port.</param>        /// <param name="username">Authentication username.</param>        /// <param name="password">Authentication password.</param>        /// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>        /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, or <paramref name="username"/> is null or contains whitespace characters.</exception>        /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="F:System.Net.IPEndPoint.MinPort"/> and <see cref="System.Net.IPEndPoint.MaxPort"/>.</exception>        [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)        {        }        /// <summary>        /// Initializes a new instance of the <see cref="SshClient"/> class.        /// </summary>        /// <param name="host">Connection host.</param>        /// <param name="username">Authentication username.</param>        /// <param name="password">Authentication password.</param>        /// <example>        ///     <code source="..\..\Renci.SshNet.Tests\Classes\SshClientTest.cs" region="Example SshClient(host, username) Connect" language="C#" title="Connect using username and password" />        /// </example>        /// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>        /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, or <paramref name="username"/> is null or contains whitespace characters.</exception>        public SshClient(string host, string username, string password)            : this(host, ConnectionInfo.DEFAULT_PORT, username, password)        {        }        /// <summary>        /// Initializes a new instance of the <see cref="SshClient"/> class.        /// </summary>        /// <param name="host">Connection host.</param>        /// <param name="port">Connection port.</param>        /// <param name="username">Authentication username.</param>        /// <param name="keyFiles">Authentication private key file(s) .</param>        /// <example>        ///     <code source="..\..\Renci.SshNet.Tests\Classes\SshClientTest.cs" region="Example SshClient(host, username) Connect PrivateKeyFile" language="C#" title="Connect using username and private key" />        ///     <code source="..\..\Renci.SshNet.Tests\Classes\SshClientTest.cs" region="Example SshClient(host, username) Connect PrivateKeyFile PassPhrase" language="C#" title="Connect using username and private key and pass phrase" />        /// </example>        /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is null.</exception>        /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is null or contains whitespace characters.</exception>        /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="F:System.Net.IPEndPoint.MinPort"/> and <see cref="System.Net.IPEndPoint.MaxPort"/>.</exception>        [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)        {        }        /// <summary>        /// Initializes a new instance of the <see cref="SshClient"/> class.        /// </summary>        /// <param name="host">Connection host.</param>        /// <param name="username">Authentication username.</param>        /// <param name="keyFiles">Authentication private key file(s) .</param>        /// <example>        ///     <code source="..\..\Renci.SshNet.Tests\Classes\SshClientTest.cs" region="Example SshClient(host, username) Connect PrivateKeyFile" language="C#" title="Connect using private key" />        ///     <code source="..\..\Renci.SshNet.Tests\Classes\SshClientTest.cs" region="Example SshClient(host, username) Connect PrivateKeyFile PassPhrase" language="C#" title="Connect using private key and pass phrase" />        /// </example>        /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is null.</exception>        /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is null or contains whitespace characters.</exception>        public SshClient(string host, string username, params PrivateKeyFile[] keyFiles)            : this(host, ConnectionInfo.DEFAULT_PORT, username, keyFiles)        {        }        /// <summary>        /// Initializes a new instance of the <see cref="SshClient"/> class.        /// </summary>        /// <param name="connectionInfo">The connection info.</param>        /// <param name="ownsConnectionInfo">Specified whether this instance owns the connection info.</param>        /// <exception cref="ArgumentNullException"><paramref name="connectionInfo"/> is null.</exception>        /// <remarks>        /// If <paramref name="ownsConnectionInfo"/> is <c>true</c>, then the        /// connection info will be disposed when this instance is disposed.        /// </remarks>        private SshClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo)            : base(connectionInfo, ownsConnectionInfo)        {            _forwardedPorts = new List<ForwardedPort>();        }        #endregion        /// <summary>        /// Called when client is disconnecting from the server.        /// </summary>        protected override void OnDisconnecting()        {            base.OnDisconnecting();            foreach (var port in this._forwardedPorts)            {                port.Stop();            }        }        /// <summary>        /// Adds the forwarded port.        /// </summary>        /// <param name="port">The port.</param>        /// <example>        ///     <code source="..\..\Renci.SshNet.Tests\Classes\ForwardedPortRemoteTest.cs" region="Example SshClient AddForwardedPort Start Stop ForwardedPortRemote" language="C#" title="Remote port forwarding" />        ///     <code source="..\..\Renci.SshNet.Tests\Classes\ForwardedPortLocalTest.cs" region="Example SshClient AddForwardedPort Start Stop ForwardedPortLocal" language="C#" title="Local port forwarding" />        /// </example>        /// <exception cref="InvalidOperationException">Forwarded port is already added to a different client.</exception>        /// <exception cref="ArgumentNullException"><paramref name="port"/> is null.</exception>        /// <exception cref="SshConnectionException">Client is not connected.</exception>        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);        }        /// <summary>        /// Stops and removes the forwarded port from the list.        /// </summary>        /// <param name="port">Forwarded port.</param>        /// <exception cref="ArgumentNullException"><paramref name="port"/> is null.</exception>        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);        }        /// <summary>        /// Creates the command to be executed.        /// </summary>        /// <param name="commandText">The command text.</param>        /// <returns><see cref="SshCommand"/> object.</returns>        /// <exception cref="SshConnectionException">Client is not connected.</exception>        public SshCommand CreateCommand(string commandText)        {            return this.CreateCommand(commandText, this.ConnectionInfo.Encoding);        }        /// <summary>        /// Creates the command to be executed with specified encoding.        /// </summary>        /// <param name="commandText">The command text.</param>        /// <param name="encoding">The encoding to use for results.</param>        /// <returns><see cref="SshCommand"/> object which uses specified encoding.</returns>        /// <remarks>This method will change current default encoding.</remarks>        /// <exception cref="SshConnectionException">Client is not connected.</exception>        /// <exception cref="ArgumentNullException"><paramref name="commandText"/> or <paramref name="encoding"/> is null.</exception>        public SshCommand CreateCommand(string commandText, Encoding encoding)        {            this.ConnectionInfo.Encoding = encoding;            return new SshCommand(this.Session, commandText);        }        /// <summary>        /// Creates and executes the command.        /// </summary>        /// <param name="commandText">The command text.</param>        /// <returns>Returns an instance of <see cref="SshCommand"/> with execution results.</returns>        /// <remarks>This method internally uses asynchronous calls.</remarks>        /// <example>        ///     <code source="..\..\Renci.SshNet.Tests\Classes\SshCommandTest.cs" region="Example SshCommand RunCommand Result" language="C#" title="Running simple command" />        ///     <code source="..\..\Renci.SshNet.Tests\Classes\SshCommandTest.NET40.cs" region="Example SshCommand RunCommand Parallel" language="C#" title="Run many commands in parallel" />        /// </example>        /// <exception cref="ArgumentException">CommandText property is empty.</exception>        /// <exception cref="T:Renci.SshNet.Common.SshException">Invalid Operation - An existing channel was used to execute this command.</exception>        /// <exception cref="InvalidOperationException">Asynchronous operation is already in progress.</exception>        /// <exception cref="SshConnectionException">Client is not connected.</exception>        /// <exception cref="ArgumentNullException"><paramref name="commandText"/> is null.</exception>        public SshCommand RunCommand(string commandText)        {            var cmd = this.CreateCommand(commandText);            cmd.Execute();            return cmd;        }        /// <summary>        /// Creates the shell.        /// </summary>        /// <param name="input">The input.</param>        /// <param name="output">The output.</param>        /// <param name="extendedOutput">The extended output.</param>        /// <param name="terminalName">Name of the terminal.</param>        /// <param name="columns">The columns.</param>        /// <param name="rows">The rows.</param>        /// <param name="width">The width.</param>        /// <param name="height">The height.</param>        /// <param name="terminalModes">The terminal mode.</param>        /// <param name="bufferSize">Size of the internal read buffer.</param>        /// <returns>        /// Returns a representation of a <see cref="Shell" /> object.        /// </returns>        public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes, int bufferSize)        {            return new Shell(this.Session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize);        }        /// <summary>        /// Creates the shell.        /// </summary>        /// <param name="input">The input.</param>        /// <param name="output">The output.</param>        /// <param name="extendedOutput">The extended output.</param>        /// <param name="terminalName">Name of the terminal.</param>        /// <param name="columns">The columns.</param>        /// <param name="rows">The rows.</param>        /// <param name="width">The width.</param>        /// <param name="height">The height.</param>        /// <param name="terminalModes">The terminal mode.</param>        /// <returns>        /// Returns a representation of a <see cref="Shell" /> object.        /// </returns>        public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes)        {            return this.CreateShell(input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, 1024);        }        /// <summary>        /// Creates the shell.        /// </summary>        /// <param name="input">The input.</param>        /// <param name="output">The output.</param>        /// <param name="extendedOutput">The extended output.</param>        /// <returns>        /// Returns a representation of a <see cref="Shell" /> object.        /// </returns>        public Shell CreateShell(Stream input, Stream output, Stream extendedOutput)        {            return this.CreateShell(input, output, extendedOutput, string.Empty, 0, 0, 0, 0, null, 1024);        }        /// <summary>        /// Creates the shell.        /// </summary>        /// <param name="encoding">The encoding to use to send the input.</param>        /// <param name="input">The input.</param>        /// <param name="output">The output.</param>        /// <param name="extendedOutput">The extended output.</param>        /// <param name="terminalName">Name of the terminal.</param>        /// <param name="columns">The columns.</param>        /// <param name="rows">The rows.</param>        /// <param name="width">The width.</param>        /// <param name="height">The height.</param>        /// <param name="terminalModes">The terminal mode.</param>        /// <param name="bufferSize">Size of the internal read buffer.</param>        /// <returns>        /// Returns a representation of a <see cref="Shell" /> object.        /// </returns>        public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> 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);        }        /// <summary>        /// Creates the shell.        /// </summary>        /// <param name="encoding">The encoding.</param>        /// <param name="input">The input.</param>        /// <param name="output">The output.</param>        /// <param name="extendedOutput">The extended output.</param>        /// <param name="terminalName">Name of the terminal.</param>        /// <param name="columns">The columns.</param>        /// <param name="rows">The rows.</param>        /// <param name="width">The width.</param>        /// <param name="height">The height.</param>        /// <param name="terminalModes">The terminal modes.</param>        /// <returns>        /// Returns a representation of a <see cref="Shell" /> object.        /// </returns>        public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes)        {            return this.CreateShell(encoding, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, 1024);        }        /// <summary>        /// Creates the shell.        /// </summary>        /// <param name="encoding">The encoding.</param>        /// <param name="input">The input.</param>        /// <param name="output">The output.</param>        /// <param name="extendedOutput">The extended output.</param>        /// <returns>        /// Returns a representation of a <see cref="Shell" /> object.        /// </returns>        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);        }        /// <summary>        /// Creates the shell stream.        /// </summary>        /// <param name="terminalName">Name of the terminal.</param>        /// <param name="columns">The columns.</param>        /// <param name="rows">The rows.</param>        /// <param name="width">The width.</param>        /// <param name="height">The height.</param>        /// <param name="bufferSize">Size of the buffer.</param>        /// <returns>        /// Reference to Created ShellStream object.        /// </returns>        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);        }        /// <summary>        /// Creates the shell stream.        /// </summary>        /// <param name="terminalName">Name of the terminal.</param>        /// <param name="columns">The columns.</param>        /// <param name="rows">The rows.</param>        /// <param name="width">The width.</param>        /// <param name="height">The height.</param>        /// <param name="bufferSize">Size of the buffer.</param>        /// <param name="terminalModeValues">The terminal mode values.</param>        /// <returns>        /// Reference to Created ShellStream object.        /// </returns>        public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, IDictionary<TerminalModes, uint> terminalModeValues)        {            return new ShellStream(this.Session, terminalName, columns, rows, width, height, bufferSize, terminalModeValues);        }        /// <summary>        /// Stops forwarded ports.        /// </summary>        protected override void OnDisconnected()        {            base.OnDisconnected();            foreach (var forwardedPort in this._forwardedPorts.ToArray())            {                this.RemoveForwardedPort(forwardedPort);            }        }        /// <summary>        /// Releases unmanaged and - optionally - managed resources        /// </summary>        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>        protected override void Dispose(bool disposing)        {            base.Dispose(disposing);            if (this._inputStream != null)            {                this._inputStream.Dispose();                this._inputStream = null;            }        }    }}
 |