mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 01:05:42 +00:00
Add ChannelAsyncResult and BeginEecute and EndExecute methods
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Renci.SshClient.Channels
|
||||
{
|
||||
public class ChannelAsyncResult : IAsyncResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the channel that async result was created for.
|
||||
/// </summary>
|
||||
/// <value>The channel.</value>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Channels\ChannelAsyncResult.cs" />
|
||||
<Compile Include="Security\Algorithm.cs" />
|
||||
<Compile Include="Security\Cipher.cs" />
|
||||
<Compile Include="Security\CipherAES128.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,
|
||||
|
||||
@@ -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<ChannelExec>();
|
||||
|
||||
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<ChannelExec>();
|
||||
|
||||
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<ChannelExec>();
|
||||
|
||||
return channel.BeginExecute(command, output, extendedOutput, callback, state);
|
||||
}
|
||||
|
||||
public void EndExecute(IAsyncResult asynchResult)
|
||||
{
|
||||
ChannelAsyncResult channelAsyncResult = asynchResult as ChannelAsyncResult;
|
||||
|
||||
channelAsyncResult.Channel.EndExecute(asynchResult);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user