Forráskód Böngészése

Avoid event-based memory leak when client is not disposing instance.
Remove partial modifier.

drieseng 9 éve
szülő
commit
9100a47ddd
2 módosított fájl, 41 hozzáadás és 16 törlés
  1. 1 1
      src/Renci.SshNet/Shell.cs
  2. 40 15
      src/Renci.SshNet/ShellStream.cs

+ 1 - 1
src/Renci.SshNet/Shell.cs

@@ -280,7 +280,7 @@ namespace Renci.SshNet
         }
 
         /// <summary>
-        /// Unsubscribes the current <see cref="Channel"/> from session events.
+        /// Unsubscribes the current <see cref="Shell"/> from session events.
         /// </summary>
         /// <param name="session">The session.</param>
         /// <remarks>

+ 40 - 15
src/Renci.SshNet/ShellStream.cs

@@ -14,7 +14,7 @@ namespace Renci.SshNet
     /// <summary>
     /// Contains operation for working with SSH Shell.
     /// </summary>
-    public partial class ShellStream : Stream
+    public class ShellStream : Stream
     {
         private const string CrLf = "\r\n";
         private const int BufferSize = 1024;
@@ -25,6 +25,7 @@ namespace Renci.SshNet
         private readonly Queue<byte> _outgoing;
         private IChannelSession _channel;
         private AutoResetEvent _dataReceived = new AutoResetEvent(false);
+        private bool _isDisposed;
 
         /// <summary>
         /// Occurs when data was received.
@@ -667,27 +668,51 @@ namespace Renci.SshNet
         {
             base.Dispose(disposing);
 
-            if (_session != null)
-            {
-                _session.Disconnected -= Session_Disconnected;
-                _session.ErrorOccured -= Session_ErrorOccured;
-            }
+            if (_isDisposed)
+                return;
 
-            if (_channel != null)
+            if (disposing)
             {
-                _channel.DataReceived -= Channel_DataReceived;
-                _channel.Closed -= Channel_Closed;
-                _channel.Dispose();
-                _channel = null;
-            }
+                UnsubscribeFromSessionEvents(_session);
 
-            if (_dataReceived != null)
+                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
             {
-                _dataReceived.Dispose();
-                _dataReceived = null;
+                UnsubscribeFromSessionEvents(_session);
             }
         }
 
+        /// <summary>
+        /// Unsubscribes the current <see cref="Shell"/> from session events.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <remarks>
+        /// Does nothing when <paramref name="session"/> is <c>null</c>.
+        /// </remarks>
+        private void UnsubscribeFromSessionEvents(ISession session)
+        {
+            if (session == null)
+                return;
+
+            session.Disconnected -= Session_Disconnected;
+            session.ErrorOccured -= Session_ErrorOccured;
+        }
+
         private void Session_ErrorOccured(object sender, ExceptionEventArgs e)
         {
             OnRaiseError(e);