瀏覽代碼

Fix analyzer errors in Renci.SshNet and Renci.SshNet.TestTools.OpenSSH (#1229)

* Fix analyzer errors in Renci.SshNet and Renci.SshNet.TestTools.OpenSSH.
Suppress all errors in unit tests and integration tests.

* Update unit tests now that we pass 'mode' as argument name when we throw ArgumentException.

* Remove stale comment and add unit tests for SshData.ReadBytes(int length).

* Remove unnessary suppression.

* Remove Visual Studio magic.

* Removed duplicate source file.

* Clarified that suppression hides a false positive.

* Remove suppressions for S2372.

* Update ReadExtensionPair() to return concrete dictionary.
Gert Driesen 2 年之前
父節點
當前提交
508fc87d2a
共有 100 個文件被更改,包括 1094 次插入523 次删除
  1. 50 0
      .editorconfig
  2. 3 5
      Directory.Build.props
  3. 121 2
      src/Renci.SshNet/.editorconfig
  4. 0 4
      src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs
  5. 3 3
      src/Renci.SshNet/Abstractions/DnsAbstraction.cs
  6. 1 1
      src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs
  7. 6 6
      src/Renci.SshNet/Abstractions/SocketAbstraction.cs
  8. 22 9
      src/Renci.SshNet/Abstractions/SocketExtensions.cs
  9. 17 5
      src/Renci.SshNet/Abstractions/ThreadAbstraction.cs
  10. 2 0
      src/Renci.SshNet/AuthenticationMethod.cs
  11. 3 1
      src/Renci.SshNet/AuthenticationResult.cs
  12. 11 4
      src/Renci.SshNet/BaseClient.cs
  13. 7 7
      src/Renci.SshNet/Channels/Channel.cs
  14. 4 4
      src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs
  15. 1 1
      src/Renci.SshNet/Channels/ChannelSession.cs
  16. 8 6
      src/Renci.SshNet/Channels/ChannelTypes.cs
  17. 1 1
      src/Renci.SshNet/Channels/ClientChannel.cs
  18. 6 2
      src/Renci.SshNet/Channels/IChannelSession.cs
  19. 1 1
      src/Renci.SshNet/CipherInfo.cs
  20. 20 6
      src/Renci.SshNet/ClientAuthentication.cs
  21. 0 46
      src/Renci.SshNet/Common/AsyncResult.cs
  22. 50 0
      src/Renci.SshNet/Common/AsyncResult{TResult}.cs
  23. 134 41
      src/Renci.SshNet/Common/BigInteger.cs
  24. 9 1
      src/Renci.SshNet/Common/ChannelDataEventArgs.cs
  25. 6 0
      src/Renci.SshNet/Common/ChannelRequestEventArgs.cs
  26. 1 1
      src/Renci.SshNet/Common/DerData.cs
  27. 2 1
      src/Renci.SshNet/Common/Extensions.cs
  28. 30 14
      src/Renci.SshNet/Common/HostKeyEventArgs.cs
  29. 1 1
      src/Renci.SshNet/Common/NetConfServerException.cs
  30. 2 0
      src/Renci.SshNet/Common/ObjectIdentifier.cs
  31. 30 15
      src/Renci.SshNet/Common/PipeStream.cs
  32. 2 2
      src/Renci.SshNet/Common/SemaphoreLight.cs
  33. 11 0
      src/Renci.SshNet/Common/SshConnectionException.cs
  34. 31 15
      src/Renci.SshNet/Common/SshData.cs
  35. 18 18
      src/Renci.SshNet/Common/SshDataStream.cs
  36. 5 1
      src/Renci.SshNet/Common/TerminalModes.cs
  37. 1 1
      src/Renci.SshNet/Compression/CompressionMode.cs
  38. 7 5
      src/Renci.SshNet/Compression/Compressor.cs
  39. 2 2
      src/Renci.SshNet/Compression/Zlib.cs
  40. 3 3
      src/Renci.SshNet/Compression/ZlibOpenSsh.cs
  41. 9 0
      src/Renci.SshNet/Compression/ZlibStream.cs
  42. 18 0
      src/Renci.SshNet/Connection/IConnector.cs
  43. 13 1
      src/Renci.SshNet/Connection/IProtocolVersionExchange.cs
  44. 14 0
      src/Renci.SshNet/Connection/ISocketFactory.cs
  45. 11 1
      src/Renci.SshNet/Connection/ProtocolVersionExchange.cs
  46. 33 2
      src/Renci.SshNet/Connection/ProxyConnector.cs
  47. 15 1
      src/Renci.SshNet/Connection/SocketFactory.cs
  48. 17 15
      src/Renci.SshNet/Connection/Socks4Connector.cs
  49. 34 28
      src/Renci.SshNet/Connection/Socks5Connector.cs
  50. 18 2
      src/Renci.SshNet/ConnectionInfo.cs
  51. 4 2
      src/Renci.SshNet/ForwardedPortDynamic.cs
  52. 2 0
      src/Renci.SshNet/ForwardedPortStatus.cs
  53. 2 2
      src/Renci.SshNet/HashInfo.cs
  54. 1 6
      src/Renci.SshNet/IBaseClient.cs
  55. 17 1
      src/Renci.SshNet/IClientAuthentication.cs
  56. 0 29
      src/Renci.SshNet/IConnectionInfo.cs
  57. 37 0
      src/Renci.SshNet/IConnectionInfoInternal.cs
  58. 0 30
      src/Renci.SshNet/IForwardedPort.cs
  59. 4 1
      src/Renci.SshNet/ISession.cs
  60. 20 18
      src/Renci.SshNet/ISftpClient.cs
  61. 5 5
      src/Renci.SshNet/ISubsystemSession.cs
  62. 2 1
      src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs
  63. 7 1
      src/Renci.SshNet/Messages/Authentication/FailureMessage.cs
  64. 2 1
      src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs
  65. 0 1
      src/Renci.SshNet/Messages/Authentication/RequestMessage.cs
  66. 1 1
      src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs
  67. 0 1
      src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs
  68. 0 1
      src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs
  69. 0 1
      src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs
  70. 1 1
      src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenInfo.cs
  71. 2 2
      src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs
  72. 20 8
      src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs
  73. 2 2
      src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs
  74. 2 2
      src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs
  75. 0 1
      src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs
  76. 7 4
      src/Renci.SshNet/Messages/Connection/ChannelOpenFailureReasons.cs
  77. 4 4
      src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs
  78. 5 2
      src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs
  79. 2 2
      src/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs
  80. 4 4
      src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs
  81. 3 3
      src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs
  82. 2 2
      src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs
  83. 3 3
      src/Renci.SshNet/Messages/Connection/ChannelRequest/KeepAliveRequestInfo.cs
  84. 1 1
      src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalRequestInfo.cs
  85. 1 1
      src/Renci.SshNet/Messages/Connection/ChannelRequest/RequestInfo.cs
  86. 2 2
      src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs
  87. 1 1
      src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs
  88. 2 2
      src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs
  89. 2 2
      src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs
  90. 1 1
      src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs
  91. 2 2
      src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs
  92. 0 1
      src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs
  93. 1 1
      src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs
  94. 3 2
      src/Renci.SshNet/Messages/Connection/GlobalRequestName.cs
  95. 59 54
      src/Renci.SshNet/Messages/Message.cs
  96. 4 5
      src/Renci.SshNet/Messages/MessageAttribute.cs
  97. 3 3
      src/Renci.SshNet/Messages/ServiceName.cs
  98. 1 1
      src/Renci.SshNet/Messages/Transport/DebugMessage.cs
  99. 33 16
      src/Renci.SshNet/Messages/Transport/DisconnectReason.cs
  100. 3 1
      src/Renci.SshNet/Messages/Transport/IKeyExchangedAllowed.cs

+ 50 - 0
.editorconfig

@@ -77,6 +77,12 @@ dotnet_diagnostic.S1172.severity = none
 # This is a duplicate of IDE0059.
 dotnet_diagnostic.S1481.severity = none
 
+# S1854: Unused assignments should be removed
+# https://rules.sonarsource.com/csharp/RSPEC-1854
+#
+# This is a duplicate of IDE0059.
+dotnet_diagnostic.S1854.severity = none
+
 # S2259: Null pointers should not be dereferenced
 # https://rules.sonarsource.com/csharp/RSPEC-2259
 #
@@ -168,6 +174,12 @@ dotnet_diagnostic.S3928.severity = none
 # This is a duplicate of CA2002, and partial duplicate of MA0064.
 dotnet_diagnostic.S3998.severity = none
 
+# S4070: Non-flags enums should not be marked with "FlagsAttribute"
+# https://rules.sonarsource.com/csharp/RSPEC-4070
+#
+# This is a duplicate of MA0062.
+dotnet_diagnostic.S4070.severity = none
+
 # S4456: Parameter validation in yielding methods should be wrapped
 # https://rules.sonarsource.com/csharp/RSPEC-4456
 #
@@ -364,6 +376,14 @@ dotnet_diagnostic.MA0018.severity = none
 # No strong need for this, and may negatively affect performance.
 dotnet_diagnostic.MA0021.severity = none
 
+# MA0025: Implement the functionality instead of throwing NotImplementedException
+# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0031.md
+dotnet_diagnostic.MA0025.severity = none
+
+# MA0026: Fix TODO comment
+# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0026.md
+dotnet_diagnostic.MA0026.severity = suggestion
+
 # MA0031: Optimize Enumerable.Count() usage
 # https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0031.md
 #
@@ -436,6 +456,12 @@ dotnet_diagnostic.MA0112.severity = error
 # instead of a base class or interface.
 dotnet_diagnostic.CA1002.severity = none
 
+# CA1003: Use generic event handler instances
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1003
+#
+# Similar to MA0046.
+dotnet_diagnostic.CA1003.severity = none
+
 # CA1008: Enums should have zero value
 #
 # TODO: To be discussed. Having a zero value offers a performance advantage.
@@ -460,6 +486,10 @@ dotnet_diagnostic.CA1051.severity = none
 # By default, this diagnostic is only reported for public types.
 dotnet_code_quality.CA1052.api_surface = all
 
+# CA1065: Do not raise exceptions in unexpected locations
+# https://learn.microsoft.com/en-US/dotnet/fundamentals/code-analysis/quality-rules/ca1065
+dotnet_diagnostic.CA1065.severity = none
+
 # CA1303: Do not pass literals as localized parameters
 #
 # We don't care about localization.
@@ -473,6 +503,10 @@ dotnet_diagnostic.CA1303.severity = none
 # Submitted https://github.com/dotnet/roslyn-analyzers/issues/6096 to fix CA1305.
 dotnet_diagnostic.CA1305.severity = none
 
+# CA1309: Use ordinal StringComparison
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1309
+dotnet_diagnostic.CA1309.severity = none
+
 # CA1510: Use ArgumentNullException throw helper
 #
 # This is only available in .NET 6.0 and higher. We'd need to use conditional compilation to only
@@ -577,6 +611,22 @@ dotnet_diagnostic.IDE0130.severity = none
 # var inputPath = originalDossierPathList.Find(x => x.id == updatedPath.id) ?? throw new PcsException($"Path id ({updatedPath.id}) unknown in PCS for dossier id {dossierFromTs.dossier.id}", updatedPath.id);
 dotnet_diagnostic.IDE0270.severity = none
 
+# IDE0290: Use primary constructor
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0290
+dotnet_diagnostic.IDE0290.severity = none
+
+# IDE0300: Collection initialization can be simplified
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0300
+#
+# TODO: Discuss whether we want to start using this
+dotnet_diagnostic.IDE0300.severity = none
+
+# IDE0301: Simplify collection initialization
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0301
+#
+# TODO: Discuss whether we want to start using this
+dotnet_diagnostic.IDE0301.severity = none
+
 #### .NET Compiler Platform code style rules ####
 
 ### Language rules ###

+ 3 - 5
Directory.Build.props

@@ -18,7 +18,7 @@
         Code analysis properties.
     -->
     <PropertyGroup>
-        <EnableNETAnalyzers>false</EnableNETAnalyzers>
+        <EnableNETAnalyzers>true</EnableNETAnalyzers>
         <AnalysisLevel>preview-All</AnalysisLevel>
         <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
     </PropertyGroup>
@@ -34,11 +34,9 @@
         Use fixed version of analyzers.
     -->
     <ItemGroup>
-        <!--
         <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0-preview1.23165.1" PrivateAssets="all" />
         <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="all" />
-        <PackageReference Include="Meziantou.Analyzer" Version="2.0.54" PrivateAssets="all" />
-        <PackageReference Include="SonarAnalyzer.CSharp" Version="8.55.0.65544" PrivateAssets="all" />
-        -->        
+        <PackageReference Include="Meziantou.Analyzer" Version="2.0.103" PrivateAssets="all" />
+        <PackageReference Include="SonarAnalyzer.CSharp" Version="9.12.0.78982" PrivateAssets="all" />
     </ItemGroup>
 </Project>

+ 121 - 2
src/Renci.SshNet/.editorconfig

@@ -1,5 +1,38 @@
 [*.cs]
 
+#### Sonar rules ####
+
+# S1264: A "while" loop should be used instead of a "for" loop
+# https://rules.sonarsource.com/csharp/RSPEC-1264
+dotnet_diagnostic.S1264.severity = none
+
+# S1450: Private fields only used as local variables in methods should become local variables
+# https://rules.sonarsource.com/csharp/RSPEC-1450
+#
+# TODO: Re-enable when the following issue is resolved:
+# https://github.com/SonarSource/sonar-dotnet/issues/8239
+dotnet_diagnostic.S1450.severity = none
+
+# S2372: Exceptions should not be thrown from property getters
+# https://rules.sonarsource.com/csharp/RSPEC-2372/
+dotnet_diagnostic.S2372.severity = none
+
+# S2583: Conditionally executed code should be reachable
+# https://rules.sonarsource.com/csharp/RSPEC-2583/
+#
+# TODO: Re-enable when the following issue is resolved:
+# https://github.com/SonarSource/sonar-dotnet/issues/8264
+dotnet_diagnostic.S2583.severity = none
+
+# S2589: Boolean expressions should not be gratuitous
+# https://rules.sonarsource.com/csharp/RSPEC-2589/
+#
+# TODO: Re-enable when the following issue is resolved:
+# https://github.com/SonarSource/sonar-dotnet/issues/8262
+dotnet_diagnostic.S2589.severity = none
+
+dotnet_diagnostic.S2372.severity = none
+
 #### SYSLIB diagnostics ####
 
 # SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time
@@ -7,32 +40,114 @@
 # TODO: Remove this when https://github.com/sshnet/SSH.NET/issues/1131 is implemented.
 dotnet_diagnostic.SYSLIB1045.severity = none
 
-### StyleCop Analyzers rules ###
+#### StyleCop Analyzers rules ####
+
+# SA1123: Do not place regions within elements
+# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1123.md
+dotnet_diagnostic.SA1123.severity = none
+
+# SA1124: Do not use regions
+# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1124.md
+dotnet_diagnostic.SA1124.severity = none
 
 # SA1202: Elements must be ordered by access
 # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1202.md
 dotnet_diagnostic.SA1202.severity = none
 
+# SA1204: Static elements must appear before instance elements
+# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1204.md
+dotnet_diagnostic.SA1204.severity = none
+
+# SA1310: Field names must not contain underscore
+# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1310.md
+#dotnet_diagnostic.SA1310.severity = none
+
+# SA1312: Variable names should begin with lower-case letter
+# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md
+dotnet_diagnostic.SA1312.severity = none
+
+# SA1636: File header copyright text should match
+# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1636.md
+dotnet_diagnostic.SA1636.severity = none
+
+# SA1643: Destructor summary documentation must begin with standard text
+# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1643.md
+dotnet_diagnostic.SA1643.severity = none
+
 #### Meziantou.Analyzer rules ####
 
+# MA0001: StringComparison is missing
+# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0001.md
+dotnet_diagnostic.MA0001.severity = none
+
+# MA0011: IFormatProvider is missing
+# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0011.md
+#
+# TODO: Remove exclusion when issues are fixed
+dotnet_diagnostic.MA0011.severity = none
+
+# MA0015: Specify the parameter name in ArgumentException
+# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0015.md
+#
+# TODO: Remove exclusion when issues are fixed
+dotnet_diagnostic.MA0015.severity = none
+
+# MA0050: Validate arguments correctly in iterator methods
+# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0050.md
+#
+# TODO: Re-enable when https://github.com/meziantou/Meziantou.Analyzer/issues/617 is fixed
+dotnet_diagnostic.MA0050.severity = none
+
 # MA0053: Make class sealed
 # https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0053.md
 MA0053.public_class_should_be_sealed = false
 
+# MA0055: Do not use finalizer
+# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0055.md
+#
+# TODO: Remove exclusion when issues are fixed
+dotnet_diagnostic.MA0055.severity = none
+
+# MA0110: Use the Regex source generator
+# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0110.md
+dotnet_diagnostic.MA0110.severity = none
+
 #### .NET Compiler Platform analysers rules ####
 
 # CA1030: Use events where appropriate
 # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1030
-dotnet_diagnostic.CA10310.severity = none
+dotnet_diagnostic.CA1030.severity = none
 
 # CA1031: Do not catch general exception types
 # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1031
 dotnet_diagnostic.CA1031.severity = none
 
+# CA1062: Validate arguments of public methods
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1062
+#
+# TODO: Remove exclusion when issues are fixed
+dotnet_diagnostic.CA1062.severity = none
+
+# CA1307: Specify StringComparison for clarity
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1307
+dotnet_diagnostic.CA1307.severity = none
+
+# CA1716: Identifiers should not match keywords
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1716
+dotnet_diagnostic.CA1716.severity = none
+
+# CA1822: Mark members as static
+# https://learn.microsoft.com/en-US/dotnet/fundamentals/code-analysis/quality-rules/ca1822
+dotnet_code_quality.CA1822.api_surface = private,internal
+
 # CA2213: Disposable fields should be disposed
 # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2213
 dotnet_diagnostic.CA2213.severity = none
 
+# CA3075: Insecure DTD Processing
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca3075
+dotnet_diagnostic.CA3075.severity = none
+
 # IDE0004: Types that own disposable fields should be disposable
 # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0004
 dotnet_diagnostic.IDE0004.severity = none
@@ -40,3 +155,7 @@ dotnet_diagnostic.IDE0004.severity = none
 # IDE0048: Add parentheses for clarity
 # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0047
 dotnet_diagnostic.IDE0048.severity = none
+
+# IDE0305: Collection initialization can be simplified
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0305
+dotnet_diagnostic.IDE0305.severity = none

+ 0 - 4
src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs

@@ -22,11 +22,7 @@ namespace Renci.SshNet.Abstractions
         public static void Log(string text)
         {
             Loggging.TraceEvent(TraceEventType.Verbose,
-#if NET6_0_OR_GREATER
                                 System.Environment.CurrentManagedThreadId,
-#else
-                                System.Threading.Thread.CurrentThread.ManagedThreadId,
-#endif // NET6_0_OR_GREATER
                                 text);
         }
     }

+ 3 - 3
src/Renci.SshNet/Abstractions/DnsAbstraction.cs

@@ -25,7 +25,7 @@ namespace Renci.SshNet.Abstractions
         /// <summary>
         /// Returns the Internet Protocol (IP) addresses for the specified host.
         /// </summary>
-        /// <param name="hostNameOrAddress">The host name or IP address to resolve</param>
+        /// <param name="hostNameOrAddress">The host name or IP address to resolve.</param>
         /// <returns>
         /// An array of type <see cref="IPAddress"/> that holds the IP addresses for the host that
         /// is specified by the <paramref name="hostNameOrAddress"/> parameter.
@@ -34,7 +34,7 @@ namespace Renci.SshNet.Abstractions
         /// <exception cref="SocketException">An error is encountered when resolving <paramref name="hostNameOrAddress"/>.</exception>
         public static IPAddress[] GetHostAddresses(string hostNameOrAddress)
         {
-            // TODO Eliminate sync variant, and implement timeout
+            /* TODO Eliminate sync variant, and implement timeout */
 
 #if FEATURE_DNS_SYNC
             return Dns.GetHostAddresses(hostNameOrAddress);
@@ -92,7 +92,7 @@ namespace Renci.SshNet.Abstractions
         /// <summary>
         /// Returns the Internet Protocol (IP) addresses for the specified host.
         /// </summary>
-        /// <param name="hostNameOrAddress">The host name or IP address to resolve</param>
+        /// <param name="hostNameOrAddress">The host name or IP address to resolve.</param>
         /// <returns>
         /// A task with result of an array of type <see cref="IPAddress"/> that holds the IP addresses for the host that
         /// is specified by the <paramref name="hostNameOrAddress"/> parameter.

+ 1 - 1
src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs

@@ -7,7 +7,7 @@ namespace Renci.SshNet.Abstractions
     internal static class ReflectionAbstraction
     {
         public static IEnumerable<T> GetCustomAttributes<T>(this Type type, bool inherit)
-            where T:Attribute
+            where T : Attribute
         {
             var attributes = type.GetCustomAttributes(typeof(T), inherit);
             return attributes.Cast<T>();

+ 6 - 6
src/Renci.SshNet/Abstractions/SocketAbstraction.cs

@@ -261,11 +261,6 @@ namespace Renci.SshNet.Abstractions
             return buffer;
         }
 
-        public static Task<int> ReadAsync(Socket socket, byte[] buffer, int offset, int length, CancellationToken cancellationToken)
-        {
-            return socket.ReceiveAsync(buffer, offset, length, cancellationToken);
-        }
-
         /// <summary>
         /// Receives data from a bound <see cref="Socket"/> into a receive buffer.
         /// </summary>
@@ -293,7 +288,7 @@ namespace Renci.SshNet.Abstractions
             var totalBytesRead = 0;
             var totalBytesToRead = size;
 
-            socket.ReceiveTimeout = (int)readTimeout.TotalMilliseconds;
+            socket.ReceiveTimeout = (int) readTimeout.TotalMilliseconds;
 
             do
             {
@@ -330,6 +325,11 @@ namespace Renci.SshNet.Abstractions
             return totalBytesRead;
         }
 
+        public static Task<int> ReadAsync(Socket socket, byte[] buffer, int offset, int length, CancellationToken cancellationToken)
+        {
+            return socket.ReceiveAsync(buffer, offset, length, cancellationToken);
+        }
+
         public static void Send(Socket socket, byte[] data)
         {
             Send(socket, data, 0, data.Length);

+ 22 - 9
src/Renci.SshNet/Abstractions/SocketExtensions.cs

@@ -10,24 +10,25 @@ namespace Renci.SshNet.Abstractions
     // Async helpers based on https://devblogs.microsoft.com/pfxteam/awaiting-socket-operations/
     internal static class SocketExtensions
     {
-        private sealed class SocketAsyncEventArgsAwaitable : SocketAsyncEventArgs, INotifyCompletion
+        private sealed class AwaitableSocketAsyncEventArgs : SocketAsyncEventArgs, INotifyCompletion
         {
             private static readonly Action SENTINEL = () => { };
 
             private bool _isCancelled;
             private Action _continuationAction;
 
-            public SocketAsyncEventArgsAwaitable()
+            public AwaitableSocketAsyncEventArgs()
             {
-                Completed += delegate { SetCompleted(); };
+                Completed += (sender, e) => SetCompleted();
             }
 
-            public SocketAsyncEventArgsAwaitable ExecuteAsync(Func<SocketAsyncEventArgs, bool> func)
+            public AwaitableSocketAsyncEventArgs ExecuteAsync(Func<SocketAsyncEventArgs, bool> func)
             {
                 if (!func(this))
                 {
                     SetCompleted();
                 }
+
                 return this;
             }
 
@@ -48,7 +49,9 @@ namespace Renci.SshNet.Abstractions
                 SetCompleted();
             }
 
-            public SocketAsyncEventArgsAwaitable GetAwaiter()
+#pragma warning disable S1144 // Unused private types or members should be removed
+            public AwaitableSocketAsyncEventArgs GetAwaiter()
+#pragma warning restore S1144 // Unused private types or members should be removed
             {
                 return this;
             }
@@ -64,7 +67,9 @@ namespace Renci.SshNet.Abstractions
                 }
             }
 
+#pragma warning disable S1144 // Unused private types or members should be removed
             public void GetResult()
+#pragma warning restore S1144 // Unused private types or members should be removed
             {
                 if (_isCancelled)
                 {
@@ -88,11 +93,15 @@ namespace Renci.SshNet.Abstractions
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            using (var args = new SocketAsyncEventArgsAwaitable())
+            using (var args = new AwaitableSocketAsyncEventArgs())
             {
                 args.RemoteEndPoint = remoteEndpoint;
 
-                using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, useSynchronizationContext: false))
+#if NET || NETSTANDARD2_1_OR_GREATER
+                await using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs)o).SetCancelled(), args, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false))
+#else
+                using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs) o).SetCancelled(), args, useSynchronizationContext: false))
+#endif // NET || NETSTANDARD2_1_OR_GREATER
                 {
                     await args.ExecuteAsync(socket.ConnectAsync);
                 }
@@ -103,11 +112,15 @@ namespace Renci.SshNet.Abstractions
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            using (var args = new SocketAsyncEventArgsAwaitable())
+            using (var args = new AwaitableSocketAsyncEventArgs())
             {
                 args.SetBuffer(buffer, offset, length);
 
-                using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, useSynchronizationContext: false))
+#if NET || NETSTANDARD2_1_OR_GREATER
+                await using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs) o).SetCancelled(), args, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false))
+#else
+                using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs) o).SetCancelled(), args, useSynchronizationContext: false))
+#endif // NET || NETSTANDARD2_1_OR_GREATER
                 {
                     await args.ExecuteAsync(socket.ReceiveAsync);
                 }

+ 17 - 5
src/Renci.SshNet/Abstractions/ThreadAbstraction.cs

@@ -1,4 +1,6 @@
 using System;
+using System.Threading;
+using System.Threading.Tasks;
 
 namespace Renci.SshNet.Abstractions
 {
@@ -10,18 +12,28 @@ namespace Renci.SshNet.Abstractions
         /// <param name="millisecondsTimeout">The number of milliseconds for which the thread is suspended.</param>
         public static void Sleep(int millisecondsTimeout)
         {
-            System.Threading.Thread.Sleep(millisecondsTimeout);
+            Thread.Sleep(millisecondsTimeout);
         }
 
-        public static void ExecuteThreadLongRunning(Action action)
+        /// <summary>
+        /// Creates and starts a long-running <see cref="Task"/> for the specified <see cref="Action"/>.
+        /// </summary>
+        /// <param name="action">The <see cref="Action"/> to start.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="action"/> is <see langword="null"/>.</exception>
+        /// <returns>
+        /// A task that represents the execution of the specified <see cref="Action"/>.
+        /// </returns>
+        public static Task ExecuteThreadLongRunning(Action action)
         {
             if (action is null)
             {
                 throw new ArgumentNullException(nameof(action));
             }
 
-            var taskCreationOptions = System.Threading.Tasks.TaskCreationOptions.LongRunning;
-            _ = System.Threading.Tasks.Task.Factory.StartNew(action, taskCreationOptions);
+            return Task.Factory.StartNew(action,
+                                         CancellationToken.None,
+                                         TaskCreationOptions.LongRunning,
+                                         TaskScheduler.Current);
         }
 
         /// <summary>
@@ -35,7 +47,7 @@ namespace Renci.SshNet.Abstractions
                 throw new ArgumentNullException(nameof(action));
             }
 
-            _ = System.Threading.ThreadPool.QueueUserWorkItem(o => action());
+            _ = ThreadPool.QueueUserWorkItem(o => action());
         }
     }
 }

+ 2 - 0
src/Renci.SshNet/AuthenticationMethod.cs

@@ -13,7 +13,9 @@ namespace Renci.SshNet
         /// <value>
         /// The name of the authentication method.
         /// </value>
+#pragma warning disable CA2119 // Seal methods that satisfy private interfaces
         public abstract string Name { get; }
+#pragma warning restore CA2119 // Seal methods that satisfy private interfaces
 
         /// <summary>
         /// Gets connection username.

+ 3 - 1
src/Renci.SshNet/AuthenticationResult.cs

@@ -1,7 +1,7 @@
 namespace Renci.SshNet
 {
     /// <summary>
-    /// Represents possible authentication methods results
+    /// Represents possible authentication methods results.
     /// </summary>
     public enum AuthenticationResult
     {
@@ -9,10 +9,12 @@
         /// Authentication was successful.
         /// </summary>
         Success,
+
         /// <summary>
         /// Authentication completed with partial success.
         /// </summary>
         PartialSuccess,
+
         /// <summary>
         /// Authentication failed.
         /// </summary>

+ 11 - 4
src/Renci.SshNet/BaseClient.cs

@@ -12,7 +12,7 @@ namespace Renci.SshNet
     /// <summary>
     /// Serves as base class for client implementations, provides common client functionality.
     /// </summary>
-    public abstract class BaseClient : IBaseClient, IDisposable
+    public abstract class BaseClient : IBaseClient
     {
         /// <summary>
         /// Holds value indicating whether the connection info is owned by this client.
@@ -341,7 +341,9 @@ namespace Renci.SshNet
         /// intervals.
         /// </remarks>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
+#pragma warning disable S1133 // Deprecated code should be removed
         [Obsolete("Use KeepAliveInterval to send a keep-alive message at regular intervals.")]
+#pragma warning restore S1133 // Deprecated code should be removed
         public void SendKeepAlive()
         {
             CheckDisposed();
@@ -393,8 +395,6 @@ namespace Renci.SshNet
         /// </summary>
         public void Dispose()
         {
-            DiagnosticAbstraction.Log("Disposing client.");
-
             Dispose(disposing: true);
             GC.SuppressFinalize(this);
         }
@@ -412,14 +412,17 @@ namespace Renci.SshNet
 
             if (disposing)
             {
+                DiagnosticAbstraction.Log("Disposing client.");
+
                 Disconnect();
 
-                if (_ownsConnectionInfo && _connectionInfo != null)
+                if (_ownsConnectionInfo && _connectionInfo is not null)
                 {
                     if (_connectionInfo is IDisposable connectionInfoDisposable)
                     {
                         connectionInfoDisposable.Dispose();
                     }
+
                     _connectionInfo = null;
                 }
 
@@ -433,10 +436,14 @@ namespace Renci.SshNet
         /// <exception cref="ObjectDisposedException">THe current instance is disposed.</exception>
         protected void CheckDisposed()
         {
+#if NET7_0_OR_GREATER
+            ObjectDisposedException.ThrowIf(_isDisposed, this);
+#else
             if (_isDisposed)
             {
                 throw new ObjectDisposedException(GetType().FullName);
             }
+#endif // NET7_0_OR_GREATER
         }
 
         /// <summary>

+ 7 - 7
src/Renci.SshNet/Channels/Channel.cs

@@ -16,13 +16,14 @@ namespace Renci.SshNet.Channels
     internal abstract class Channel : IChannel
     {
         private readonly object _serverWindowSizeLock = new object();
+        private readonly object _messagingLock = new object();
         private readonly uint _initialWindowSize;
+        private readonly ISession _session;
         private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(initialState: false);
         private EventWaitHandle _channelServerWindowAdjustWaitHandle = new ManualResetEvent(initialState: false);
         private uint? _remoteWindowSize;
         private uint? _remoteChannelNumber;
         private uint? _remotePacketSize;
-        private readonly ISession _session;
         private bool _isDisposed;
 
         /// <summary>
@@ -497,7 +498,7 @@ namespace Renci.SshNet.Channels
                 throw CreateChannelClosedException();
             }
 
-            lock (this)
+            lock (_messagingLock)
             {
                 _session.SendMessage(new ChannelEofMessage(RemoteChannelNumber));
                 _eofMessageSent = true;
@@ -525,7 +526,7 @@ namespace Renci.SshNet.Channels
              * message causing the server to disconnect the session.
              */
 
-            lock (this)
+            lock (_messagingLock)
             {
                 // Send EOF message first the following conditions are met:
                 // * we have not sent a SSH_MSG_CHANNEL_EOF message
@@ -704,7 +705,6 @@ namespace Renci.SshNet.Channels
             {
                 try
                 {
-
                     if (_session.ConnectionInfo.ChannelRequests.TryGetValue(e.Message.RequestName, out var requestInfo))
                     {
                         // Load request specific data
@@ -832,7 +832,7 @@ namespace Renci.SshNet.Channels
                 Close();
 
                 var session = _session;
-                if (session != null)
+                if (session is not null)
                 {
                     session.ChannelWindowAdjustReceived -= OnChannelWindowAdjust;
                     session.ChannelDataReceived -= OnChannelData;
@@ -847,14 +847,14 @@ namespace Renci.SshNet.Channels
                 }
 
                 var channelClosedWaitHandle = _channelClosedWaitHandle;
-                if (channelClosedWaitHandle != null)
+                if (channelClosedWaitHandle is not null)
                 {
                     _channelClosedWaitHandle = null;
                     channelClosedWaitHandle.Dispose();
                 }
 
                 var channelServerWindowAdjustWaitHandle = _channelServerWindowAdjustWaitHandle;
-                if (channelServerWindowAdjustWaitHandle != null)
+                if (channelServerWindowAdjustWaitHandle is not null)
                 {
                     _channelServerWindowAdjustWaitHandle = null;
                     channelServerWindowAdjustWaitHandle.Dispose();

+ 4 - 4
src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs

@@ -17,7 +17,7 @@ namespace Renci.SshNet.Channels
         private IForwardedPort _forwardedPort;
 
         /// <summary>
-        /// Initializes a new <see cref="ChannelForwardedTcpip"/> instance.
+        /// Initializes a new instance of the <see cref="ChannelForwardedTcpip"/> class.
         /// </summary>
         /// <param name="session">The session.</param>
         /// <param name="localChannelNumber">The local channel number.</param>
@@ -69,17 +69,17 @@ namespace Renci.SshNet.Channels
             _forwardedPort = forwardedPort;
             _forwardedPort.Closing += ForwardedPort_Closing;
 
-            //  Try to connect to the socket 
+            // Try to connect to the socket
             try
             {
                 _socket = SocketAbstraction.Connect(remoteEndpoint, ConnectionInfo.Timeout);
 
-                // send channel open confirmation message
+                // Send channel open confirmation message
                 SendMessage(new ChannelOpenConfirmationMessage(RemoteChannelNumber, LocalWindowSize, LocalPacketSize, LocalChannelNumber));
             }
             catch (Exception exp)
             {
-                // send channel open failure message
+                // Send channel open failure message
                 SendMessage(new ChannelOpenFailureMessage(RemoteChannelNumber, exp.ToString(), ChannelOpenFailureMessage.ConnectFailed, "en"));
 
                 throw;

+ 1 - 1
src/Renci.SshNet/Channels/ChannelSession.cs

@@ -394,7 +394,7 @@ namespace Renci.SshNet.Channels
         /// </remarks>
         private void SendChannelOpenMessage()
         {
-            // do not allow open to be ChannelOpenMessage to be sent again until we've
+            // do not allow the ChannelOpenMessage to be sent again until we've
             // had a response on the previous attempt for the current channel
             if (Interlocked.CompareExchange(ref _sessionSemaphoreObtained, 1, 0) == 0)
             {

+ 8 - 6
src/Renci.SshNet/Channels/ChannelTypes.cs

@@ -1,5 +1,4 @@
-
-namespace Renci.SshNet.Channels
+namespace Renci.SshNet.Channels
 {
     /// <summary>
     /// Lists channel types as defined by the protocol.
@@ -7,19 +6,22 @@ namespace Renci.SshNet.Channels
     internal enum ChannelTypes
     {
         /// <summary>
-        /// session
+        /// Session.
         /// </summary>
         Session,
+
         /// <summary>
-        /// x11
+        /// X11.
         /// </summary>
         X11,
+
         /// <summary>
-        /// forwarded-tcpip
+        /// Forwarded-tcpip.
         /// </summary>
         ForwardedTcpip,
+
         /// <summary>
-        /// direct-tcpip
+        /// Direct-tcpip.
         /// </summary>
         DirectTcpip
     }

+ 1 - 1
src/Renci.SshNet/Channels/ClientChannel.cs

@@ -49,7 +49,7 @@ namespace Renci.SshNet.Channels
         /// <summary>
         /// Send message to open a channel.
         /// </summary>
-        /// <param name="message">Message to send</param>
+        /// <param name="message">Message to send.</param>
         /// <exception cref="SshConnectionException">The client is not connected.</exception>
         /// <exception cref="SshOperationTimeoutException">The operation timed out.</exception>
         /// <exception cref="InvalidOperationException">The size of the packet exceeds the maximum size defined by the protocol.</exception>

+ 6 - 2
src/Renci.SshNet/Channels/IChannelSession.cs

@@ -25,8 +25,12 @@ namespace Renci.SshNet.Channels
         /// <returns>
         /// <see langword="true"/> if request was successful; otherwise <see langword="false"/>.
         /// </returns>
-        bool SendPseudoTerminalRequest(string environmentVariable, uint columns, uint rows, uint width, uint height,
-            IDictionary<TerminalModes, uint> terminalModeValues);
+        bool SendPseudoTerminalRequest(string environmentVariable,
+                                       uint columns,
+                                       uint rows,
+                                       uint width,
+                                       uint height,
+                                       IDictionary<TerminalModes, uint> terminalModeValues);
 
         /// <summary>
         /// Sends the X11 forwarding request.

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

@@ -5,7 +5,7 @@ using Renci.SshNet.Security.Cryptography;
 namespace Renci.SshNet
 {
     /// <summary>
-    /// Holds information about key size and cipher to use
+    /// Holds information about key size and cipher to use.
     /// </summary>
     public class CipherInfo
     {

+ 20 - 6
src/Renci.SshNet/ClientAuthentication.cs

@@ -1,9 +1,14 @@
 using System;
 using System.Collections.Generic;
+using System.Globalization;
+
 using Renci.SshNet.Common;
 
 namespace Renci.SshNet
 {
+    /// <summary>
+    /// Represents a mechanism to authenticate a given client.
+    /// </summary>
     internal sealed class ClientAuthentication : IClientAuthentication
     {
         private readonly int _partialSuccessLimit;
@@ -37,11 +42,14 @@ namespace Renci.SshNet
         }
 
         /// <summary>
-        /// Attempts to authentication for a given <see cref="ISession"/> using the <see cref="IConnectionInfoInternal.AuthenticationMethods"/>
-        /// of the specified <see cref="IConnectionInfoInternal"/>.
+        /// Attempts to perform authentication for a given <see cref="ISession"/> using the
+        /// <see cref="IConnectionInfoInternal.AuthenticationMethods"/> of the specified
+        /// <see cref="IConnectionInfoInternal"/>.
         /// </summary>
         /// <param name="connectionInfo">A <see cref="IConnectionInfoInternal"/> to use for authenticating.</param>
         /// <param name="session">The <see cref="ISession"/> for which to perform authentication.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="connectionInfo"/> or <paramref name="session"/> is <see langword="null"/>.</exception>
+        /// <exception cref="SshAuthenticationException">Failed to authenticate the client.</exception>
         public void Authenticate(IConnectionInfoInternal connectionInfo, ISession session)
         {
             if (connectionInfo is null)
@@ -102,8 +110,14 @@ namespace Renci.SshNet
             var matchingAuthenticationMethods = authenticationState.GetSupportedAuthenticationMethods(allowedAuthenticationMethods);
             if (matchingAuthenticationMethods.Count == 0)
             {
-                authenticationException = new SshAuthenticationException(string.Format("No suitable authentication method found to complete authentication ({0}).",
-                                                                                       string.Join(",", allowedAuthenticationMethods)));
+                authenticationException = new SshAuthenticationException(string.Format(CultureInfo.InvariantCulture,
+                                                                                       "No suitable authentication method found to complete authentication ({0}).",
+#if NET || NETSTANDARD2_1_OR_GREATER
+                                                                                       string.Join(',', allowedAuthenticationMethods)))
+#else
+                                                                                       string.Join(",", allowedAuthenticationMethods)))
+#endif // NET || NETSTANDARD2_1_OR_GREATER
+                ;
                 return false;
             }
 
@@ -113,7 +127,7 @@ namespace Renci.SshNet
                 // methods after a partial success
                 if (authenticationState.GetPartialSuccessCount(authenticationMethod) >= _partialSuccessLimit)
                 {
-                    // TODO Get list of all authentication methods that have reached the partial success limit?
+                    /* TODO Get list of all authentication methods that have reached the partial success limit? */
 
                     authenticationException = new SshAuthenticationException(string.Format("Reached authentication attempt limit for method ({0}).",
                                                                                            authenticationMethod.Name));
@@ -195,7 +209,7 @@ namespace Renci.SshNet
             {
                 if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out var partialSuccessCount))
                 {
-                    _authenticationMethodPartialSuccessRegister[authenticationMethod] = ++partialSuccessCount;
+                    _authenticationMethodPartialSuccessRegister[authenticationMethod] = partialSuccessCount + 1;
                 }
                 else
                 {

+ 0 - 46
src/Renci.SshNet/Common/AsyncResult.cs

@@ -155,50 +155,4 @@ namespace Renci.SshNet.Common
             get { return _completedState != StatePending; }
         }
     }
-
-    /// <summary>
-    /// Base class to encapsulates the results of an asynchronous operation that returns result.
-    /// </summary>
-    /// <typeparam name="TResult">The type of the result.</typeparam>
-    public abstract class AsyncResult<TResult> : AsyncResult
-    {
-        // Field set when operation completes
-        private TResult _result;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="AsyncResult{TResult}"/> class.
-        /// </summary>
-        /// <param name="asyncCallback">The async callback.</param>
-        /// <param name="state">The state.</param>
-        protected AsyncResult(AsyncCallback asyncCallback, object state)
-            : base(asyncCallback, state)
-        {
-        }
-
-        /// <summary>
-        /// Marks asynchronous operation as completed.
-        /// </summary>
-        /// <param name="result">The result.</param>
-        /// <param name="completedSynchronously">if set to <see langword="true"/> [completed synchronously].</param>
-        public void SetAsCompleted(TResult result, bool completedSynchronously)
-        {
-            // Save the asynchronous operation's result
-            _result = result;
-
-            // Tell the base class that the operation completed successfully (no exception)
-            SetAsCompleted(exception: null, completedSynchronously);
-        }
-
-        /// <summary>
-        /// Waits until the asynchronous operation completes, and then returns the value generated by the asynchronous operation. 
-        /// </summary>
-        /// <returns>
-        /// The invocation result.
-        /// </returns>
-        public new TResult EndInvoke()
-        {
-            base.EndInvoke(); // Wait until operation has completed
-            return _result;  // Return the result (if above didn't throw)
-        }
-    }
 }

+ 50 - 0
src/Renci.SshNet/Common/AsyncResult{TResult}.cs

@@ -0,0 +1,50 @@
+using System;
+
+namespace Renci.SshNet.Common
+{
+    /// <summary>
+    /// Base class to encapsulates the results of an asynchronous operation that returns result.
+    /// </summary>
+    /// <typeparam name="TResult">The type of the result.</typeparam>
+    public abstract class AsyncResult<TResult> : AsyncResult
+    {
+        // Field set when operation completes
+        private TResult _result;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AsyncResult{TResult}"/> class.
+        /// </summary>
+        /// <param name="asyncCallback">The async callback.</param>
+        /// <param name="state">The state.</param>
+        protected AsyncResult(AsyncCallback asyncCallback, object state)
+            : base(asyncCallback, state)
+        {
+        }
+
+        /// <summary>
+        /// Marks asynchronous operation as completed.
+        /// </summary>
+        /// <param name="result">The result.</param>
+        /// <param name="completedSynchronously">if set to <see langword="true"/> [completed synchronously].</param>
+        public void SetAsCompleted(TResult result, bool completedSynchronously)
+        {
+            // Save the asynchronous operation's result
+            _result = result;
+
+            // Tell the base class that the operation completed successfully (no exception)
+            SetAsCompleted(exception: null, completedSynchronously);
+        }
+
+        /// <summary>
+        /// Waits until the asynchronous operation completes, and then returns the value generated by the asynchronous operation.
+        /// </summary>
+        /// <returns>
+        /// The invocation result.
+        /// </returns>
+        public new TResult EndInvoke()
+        {
+            base.EndInvoke(); // Wait until operation has completed
+            return _result;  // Return the result (if above didn't throw)
+        }
+    }
+}

+ 134 - 41
src/Renci.SshNet/Common/BigInteger.cs

@@ -1,4 +1,6 @@
-//
+#pragma warning disable SA1028 // Code should not contain trailing whitespace
+#pragma warning disable SA1515 // Single-line comment should be preceded by blank line
+//
 // System.Numerics.BigInteger
 //
 // Authors:
@@ -44,6 +46,8 @@
 *
 *
 * ***************************************************************************/
+#pragma warning restore SA1515 // Single-line comment should be preceded by blank line
+#pragma warning restore SA1028 // Code should not contain trailing whitespace
 
 using System;
 using System.Collections.Generic;
@@ -106,7 +110,7 @@ namespace Renci.SshNet.Common
 
                 var msbBitCount = BitScanBackward(_data[msbIndex]) + 1;
 
-                return msbIndex * 4 * 8 + msbBitCount + ((_sign > 0) ? 0 : 1);
+                return (msbIndex * 4 * 8) + msbBitCount + ((_sign > 0) ? 0 : 1);
             }
         }
 
@@ -145,8 +149,8 @@ namespace Renci.SshNet.Common
 
                 p1 += (b / a) * p0;
                 b %= a;
-
             }
+
             return 0;
         }
 
@@ -210,7 +214,9 @@ namespace Renci.SshNet.Common
             else
             {
                 _sign = -1;
+#pragma warning disable SA1021 // Negative signs should be spaced correctly
                 _data = new[] { (uint) -value };
+#pragma warning restore SA1021 // Negative signs should be spaced correctly
             }
         }
 
@@ -419,7 +425,9 @@ namespace Renci.SshNet.Common
                 _sign = 1;
             }
 
+#pragma warning disable CA1508 // Avoid dead conditional code | this is the following bug in the analyzer rule: https://github.com/dotnet/roslyn-analyzers/issues/6991
             if (_sign == 1)
+#pragma warning restore CA1508 // Avoid dead conditional code
             {
                 while (value[len - 1] == 0)
                 {
@@ -514,8 +522,9 @@ namespace Renci.SshNet.Common
 
                 if (borrow != 0)
                 {
-                    // FIXME I believe this can't happen, can someone write a test for it?
+#pragma warning disable CA2201 // Do not raise reserved exception types
                     throw new Exception("non zero final carry");
+#pragma warning restore CA2201 // Do not raise reserved exception types
                 }
             }
         }
@@ -535,14 +544,14 @@ namespace Renci.SshNet.Common
             var i1 = (uint)v[0] | ((uint)v[1] << 8) | ((uint)v[2] << 16) | ((uint)v[3] << 24);
             var i2 = (uint)v[4] | ((uint)v[5] << 8) | ((uint)(v[6] & 0xF) << 16);
 
-            return ((ulong) i1 | ((ulong) i2 << 32));
+            return (ulong) i1 | ((ulong) i2 << 32);
         }
 
         /// <summary>
         /// Gets a value indicating whether the value of the current <see cref="BigInteger"/> object is an even number.
         /// </summary>
         /// <value>
-        /// <see langword="true"/> if the value of the BigInteger object is an even number; otherwise, <see langword="false"/>.
+        /// <see langword="true"/> if the value of the <see cref="BigInteger"/> object is an even number; otherwise, <see langword="false"/>.
         /// </value>
         public readonly bool IsEven
         {
@@ -768,7 +777,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator int(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (value._data is null)
             {
@@ -813,7 +824,9 @@ namespace Renci.SshNet.Common
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
         [CLSCompliant(false)]
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator uint(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (value._data is null)
             {
@@ -835,7 +848,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator short(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             var val = (int) value;
             if (val is < short.MinValue or > short.MaxValue)
@@ -854,7 +869,9 @@ namespace Renci.SshNet.Common
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
         [CLSCompliant(false)]
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator ushort(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             var val = (uint) value;
             if (val > ushort.MaxValue)
@@ -872,7 +889,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator byte(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             var val = (uint) value;
             if (val > byte.MaxValue)
@@ -891,7 +910,9 @@ namespace Renci.SshNet.Common
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
         [CLSCompliant(false)]
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator sbyte(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             var val = (int) value;
             if (val is < sbyte.MinValue or > sbyte.MaxValue)
@@ -909,7 +930,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator long(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (value._data is null)
             {
@@ -973,7 +996,9 @@ namespace Renci.SshNet.Common
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
         [CLSCompliant(false)]
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator ulong(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (value._data is null)
             {
@@ -1002,7 +1027,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator double(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (value._data is null)
             {
@@ -1041,7 +1068,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator float(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return (float) (double) value;
         }
@@ -1053,7 +1082,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator decimal(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (value._data is null)
             {
@@ -1092,7 +1123,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static implicit operator BigInteger(int value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1105,7 +1138,9 @@ namespace Renci.SshNet.Common
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
         [CLSCompliant(false)]
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static implicit operator BigInteger(uint value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1117,7 +1152,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static implicit operator BigInteger(short value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1130,7 +1167,9 @@ namespace Renci.SshNet.Common
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
         [CLSCompliant(false)]
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static implicit operator BigInteger(ushort value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1142,20 +1181,24 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static implicit operator BigInteger(byte value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
 
         /// <summary>
-        /// 
+        /// Defines an implicit conversion of a signed byte to a <see cref="BigInteger"/> value.
         /// </summary>
         /// <param name="value">The value to convert to a <see cref="BigInteger"/>.</param>
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
         [CLSCompliant(false)]
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static implicit operator BigInteger(sbyte value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1167,7 +1210,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static implicit operator BigInteger(long value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1180,7 +1225,9 @@ namespace Renci.SshNet.Common
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
         [CLSCompliant(false)]
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static implicit operator BigInteger(ulong value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1192,7 +1239,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator BigInteger(double value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1204,7 +1253,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator BigInteger(float value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1216,7 +1267,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// An object that contains the value of the <paramref name="value"/> parameter.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static explicit operator BigInteger(decimal value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return new BigInteger(value);
         }
@@ -1255,7 +1308,7 @@ namespace Renci.SshNet.Common
 
             if (r > 0)
             {
-                //left > right
+                // left > right
                 return new BigInteger(left._sign, CoreSub(left._data, right._data));
             }
 
@@ -1279,7 +1332,9 @@ namespace Renci.SshNet.Common
 
             if (left._sign == 0)
             {
+#pragma warning disable SA1021 // Negative signs should be spaced correctly
                 return new BigInteger((short) -right._sign, right._data);
+#pragma warning restore SA1021 // Negative signs should be spaced correctly
             }
 
             if (left._sign == right._sign)
@@ -1351,7 +1406,7 @@ namespace Renci.SshNet.Common
                 ulong carry = 0;
                 for (var j = 0; j < b.Length; ++j)
                 {
-                    carry = carry + ((ulong) ai) * b[j] + res[k];
+                    carry = carry + (((ulong) ai) * b[j]) + res[k];
                     res[k++] = (uint)carry;
                     carry >>= 32;
                 }
@@ -1475,7 +1530,9 @@ namespace Renci.SshNet.Common
                 return value;
             }
 
+#pragma warning disable SA1021 // Negative signs should be spaced correctly
             return new BigInteger((short) -value._sign, value._data);
+#pragma warning restore SA1021 // Negative signs should be spaced correctly
         }
 
         /// <summary>
@@ -1488,7 +1545,9 @@ namespace Renci.SshNet.Common
         /// <remarks>
         /// The sign of the operand is unchanged.
         /// </remarks>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static BigInteger operator +(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             return value;
         }
@@ -1500,7 +1559,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The value of the <paramref name="value"/> parameter incremented by 1.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static BigInteger operator ++(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (value._data is null)
             {
@@ -1534,7 +1595,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The value of the <paramref name="value"/> parameter decremented by 1.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static BigInteger operator --(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (value._data is null)
             {
@@ -1569,7 +1632,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The result of the bitwise <c>And</c> operation.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static BigInteger operator &(BigInteger left, BigInteger right)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (left._sign == 0)
             {
@@ -1659,7 +1724,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The result of the bitwise <c>Or</c> operation.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static BigInteger operator |(BigInteger left, BigInteger right)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (left._sign == 0)
             {
@@ -1749,7 +1816,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The result of the bitwise <c>Or</c> operation.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static BigInteger operator ^(BigInteger left, BigInteger right)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (left._sign == 0)
             {
@@ -1838,7 +1907,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The bitwise one's complement of <paramref name="value"/>.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static BigInteger operator ~(BigInteger value)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (value._data is null)
             {
@@ -1895,9 +1966,14 @@ namespace Renci.SshNet.Common
             return new BigInteger(negRes ? (short)-1 : (short)1, result);
         }
 
-        //returns the 0-based index of the most significant set bit
-        //returns 0 if no bit is set, so extra care when using it
-        static int BitScanBackward(uint word)
+        /// <summary>
+        /// Returns the zero-based index of the most significant set bit.
+        /// </summary>
+        /// <param name="word">The value to scan.</param>
+        /// <returns>
+        /// The zero-based index of the most significant set bit, or zero if no bit is set.
+        /// </returns>
+        private static int BitScanBackward(uint word)
         {
             for (var i = 31; i >= 0; --i)
             {
@@ -1919,7 +1995,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// A value that has been shifted to the left by the specified number of bits.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static BigInteger operator <<(BigInteger value, int shift)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (shift == 0 || value._data is null)
             {
@@ -1976,7 +2054,9 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// A value that has been shifted to the right by the specified number of bits.
         /// </returns>
+#pragma warning disable CA2225 // Operator overloads have named alternates
         public static BigInteger operator >>(BigInteger value, int shift)
+#pragma warning restore CA2225 // Operator overloads have named alternates
         {
             if (shift == 0 || value._sign == 0)
             {
@@ -2092,7 +2172,6 @@ namespace Renci.SshNet.Common
             return left.CompareTo(right) < 0;
         }
 
-
         /// <summary>
         /// Returns a value that indicates whether a 64-bit signed integer is less than a <see cref="BigInteger"/> value.
         /// </summary>
@@ -2672,7 +2751,11 @@ namespace Renci.SshNet.Common
                         return additional + baseStr;
                     }
 
+#if NET
+                    return string.Concat("-", additional, baseStr.AsSpan(1));
+#else
                     return "-" + additional + baseStr.Substring(1);
+#endif // NET
                 }
 
                 return baseStr;
@@ -2689,9 +2772,9 @@ namespace Renci.SshNet.Common
             for (var i = 0; i < v.Length; ++i)
             {
                 var word = v[i];
-                carry = (ulong)~word + carry;
-                word = (uint)carry;
-                carry = (uint)(carry >> 32);
+                carry = (ulong) ~word + carry;
+                word = (uint) carry;
+                carry = (uint) (carry >> 32);
                 res[i] = word;
             }
 
@@ -2713,7 +2796,7 @@ namespace Renci.SshNet.Common
 
             if (characterSet.Length < radix)
             {
-                throw new ArgumentException("charSet length less than radix", "characterSet");
+                throw new ArgumentException("charSet length less than radix", nameof(radix));
             }
 
             if (radix == 1)
@@ -2731,7 +2814,7 @@ namespace Renci.SshNet.Common
                 return _sign == 1 ? "1" : "-1";
             }
 
-            var digits = new List<char>(1 + _data.Length * 3 / 10);
+            var digits = new List<char>(1 + ((_data.Length * 3) / 10));
 
             BigInteger a;
             if (_sign == 1)
@@ -2910,7 +2993,9 @@ namespace Renci.SshNet.Common
             return true;
         }
 
+#pragma warning disable S4136 // Method overloads should be grouped together
         private static bool Parse(string value, NumberStyles style, IFormatProvider fp, bool tryParse, out BigInteger result, out Exception exc)
+#pragma warning restore S4136 // Method overloads should be grouped together
         {
             result = Zero;
             exc = null;
@@ -2949,16 +3034,16 @@ namespace Renci.SshNet.Common
                 return false;
             }
 
-            var allowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
-            var allowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
-            var allowThousands = (style & NumberStyles.AllowThousands) != 0;
-            var allowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
-            var allowParentheses = (style & NumberStyles.AllowParentheses) != 0;
-            var allowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
-            var allowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
-            var allowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
-            var allowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
-            var allowExponent = (style & NumberStyles.AllowExponent) != 0;
+            var allowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) == NumberStyles.AllowCurrencySymbol;
+            var allowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier;
+            var allowThousands = (style & NumberStyles.AllowThousands) == NumberStyles.AllowThousands;
+            var allowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) == NumberStyles.AllowDecimalPoint;
+            var allowParentheses = (style & NumberStyles.AllowParentheses) == NumberStyles.AllowParentheses;
+            var allowTrailingSign = (style & NumberStyles.AllowTrailingSign) == NumberStyles.AllowTrailingSign;
+            var allowLeadingSign = (style & NumberStyles.AllowLeadingSign) == NumberStyles.AllowLeadingSign;
+            var allowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) == NumberStyles.AllowTrailingWhite;
+            var allowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) == NumberStyles.AllowLeadingWhite;
+            var allowExponent = (style & NumberStyles.AllowExponent) == NumberStyles.AllowExponent;
 
             var pos = 0;
 
@@ -3223,7 +3308,11 @@ namespace Renci.SshNet.Common
                 {
                     if (!tryParse)
                     {
-                        exc = new OverflowException("Value too large or too small. exp=" + exponent + " rem = " + remainder + " pow = " + Pow(10, -exponent));
+                        exc = new OverflowException(string.Format(CultureInfo.InvariantCulture,
+                                                                  "Value too large or too small. exp= {0} rem = {1} pow = {2}",
+                                                                  exponent,
+                                                                  remainder,
+                                                                  Pow(10, -exponent)));
                     }
 
                     return false;
@@ -3252,20 +3341,20 @@ namespace Renci.SshNet.Common
 
         private static bool CheckStyle(NumberStyles style, bool tryParse, ref Exception exc)
         {
-            if ((style & NumberStyles.AllowHexSpecifier) != 0)
+            if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
             {
                 var ne = style ^ NumberStyles.AllowHexSpecifier;
-                if ((ne & NumberStyles.AllowLeadingWhite) != 0)
+                if ((ne & NumberStyles.AllowLeadingWhite) == NumberStyles.AllowLeadingWhite)
                 {
                     ne ^= NumberStyles.AllowLeadingWhite;
                 }
 
-                if ((ne & NumberStyles.AllowTrailingWhite) != 0)
+                if ((ne & NumberStyles.AllowTrailingWhite) == NumberStyles.AllowTrailingWhite)
                 {
                     ne ^= NumberStyles.AllowTrailingWhite;
                 }
 
-                if (ne != 0)
+                if (ne != NumberStyles.None)
                 {
                     if (!tryParse)
                     {
@@ -3424,7 +3513,7 @@ namespace Renci.SshNet.Common
             return char.IsDigit(e);
         }
 
-        private static Exception GetFormatException()
+        private static FormatException GetFormatException()
         {
             return new FormatException("Input string was not in the correct format");
         }
@@ -3545,7 +3634,9 @@ namespace Renci.SshNet.Common
             {
                 result = val;
             }
+#pragma warning disable CA1508 // Avoid dead conditional code | this is the following bug in the analyzer rule: https://github.com/dotnet/roslyn-analyzers/issues/6991
             else if (sign == -1)
+#pragma warning restore CA1508 // Avoid dead conditional code
             {
                 result = new BigInteger(-1, val._data);
             }
@@ -3836,7 +3927,6 @@ namespace Renci.SshNet.Common
                 g = x;
                 x = y % x;
                 y = g;
-
             }
 
             if (x.IsZero)
@@ -3926,7 +4016,7 @@ namespace Renci.SshNet.Common
             {
                 if ((value._data[length] & (1 << curBit)) != 0)
                 {
-                    bitCount = curBit + length * 32;
+                    bitCount = curBit + (length * 32);
                     break;
                 }
             }
@@ -4472,7 +4562,7 @@ namespace Renci.SshNet.Common
                 if (carry == 0)
                 {
                     var ex = FirstNonFfByte(word);
-                    var needExtra = (word & (1 << (ex * 8 - 1))) == 0;
+                    var needExtra = (word & (1 << ((ex * 8) - 1))) == 0;
                     var to = ex + (needExtra ? 1 : 0);
 
                     if (to != extra)
@@ -4488,7 +4578,9 @@ namespace Renci.SshNet.Common
 
                     if (needExtra)
                     {
+#pragma warning disable S1854 // Unused assignments should be removed
                         res[j++] = 0xFF;
+#pragma warning restore S1854 // Unused assignments should be removed
                     }
                 }
                 else
@@ -4498,7 +4590,9 @@ namespace Renci.SshNet.Common
                     res[j++] = (byte)(word >> 8);
                     res[j++] = (byte)(word >> 16);
                     res[j++] = (byte)(word >> 24);
+#pragma warning disable S1854 // Unused assignments should be removed
                     res[j++] = 0xFF;
+#pragma warning restore S1854 // Unused assignments should be removed
                 }
             }
 
@@ -4807,14 +4901,14 @@ namespace Renci.SshNet.Common
                 {
                     int i;
 
-                    var rr = Base * un[j + n] + un[j + n - 1];
+                    var rr = (Base * un[j + n]) + un[j + n - 1];
                     var qq = rr / vn[n - 1];
                     rr -= qq * vn[n - 1];
 
-                    for (;;)
+                    for (; ; )
                     {
                         // Estimate too big ?
-                        if ((qq >= Base) || (qq * vn[n - 2] > (rr * Base + un[j + n - 2])))
+                        if ((qq >= Base) || (qq * vn[n - 2] > ((rr * Base) + un[j + n - 2])))
                         {
                             qq--;
                             rr += (ulong)vn[n - 1];
@@ -4827,7 +4921,6 @@ namespace Renci.SshNet.Common
                         break;
                     }
 
-
                     // Multiply and subtract
                     long b = 0;
                     long t;

+ 9 - 1
src/Renci.SshNet/Common/ChannelDataEventArgs.cs

@@ -1,4 +1,6 @@
-namespace Renci.SshNet.Common
+using System;
+
+namespace Renci.SshNet.Common
 {
     /// <summary>
     /// Provides data for <see cref="Channels.Channel.DataReceived"/> event.
@@ -10,9 +12,15 @@
         /// </summary>
         /// <param name="channelNumber">Channel number.</param>
         /// <param name="data">Channel data.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="data"/> is <see langword="null"/>.</exception>
         public ChannelDataEventArgs(uint channelNumber, byte[] data)
             : base(channelNumber)
         {
+            if (data is null)
+            {
+                throw new ArgumentNullException(nameof(data));
+            }
+
             Data = data;
         }
 

+ 6 - 0
src/Renci.SshNet/Common/ChannelRequestEventArgs.cs

@@ -13,8 +13,14 @@ namespace Renci.SshNet.Common
         /// Initializes a new instance of the <see cref="ChannelRequestEventArgs"/> class.
         /// </summary>
         /// <param name="info">Request information.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="info"/> is <see langword="null"/>.</exception>
         public ChannelRequestEventArgs(RequestInfo info)
         {
+            if (info is null)
+            {
+                throw new ArgumentNullException(nameof(info));
+            }
+
             Info = info;
         }
 

+ 1 - 1
src/Renci.SshNet/Common/DerData.cs

@@ -48,7 +48,7 @@ namespace Renci.SshNet.Common
         /// Initializes a new instance of the <see cref="DerData"/> class.
         /// </summary>
         /// <param name="data">DER encoded data.</param>
-        /// <param name="construct">its a construct</param>
+        /// <param name="construct">its a construct.</param>
         public DerData(byte[] data, bool construct = false)
         {
             _data = new List<byte>(data);

+ 2 - 1
src/Renci.SshNet/Common/Extensions.cs

@@ -50,7 +50,7 @@ namespace Renci.SshNet.Common
         }
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="BigInteger"/> structure using the SSH BigNum2 Format
+        /// Initializes a new instance of the <see cref="BigInteger"/> structure using the SSH BigNum2 Format.
         /// </summary>
         public static BigInteger ToBigInteger2(this byte[] data)
         {
@@ -60,6 +60,7 @@ namespace Renci.SshNet.Common
                 Buffer.BlockCopy(data, 0, buf, 1, data.Length);
                 data = buf;
             }
+
             return data.ToBigInteger();
         }
 

+ 30 - 14
src/Renci.SshNet/Common/HostKeyEventArgs.cs

@@ -30,7 +30,7 @@ namespace Renci.SshNet.Common
         /// <summary>
         /// Gets the host key name.
         /// </summary>
-        public string HostKeyName{ get; private set; }
+        public string HostKeyName { get; private set; }
 
         /// <summary>
         /// Gets the MD5 fingerprint.
@@ -50,7 +50,7 @@ namespace Renci.SshNet.Common
         /// Gets the SHA256 fingerprint of the host key in the same format as the ssh command,
         /// i.e. non-padded base64, but without the <c>SHA256:</c> prefix.
         /// </summary>
-        /// <example><c>ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og</c></example>
+        /// <example><c>ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og</c>.</example>
         /// <value>
         /// Base64 encoded SHA256 fingerprint with padding (equals sign) removed.
         /// </value>
@@ -66,7 +66,7 @@ namespace Renci.SshNet.Common
         /// Gets the MD5 fingerprint of the host key in the same format as the ssh command,
         /// i.e. hexadecimal bytes separated by colons, but without the <c>MD5:</c> prefix.
         /// </summary>
-        /// <example><c>97:70:33:82:fd:29:3a:73:39:af:6a:07:ad:f8:80:49</c></example>
+        /// <example><c>97:70:33:82:fd:29:3a:73:39:af:6a:07:ad:f8:80:49</c>.</example>
         public string FingerPrintMD5
         {
             get
@@ -87,27 +87,43 @@ namespace Renci.SshNet.Common
         /// Initializes a new instance of the <see cref="HostKeyEventArgs"/> class.
         /// </summary>
         /// <param name="host">The host.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="host"/> is <see langword="null"/>.</exception>
         public HostKeyEventArgs(KeyHostAlgorithm host)
         {
+            if (host is null)
+            {
+                throw new ArgumentNullException(nameof(host));
+            }
+
             CanTrust = true;
             HostKey = host.Data;
             HostKeyName = host.Name;
             KeyLength = host.Key.KeyLength;
-            
+
             _lazyFingerPrint = new Lazy<byte[]>(() =>
-            {
-                using var md5 = CryptoAbstraction.CreateMD5();
-                return md5.ComputeHash(HostKey);
-            });
+                {
+                    using var md5 = CryptoAbstraction.CreateMD5();
+                    return md5.ComputeHash(HostKey);
+                });
 
             _lazyFingerPrintSHA256 = new Lazy<string>(() =>
-            {
-                using var sha256 = CryptoAbstraction.CreateSHA256();
-                return Convert.ToBase64String(sha256.ComputeHash(HostKey)).Replace("=", "");
-            });
+                {
+                    using var sha256 = CryptoAbstraction.CreateSHA256();
+
+                    return Convert.ToBase64String(sha256.ComputeHash(HostKey))
+#if NET || NETSTANDARD2_1_OR_GREATER
+                                  .Replace("=", string.Empty, StringComparison.Ordinal);
+#else
+                                  .Replace("=", string.Empty);
+#endif // NET || NETSTANDARD2_1_OR_GREATER
+                });
 
-            _lazyFingerPrintMD5 = new Lazy<string>(() => 
-                BitConverter.ToString(FingerPrint).Replace("-", ":").ToLowerInvariant());
+            _lazyFingerPrintMD5 = new Lazy<string>(() =>
+                {
+#pragma warning disable CA1308 // Normalize strings to uppercase
+                    return BitConverter.ToString(FingerPrint).Replace('-', ':').ToLowerInvariant();
+#pragma warning restore CA1308 // Normalize strings to uppercase
+                });
         }
     }
 }

+ 1 - 1
src/Renci.SshNet/Common/NetConfServerException.cs

@@ -41,7 +41,7 @@ namespace Renci.SshNet.Common
 
 #if FEATURE_BINARY_SERIALIZATION
         /// <summary>
-        /// Initializes a new instance of the <see cref="SshAuthenticationException"/> class.
+        /// Initializes a new instance of the <see cref="NetConfServerException"/> class.
         /// </summary>
         /// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
         /// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>

+ 2 - 0
src/Renci.SshNet/Common/ObjectIdentifier.cs

@@ -7,7 +7,9 @@ namespace Renci.SshNet.Common
     /// <summary>
     /// Describes object identifier for DER encoding.
     /// </summary>
+#pragma warning disable CA1815 // Override equals and operator equals on value types
     public struct ObjectIdentifier
+#pragma warning restore CA1815 // Override equals and operator equals on value types
     {
         /// <summary>
         /// Gets the object identifier.

+ 30 - 15
src/Renci.SshNet/Common/PipeStream.cs

@@ -10,8 +10,6 @@ namespace Renci.SshNet.Common
     /// PipeStream is a thread-safe read/write data stream for use between two threads in a
     /// single-producer/single-consumer type problem.
     /// </summary>
-    /// <version>2006/10/13 1.0</version>
-    /// <remarks>Update on 2008/10/9 1.1 - uses Monitor instead of Manual Reset events for more elegant synchronicity.</remarks>
     /// <license>
     /// Copyright (c) 2006 James Kolpack (james dot kolpack at google mail)
     ///
@@ -46,11 +44,6 @@ namespace Renci.SshNet.Common
         /// </summary>
         private bool _isFlushed;
 
-        /// <summary>
-        /// Maximum number of bytes to store in the buffer.
-        /// </summary>
-        private long _maxBufferLength = 200 * 1024 * 1024;
-
         /// <summary>
         /// Setting this to true will cause Read() to block if it appears
         /// that it will run out of data.
@@ -66,11 +59,7 @@ namespace Renci.SshNet.Common
         /// Gets or sets the maximum number of bytes to store in the buffer.
         /// </summary>
         /// <value>The length of the max buffer.</value>
-        public long MaxBufferLength
-        {
-            get { return _maxBufferLength; }
-            set { _maxBufferLength = value; }
-        }
+        public long MaxBufferLength { get; set; } = 200 * 1024 * 1024;
 
         /// <summary>
         /// Gets or sets a value indicating whether to block last read method before the buffer is empty.
@@ -88,19 +77,27 @@ namespace Renci.SshNet.Common
         {
             get
             {
+#if NET7_0_OR_GREATER
+                ObjectDisposedException.ThrowIf(_isDisposed, this);
+#else
                 if (_isDisposed)
                 {
                     throw CreateObjectDisposedException();
                 }
+#endif // NET7_0_OR_GREATER
 
                 return _canBlockLastRead;
             }
             set
             {
+#if NET7_0_OR_GREATER
+                ObjectDisposedException.ThrowIf(_isDisposed, this);
+#else
                 if (_isDisposed)
                 {
                     throw CreateObjectDisposedException();
                 }
+#endif // NET7_0_OR_GREATER
 
                 _canBlockLastRead = value;
 
@@ -126,10 +123,14 @@ namespace Renci.SshNet.Common
         /// </remarks>
         public override void Flush()
         {
+#if NET7_0_OR_GREATER
+            ObjectDisposedException.ThrowIf(_isDisposed, this);
+#else
             if (_isDisposed)
             {
                 throw CreateObjectDisposedException();
             }
+#endif // NET7_0_OR_GREATER
 
             _isFlushed = true;
             lock (_buffer)
@@ -200,15 +201,19 @@ namespace Renci.SshNet.Common
                 throw new ArgumentOutOfRangeException(nameof(offset), "offset or count is negative.");
             }
 
-            if (BlockLastReadBuffer && count >= _maxBufferLength)
+            if (BlockLastReadBuffer && count >= MaxBufferLength)
             {
-                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "count({0}) > mMaxBufferLength({1})", count, _maxBufferLength));
+                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "count({0}) > mMaxBufferLength({1})", count, MaxBufferLength));
             }
 
+#if NET7_0_OR_GREATER
+            ObjectDisposedException.ThrowIf(_isDisposed, this);
+#else
             if (_isDisposed)
             {
                 throw CreateObjectDisposedException();
             }
+#endif // NET7_0_OR_GREATER
 
             if (count == 0)
             {
@@ -284,10 +289,14 @@ namespace Renci.SshNet.Common
                 throw new ArgumentOutOfRangeException(nameof(offset), "offset or count is negative.");
             }
 
+#if NET7_0_OR_GREATER
+            ObjectDisposedException.ThrowIf(_isDisposed, this);
+#else
             if (_isDisposed)
             {
                 throw CreateObjectDisposedException();
             }
+#endif // NET7_0_OR_GREATER
 
             if (count == 0)
             {
@@ -297,7 +306,7 @@ namespace Renci.SshNet.Common
             lock (_buffer)
             {
                 // wait until the buffer isn't full
-                while (Length >= _maxBufferLength)
+                while (Length >= MaxBufferLength)
                 {
                     _ = Monitor.Wait(_buffer);
                 }
@@ -380,10 +389,14 @@ namespace Renci.SshNet.Common
         {
             get
             {
+#if NET7_0_OR_GREATER
+                ObjectDisposedException.ThrowIf(_isDisposed, this);
+#else
                 if (_isDisposed)
                 {
                     throw CreateObjectDisposedException();
                 }
+#endif // NET7_0_OR_GREATER
 
                 return _buffer.Count;
             }
@@ -402,9 +415,11 @@ namespace Renci.SshNet.Common
             set { throw new NotSupportedException(); }
         }
 
+#if !NET7_0_OR_GREATER
         private ObjectDisposedException CreateObjectDisposedException()
         {
             return new ObjectDisposedException(GetType().FullName);
         }
+#endif // !NET7_0_OR_GREATER
     }
 }

+ 2 - 2
src/Renci.SshNet/Common/SemaphoreLight.cs

@@ -6,7 +6,7 @@ namespace Renci.SshNet.Common
     /// <summary>
     /// Light implementation of SemaphoreSlim.
     /// </summary>
-    public class SemaphoreLight : IDisposable
+    public sealed class SemaphoreLight : IDisposable
     {
         private readonly object _lock = new object();
         private ManualResetEvent _waitHandle;
@@ -228,7 +228,7 @@ namespace Renci.SshNet.Common
         /// Releases unmanaged and - optionally - managed resources.
         /// </summary>
         /// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
-        protected void Dispose(bool disposing)
+        private void Dispose(bool disposing)
         {
             if (disposing)
             {

+ 11 - 0
src/Renci.SshNet/Common/SshConnectionException.cs

@@ -47,6 +47,17 @@ namespace Renci.SshNet.Common
             DisconnectReason = disconnectReasonCode;
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SshConnectionException"/> class.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        /// <param name="inner">The inner.</param>
+        public SshConnectionException(string message, Exception inner)
+            : base(message, inner)
+        {
+            DisconnectReason = DisconnectReason.None;
+        }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SshConnectionException"/> class.
         /// </summary>

+ 31 - 15
src/Renci.SshNet/Common/SshData.cs

@@ -7,7 +7,9 @@ namespace Renci.SshNet.Common
     /// <summary>
     /// Base ssh data serialization type.
     /// </summary>
+#pragma warning disable CA1001 // Types that own disposable fields should be disposable
     public abstract class SshData
+#pragma warning restore CA1001 // Types that own disposable fields should be disposable
     {
         internal const int DefaultCapacity = 64;
 
@@ -63,9 +65,12 @@ namespace Renci.SshNet.Common
         {
             var messageLength = BufferCapacity;
             var capacity = messageLength != -1 ? messageLength : DefaultCapacity;
-            var dataStream = new SshDataStream(capacity);
-            WriteBytes(dataStream);
-            return dataStream.ToArray();
+
+            using (var dataStream = new SshDataStream(capacity))
+            {
+                WriteBytes(dataStream);
+                return dataStream.ToArray();
+            }
         }
 
         /// <summary>
@@ -129,7 +134,9 @@ namespace Renci.SshNet.Common
         /// <summary>
         /// Reads all data left in internal buffer at current position.
         /// </summary>
-        /// <returns>An array of bytes containing the remaining data in the internal buffer.</returns>
+        /// <returns>
+        /// An array of bytes containing the remaining data in the internal buffer.
+        /// </returns>
         protected byte[] ReadBytes()
         {
             var bytesLength = (int) (_stream.Length - _stream.Position);
@@ -142,16 +149,12 @@ namespace Renci.SshNet.Common
         /// Reads next specified number of bytes data type from internal buffer.
         /// </summary>
         /// <param name="length">Number of bytes to read.</param>
-        /// <returns>An array of bytes that was read from the internal buffer.</returns>
-        /// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is greater than the internal buffer size.</exception>
+        /// <returns>
+        /// An array of bytes that was read from the internal buffer.
+        /// </returns>
+        /// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is greater than the number of bytes available to be read.</exception>
         protected byte[] ReadBytes(int length)
         {
-            /*
-             * Note that this also prevents allocating non-relevant lengths, such as if length is greater than _data.Count but less than int.MaxValue.
-             * For the nerds, the condition translates to: if (length > data.Count && length < int.MaxValue)
-             * Which probably would cause all sorts of exception, most notably OutOfMemoryException.
-             */
-
             var data = new byte[length];
             var bytesRead = _stream.Read(data, 0, length);
 
@@ -166,7 +169,10 @@ namespace Renci.SshNet.Common
         /// <summary>
         /// Reads next byte data type from internal buffer.
         /// </summary>
-        /// <returns>Byte read.</returns>
+        /// <returns>
+        /// The <see cref="byte"/> read.
+        /// </returns>
+        /// <exception cref="InvalidOperationException">Attempt to read past the end of the stream.</exception>
         protected byte ReadByte()
         {
             var byteRead = _stream.ReadByte();
@@ -184,6 +190,7 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The <see cref="bool"/> that was read.
         /// </returns>
+        /// <exception cref="InvalidOperationException">Attempt to read past the end of the stream.</exception>
         protected bool ReadBoolean()
         {
             return ReadByte() != 0;
@@ -195,6 +202,7 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The <see cref="ushort"/> that was read.
         /// </returns>
+        /// <exception cref="InvalidOperationException">Attempt to read past the end of the stream.</exception>
         protected ushort ReadUInt16()
         {
             return Pack.BigEndianToUInt16(ReadBytes(2));
@@ -206,6 +214,7 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The <see cref="uint"/> that was read.
         /// </returns>
+        /// <exception cref="InvalidOperationException">Attempt to read past the end of the stream.</exception>
         protected uint ReadUInt32()
         {
             return Pack.BigEndianToUInt32(ReadBytes(4));
@@ -217,6 +226,7 @@ namespace Renci.SshNet.Common
         /// <returns>
         /// The <see cref="ulong"/> that was read.
         /// </returns>
+        /// <exception cref="InvalidOperationException">Attempt to read past the end of the stream.</exception>
         protected ulong ReadUInt64()
         {
             return Pack.BigEndianToUInt64(ReadBytes(8));
@@ -260,8 +270,10 @@ namespace Renci.SshNet.Common
         /// <summary>
         /// Reads next extension-pair data type from internal buffer.
         /// </summary>
-        /// <returns>Extensions pair dictionary.</returns>
-        protected IDictionary<string, string> ReadExtensionPair()
+        /// <returns>
+        /// Extensions pair dictionary.
+        /// </returns>
+        protected Dictionary<string, string> ReadExtensionPair()
         {
             var result = new Dictionary<string, string>();
 
@@ -373,7 +385,11 @@ namespace Renci.SshNet.Common
         /// <param name="data">name-list data to write.</param>
         protected void Write(string[] data)
         {
+#if NET || NETSTANDARD2_1_OR_GREATER
+            Write(string.Join(',', data), Ascii);
+#else
             Write(string.Join(",", data), Ascii);
+#endif // NET || NETSTANDARD2_1_OR_GREATER
         }
 
         /// <summary>

+ 18 - 18
src/Renci.SshNet/Common/SshDataStream.cs

@@ -101,6 +101,24 @@ namespace Renci.SshNet.Common
             Write(data, 0, data.Length);
         }
 
+        /// <summary>
+        /// Writes string data to the SSH data stream using the specified encoding.
+        /// </summary>
+        /// <param name="s">The string data to write.</param>
+        /// <param name="encoding">The character encoding to use.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="s"/> is <see langword="null"/>.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="encoding"/> is <see langword="null"/>.</exception>
+        public void Write(string s, Encoding encoding)
+        {
+            if (encoding is null)
+            {
+                throw new ArgumentNullException(nameof(encoding));
+            }
+
+            var bytes = encoding.GetBytes(s);
+            WriteBinary(bytes, 0, bytes.Length);
+        }
+
         /// <summary>
         /// Reads a byte array from the SSH data stream.
         /// </summary>
@@ -149,24 +167,6 @@ namespace Renci.SshNet.Common
             Write(buffer, offset, count);
         }
 
-        /// <summary>
-        /// Writes string data to the SSH data stream using the specified encoding.
-        /// </summary>
-        /// <param name="s">The string data to write.</param>
-        /// <param name="encoding">The character encoding to use.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="s"/> is <see langword="null"/>.</exception>
-        /// <exception cref="ArgumentNullException"><paramref name="encoding"/> is <see langword="null"/>.</exception>
-        public void Write(string s, Encoding encoding)
-        {
-            if (encoding is null)
-            {
-                throw new ArgumentNullException(nameof(encoding));
-            }
-
-            var bytes = encoding.GetBytes(s);
-            WriteBinary(bytes, 0, bytes.Length);
-        }
-
         /// <summary>
         /// Reads a <see cref="BigInteger"/> from the SSH datastream.
         /// </summary>

+ 5 - 1
src/Renci.SshNet/Common/TerminalModes.cs

@@ -1,10 +1,13 @@
 namespace Renci.SshNet.Common
 {
     /// <summary>
-    /// Specifies the initial assignments of the opcode values that are used in the 'encoded terminal modes' valu
+    /// Specifies the initial assignments of the opcode values that are used in the 'encoded terminal modes' value.
     /// </summary>
+#pragma warning disable CA1028 // Enum Storage should be Int32
     public enum TerminalModes : byte
+#pragma warning restore CA1028 // Enum Storage should be Int32
     {
+#pragma warning disable CA1707 // Identifiers should not contain underscores
         /// <summary>
         /// Indicates end of options.
         /// </summary>
@@ -289,5 +292,6 @@
         /// Specifies the output baud rate in bits per second.
         /// </summary>
         TTY_OP_OSPEED = 129,
+#pragma warning restore CA1707 // Identifiers should not contain underscores
     }
 }

+ 1 - 1
src/Renci.SshNet/Compression/CompressionMode.cs

@@ -1,7 +1,7 @@
 namespace Renci.SshNet.Compression
 {
     /// <summary>
-    /// Specifies compression modes
+    /// Specifies compression modes.
     /// </summary>
     public enum CompressionMode
     {

+ 7 - 5
src/Renci.SshNet/Compression/Compressor.cs

@@ -6,7 +6,7 @@ using Renci.SshNet.Security;
 namespace Renci.SshNet.Compression
 {
     /// <summary>
-    /// Represents base class for compression algorithm implementation
+    /// Represents base class for compression algorithm implementation.
     /// </summary>
     public abstract class Compressor : Algorithm, IDisposable
     {
@@ -20,7 +20,7 @@ namespace Renci.SshNet.Compression
         /// Gets or sets a value indicating whether compression is active.
         /// </summary>
         /// <value>
-        ///   <see langword="true"/> if compression is active; otherwise, <see langword="false"/>.
+        /// <see langword="true"/> if compression is active; otherwise, <see langword="false"/>.
         /// </value>
         protected bool IsActive { get; set; }
 
@@ -42,7 +42,7 @@ namespace Renci.SshNet.Compression
         }
 
         /// <summary>
-        /// Initializes the algorithm
+        /// Initializes the algorithm.
         /// </summary>
         /// <param name="session">The session.</param>
         public virtual void Init(Session session)
@@ -54,7 +54,9 @@ namespace Renci.SshNet.Compression
         /// Compresses the specified data.
         /// </summary>
         /// <param name="data">Data to compress.</param>
-        /// <returns>Compressed data</returns>
+        /// <returns>
+        /// The compressed data.
+        /// </returns>
         public virtual byte[] Compress(byte[] data)
         {
             return Compress(data, 0, data.Length);
@@ -142,7 +144,7 @@ namespace Renci.SshNet.Compression
         }
 
         /// <summary>
-        /// Releases unmanaged and - optionally - managed resources
+        /// Releases unmanaged and - optionally - managed resources.
         /// </summary>
         /// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
         protected virtual void Dispose(bool disposing)

+ 2 - 2
src/Renci.SshNet/Compression/Zlib.cs

@@ -1,7 +1,7 @@
 namespace Renci.SshNet.Compression
 {
     /// <summary>
-    /// Represents "zlib" compression implementation
+    /// Represents "zlib" compression implementation.
     /// </summary>
     internal sealed class Zlib : Compressor
     {
@@ -14,7 +14,7 @@
         }
 
         /// <summary>
-        /// Initializes the algorithm
+        /// Initializes the algorithm.
         /// </summary>
         /// <param name="session">The session.</param>
         public override void Init(Session session)

+ 3 - 3
src/Renci.SshNet/Compression/ZlibOpenSsh.cs

@@ -3,7 +3,7 @@
 namespace Renci.SshNet.Compression
 {
     /// <summary>
-    /// Represents "zlib@openssh.org" compression implementation
+    /// Represents "zlib@openssh.org" compression implementation.
     /// </summary>
     public class ZlibOpenSsh : Compressor
     {
@@ -16,7 +16,7 @@ namespace Renci.SshNet.Compression
         }
 
         /// <summary>
-        /// Initializes the algorithm
+        /// Initializes the algorithm.
         /// </summary>
         /// <param name="session">The session.</param>
         public override void Init(Session session)
@@ -32,4 +32,4 @@ namespace Renci.SshNet.Compression
             Session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived;
         }
     }
-}
+}

+ 9 - 0
src/Renci.SshNet/Compression/ZlibStream.cs

@@ -1,11 +1,16 @@
 using System.IO;
 
+#pragma warning disable S125 // Sections of code should not be commented out
+#pragma warning disable SA1005 // Single line comments should begin with single space
+
 namespace Renci.SshNet.Compression
 {
     /// <summary>
     /// Implements Zlib compression algorithm.
     /// </summary>
+#pragma warning disable CA1711 // Identifiers should not have incorrect suffix
     public class ZlibStream
+#pragma warning restore CA1711 // Identifiers should not have incorrect suffix
     {
         //private readonly Ionic.Zlib.ZlibStream _baseStream;
 
@@ -45,5 +50,9 @@ namespace Renci.SshNet.Compression
         {
             //this._baseStream.Write(buffer, offset, count);
         }
+#pragma warning restore SA1005 // Single line comments should begin with single space
     }
 }
+
+#pragma warning restore SA1005 // Single line comments should begin with single space
+#pragma warning restore S125 // Sections of code should not be commented out

+ 18 - 0
src/Renci.SshNet/Connection/IConnector.cs

@@ -3,10 +3,28 @@ using System.Threading;
 
 namespace Renci.SshNet.Connection
 {
+    /// <summary>
+    /// Represents a means to connect to a SSH endpoint.
+    /// </summary>
     internal interface IConnector
     {
+        /// <summary>
+        /// Connects to a SSH endpoint using the specified <see cref="IConnectionInfo"/>.
+        /// </summary>
+        /// <param name="connectionInfo">The <see cref="IConnectionInfo"/> to use to establish a connection to a SSH endpoint.</param>
+        /// <returns>
+        /// A <see cref="Socket"/> connected to the SSH endpoint represented by the specified <see cref="IConnectionInfo"/>.
+        /// </returns>
         Socket Connect(IConnectionInfo connectionInfo);
 
+        /// <summary>
+        /// Asynchronously connects to a SSH endpoint using the specified <see cref="IConnectionInfo"/>.
+        /// </summary>
+        /// <param name="connectionInfo">The <see cref="IConnectionInfo"/> to use to establish a connection to a SSH endpoint.</param>
+        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
+        /// <returns>
+        /// A <see cref="Socket"/> connected to the SSH endpoint represented by the specified <see cref="IConnectionInfo"/>.
+        /// </returns>
         System.Threading.Tasks.Task<Socket> ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken);
     }
 }

+ 13 - 1
src/Renci.SshNet/Connection/IProtocolVersionExchange.cs

@@ -1,5 +1,7 @@
 using System;
 using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
 
 namespace Renci.SshNet.Connection
 {
@@ -19,6 +21,16 @@ namespace Renci.SshNet.Connection
         /// </returns>
         SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout);
 
-        System.Threading.Tasks.Task<SshIdentification> StartAsync(string clientVersion, Socket socket, System.Threading.CancellationToken cancellationToken);
+        /// <summary>
+        /// Asynchronously performs the SSH protocol version exchange.
+        /// </summary>
+        /// <param name="clientVersion">The identification string of the SSH client.</param>
+        /// <param name="socket">A <see cref="Socket"/> connected to the server.</param>
+        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
+        /// <returns>
+        /// A task that represents the SSH protocol version exchange. The value of its
+        /// <see cref="Task{Task}.Result"/> contains the SSH identification of the server.
+        /// </returns>
+        Task<SshIdentification> StartAsync(string clientVersion, Socket socket, CancellationToken cancellationToken);
     }
 }

+ 14 - 0
src/Renci.SshNet/Connection/ISocketFactory.cs

@@ -2,8 +2,22 @@
 
 namespace Renci.SshNet.Connection
 {
+    /// <summary>
+    /// Represents a factory to create <see cref="Socket"/> instances.
+    /// </summary>
     internal interface ISocketFactory
     {
+        /// <summary>
+        /// Creates a <see cref="Socket"/> with the specified <see cref="AddressFamily"/>,
+        /// <see cref="SocketType"/> and <see cref="ProtocolType"/> that does not use the
+        /// <c>Nagle</c> algorithm.
+        /// </summary>
+        /// <param name="addressFamily">The <see cref="AddressFamily"/>.</param>
+        /// <param name="socketType">The <see cref="SocketType"/>.</param>
+        /// <param name="protocolType">The <see cref="ProtocolType"/>.</param>
+        /// <returns>
+        /// The <see cref="Socket"/>.
+        /// </returns>
         Socket Create(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);
     }
 }

+ 11 - 1
src/Renci.SshNet/Connection/ProtocolVersionExchange.cs

@@ -23,7 +23,7 @@ namespace Renci.SshNet.Connection
     {
         private const byte Null = 0x00;
 
-        private static readonly Regex ServerVersionRe = new Regex("^SSH-(?<protoversion>[^-]+)-(?<softwareversion>.+?)([ ](?<comments>.+))?$", RegexOptions.Compiled);
+        private static readonly Regex ServerVersionRe = new Regex("^SSH-(?<protoversion>[^-]+)-(?<softwareversion>.+?)([ ](?<comments>.+))?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
 
         /// <summary>
         /// Performs the SSH protocol version exchange.
@@ -67,6 +67,16 @@ namespace Renci.SshNet.Connection
             }
         }
 
+        /// <summary>
+        /// Asynchronously performs the SSH protocol version exchange.
+        /// </summary>
+        /// <param name="clientVersion">The identification string of the SSH client.</param>
+        /// <param name="socket">A <see cref="Socket"/> connected to the server.</param>
+        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
+        /// <returns>
+        /// A task that represents the SSH protocol version exchange. The value of its
+        /// <see cref="Task{Task}.Result"/> contains the SSH identification of the server.
+        /// </returns>
         public async Task<SshIdentification> StartAsync(string clientVersion, Socket socket, CancellationToken cancellationToken)
         {
             // Immediately send the identification string since the spec states both sides MUST send an identification string

+ 33 - 2
src/Renci.SshNet/Connection/ProxyConnector.cs

@@ -5,6 +5,10 @@ using System.Threading.Tasks;
 
 namespace Renci.SshNet.Connection
 {
+    /// <summary>
+    /// Represents a connector that uses a proxy server to establish a connection to a given SSH
+    /// endpoint.
+    /// </summary>
     internal abstract class ProxyConnector : ConnectorBase
     {
         protected ProxyConnector(ISocketFactory socketFactory)
@@ -15,18 +19,37 @@ namespace Renci.SshNet.Connection
         protected abstract void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket);
 
         // ToDo: Performs async/sync fallback, true async version should be implemented in derived classes
-        protected virtual Task HandleProxyConnectAsync(IConnectionInfo connectionInfo, Socket socket, CancellationToken cancellationToken)
+        protected virtual
+#if NET || NETSTANDARD2_1_OR_GREATER
+        async
+#endif // NET || NETSTANDARD2_1_OR_GREATER
+        Task HandleProxyConnectAsync(IConnectionInfo connectionInfo, Socket socket, CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            using (cancellationToken.Register(o => ((Socket)o).Dispose(), socket, useSynchronizationContext: false))
+#if NET || NETSTANDARD2_1_OR_GREATER
+            await using (cancellationToken.Register(o => ((Socket)o).Dispose(), socket, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false))
+#else
+            using (cancellationToken.Register(o => ((Socket) o).Dispose(), socket, useSynchronizationContext: false))
+#endif // NET || NETSTANDARD2_1_OR_GREATER
             {
+#pragma warning disable MA0042 // Do not use blocking calls in an async method; false positive caused by https://github.com/meziantou/Meziantou.Analyzer/issues/613
                 HandleProxyConnect(connectionInfo, socket);
+#pragma warning restore MA0042 // Do not use blocking calls in an async method
             }
 
+#if !NET && !NETSTANDARD2_1_OR_GREATER
             return Task.CompletedTask;
+#endif // !NET && !NETSTANDARD2_1_OR_GREATER
         }
 
+        /// <summary>
+        /// Connects to a SSH endpoint using the specified <see cref="IConnectionInfo"/>.
+        /// </summary>
+        /// <param name="connectionInfo">The <see cref="IConnectionInfo"/> to use to establish a connection to a SSH endpoint.</param>
+        /// <returns>
+        /// A <see cref="Socket"/> connected to the SSH endpoint represented by the specified <see cref="IConnectionInfo"/>.
+        /// </returns>
         public override Socket Connect(IConnectionInfo connectionInfo)
         {
             var socket = SocketConnect(connectionInfo.ProxyHost, connectionInfo.ProxyPort, connectionInfo.Timeout);
@@ -45,6 +68,14 @@ namespace Renci.SshNet.Connection
             }
         }
 
+        /// <summary>
+        /// Asynchronously connects to a SSH endpoint using the specified <see cref="IConnectionInfo"/>.
+        /// </summary>
+        /// <param name="connectionInfo">The <see cref="IConnectionInfo"/> to use to establish a connection to a SSH endpoint.</param>
+        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
+        /// <returns>
+        /// A <see cref="Socket"/> connected to the SSH endpoint represented by the specified <see cref="IConnectionInfo"/>.
+        /// </returns>
         public override async Task<Socket> ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken)
         {
             var socket = await SocketConnectAsync(connectionInfo.ProxyHost, connectionInfo.ProxyPort, cancellationToken).ConfigureAwait(false);

+ 15 - 1
src/Renci.SshNet/Connection/SocketFactory.cs

@@ -2,11 +2,25 @@
 
 namespace Renci.SshNet.Connection
 {
+    /// <summary>
+    /// Represents a factory to create <see cref="Socket"/> instances.
+    /// </summary>
     internal sealed class SocketFactory : ISocketFactory
     {
+        /// <summary>
+        /// Creates a <see cref="Socket"/> with the specified <see cref="AddressFamily"/>,
+        /// <see cref="SocketType"/> and <see cref="ProtocolType"/> that does not use the
+        /// <c>Nagle</c> algorithm.
+        /// </summary>
+        /// <param name="addressFamily">The <see cref="AddressFamily"/>.</param>
+        /// <param name="socketType">The <see cref="SocketType"/>.</param>
+        /// <param name="protocolType">The <see cref="ProtocolType"/>.</param>
+        /// <returns>
+        /// The <see cref="Socket"/>.
+        /// </returns>
         public Socket Create(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
         {
-            return new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
+            return new Socket(addressFamily, socketType, protocolType) { NoDelay = true };
         }
     }
 }

+ 17 - 15
src/Renci.SshNet/Connection/Socks4Connector.cs

@@ -62,21 +62,23 @@ namespace Renci.SshNet.Connection
             var addressBytes = GetSocks4DestinationAddress(hostname);
             var proxyUserBytes = GetProxyUserBytes(username);
 
-            var connectionRequest = new byte
-                [
-                    // SOCKS version number
-                    1 +
-                    // Command code
-                    1 +
-                    // Port number
-                    2 +
-                    // IP address
-                    addressBytes.Length +
-                    // Username
-                    proxyUserBytes.Length +
-                    // Null terminator
-                    1
-                ];
+            var connectionRequest = new byte[// SOCKS version number
+                                             1 +
+
+                                             // Command code
+                                             1 +
+
+                                             // Port number
+                                             2 +
+
+                                             // IP address
+                                             addressBytes.Length +
+
+                                             // Username
+                                             proxyUserBytes.Length +
+
+                                             // Null terminator
+                                             1];
 
             var index = 0;
 

+ 34 - 28
src/Renci.SshNet/Connection/Socks5Connector.cs

@@ -30,10 +30,13 @@ namespace Renci.SshNet.Connection
                 {
                     // SOCKS version number
                     0x05,
+
                     // Number of supported authentication methods
                     0x02,
+
                     // No authentication
                     0x00,
+
                     // Username/Password authentication
                     0x02
                 };
@@ -156,19 +159,20 @@ namespace Renci.SshNet.Connection
                 throw new ProxyException("Proxy password is too long.");
             }
 
-            var authenticationRequest = new byte
-                [
-                    // Version of the negotiation
-                    1 +
-                    // Length of the username
-                    1 +
-                    // Username
-                    username.Length +
-                    // Length of the password
-                    1 +
-                    // Password
-                    password.Length
-                ];
+            var authenticationRequest = new byte[// Version of the negotiation
+                                                 1 +
+
+                                                 // Length of the username
+                                                 1 +
+
+                                                 // Username
+                                                 username.Length +
+
+                                                 // Length of the password
+                                                 1 +
+
+                                                 // Password
+                                                 password.Length];
 
             var index = 0;
 
@@ -195,21 +199,23 @@ namespace Renci.SshNet.Connection
         {
             var addressBytes = GetSocks5DestinationAddress(hostname, out var addressType);
 
-            var connectionRequest = new byte
-                [
-                    // SOCKS version number
-                    1 +
-                    // Command code
-                    1 +
-                    // Reserved
-                    1 +
-                    // Address type
-                    1 +
-                    // Address
-                    addressBytes.Length +
-                    // Port number
-                    2
-                ];
+            var connectionRequest = new byte[// SOCKS version number
+                                             1 +
+
+                                             // Command code
+                                             1 +
+
+                                             // Reserved
+                                             1 +
+
+                                             // Address type
+                                             1 +
+
+                                             // Address
+                                             addressBytes.Length +
+
+                                             // Port number
+                                             2];
 
             var index = 0;
 

+ 18 - 2
src/Renci.SshNet/ConnectionInfo.cs

@@ -398,8 +398,10 @@ namespace Renci.SshNet
                     { "ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data) },
                     { "ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data) },
                     { "ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data) },
-                    { "rsa-sha2-512", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-512", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); }},
-                    { "rsa-sha2-256", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-256", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); }},
+#pragma warning disable SA1107 // Code should not contain multiple statements on one line
+                    { "rsa-sha2-512", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-512", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); } },
+                    { "rsa-sha2-256", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-256", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); } },
+#pragma warning restore SA1107 // Code should not contain multiple statements on one line
                     { "ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data) },
                     { "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data) },
                 };
@@ -470,14 +472,28 @@ namespace Renci.SshNet
             AuthenticationBanner?.Invoke(this, new AuthenticationBannerEventArgs(Username, e.Message.Message, e.Message.Language));
         }
 
+        /// <summary>
+        /// Creates a <c>none</c> authentication method.
+        /// </summary>
+        /// <returns>
+        /// A <c>none</c> authentication method.
+        /// </returns>
         IAuthenticationMethod IConnectionInfoInternal.CreateNoneAuthenticationMethod()
         {
             return new NoneAuthenticationMethod(Username);
         }
 
+        /// <summary>
+        /// Gets the supported authentication methods for this connection.
+        /// </summary>
+        /// <value>
+        /// The supported authentication methods for this connection.
+        /// </value>
         IList<IAuthenticationMethod> IConnectionInfoInternal.AuthenticationMethods
         {
+#pragma warning disable S2365 // Properties should not make collection or array copies
             get { return AuthenticationMethods.Cast<IAuthenticationMethod>().ToList(); }
+#pragma warning restore S2365 // Properties should not make collection or array copies
         }
     }
 }

+ 4 - 2
src/Renci.SshNet/ForwardedPortDynamic.cs

@@ -361,10 +361,12 @@ namespace Renci.SshNet
                 Closing -= closeClientSocket;
             }
 
-            void closeClientSocket(object _, EventArgs args)
+#pragma warning disable SA1300 // Element should begin with upper-case letter
+            void closeClientSocket(object sender, EventArgs args)
             {
                 CloseClientSocket(clientSocket);
-            };
+            }
+#pragma warning restore SA1300 // Element should begin with upper-case letter
         }
 
         private static void CloseClientSocket(Socket clientSocket)

+ 2 - 0
src/Renci.SshNet/ForwardedPortStatus.cs

@@ -34,7 +34,9 @@ namespace Renci.SshNet
             return forwardedPortStatus._value == _value;
         }
 
+#pragma warning disable S3875 // "operator==" should not be overloaded on reference types
         public static bool operator ==(ForwardedPortStatus left, ForwardedPortStatus right)
+#pragma warning restore S3875 // "operator==" should not be overloaded on reference types
         {
             // check if lhs is null
             if (left is null)

+ 2 - 2
src/Renci.SshNet/HashInfo.cs

@@ -5,7 +5,7 @@ using Renci.SshNet.Common;
 namespace Renci.SshNet
 {
     /// <summary>
-    /// Holds information about key size and cipher to use
+    /// Holds information about key size and cipher to use.
     /// </summary>
     public class HashInfo
     {
@@ -23,7 +23,7 @@ namespace Renci.SshNet
         public Func<byte[], HashAlgorithm> HashAlgorithm { get; private set; }
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="CipherInfo"/> class.
+        /// Initializes a new instance of the <see cref="HashInfo"/> class.
         /// </summary>
         /// <param name="keySize">Size of the key.</param>
         /// <param name="hash">The hash algorithm to use for a given key.</param>

+ 1 - 6
src/Renci.SshNet/IBaseClient.cs

@@ -10,7 +10,7 @@ namespace Renci.SshNet
     /// <summary>
     /// Serves as base class for client implementations, provides common client functionality.
     /// </summary>
-    public interface IBaseClient
+    public interface IBaseClient : IDisposable
     {
         /// <summary>
         /// Gets the connection info.
@@ -87,11 +87,6 @@ namespace Renci.SshNet
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
         void Disconnect();
 
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        void Dispose();
-
         /// <summary>
         /// Sends a keep-alive message to the server.
         /// </summary>

+ 17 - 1
src/Renci.SshNet/IClientAuthentication.cs

@@ -1,7 +1,23 @@
-namespace Renci.SshNet
+using System;
+
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet
 {
+    /// <summary>
+    /// Represents a mechanism to authenticate a given client.
+    /// </summary>
     internal interface IClientAuthentication
     {
+        /// <summary>
+        /// Attempts to perform authentication for a given <see cref="ISession"/> using the
+        /// <see cref="IConnectionInfoInternal.AuthenticationMethods"/> of the specified
+        /// <see cref="IConnectionInfoInternal"/>.
+        /// </summary>
+        /// <param name="connectionInfo">A <see cref="IConnectionInfoInternal"/> to use for authenticating.</param>
+        /// <param name="session">The <see cref="ISession"/> for which to perform authentication.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="connectionInfo"/> or <paramref name="session"/> is <see langword="null"/>.</exception>
+        /// <exception cref="SshAuthenticationException">Failed to Authenticate the client.</exception>
         void Authenticate(IConnectionInfoInternal connectionInfo, ISession session);
     }
 }

+ 0 - 29
src/Renci.SshNet/IConnectionInfo.cs

@@ -3,39 +3,10 @@ using System.Collections.Generic;
 using System.Text;
 
 using Renci.SshNet.Common;
-using Renci.SshNet.Messages.Authentication;
 using Renci.SshNet.Messages.Connection;
 
 namespace Renci.SshNet
 {
-    internal interface IConnectionInfoInternal : IConnectionInfo
-    {
-        /// <summary>
-        /// Signals that an authentication banner message was received from the server.
-        /// </summary>
-        /// <param name="sender">The session in which the banner message was received.</param>
-        /// <param name="e">The banner message.</param>
-        void UserAuthenticationBannerReceived(object sender, MessageEventArgs<BannerMessage> e);
-
-        /// <summary>
-        /// Gets the supported authentication methods for this connection.
-        /// </summary>
-        /// <value>
-        /// The supported authentication methods for this connection.
-        /// </value>
-        IList<IAuthenticationMethod> AuthenticationMethods { get; }
-
-        /// <summary>
-        /// Creates a <see cref="NoneAuthenticationMethod"/> for the credentials represented
-        /// by the current <see cref="IConnectionInfo"/>.
-        /// </summary>
-        /// <returns>
-        /// A <see cref="NoneAuthenticationMethod"/> for the credentials represented by the
-        /// current <see cref="IConnectionInfo"/>.
-        /// </returns>
-        IAuthenticationMethod CreateNoneAuthenticationMethod();
-    }
-
     /// <summary>
     /// Represents remote connection information.
     /// </summary>

+ 37 - 0
src/Renci.SshNet/IConnectionInfoInternal.cs

@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+
+using Renci.SshNet.Messages.Authentication;
+
+namespace Renci.SshNet
+{
+    /// <summary>
+    /// Represents remote connection information.
+    /// </summary>
+    internal interface IConnectionInfoInternal : IConnectionInfo
+    {
+        /// <summary>
+        /// Signals that an authentication banner message was received from the server.
+        /// </summary>
+        /// <param name="sender">The session in which the banner message was received.</param>
+        /// <param name="e">The banner message.</param>
+        void UserAuthenticationBannerReceived(object sender, MessageEventArgs<BannerMessage> e);
+
+        /// <summary>
+        /// Gets the supported authentication methods for this connection.
+        /// </summary>
+        /// <value>
+        /// The supported authentication methods for this connection.
+        /// </value>
+        IList<IAuthenticationMethod> AuthenticationMethods { get; }
+
+        /// <summary>
+        /// Creates a <see cref="NoneAuthenticationMethod"/> for the credentials represented
+        /// by the current <see cref="IConnectionInfo"/>.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="NoneAuthenticationMethod"/> for the credentials represented by the
+        /// current <see cref="IConnectionInfo"/>.
+        /// </returns>
+        IAuthenticationMethod CreateNoneAuthenticationMethod();
+    }
+}

+ 0 - 30
src/Renci.SshNet/IForwardedPort.cs

@@ -1,7 +1,5 @@
 using System;
 
-using Renci.SshNet.Common;
-
 namespace Renci.SshNet
 {
     /// <summary>
@@ -13,33 +11,5 @@ namespace Renci.SshNet
         /// The <see cref="Closing"/> event occurs as the forwarded port is being stopped.
         /// </summary>
         event EventHandler Closing;
-
-        /// <summary>
-        /// Occurs when an exception is thrown.
-        /// </summary>
-        event EventHandler<ExceptionEventArgs> Exception;
-
-        /// <summary>
-        /// Occurs when a port forwarding request is received.
-        /// </summary>
-        event EventHandler<PortForwardEventArgs> RequestReceived;
-
-        /// <summary>
-        /// Gets a value indicating whether port forwarding is started.
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if port forwarding is started; otherwise, <see langword="false"/>.
-        /// </value>
-        bool IsStarted { get; }
-
-        /// <summary>
-        /// Starts port forwarding.
-        /// </summary>
-        void Start();
-
-        /// <summary>
-        /// Stops port forwarding.
-        /// </summary>
-        void Stop();
     }
 }

+ 4 - 1
src/Renci.SshNet/ISession.cs

@@ -17,7 +17,7 @@ namespace Renci.SshNet
     internal interface ISession : IDisposable
     {
         /// <summary>
-        /// Gets or sets the connection info.
+        /// Gets the connection info.
         /// </summary>
         /// <value>The connection info.</value>
         IConnectionInfo ConnectionInfo { get; }
@@ -86,6 +86,9 @@ namespace Renci.SshNet
         /// <summary>
         /// Creates a "forwarded-tcpip" SSH channel.
         /// </summary>
+        /// <param name="remoteChannelNumber">The number of the remote channel.</param>
+        /// <param name="remoteWindowSize">The window size of the remote channel.</param>
+        /// <param name="remoteChannelDataPacketSize">The data packet size of the remote channel.</param>
         /// <returns>
         /// A new "forwarded-tcpip" SSH channel.
         /// </returns>

+ 20 - 18
src/Renci.SshNet/ISftpClient.cs

@@ -13,7 +13,7 @@ namespace Renci.SshNet
     /// <summary>
     /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH.
     /// </summary>
-    public interface ISftpClient : IBaseClient, IDisposable
+    public interface ISftpClient : IBaseClient
     {
         /// <summary>
         /// Gets or sets the maximum size of the buffer in bytes.
@@ -78,12 +78,12 @@ namespace Renci.SshNet
         /// </summary>
         /// <param name="path">The file to append the lines to. The file is created if it does not already exist.</param>
         /// <param name="contents">The lines to append to the file.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is<see langword="null"/> <para>-or-</para> <paramref name="contents"/> is <see langword="null"/>.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>. <para>-or-</para> <paramref name="contents"/> is <see langword="null"/>.</exception>
         /// <exception cref="SshConnectionException">Client is not connected.</exception>
         /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
         /// <remarks>
-        /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM)
+        /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
         /// </remarks>
         void AppendAllLines(string path, IEnumerable<string> contents);
 
@@ -239,7 +239,7 @@ namespace Renci.SshNet
         /// </returns>
         /// <exception cref="ArgumentNullException"><paramref name="sourcePath"/> is <see langword="null"/>.</exception>
         /// <exception cref="ArgumentException"><paramref name="destinationPath"/> is <see langword="null"/> or contains only whitespace.</exception>
-        /// <exception cref="SshException">If a problem occurs while copying the file</exception>
+        /// <exception cref="SshException">If a problem occurs while copying the file.</exception>
         IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state);
 
         /// <summary>
@@ -568,7 +568,7 @@ namespace Renci.SshNet
         void EndUploadFile(IAsyncResult asyncResult);
 
         /// <summary>
-        /// Checks whether file or directory exists;
+        /// Checks whether file or directory exists.
         /// </summary>
         /// <param name="path">The path.</param>
         /// <returns>
@@ -592,7 +592,9 @@ namespace Renci.SshNet
         /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</exception>
         /// <exception cref="ArgumentNullException"><paramref name="path" /> is <see langword="null"/>.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
+#pragma warning disable CA1716 // Identifiers should not match keywords
         ISftpFile Get(string path);
+#pragma warning restore CA1716 // Identifiers should not match keywords
 
         /// <summary>
         /// Gets the <see cref="SftpFileAttributes"/> of the file on the path.
@@ -898,31 +900,31 @@ namespace Renci.SshNet
         void RenameFile(string oldPath, string newPath);
 
         /// <summary>
-        /// Asynchronously renames remote file from old path to new path.
+        /// Renames remote file from old path to new path.
         /// </summary>
         /// <param name="oldPath">Path to the old file location.</param>
         /// <param name="newPath">Path to the new file location.</param>
-        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
-        /// <returns>A <see cref="Task"/> that represents the asynchronous rename operation.</returns>
-        /// <exception cref="ArgumentNullException"><paramref name="oldPath"/> is <see langword="null"/>. <para>-or-</para> or <paramref name="newPath"/> is <see langword="null"/>.</exception>
+        /// <param name="isPosix">if set to <see langword="true"/> then perform a posix rename.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="oldPath" /> is <see langword="null"/>. <para>-or-</para> or <paramref name="newPath" /> is <see langword="null"/>.</exception>
         /// <exception cref="SshConnectionException">Client is not connected.</exception>
         /// <exception cref="SftpPermissionDeniedException">Permission to rename the file was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception>
-        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the remote host.</exception>
+        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the remote host.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken);
+        void RenameFile(string oldPath, string newPath, bool isPosix);
 
         /// <summary>
-        /// Renames remote file from old path to new path.
+        /// Asynchronously renames remote file from old path to new path.
         /// </summary>
         /// <param name="oldPath">Path to the old file location.</param>
         /// <param name="newPath">Path to the new file location.</param>
-        /// <param name="isPosix">if set to <see langword="true"/> then perform a posix rename.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="oldPath" /> is <see langword="null"/>. <para>-or-</para> or <paramref name="newPath" /> is <see langword="null"/>.</exception>
+        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
+        /// <returns>A <see cref="Task"/> that represents the asynchronous rename operation.</returns>
+        /// <exception cref="ArgumentNullException"><paramref name="oldPath"/> is <see langword="null"/>. <para>-or-</para> or <paramref name="newPath"/> is <see langword="null"/>.</exception>
         /// <exception cref="SshConnectionException">Client is not connected.</exception>
         /// <exception cref="SftpPermissionDeniedException">Permission to rename the file was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception>
-        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the remote host.</exception>
+        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the remote host.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        void RenameFile(string oldPath, string newPath, bool isPosix);
+        Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken);
 
         /// <summary>
         /// Sets the date and time the specified file was last accessed.
@@ -951,7 +953,7 @@ namespace Renci.SshNet
         /// <param name="path">The file for which to set the date and time information.</param>
         /// <param name="lastWriteTimeUtc">A <see cref="DateTime"/> containing the value to set for the last write date and time of path. This value is expressed in UTC time.</param>
         void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc);
-        
+
         /// <summary>
         /// Sets the specified <see cref="SftpFileAttributes"/> of the file on the specified path.
         /// </summary>
@@ -986,7 +988,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentNullException"><paramref name="sourcePath"/> is <see langword="null"/>.</exception>
         /// <exception cref="ArgumentException"><paramref name="destinationPath"/> is <see langword="null"/> or contains only whitespace.</exception>
         /// <exception cref="SftpPathNotFoundException"><paramref name="destinationPath"/> was not found on the remote host.</exception>
-        /// <exception cref="SshException">If a problem occurs while copying the file</exception>
+        /// <exception cref="SshException">If a problem occurs while copying the file.</exception>
         IEnumerable<FileInfo> SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern);
 
         /// <summary>

+ 5 - 5
src/Renci.SshNet/ISubsystemSession.cs

@@ -13,7 +13,7 @@ namespace Renci.SshNet
         /// Gets or set the number of seconds to wait for an operation to complete.
         /// </summary>
         /// <value>
-        /// The number of seconds to wait for an operation to complete, or -1 to wait indefinitely.
+        /// The number of seconds to wait for an operation to complete, or <c>-1</c> to wait indefinitely.
         /// </value>
         int OperationTimeout { get; }
 
@@ -41,7 +41,7 @@ namespace Renci.SshNet
         /// Waits a specified time for a given <see cref="WaitHandle"/> to get signaled.
         /// </summary>
         /// <param name="waitHandle">The handle to wait for.</param>
-        /// <param name="millisecondsTimeout">The number of millieseconds wait for <paramref name="waitHandle"/> to get signaled, or -1 to wait indefinitely.</param>
+        /// <param name="millisecondsTimeout">The number of millieseconds wait for <paramref name="waitHandle"/> to get signaled, or <c>-1</c> to wait indefinitely.</param>
         /// <exception cref="SshException">The connection was closed by the server.</exception>
         /// <exception cref="SshException">The channel was closed.</exception>
         /// <exception cref="SshOperationTimeoutException">The handle did not get signaled within the specified timeout.</exception>
@@ -52,7 +52,7 @@ namespace Renci.SshNet
         /// 32-bit signed integer to specify the time interval in milliseconds.
         /// </summary>
         /// <param name="waitHandle">The handle to wait for.</param>
-        /// <param name="millisecondsTimeout">To number of milliseconds to wait for <paramref name="waitHandle"/> to get signaled, or -1 to wait indefinitely.</param>
+        /// <param name="millisecondsTimeout">To number of milliseconds to wait for <paramref name="waitHandle"/> to get signaled, or <c>-1</c> to wait indefinitely.</param>
         /// <returns>
         /// <see langword="true"/> if <paramref name="waitHandle"/> received a signal within the specified timeout;
         /// otherwise, <see langword="false"/>.
@@ -72,7 +72,7 @@ namespace Renci.SshNet
         /// </summary>
         /// <param name="waitHandleA">The first handle to wait for.</param>
         /// <param name="waitHandleB">The second handle to wait for.</param>
-        /// <param name="millisecondsTimeout">To number of milliseconds to wait for a <see cref="WaitHandle"/> to get signaled, or -1 to wait indefinitely.</param>
+        /// <param name="millisecondsTimeout">To number of milliseconds to wait for a <see cref="WaitHandle"/> to get signaled, or <c>-1</c> to wait indefinitely.</param>
         /// <returns>
         /// <c>0</c> if <paramref name="waitHandleA"/> received a signal within the specified timeout and <c>1</c>
         /// if <paramref name="waitHandleB"/> received a signal within the specified timeout, or <see cref="WaitHandle.WaitTimeout"/>
@@ -98,7 +98,7 @@ namespace Renci.SshNet
         /// integer to specify the time interval.
         /// </summary>
         /// <param name="waitHandles">A <see cref="WaitHandle"/> array - constructed using <see cref="CreateWaitHandleArray(WaitHandle[])"/> - containing the objects to wait for.</param>
-        /// <param name="millisecondsTimeout">To number of milliseconds to wait for a <see cref="WaitHandle"/> to get signaled, or -1 to wait indefinitely.</param>
+        /// <param name="millisecondsTimeout">To number of milliseconds to wait for a <see cref="WaitHandle"/> to get signaled, or <c>-1</c> to wait indefinitely.</param>
         /// <returns>
         /// The array index of the first non-system object that satisfied the wait.
         /// </returns>

+ 2 - 1
src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs

@@ -134,12 +134,13 @@ namespace Renci.SshNet
                     kbdInteractive.AuthenticationPrompt += AuthenticationMethod_AuthenticationPrompt;
                 }
             }
-
         }
 
         private void AuthenticationMethod_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e)
         {
+#pragma warning disable MA0091 // Sender should be 'this' for instance events
             AuthenticationPrompt?.Invoke(sender, e);
+#pragma warning restore MA0091 // Sender should be 'this' for instance events
         }
 
         /// <summary>

+ 7 - 1
src/Renci.SshNet/Messages/Authentication/FailureMessage.cs

@@ -25,7 +25,7 @@ namespace Renci.SshNet.Messages.Authentication
         /// Gets a value indicating whether authentication is partially successful.
         /// </summary>
         /// <value>
-        ///   <see langword="true"/> if partially successful; otherwise, <see langword="false"/>.
+        /// <see langword="true"/> if partially successful; otherwise, <see langword="false"/>.
         /// </value>
         public bool PartialSuccess { get; private set; }
 
@@ -38,7 +38,11 @@ namespace Renci.SshNet.Messages.Authentication
             PartialSuccess = ReadBoolean();
             if (PartialSuccess)
             {
+#if NET || NETSTANDARD2_1_OR_GREATER
+                Message = string.Join(',', AllowedAuthentications);
+#else
                 Message = string.Join(",", AllowedAuthentications);
+#endif // NET || NETSTANDARD2_1_OR_GREATER
             }
         }
 
@@ -47,7 +51,9 @@ namespace Renci.SshNet.Messages.Authentication
         /// </summary>
         protected override void SaveData()
         {
+#pragma warning disable MA0025 // Implement the functionality instead of throwing NotImplementedException
             throw new NotImplementedException();
+#pragma warning restore MA0025 // Implement the functionality instead of throwing NotImplementedException
         }
 
         internal override void Process(Session session)

+ 2 - 1
src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs

@@ -12,7 +12,7 @@ namespace Renci.SshNet.Messages.Authentication
         /// <summary>
         /// Gets authentication responses.
         /// </summary>
-        public IList<string> Responses { get; private set; }
+        public List<string> Responses { get; private set; }
 
         /// <summary>
         /// Gets the size of the message in bytes.
@@ -48,6 +48,7 @@ namespace Renci.SshNet.Messages.Authentication
         protected override void SaveData()
         {
             Write((uint) Responses.Count);
+
             foreach (var response in Responses)
             {
                 Write(response);

+ 0 - 1
src/Renci.SshNet/Messages/Authentication/RequestMessage.cs

@@ -108,4 +108,3 @@ namespace Renci.SshNet.Messages.Authentication
         }
     }
 }
-

+ 1 - 1
src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs

@@ -6,7 +6,7 @@
     internal sealed class RequestMessageNone : RequestMessage
     {
         /// <summary>
-        /// Initializes a new instance of the <see cref="RequestMessagePassword"/> class.
+        /// Initializes a new instance of the <see cref="RequestMessageNone"/> class.
         /// </summary>
         /// <param name="serviceName">Name of the service.</param>
         /// <param name="username">Authentication username.</param>

+ 0 - 1
src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs

@@ -11,7 +11,6 @@
         /// </summary>
         public ChannelCloseMessage()
         {
-
         }
 
         /// <summary>

+ 0 - 1
src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs

@@ -11,7 +11,6 @@
         /// </summary>
         public ChannelEofMessage()
         {
-
         }
 
         /// <summary>

+ 0 - 1
src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs

@@ -11,7 +11,6 @@
         /// </summary>
         public ChannelFailureMessage()
         {
-
         }
 
         /// <summary>

+ 1 - 1
src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenInfo.cs

@@ -3,7 +3,7 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Base class for open channel messages
+    /// Base class for open channel messages.
     /// </summary>
     public abstract class ChannelOpenInfo : SshData
     {

+ 2 - 2
src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs

@@ -3,7 +3,7 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Used to open "direct-tcpip" channel type
+    /// Used to open "direct-tcpip" channel type.
     /// </summary>
     internal sealed class DirectTcpipChannelInfo : ChannelOpenInfo
     {
@@ -11,7 +11,7 @@ namespace Renci.SshNet.Messages.Connection
         private byte[] _originatorAddress;
 
         /// <summary>
-        /// Specifies channel open type
+        /// Specifies channel open type.
         /// </summary>
         public const string NAME = "direct-tcpip";
 

+ 20 - 8
src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs

@@ -3,10 +3,15 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Used to open "forwarded-tcpip" channel type
+    /// Used to open "forwarded-tcpip" channel type.
     /// </summary>
     internal sealed class ForwardedTcpipChannelInfo : ChannelOpenInfo
     {
+        /// <summary>
+        /// Specifies channel open type.
+        /// </summary>
+        public const string NAME = "forwarded-tcpip";
+
         private byte[] _connectedAddress;
         private byte[] _originatorAddress;
 
@@ -21,8 +26,8 @@ namespace Renci.SshNet.Messages.Connection
         }
 
         /// <summary>
-        /// Initializes a new <see cref="ForwardedTcpipChannelInfo"/> instance with the specified connector
-        /// address and port, and originator address and port.
+        /// Initializes a new instance of the <see cref="ForwardedTcpipChannelInfo"/> class with the
+        /// specified connector address and port, and originator address and port.
         /// </summary>
         public ForwardedTcpipChannelInfo(string connectedAddress, uint connectedPort, string originatorAddress, uint originatorPort)
         {
@@ -32,11 +37,6 @@ namespace Renci.SshNet.Messages.Connection
             OriginatorPort = originatorPort;
         }
 
-        /// <summary>
-        /// Specifies channel open type
-        /// </summary>
-        public const string NAME = "forwarded-tcpip";
-
         /// <summary>
         /// Gets the type of the channel to open.
         /// </summary>
@@ -51,6 +51,9 @@ namespace Renci.SshNet.Messages.Connection
         /// <summary>
         /// Gets the connected address.
         /// </summary>
+        /// <value>
+        /// The connected address.
+        /// </value>
         public string ConnectedAddress
         {
             get { return Utf8.GetString(_connectedAddress, 0, _connectedAddress.Length); }
@@ -60,11 +63,17 @@ namespace Renci.SshNet.Messages.Connection
         /// <summary>
         /// Gets the connected port.
         /// </summary>
+        /// <value>
+        /// The connected port.
+        /// </value>
         public uint ConnectedPort { get; private set; }
 
         /// <summary>
         /// Gets the originator address.
         /// </summary>
+        /// <value>
+        /// The originator address.
+        /// </value>
         public string OriginatorAddress
         {
             get { return Utf8.GetString(_originatorAddress, 0, _originatorAddress.Length); }
@@ -74,6 +83,9 @@ namespace Renci.SshNet.Messages.Connection
         /// <summary>
         /// Gets the originator port.
         /// </summary>
+        /// <value>
+        /// The originator port.
+        /// </value>
         public uint OriginatorPort { get; private set; }
 
         /// <summary>

+ 2 - 2
src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs

@@ -3,12 +3,12 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Used to open "session" channel type
+    /// Used to open "session" channel type.
     /// </summary>
     internal sealed class SessionChannelOpenInfo : ChannelOpenInfo
     {
         /// <summary>
-        /// Specifies channel open type
+        /// Specifies channel open type.
         /// </summary>
         public const string Name = "session";
 

+ 2 - 2
src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs

@@ -3,14 +3,14 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Used to open "x11" channel type
+    /// Used to open "x11" channel type.
     /// </summary>
     internal sealed class X11ChannelOpenInfo : ChannelOpenInfo
     {
         private byte[] _originatorAddress;
 
         /// <summary>
-        /// Specifies channel open type
+        /// Specifies channel open type.
         /// </summary>
         public const string Name = "x11";
 

+ 0 - 1
src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs

@@ -62,7 +62,6 @@
         /// </summary>
         public ChannelOpenFailureMessage()
         {
-
         }
 
         /// <summary>

+ 7 - 4
src/Renci.SshNet/Messages/Connection/ChannelOpenFailureReasons.cs

@@ -6,19 +6,22 @@
     internal enum ChannelOpenFailureReasons : uint
     {
         /// <summary>
-        /// SSH_OPEN_ADMINISTRATIVELY_PROHIBITED
+        /// SSH_OPEN_ADMINISTRATIVELY_PROHIBITED.
         /// </summary>
         AdministativelyProhibited = 1,
+
         /// <summary>
-        /// SSH_OPEN_CONNECT_FAILED
+        /// SSH_OPEN_CONNECT_FAILED.
         /// </summary>
         ConnectFailed = 2,
+
         /// <summary>
-        /// SSH_OPEN_UNKNOWN_CHANNEL_TYPE
+        /// SSH_OPEN_UNKNOWN_CHANNEL_TYPE.
         /// </summary>
         UnknownChannelType = 3,
+
         /// <summary>
-        /// SSH_OPEN_RESOURCE_SHORTAGE
+        /// SSH_OPEN_RESOURCE_SHORTAGE.
         /// </summary>
         ResourceShortage = 4
     }

+ 4 - 4
src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs

@@ -1,12 +1,12 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "break" type channel request information
+    /// Represents "break" type channel request information.
     /// </summary>
     internal sealed class BreakRequestInfo : RequestInfo
     {
         /// <summary>
-        /// Channel request name
+        /// Channel request name.
         /// </summary>
         public const string Name = "break";
 
@@ -43,7 +43,7 @@
         }
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="ExecRequestInfo"/> class.
+        /// Initializes a new instance of the <see cref="BreakRequestInfo"/> class.
         /// </summary>
         public BreakRequestInfo()
         {
@@ -51,7 +51,7 @@
         }
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="ExecRequestInfo"/> class.
+        /// Initializes a new instance of the <see cref="BreakRequestInfo"/> class.
         /// </summary>
         /// <param name="breakLength">Length of the break.</param>
         public BreakRequestInfo(uint breakLength)

+ 5 - 2
src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs

@@ -17,7 +17,10 @@
         /// </value>
         public string RequestName
         {
-            get { return _requestName; }
+            get
+            {
+                return _requestName;
+            }
             private set
             {
                 _requestName = value;
@@ -53,7 +56,7 @@
         /// </summary>
         public ChannelRequestMessage()
         {
-            //  Required for dynamically loading request type when it comes from the server
+            // Required for dynamically loading request type when it comes from the server
         }
 
         /// <summary>

+ 2 - 2
src/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs

@@ -1,12 +1,12 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "eow@openssh.com" type channel request information
+    /// Represents "eow@openssh.com" type channel request information.
     /// </summary>
     public class EndOfWriteRequestInfo : RequestInfo
     {
         /// <summary>
-        /// Channel request name
+        /// Channel request name.
         /// </summary>
         public const string Name = "eow@openssh.com";
 

+ 4 - 4
src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs

@@ -1,7 +1,7 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "env" type channel request information
+    /// Represents "env" type channel request information.
     /// </summary>
     internal sealed class EnvironmentVariableRequestInfo : RequestInfo
     {
@@ -9,7 +9,7 @@
         private byte[] _variableValue;
 
         /// <summary>
-        /// Channel request name
+        /// Channel request name.
         /// </summary>
         public const string Name = "env";
 
@@ -25,7 +25,7 @@
         }
 
         /// <summary>
-        /// Gets or sets the name of the variable.
+        /// Gets the name of the variable.
         /// </summary>
         /// <value>
         /// The name of the variable.
@@ -36,7 +36,7 @@
         }
 
         /// <summary>
-        /// Gets or sets the variable value.
+        /// Gets the value of the variable.
         /// </summary>
         /// <value>
         /// The variable value.

+ 3 - 3
src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs

@@ -1,7 +1,7 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "exit-signal" type channel request information
+    /// Represents "exit-signal" type channel request information.
     /// </summary>
     internal sealed class ExitSignalRequestInfo : RequestInfo
     {
@@ -10,7 +10,7 @@
         private byte[] _language;
 
         /// <summary>
-        /// Channel request name
+        /// Channel request name.
         /// </summary>
         public const string Name = "exit-signal";
 
@@ -41,7 +41,7 @@
         /// Gets a value indicating whether core is dumped.
         /// </summary>
         /// <value>
-        ///   <see langword="true"/> if core is dumped; otherwise, <see langword="false"/>.
+        /// <see langword="true"/> if core is dumped; otherwise, <see langword="false"/>.
         /// </value>
         public bool CoreDumped { get; private set; }
 

+ 2 - 2
src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs

@@ -1,7 +1,7 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "exit-status" type channel request information
+    /// Represents "exit-status" type channel request information.
     /// </summary>
     internal sealed class ExitStatusRequestInfo : RequestInfo
     {
@@ -30,7 +30,7 @@
         {
             get
             {
-                 var capacity = base.BufferCapacity;
+                var capacity = base.BufferCapacity;
                 capacity += 4; // ExitStatus
                 return capacity;
             }

+ 3 - 3
src/Renci.SshNet/Messages/Connection/ChannelRequest/KeepAliveRequestInfo.cs

@@ -1,12 +1,12 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "keepalive@openssh.com" type channel request information
+    /// Represents "keepalive@openssh.com" type channel request information.
     /// </summary>
     public class KeepAliveRequestInfo : RequestInfo
     {
         /// <summary>
-        /// Channel request name
+        /// Channel request name.
         /// </summary>
         public const string Name = "keepalive@openssh.com";
 
@@ -22,7 +22,7 @@
         }
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="EndOfWriteRequestInfo"/> class.
+        /// Initializes a new instance of the <see cref="KeepAliveRequestInfo"/> class.
         /// </summary>
         public KeepAliveRequestInfo()
         {

+ 1 - 1
src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs → src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalRequestInfo.cs

@@ -141,7 +141,7 @@ namespace Renci.SshNet.Messages.Connection
                 // write total length of encoded terminal modes, which is 1 bytes for the opcode / terminal mode
                 // and 4 bytes for the uint argument for each entry; the encoded terminal modes are terminated by
                 // opcode TTY_OP_END (which is 1 byte)
-                Write((uint) TerminalModeValues.Count*(1 + 4) + 1);
+                Write(((uint) TerminalModeValues.Count*(1 + 4)) + 1);
 
                 foreach (var item in TerminalModeValues)
                 {

+ 1 - 1
src/Renci.SshNet/Messages/Connection/ChannelRequest/RequestInfo.cs

@@ -19,7 +19,7 @@ namespace Renci.SshNet.Messages.Connection
         /// Gets or sets a value indicating whether reply message is needed.
         /// </summary>
         /// <value>
-        ///   <see langword="true"/> if reply message is needed; otherwise, <see langword="false"/>.
+        /// <see langword="true"/> if reply message is needed; otherwise, <see langword="false"/>.
         /// </value>
         public bool WantReply { get; protected set; }
 

+ 2 - 2
src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs

@@ -1,12 +1,12 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "shell" type channel request information
+    /// Represents "shell" type channel request information.
     /// </summary>
     internal sealed class ShellRequestInfo : RequestInfo
     {
         /// <summary>
-        /// Channel request name
+        /// Channel request name.
         /// </summary>
         public const string Name = "shell";
 

+ 1 - 1
src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs

@@ -1,7 +1,7 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "signal" type channel request information
+    /// Represents "signal" type channel request information.
     /// </summary>
     internal sealed class SignalRequestInfo : RequestInfo
     {

+ 2 - 2
src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs

@@ -1,14 +1,14 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "subsystem" type channel request information
+    /// Represents "subsystem" type channel request information.
     /// </summary>
     internal sealed class SubsystemRequestInfo : RequestInfo
     {
         private byte[] _subsystemName;
 
         /// <summary>
-        /// Channel request name
+        /// Channel request name.
         /// </summary>
         public const string Name = "subsystem";
 

+ 2 - 2
src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs

@@ -1,12 +1,12 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "window-change" type channel request information
+    /// Represents "window-change" type channel request information.
     /// </summary>
     internal sealed class WindowChangeRequestInfo : RequestInfo
     {
         /// <summary>
-        /// Channe request name
+        /// Channe request name.
         /// </summary>
         public const string Name = "window-change";
 

+ 1 - 1
src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs

@@ -32,7 +32,7 @@
         public bool IsSingleConnection { get; set; }
 
         /// <summary>
-        /// Gets or sets the authentication protocol.
+        /// Gets the authentication protocol.
         /// </summary>
         /// <value>
         /// The authentication protocol.

+ 2 - 2
src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs

@@ -1,7 +1,7 @@
 namespace Renci.SshNet.Messages.Connection
 {
     /// <summary>
-    /// Represents "xon-xoff" type channel request information
+    /// Represents "xon-xoff" type channel request information.
     /// </summary>
     internal sealed class XonXoffRequestInfo : RequestInfo
     {
@@ -25,7 +25,7 @@
         /// Gets or sets a value indicating whether client can do.
         /// </summary>
         /// <value>
-        ///   <see langword="true"/> if client can do; otherwise, <see langword="false"/>.
+        /// <see langword="true"/> if client can do; otherwise, <see langword="false"/>.
         /// </value>
         public bool ClientCanDo { get; set; }
 

+ 0 - 1
src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs

@@ -11,7 +11,6 @@
         /// </summary>
         public ChannelSuccessMessage()
         {
-
         }
 
         /// <summary>

+ 1 - 1
src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs

@@ -23,7 +23,7 @@
         /// Gets a value indicating whether message reply should be sent..
         /// </summary>
         /// <value>
-        ///   <see langword="true"/> if message reply should be sent; otherwise, <see langword="false"/>.
+        /// <see langword="true"/> if message reply should be sent; otherwise, <see langword="false"/>.
         /// </value>
         public bool WantReply { get; private set; }
 

+ 3 - 2
src/Renci.SshNet/Messages/Connection/GlobalRequestName.cs

@@ -6,11 +6,12 @@
     public enum GlobalRequestName
     {
         /// <summary>
-        /// tcpip-forward
+        /// tcpip-forward.
         /// </summary>
         TcpIpForward,
+
         /// <summary>
-        /// cancel-tcpip-forward
+        /// cancel-tcpip-forward.
         /// </summary>
         CancelTcpIpForward,
     }

+ 59 - 54
src/Renci.SshNet/Messages/Message.cs

@@ -8,7 +8,7 @@ using Renci.SshNet.Compression;
 namespace Renci.SshNet.Messages
 {
     /// <summary>
-    /// Base class for all SSH protocol messages
+    /// Base class for all SSH protocol messages.
     /// </summary>
     public abstract class Message : SshData
     {
@@ -29,6 +29,7 @@ namespace Renci.SshNet.Messages
         /// <summary>
         /// Writes the message to the specified <see cref="SshDataStream"/>.
         /// </summary>
+        /// <param name="stream">The <see cref="SshDataStream"/> to write the message to.</param>
         protected override void WriteBytes(SshDataStream stream)
         {
             var enumerator = GetType().GetCustomAttributes<MessageAttribute>(inherit: true).GetEnumerator();
@@ -55,58 +56,61 @@ namespace Renci.SshNet.Messages
 
             var messageLength = BufferCapacity;
 
-            SshDataStream sshDataStream;
-
             if (messageLength == -1 || compressor != null)
             {
-                sshDataStream = new SshDataStream(DefaultCapacity);
+                using (var sshDataStream = new SshDataStream(DefaultCapacity))
+                {
+                    // skip:
+                    // * 4 bytes for the outbound packet sequence
+                    // * 4 bytes for the packet data length
+                    // * one byte for the packet padding length
+                    _ = sshDataStream.Seek(outboundPacketSequenceSize + 4 + 1, SeekOrigin.Begin);
 
-                // skip:
-                // * 4 bytes for the outbound packet sequence
-                // * 4 bytes for the packet data length
-                // * one byte for the packet padding length
-                _ = sshDataStream.Seek(outboundPacketSequenceSize + 4 + 1, SeekOrigin.Begin);
+                    if (compressor != null)
+                    {
+                        // obtain uncompressed message payload
+                        using (var uncompressedDataStream = new SshDataStream(messageLength != -1 ? messageLength : DefaultCapacity))
+                        {
+                            WriteBytes(uncompressedDataStream);
 
-                if (compressor != null)
-                {
-                    // obtain uncompressed message payload
-                    var uncompressedDataStream = new SshDataStream(messageLength != -1 ? messageLength : DefaultCapacity);
-                    WriteBytes(uncompressedDataStream);
+                            // compress message payload
+                            var compressedMessageData = compressor.Compress(uncompressedDataStream.ToArray());
 
-                    // compress message payload
-                    var compressedMessageData = compressor.Compress(uncompressedDataStream.ToArray());
+                            // add compressed message payload
+                            sshDataStream.Write(compressedMessageData, 0, compressedMessageData.Length);
+                        }
+                    }
+                    else
+                    {
+                        // add message payload
+                        WriteBytes(sshDataStream);
+                    }
 
-                    // add compressed message payload
-                    sshDataStream.Write(compressedMessageData, 0, compressedMessageData.Length);
-                }
-                else
-                {
-                    // add message payload
-                    WriteBytes(sshDataStream);
-                }
+                    messageLength = (int) sshDataStream.Length - (outboundPacketSequenceSize + 4 + 1);
 
-                messageLength = (int) sshDataStream.Length - (outboundPacketSequenceSize + 4 + 1);
+                    var packetLength = messageLength + 4 + 1;
 
-                var packetLength = messageLength + 4 + 1;
+                    // determine the padding length
+                    var paddingLength = GetPaddingLength(paddingMultiplier, packetLength);
 
-                // determine the padding length
-                var paddingLength = GetPaddingLength(paddingMultiplier, packetLength);
+                    // add padding bytes
+                    var paddingBytes = new byte[paddingLength];
+                    CryptoAbstraction.GenerateRandom(paddingBytes);
+                    sshDataStream.Write(paddingBytes, 0, paddingLength);
 
-                // add padding bytes
-                var paddingBytes = new byte[paddingLength];
-                CryptoAbstraction.GenerateRandom(paddingBytes);
-                sshDataStream.Write(paddingBytes, 0, paddingLength);
+                    var packetDataLength = GetPacketDataLength(messageLength, paddingLength);
 
-                var packetDataLength = GetPacketDataLength(messageLength, paddingLength);
+                    // skip bytes for outbound packet sequence
+                    _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin);
 
-                // skip bytes for outbound packet sequence
-                _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin);
+                    // add packet data length
+                    sshDataStream.Write(packetDataLength);
 
-                // add packet data length
-                sshDataStream.Write(packetDataLength);
+                    // add packet padding length
+                    sshDataStream.WriteByte(paddingLength);
 
-                // add packet padding length
-                sshDataStream.WriteByte(paddingLength);
+                    return sshDataStream.ToArray();
+                }
             }
             else
             {
@@ -118,27 +122,28 @@ namespace Renci.SshNet.Messages
                 var packetDataLength = GetPacketDataLength(messageLength, paddingLength);
 
                 // lets construct an SSH data stream of the exact size required
-                sshDataStream = new SshDataStream(packetLength + paddingLength + outboundPacketSequenceSize);
+                using (var sshDataStream = new SshDataStream(packetLength + paddingLength + outboundPacketSequenceSize))
+                {
+                    // skip bytes for outbound packet sequenceSize
+                    _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin);
 
-                // skip bytes for outbound packet sequenceSize
-                _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin);
+                    // add packet data length
+                    sshDataStream.Write(packetDataLength);
 
-                // add packet data length
-                sshDataStream.Write(packetDataLength);
+                    // add packet padding length
+                    sshDataStream.WriteByte(paddingLength);
 
-                // add packet padding length
-                sshDataStream.WriteByte(paddingLength);
+                    // add message payload
+                    WriteBytes(sshDataStream);
 
-                // add message payload
-                WriteBytes(sshDataStream);
+                    // add padding bytes
+                    var paddingBytes = new byte[paddingLength];
+                    CryptoAbstraction.GenerateRandom(paddingBytes);
+                    sshDataStream.Write(paddingBytes, 0, paddingLength);
 
-                // add padding bytes
-                var paddingBytes = new byte[paddingLength];
-                CryptoAbstraction.GenerateRandom(paddingBytes);
-                sshDataStream.Write(paddingBytes, 0, paddingLength);
+                    return sshDataStream.ToArray();
+                }
             }
-
-            return sshDataStream.ToArray();
         }
 
         private static uint GetPacketDataLength(int messageLength, byte paddingLength)

+ 4 - 5
src/Renci.SshNet/Messages/MessageAttribute.cs

@@ -2,7 +2,6 @@
 
 namespace Renci.SshNet.Messages
 {
-
     /// <summary>
     /// Indicates that a class represents SSH message. This class cannot be inherited.
     /// </summary>
@@ -10,20 +9,20 @@ namespace Renci.SshNet.Messages
     public sealed class MessageAttribute : Attribute
     {
         /// <summary>
-        /// Gets or sets message name as defined in RFC 4250.
+        /// Gets the message name as defined in RFC 4250.
         /// </summary>
         /// <value>
         /// The name.
         /// </value>
-        public string Name { get; set; }
+        public string Name { get; }
 
         /// <summary>
-        /// Gets or sets message number as defined in RFC 4250.
+        /// Gets the message number as defined in RFC 4250.
         /// </summary>
         /// <value>
         /// The number.
         /// </value>
-        public byte Number { get; set; }
+        public byte Number { get; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="MessageAttribute"/> class.

+ 3 - 3
src/Renci.SshNet/Messages/ServiceName.cs

@@ -1,17 +1,17 @@
 namespace Renci.SshNet.Messages
 {
     /// <summary>
-    /// Specifies list of supported services
+    /// Specifies list of supported services.
     /// </summary>
     public enum ServiceName
     {
         /// <summary>
-        /// ssh-userauth
+        /// ssh-userauth.
         /// </summary>
         UserAuthentication,
 
         /// <summary>
-        /// ssh-connection
+        /// ssh-connection.
         /// </summary>
         Connection
     }

+ 1 - 1
src/Renci.SshNet/Messages/Transport/DebugMessage.cs

@@ -13,7 +13,7 @@
         /// Gets a value indicating whether the message to be always displayed.
         /// </summary>
         /// <value>
-        /// 	<see langword="true"/> if the message always to be displayed; otherwise, <see langword="false"/>.
+        /// <see langword="true"/> if the message always to be displayed; otherwise, <see langword="false"/>.
         /// </value>
         public bool IsAlwaysDisplay { get; private set; }
 

+ 33 - 16
src/Renci.SshNet/Messages/Transport/DisconnectReason.cs

@@ -9,65 +9,82 @@
         /// Disconnect reason is not provided.
         /// </summary>
         None = 0,
+
         /// <summary>
-        /// SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT
+        /// SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT.
         /// </summary>
         HostNotAllowedToConnect = 1,
+
         /// <summary>
-        /// SSH_DISCONNECT_PROTOCOL_ERROR
+        /// SSH_DISCONNECT_PROTOCOL_ERROR.
         /// </summary>
         ProtocolError = 2,
+
         /// <summary>
-        /// SSH_DISCONNECT_KEY_EXCHANGE_FAILED
+        /// SSH_DISCONNECT_KEY_EXCHANGE_FAILED.
         /// </summary>
         KeyExchangeFailed = 3,
+
         /// <summary>
-        /// SSH_DISCONNECT_RESERVED
+        /// SSH_DISCONNECT_RESERVED.
         /// </summary>
+#pragma warning disable CA1700 // Do not name enum values 'Reserved'
         Reserved = 4,
+#pragma warning restore CA1700 // Do not name enum values 'Reserved'
+
         /// <summary>
-        /// SSH_DISCONNECT_MAC_ERROR
+        /// SSH_DISCONNECT_MAC_ERROR.
         /// </summary>
         MacError = 5,
+
         /// <summary>
-        /// SSH_DISCONNECT_COMPRESSION_ERROR
+        /// SSH_DISCONNECT_COMPRESSION_ERROR.
         /// </summary>
         CompressionError = 6,
+
         /// <summary>
-        /// SSH_DISCONNECT_SERVICE_NOT_AVAILABLE
+        /// SSH_DISCONNECT_SERVICE_NOT_AVAILABLE.
         /// </summary>
         ServiceNotAvailable = 7,
+
         /// <summary>
-        /// SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED
+        /// SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED.
         /// </summary>
         ProtocolVersionNotSupported = 8,
+
         /// <summary>
-        /// SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE
+        /// SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE.
         /// </summary>
         HostKeyNotVerifiable = 9,
+
         /// <summary>
-        /// SSH_DISCONNECT_CONNECTION_LOST
+        /// SSH_DISCONNECT_CONNECTION_LOST.
         /// </summary>
         ConnectionLost = 10,
+
         /// <summary>
-        /// SSH_DISCONNECT_BY_APPLICATION
+        /// SSH_DISCONNECT_BY_APPLICATION.
         /// </summary>
         ByApplication = 11,
+
         /// <summary>
-        /// SSH_DISCONNECT_TOO_MANY_CONNECTIONS
+        /// SSH_DISCONNECT_TOO_MANY_CONNECTIONS.
         /// </summary>
         TooManyConnections = 12,
+
         /// <summary>
-        /// SSH_DISCONNECT_AUTH_CANCELLED_BY_USER
+        /// SSH_DISCONNECT_AUTH_CANCELLED_BY_USER.
         /// </summary>
         AuthenticationCanceledByUser = 13,
+
         /// <summary>
-        /// SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE
+        /// SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE.
         /// </summary>
         NoMoreAuthenticationMethodsAvailable = 14,
+
         /// <summary>
-        /// SSH_DISCONNECT_ILLEGAL_USER_NAME
+        /// SSH_DISCONNECT_ILLEGAL_USER_NAME.
         /// </summary>
-        IllegalUserName = 15,
+        IllegalUserName = 15
     }
 }

+ 3 - 1
src/Renci.SshNet/Messages/Transport/IKeyExchangedAllowed.cs

@@ -1,9 +1,11 @@
 namespace Renci.SshNet.Messages.Transport
 {
     /// <summary>
-    /// Indicates that message that implement this interface is allowed during key exchange phase
+    /// Indicates that message that implement this interface is allowed during key exchange phase.
     /// </summary>
+#pragma warning disable CA1040 // Avoid empty interfaces
     public interface IKeyExchangedAllowed
+#pragma warning restore CA1040 // Avoid empty interfaces
     {
     }
 }

Some files were not shown because too many files changed in this diff