diff --git a/Renci.SshClient/Renci.SshClient/Channels/Channel.cs b/Renci.SshClient/Renci.SshClient/Channels/Channel.cs
index ea10adb4..f45fee22 100644
--- a/Renci.SshClient/Renci.SshClient/Channels/Channel.cs
+++ b/Renci.SshClient/Renci.SshClient/Channels/Channel.cs
@@ -1,6 +1,5 @@
using System;
-using System.Text;
using System.Threading;
using Renci.SshClient.Common;
using Renci.SshClient.Messages;
@@ -22,10 +21,6 @@ namespace Renci.SshClient.Channels
//private uint _maximumPacketSize = 0x4000;
private uint _maximumPacketSize = 1024;
- protected StringBuilder ChannelData { get; private set; }
-
- protected StringBuilder ChannelExtendedData { get; private set; }
-
public abstract ChannelTypes ChannelType { get; }
public uint ClientChannelNumber { get; set; }
@@ -62,8 +57,6 @@ namespace Renci.SshClient.Channels
}
this.Session = session;
- this.ChannelData = new StringBuilder((int)this._initialWindowSize);
- this.ChannelExtendedData = new StringBuilder((int)this._initialWindowSize);
this.WindowSize = this._initialWindowSize; // Initial window size
this.PacketSize = this._maximumPacketSize; // Maximum packet size
}
diff --git a/Renci.SshClient/Renci.SshClient/Channels/ChannelAsyncResult.cs b/Renci.SshClient/Renci.SshClient/Channels/ChannelAsyncResult.cs
new file mode 100644
index 00000000..e5f7bfad
--- /dev/null
+++ b/Renci.SshClient/Renci.SshClient/Channels/ChannelAsyncResult.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Threading;
+
+namespace Renci.SshClient.Channels
+{
+ public class ChannelAsyncResult : IAsyncResult
+ {
+ ///
+ /// Gets or sets the channel that async result was created for.
+ ///
+ /// The channel.
+ internal ChannelExec Channel { get; private set; }
+
+ public int BytesReceived { get; set; }
+
+ #region IAsyncResult Members
+
+ public object AsyncState { get; internal set; }
+
+ public WaitHandle AsyncWaitHandle { get; internal set; }
+
+ public bool CompletedSynchronously { get; internal set; }
+
+ public bool IsCompleted { get; internal set; }
+
+ #endregion
+
+ internal ChannelAsyncResult(ChannelExec channel)
+ {
+ this.Channel = channel;
+ }
+ }
+}
diff --git a/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs b/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs
index 60372669..3a0c6c46 100644
--- a/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs
+++ b/Renci.SshClient/Renci.SshClient/Channels/ChannelExec.cs
@@ -10,14 +10,16 @@ namespace Renci.SshClient.Channels
internal class ChannelExec : Channel
{
- private EventWaitHandle _channelExecutionWaitHandle = new AutoResetEvent(false);
-
private Stream _channelData;
private Stream _channelExtendedData;
private Exception _exception;
+ private ChannelAsyncResult _asyncResult;
+
+ private AsyncCallback _callback;
+
public override ChannelTypes ChannelType
{
get { return ChannelTypes.Session; }
@@ -28,8 +30,24 @@ namespace Renci.SshClient.Channels
{
}
- internal void Execute(string command, Stream output, Stream extendedOutput)
+ internal ChannelAsyncResult BeginExecute(string command, Stream output, Stream extendedOutput, AsyncCallback callback, object state)
{
+ // Prevent from executing BeginExecute before calling EndExecute
+ if (this._asyncResult != null)
+ {
+ throw new InvalidOperationException("");
+ }
+
+ // Create new AsyncResult object
+ this._asyncResult = new ChannelAsyncResult(this)
+ {
+ AsyncWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset),
+ IsCompleted = false,
+ AsyncState = state,
+ };
+
+ this._callback = callback;
+
this._channelData = output;
this._channelExtendedData = extendedOutput;
@@ -44,11 +62,25 @@ namespace Renci.SshClient.Channels
Command = command,
});
+ return _asyncResult;
+ }
- this.Session.WaitHandle(this._channelExecutionWaitHandle);
+ internal void EndExecute(IAsyncResult result)
+ {
+ 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._asyncResult.AsyncWaitHandle.WaitOne();
this.Close();
+ this._asyncResult = null;
+
if (this._exception != null)
{
var exception = this._exception;
@@ -61,14 +93,14 @@ namespace Renci.SshClient.Channels
{
base.OnChannelEof();
- this._channelExecutionWaitHandle.Set();
+ this.ExecutionCompleted();
}
protected override void OnChannelFailed(uint reasonCode, string description)
{
base.OnChannelFailed(reasonCode, description);
this._exception = new InvalidOperationException(string.Format("Channel failed to open. Code: {0}, Reason {1}", reasonCode, description));
- this._channelExecutionWaitHandle.Set();
+ this.ExecutionCompleted();
}
protected override void OnChannelData(string data)
@@ -92,10 +124,14 @@ namespace Renci.SshClient.Channels
}
}
- private void Init()
+ private void ExecutionCompleted()
{
- this.ChannelData.Length = 0;
- this.ChannelExtendedData.Length = 0;
+ this._asyncResult.IsCompleted = true;
+ if (this._callback != null)
+ {
+ this._callback(this._asyncResult);
+ }
+ ((EventWaitHandle)_asyncResult.AsyncWaitHandle).Set();
}
}
}
diff --git a/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj b/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj
index fe73c195..72e90aeb 100644
--- a/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj
+++ b/Renci.SshClient/Renci.SshClient/Renci.SshClient.csproj
@@ -44,6 +44,7 @@
+
diff --git a/Renci.SshClient/Renci.SshClient/Session.cs b/Renci.SshClient/Renci.SshClient/Session.cs
index 5d2cdc0d..2558c177 100644
--- a/Renci.SshClient/Renci.SshClient/Session.cs
+++ b/Renci.SshClient/Renci.SshClient/Session.cs
@@ -27,7 +27,13 @@ namespace Renci.SshClient
var ep = new IPEndPoint(Dns.GetHostAddresses(connectionInfo.Host)[0], connectionInfo.Port);
var socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.ExclusiveAddressUse = true;
- socket.Connect(ep);
+
+ // Connect socket with 5 seconds timeout
+ var connectResult = socket.BeginConnect(ep, null, null);
+
+ connectResult.AsyncWaitHandle.WaitOne(1000 * 15);
+
+ socket.EndConnect(connectResult);
// Get server version from the server,
// ignore text lines which are sent before if any
@@ -208,9 +214,9 @@ namespace Renci.SshClient
internal abstract void SendMessage(Message message);
- internal void WaitHandle(EventWaitHandle waitHandle)
+ internal void WaitHandle(WaitHandle waitHandle)
{
- var waitHandles = new EventWaitHandle[]
+ var waitHandles = new WaitHandle[]
{
this._disconnectWaitHandle,
this._exceptionWaitHandle,
diff --git a/Renci.SshClient/Renci.SshClient/Shell.cs b/Renci.SshClient/Renci.SshClient/Shell.cs
index 416ae228..94db9541 100644
--- a/Renci.SshClient/Renci.SshClient/Shell.cs
+++ b/Renci.SshClient/Renci.SshClient/Shell.cs
@@ -1,4 +1,5 @@
+using System;
using System.IO;
using System.Text;
using Renci.SshClient.Channels;
@@ -15,28 +16,41 @@ namespace Renci.SshClient
public string Execute(string command)
{
- //var channel = new ChannelSession(this._session);
-
- MemoryStream resultStream = new MemoryStream();
-
-
- var channel = this._session.CreateChannel();
-
- channel.Execute(command, resultStream, null);
-
- return Encoding.ASCII.GetString(resultStream.ToArray());
+ return this.Execute(command, null);
}
public string Execute(string command, Stream extended)
{
MemoryStream resultStream = new MemoryStream();
- var channel = this._session.CreateChannel();
-
- channel.Execute(command, resultStream, extended);
+ this.Execute(command, resultStream, extended);
return Encoding.ASCII.GetString(resultStream.ToArray());
}
+ public void Execute(string command, Stream output, Stream extended)
+ {
+ this.EndExecute(this.BeginExecute(command, output, extended, null, null));
+ }
+
+ public IAsyncResult BeginExecute(string command, Stream output, AsyncCallback callback, object state)
+ {
+ return this.BeginExecute(command, output, null, callback, state);
+ }
+
+ public IAsyncResult BeginExecute(string command, Stream output, Stream extendedOutput, AsyncCallback callback, object state)
+ {
+ var channel = this._session.CreateChannel();
+
+ return channel.BeginExecute(command, output, extendedOutput, callback, state);
+ }
+
+ public void EndExecute(IAsyncResult asynchResult)
+ {
+ ChannelAsyncResult channelAsyncResult = asynchResult as ChannelAsyncResult;
+
+ channelAsyncResult.Channel.EndExecute(asynchResult);
+ }
+
}
}