/// <summary> /// Connects the subsystem using a new SSH channel session. /// </summary> /// <exception cref="InvalidOperationException">The session is already connected.</exception> /// <exception cref="ObjectDisposedException">The method was called after the session was disposed.</exception> public void Connect() { EnsureNotDisposed(); if (IsOpen) { throw new InvalidOperationException("The session is already connected."); } // reset waithandles in case we're reconnecting _errorOccuredWaitHandle.Reset(); _sessionDisconnectedWaitHandle.Reset(); _sessionDisconnectedWaitHandle.Reset(); _channelClosedWaitHandle.Reset(); _session.ErrorOccured += Session_ErrorOccured; _session.Disconnected += Session_Disconnected; _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.Exception += Channel_Exception; _channel.Closed += Channel_Closed; _channel.Open(); _channel.SendSubsystemRequest(_subsystemName); OnChannelOpen(); }
/// <summary> /// Initializes a new <see cref="ShellStream"/> instance. /// </summary> /// <param name="session">The SSH session.</param> /// <param name="terminalName">The <c>TERM</c> environment variable.</param> /// <param name="columns">The terminal width in columns.</param> /// <param name="rows">The terminal width in rows.</param> /// <param name="width">The terminal height in pixels.</param> /// <param name="height">The terminal height in pixels.</param> /// <param name="terminalModeValues">The terminal mode values.</param> /// <param name="bufferSize">The size of the buffer.</param> /// <exception cref="SshException">The channel could not be opened.</exception> /// <exception cref="SshException">The pseudo-terminal request was not accepted by the server.</exception> /// <exception cref="SshException">The request to start a shell was not accepted by the server.</exception> 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; try { _channel.Open(); if (!_channel.SendPseudoTerminalRequest(terminalName, columns, rows, width, height, terminalModeValues)) { throw new SshException("The pseudo-terminal request was not accepted by the server. Consult the server log for more information."); } if (!_channel.SendShellRequest()) { throw new SshException("The request to start a shell was not accepted by the server. Consult the server log for more information."); } } catch { UnsubscribeFromSessionEvents(session); _channel.Dispose(); throw; } }
/// <summary> /// Begins an asynchronous command execution. /// </summary> /// <param name="callback">An optional asynchronous callback, to be called when the command execution is complete.</param> /// <param name="state">A user-provided object that distinguishes this particular asynchronous read request from other requests.</param> /// <returns> /// An <see cref="IAsyncResult" /> that represents the asynchronous command execution, which could still be pending. /// </returns> /// <exception cref="InvalidOperationException">Asynchronous operation is already in progress.</exception> /// <exception cref="SshException">Invalid operation.</exception> /// <exception cref="ArgumentException">CommandText property is empty.</exception> /// <exception cref="SshConnectionException">Client is not connected.</exception> /// <exception cref="SshOperationTimeoutException">Operation has timed out.</exception> /// <exception cref="InvalidOperationException">Asynchronous operation is already in progress.</exception> /// <exception cref="ArgumentException">CommandText property is empty.</exception> public IAsyncResult BeginExecute(AsyncCallback callback, object state) { // Prevent from executing BeginExecute before calling EndExecute if (_asyncResult != null && !_asyncResult.EndCalled) { throw new InvalidOperationException("Asynchronous operation is already in progress."); } // Create new AsyncResult object _asyncResult = new CommandAsyncResult { AsyncWaitHandle = new ManualResetEvent(false), IsCompleted = false, AsyncState = state, }; // When command re-executed again, create a new channel if (_channel != null) { throw new SshException("Invalid operation."); } if (string.IsNullOrEmpty(CommandText)) { throw new ArgumentException("CommandText property is empty."); } var outputStream = OutputStream; if (outputStream != null) { outputStream.Dispose(); OutputStream = null; } var extendedOutputStream = ExtendedOutputStream; if (extendedOutputStream != null) { extendedOutputStream.Dispose(); ExtendedOutputStream = null; } // Initialize output streams OutputStream = new PipeStream(); ExtendedOutputStream = new PipeStream(); _result = null; _error = null; _callback = callback; _channel = CreateChannel(); _channel.Open(); _channel.SendExecRequest(CommandText); return(_asyncResult); }
internal ShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary <TerminalModes, uint> terminalModeValues) { _encoding = session.ConnectionInfo.Encoding; _session = session; _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(); }
internal ShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues) { _encoding = session.ConnectionInfo.Encoding; _session = session; _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(); }
/// <summary> /// Connects the subsystem using a new SSH channel session. /// </summary> /// <exception cref="InvalidOperationException">The session is already connected.</exception> /// <exception cref="ObjectDisposedException">The method was called after the session was disposed.</exception> /// <exception cref="SshException">The channel session could not be opened, or the subsystem could not be executed.</exception> public void Connect() { EnsureNotDisposed(); if (IsOpen) { throw new InvalidOperationException("The session is already connected."); } // reset waithandles in case we're reconnecting _errorOccuredWaitHandle.Reset(); _sessionDisconnectedWaitHandle.Reset(); _sessionDisconnectedWaitHandle.Reset(); _channelClosedWaitHandle.Reset(); _session.ErrorOccured += Session_ErrorOccured; _session.Disconnected += Session_Disconnected; _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.Exception += Channel_Exception; _channel.Closed += Channel_Closed; _channel.Open(); if (!_channel.SendSubsystemRequest(_subsystemName)) { // close channel session Disconnect(); // signal subsystem failure throw new SshException(string.Format(CultureInfo.InvariantCulture, "Subsystem '{0}' could not be executed.", _subsystemName)); } OnChannelOpen(); }
/// <summary> /// Starts this shell. /// </summary> /// <exception cref="SshException">Shell is started.</exception> public void Start() { if (IsStarted) { throw new SshException("Shell is started."); } if (Starting != null) { Starting(this, new EventArgs()); } _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.ExtendedDataReceived += Channel_ExtendedDataReceived; _channel.Closed += Channel_Closed; _session.Disconnected += Session_Disconnected; _session.ErrorOccured += Session_ErrorOccured; _channel.Open(); _channel.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModes); _channel.SendShellRequest(); _channelClosedWaitHandle = new AutoResetEvent(false); // Start input stream listener _dataReaderTaskCompleted = new ManualResetEvent(false); ThreadAbstraction.ExecuteThread(() => { try { var buffer = new byte[_bufferSize]; while (_channel.IsOpen) { #if FEATURE_STREAM_TAP var readTask = _input.ReadAsync(buffer, 0, buffer.Length); var readWaitHandle = ((IAsyncResult)readTask).AsyncWaitHandle; if (WaitHandle.WaitAny(new[] { readWaitHandle, _channelClosedWaitHandle }) == 0) { var read = readTask.Result; _channel.SendData(buffer, 0, read); continue; } #elif FEATURE_STREAM_APM var asyncResult = _input.BeginRead(buffer, 0, buffer.Length, result => { // If input stream is closed and disposed already don't finish reading the stream if (_input == null) { return; } var read = _input.EndRead(result); _channel.SendData(buffer, 0, read); }, null); WaitHandle.WaitAny(new[] { asyncResult.AsyncWaitHandle, _channelClosedWaitHandle }); if (asyncResult.IsCompleted) { continue; } #else #error Async receive is not implemented. #endif break; } } catch (Exception exp) { RaiseError(new ExceptionEventArgs(exp)); } finally { _dataReaderTaskCompleted.Set(); } }); IsStarted = true; if (Started != null) { Started(this, new EventArgs()); } }
/// <summary> /// Connects the subsystem using a new SSH channel session. /// </summary> /// <exception cref="InvalidOperationException">The session is already connected.</exception> /// <exception cref="ObjectDisposedException">The method was called after the session was disposed.</exception> public void Connect() { EnsureNotDisposed(); if (IsOpen) throw new InvalidOperationException("The session is already connected."); // reset waithandles in case we're reconnecting _errorOccuredWaitHandle.Reset(); _sessionDisconnectedWaitHandle.Reset(); _sessionDisconnectedWaitHandle.Reset(); _channelClosedWaitHandle.Reset(); _session.ErrorOccured += Session_ErrorOccured; _session.Disconnected += Session_Disconnected; _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.Exception += Channel_Exception; _channel.Closed += Channel_Closed; _channel.Open(); _channel.SendSubsystemRequest(_subsystemName); OnChannelOpen(); }
/// <summary> /// Starts this shell. /// </summary> /// <exception cref="SshException">Shell is started.</exception> public void Start() { if (IsStarted) { throw new SshException("Shell is started."); } if (Starting != null) { Starting(this, new EventArgs()); } _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.ExtendedDataReceived += Channel_ExtendedDataReceived; _channel.Closed += Channel_Closed; _session.Disconnected += Session_Disconnected; _session.ErrorOccured += Session_ErrorOccured; _channel.Open(); _channel.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModes); _channel.SendShellRequest(); _channelClosedWaitHandle = new AutoResetEvent(false); // Start input stream listener _dataReaderTaskCompleted = new ManualResetEvent(false); ThreadAbstraction.ExecuteThread(() => { try { var buffer = new byte[_bufferSize]; while (_channel.IsOpen) { #if FEATURE_STREAM_TAP var readTask = _input.ReadAsync(buffer, 0, buffer.Length); var readWaitHandle = ((IAsyncResult) readTask).AsyncWaitHandle; if (WaitHandle.WaitAny(new[] {readWaitHandle, _channelClosedWaitHandle}) == 0) { var read = readTask.Result; _channel.SendData(buffer, 0, read); continue; } #elif FEATURE_STREAM_APM var asyncResult = _input.BeginRead(buffer, 0, buffer.Length, result => { // If input stream is closed and disposed already don't finish reading the stream if (_input == null) return; var read = _input.EndRead(result); _channel.SendData(buffer, 0, read); }, null); WaitHandle.WaitAny(new[] { asyncResult.AsyncWaitHandle, _channelClosedWaitHandle }); if (asyncResult.IsCompleted) continue; #else #error Async receive is not implemented. #endif break; } } catch (Exception exp) { RaiseError(new ExceptionEventArgs(exp)); } finally { _dataReaderTaskCompleted.Set(); } }); IsStarted = true; if (Started != null) { Started(this, new EventArgs()); } }
/// <summary> /// Starts this shell. /// </summary> /// <exception cref="SshException">Shell is started.</exception> public void Start() { if (IsStarted) { throw new SshException("Shell is started."); } if (Starting != null) { Starting(this, new EventArgs()); } _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.ExtendedDataReceived += Channel_ExtendedDataReceived; _channel.Closed += Channel_Closed; _session.Disconnected += Session_Disconnected; _session.ErrorOccured += Session_ErrorOccured; _channel.Open(); _channel.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModes); _channel.SendShellRequest(); _channelClosedWaitHandle = new AutoResetEvent(false); // Start input stream listener _dataReaderTaskCompleted = new ManualResetEvent(false); ExecuteThread(() => { try { var buffer = new byte[_bufferSize]; while (_channel.IsOpen) { var asyncResult = _input.BeginRead(buffer, 0, buffer.Length, delegate(IAsyncResult result) { // If input stream is closed and disposed already dont finish reading the stream if (_input == null) return; var read = _input.EndRead(result); if (read > 0) { #if TUNING _channel.SendData(buffer, 0, read); #else _channel.SendData(buffer.Take(read).ToArray()); #endif } }, null); EventWaitHandle.WaitAny(new WaitHandle[] { asyncResult.AsyncWaitHandle, _channelClosedWaitHandle }); if (asyncResult.IsCompleted) continue; break; } } catch (Exception exp) { RaiseError(new ExceptionEventArgs(exp)); } finally { _dataReaderTaskCompleted.Set(); } }); IsStarted = true; if (Started != null) { Started(this, new EventArgs()); } }
/// <summary> /// Starts this shell. /// </summary> /// <exception cref="SshException">Shell is started.</exception> public void Start() { if (IsStarted) { throw new SshException("Shell is started."); } if (Starting != null) { Starting(this, new EventArgs()); } _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.ExtendedDataReceived += Channel_ExtendedDataReceived; _channel.Closed += Channel_Closed; _session.Disconnected += Session_Disconnected; _session.ErrorOccured += Session_ErrorOccured; _channel.Open(); _channel.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModes); _channel.SendShellRequest(); _channelClosedWaitHandle = new AutoResetEvent(false); // Start input stream listener _dataReaderTaskCompleted = new ManualResetEvent(false); ExecuteThread(async() => { try { var buffer = new byte[_bufferSize]; while (_channel.IsOpen) { var read = await _input.ReadAsync(buffer, 0, buffer.Length); if (read > 0) { #if true //old TUNING _channel.SendData(buffer, 0, read); #else _channel.SendData(buffer.Take(read).ToArray()); #endif } if (_channelClosedWaitHandle.WaitOne(0)) { break; } } } catch (Exception exp) { RaiseError(new ExceptionEventArgs(exp)); } finally { _dataReaderTaskCompleted.Set(); } }); IsStarted = true; if (Started != null) { Started(this, new EventArgs()); } }
/// <summary> /// Begins an asynchronous command execution. /// </summary> /// <param name="callback">An optional asynchronous callback, to be called when the command execution is complete.</param> /// <param name="state">A user-provided object that distinguishes this particular asynchronous read request from other requests.</param> /// <returns> /// An <see cref="IAsyncResult" /> that represents the asynchronous command execution, which could still be pending. /// </returns> /// <exception cref="InvalidOperationException">Asynchronous operation is already in progress.</exception> /// <exception cref="SshException">Invalid operation.</exception> /// <exception cref="ArgumentException">CommandText property is empty.</exception> /// <exception cref="SshConnectionException">Client is not connected.</exception> /// <exception cref="SshOperationTimeoutException">Operation has timed out.</exception> /// <exception cref="InvalidOperationException">Asynchronous operation is already in progress.</exception> /// <exception cref="ArgumentException">CommandText property is empty.</exception> public IAsyncResult BeginExecute(AsyncCallback callback, object state) { // Prevent from executing BeginExecute before calling EndExecute if (_asyncResult != null && !_asyncResult.EndCalled) { throw new InvalidOperationException("Asynchronous operation is already in progress."); } // Create new AsyncResult object _asyncResult = new CommandAsyncResult { AsyncWaitHandle = new ManualResetEvent(false), IsCompleted = false, AsyncState = state, }; // When command re-executed again, create a new channel if (_channel != null) { throw new SshException("Invalid operation."); } if (string.IsNullOrEmpty(CommandText)) throw new ArgumentException("CommandText property is empty."); var outputStream = OutputStream; if (outputStream != null) { outputStream.Dispose(); OutputStream = null; } var extendedOutputStream = ExtendedOutputStream; if (extendedOutputStream != null) { extendedOutputStream.Dispose(); ExtendedOutputStream = null; } // Initialize output streams OutputStream = new PipeStream(); ExtendedOutputStream = new PipeStream(); _result = null; _error = null; _callback = callback; _channel = CreateChannel(); _channel.Open(); _channel.SendExecRequest(CommandText); return _asyncResult; }
/// <summary> /// Starts this shell. /// </summary> /// <exception cref="SshException">Shell is started.</exception> public void Start() { if (IsStarted) { throw new SshException("Shell is started."); } if (Starting != null) { Starting(this, new EventArgs()); } _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; _channel.ExtendedDataReceived += Channel_ExtendedDataReceived; _channel.Closed += Channel_Closed; _session.Disconnected += Session_Disconnected; _session.ErrorOccured += Session_ErrorOccured; _channel.Open(); _channel.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModes); _channel.SendShellRequest(); _channelClosedWaitHandle = new AutoResetEvent(false); // Start input stream listener _dataReaderTaskCompleted = new ManualResetEvent(false); ExecuteThread(() => { try { var buffer = new byte[_bufferSize]; while (_channel.IsOpen) { var asyncResult = _input.BeginRead(buffer, 0, buffer.Length, delegate(IAsyncResult result) { // If input stream is closed and disposed already dont finish reading the stream if (_input == null) { return; } var read = _input.EndRead(result); if (read > 0) { #if TUNING _channel.SendData(buffer, 0, read); #else _channel.SendData(buffer.Take(read).ToArray()); #endif } }, null); EventWaitHandle.WaitAny(new WaitHandle[] { asyncResult.AsyncWaitHandle, _channelClosedWaitHandle }); if (asyncResult.IsCompleted) { continue; } break; } } catch (Exception exp) { RaiseError(new ExceptionEventArgs(exp)); } finally { _dataReaderTaskCompleted.Set(); } }); IsStarted = true; if (Started != null) { Started(this, new EventArgs()); } }