diff --git a/Renci.SshClient/Renci.SshNet/Channels/Channel.cs b/Renci.SshClient/Renci.SshNet/Channels/Channel.cs
index e06f6a73..02a86a17 100644
--- a/Renci.SshClient/Renci.SshNet/Channels/Channel.cs
+++ b/Renci.SshClient/Renci.SshNet/Channels/Channel.cs
@@ -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));
+ }
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Channels/ChannelSession.cs b/Renci.SshClient/Renci.SshNet/Channels/ChannelSession.cs
index 79cf94c6..473e9af5 100644
--- a/Renci.SshClient/Renci.SshNet/Channels/ChannelSession.cs
+++ b/Renci.SshClient/Renci.SshNet/Channels/ChannelSession.cs
@@ -7,7 +7,7 @@ using System.Globalization;
namespace Renci.SshNet.Channels
{
///
- /// Implements "forwarded-tcpip" SSH channel.
+ /// Implements Session SSH channel.
///
internal class ChannelSession : Channel
{
@@ -271,6 +271,37 @@ namespace Renci.SshNet.Channels
return true;
}
+ ///
+ /// Sends eow@openssh.com request.
+ ///
+ /// true if request was successful; otherwise false.
+ public bool SendEndOfWriteRequest()
+ {
+ this._channelRequestResponse.Reset();
+
+ this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new EndOfWriteRequestInfo()));
+
+ this._channelRequestResponse.WaitOne();
+
+ return this._channelRequestSucces;
+ }
+
+ ///
+ /// Sends keepalive@openssh.com request.
+ ///
+ /// true if request was successful; otherwise false.
+ public bool SendKeepAliveRequest()
+ {
+ this._channelRequestResponse.Reset();
+
+ this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new KeepAliveRequestInfo()));
+
+ this._channelRequestResponse.WaitOne();
+
+ return this._channelRequestSucces;
+ }
+
+
///
/// Called when channel request was successful
///
diff --git a/Renci.SshClient/Renci.SshNet/ConnectionInfo.cs b/Renci.SshClient/Renci.SshNet/ConnectionInfo.cs
index 6b8a48e4..61caefdb 100644
--- a/Renci.SshClient/Renci.SshNet/ConnectionInfo.cs
+++ b/Renci.SshClient/Renci.SshNet/ConnectionInfo.cs
@@ -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
{
///
@@ -68,6 +69,11 @@ namespace Renci.SshNet
///
public IDictionary CompressionAlgorithms { get; private set; }
+ ///
+ /// Gets supported channel requests for this connection.
+ ///
+ public IDictionary ChannelRequests { get; private set; }
+
///
/// Gets connection host.
///
@@ -194,6 +200,22 @@ namespace Renci.SshNet
{"zlib@openssh.com", typeof(ZlibOpenSsh)},
};
+ this.ChannelRequests = new Dictionary()
+ {
+ {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()},
+ };
}
///
diff --git a/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs b/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs
index e1be096a..cf84643b 100644
--- a/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs
+++ b/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs
@@ -15,32 +15,12 @@ namespace Renci.SshNet.Messages.Connection
///
/// The name of the request.
///
- public string RequestName
- {
- get
- {
- return this.Info.RequestName;
- }
- }
+ public string RequestName { get; private set; }
///
- /// Gets a value indicating whether the reply is needed.
+ /// Gets channel request data.
///
- ///
- /// true if reply is needed; otherwise, false.
- ///
- public bool WantReply
- {
- get
- {
- return this.Info.WantReply;
- }
- }
-
- ///
- /// Gets channel request information.
- ///
- public RequestInfo Info { get; private set; }
+ public byte[] RequestData { get; private set; }
///
/// Initializes a new instance of the 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();
}
///
@@ -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();
}
///
@@ -131,7 +61,7 @@ namespace Renci.SshNet.Messages.Connection
base.SaveData();
this.Write(this.RequestName);
- this.Write(this.Info.GetBytes());
+ this.Write(this.RequestData);
}
}
}
diff --git a/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs b/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs
new file mode 100644
index 00000000..5ef73c00
--- /dev/null
+++ b/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs
@@ -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
+ {
+ ///
+ /// Channel request name
+ ///
+ public const string NAME = "eow@openssh.com";
+
+ ///
+ /// Gets the name of the request.
+ ///
+ ///
+ /// The name of the request.
+ ///
+ public override string RequestName
+ {
+ get { return EndOfWriteRequestInfo.NAME; }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public EndOfWriteRequestInfo()
+ {
+ this.WantReply = false;
+ }
+ }
+}
diff --git a/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/KeepAliveRequestInfo.cs b/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/KeepAliveRequestInfo.cs
new file mode 100644
index 00000000..048730ce
--- /dev/null
+++ b/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/KeepAliveRequestInfo.cs
@@ -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
+ {
+ ///
+ /// Channel request name
+ ///
+ public const string NAME = "keepalive@openssh.com";
+
+ ///
+ /// Gets the name of the request.
+ ///
+ ///
+ /// The name of the request.
+ ///
+ public override string RequestName
+ {
+ get { return KeepAliveRequestInfo.NAME; }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public KeepAliveRequestInfo()
+ {
+ this.WantReply = false;
+ }
+ }
+}
diff --git a/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj b/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj
index 19c5c237..ee69304e 100644
--- a/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj
+++ b/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj
@@ -103,6 +103,8 @@
Code
+
+
Code