diff --git a/.editorconfig b/.editorconfig
index 562309d42..c897d8a93 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -195,6 +195,9 @@ dotnet_diagnostic.S2971.severity = none
# This is rather harmless.
dotnet_diagnostic.S3218.severity = none
+# S3236: Remove this argument from the method call; it hides the caller information.
+dotnet_diagnostic.S3236.severity = none
+
# S3267: Loops should be simplified with "LINQ" expressions
# https://rules.sonarsource.com/csharp/RSPEC-3267
#
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 6e4b721d2..458e018c5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -17,13 +17,13 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 8.0.x
+ dotnet-version: 9.0.x
- name: Build Unit Tests .NET
- run: dotnet build -f net8.0 test/Renci.SshNet.Tests/
+ run: dotnet build -f net9.0 test/Renci.SshNet.Tests/
- name: Build IntegrationTests .NET
- run: dotnet build -f net8.0 test/Renci.SshNet.IntegrationTests/
+ run: dotnet build -f net9.0 test/Renci.SshNet.IntegrationTests/
- name: Build IntegrationTests .NET Framework
run: dotnet build -f net48 test/Renci.SshNet.IntegrationTests/
@@ -31,25 +31,25 @@ jobs:
- name: Run Unit Tests .NET
run: |
dotnet test \
- -f net8.0 \
+ -f net9.0 \
--no-build \
--logger "console;verbosity=normal" \
--logger GitHubActions \
-p:CollectCoverage=true \
-p:CoverletOutputFormat=cobertura \
- -p:CoverletOutput=../../coverlet/linux_unit_test_net_8_coverage.xml \
+ -p:CoverletOutput=../../coverlet/linux_unit_test_net_9_coverage.xml \
test/Renci.SshNet.Tests/
- name: Run Integration Tests .NET
run: |
dotnet test \
- -f net8.0 \
+ -f net9.0 \
--no-build \
--logger "console;verbosity=normal" \
--logger GitHubActions \
-p:CollectCoverage=true \
-p:CoverletOutputFormat=cobertura \
- -p:CoverletOutput=../../coverlet/linux_integration_test_net_8_coverage.xml \
+ -p:CoverletOutput=../../coverlet/linux_integration_test_net_9_coverage.xml \
test/Renci.SshNet.IntegrationTests/
# Also run a subset of the integration tests targeting netfx using mono. This is a temporary measure to get
@@ -111,13 +111,13 @@ jobs:
- name: Run Unit Tests .NET
run: |
dotnet test `
- -f net8.0 `
+ -f net9.0 `
--no-build `
--logger "console;verbosity=normal" `
--logger GitHubActions `
-p:CollectCoverage=true `
-p:CoverletOutputFormat=cobertura `
- -p:CoverletOutput=../../coverlet/windows_unit_test_net_8_coverage.xml `
+ -p:CoverletOutput=../../coverlet/windows_unit_test_net_9_coverage.xml `
test/Renci.SshNet.Tests/
- name: Run Unit Tests .NET Framework
diff --git a/global.json b/global.json
index d07970ac2..f65788943 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.100",
+ "version": "9.0.100",
"rollForward": "latestMajor"
}
}
diff --git a/src/Renci.SshNet/Channels/Channel.cs b/src/Renci.SshNet/Channels/Channel.cs
index 4c0909f26..ca8e910fa 100644
--- a/src/Renci.SshNet/Channels/Channel.cs
+++ b/src/Renci.SshNet/Channels/Channel.cs
@@ -14,8 +14,8 @@ namespace Renci.SshNet.Channels
///
internal abstract class Channel : IChannel
{
- private readonly object _serverWindowSizeLock = new object();
- private readonly object _messagingLock = new object();
+ private readonly Lock _serverWindowSizeLock = new Lock();
+ private readonly Lock _messagingLock = new Lock();
private readonly uint _initialWindowSize;
private readonly ISession _session;
private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(initialState: false);
diff --git a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs
index 6a07d59b0..7b00c3bae 100644
--- a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs
+++ b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs
@@ -14,7 +14,7 @@ namespace Renci.SshNet.Channels
///
internal sealed class ChannelDirectTcpip : ClientChannel, IChannelDirectTcpip
{
- private readonly object _socketLock = new object();
+ private readonly Lock _socketLock = new Lock();
private EventWaitHandle _channelOpen = new AutoResetEvent(initialState: false);
private EventWaitHandle _channelData = new AutoResetEvent(initialState: false);
diff --git a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs
index 07271c834..2cc0c16f8 100644
--- a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs
+++ b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs
@@ -1,6 +1,9 @@
using System;
using System.Net;
using System.Net.Sockets;
+#if NET9_0_OR_GREATER
+using System.Threading;
+#endif
using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
@@ -13,7 +16,7 @@ namespace Renci.SshNet.Channels
///
internal sealed class ChannelForwardedTcpip : ServerChannel, IChannelForwardedTcpip
{
- private readonly object _socketShutdownAndCloseLock = new object();
+ private readonly Lock _socketShutdownAndCloseLock = new Lock();
private Socket _socket;
private IForwardedPort _forwardedPort;
diff --git a/src/Renci.SshNet/Common/Lock.cs b/src/Renci.SshNet/Common/Lock.cs
new file mode 100644
index 000000000..fc29776d3
--- /dev/null
+++ b/src/Renci.SshNet/Common/Lock.cs
@@ -0,0 +1,19 @@
+#if !NET9_0_OR_GREATER
+using System.Threading;
+
+namespace Renci.SshNet.Common
+{
+ internal sealed class Lock
+ {
+ public bool TryEnter()
+ {
+ return Monitor.TryEnter(this);
+ }
+
+ public void Exit()
+ {
+ Monitor.Exit(this);
+ }
+ }
+}
+#endif
diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj
index bf822da85..d00f773fa 100644
--- a/src/Renci.SshNet/Renci.SshNet.csproj
+++ b/src/Renci.SshNet/Renci.SshNet.csproj
@@ -4,7 +4,7 @@
Renci.SshNet
SSH.NET
SSH.NET
- net462;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0
+ net462;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0;net9.0
diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs
index d914858bb..63560b685 100644
--- a/src/Renci.SshNet/Session.cs
+++ b/src/Renci.SshNet/Session.cs
@@ -80,7 +80,7 @@ public class Session : ISession
/// Holds an object that is used to ensure only a single thread can read from
/// at any given time.
///
- private readonly object _socketReadLock = new object();
+ private readonly Lock _socketReadLock = new Lock();
///
/// Holds an object that is used to ensure only a single thread can write to
@@ -90,7 +90,7 @@ public class Session : ISession
/// This is also used to ensure that is
/// incremented atomatically.
///
- private readonly object _socketWriteLock = new object();
+ private readonly Lock _socketWriteLock = new Lock();
///
/// Holds an object that is used to ensure only a single thread can dispose
@@ -1894,7 +1894,7 @@ private bool IsSocketConnected()
return false;
}
- if (!Monitor.TryEnter(_socketReadLock))
+ if (!_socketReadLock.TryEnter())
{
return true;
}
@@ -1906,7 +1906,7 @@ private bool IsSocketConnected()
}
finally
{
- Monitor.Exit(_socketReadLock);
+ _socketReadLock.Exit();
}
}
finally
diff --git a/src/Renci.SshNet/Sftp/SftpFileStream.cs b/src/Renci.SshNet/Sftp/SftpFileStream.cs
index 97b0f393a..8ef5d960d 100644
--- a/src/Renci.SshNet/Sftp/SftpFileStream.cs
+++ b/src/Renci.SshNet/Sftp/SftpFileStream.cs
@@ -18,7 +18,7 @@ namespace Renci.SshNet.Sftp
#pragma warning restore IDE0079
public class SftpFileStream : Stream
{
- private readonly object _lock = new object();
+ private readonly Lock _lock = new Lock();
private readonly int _readBufferSize;
private readonly int _writeBufferSize;
diff --git a/src/Renci.SshNet/SshMessageFactory.cs b/src/Renci.SshNet/SshMessageFactory.cs
index c9b8e8c10..e023f5bb0 100644
--- a/src/Renci.SshNet/SshMessageFactory.cs
+++ b/src/Renci.SshNet/SshMessageFactory.cs
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+#if NET9_0_OR_GREATER
+using System.Threading;
+#endif
using Renci.SshNet.Common;
using Renci.SshNet.Messages;
@@ -14,7 +17,7 @@ internal sealed class SshMessageFactory
{
private readonly MessageMetadata[] _enabledMessagesByNumber;
private readonly bool[] _activatedMessagesById;
- private readonly object _lock = new object();
+ private readonly Lock _lock = new Lock();
internal static readonly MessageMetadata[] AllMessages = new MessageMetadata[]
{
diff --git a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj
index d07465ef1..f421ad23f 100644
--- a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj
+++ b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ net9.0
enable
enable
diff --git a/test/Renci.SshNet.IntegrationBenchmarks/Renci.SshNet.IntegrationBenchmarks.csproj b/test/Renci.SshNet.IntegrationBenchmarks/Renci.SshNet.IntegrationBenchmarks.csproj
index 0f149c013..3f32fe9bb 100644
--- a/test/Renci.SshNet.IntegrationBenchmarks/Renci.SshNet.IntegrationBenchmarks.csproj
+++ b/test/Renci.SshNet.IntegrationBenchmarks/Renci.SshNet.IntegrationBenchmarks.csproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ net9.0
enable
enable
diff --git a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj
index 5fa390ad4..06ae83ea6 100644
--- a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj
+++ b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj
@@ -1,7 +1,7 @@
- net48;net8.0
+ net48;net8.0;net9.0
enable
true
$(NoWarn);SYSLIB0021;SYSLIB1045;SYSLIB0014;IDE0220;IDE0010
diff --git a/test/Renci.SshNet.Tests/Common/AsyncSocketListener.cs b/test/Renci.SshNet.Tests/Common/AsyncSocketListener.cs
index a27db194d..23e48799a 100644
--- a/test/Renci.SshNet.Tests/Common/AsyncSocketListener.cs
+++ b/test/Renci.SshNet.Tests/Common/AsyncSocketListener.cs
@@ -4,6 +4,8 @@
using System.Net;
using System.Net.Sockets;
using System.Threading;
+
+using Renci.SshNet.Common;
#pragma warning restore IDE0005
namespace Renci.SshNet.Tests.Common
@@ -13,7 +15,7 @@ public class AsyncSocketListener : IDisposable
private readonly IPEndPoint _endPoint;
private readonly ManualResetEvent _acceptCallbackDone;
private readonly List _connectedClients;
- private readonly object _syncLock;
+ private readonly Lock _syncLock;
private Socket _listener;
private Thread _receiveThread;
private bool _started;
@@ -31,7 +33,7 @@ public AsyncSocketListener(IPEndPoint endPoint)
_endPoint = endPoint;
_acceptCallbackDone = new ManualResetEvent(false);
_connectedClients = new List();
- _syncLock = new object();
+ _syncLock = new Lock();
ShutdownRemoteCommunicationSocket = true;
}
diff --git a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj
index df872d754..4b91384d3 100644
--- a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj
+++ b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj
@@ -1,7 +1,7 @@
- net462;net6.0;net7.0;net8.0
+ net462;net6.0;net7.0;net8.0;net9.0