On one particular server, I'm getting timeout exceptions trying to upload. It's sitting there waiting for a SSH_MSG_CHANNEL_WINDOW_ADJUST message from the server, but the server still has like 14KB remaining on its channel window, so it's not interested increasing the window size at that point. The client ends up deadlocked with the server waiting for the other to act.
I managed to get the upload to go through by decreasing the buffer size on the SftpClient, but that's not really a good way of dealing with it: there's not any good way to know what the server's threshold for increasing the window is. So I modified Channel.SendMessage to split the data into a smaller chunk that will fit, and then wait for it to increase again before sending the remainder of the message.
```
protected void SendMessage(ChannelDataMessage message)
{
const int lowerLimit = 256;
while (message != null && message.Data != null)
{
// Send channel messages only while channel is open
if (!this.IsOpen)
return;
var messageLength = message.Data.Length;
if (messageLength == 0)
return;
lock (this._serverWindowSizeLock)
{
var serverWindowSize = this.ServerWindowSize;
if (serverWindowSize < messageLength)
{
if (serverWindowSize < lowerLimit)
{
// Wait for window to be big enough for this message
this._channelServerWindowAdjustWaitHandle.Reset();
messageLength = 0;
}
else
{
messageLength = (int)serverWindowSize - lowerLimit;
}
}
this.ServerWindowSize -= (uint)messageLength;
}
if (messageLength == 0)
{
// Wait for window to change
this.WaitHandle(this._channelServerWindowAdjustWaitHandle);
continue;
}
var nextMessage = message.SplitData(messageLength);
this._session.SendMessage(message);
message = nextMessage;
}
}
```
And the code for ChannelDataMessage.SplitData:
```
public ChannelDataMessage SplitData(int Size)
{
if (Size < Data.Length)
return null;
byte[] firstPart = new byte[Size];
byte[] lastPart = new byte[Data.Length - Size];
System.Array.Copy(Data, firstPart, Size);
System.Array.Copy(Data, Size, lastPart, 0, lastPart.Length);
this.Data = firstPart;
return new ChannelDataMessage(LocalChannelNumber, lastPart);
}
```
Comments: ** Comment from web user: drieseng **
I managed to get the upload to go through by decreasing the buffer size on the SftpClient, but that's not really a good way of dealing with it: there's not any good way to know what the server's threshold for increasing the window is. So I modified Channel.SendMessage to split the data into a smaller chunk that will fit, and then wait for it to increase again before sending the remainder of the message.
```
protected void SendMessage(ChannelDataMessage message)
{
const int lowerLimit = 256;
while (message != null && message.Data != null)
{
// Send channel messages only while channel is open
if (!this.IsOpen)
return;
var messageLength = message.Data.Length;
if (messageLength == 0)
return;
lock (this._serverWindowSizeLock)
{
var serverWindowSize = this.ServerWindowSize;
if (serverWindowSize < messageLength)
{
if (serverWindowSize < lowerLimit)
{
// Wait for window to be big enough for this message
this._channelServerWindowAdjustWaitHandle.Reset();
messageLength = 0;
}
else
{
messageLength = (int)serverWindowSize - lowerLimit;
}
}
this.ServerWindowSize -= (uint)messageLength;
}
if (messageLength == 0)
{
// Wait for window to change
this.WaitHandle(this._channelServerWindowAdjustWaitHandle);
continue;
}
var nextMessage = message.SplitData(messageLength);
this._session.SendMessage(message);
message = nextMessage;
}
}
```
And the code for ChannelDataMessage.SplitData:
```
public ChannelDataMessage SplitData(int Size)
{
if (Size < Data.Length)
return null;
byte[] firstPart = new byte[Size];
byte[] lastPart = new byte[Data.Length - Size];
System.Array.Copy(Data, firstPart, Size);
System.Array.Copy(Data, Size, lastPart, 0, lastPart.Length);
this.Data = firstPart;
return new ChannelDataMessage(LocalChannelNumber, lastPart);
}
```
Comments: ** Comment from web user: drieseng **
Fixed in changeset 35151.