diff --git a/Renci.SshClient/Renci.SshClient/Sftp/SftpCommand.cs b/Renci.SshClient/Renci.SshClient/Sftp/SftpCommand.cs
index f02c65a5..1cc1812d 100644
--- a/Renci.SshClient/Renci.SshClient/Sftp/SftpCommand.cs
+++ b/Renci.SshClient/Renci.SshClient/Sftp/SftpCommand.cs
@@ -7,6 +7,9 @@ using Renci.SshClient.Messages.Sftp;
namespace Renci.SshClient.Sftp
{
+ ///
+ /// Base class for all SFTP Commands
+ ///
internal abstract class SftpCommand
{
private SftpSession _sftpSession;
@@ -17,6 +20,8 @@ namespace Renci.SshClient.Sftp
private Exception _error;
+ private bool _handleCloseMessageSent;
+
protected SftpAsyncResult AsyncResult { get; private set; }
public int CommandTimeout { get; set; }
@@ -70,6 +75,12 @@ namespace Renci.SshClient.Sftp
protected virtual void OnStatus(StatusCodes statusCode, string errorMessage, string language)
{
+ if (this._handleCloseMessageSent)
+ {
+ this.OnHandleClosed();
+
+ this._handleCloseMessageSent = false;
+ }
}
protected virtual void OnName(IEnumerable files)
@@ -107,6 +118,8 @@ namespace Renci.SshClient.Sftp
{
Handle = handle,
});
+
+ this._handleCloseMessageSent = true;
}
protected void SendReadMessage(string handle, ulong offset, uint bufferSize)
@@ -262,19 +275,19 @@ namespace Renci.SshClient.Sftp
if (this._requestId == e.Message.RequestId)
{
this.OnStatus(e.Message.StatusCode, e.Message.ErrorMessage, e.Message.Language);
- }
- if (e.Message.StatusCode == StatusCodes.NoSuchFile ||
- e.Message.StatusCode == StatusCodes.PermissionDenied ||
- e.Message.StatusCode == StatusCodes.Failure ||
- e.Message.StatusCode == StatusCodes.BadMessage ||
- e.Message.StatusCode == StatusCodes.NoConnection ||
- e.Message.StatusCode == StatusCodes.ConnectionLost ||
- e.Message.StatusCode == StatusCodes.OperationUnsupported
- )
- {
- // Throw an exception if it was not handled by the command
- throw new SshException(e.Message.ErrorMessage);
+ if (e.Message.StatusCode == StatusCodes.NoSuchFile ||
+ e.Message.StatusCode == StatusCodes.PermissionDenied ||
+ e.Message.StatusCode == StatusCodes.Failure ||
+ e.Message.StatusCode == StatusCodes.BadMessage ||
+ e.Message.StatusCode == StatusCodes.NoConnection ||
+ e.Message.StatusCode == StatusCodes.ConnectionLost ||
+ e.Message.StatusCode == StatusCodes.OperationUnsupported
+ )
+ {
+ // Throw an exception if it was not handled by the command
+ throw new SshException(e.Message.ErrorMessage);
+ }
}
}
diff --git a/Renci.SshClient/Renci.SshClient/Sftp/SftpSession.cs b/Renci.SshClient/Renci.SshClient/Sftp/SftpSession.cs
index 7a517861..b59181b4 100644
--- a/Renci.SshClient/Renci.SshClient/Sftp/SftpSession.cs
+++ b/Renci.SshClient/Renci.SshClient/Sftp/SftpSession.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@@ -89,15 +90,39 @@ namespace Renci.SshClient.Sftp
private void Channel_DataReceived(object sender, Common.ChannelDataEventArgs e)
{
+ var packets = new Queue();
+
if (this._packetData == null)
{
- var packetLength = (uint)(e.Data[0] << 24 | e.Data[1] << 16 | e.Data[2] << 8 | e.Data[3]);
+ var dataOffset = 0;
+ while (true)
+ {
+ // Read SFTP packet length
+ var packetLength = (e.Data[dataOffset + 0] << 24 | e.Data[dataOffset + 1] << 16 | e.Data[dataOffset + 2] << 8 | e.Data[dataOffset + 3]);
- this._packetData = new StringBuilder((int)packetLength, (int)packetLength);
- this._packetData.Append(e.Data.GetSshBytes().Skip(4).GetSshString());
+ // Create data holder for SFTP packet
+ this._packetData = new StringBuilder(packetLength, packetLength);
+
+ // Add data to the packet holder
+ this._packetData.Append(e.Data.GetSshBytes().Skip(dataOffset + 4).Take((int)packetLength).GetSshString());
+
+ dataOffset += (packetLength + 4);
+
+ if (dataOffset < e.Data.Length)
+ {
+ // If there is another SFTP packet in current message then queue this data and read next one
+ packets.Enqueue(this._packetData.ToString());
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
}
else
{
+ // Add message data to packet data
this._packetData.Append(e.Data);
}
@@ -107,18 +132,25 @@ namespace Renci.SshClient.Sftp
return;
}
- dynamic sftpMessage = SftpMessage.Load(this._packetData.ToString().GetSshBytes());
+ // Add last packet to the queue of packet data that need to be proccessed
+ packets.Enqueue(this._packetData.ToString());
this._packetData = null;
- try
+ foreach (var packetData in packets)
{
- // TODO: Check to run on different thread
- this.HandleMessage(sftpMessage);
- }
- catch (Exception exp)
- {
- this.RaiseError(exp);
+ dynamic sftpMessage = SftpMessage.Load(packetData.GetSshBytes());
+
+ try
+ {
+ // TODO: Check to run on different thread
+ this.HandleMessage(sftpMessage);
+ }
+ catch (Exception exp)
+ {
+ this.RaiseError(exp);
+ break;
+ }
}
}