|
|
@@ -8,7 +8,6 @@ using System.Security.Cryptography;
|
|
|
using System.Text;
|
|
|
using System.Text.RegularExpressions;
|
|
|
using System.Threading;
|
|
|
-using System.Threading.Tasks;
|
|
|
using Renci.SshNet.Channels;
|
|
|
using Renci.SshNet.Common;
|
|
|
using Renci.SshNet.Compression;
|
|
|
@@ -24,7 +23,7 @@ namespace Renci.SshNet
|
|
|
/// <summary>
|
|
|
/// Provides functionality to connect and interact with SSH server.
|
|
|
/// </summary>
|
|
|
- public class Session : IDisposable
|
|
|
+ public partial class Session : IDisposable
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// Specifies maximum packet size defined by the protocol.
|
|
|
@@ -46,7 +45,7 @@ namespace Renci.SshNet
|
|
|
/// <remarks>
|
|
|
/// Some server may restrict number to prevent authentication attacks
|
|
|
/// </remarks>
|
|
|
- private static SemaphoreSlim _authenticationConnection = new SemaphoreSlim(3);
|
|
|
+ private static SemaphoreLight _authenticationConnection = new SemaphoreLight(3);
|
|
|
|
|
|
/// <summary>
|
|
|
/// Holds metada about session messages
|
|
|
@@ -61,7 +60,7 @@ namespace Renci.SshNet
|
|
|
/// <summary>
|
|
|
/// Holds reference to task that listens for incoming messages
|
|
|
/// </summary>
|
|
|
- private Task _messageListener;
|
|
|
+ private EventWaitHandle _messageListenerCompleted;
|
|
|
|
|
|
/// <summary>
|
|
|
/// Specifies outbound packet number
|
|
|
@@ -117,12 +116,12 @@ namespace Renci.SshNet
|
|
|
|
|
|
private Compressor _clientCompression;
|
|
|
|
|
|
- private SemaphoreSlim _sessionSemaphore;
|
|
|
+ private SemaphoreLight _sessionSemaphore;
|
|
|
/// <summary>
|
|
|
/// Gets the session semaphore that controls session channels.
|
|
|
/// </summary>
|
|
|
/// <value>The session semaphore.</value>
|
|
|
- public SemaphoreSlim SessionSemaphore
|
|
|
+ public SemaphoreLight SessionSemaphore
|
|
|
{
|
|
|
get
|
|
|
{
|
|
|
@@ -132,7 +131,7 @@ namespace Renci.SshNet
|
|
|
{
|
|
|
if (this._sessionSemaphore == null)
|
|
|
{
|
|
|
- this._sessionSemaphore = new SemaphoreSlim(this.ConnectionInfo.MaxSessions);
|
|
|
+ this._sessionSemaphore = new SemaphoreLight(this.ConnectionInfo.MaxSessions);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -173,7 +172,7 @@ namespace Renci.SshNet
|
|
|
{
|
|
|
get
|
|
|
{
|
|
|
- return this._socket != null && this._socket.Connected && this._isAuthenticated && this._messageListener.Status == TaskStatus.Running;
|
|
|
+ return this._socket != null && this._socket.Connected && this._isAuthenticated && this._messageListenerCompleted != null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -492,7 +491,19 @@ namespace Renci.SshNet
|
|
|
this.RegisterMessage("SSH_MSG_USERAUTH_BANNER");
|
|
|
|
|
|
// Start incoming request listener
|
|
|
- this._messageListener = Task.Factory.StartNew(() => { this.MessageListener(); }, TaskCreationOptions.LongRunning);
|
|
|
+ this._messageListenerCompleted = new ManualResetEvent(false);
|
|
|
+
|
|
|
+ this.ExecuteThread(() =>
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ this.MessageListener();
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ this._messageListenerCompleted.Set();
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
// Wait for key exchange to be completed
|
|
|
this.WaitHandle(this._keyExchangeCompletedWaitHandle);
|
|
|
@@ -844,11 +855,12 @@ namespace Renci.SshNet
|
|
|
this._socket.Disconnect(true);
|
|
|
|
|
|
// When socket is disconnected wait for listener to finish
|
|
|
- if (this._messageListener != null)
|
|
|
+ if (this._messageListenerCompleted != null)
|
|
|
{
|
|
|
// Wait for listener task to finish
|
|
|
- this._messageListener.Wait();
|
|
|
- this._messageListener = null;
|
|
|
+ this._messageListenerCompleted.WaitOne();
|
|
|
+ this._messageListenerCompleted.Dispose();
|
|
|
+ this._messageListenerCompleted = null;
|
|
|
}
|
|
|
|
|
|
this._socket.Dispose();
|
|
|
@@ -1495,12 +1507,7 @@ namespace Renci.SshNet
|
|
|
/// <param name="messageName">Name of the message.</param>
|
|
|
public void RegisterMessage(string messageName)
|
|
|
{
|
|
|
- lock (this._messagesMetadata)
|
|
|
- {
|
|
|
- Parallel.ForEach(
|
|
|
- from m in this._messagesMetadata where m.Name == messageName select m,
|
|
|
- (item) => { item.Enabled = true; item.Activated = true; });
|
|
|
- }
|
|
|
+ this.InternalRegisterMessage(messageName);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -1509,12 +1516,7 @@ namespace Renci.SshNet
|
|
|
/// <param name="messageName">Name of the message.</param>
|
|
|
public void UnRegisterMessage(string messageName)
|
|
|
{
|
|
|
- lock (this._messagesMetadata)
|
|
|
- {
|
|
|
- Parallel.ForEach(
|
|
|
- from m in this._messagesMetadata where m.Name == messageName select m,
|
|
|
- (item) => { item.Enabled = false; item.Activated = false; });
|
|
|
- }
|
|
|
+ this.InternalUnRegisterMessage(messageName);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -1537,8 +1539,14 @@ namespace Renci.SshNet
|
|
|
return message;
|
|
|
}
|
|
|
|
|
|
+ partial void InternalRegisterMessage(string messageName);
|
|
|
+
|
|
|
+ partial void InternalUnRegisterMessage(string messageName);
|
|
|
+
|
|
|
#endregion
|
|
|
|
|
|
+ partial void ExecuteThread(Action action);
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Listens for incoming message from the server and handles them. This method run as a task on separate thread.
|
|
|
/// </summary>
|
|
|
@@ -1632,12 +1640,12 @@ namespace Renci.SshNet
|
|
|
this._socket = null;
|
|
|
}
|
|
|
|
|
|
- if (this._messageListener != null)
|
|
|
+ if (this._messageListenerCompleted != null)
|
|
|
{
|
|
|
// Wait for socket to be closed and for task to complete before disposing a task
|
|
|
- this._messageListener.Wait();
|
|
|
- this._messageListener.Dispose();
|
|
|
- this._messageListener = null;
|
|
|
+ this._messageListenerCompleted.WaitOne();
|
|
|
+ this._messageListenerCompleted.Dispose();
|
|
|
+ this._messageListenerCompleted = null;
|
|
|
}
|
|
|
|
|
|
if (this._serviceAccepted != null)
|
|
|
@@ -1652,12 +1660,6 @@ namespace Renci.SshNet
|
|
|
this._exceptionWaitHandle = null;
|
|
|
}
|
|
|
|
|
|
- if (this._sessionSemaphore != null)
|
|
|
- {
|
|
|
- this._sessionSemaphore.Dispose();
|
|
|
- this._sessionSemaphore = null;
|
|
|
- }
|
|
|
-
|
|
|
if (this._keyExchangeCompletedWaitHandle != null)
|
|
|
{
|
|
|
this._keyExchangeCompletedWaitHandle.Dispose();
|