Explorar o código

Ensure that command EndExecute called only once
Call callback before End* command for SFTP operations

olegkap_cp %!s(int64=14) %!d(string=hai) anos
pai
achega
79095fa477

+ 0 - 13
Renci.SshClient/Renci.SshNet/ChannelAsyncResult.cs

@@ -62,18 +62,5 @@ namespace Renci.SshNet
         {
             this._command = command;
         }
-
-        /// <summary>
-        /// Validates that command object is valid to be used with this instance.
-        /// </summary>
-        /// <param name="command">The command.</param>
-        public void ValidateCommand(SshCommand command)
-        {
-            if (this._command != command)
-            {
-                throw new InvalidOperationException("Invalid IAsyncResult parameter");
-            }
-
-        }
     }
 }

+ 10 - 9
Renci.SshClient/Renci.SshNet/Sftp/SftpCommand.cs

@@ -55,15 +55,6 @@ namespace Renci.SshNet.Sftp
         {
             this.SftpSession.WaitHandle(result.AsyncWaitHandle, this.CommandTimeout);
 
-            if (this._callback != null)
-            {
-                //  Execute callback on new pool thread
-                Task.Factory.StartNew(() =>
-                {
-                    this._callback(result);
-                });
-            }
-
             if (this._error != null)
                 throw this._error;
 
@@ -200,6 +191,16 @@ namespace Renci.SshNet.Sftp
 
         protected void CompleteExecution()
         {
+            //  Call callback if exists
+            if (this._callback != null)
+            {
+                //  Execute callback on new pool thread
+                Task.Factory.StartNew(() =>
+                {
+                    this._callback(this.AsyncResult);
+                });
+            }
+
             this.AsyncResult.Complete();
 
             this.SftpSession.AttributesMessageReceived -= SftpSession_AttributesMessageReceived;

+ 50 - 20
Renci.SshClient/Renci.SshNet/SshCommand.cs

@@ -34,6 +34,8 @@ namespace Renci.SshNet
 
         private bool _hasError;
 
+        private object _endExecuteLock = new object();
+
         /// <summary>
         /// Gets the command text.
         /// </summary>
@@ -204,22 +206,31 @@ namespace Renci.SshNet
         /// <returns></returns>
         public string EndExecute(IAsyncResult asyncResult)
         {
-            CommandAsyncResult channelAsyncResult = asyncResult as CommandAsyncResult;
-
-            if (channelAsyncResult == null)
-                throw new ArgumentException("Not valid 'asynchResult' parameter.");
-
-            channelAsyncResult.ValidateCommand(this);
-
-            //  Make sure that operation completed if not wait for it to finish
-            this.WaitHandle(this._asyncResult.AsyncWaitHandle);
-
-            this._channel.Close();
+            if (this._asyncResult == asyncResult && this._asyncResult != null)
+            {
+                lock (this._endExecuteLock)
+                {
+                    if (this._asyncResult != null)
+                    {
+                        //  Make sure that operation completed if not wait for it to finish
+                        this.WaitHandle(this._asyncResult.AsyncWaitHandle);
 
-            this._channel = null;
+                        this._channel.Close();
 
-            this._asyncResult = null;
+                        this._channel = null;
 
+                        this._asyncResult = null;
+                    }
+                    else
+                    {
+                        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.");
+                    }
+                }
+            }
+            else
+            {
+                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 this.Result;
         }
 
@@ -237,10 +248,28 @@ namespace Renci.SshNet
         /// <summary>
         /// Cancels command execution in asynchronous scenarios. CURRENTLY NOT IMPLEMENTED.
         /// </summary>
-        public void Cancel()
-        {
-            throw new NotImplementedException();
-        }
+        //public void Cancel()
+        //{
+        //    if (this._channel != null && this._channel.IsOpen)
+        //    {
+        //        //this._channel.SendData(Encoding.ASCII.GetBytes("~."));
+        //        this._channel.SendExecRequest("\0x03");
+
+        //        //this._channel.SendSignalRequest("ABRT");
+        //        //this._channel.SendSignalRequest("ALRM");
+        //        //this._channel.SendSignalRequest("FPE");
+        //        //this._channel.SendSignalRequest("HUP");
+        //        //this._channel.SendSignalRequest("ILL");
+        //        //this._channel.SendSignalRequest("INT");
+        //        //this._channel.SendSignalRequest("PIPE");
+        //        //this._channel.SendSignalRequest("QUIT");
+        //        //this._channel.SendSignalRequest("SEGV");
+        //        //this._channel.SendSignalRequest("TERM");
+        //        //this._channel.SendSignalRequest("SEGV");
+        //        //this._channel.SendSignalRequest("USR1");
+        //        //this._channel.SendSignalRequest("USR2");
+        //    }
+        //}
 
         /// <summary>
         /// Executes the specified command text.
@@ -262,7 +291,7 @@ namespace Renci.SshNet
             this._channel.ExtendedDataReceived += Channel_ExtendedDataReceived;
             this._channel.RequestReceived += Channel_RequestReceived;
             this._channel.Closed += Channel_Closed;
-            
+
             //  Dispose of streams if already exists
             if (this.OutputStream != null)
             {
@@ -280,7 +309,7 @@ namespace Renci.SshNet
             this.OutputStream = new PipeStream();
             this.ExtendedOutputStream = new PipeStream();
 
-            this._result = null; 
+            this._result = null;
             this._error = null;
         }
 
@@ -311,12 +340,13 @@ namespace Renci.SshNet
             }
 
             this._asyncResult.IsCompleted = true;
+
             if (this._callback != null)
             {
                 //  Execute callback on different thread
                 Task.Factory.StartNew(() => { this._callback(this._asyncResult); });
             }
-            ((EventWaitHandle)_asyncResult.AsyncWaitHandle).Set();
+            ((EventWaitHandle)this._asyncResult.AsyncWaitHandle).Set();
         }
 
         private void Channel_RequestReceived(object sender, Common.ChannelRequestEventArgs e)