From 7b3ea80999c4a8d4ba13144df3aacec7205844ef Mon Sep 17 00:00:00 2001 From: Marius Thesing Date: Thu, 5 Sep 2024 19:45:05 +0200 Subject: [PATCH] fix "client not connected" after SFTP reconnect if the server closes the session and the client reconnects, this currently leads to a broken state because the session is re-created, but the SFTP subsession is not and still references the old session. This causes all operations to fail with "client not connected" or even throwing the "An established connection was aborted by the server." exception of the old session. Always re-create the SFTP subsession to fix this. fixes #1474 --- src/Renci.SshNet/SftpClient.cs | 11 +---- .../ConnectivityTests.cs | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index b82e605cc..d4d04183d 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -2496,15 +2496,8 @@ protected override void OnConnected() { base.OnConnected(); - var sftpSession = _sftpSession; - if (sftpSession is null) - { - _sftpSession = CreateAndConnectToSftpSession(); - } - else if (!sftpSession.IsOpen) - { - sftpSession.Connect(); - } + _sftpSession?.Dispose(); + _sftpSession = CreateAndConnectToSftpSession(); } /// diff --git a/test/Renci.SshNet.IntegrationTests/ConnectivityTests.cs b/test/Renci.SshNet.IntegrationTests/ConnectivityTests.cs index 16b80e161..3fae0a8dc 100644 --- a/test/Renci.SshNet.IntegrationTests/ConnectivityTests.cs +++ b/test/Renci.SshNet.IntegrationTests/ConnectivityTests.cs @@ -326,6 +326,54 @@ public async Task SftpClient_HandleSftpSessionCloseAsync() } } + [TestMethod] + public void SftpClient_HandleSftpSessionAbortByServer() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + Assert.IsTrue(client.IsConnected); + + _sshConnectionDisruptor.BreakConnections(); + WaitForConnectionInterruption(client); + Assert.IsFalse(client.IsConnected); + + client.Connect(); + Assert.IsTrue(client.IsConnected); + + foreach (var file in client.ListDirectory(".")) + { + } + + client.Disconnect(); + Assert.IsFalse(client.IsConnected); + } + } + + [TestMethod] + public async Task SftpClient_HandleSftpSessionAbortByServerAsync() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + await client.ConnectAsync(CancellationToken.None); + Assert.IsTrue(client.IsConnected); + + _sshConnectionDisruptor.BreakConnections(); + WaitForConnectionInterruption(client); + Assert.IsFalse(client.IsConnected); + + await client.ConnectAsync(CancellationToken.None); + Assert.IsTrue(client.IsConnected); + + await foreach (var file in client.ListDirectoryAsync(".", CancellationToken.None)) + { + } + + client.Disconnect(); + Assert.IsFalse(client.IsConnected); + } + } + [TestMethod] public void Common_DetectSessionKilledOnServer() {