<PackageReference Include="SSH.NET" Version="2016.1.0" />

ShellStream

public class ShellStream : Stream
Contains operation for working with SSH Shell.
using Renci.SshNet.Abstractions; using Renci.SshNet.Channels; using Renci.SshNet.Common; using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Threading; namespace Renci.SshNet { public class ShellStream : Stream { private const string CrLf = "\r\n"; private readonly ISession _session; private readonly Encoding _encoding; private readonly int _bufferSize; private readonly Queue<byte> _incoming; private readonly Queue<byte> _outgoing; private IChannelSession _channel; private AutoResetEvent _dataReceived = new AutoResetEvent(false); private bool _isDisposed; public bool DataAvailable { get { lock (_incoming) { return _incoming.Count > 0; } } } internal int BufferSize => _bufferSize; public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => true; public override long Length { get { lock (_incoming) { return _incoming.Count; } } } public override long Position { get { return 0; } set { throw new NotSupportedException(); } } public event EventHandler<ShellDataEventArgs> DataReceived; public event EventHandler<ExceptionEventArgs> ErrorOccurred; internal ShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues, int bufferSize) { _encoding = session.ConnectionInfo.Encoding; _session = session; _bufferSize = bufferSize; _incoming = new Queue<byte>(); _outgoing = new Queue<byte>(); _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.Closed += Channel_Closed; _session.Disconnected += Session_Disconnected; _session.ErrorOccured += Session_ErrorOccured; _channel.Open(); _channel.SendPseudoTerminalRequest(terminalName, columns, rows, width, height, terminalModeValues); _channel.SendShellRequest(); } public override void Flush() { if (_channel == null) throw new ObjectDisposedException("ShellStream"); if (_outgoing.Count > 0) { _channel.SendData(_outgoing.ToArray()); _outgoing.Clear(); } } public override int Read(byte[] buffer, int offset, int count) { int i = 0; lock (_incoming) { for (; i < count; i++) { if (_incoming.Count <= 0) return i; buffer[offset + i] = _incoming.Dequeue(); } return i; } } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { byte[] array = buffer.Take(offset, count); foreach (byte item in array) { if (_outgoing.Count == _bufferSize) Flush(); _outgoing.Enqueue(item); } } public void Expect(params ExpectAction[] expectActions) { Expect(TimeSpan.Zero, expectActions); } public void Expect(TimeSpan timeout, params ExpectAction[] expectActions) { bool flag = false; string text = string.Empty; do { lock (_incoming) { if (_incoming.Count > 0) text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); if (text.Length > 0) { foreach (ExpectAction expectAction in expectActions) { Match match = expectAction.Expect.Match(text); if (match.Success) { string obj = text.Substring(0, match.Index + match.Length); for (int j = 0; j < match.Index + match.Length; j++) { if (_incoming.Count <= 0) break; _incoming.Dequeue(); } expectAction.Action(obj); flag = true; } } } } if (!flag) { if (timeout.Ticks > 0) { if (!_dataReceived.WaitOne(timeout)) break; } else _dataReceived.WaitOne(); } } while (!flag); } public IAsyncResult BeginExpect(params ExpectAction[] expectActions) { return BeginExpect(TimeSpan.Zero, null, null, expectActions); } public IAsyncResult BeginExpect(AsyncCallback callback, params ExpectAction[] expectActions) { return BeginExpect(TimeSpan.Zero, callback, null, expectActions); } public IAsyncResult BeginExpect(AsyncCallback callback, object state, params ExpectAction[] expectActions) { return BeginExpect(TimeSpan.Zero, callback, state, expectActions); } public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object state, params ExpectAction[] expectActions) { string text = string.Empty; ExpectAsyncResult asyncResult = new ExpectAsyncResult(callback, state); ThreadAbstraction.ExecuteThread(delegate { string text2 = null; try { while (true) { lock (_incoming) { if (_incoming.Count > 0) text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); if (text.Length > 0) { ExpectAction[] array = expectActions; foreach (ExpectAction expectAction in array) { Match match = expectAction.Expect.Match(text); if (match.Success) { string text3 = text.Substring(0, match.Index + match.Length); for (int j = 0; j < match.Index + match.Length; j++) { if (_incoming.Count <= 0) break; _incoming.Dequeue(); } expectAction.Action(text3); if (callback != null) callback(asyncResult); text2 = text3; } } } } if (text2 != null) break; if (timeout.Ticks > 0) { if (!_dataReceived.WaitOne(timeout)) { if (callback != null) callback(asyncResult); break; } } else _dataReceived.WaitOne(); } asyncResult.SetAsCompleted(text2, true); } catch (Exception exception) { asyncResult.SetAsCompleted(exception, true); } }); return asyncResult; } public string EndExpect(IAsyncResult asyncResult) { ExpectAsyncResult expectAsyncResult = asyncResult as ExpectAsyncResult; if (expectAsyncResult == null || expectAsyncResult.EndInvokeCalled) throw new ArgumentException("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."); return expectAsyncResult.EndInvoke(); } public string Expect(string text) { return Expect(new Regex(Regex.Escape(text)), Session.InfiniteTimeSpan); } public string Expect(string text, TimeSpan timeout) { return Expect(new Regex(Regex.Escape(text)), timeout); } public string Expect(Regex regex) { return Expect(regex, TimeSpan.Zero); } public string Expect(Regex regex, TimeSpan timeout) { string text = string.Empty; while (true) { lock (_incoming) { if (_incoming.Count > 0) text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); Match match = regex.Match(text); if (match.Success) { for (int i = 0; i < match.Index + match.Length; i++) { if (_incoming.Count <= 0) return text; _incoming.Dequeue(); } return text; } } if (timeout.Ticks > 0) { if (!_dataReceived.WaitOne(timeout)) break; } else _dataReceived.WaitOne(); } return null; } public string ReadLine() { return ReadLine(TimeSpan.Zero); } public string ReadLine(TimeSpan timeout) { string text = string.Empty; while (true) { lock (_incoming) { if (_incoming.Count > 0) text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); int num = text.IndexOf("\r\n", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num); int byteCount = _encoding.GetByteCount(text + "\r\n"); for (int i = 0; i < byteCount; i++) { _incoming.Dequeue(); } return text; } } if (timeout.Ticks > 0) { if (!_dataReceived.WaitOne(timeout)) break; } else _dataReceived.WaitOne(); } return null; } public string Read() { lock (_incoming) { string string = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); _incoming.Clear(); return string; } } public void Write(string text) { if (text != null) { if (_channel == null) throw new ObjectDisposedException("ShellStream"); byte[] bytes = _encoding.GetBytes(text); _channel.SendData(bytes); } } public void WriteLine(string line) { Write(line + "\r"); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (!_isDisposed) { if (disposing) { UnsubscribeFromSessionEvents(_session); if (_channel != null) { _channel.DataReceived -= Channel_DataReceived; _channel.Closed -= Channel_Closed; _channel.Dispose(); _channel = null; } if (_dataReceived != null) { _dataReceived.Dispose(); _dataReceived = null; } _isDisposed = true; } else UnsubscribeFromSessionEvents(_session); } } private void UnsubscribeFromSessionEvents(ISession session) { if (session != null) { session.Disconnected -= Session_Disconnected; session.ErrorOccured -= Session_ErrorOccured; } } private void Session_ErrorOccured(object sender, ExceptionEventArgs e) { OnRaiseError(e); } private void Session_Disconnected(object sender, EventArgs e) { if (_channel != null) _channel.Dispose(); } private void Channel_Closed(object sender, ChannelEventArgs e) { Dispose(); } private void Channel_DataReceived(object sender, ChannelDataEventArgs e) { lock (_incoming) { byte[] data = e.Data; foreach (byte item in data) { _incoming.Enqueue(item); } } if (_dataReceived != null) _dataReceived.Set(); OnDataReceived(e.Data); } private void OnRaiseError(ExceptionEventArgs e) { this.ErrorOccurred?.Invoke(this, e); } private void OnDataReceived(byte[] data) { this.DataReceived?.Invoke(this, new ShellDataEventArgs(data)); } } }