From a49dd503b8637748dc34452fc356db1c160cd556 Mon Sep 17 00:00:00 2001 From: Igor Milavec Date: Wed, 23 Feb 2022 00:51:03 +0100 Subject: [PATCH 1/4] Fix PipeStream returning 0 prematurely --- src/Renci.SshNet/Common/PipeStream.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/Renci.SshNet/Common/PipeStream.cs b/src/Renci.SshNet/Common/PipeStream.cs index fac54fb62..31528794c 100644 --- a/src/Renci.SshNet/Common/PipeStream.cs +++ b/src/Renci.SshNet/Common/PipeStream.cs @@ -42,12 +42,6 @@ public class PipeStream : Stream /// Possible more effecient ways to accomplish this. private readonly Queue _buffer = new Queue(); - /// - /// Indicates that the input stream has been flushed and that - /// all remaining data should be written to the output stream. - /// - private bool _isFlushed; - /// /// Maximum number of bytes to store in the buffer. /// @@ -131,7 +125,6 @@ public override void Flush() if (_isDisposed) throw CreateObjectDisposedException(); - _isFlushed = true; lock (_buffer) { // unblock read hereby allowing buffer to be partially filled @@ -180,8 +173,6 @@ public override void SetLength(long value) ///offset or count is negative. public override int Read(byte[] buffer, int offset, int count) { - if (offset != 0) - throw new NotSupportedException("Offsets with value of non-zero are not supported"); if (buffer == null) throw new ArgumentNullException("buffer"); if (offset + count > buffer.Length) @@ -213,7 +204,7 @@ public override int Read(byte[] buffer, int offset, int count) // fill the read buffer for (; readLength < count && _buffer.Count > 0; readLength++) { - buffer[readLength] = _buffer.Dequeue(); + buffer[offset + readLength] = _buffer.Dequeue(); } Monitor.Pulse(_buffer); @@ -229,8 +220,7 @@ public override int Read(byte[] buffer, int offset, int count) /// True if data available; otherwisefalse. private bool ReadAvailable(int count) { - var length = Length; - return (_isFlushed || length >= count) && (length >= (count + 1) || !BlockLastReadBuffer); + return (Length >= count || !BlockLastReadBuffer); } /// @@ -264,8 +254,6 @@ public override void Write(byte[] buffer, int offset, int count) while (Length >= _maxBufferLength) Monitor.Wait(_buffer); - _isFlushed = false; // if it were flushed before, it soon will not be. - // queue up the buffer data for (var i = offset; i < offset + count; i++) { From 1a607820230a642d5601e7a03c4864316a8bdb0e Mon Sep 17 00:00:00 2001 From: Igor Milavec Date: Wed, 23 Feb 2022 12:59:21 +0100 Subject: [PATCH 2/4] Fix PipeStreamTest --- src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs index 4c11b432a..d12a09a46 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs @@ -76,6 +76,7 @@ public void Read() }); writeToStreamThread.Start(); + target.BlockLastReadBuffer = true; readBuffer = new byte[2]; bytesRead = target.Read(readBuffer, 0, readBuffer.Length); Assert.AreEqual(2, bytesRead); From 6d846dfa99a1d887570977628a6410e596d86352 Mon Sep 17 00:00:00 2001 From: Igor Milavec Date: Wed, 23 Feb 2022 20:58:27 +0100 Subject: [PATCH 3/4] Additional fix and extend tests for this scenario --- .../Classes/Common/PipeStreamTest.cs | 16 +++++++++++++--- src/Renci.SshNet/Common/PipeStream.cs | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs index d12a09a46..2885d97ec 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs @@ -63,7 +63,7 @@ public void Read() var readBuffer = new byte[2]; var bytesRead = target.Read(readBuffer, 0, readBuffer.Length); - Assert.AreEqual(2, bytesRead); + Assert.AreEqual(readBuffer.Length, bytesRead); Assert.AreEqual(0x0a, readBuffer[0]); Assert.AreEqual(0x0d, readBuffer[1]); @@ -78,8 +78,18 @@ public void Read() target.BlockLastReadBuffer = true; readBuffer = new byte[2]; - bytesRead = target.Read(readBuffer, 0, readBuffer.Length); - Assert.AreEqual(2, bytesRead); + int bufferOffset = 0; + while (bufferOffset < readBuffer.Length) + { + bytesRead = target.Read(readBuffer, bufferOffset, readBuffer.Length - bufferOffset); + if (bytesRead == 0) + { + Assert.Fail("PipeStream.Read returned 0"); + } + + bufferOffset += bytesRead; + } + Assert.AreEqual(readBuffer.Length, bufferOffset); Assert.AreEqual(0x09, readBuffer[0]); Assert.AreEqual(0x05, readBuffer[1]); } diff --git a/src/Renci.SshNet/Common/PipeStream.cs b/src/Renci.SshNet/Common/PipeStream.cs index 31528794c..f396d8f2f 100644 --- a/src/Renci.SshNet/Common/PipeStream.cs +++ b/src/Renci.SshNet/Common/PipeStream.cs @@ -220,7 +220,7 @@ public override int Read(byte[] buffer, int offset, int count) /// True if data available; otherwisefalse. private bool ReadAvailable(int count) { - return (Length >= count || !BlockLastReadBuffer); + return BlockLastReadBuffer ? Length >= count : Length > 0; } /// From f6e6bc29746132c923aae483cf8730b4922b987a Mon Sep 17 00:00:00 2001 From: Igor Milavec Date: Thu, 24 Feb 2022 10:31:14 +0100 Subject: [PATCH 4/4] Fix PipeStream_Close_BlockingRead --- .../Classes/Common/PipeStream_Close_BlockingRead.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs index fb010c14f..7f78370f5 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs @@ -15,6 +15,7 @@ public class PipeStream_Close_BlockingRead : TripleATestBase protected override void Arrange() { _pipeStream = new PipeStream(); + _pipeStream.BlockLastReadBuffer = true; _pipeStream.WriteByte(10); _pipeStream.WriteByte(13);