diff --git a/Renci.SshClient/Renci.SshNet/ExpectAsyncResult.cs b/Renci.SshClient/Renci.SshNet/ExpectAsyncResult.cs index 93d2362e..ae004e26 100644 --- a/Renci.SshClient/Renci.SshNet/ExpectAsyncResult.cs +++ b/Renci.SshClient/Renci.SshNet/ExpectAsyncResult.cs @@ -1,4 +1,5 @@ -using System; +using Renci.SshNet.Common; +using System; using System.Threading; namespace Renci.SshNet @@ -6,61 +7,17 @@ namespace Renci.SshNet /// /// Provides additional information for asynchronous command execution /// - public class ExpectAsyncResult : IAsyncResult + public class ExpectAsyncResult : AsyncResult { /// - /// Gets or sets the ShellStream that async result was created for. - /// - /// The ShellStream. - internal ShellStream ShellStream { get; private set; } - - ///// - ///// Gets or sets the bytes received. If SFTP only file bytes are counted. - ///// - ///// Total bytes received. - //public int BytesReceived { get; set; } - - ///// - ///// Gets or sets the bytes sent by SFTP. - ///// - ///// Total bytes sent. - //public int BytesSent { get; set; } - - #region IAsyncResult Members - - /// - /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. - /// - /// A user-defined object that qualifies or contains information about an asynchronous operation. - public object AsyncState { get; internal set; } - - /// - /// Gets a that is used to wait for an asynchronous operation to complete. - /// - /// A that is used to wait for an asynchronous operation to complete. - public WaitHandle AsyncWaitHandle { get; internal set; } - - /// - /// Gets a value that indicates whether the asynchronous operation completed synchronously. - /// - /// true if the asynchronous operation completed synchronously; otherwise, false. - public bool CompletedSynchronously { get; internal set; } - - /// - /// Gets a value that indicates whether the asynchronous operation has completed. - /// - /// true if the operation is complete; otherwise, false. - public bool IsCompleted { get; internal set; } - - #endregion - - /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The shell stream. - internal ExpectAsyncResult(ShellStream shellStream) + /// The async callback. + /// The state. + internal ExpectAsyncResult(AsyncCallback asyncCallback, Object state) + : base(asyncCallback, state) { - this.ShellStream = shellStream; } } } diff --git a/Renci.SshClient/Renci.SshNet/ShellStream.cs b/Renci.SshClient/Renci.SshNet/ShellStream.cs index cf1cda72..c6613660 100644 --- a/Renci.SshClient/Renci.SshNet/ShellStream.cs +++ b/Renci.SshClient/Renci.SshNet/ShellStream.cs @@ -55,7 +55,7 @@ namespace Renci.SshNet internal ShellStream(Session session, string terminalName, uint columns, uint rows, uint width, uint height, int maxLines, IDictionary terminalModeValues) { - this._encoding = new Renci.SshNet.Common.ASCIIEncoding(); + this._encoding = session.ConnectionInfo.Encoding; this._session = session; this._incoming = new Queue(); this._outgoing = new Queue(); @@ -368,70 +368,77 @@ namespace Renci.SshNet var text = string.Empty; // Create new AsyncResult object - var asyncResult = new ExpectAsyncResult(this) - { - AsyncWaitHandle = new ManualResetEvent(false), - IsCompleted = false, - AsyncState = state, - }; + var asyncResult = new ExpectAsyncResult(callback, state); // Execute callback on different thread this.ExecuteThread(() => { - do + string expectActionResult = null; + try { - lock (this._incoming) + + do { - - if (this._incoming.Count > 0) - text = this._encoding.GetString(this._incoming.ToArray(), 0, this._incoming.Count); - - if (text.Length > 0) + lock (this._incoming) { - foreach (var expectAction in expectActions) + + if (this._incoming.Count > 0) + text = this._encoding.GetString(this._incoming.ToArray(), 0, this._incoming.Count); + + if (text.Length > 0) { - var match = expectAction.Expect.Match(text); - - if (match.Success) + foreach (var expectAction in expectActions) { - var result = text.Substring(0, match.Index + match.Length); + var match = expectAction.Expect.Match(text); - for (int i = 0; i < match.Index + match.Length && this._incoming.Count > 0; i++) + if (match.Success) { - // Remove processed items from the queue - this._incoming.Dequeue(); - } + var result = text.Substring(0, match.Index + match.Length); - expectAction.Action(result); + for (int i = 0; i < match.Index + match.Length && this._incoming.Count > 0; i++) + { + // Remove processed items from the queue + this._incoming.Dequeue(); + } - if (callback != null) - { - callback(asyncResult); + expectAction.Action(result); + + if (callback != null) + { + callback(asyncResult); + } + expectActionResult = result; } - ((EventWaitHandle)asyncResult.AsyncWaitHandle).Set(); - break; } } } - } - if (timeout != null) - { - if (!this._dataReceived.WaitOne(timeout)) - { - if (callback != null) - { - callback(asyncResult); - } - ((EventWaitHandle)asyncResult.AsyncWaitHandle).Set(); + if (expectActionResult != null) break; + + if (timeout != null) + { + if (!this._dataReceived.WaitOne(timeout)) + { + if (callback != null) + { + callback(asyncResult); + } + break; + } } - } - else - { - this._dataReceived.WaitOne(); - } - } while (true); + else + { + this._dataReceived.WaitOne(); + } + } while (true); + + asyncResult.SetAsCompleted(expectActionResult, true); + } + catch (Exception exp) + { + asyncResult.SetAsCompleted(exp, true); + } }); return asyncResult; @@ -442,18 +449,15 @@ namespace Renci.SshNet /// /// The async result. /// 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 void EndExpect(IAsyncResult asyncResult) + public string EndExpect(IAsyncResult asyncResult) { - var expectAsyncResult = asyncResult as ExpectAsyncResult; - if (expectAsyncResult != null && expectAsyncResult.ShellStream == this) - { - // Make sure that operation completed if not wait for it to finish - this.WaitHandle(asyncResult.AsyncWaitHandle); + var ar = asyncResult as ExpectAsyncResult; - return; - } + if (ar == null || ar.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."); - 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."); + // Wait for operation to complete, then return result or throw exception + return ar.EndInvoke(); } /// @@ -465,7 +469,7 @@ namespace Renci.SshNet /// public string Expect(string text) { - return this.Expect(new Regex(Regex.Escape(text)), TimeSpan.Zero); + return this.Expect(new Regex(Regex.Escape(text)), TimeSpan.FromMilliseconds(-1)); } /// @@ -511,7 +515,7 @@ namespace Renci.SshNet if (this._incoming.Count > 0) text = this._encoding.GetString(this._incoming.ToArray(), 0, this._incoming.Count); - var match = regex.Match(text.ToString()); + var match = regex.Match(text); if (match.Success) {