Skip to content

Commit 6669309

Browse files
authored
fix "client not connected" after SFTP reconnect (#1484)
* 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 * Dispose old session on reconnect
1 parent a157dd3 commit 6669309

File tree

3 files changed

+60
-9
lines changed

3 files changed

+60
-9
lines changed

src/Renci.SshNet/BaseClient.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,11 @@ public void Connect()
240240
var session = Session;
241241
if (session is null || !session.IsConnected)
242242
{
243+
if (session is not null)
244+
{
245+
DisposeSession(session);
246+
}
247+
243248
Session = CreateAndConnectSession();
244249
}
245250

@@ -304,6 +309,11 @@ public async Task ConnectAsync(CancellationToken cancellationToken)
304309
var session = Session;
305310
if (session is null || !session.IsConnected)
306311
{
312+
if (session is not null)
313+
{
314+
DisposeSession(session);
315+
}
316+
307317
Session = await CreateAndConnectSessionAsync(cancellationToken).ConfigureAwait(false);
308318
}
309319

src/Renci.SshNet/SftpClient.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2496,15 +2496,8 @@ protected override void OnConnected()
24962496
{
24972497
base.OnConnected();
24982498

2499-
var sftpSession = _sftpSession;
2500-
if (sftpSession is null)
2501-
{
2502-
_sftpSession = CreateAndConnectToSftpSession();
2503-
}
2504-
else if (!sftpSession.IsOpen)
2505-
{
2506-
sftpSession.Connect();
2507-
}
2499+
_sftpSession?.Dispose();
2500+
_sftpSession = CreateAndConnectToSftpSession();
25082501
}
25092502

25102503
/// <summary>

test/Renci.SshNet.IntegrationTests/ConnectivityTests.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,54 @@ public async Task SftpClient_HandleSftpSessionCloseAsync()
326326
}
327327
}
328328

329+
[TestMethod]
330+
public void SftpClient_HandleSftpSessionAbortByServer()
331+
{
332+
using (var client = new SftpClient(_connectionInfoFactory.Create()))
333+
{
334+
client.Connect();
335+
Assert.IsTrue(client.IsConnected);
336+
337+
_sshConnectionDisruptor.BreakConnections();
338+
WaitForConnectionInterruption(client);
339+
Assert.IsFalse(client.IsConnected);
340+
341+
client.Connect();
342+
Assert.IsTrue(client.IsConnected);
343+
344+
foreach (var file in client.ListDirectory("."))
345+
{
346+
}
347+
348+
client.Disconnect();
349+
Assert.IsFalse(client.IsConnected);
350+
}
351+
}
352+
353+
[TestMethod]
354+
public async Task SftpClient_HandleSftpSessionAbortByServerAsync()
355+
{
356+
using (var client = new SftpClient(_connectionInfoFactory.Create()))
357+
{
358+
await client.ConnectAsync(CancellationToken.None);
359+
Assert.IsTrue(client.IsConnected);
360+
361+
_sshConnectionDisruptor.BreakConnections();
362+
WaitForConnectionInterruption(client);
363+
Assert.IsFalse(client.IsConnected);
364+
365+
await client.ConnectAsync(CancellationToken.None);
366+
Assert.IsTrue(client.IsConnected);
367+
368+
await foreach (var file in client.ListDirectoryAsync(".", CancellationToken.None))
369+
{
370+
}
371+
372+
client.Disconnect();
373+
Assert.IsFalse(client.IsConnected);
374+
}
375+
}
376+
329377
[TestMethod]
330378
public void Common_DetectSessionKilledOnServer()
331379
{

0 commit comments

Comments
 (0)