SFTP: "client not connected" after server closed connection
Closed this issue · 4 comments
As reported by multiple people here #843 (comment) , #1362 does not completely fix the general issue. A "client not connected" exception can still happen after checking for IsConnected
.
I will try to reproduce this and create a PR.
This issue happened only if I didn't set the KeepAliveInternal
. Figured it might be important for your tests or for someone trying to avoid the issue.
As mention by Rob-Hague in #843 (comment) , this can't really be fixed. IsConnected
just can't be relied upon because you have to actually send data to notice that the connection is gone.
Even if the check that throws the exception would be removed, the sending itself would fail. The only way to avoid this, is to configure a keep alive on the client or the server.
Reopening this. We have a case where the keep alive doesn't help. Affected server is PSFTPd .
I think there is at least one issue in SSH.NET: if the "Client not connected" exception happens, I would expect IsConnected
to be false
after this, but it seems like it stays true
so another OpenAsync
fails again with Client not connected.
.
Idea why the keep alive doesn't help: maybe the SFTP subsession needs its own keep-alive? Or maybe the server is just not reacting to keep alives and closing the session either way....
fyi @Rob-Hague
Renci.SshNet.Common.SshConnectionException: Client not connected.
at Renci.SshNet.Session.SendMessage(Message message)
at Renci.SshNet.Session.Renci.SshNet.ISession.SendMessage(Message message)
at Renci.SshNet.Channels.Channel.SendData(Byte[] data, Int32 offset, Int32 size)
at Renci.SshNet.Channels.Channel.SendData(Byte[] data)
at Renci.SshNet.SubsystemSession.SendData(Byte[] data)
at Renci.SshNet.Sftp.SftpSession.SendMessage(SftpMessage sftpMessage)
at Renci.SshNet.Sftp.SftpSession.SendRequest(SftpRequest request)
at Renci.SshNet.Sftp.SftpSession.RequestOpenAsync(String path, Flags flags, CancellationToken cancellationToken)
at Renci.SshNet.Sftp.SftpSession.RequestOpenAsync(String path, Flags flags, CancellationToken cancellationToken)
at Renci.SshNet.Sftp.SftpFileStream.OpenAsync(ISftpSession session, String path, FileMode mode, FileAccess access, Int32 bufferSize, CancellationToken cancellationToken)
There also seems be a related issue where the client can get into a broken state. Even after re-connect with ConnectAsync
, any following OpenAsync
keeps throwing the exception from the old session. It seems like Session.Reset()
is not called in some cases (which would reset the exception handle).
We currently work around both issues by explicitly disconnecting before doing a reconnect. This seems to work (for now).
Renci.SshNet.Common.SshConnectionException: An established connection was aborted by the server.
at Renci.SshNet.Session.WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout)
at Renci.SshNet.Session.Renci.SshNet.ISession.WaitOnHandle(WaitHandle waitHandle)
at Renci.SshNet.Channels.Channel.GetDataLengthThatCanBeSentInMessage(Int32 messageLength)
at Renci.SshNet.Sftp.SftpSession.SendRequest(SftpRequest request)
at Renci.SshNet.Sftp.SftpSession.RequestOpenAsync(String path, Flags flags, CancellationToken cancellationToken)
at Renci.SshNet.Sftp.SftpSession.RequestOpenAsync(String path, Flags flags, CancellationToken cancellationToken)
at Renci.SshNet.Sftp.SftpFileStream.OpenAsync(ISftpSession session, String path, FileMode mode, FileAccess access, Int32 bufferSize, CancellationToken cancellationToken)
Also worth mentioning that when the server disconnects the session, we do get an ErrorOccurred
event with this exception (as expected).