Add KeepAliveRequestInfo class

Add EndOfWriteRequestInfo class
Refactor channel request messages to allow custom channel reuqest support
This commit is contained in:
olegkap_cp
2011-08-03 18:53:45 +00:00
parent e369b0f53e
commit 033218647f
7 changed files with 148 additions and 80 deletions
@@ -3,6 +3,7 @@ using System.Threading;
using Renci.SshNet.Common;
using Renci.SshNet.Messages;
using Renci.SshNet.Messages.Connection;
using System.Globalization;
namespace Renci.SshNet.Channels
{
@@ -540,7 +541,21 @@ namespace Renci.SshNet.Channels
{
if (e.Message.LocalChannelNumber == this.LocalChannelNumber)
{
this.OnRequest(e.Message.Info);
if (this._session.ConnectionInfo.ChannelRequests.ContainsKey(e.Message.RequestName))
{
// Get request specific class
RequestInfo requestInfo = this._session.ConnectionInfo.ChannelRequests[e.Message.RequestName];
// Load request specific data
requestInfo.Load(e.Message.RequestData);
// Raise request specific event
this.OnRequest(requestInfo);
}
else
{
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Request '{0}' is not supported.", e.Message.RequestName));
}
}
}
@@ -7,7 +7,7 @@ using System.Globalization;
namespace Renci.SshNet.Channels
{
/// <summary>
/// Implements "forwarded-tcpip" SSH channel.
/// Implements Session SSH channel.
/// </summary>
internal class ChannelSession : Channel
{
@@ -271,6 +271,37 @@ namespace Renci.SshNet.Channels
return true;
}
/// <summary>
/// Sends eow@openssh.com request.
/// </summary>
/// <returns>true if request was successful; otherwise false.</returns>
public bool SendEndOfWriteRequest()
{
this._channelRequestResponse.Reset();
this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new EndOfWriteRequestInfo()));
this._channelRequestResponse.WaitOne();
return this._channelRequestSucces;
}
/// <summary>
/// Sends keepalive@openssh.com request.
/// </summary>
/// <returns>true if request was successful; otherwise false.</returns>
public bool SendKeepAliveRequest()
{
this._channelRequestResponse.Reset();
this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new KeepAliveRequestInfo()));
this._channelRequestResponse.WaitOne();
return this._channelRequestSucces;
}
/// <summary>
/// Called when channel request was successful
/// </summary>
@@ -8,6 +8,7 @@ using Renci.SshNet.Messages.Authentication;
using Renci.SshNet.Common;
using System.Threading;
using System.Net;
using Renci.SshNet.Messages.Connection;
namespace Renci.SshNet
{
/// <summary>
@@ -68,6 +69,11 @@ namespace Renci.SshNet
/// </summary>
public IDictionary<string, Type> CompressionAlgorithms { get; private set; }
/// <summary>
/// Gets supported channel requests for this connection.
/// </summary>
public IDictionary<string, RequestInfo> ChannelRequests { get; private set; }
/// <summary>
/// Gets connection host.
/// </summary>
@@ -194,6 +200,22 @@ namespace Renci.SshNet
{"zlib@openssh.com", typeof(ZlibOpenSsh)},
};
this.ChannelRequests = new Dictionary<string, RequestInfo>()
{
{EnvironmentVariableRequestInfo.NAME, new EnvironmentVariableRequestInfo()},
{ExecRequestInfo.NAME, new ExecRequestInfo()},
{ExitSignalRequestInfo.NAME, new ExitSignalRequestInfo()},
{ExitStatusRequestInfo.NAME, new ExitStatusRequestInfo()},
{PseudoTerminalRequestInfo.NAME, new PseudoTerminalRequestInfo()},
{ShellRequestInfo.NAME, new ShellRequestInfo()},
{SignalRequestInfo.NAME, new SignalRequestInfo()},
{SubsystemRequestInfo.NAME, new SubsystemRequestInfo()},
{WindowChangeRequestInfo.NAME, new WindowChangeRequestInfo()},
{X11ForwardingRequestInfo.NAME, new X11ForwardingRequestInfo()},
{XonXoffRequestInfo.NAME, new XonXoffRequestInfo()},
{EndOfWriteRequestInfo.NAME, new EndOfWriteRequestInfo()},
{KeepAliveRequestInfo.NAME, new KeepAliveRequestInfo()},
};
}
/// <summary>
@@ -15,32 +15,12 @@ namespace Renci.SshNet.Messages.Connection
/// <value>
/// The name of the request.
/// </value>
public string RequestName
{
get
{
return this.Info.RequestName;
}
}
public string RequestName { get; private set; }
/// <summary>
/// Gets a value indicating whether the reply is needed.
/// Gets channel request data.
/// </summary>
/// <value>
/// <c>true</c> if reply is needed; otherwise, <c>false</c>.
/// </value>
public bool WantReply
{
get
{
return this.Info.WantReply;
}
}
/// <summary>
/// Gets channel request information.
/// </summary>
public RequestInfo Info { get; private set; }
public byte[] RequestData { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="ChannelRequestMessage"/> class.
@@ -58,7 +38,8 @@ namespace Renci.SshNet.Messages.Connection
public ChannelRequestMessage(uint localChannelName, RequestInfo info)
{
this.LocalChannelNumber = localChannelName;
this.Info = info;
this.RequestName = info.RequestName;
this.RequestData = info.GetBytes();
}
/// <summary>
@@ -68,59 +49,8 @@ namespace Renci.SshNet.Messages.Connection
{
base.LoadData();
var requestName = this.ReadString();
var bytes = this.ReadBytes();
if (requestName == EnvironmentVariableRequestInfo.NAME)
{
this.Info = new EnvironmentVariableRequestInfo();
}
else if (requestName == ExecRequestInfo.NAME)
{
this.Info = new ExecRequestInfo();
}
else if (requestName == ExitSignalRequestInfo.NAME)
{
this.Info = new ExitSignalRequestInfo();
}
else if (requestName == ExitStatusRequestInfo.NAME)
{
this.Info = new ExitStatusRequestInfo();
}
else if (requestName == PseudoTerminalRequestInfo.NAME)
{
this.Info = new PseudoTerminalRequestInfo();
}
else if (requestName == ShellRequestInfo.NAME)
{
this.Info = new ShellRequestInfo();
}
else if (requestName == SignalRequestInfo.NAME)
{
this.Info = new SignalRequestInfo();
}
else if (requestName == SubsystemRequestInfo.NAME)
{
this.Info = new SubsystemRequestInfo();
}
else if (requestName == WindowChangeRequestInfo.NAME)
{
this.Info = new WindowChangeRequestInfo();
}
else if (requestName == X11ForwardingRequestInfo.NAME)
{
this.Info = new X11ForwardingRequestInfo();
}
else if (requestName == XonXoffRequestInfo.NAME)
{
this.Info = new XonXoffRequestInfo();
}
else
{
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Request '{0}' is not supported.", requestName));
}
this.Info.Load(bytes);
this.RequestName = this.ReadString();
this.RequestData = this.ReadBytes();
}
/// <summary>
@@ -131,7 +61,7 @@ namespace Renci.SshNet.Messages.Connection
base.SaveData();
this.Write(this.RequestName);
this.Write(this.Info.GetBytes());
this.Write(this.RequestData);
}
}
}
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Messages.Connection
{
public class EndOfWriteRequestInfo : RequestInfo
{
/// <summary>
/// Channel request name
/// </summary>
public const string NAME = "eow@openssh.com";
/// <summary>
/// Gets the name of the request.
/// </summary>
/// <value>
/// The name of the request.
/// </value>
public override string RequestName
{
get { return EndOfWriteRequestInfo.NAME; }
}
/// <summary>
/// Initializes a new instance of the <see cref="EndOfWriteRequestInfo"/> class.
/// </summary>
public EndOfWriteRequestInfo()
{
this.WantReply = false;
}
}
}
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Messages.Connection
{
public class KeepAliveRequestInfo : RequestInfo
{
/// <summary>
/// Channel request name
/// </summary>
public const string NAME = "keepalive@openssh.com";
/// <summary>
/// Gets the name of the request.
/// </summary>
/// <value>
/// The name of the request.
/// </value>
public override string RequestName
{
get { return KeepAliveRequestInfo.NAME; }
}
/// <summary>
/// Initializes a new instance of the <see cref="EndOfWriteRequestInfo"/> class.
/// </summary>
public KeepAliveRequestInfo()
{
this.WantReply = false;
}
}
}
@@ -103,6 +103,8 @@
<Compile Include="ForwardedPortLocal.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Messages\Connection\ChannelRequest\EndOfWriteRequestInfo.cs" />
<Compile Include="Messages\Connection\ChannelRequest\KeepAliveRequestInfo.cs" />
<Compile Include="Security\Algorithm.cs">
<SubType>Code</SubType>
</Compile>