diff --git a/Renci.SshClient/Renci.SshClient/Channels/Channel.cs b/Renci.SshClient/Renci.SshClient/Channels/Channel.cs
index 9a514df9..1af100ff 100644
--- a/Renci.SshClient/Renci.SshClient/Channels/Channel.cs
+++ b/Renci.SshClient/Renci.SshClient/Channels/Channel.cs
@@ -13,7 +13,7 @@ namespace Renci.SshClient.Channels
private uint _initialWindowSize = 0x100000;
- private uint _maximumPacketSize = 0x4000;
+ private uint _maximumPacketSize = 0x8000;
///
/// Counts faile channel open attempts
@@ -196,10 +196,19 @@ namespace Renci.SshClient.Channels
if (message.RequestName == RequestNames.ExitStatus)
{
var exitStatus = message.ExitStatus;
+
replyMessage = new ChannelSuccessMessage()
{
ChannelNumber = message.ChannelNumber,
};
+
+ this.SendChannelCloseMessage();
+
+ // TODO: if exitStatus is not 0 then throw an exception or notify user that command failed to execute correctly
+ }
+ else
+ {
+ throw new NotImplementedException(string.Format("Request name {0} is not implemented.", message.RequestName));
}
if (message.WantReply)
@@ -229,6 +238,8 @@ namespace Renci.SshClient.Channels
this._channelClosedWaitHandle.Set();
}
+ #endregion
+
private void AdjustDataWindow(string messageData)
{
this.WindowSize -= (uint)messageData.Length;
@@ -245,8 +256,6 @@ namespace Renci.SshClient.Channels
}
}
- #endregion
-
private void RaiseOpened()
{
if (this.Opened != null)
diff --git a/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs b/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs
index a0864920..81974ef1 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, 0x100000, 0x1000)
+ : base(session, channelId, 0x100000, 0x8000)
{
}
@@ -47,7 +47,6 @@ namespace Renci.SshClient.Channels
};
this._callback = callback;
-
this._channelData = output;
this._channelExtendedData = extendedOutput;
@@ -67,26 +66,34 @@ namespace Renci.SshClient.Channels
internal void EndExecute(IAsyncResult result)
{
- ChannelAsyncResult channelAsyncResult = result as ChannelAsyncResult;
-
- if (channelAsyncResult.Channel != this)
+ try
{
- throw new InvalidOperationException("Invalid IAsyncResult parameter");
+ ChannelAsyncResult channelAsyncResult = result as ChannelAsyncResult;
+
+ if (channelAsyncResult.Channel != this)
+ {
+ throw new InvalidOperationException("Invalid IAsyncResult parameter");
+ }
+
+ //Make sure that operation completed if not wait for it to finish
+ this.Session.WaitHandle(this._asyncResult.AsyncWaitHandle);
+
+ this.Close();
+
+ this._asyncResult = null;
+
+ if (this._exception != null)
+ {
+ var exception = this._exception;
+ this._exception = null; // Clean exception
+ throw exception;
+ }
+ }
+ catch (Exception exp)
+ {
+ throw;
}
- //Make sure that operation completed if not wait for it to finish
- this.Session.WaitHandle(this._asyncResult.AsyncWaitHandle);
-
- this.Close();
-
- this._asyncResult = null;
-
- if (this._exception != null)
- {
- var exception = this._exception;
- this._exception = null; // Clean exception
- throw exception;
- }
}
protected override void OnChannelEof()
@@ -96,6 +103,13 @@ namespace Renci.SshClient.Channels
this.ExecutionCompleted();
}
+ protected override void OnChannelClose()
+ {
+ base.OnChannelClose();
+
+ this.ExecutionCompleted();
+ }
+
protected override void OnChannelFailed(uint reasonCode, string description)
{
base.OnChannelFailed(reasonCode, description);
diff --git a/Renci.SshClient/Renci.SshClient/Common/BlockingStack.cs b/Renci.SshClient/Renci.SshClient/Common/BlockingStack.cs
index b9b195fc..de4c50b7 100644
--- a/Renci.SshClient/Renci.SshClient/Common/BlockingStack.cs
+++ b/Renci.SshClient/Renci.SshClient/Common/BlockingStack.cs
@@ -126,12 +126,12 @@ namespace Renci.SshClient.Common
public bool IsSynchronized
{
- get { throw new System.NotImplementedException(); }
+ get { return true; }
}
public object SyncRoot
{
- get { throw new System.NotImplementedException(); }
+ get { return this; }
}
#endregion
diff --git a/Renci.SshClient/Renci.SshClient/Session.cs b/Renci.SshClient/Renci.SshClient/Session.cs
index 4ebafd2b..7b249d6b 100644
--- a/Renci.SshClient/Renci.SshClient/Session.cs
+++ b/Renci.SshClient/Renci.SshClient/Session.cs
@@ -72,6 +72,11 @@ namespace Renci.SshClient
///
private EventWaitHandle _exceptionWaitHandle = new AutoResetEvent(false);
+ ///
+ /// WaitHandle to signal that listner ended
+ ///
+ private EventWaitHandle _listenerWaitHandle = new AutoResetEvent(false);
+
///
/// Keeps track of all open channels
///
@@ -87,6 +92,11 @@ namespace Renci.SshClient
///
private bool _isAuthenticated;
+ ///
+ /// Specifies weither Disconnect method was called
+ ///
+ private bool _isDisconnecting;
+
///
/// holds number to be used for session channels
///
@@ -233,15 +243,18 @@ namespace Renci.SshClient
if (this.IsConnected)
return;
- lock (this)
+ try
{
- // If connected dont connect again
+ _authenticationConnection.Wait();
+
if (this.IsConnected)
return;
- try
+ lock (this)
{
- _authenticationConnection.Wait();
+ // If connected dont connect again
+ if (this.IsConnected)
+ return;
var ep = new IPEndPoint(Dns.GetHostAddresses(connectionInfo.Host)[0], connectionInfo.Port);
this._socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
@@ -331,11 +344,13 @@ namespace Renci.SshClient
{
throw new AuthenticationException(errorMessage ?? "User cannot be authenticated.");
}
+
+ Monitor.Pulse(this);
}
- finally
- {
- _authenticationConnection.Release();
- }
+ }
+ finally
+ {
+ _authenticationConnection.Release();
}
}
@@ -344,7 +359,8 @@ namespace Renci.SshClient
///
public void Disconnect()
{
- // TODO: Change message to something more appropriate
+ this._isDisconnecting = true;
+
this.Disconnect(DisconnectReasonCodes.ByApplication, "Connection terminated by the client.");
this.DisconnectCleanup();
@@ -359,6 +375,7 @@ namespace Renci.SshClient
var waitHandles = new WaitHandle[]
{
this._exceptionWaitHandle,
+ this._listenerWaitHandle, // When listener exits
waitHandle,
};
@@ -491,7 +508,7 @@ namespace Renci.SshClient
// Test packet minimum and maximum boundaries
if (packetLength < Math.Max((byte)16, blockSize) - 4 || packetLength > Session.MAXIMUM_PACKET_SIZE - 4)
- throw new InvalidOperationException(string.Format("Bad packet length {0}", packetLength));
+ throw new IOException(string.Format("Bad packet length {0}", packetLength));
// Read rest of the packet data
int bytesToRead = (int)(packetLength - (blockSize - 4));
@@ -525,7 +542,7 @@ namespace Renci.SshClient
if (!serverHash.IsEqualTo(clientHash))
{
- throw new InvalidOperationException("MAC error");
+ throw new IOException("MAC error");
}
}
@@ -839,9 +856,19 @@ namespace Renci.SshClient
this.RaiseMessageReceived(this, new MessageReceivedEventArgs(message));
}
}
- catch (IOException)
+ 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)
{
@@ -854,6 +881,8 @@ namespace Renci.SshClient
this._exceptionWaitHandle.Set();
}
+
+ this._listenerWaitHandle.Set();
}
///
@@ -910,6 +939,11 @@ namespace Renci.SshClient
{
this._exceptionWaitHandle.Dispose();
}
+
+ if (this._listenerWaitHandle != null)
+ {
+ this._listenerWaitHandle.Dispose();
+ }
}
// Note disposing has been done.