diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs index cfd68b078..3048806d9 100644 --- a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs @@ -4,6 +4,7 @@ using Renci.SshNet.Tests.Properties; using System; using System.IO; +using System.Linq; using System.Text; using System.Threading; #if FEATURE_TPL @@ -266,7 +267,7 @@ public void Test_Execute_Command_ExitStatus() client.Connect(); var cmd = client.RunCommand("exit 128"); - + Console.WriteLine(cmd.ExitStatus); client.Disconnect(); @@ -500,6 +501,55 @@ public void Test_Execute_Invalid_Command() } } + [TestMethod] + [TestCategory("integration")] + public void SendDataTestText() + { + SendDataTest( + Encoding.UTF8.GetBytes("Hello "), Encoding.UTF8.GetBytes("world!"), + Encoding.UTF8.GetBytes("A\nB\nC\nD")); + } + + [TestMethod] + [TestCategory("integration")] + public void SendDataTestRandomBytes() + { + var random = new Random(); + var randomData = new byte[1024]; + random.NextBytes(randomData); + + SendDataTest(randomData); + } + + public void SendDataTest(params byte[][] data) + { + using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + { + #region Example SshCommand CreateCommand BeginExecute SendData EndExecute + + client.Connect(); + + var cmd = client.CreateCommand("cat -"); + + var asynch = cmd.BeginExecute(); + + foreach (var dataBlock in data) + { + cmd.SendData(dataBlock); + + var fromStdout = new byte[dataBlock.Length]; + cmd.OutputStream.Read(fromStdout, 0, 0); + + Assert.IsTrue(dataBlock.SequenceEqual(fromStdout)); + } + + cmd.EndExecute(asynch); + + client.Disconnect(); + + #endregion + } + } /// ///A test for BeginExecute @@ -637,7 +687,7 @@ public void Test_MultipleThread_Example_MultipleConnections() try { -#region Example SshCommand RunCommand Parallel + #region Example SshCommand RunCommand Parallel System.Threading.Tasks.Parallel.For(0, 10000, () => { @@ -657,7 +707,7 @@ public void Test_MultipleThread_Example_MultipleConnections() client.Dispose(); } ); -#endregion + #endregion } catch (Exception exp) diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index 37e91da08..31996bb2b 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -471,6 +471,41 @@ private void Channel_DataReceived(object sender, ChannelDataEventArgs e) } } + /// + /// Sends a SSH_MSG_CHANNEL_DATA message with the specified payload. + /// + /// The payload to send. + public void SendData(byte[] data) + { + _channel.SendData(data); + } + + /// + /// Sends a SSH_MSG_CHANNEL_DATA message with the specified payload. + /// + /// An array of containing the payload to send. + /// The zero-based offset in at which to begin taking data from. + /// The number of bytes of to send. + /// + /// + /// When the size of the data to send exceeds the maximum packet size or the remote window + /// size does not allow the full data to be sent, then this method will send the data in + /// multiple chunks and will wait for the remote window size to be adjusted when it's zero. + /// + /// + /// This is done to support SSH servers will a small window size that do not agressively + /// increase their window size. We need to take into account that there may be SSH servers + /// that only increase their window size when it has reached zero. + /// + /// + public void SendData(byte[] data, int offset, int size) + { + _channel.SendData(data, offset, size); + } + + /// + /// Waits on the wait handle . + /// /// Command '{0}' has timed out. /// The actual command will be included in the exception message. private void WaitOnHandle(WaitHandle waitHandle)