diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs
index 56d2145cc..25d178f85 100644
--- a/src/Renci.SshNet/BaseClient.cs
+++ b/src/Renci.SshNet/BaseClient.cs
@@ -1,9 +1,9 @@
using System;
+using System.Diagnostics;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
-using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;
@@ -317,7 +317,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken)
/// The method was called after the client was disposed.
public void Disconnect()
{
- DiagnosticAbstraction.Log("Disconnecting client.");
+ Diagnostic.Log("Disconnecting client.", TraceEventType.Verbose);
CheckDisposed();
@@ -416,7 +416,7 @@ protected virtual void Dispose(bool disposing)
if (disposing)
{
- DiagnosticAbstraction.Log("Disposing client.");
+ Diagnostic.Log("Disposing client.", TraceEventType.Verbose);
Disconnect();
diff --git a/src/Renci.SshNet/Channels/Channel.cs b/src/Renci.SshNet/Channels/Channel.cs
index 25975872d..162f20e73 100644
--- a/src/Renci.SshNet/Channels/Channel.cs
+++ b/src/Renci.SshNet/Channels/Channel.cs
@@ -1,9 +1,9 @@
using System;
+using System.Diagnostics;
using System.Globalization;
using System.Net.Sockets;
using System.Threading;
-using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Messages;
using Renci.SshNet.Messages.Connection;
@@ -556,7 +556,7 @@ protected virtual void Close()
var closeWaitResult = _session.TryWait(_channelClosedWaitHandle, ConnectionInfo.ChannelCloseTimeout);
if (closeWaitResult != WaitResult.Success)
{
- DiagnosticAbstraction.Log(string.Format("Wait for channel close not successful: {0:G}.", closeWaitResult));
+ Diagnostic.Log(string.Format("Wait for channel close not successful: {0:G}.", closeWaitResult), TraceEventType.Warning);
}
}
}
diff --git a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs
index 6c521bce2..d60a34885 100644
--- a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs
+++ b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs
@@ -1,7 +1,9 @@
using System;
+using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
+
using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Connection;
@@ -156,8 +158,7 @@ private void ShutdownSocket(SocketShutdown how)
}
catch (SocketException ex)
{
- // TODO: log as warning
- DiagnosticAbstraction.Log("Failure shutting down socket: " + ex);
+ Diagnostic.Log("Failure shutting down socket: " + ex, TraceEventType.Warning);
}
}
}
diff --git a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs
index a8382015a..416f3f8b8 100644
--- a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs
+++ b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs
@@ -1,6 +1,8 @@
using System;
+using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
+
using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Connection;
@@ -138,8 +140,7 @@ private void ShutdownSocket(SocketShutdown how)
}
catch (SocketException ex)
{
- // TODO: log as warning
- DiagnosticAbstraction.Log("Failure shutting down socket: " + ex);
+ Diagnostic.Log("Failure shutting down socket: " + ex, TraceEventType.Warning);
}
}
}
diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs
index ae390d604..35ce537c5 100644
--- a/src/Renci.SshNet/Common/Extensions.cs
+++ b/src/Renci.SshNet/Common/Extensions.cs
@@ -315,5 +315,12 @@ internal static bool IsConnected(this Socket socket)
return socket.Connected;
}
+
+ internal static string Join(this IEnumerable values, string separator)
+ {
+ // A sly way to prevent analyzers asking to "use an overload with a char parameter"
+ // which is not available on all targets.
+ return string.Join(separator, values);
+ }
}
}
diff --git a/src/Renci.SshNet/Connection/ConnectorBase.cs b/src/Renci.SshNet/Connection/ConnectorBase.cs
index 384091b18..0d8949e04 100644
--- a/src/Renci.SshNet/Connection/ConnectorBase.cs
+++ b/src/Renci.SshNet/Connection/ConnectorBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
@@ -41,7 +42,7 @@ protected Socket SocketConnect(string host, int port, TimeSpan timeout)
var ipAddress = Dns.GetHostAddresses(host)[0];
var ep = new IPEndPoint(ipAddress, port);
- DiagnosticAbstraction.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port));
+ Diagnostic.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port), TraceEventType.Information);
var socket = SocketFactory.Create(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
@@ -81,7 +82,7 @@ protected async Task SocketConnectAsync(string host, int port, Cancellat
var ep = new IPEndPoint(ipAddress, port);
- DiagnosticAbstraction.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port));
+ Diagnostic.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port), TraceEventType.Information);
var socket = SocketFactory.Create(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
diff --git a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs b/src/Renci.SshNet/Diagnostic.cs
similarity index 61%
rename from src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs
rename to src/Renci.SshNet/Diagnostic.cs
index bc1248dc0..e8584981c 100644
--- a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs
+++ b/src/Renci.SshNet/Diagnostic.cs
@@ -1,28 +1,24 @@
-using System.ComponentModel;
+using System;
using System.Diagnostics;
-namespace Renci.SshNet.Abstractions
+namespace Renci.SshNet
{
///
/// Provides access to the internals of SSH.NET.
///
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static class DiagnosticAbstraction
+ public static class Diagnostic
{
///
/// The instance used by SSH.NET.
///
///
///
- /// Currently, the library only traces events when compiled in Debug mode.
- ///
- ///
/// Configuration on .NET Core must be done programmatically, e.g.
///
- /// DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", "Verbose");
- /// DiagnosticAbstraction.Source.Listeners.Remove("Default");
- /// DiagnosticAbstraction.Source.Listeners.Add(new ConsoleTraceListener());
- /// DiagnosticAbstraction.Source.Listeners.Add(new TextWriterTraceListener("trace.log"));
+ /// Diagnostics.Source.Switch = new SourceSwitch("sourceSwitch", nameof(SourceLevels.Verbose));
+ /// Diagnostics.Source.Listeners.Remove("Default");
+ /// Diagnostics.Source.Listeners.Add(new ConsoleTraceListener());
+ /// Diagnostics.Source.Listeners.Add(new TextWriterTraceListener("SshNetTrace.log"));
///
///
///
@@ -53,17 +49,19 @@ public static class DiagnosticAbstraction
public static readonly TraceSource Source = new TraceSource("SshNet.Logging");
///
- /// Logs a message to at the
- /// level.
+ /// Logs a message to with the specified event type.
///
/// The message to log.
- /// The trace event type.
- [Conditional("DEBUG")]
- public static void Log(string text, TraceEventType type = TraceEventType.Verbose)
+ /// The trace event type.
+ public static void Log(string text, TraceEventType eventType)
+ {
+ Source.TraceEvent(eventType, Environment.CurrentManagedThreadId, text);
+ }
+
+ ///
+ public static bool IsEnabled(TraceEventType eventType)
{
- Source.TraceEvent(type,
- System.Environment.CurrentManagedThreadId,
- text);
+ return Source.Switch.ShouldTrace(eventType);
}
}
}
diff --git a/src/Renci.SshNet/ForwardedPortDynamic.cs b/src/Renci.SshNet/ForwardedPortDynamic.cs
index 0c6e417a8..2d354850d 100644
--- a/src/Renci.SshNet/ForwardedPortDynamic.cs
+++ b/src/Renci.SshNet/ForwardedPortDynamic.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net;
@@ -413,8 +414,7 @@ private void InternalStop(TimeSpan timeout)
if (!_pendingChannelCountdown.Wait(timeout))
{
- // TODO: log as warning
- DiagnosticAbstraction.Log("Timeout waiting for pending channels in dynamic forwarded port to close.");
+ Diagnostic.Log("Timeout waiting for pending channels in dynamic forwarded port to close.", TraceEventType.Warning);
}
}
diff --git a/src/Renci.SshNet/ForwardedPortLocal.cs b/src/Renci.SshNet/ForwardedPortLocal.cs
index fce8f7fd7..e51d205a1 100644
--- a/src/Renci.SshNet/ForwardedPortLocal.cs
+++ b/src/Renci.SshNet/ForwardedPortLocal.cs
@@ -1,9 +1,9 @@
using System;
+using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
-using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
namespace Renci.SshNet
@@ -399,8 +399,7 @@ private void InternalStop(TimeSpan timeout)
if (!_pendingChannelCountdown.Wait(timeout))
{
- // TODO: log as warning
- DiagnosticAbstraction.Log("Timeout waiting for pending channels in local forwarded port to close.");
+ Diagnostic.Log("Timeout waiting for pending channels in local forwarded port to close.", TraceEventType.Warning);
}
}
diff --git a/src/Renci.SshNet/ForwardedPortRemote.cs b/src/Renci.SshNet/ForwardedPortRemote.cs
index 10430abc3..112193eef 100644
--- a/src/Renci.SshNet/ForwardedPortRemote.cs
+++ b/src/Renci.SshNet/ForwardedPortRemote.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Threading;
@@ -213,8 +214,7 @@ protected override void StopPort(TimeSpan timeout)
if (!_pendingChannelCountdown.Wait(timeout))
{
- // TODO: log as warning
- DiagnosticAbstraction.Log("Timeout waiting for pending channels in remote forwarded port to close.");
+ Diagnostic.Log("Timeout waiting for pending channels in remote forwarded port to close.", TraceEventType.Warning);
}
_status = ForwardedPortStatus.Stopped;
diff --git a/src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs b/src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs
index 88ad5a01a..eef36bf70 100644
--- a/src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs
+++ b/src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs
@@ -112,5 +112,11 @@ internal override void Process(Session session)
{
session.OnDisconnectReceived(this);
}
+
+ ///
+ public override string ToString()
+ {
+ return $"SSH_MSG_DISCONNECT ({ReasonCode}) {Description}";
+ }
}
}
diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs
index f24dcafe1..279fb242d 100644
--- a/src/Renci.SshNet/Security/KeyExchange.cs
+++ b/src/Renci.SshNet/Security/KeyExchange.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
-using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Compression;
using Renci.SshNet.Messages;
@@ -71,12 +71,20 @@ public virtual void Start(Session session, KeyExchangeInitMessage message, bool
SendMessage(session.ClientInitMessage);
}
- // Determine encryption algorithm
+ var sessionId = Session.ToHex(Session.SessionId);
+
+ // Determine client encryption algorithm
var clientEncryptionAlgorithmName = (from b in session.ConnectionInfo.Encryptions.Keys
from a in message.EncryptionAlgorithmsClientToServer
where a == b
select a).FirstOrDefault();
+ if (Diagnostic.IsEnabled(TraceEventType.Verbose))
+ {
+ Diagnostic.Log($"[{sessionId}] Encryption client to server: we offer {session.ConnectionInfo.Encryptions.Keys.Join(",")}", TraceEventType.Verbose);
+ Diagnostic.Log($"[{sessionId}] Encryption client to server: they offer {message.EncryptionAlgorithmsClientToServer.Join(",")}", TraceEventType.Verbose);
+ }
+
if (string.IsNullOrEmpty(clientEncryptionAlgorithmName))
{
throw new SshConnectionException("Client encryption algorithm not found", DisconnectReason.KeyExchangeFailed);
@@ -84,11 +92,18 @@ from a in message.EncryptionAlgorithmsClientToServer
session.ConnectionInfo.CurrentClientEncryption = clientEncryptionAlgorithmName;
- // Determine encryption algorithm
+ // Determine server encryption algorithm
var serverDecryptionAlgorithmName = (from b in session.ConnectionInfo.Encryptions.Keys
from a in message.EncryptionAlgorithmsServerToClient
where a == b
select a).FirstOrDefault();
+
+ if (Diagnostic.IsEnabled(TraceEventType.Verbose))
+ {
+ Diagnostic.Log($"[{sessionId}] Encryption server to client: we offer {session.ConnectionInfo.Encryptions.Keys.Join(",")}", TraceEventType.Verbose);
+ Diagnostic.Log($"[{sessionId}] Encryption server to client: they offer {message.EncryptionAlgorithmsServerToClient.Join(",")}", TraceEventType.Verbose);
+ }
+
if (string.IsNullOrEmpty(serverDecryptionAlgorithmName))
{
throw new SshConnectionException("Server decryption algorithm not found", DisconnectReason.KeyExchangeFailed);
@@ -101,6 +116,13 @@ from a in message.EncryptionAlgorithmsServerToClient
from a in message.MacAlgorithmsClientToServer
where a == b
select a).FirstOrDefault();
+
+ if (Diagnostic.IsEnabled(TraceEventType.Verbose))
+ {
+ Diagnostic.Log($"[{sessionId}] MAC client to server: we offer {session.ConnectionInfo.HmacAlgorithms.Keys.Join(",")}", TraceEventType.Verbose);
+ Diagnostic.Log($"[{sessionId}] MAC client to server: they offer {message.MacAlgorithmsClientToServer.Join(",")}", TraceEventType.Verbose);
+ }
+
if (string.IsNullOrEmpty(clientHmacAlgorithmName))
{
throw new SshConnectionException("Server HMAC algorithm not found", DisconnectReason.KeyExchangeFailed);
@@ -113,6 +135,13 @@ from a in message.MacAlgorithmsClientToServer
from a in message.MacAlgorithmsServerToClient
where a == b
select a).FirstOrDefault();
+
+ if (Diagnostic.IsEnabled(TraceEventType.Verbose))
+ {
+ Diagnostic.Log($"[{sessionId}] MAC server to client: we offer {session.ConnectionInfo.HmacAlgorithms.Keys.Join(",")}", TraceEventType.Verbose);
+ Diagnostic.Log($"[{sessionId}] MAC server to client: they offer {message.MacAlgorithmsServerToClient.Join(",")}", TraceEventType.Verbose);
+ }
+
if (string.IsNullOrEmpty(serverHmacAlgorithmName))
{
throw new SshConnectionException("Server HMAC algorithm not found", DisconnectReason.KeyExchangeFailed);
@@ -124,7 +153,14 @@ from a in message.MacAlgorithmsServerToClient
var compressionAlgorithmName = (from b in session.ConnectionInfo.CompressionAlgorithms.Keys
from a in message.CompressionAlgorithmsClientToServer
where a == b
- select a).LastOrDefault();
+ select a).FirstOrDefault();
+
+ if (Diagnostic.IsEnabled(TraceEventType.Verbose))
+ {
+ Diagnostic.Log($"[{sessionId}] Compression client to server: we offer {session.ConnectionInfo.CompressionAlgorithms.Keys.Join(",")}", TraceEventType.Verbose);
+ Diagnostic.Log($"[{sessionId}] Compression client to server: they offer {message.CompressionAlgorithmsClientToServer.Join(",")}", TraceEventType.Verbose);
+ }
+
if (string.IsNullOrEmpty(compressionAlgorithmName))
{
throw new SshConnectionException("Compression algorithm not found", DisconnectReason.KeyExchangeFailed);
@@ -136,7 +172,14 @@ from a in message.CompressionAlgorithmsClientToServer
var decompressionAlgorithmName = (from b in session.ConnectionInfo.CompressionAlgorithms.Keys
from a in message.CompressionAlgorithmsServerToClient
where a == b
- select a).LastOrDefault();
+ select a).FirstOrDefault();
+
+ if (Diagnostic.IsEnabled(TraceEventType.Verbose))
+ {
+ Diagnostic.Log($"[{sessionId}] Compression server to client: we offer {session.ConnectionInfo.CompressionAlgorithms.Keys.Join(",")}", TraceEventType.Verbose);
+ Diagnostic.Log($"[{sessionId}] Compression server to client: they offer {message.CompressionAlgorithmsClientToServer.Join(",")}", TraceEventType.Verbose);
+ }
+
if (string.IsNullOrEmpty(decompressionAlgorithmName))
{
throw new SshConnectionException("Decompression algorithm not found", DisconnectReason.KeyExchangeFailed);
@@ -182,9 +225,13 @@ public Cipher CreateServerCipher()
serverKey = GenerateSessionKey(SharedKey, ExchangeHash, serverKey, _serverCipherInfo.KeySize / 8);
- DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} server cipher.",
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log(string.Format("[{0}] Creating {1} server cipher.",
Session.ToHex(Session.SessionId),
- Session.ConnectionInfo.CurrentServerEncryption));
+ Session.ConnectionInfo.CurrentServerEncryption),
+ TraceEventType.Information);
+ }
// Create server cipher
return _serverCipherInfo.Cipher(serverKey, serverVector);
@@ -207,9 +254,13 @@ public Cipher CreateClientCipher()
clientKey = GenerateSessionKey(SharedKey, ExchangeHash, clientKey, _clientCipherInfo.KeySize / 8);
- DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} client cipher.",
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log(string.Format("[{0}] Creating {1} client cipher.",
Session.ToHex(Session.SessionId),
- Session.ConnectionInfo.CurrentClientEncryption));
+ Session.ConnectionInfo.CurrentClientEncryption),
+ TraceEventType.Information);
+ }
// Create client cipher
return _clientCipherInfo.Cipher(clientKey, clientVector);
@@ -231,9 +282,13 @@ public HashAlgorithm CreateServerHash()
Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'F', sessionId)),
_serverHashInfo.KeySize / 8);
- DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} server hmac algorithm.",
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log(string.Format("[{0}] Creating {1} server hmac algorithm.",
Session.ToHex(Session.SessionId),
- Session.ConnectionInfo.CurrentServerHmacAlgorithm));
+ Session.ConnectionInfo.CurrentServerHmacAlgorithm),
+ TraceEventType.Information);
+ }
return _serverHashInfo.HashAlgorithm(serverKey);
}
@@ -254,9 +309,13 @@ public HashAlgorithm CreateClientHash()
Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'E', sessionId)),
_clientHashInfo.KeySize / 8);
- DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} client hmac algorithm.",
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log(string.Format("[{0}] Creating {1} client hmac algorithm.",
Session.ToHex(Session.SessionId),
- Session.ConnectionInfo.CurrentClientHmacAlgorithm));
+ Session.ConnectionInfo.CurrentClientHmacAlgorithm),
+ TraceEventType.Information);
+ }
return _clientHashInfo.HashAlgorithm(clientKey);
}
@@ -274,9 +333,13 @@ public Compressor CreateCompressor()
return null;
}
- DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} client compressor.",
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log(string.Format("[{0}] Creating {1} client compressor.",
Session.ToHex(Session.SessionId),
- Session.ConnectionInfo.CurrentClientCompressionAlgorithm));
+ Session.ConnectionInfo.CurrentClientCompressionAlgorithm),
+ TraceEventType.Information);
+ }
var compressor = _compressorFactory();
@@ -298,9 +361,13 @@ public Compressor CreateDecompressor()
return null;
}
- DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} server decompressor.",
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log(string.Format("[{0}] Creating {1} server decompressor.",
Session.ToHex(Session.SessionId),
- Session.ConnectionInfo.CurrentServerCompressionAlgorithm));
+ Session.ConnectionInfo.CurrentServerCompressionAlgorithm),
+ TraceEventType.Information);
+ }
var decompressor = _decompressorFactory();
diff --git a/src/Renci.SshNet/ServiceFactory.cs b/src/Renci.SshNet/ServiceFactory.cs
index ece94505b..89263ab7c 100644
--- a/src/Renci.SshNet/ServiceFactory.cs
+++ b/src/Renci.SshNet/ServiceFactory.cs
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Net.Sockets;
using System.Text;
-using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Connection;
using Renci.SshNet.Messages.Transport;
@@ -93,17 +93,25 @@ public IKeyExchange CreateKeyExchange(IDictionary> cl
}
// find an algorithm that is supported by both client and server
- var keyExchangeAlgorithmFactory = (from c in clientAlgorithms
+ var keyExchangeAlgorithm = (from c in clientAlgorithms
from s in serverAlgorithms
where s == c.Key
- select c.Value).FirstOrDefault();
+ select c).FirstOrDefault();
- if (keyExchangeAlgorithmFactory is null)
+ if (Diagnostic.IsEnabled(TraceEventType.Verbose))
+ {
+ Diagnostic.Log($"Key exchange algorithm: we offer {clientAlgorithms.Keys.Join(",")}", TraceEventType.Verbose);
+ Diagnostic.Log($"Key exchange algorithm: they offer {serverAlgorithms.Join(",")}", TraceEventType.Verbose);
+ }
+
+ Diagnostic.Log($"Key exchange algorithm: using {keyExchangeAlgorithm.Key}", TraceEventType.Information);
+
+ if (keyExchangeAlgorithm.Value is null)
{
throw new SshConnectionException("Failed to negotiate key exchange algorithm.", DisconnectReason.KeyExchangeFailed);
}
- return keyExchangeAlgorithmFactory();
+ return keyExchangeAlgorithm.Value();
}
///
@@ -159,7 +167,7 @@ public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSe
fileSize = null;
maxPendingReads = defaultMaxPendingReads;
- DiagnosticAbstraction.Log(string.Format("Failed to obtain size of file. Allowing maximum {0} pending reads: {1}", maxPendingReads, ex));
+ Diagnostic.Log(string.Format("Failed to obtain size of file. Allowing maximum {0} pending reads: {1}", maxPendingReads, ex), TraceEventType.Error);
}
return sftpSession.CreateFileReader(handle, sftpSession, chunkSize, maxPendingReads, fileSize);
diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs
index 122e28d3d..4cf2e75e4 100644
--- a/src/Renci.SshNet/Session.cs
+++ b/src/Renci.SshNet/Session.cs
@@ -1,9 +1,12 @@
using System;
+using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
+#if !NET
using System.Text;
+#endif
using System.Threading;
using System.Threading.Tasks;
@@ -616,7 +619,11 @@ public void Connect()
ServerVersion = ConnectionInfo.ServerVersion = serverIdentification.ToString();
ConnectionInfo.ClientVersion = ClientVersion;
- DiagnosticAbstraction.Log(string.Format("Server version '{0}'.", serverIdentification));
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log($"Our identification: '{ClientVersion}'.", TraceEventType.Information);
+ Diagnostic.Log($"Their identification: '{serverIdentification}'.", TraceEventType.Information);
+ }
if (!(serverIdentification.ProtocolVersion.Equals("2.0") || serverIdentification.ProtocolVersion.Equals("1.99")))
{
@@ -735,7 +742,11 @@ public async Task ConnectAsync(CancellationToken cancellationToken)
ServerVersion = ConnectionInfo.ServerVersion = serverIdentification.ToString();
ConnectionInfo.ClientVersion = ClientVersion;
- DiagnosticAbstraction.Log(string.Format("Server version '{0}'.", serverIdentification));
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log($"Our identification: '{ClientVersion}'.", TraceEventType.Information);
+ Diagnostic.Log($"Their identification: '{serverIdentification}'.", TraceEventType.Information);
+ }
if (!(serverIdentification.ProtocolVersion.Equals("2.0") || serverIdentification.ProtocolVersion.Equals("1.99")))
{
@@ -821,7 +832,10 @@ public async Task ConnectAsync(CancellationToken cancellationToken)
///
public void Disconnect()
{
- DiagnosticAbstraction.Log(string.Format("[{0}] Disconnecting session.", ToHex(SessionId)));
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log(string.Format("[{0}] Disconnecting session.", ToHex(SessionId)), TraceEventType.Information);
+ }
// send SSH_MSG_DISCONNECT message, clear socket read buffer and dispose it
Disconnect(DisconnectReason.ByApplication, "Connection terminated by the client.");
@@ -1057,7 +1071,10 @@ internal void SendMessage(Message message)
WaitOnHandle(_keyExchangeCompletedWaitHandle.WaitHandle);
}
- DiagnosticAbstraction.Log(string.Format("[{0}] Sending message '{1}' to server: '{2}'.", ToHex(SessionId), message.GetType().Name, message));
+ if (Diagnostic.IsEnabled(TraceEventType.Verbose))
+ {
+ Diagnostic.Log(string.Format("[{0}] Sending message '{1}' to server: '{2}'.", ToHex(SessionId), message.GetType().Name, message), TraceEventType.Verbose);
+ }
var paddingMultiplier = _clientCipher is null ? (byte) 8 : Math.Max((byte) 8, _serverCipher.MinimumSize);
var packetData = message.GetPacket(paddingMultiplier, _clientCompression);
@@ -1168,15 +1185,16 @@ private bool TrySendMessage(Message message)
SendMessage(message);
return true;
}
- catch (SshException ex)
- {
- DiagnosticAbstraction.Log(string.Format("Failure sending message '{0}' to server: '{1}' => {2}", message.GetType().Name, message, ex));
- return false;
- }
- catch (SocketException ex)
+ catch (Exception ex)
{
- DiagnosticAbstraction.Log(string.Format("Failure sending message '{0}' to server: '{1}' => {2}", message.GetType().Name, message, ex));
- return false;
+ Diagnostic.Log(string.Format("Failure sending message '{0}' to server: '{1}' => {2}", message.GetType().Name, message, ex), TraceEventType.Error);
+
+ if (ex is SshException or SocketException)
+ {
+ return false;
+ }
+
+ throw;
}
}
@@ -1324,7 +1342,10 @@ private void TrySendDisconnect(DisconnectReason reasonCode, string message)
/// message.
internal void OnDisconnectReceived(DisconnectMessage message)
{
- DiagnosticAbstraction.Log(string.Format("[{0}] Disconnect received: {1} {2}.", ToHex(SessionId), message.ReasonCode, message.Description));
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log(string.Format("[{0}] Disconnect received: {1} {2}.", ToHex(SessionId), message.ReasonCode, message.Description), TraceEventType.Information);
+ }
// transition to disconnecting state to avoid throwing exceptions while cleaning up, and to
// ensure any exceptions that are raised do not overwrite the SshConnectionException that we
@@ -1423,7 +1444,10 @@ internal void OnKeyExchangeInitReceived(KeyExchangeInitMessage message)
ConnectionInfo.CurrentKeyExchangeAlgorithm = _keyExchange.Name;
- DiagnosticAbstraction.Log(string.Format("[{0}] Performing {1} key exchange.", ToHex(SessionId), ConnectionInfo.CurrentKeyExchangeAlgorithm));
+ if (Diagnostic.IsEnabled(TraceEventType.Information))
+ {
+ Diagnostic.Log(string.Format("[{0}] Performing {1} key exchange.", ToHex(SessionId), ConnectionInfo.CurrentKeyExchangeAlgorithm), TraceEventType.Information);
+ }
_keyExchange.HostKeyReceived += KeyExchange_HostKeyReceived;
@@ -1726,34 +1750,34 @@ private Message LoadMessage(byte[] data, int offset, int count)
var message = _sshMessageFactory.Create(messageType);
message.Load(data, offset + 1, count - 1);
- DiagnosticAbstraction.Log(string.Format("[{0}] Received message '{1}' from server: '{2}'.", ToHex(SessionId), message.GetType().Name, message));
+ if (Diagnostic.IsEnabled(TraceEventType.Verbose))
+ {
+ Diagnostic.Log(string.Format("[{0}] Received message '{1}' from server: '{2}'.", ToHex(SessionId), message.GetType().Name, message), TraceEventType.Verbose);
+ }
return message;
}
- private static string ToHex(byte[] bytes, int offset)
+ internal static string ToHex(byte[] bytes)
{
- var byteCount = bytes.Length - offset;
+ if (bytes is null)
+ {
+ return null;
+ }
+#if NET
+ return Convert.ToHexString(bytes);
+#else
var builder = new StringBuilder(bytes.Length * 2);
- for (var i = offset; i < byteCount; i++)
+ for (var i = 0; i < bytes.Length; i++)
{
var b = bytes[i];
_ = builder.Append(b.ToString("X2"));
}
return builder.ToString();
- }
-
- internal static string ToHex(byte[] bytes)
- {
- if (bytes is null)
- {
- return null;
- }
-
- return ToHex(bytes, 0);
+#endif
}
///
@@ -1870,7 +1894,7 @@ private void SocketDisconnectAndDispose()
{
try
{
- DiagnosticAbstraction.Log(string.Format("[{0}] Shutting down socket.", ToHex(SessionId)));
+ Diagnostic.Log(string.Format("[{0}] Shutting down socket.", ToHex(SessionId)), TraceEventType.Verbose);
// Interrupt any pending reads; should be done outside of socket read lock as we
// actually want shutdown the socket to make sure blocking reads are interrupted.
@@ -1882,14 +1906,15 @@ private void SocketDisconnectAndDispose()
}
catch (SocketException ex)
{
- // TODO: log as warning
- DiagnosticAbstraction.Log("Failure shutting down socket: " + ex);
+ Diagnostic.Log("Failure shutting down socket: " + ex, TraceEventType.Warning);
}
}
- DiagnosticAbstraction.Log(string.Format("[{0}] Disposing socket.", ToHex(SessionId)));
+ Diagnostic.Log(string.Format("[{0}] Disposing socket.", ToHex(SessionId)), TraceEventType.Verbose);
+
_socket.Dispose();
- DiagnosticAbstraction.Log(string.Format("[{0}] Disposed socket.", ToHex(SessionId)));
+ Diagnostic.Log(string.Format("[{0}] Disposed socket.", ToHex(SessionId)), TraceEventType.Verbose);
+
_socket = null;
}
}
@@ -1973,7 +1998,7 @@ private void RaiseError(Exception exp)
{
var connectionException = exp as SshConnectionException;
- DiagnosticAbstraction.Log(string.Format("[{0}] Raised exception: {1}", ToHex(SessionId), exp));
+ Diagnostic.Log(string.Format("[{0}] Raised exception: {1}", ToHex(SessionId), exp), TraceEventType.Warning);
if (_isDisconnecting)
{
@@ -2000,7 +2025,8 @@ private void RaiseError(Exception exp)
if (connectionException != null)
{
- DiagnosticAbstraction.Log(string.Format("[{0}] Disconnecting after exception: {1}", ToHex(SessionId), exp));
+ Diagnostic.Log(string.Format("[{0}] Disconnecting after exception: {1}", ToHex(SessionId), exp), TraceEventType.Information);
+
Disconnect(connectionException.DisconnectReason, exp.ToString());
}
}
@@ -2052,7 +2078,7 @@ protected virtual void Dispose(bool disposing)
if (disposing)
{
- DiagnosticAbstraction.Log(string.Format("[{0}] Disposing session.", ToHex(SessionId)));
+ Diagnostic.Log(string.Format("[{0}] Disposing session.", ToHex(SessionId)), TraceEventType.Verbose);
Disconnect();
diff --git a/src/Renci.SshNet/Sftp/SftpFileReader.cs b/src/Renci.SshNet/Sftp/SftpFileReader.cs
index 8d3ef211f..88fdf5af4 100644
--- a/src/Renci.SshNet/Sftp/SftpFileReader.cs
+++ b/src/Renci.SshNet/Sftp/SftpFileReader.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
using System.Runtime.ExceptionServices;
using System.Threading;
@@ -278,7 +279,7 @@ private void Dispose(bool disposing)
}
catch (Exception ex)
{
- DiagnosticAbstraction.Log("Failure closing handle: " + ex);
+ Diagnostic.Log("Failure closing handle: " + ex, TraceEventType.Error);
}
}
}
diff --git a/src/Renci.SshNet/SubsystemSession.cs b/src/Renci.SshNet/SubsystemSession.cs
index 70385d903..2c754a18e 100644
--- a/src/Renci.SshNet/SubsystemSession.cs
+++ b/src/Renci.SshNet/SubsystemSession.cs
@@ -1,9 +1,9 @@
using System;
+using System.Diagnostics;
using System.Globalization;
using System.Runtime.ExceptionServices;
using System.Threading;
-using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
@@ -191,7 +191,7 @@ protected void RaiseError(Exception error)
{
_exception = error;
- DiagnosticAbstraction.Log("Raised exception: " + error);
+ Diagnostic.Log("Raised exception: " + error, TraceEventType.Warning);
_ = _errorOccuredWaitHandle?.Set();
diff --git a/test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs b/test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs
index d08578e4e..dfe8f18bb 100644
--- a/test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs
+++ b/test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs
@@ -1,7 +1,5 @@
using System.Diagnostics;
-using Renci.SshNet.Abstractions;
-
namespace Renci.SshNet.IntegrationTests.TestsFixtures
{
///
@@ -88,15 +86,15 @@ protected void CreateTestFile(string fileName, int size)
protected void EnableTracing()
{
- DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", nameof(SourceLevels.Verbose));
- DiagnosticAbstraction.Source.Listeners.Remove("Default");
- DiagnosticAbstraction.Source.Listeners.Add(new ConsoleTraceListener() { Name = "TestConsoleLogger" });
+ Diagnostic.Source.Switch = new SourceSwitch("sourceSwitch", nameof(SourceLevels.Verbose));
+ Diagnostic.Source.Listeners.Remove("Default");
+ Diagnostic.Source.Listeners.Add(new ConsoleTraceListener() { Name = "TestConsoleLogger" });
}
protected void DisableTracing()
{
- DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", nameof(SourceLevels.Off));
- DiagnosticAbstraction.Source.Listeners.Remove("TestConsoleLogger");
+ Diagnostic.Source.Switch = new SourceSwitch("sourceSwitch", nameof(SourceLevels.Off));
+ Diagnostic.Source.Listeners.Remove("TestConsoleLogger");
}
}
}