diff --git a/src/Renci.SshNet/ShellStream.cs b/src/Renci.SshNet/ShellStream.cs index ce57072d5..0a3d14348 100644 --- a/src/Renci.SshNet/ShellStream.cs +++ b/src/Renci.SshNet/ShellStream.cs @@ -41,7 +41,7 @@ public class ShellStream : Stream /// Gets a value indicating whether data is available on the to be read. /// /// - /// if data is available to be read; otherwise, . + /// true if data is available to be read; otherwise, false. /// public bool DataAvailable { @@ -119,7 +119,7 @@ internal ShellStream(ISession session, string terminalName, uint columns, uint r /// Gets a value indicating whether the current stream supports reading. /// /// - /// if the stream supports reading; otherwise, . + /// true if the stream supports reading; otherwise, false. /// public override bool CanRead { @@ -130,7 +130,7 @@ public override bool CanRead /// Gets a value indicating whether the current stream supports seeking. /// /// - /// if the stream supports seeking; otherwise, . + /// true if the stream supports seeking; otherwise, false. /// public override bool CanSeek { @@ -141,7 +141,7 @@ public override bool CanSeek /// Gets a value indicating whether the current stream supports writing. /// /// - /// if the stream supports writing; otherwise, . + /// true if the stream supports writing; otherwise, false. /// public override bool CanWrite { @@ -155,14 +155,10 @@ public override bool CanWrite /// Methods were called after the stream was closed. public override void Flush() { -#if NET7_0_OR_GREATER - ObjectDisposedException.ThrowIf(_channel is null, this); -#else if (_channel is null) { - throw new ObjectDisposedException(GetType().FullName); + throw new ObjectDisposedException("ShellStream"); } -#endif // NET7_0_OR_GREATER if (_outgoing.Count > 0) { @@ -203,6 +199,36 @@ public override long Position set { throw new NotSupportedException(); } } + /// + /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. + /// The zero-based byte offset in at which to begin storing the data read from the current stream. + /// The maximum number of bytes to be read from the current stream. + /// + /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + /// + /// The sum of and is larger than the buffer length. + /// is null. + /// or is negative. + /// An I/O error occurs. + /// The stream does not support reading. + /// Methods were called after the stream was closed. + public override int Read(byte[] buffer, int offset, int count) + { + var i = 0; + + lock (_incoming) + { + for (; i < count && _incoming.Count > 0; i++) + { + buffer[offset + i] = _incoming.Dequeue(); + } + } + + return i; + } + /// /// This method is not supported. /// @@ -231,6 +257,31 @@ public override void SetLength(long value) throw new NotSupportedException(); } + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies bytes from to the current stream. + /// The zero-based byte offset in at which to begin copying bytes to the current stream. + /// The number of bytes to be written to the current stream. + /// The sum of and is greater than the buffer length. + /// is null. + /// or is negative. + /// An I/O error occurs. + /// The stream does not support writing. + /// Methods were called after the stream was closed. + public override void Write(byte[] buffer, int offset, int count) + { + foreach (var b in buffer.Take(offset, count)) + { + if (_outgoing.Count == _bufferSize) + { + Flush(); + } + + _outgoing.Enqueue(b); + } + } + /// /// Expects the specified expression and performs action when one is found. /// @@ -300,95 +351,6 @@ public void Expect(TimeSpan timeout, params ExpectAction[] expectActions) while (!expectedFound); } - /// - /// Expects the expression specified by text. - /// - /// The text to expect. - /// - /// Text available in the shell that ends with expected text. - /// - public string Expect(string text) - { - return Expect(new Regex(Regex.Escape(text)), Session.InfiniteTimeSpan); - } - - /// - /// Expects the expression specified by text. - /// - /// The text to expect. - /// Time to wait for input. - /// - /// The text available in the shell that ends with expected text, or if the specified time has elapsed. - /// - public string Expect(string text, TimeSpan timeout) - { - return Expect(new Regex(Regex.Escape(text)), timeout); - } - - /// - /// Expects the expression specified by regular expression. - /// - /// The regular expression to expect. - /// - /// The text available in the shell that contains all the text that ends with expected expression. - /// - public string Expect(Regex regex) - { - return Expect(regex, TimeSpan.Zero); - } - - /// - /// Expects the expression specified by regular expression. - /// - /// The regular expression to expect. - /// Time to wait for input. - /// - /// The text available in the shell that contains all the text that ends with expected expression, - /// or if the specified time has elapsed. - /// - public string Expect(Regex regex, TimeSpan timeout) - { - var text = string.Empty; - - while (true) - { - lock (_incoming) - { - if (_incoming.Count > 0) - { - text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); - } - - var match = regex.Match(text); - - if (match.Success) - { - // Remove processed items from the queue - for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++) - { - _ = _incoming.Dequeue(); - } - - break; - } - } - - if (timeout.Ticks > 0) - { - if (!_dataReceived.WaitOne(timeout)) - { - return null; - } - } - else - { - _ = _dataReceived.WaitOne(); - } - } - - return text; - } - /// /// Begins the expect. /// @@ -438,9 +400,7 @@ public IAsyncResult BeginExpect(AsyncCallback callback, object state, params Exp /// /// An that references the asynchronous operation. /// -#pragma warning disable CA1859 // Use concrete types when possible for improved performance public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object state, params ExpectAction[] expectActions) -#pragma warning restore CA1859 // Use concrete types when possible for improved performance { var text = string.Empty; @@ -521,9 +481,6 @@ public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object /// Ends the execute. /// /// The async result. - /// - /// Text available in the shell that ends with expected text. - /// /// Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult. public string EndExpect(IAsyncResult asyncResult) { @@ -536,6 +493,97 @@ public string EndExpect(IAsyncResult asyncResult) return ar.EndInvoke(); } + /// + /// Expects the expression specified by text. + /// + /// The text to expect. + /// + /// Text available in the shell that ends with expected text. + /// + public string Expect(string text) + { + return Expect(new Regex(Regex.Escape(text)), Session.InfiniteTimeSpan); + } + + /// + /// Expects the expression specified by text. + /// + /// The text to expect. + /// Time to wait for input. + /// + /// The text available in the shell that ends with expected text, or null if the specified time has elapsed. + /// + public string Expect(string text, TimeSpan timeout) + { + return Expect(new Regex(Regex.Escape(text)), timeout); + } + + /// + /// Expects the expression specified by regular expression. + /// + /// The regular expression to expect. + /// + /// The text available in the shell that contains all the text that ends with expected expression. + /// + public string Expect(Regex regex) + { + return Expect(regex, TimeSpan.Zero); + } + + /// + /// Expects the expression specified by regular expression. + /// + /// The regular expression to expect. + /// Time to wait for input. + /// + /// The text available in the shell that contains all the text that ends with expected expression, + /// or null if the specified time has elapsed. + /// + public string Expect(Regex regex, TimeSpan timeout) + { + var text = string.Empty; + + while (true) + { + lock (_incoming) + { + if (_incoming.Count > 0) + { + text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); + } + + var match = regex.Match(text); + + if (match.Success) + { + // Remove processed items from the queue + text = text.Substring(0, match.Index + match.Length); + var bytesProcessed = _encoding.GetByteCount(text); + for (var i = 0; i < bytesProcessed && _incoming.Count > 0; i++) + { + _ = _incoming.Dequeue(); + } + + break; + } + } + + if (timeout.Ticks > 0) + { + if (!_dataReceived.WaitOne(timeout)) + { + return null; + } + } + else + { + _ = _dataReceived.WaitOne(); + } + } + + return text; + } + /// /// Reads the line from the shell. If line is not available it will block the execution and will wait for new line. /// @@ -552,7 +600,7 @@ public string ReadLine() /// /// Time to wait for input. /// - /// The line read from the shell, or when no input is received for the specified timeout. + /// The line read from the shell, or null when no input is received for the specified timeout. /// public string ReadLine(TimeSpan timeout) { @@ -621,42 +669,12 @@ public string Read() return text; } - /// - /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. - /// - /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. - /// The zero-based byte offset in at which to begin storing the data read from the current stream. - /// The maximum number of bytes to be read from the current stream. - /// - /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. - /// - /// The sum of and is larger than the buffer length. - /// is . - /// or is negative. - /// An I/O error occurs. - /// The stream does not support reading. - /// Methods were called after the stream was closed. - public override int Read(byte[] buffer, int offset, int count) - { - var i = 0; - - lock (_incoming) - { - for (; i < count && _incoming.Count > 0; i++) - { - buffer[offset + i] = _incoming.Dequeue(); - } - } - - return i; - } - /// /// Writes the specified text to the shell. /// /// The text to be written to the shell. /// - /// If is , nothing is written. + /// If is null, nothing is written. /// public void Write(string text) { @@ -665,50 +683,21 @@ public void Write(string text) return; } -#if NET7_0_OR_GREATER - ObjectDisposedException.ThrowIf(_channel is null, this); -#else if (_channel is null) { - throw new ObjectDisposedException(GetType().FullName); + throw new ObjectDisposedException("ShellStream"); } -#endif // NET7_0_OR_GREATER var data = _encoding.GetBytes(text); _channel.SendData(data); } - /// - /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. - /// - /// An array of bytes. This method copies bytes from to the current stream. - /// The zero-based byte offset in at which to begin copying bytes to the current stream. - /// The number of bytes to be written to the current stream. - /// The sum of and is greater than the buffer length. - /// is . - /// or is negative. - /// An I/O error occurs. - /// The stream does not support writing. - /// Methods were called after the stream was closed. - public override void Write(byte[] buffer, int offset, int count) - { - foreach (var b in buffer.Take(offset, count)) - { - if (_outgoing.Count == _bufferSize) - { - Flush(); - } - - _outgoing.Enqueue(b); - } - } - /// /// Writes the line to the shell. /// /// The line to be written to the shell. /// - /// If is , only the line terminator is written. + /// If is null, only the line terminator is written. /// public void WriteLine(string line) { @@ -718,7 +707,7 @@ public void WriteLine(string line) /// /// Releases the unmanaged resources used by the and optionally releases the managed resources. /// - /// to release both managed and unmanaged resources; to release only unmanaged resources. + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) { base.Dispose(disposing); @@ -759,7 +748,7 @@ protected override void Dispose(bool disposing) /// /// The session. /// - /// Does nothing when is . + /// Does nothing when is null. /// private void UnsubscribeFromSessionEvents(ISession session) {