/// <summary> /// Sends channel extended data message to the servers. /// </summary> /// <param name="message">Channel data message.</param> /// <remarks> /// <para> /// When the data of the message exceeds the maximum packet size or the remote window /// size does not allow the full message to be sent, then this method will send the /// data in multiple chunks and will only wait for the remote window size to be adjusted /// when its zero. /// </para> /// <para> /// This is done to support SSH servers will a small window size that do not agressively /// increase their window size. We need to take into account that there may be SSH /// servers that only increase their window size when it has reached zero. /// </para> /// </remarks> protected void SendMessage(ChannelExtendedDataMessage message) { // end channel messages only while channel is open if (!this.IsOpen) return; var totalDataLength = message.Data.Length; var totalDataSent = 0; var totalBytesToSend = totalDataLength; while (totalBytesToSend > 0) { var dataThatCanBeSentInMessage = GetDataLengthThatCanBeSentInMessage(totalBytesToSend); if (dataThatCanBeSentInMessage == totalDataLength) { // we can send the message in one chunk this._session.SendMessage(message); } else { // we need to send the message in multiple chunks var dataToSend = new byte[dataThatCanBeSentInMessage]; Array.Copy(message.Data, totalDataSent, dataToSend, 0, dataThatCanBeSentInMessage); this._session.SendMessage(new ChannelExtendedDataMessage(message.LocalChannelNumber, message.DataTypeCode, dataToSend)); } totalDataSent += dataThatCanBeSentInMessage; totalBytesToSend -= dataThatCanBeSentInMessage; } }
/// <summary> /// Sends channel extended data message to the servers. /// </summary> /// <remarks>This method takes care of managing the window size.</remarks> /// <param name="message">Channel data message.</param> protected void SendMessage(ChannelExtendedDataMessage message) { // Send channel messages only while channel is open if (!this.IsOpen) return; var messageLength = message.Data.Length; do { lock (this._serverWindowSizeLock) { var serverWindowSize = this.ServerWindowSize; if (serverWindowSize < messageLength) { // Wait for window to be big enough for this message this._channelServerWindowAdjustWaitHandle.Reset(); } else { this.ServerWindowSize -= (uint)messageLength; break; } } // Wait for window to change this.WaitHandle(this._channelServerWindowAdjustWaitHandle); } while (true); this._session.SendMessage(message); }
/// <summary> /// Sends channel extended data message to the servers. /// </summary> /// <remarks>This method takes care of managing the window size.</remarks> /// <param name="message">Channel data message.</param> protected void SendMessage(ChannelExtendedDataMessage message) { // Send channel messages only while channel is open if (!this.IsOpen) return; if (this.ServerWindowSize < 1) { // Wait for window to be adjust this._session.WaitHandle(this._channelWindowAdjustWaitHandle); } this.ServerWindowSize -= (uint)message.Data.Length; this._session.SendMessage(message); }
[Ignore] // placeholder public void ChannelExtendedDataMessageConstructorTest() { ChannelExtendedDataMessage target = new ChannelExtendedDataMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); }