Strange behaviour after "the server has closed the connection" error

+1 vote
asked Mar 22, 2016 by adrianm (170 points)

I got some code sending files to a sftp.

Occationally I get the error "the server has closed the connection.".
The strange thing is that I get an "already connected" error when reconnecting (Sftp.Connect). The log looks like this:

VERBOSE Sftp(1)[7] SSH: Sending packet SSH_MSG_CHANNEL_DATA (89 bytes).
INFO Sftp(1)[7] Command: SSH_FXP_OPEN (142, 'xxx.xml', 26)
VERBOSE Sftp(1)[7] SSH: Received packet SSH_MSG_CHANNEL_CLOSE (5 bytes).
VERBOSE Sftp(1)[7] SSH: Sending packet SSH_MSG_CHANNEL_CLOSE (5 bytes).
ERROR Sftp(1)[7] Info: Rebex.Net.SftpException: The server has closed the connection.
VERBOSE Sftp(1)[7] SSH: Sending packet SSH_MSG_DISCONNECT (27 bytes).
ERROR Sftp(1)[7] Info: System.InvalidOperationException: Already connected to the server.

The code looks something like this:

try {
    using (var uploadStream = _sftp.GetUploadStream(fileName)) {
        ...
        return;
    }
}
catch (SftpException ex) {
    if (ex.Code != SftpErrorCode.UnknownError)
        throw;
    if (ex.Status != SftpExceptionStatus.ConnectionClosed)
        throw;

    _sftp.Connect(url);
    _sftp.Login(user, password);
    goto retry;
}
Applies to: Rebex SFTP

1 Answer

+1 vote
answered Mar 22, 2016 by Tomas Knopp (58,890 points)
selected Mar 23, 2016 by adrianm
 
Best answer

It looks like the Sftp client object might have been left in a state where it thinks it is still connected although the server has dropped the connection. The solution would be to either call Sftp.Disconnect before reconnecting, or even better instantiate a completely new Sftp instance. The disconnect should be enough however, the new instance is even better as you start on a 100% clean field. Try to modify your code like this and let me know whether it helped:

try
{
    using (var uploadStream = _sftp.GetUploadStream(fileName))
    {
        ...
        return;
    }
}
catch (SftpException ex)
{
    if (ex.Code != SftpErrorCode.UnknownError)
        throw;
    if (ex.Status != SftpExceptionStatus.ConnectionClosed)
        throw;

    if (ex.Status != SftpExceptionStatus.ProtocolError)
    {
        // reconnect is only needed if it was not a protocol error
        _sftp.Disconnect();

        // _sftp = new Sftp(); // optionally instantiate a new instance of Sftp client

        _sftp.Connect(url);
        _sftp.Login(user, password);
    }
    goto retry;
}
commented Mar 23, 2016 by adrianm (170 points)
Adding a `.Disconnect` solved the issue. Thanks.
...