Closed
Description
Hiya!
Affected devices: Cisco IOS-XR 6.3.3, probably other Ciscos as well.
Symptoms: SftpClient.DownloadFile()
writes zero bytes to the output stream.
Root cause:
Cisco IOS-XR has its own SFTP server, rife with bugs. One such bug is that if SSH2_FXP_OPEN
is followed by a call to SSH2_FXP_LSTAT
, it internally closes the file descriptor and sends EOF to any future SSH2_FXP_READ
requests which had handles open to it.
How SSH.NET is affected:
SSH.NET requests LSTAT
after OPEN
, but before READ
. This code in ServiceFactory.cs
exposes the bug:
public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSession, uint bufferSize)
{
const int defaultMaxPendingReads = 3;
// Issue #292: Avoid overlapping SSH_FXP_OPEN and SSH_FXP_LSTAT requests for the same file as this
// causes a performance degradation on Sun SSH
var openAsyncResult = sftpSession.BeginOpen(fileName, Flags.Read, null, null);
var handle = sftpSession.EndOpen(openAsyncResult);
var statAsyncResult = sftpSession.BeginLStat(fileName, null, null);
long? fileSize;
int maxPendingReads;
var chunkSize = sftpSession.CalculateOptimalReadLength(bufferSize);
// fallback to a default maximum of pending reads when remote server does not allow us to obtain
// the attributes of the file
try
{
var fileAttributes = sftpSession.EndLStat(statAsyncResult);
fileSize = fileAttributes.Size;
maxPendingReads = Math.Min(10, (int) Math.Ceiling((double) fileAttributes.Size / chunkSize) + 1);
}
catch (SshException ex)
{
fileSize = null;
maxPendingReads = defaultMaxPendingReads;
DiagnosticAbstraction.Log(string.Format("Failed to obtain size of file. Allowing maximum {0} pending reads: {1}", maxPendingReads, ex));
}
return sftpSession.CreateFileReader(handle, sftpSession, chunkSize, maxPendingReads, fileSize);
}
Moving BeginLStat
/EndLStat
before BeginOpen
/EndOpen
fixes the bug (this is also the call sequence that OpenSSH uses.) This shouldn't affect #292 , since it's still not overlapped.
Metadata
Metadata
Assignees
Labels
No labels