diff --git a/Renci.SshClient/Renci.SshClient/Channels/Channel.cs b/Renci.SshClient/Renci.SshClient/Channels/Channel.cs
index 0f5844d7..76ec691e 100644
--- a/Renci.SshClient/Renci.SshClient/Channels/Channel.cs
+++ b/Renci.SshClient/Renci.SshClient/Channels/Channel.cs
@@ -259,12 +259,12 @@ namespace Renci.SshClient.Channels
this.LocalWindowSize -= (uint)messageData.Length;
// Adjust window if window size is too low
- if (this.LocalWindowSize < 1)
+ if (this.LocalWindowSize < this.PacketSize)
{
this.SendMessage(new ChannelWindowAdjustMessage
{
ChannelNumber = this.ServerChannelNumber,
- BytesToAdd = this._initialWindowSize,
+ BytesToAdd = this._initialWindowSize - this.LocalWindowSize,
});
this.LocalWindowSize = this._initialWindowSize;
}
diff --git a/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs b/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs
index d47a6630..8da7d818 100644
--- a/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs
+++ b/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs
@@ -26,7 +26,7 @@ namespace Renci.SshClient.Channels
}
public ChannelExec(Session session, uint channelId)
- : base(session, channelId, 0x010000, 0x8000)
+ : base(session, channelId, 0x100000, 0x8000)
{
}
diff --git a/Renci.SshClient/Renci.SshClient/Session.cs b/Renci.SshClient/Renci.SshClient/Session.cs
index 7b249d6b..fe005163 100644
--- a/Renci.SshClient/Renci.SshClient/Session.cs
+++ b/Renci.SshClient/Renci.SshClient/Session.cs
@@ -60,27 +60,27 @@ namespace Renci.SshClient
///
/// WaitHandle to signal that key exchange was finished, weither it was succesfull or not.
///
- private EventWaitHandle _keyExhangedFinishedWaitHandle = new AutoResetEvent(false);
+ private EventWaitHandle _keyExhangedFinishedWaitHandle;
///
/// WaitHandle to signale that last service request was accepted
///
- private EventWaitHandle _serviceAccepted = new AutoResetEvent(false);
+ private EventWaitHandle _serviceAccepted;
///
/// WaitHandle to signal that exception was thrown by another thread.
///
- private EventWaitHandle _exceptionWaitHandle = new AutoResetEvent(false);
+ private EventWaitHandle _exceptionWaitHandle;
///
/// WaitHandle to signal that listner ended
///
- private EventWaitHandle _listenerWaitHandle = new AutoResetEvent(false);
+ private EventWaitHandle _listenerWaitHandle;
///
/// Keeps track of all open channels
///
- private Dictionary _openChannels = new Dictionary();
+ private Dictionary _openChannels;
///
/// Exception that need to be thrown by waiting thread
@@ -100,7 +100,7 @@ namespace Renci.SshClient
///
/// holds number to be used for session channels
///
- private BlockingStack _channelNumbers = new BlockingStack();
+ private BlockingStack _channelNumbers;
///
/// Occurs when new message received.
@@ -182,12 +182,6 @@ namespace Renci.SshClient
{
this.ConnectionInfo = connectionInfo;
this.ClientVersion = string.Format("SSH-2.0-Renci.SshClient.{0}", this.GetType().Assembly.GetName().Version);
-
- // Prepopulate chanel numbers that will be used
- for (int i = connectionInfo.MaxSessions - 1; i > 0; i--)
- {
- this._channelNumbers.Push((uint)i - 1 + 100);
- }
}
private static IDictionary> _channels = new Dictionary>()
@@ -256,6 +250,15 @@ namespace Renci.SshClient
if (this.IsConnected)
return;
+ this.Initialize();
+
+ // Prepopulate chanel numbers that will be used
+ for (int i = connectionInfo.MaxSessions - 1; i > 0; i--)
+ {
+ this._channelNumbers.Push((uint)i - 1);
+ }
+
+
var ep = new IPEndPoint(Dns.GetHostAddresses(connectionInfo.Host)[0], connectionInfo.Port);
this._socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
@@ -513,19 +516,13 @@ namespace Renci.SshClient
// Read rest of the packet data
int bytesToRead = (int)(packetLength - (blockSize - 4));
- while (bytesToRead > 0)
+ if (this.ServerCipher == null)
{
- data = new List(this.Read(blockSize));
-
- if (this.ServerCipher == null)
- {
- decryptedData.AddRange(data);
- }
- else
- {
- decryptedData.AddRange(this.ServerCipher.Decrypt(data));
- }
- bytesToRead -= blockSize;
+ decryptedData.AddRange(this.Read(bytesToRead));
+ }
+ else
+ {
+ decryptedData.AddRange(this.ServerCipher.Decrypt(this.Read(bytesToRead)));
}
// Validate message against MAC
@@ -704,29 +701,28 @@ namespace Renci.SshClient
protected byte[] Read(int length)
{
var buffer = new byte[length];
-
- var totalBytesRead = 0;
-
- while (totalBytesRead < length)
+ var offset = 0;
+ int received = 0; // how many bytes is already received
+ do
{
- int bytesRead = this._socket.Receive(buffer, length, SocketFlags.None);
+ try
+ {
+ received += this._socket.Receive(buffer, offset + received, length - received, SocketFlags.None);
+ }
+ catch (SocketException exp)
+ {
+ if (exp.SocketErrorCode == SocketError.WouldBlock ||
+ exp.SocketErrorCode == SocketError.IOPending ||
+ exp.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
+ {
+ // socket buffer is probably empty, wait and try again
+ Thread.Sleep(30);
+ }
+ else
+ throw exp; // any serious error occurr
+ }
+ } while (received < length);
- if (bytesRead == 0)
- {
- this._socket.Close();
- throw new IOException("Unable to read data to the transport connection: An established connection was aborted by the software in your host machine");
- }
-
- if (bytesRead > 0)
- {
- totalBytesRead += bytesRead;
- }
- else
- {
- totalBytesRead = bytesRead;
- break;
- }
- }
return buffer;
}
@@ -737,7 +733,29 @@ namespace Renci.SshClient
/// The data.
protected void Write(byte[] data)
{
- this._socket.Send(data);
+ int sent = 0; // how many bytes is already sent
+ int length = data.Length;
+
+ do
+ {
+ try
+ {
+ sent += this._socket.Send(data, sent, length - sent, SocketFlags.None);
+ }
+ catch (SocketException ex)
+ {
+ if (ex.SocketErrorCode == SocketError.WouldBlock ||
+ ex.SocketErrorCode == SocketError.IOPending ||
+ ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
+ {
+ // socket buffer is probably full, wait and try again
+ Thread.Sleep(30);
+ }
+ else
+ throw ex; // any serious error occurr
+ }
+ } while (sent < length);
+
}
///
@@ -798,6 +816,36 @@ namespace Renci.SshClient
#endregion
+ ///
+ /// Initializes this session.
+ ///
+ /// Initialization required when same session object being reconnected
+ private void Initialize()
+ {
+ // TODO: Consider reseting objects to initial stage instead of creating a new one
+ // Initialize session
+ this._outboundPacketSequence = 0;
+ this._inboundPacketSequence = 0;
+ this._openChannels = new Dictionary();
+ this._keyExhangedFinishedWaitHandle = new AutoResetEvent(false);
+ this._serviceAccepted = new AutoResetEvent(false);
+ this._exceptionWaitHandle = new AutoResetEvent(false);
+ this._listenerWaitHandle = new AutoResetEvent(false);
+ this._channelNumbers = new BlockingStack();
+ this._exceptionToThrow = null;
+ this.SessionId = null;
+ this.ServerVersion = null;
+ this._keyExhcange = null;
+ this.ServerMac = null;
+ this.ClientMac = null;
+ this.ClientCipher = null;
+ this.ServerCipher = null;
+ this.ServerDecompression = null;
+ this.ClientCompression = null;
+ this._isAuthenticated = false;
+ this._isDisconnecting = false;
+ }
+
private bool ValidateHash(List decryptedData, byte[] serverHash, uint packetSequence)
{
var clientHashData = new List();
@@ -831,6 +879,12 @@ namespace Renci.SshClient
{
this._socket.Close();
}
+
+ if (this._messageListener != null)
+ {
+ this._messageListener.Wait();
+ this._messageListener = null;
+ }
}
///
@@ -856,30 +910,27 @@ namespace Renci.SshClient
this.RaiseMessageReceived(this, new MessageReceivedEventArgs(message));
}
}
- catch (IOException exp)
- {
- // Ignore this error since socket was disconected
-
- // Ensure socket is disconnected
- this._socket.Close();
-
- if (!this._isDisconnecting)
- {
- this._exceptionToThrow = exp;
-
- this._exceptionWaitHandle.Set();
- }
- }
catch (Exception exp)
{
// TODO: This exception can be swolloed if it occures while running in the background, look for possible solutions
- // In case of error issue disconntect command
- this.Disconnect(DisconnectReasonCodes.ByApplication, exp.ToString());
+ // Ignore this error since socket was disconected
+ if (exp is SocketException && ((SocketException)exp).SocketErrorCode == SocketError.ConnectionAborted && this._isDisconnecting)
+ {
+ // Do nothing since connection was disconnected by the client
+ }
+ else
+ {
+ // In case of error issue disconntect command
+ this.Disconnect(DisconnectReasonCodes.ByApplication, exp.ToString());
- this._exceptionToThrow = exp;
+ this._exceptionToThrow = exp;
- this._exceptionWaitHandle.Set();
+ this._exceptionWaitHandle.Set();
+ }
+
+ // Ensure socket is disconnected
+ this._socket.Close();
}
this._listenerWaitHandle.Set();
diff --git a/Renci.SshClient/Renci.SshClient/Shell.cs b/Renci.SshClient/Renci.SshClient/Shell.cs
index 34ea15e7..c04ba0f0 100644
--- a/Renci.SshClient/Renci.SshClient/Shell.cs
+++ b/Renci.SshClient/Renci.SshClient/Shell.cs
@@ -76,6 +76,5 @@ namespace Renci.SshClient
channelAsyncResult.Channel.EndExecute(asynchResult);
}
-
}
}