瀏覽代碼

Introduce IChannel and IChannelSession interface to allow for unit testing.

Gert Driesen 11 年之前
父節點
當前提交
965a0ba4c7

+ 7 - 1
Renci.SshClient/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj

@@ -81,6 +81,12 @@
     <Compile Include="..\Renci.SshNet\Channels\ClientChannel.cs">
       <Link>Channels\ClientChannel.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Channels\IChannel.cs">
+      <Link>Channels\IChannel.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Channels\IChannelSession.cs">
+      <Link>Channels\IChannelSession.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Channels\ServerChannel.cs">
       <Link>Channels\ServerChannel.cs</Link>
     </Compile>
@@ -907,7 +913,7 @@
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
     <VisualStudio>
-      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
+      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 4 - 4
Renci.SshClient/Renci.SshNet.Silverlight/ScpClient.SilverlightShared.cs

@@ -1,5 +1,5 @@
-using Renci.SshNet.Channels;
-using Renci.SshNet.Messages.Connection;
+using System.Text;
+using Renci.SshNet.Channels;
 
 namespace Renci.SshNet
 {
@@ -8,9 +8,9 @@ namespace Renci.SshNet
     /// </summary>
     public partial class ScpClient
     {
-        partial void SendData(ChannelSession channel, string command)
+        partial void SendData(IChannelSession channel, string command)
         {
-            this.Session.SendMessage(new ChannelDataMessage(channel.RemoteChannelNumber, System.Text.Encoding.UTF8.GetBytes(command)));
+            channel.SendData(Encoding.UTF8.GetBytes(command));
         }
     }
 }

+ 7 - 1
Renci.SshClient/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj

@@ -135,6 +135,12 @@
     <Compile Include="..\Renci.SshNet\Channels\ClientChannel.cs">
       <Link>Channels\ClientChannel.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Channels\IChannel.cs">
+      <Link>Channels\IChannel.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Channels\IChannelSession.cs">
+      <Link>Channels\IChannelSession.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Channels\ServerChannel.cs">
       <Link>Channels\ServerChannel.cs</Link>
     </Compile>
@@ -896,7 +902,7 @@
       <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
         <SilverlightProjectProperties />
       </FlavorProperties>
-      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
+      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 7 - 1
Renci.SshClient/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj

@@ -129,6 +129,12 @@
     <Compile Include="..\Renci.SshNet\Channels\ClientChannel.cs">
       <Link>Channels\ClientChannel.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Channels\IChannel.cs">
+      <Link>Channels\IChannel.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Channels\IChannelSession.cs">
+      <Link>Channels\IChannelSession.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Channels\ServerChannel.cs">
       <Link>Channels\ServerChannel.cs</Link>
     </Compile>
@@ -904,7 +910,7 @@
   <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
   <ProjectExtensions>
     <VisualStudio>
-      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
+      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 11 - 4
Renci.SshClient/Renci.SshNet/Channels/Channel.cs

@@ -10,7 +10,7 @@ namespace Renci.SshNet.Channels
     /// <summary>
     /// Represents base class for SSH channel implementations.
     /// </summary>
-    internal abstract class Channel : IDisposable
+    internal abstract class Channel : IChannel
     {
         private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(false);
         private EventWaitHandle _channelServerWindowAdjustWaitHandle = new ManualResetEvent(false);
@@ -46,6 +46,9 @@ namespace Renci.SshNet.Channels
         /// <summary>
         /// Gets the local channel number.
         /// </summary>
+        /// <value>
+        /// The local channel number.
+        /// </value>
         public uint LocalChannelNumber { get; private set; }
 
         /// <summary>
@@ -238,15 +241,19 @@ namespace Renci.SshNet.Channels
         /// <summary>
         /// Sends the SSH_MSG_CHANNEL_EOF message.
         /// </summary>
-        internal void SendEof()
+        public void SendEof()
         {
             //  Send EOF message first when channel need to be closed
             this.SendMessage(new ChannelEofMessage(this.RemoteChannelNumber));
         }
 
-        internal void SendData(byte[] buffer)
+        /// <summary>
+        /// Sends a SSH_MSG_CHANNEL_DATA message with the specified payload.
+        /// </summary>
+        /// <param name="data">The payload to send.</param>
+        public void SendData(byte[] data)
         {
-            this.SendMessage(new ChannelDataMessage(this.RemoteChannelNumber, buffer));
+            this.SendMessage(new ChannelDataMessage(this.RemoteChannelNumber, data));
         }
 
         /// <summary>

+ 42 - 15
Renci.SshClient/Renci.SshNet/Channels/ChannelSession.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.Globalization;
+using System.Text;
 using System.Threading;
 using Renci.SshNet.Common;
 using Renci.SshNet.Messages.Connection;
@@ -9,7 +10,7 @@ namespace Renci.SshNet.Channels
     /// <summary>
     /// Implements Session SSH channel.
     /// </summary>
-    internal class ChannelSession : ClientChannel
+    internal class ChannelSession : ClientChannel, IChannelSession
     {
         /// <summary>
         /// Counts faile channel open attempts
@@ -112,7 +113,7 @@ namespace Renci.SshNet.Channels
         /// <param name="height">The height.</param>
         /// <param name="terminalModeValues">The terminal mode values.</param>
         /// <returns>
-        /// true if request was successful; otherwise false.
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
         /// </returns>
         public bool SendPseudoTerminalRequest(string environmentVariable, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues)
         {
@@ -129,7 +130,9 @@ namespace Renci.SshNet.Channels
         /// <param name="protocol">The protocol.</param>
         /// <param name="cookie">The cookie.</param>
         /// <param name="screenNumber">The screen number.</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendX11ForwardingRequest(bool isSingleConnection, string protocol, byte[] cookie, uint screenNumber)
         {
             this._channelRequestResponse.Reset();
@@ -143,7 +146,9 @@ namespace Renci.SshNet.Channels
         /// </summary>
         /// <param name="variableName">Name of the variable.</param>
         /// <param name="variableValue">The variable value.</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendEnvironmentVariableRequest(string variableName, string variableValue)
         {
             this._channelRequestResponse.Reset();
@@ -155,7 +160,9 @@ namespace Renci.SshNet.Channels
         /// <summary>
         /// Sends the shell request.
         /// </summary>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendShellRequest()
         {
             this._channelRequestResponse.Reset();
@@ -168,7 +175,9 @@ namespace Renci.SshNet.Channels
         /// Sends the exec request.
         /// </summary>
         /// <param name="command">The command.</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendExecRequest(string command)
         {
             this._channelRequestResponse.Reset();
@@ -181,7 +190,9 @@ namespace Renci.SshNet.Channels
         /// Sends the exec request.
         /// </summary>
         /// <param name="breakLength">Length of the break.</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendBreakRequest(uint breakLength)
         {
             this._channelRequestResponse.Reset();
@@ -194,7 +205,9 @@ namespace Renci.SshNet.Channels
         /// Sends the subsystem request.
         /// </summary>
         /// <param name="subsystem">The subsystem.</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendSubsystemRequest(string subsystem)
         {
             this._channelRequestResponse.Reset();
@@ -210,7 +223,9 @@ namespace Renci.SshNet.Channels
         /// <param name="rows">The rows.</param>
         /// <param name="width">The width.</param>
         /// <param name="height">The height.</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendWindowChangeRequest(uint columns, uint rows, uint width, uint height)
         {
             this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new WindowChangeRequestInfo(columns, rows, width, height)));
@@ -221,7 +236,9 @@ namespace Renci.SshNet.Channels
         /// Sends the local flow request.
         /// </summary>
         /// <param name="clientCanDo">if set to <c>true</c> [client can do].</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendLocalFlowRequest(bool clientCanDo)
         {
             this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new XonXoffRequestInfo(clientCanDo)));
@@ -232,7 +249,9 @@ namespace Renci.SshNet.Channels
         /// Sends the signal request.
         /// </summary>
         /// <param name="signalName">Name of the signal.</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendSignalRequest(string signalName)
         {
             this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new SignalRequestInfo(signalName)));
@@ -243,7 +262,9 @@ namespace Renci.SshNet.Channels
         /// Sends the exit status request.
         /// </summary>
         /// <param name="exitStatus">The exit status.</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendExitStatusRequest(uint exitStatus)
         {
             this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new ExitStatusRequestInfo(exitStatus)));
@@ -257,7 +278,9 @@ namespace Renci.SshNet.Channels
         /// <param name="coreDumped">if set to <c>true</c> [core dumped].</param>
         /// <param name="errorMessage">The error message.</param>
         /// <param name="language">The language.</param>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendExitSignalRequest(string signalName, bool coreDumped, string errorMessage, string language)
         {
             this.SendMessage(new ChannelRequestMessage(this.RemoteChannelNumber, new ExitSignalRequestInfo(signalName, coreDumped, errorMessage, language)));
@@ -267,7 +290,9 @@ namespace Renci.SshNet.Channels
         /// <summary>
         /// Sends eow@openssh.com request.
         /// </summary>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendEndOfWriteRequest()
         {
             this._channelRequestResponse.Reset();
@@ -279,7 +304,9 @@ namespace Renci.SshNet.Channels
         /// <summary>
         /// Sends keepalive@openssh.com request.
         /// </summary>
-        /// <returns>true if request was successful; otherwise false.</returns>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
         public bool SendKeepAliveRequest()
         {
             this._channelRequestResponse.Reset();

+ 82 - 0
Renci.SshClient/Renci.SshNet/Channels/IChannel.cs

@@ -0,0 +1,82 @@
+using System;
+using Renci.SshNet.Common;
+using Renci.SshNet.Messages.Connection;
+
+namespace Renci.SshNet.Channels
+{
+    /// <summary>
+    /// Represents SSH channel.
+    /// </summary>
+    internal interface IChannel : IDisposable
+    {
+        /// <summary>
+        /// Occurs when <see cref="ChannelDataMessage"/> message received
+        /// </summary>
+        event EventHandler<ChannelDataEventArgs> DataReceived;
+
+        /// <summary>
+        /// Occurs when <see cref="ChannelExtendedDataMessage"/> message received
+        /// </summary>
+        event EventHandler<ChannelDataEventArgs> ExtendedDataReceived;
+
+        /// <summary>
+        /// Occurs when <see cref="ChannelRequestMessage"/> message received
+        /// </summary>
+        event EventHandler<ChannelRequestEventArgs> RequestReceived;
+
+        /// <summary>
+        /// Occurs when <see cref="ChannelCloseMessage"/> message received
+        /// </summary>
+        event EventHandler<ChannelEventArgs> Closed;
+
+        /// <summary>
+        /// Gets the local channel number.
+        /// </summary>
+        /// <value>
+        /// The local channel number.
+        /// </value>
+        uint LocalChannelNumber { get; }
+
+        /// <summary>
+        /// Gets the maximum size of a packet.
+        /// </summary>
+        /// <value>
+        /// The maximum size of a packet.
+        /// </value>
+        uint LocalPacketSize { get; }
+
+        /// <summary>
+        /// Gets the maximum size of a data packet that can be sent using the channel.
+        /// </summary>
+        /// <value>
+        /// The maximum size of data that can be sent using a <see cref="ChannelDataMessage"/>
+        /// on the current channel.
+        /// </value>
+        /// <exception cref="InvalidOperationException">The channel has not been opened, or the open has not yet been confirmed.</exception>
+        uint RemotePacketSize { get; }
+
+        /// <summary>
+        /// Closes the channel.
+        /// </summary>
+        void Close();
+
+        /// <summary>
+        /// Gets a value indicating whether this channel is open.
+        /// </summary>
+        /// <value>
+        /// <c>true</c> if this channel is open; otherwise, <c>false</c>.
+        /// </value>
+        bool IsOpen { get; }
+
+        /// <summary>
+        /// Sends a SSH_MSG_CHANNEL_DATA message with the specified payload.
+        /// </summary>
+        /// <param name="data">The payload to send.</param>
+        void SendData(byte[] data);
+
+        /// <summary>
+        /// Sends the SSH_MSG_CHANNEL_EOF message.
+        /// </summary>
+        void SendEof();
+    }
+}

+ 155 - 0
Renci.SshClient/Renci.SshNet/Channels/IChannelSession.cs

@@ -0,0 +1,155 @@
+using System.Collections.Generic;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Channels
+{
+    /// <summary>
+    /// Session SSH channel.
+    /// </summary>
+    internal interface IChannelSession : IChannel
+    {
+        /// <summary>
+        /// Opens the channel.
+        /// </summary>
+        void Open();
+
+        /// <summary>
+        /// Sends the pseudo terminal request.
+        /// </summary>
+        /// <param name="environmentVariable">The environment variable.</param>
+        /// <param name="columns">The columns.</param>
+        /// <param name="rows">The rows.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <param name="terminalModeValues">The terminal mode values.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendPseudoTerminalRequest(string environmentVariable, uint columns, uint rows, uint width, uint height,
+            IDictionary<TerminalModes, uint> terminalModeValues);
+
+        /// <summary>
+        /// Sends the X11 forwarding request.
+        /// </summary>
+        /// <param name="isSingleConnection">if set to <c>true</c> the it is single connection.</param>
+        /// <param name="protocol">The protocol.</param>
+        /// <param name="cookie">The cookie.</param>
+        /// <param name="screenNumber">The screen number.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendX11ForwardingRequest(bool isSingleConnection, string protocol, byte[] cookie, uint screenNumber);
+
+        /// <summary>
+        /// Sends the environment variable request.
+        /// </summary>
+        /// <param name="variableName">Name of the variable.</param>
+        /// <param name="variableValue">The variable value.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendEnvironmentVariableRequest(string variableName, string variableValue);
+
+        /// <summary>
+        /// Sends the shell request.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendShellRequest();
+
+        /// <summary>
+        /// Sends the exec request.
+        /// </summary>
+        /// <param name="command">The command.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendExecRequest(string command);
+
+        /// <summary>
+        /// Sends the exec request.
+        /// </summary>
+        /// <param name="breakLength">Length of the break.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendBreakRequest(uint breakLength);
+
+        /// <summary>
+        /// Sends the subsystem request.
+        /// </summary>
+        /// <param name="subsystem">The subsystem.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendSubsystemRequest(string subsystem);
+
+        /// <summary>
+        /// Sends the window change request.
+        /// </summary>
+        /// <param name="columns">The columns.</param>
+        /// <param name="rows">The rows.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendWindowChangeRequest(uint columns, uint rows, uint width, uint height);
+
+        /// <summary>
+        /// Sends the local flow request.
+        /// </summary>
+        /// <param name="clientCanDo">if set to <c>true</c> [client can do].</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendLocalFlowRequest(bool clientCanDo);
+
+        /// <summary>
+        /// Sends the signal request.
+        /// </summary>
+        /// <param name="signalName">Name of the signal.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendSignalRequest(string signalName);
+
+        /// <summary>
+        /// Sends the exit status request.
+        /// </summary>
+        /// <param name="exitStatus">The exit status.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendExitStatusRequest(uint exitStatus);
+
+        /// <summary>
+        /// Sends the exit signal request.
+        /// </summary>
+        /// <param name="signalName">Name of the signal.</param>
+        /// <param name="coreDumped">if set to <c>true</c> [core dumped].</param>
+        /// <param name="errorMessage">The error message.</param>
+        /// <param name="language">The language.</param>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendExitSignalRequest(string signalName, bool coreDumped, string errorMessage, string language);
+
+        /// <summary>
+        /// Sends eow@openssh.com request.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendEndOfWriteRequest();
+
+        /// <summary>
+        /// Sends keepalive@openssh.com request.
+        /// </summary>
+        /// <returns>
+        /// <c>true</c> if request was successful; otherwise <c>false</c>.
+        /// </returns>
+        bool SendKeepAliveRequest();
+    }
+}

+ 53 - 1
Renci.SshClient/Renci.SshNet/ISession.cs

@@ -1,12 +1,64 @@
 using System;
+using Renci.SshNet.Channels;
+using Renci.SshNet.Common;
+using Renci.SshNet.Messages;
 using Renci.SshNet.Messages.Authentication;
 
 namespace Renci.SshNet
 {
-    public interface ISession
+    /// <summary>
+    /// Provides functionality to connect and interact with SSH server.
+    /// </summary>
+    internal interface ISession
     {
+        ///// <summary>
+        ///// Gets or sets the connection info.
+        ///// </summary>
+        ///// <value>The connection info.</value>
+        //IConnectionInfo ConnectionInfo { get; }
+
+        /// <summary>
+        /// Create a new SSH session channel.
+        /// </summary>
+        /// <returns>
+        /// A new SSH session channel.
+        /// </returns>
+        IChannelSession CreateChannelSession();
+
+       /// <summary>
+        /// Registers SSH message with the session.
+        /// </summary>
+        /// <param name="messageName">The name of the message to register with the session.</param>
         void RegisterMessage(string messageName);
+
+        /// <summary>
+        /// Sends a message to the server.
+        /// </summary>
+        /// <param name="message">The message to send.</param>
+        /// <exception cref="SshConnectionException">The client is not connected.</exception>
+        /// <exception cref="SshOperationTimeoutException">The operation timed out.</exception>
+        /// <exception cref="InvalidOperationException">The size of the packet exceeds the maximum size defined by the protocol.</exception>
+        void SendMessage(Message message);
+
+        /// <summary>
+        /// Unregister SSH message from the session.
+        /// </summary>
+        /// <param name="messageName">The name of the message to unregister with the session.</param>
         void UnRegisterMessage(string messageName);
+
+        /// <summary>
+        /// Occurs when session has been disconnected from the server.
+        /// </summary>
+        event EventHandler<EventArgs> Disconnected;
+
+        /// <summary>
+        /// Occurs when an error occurred.
+        /// </summary>
+        event EventHandler<ExceptionEventArgs> ErrorOccured;
+
+        /// <summary>
+        /// Occurs when <see cref="BannerMessage"/> message is received from the server.
+        /// </summary>
         event EventHandler<MessageEventArgs<BannerMessage>> UserAuthenticationBannerReceived;
     }
 }

+ 2 - 0
Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj

@@ -57,6 +57,8 @@
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="BaseClient.cs" />
+    <Compile Include="Channels\IChannel.cs" />
+    <Compile Include="Channels\IChannelSession.cs" />
     <Compile Include="CommandAsyncResult.cs" />
     <Compile Include="Channels\Channel.cs" />
     <Compile Include="Channels\ChannelDirectTcpip.cs" />

+ 1 - 1
Renci.SshClient/Renci.SshNet/ScpClient.NET.cs

@@ -295,7 +295,7 @@ namespace Renci.SshNet
             }
         }
 
-        partial void SendData(ChannelSession channel, string command)
+        partial void SendData(IChannelSession channel, string command)
         {
             channel.SendData(System.Text.Encoding.Default.GetBytes(command));
         }

+ 3 - 3
Renci.SshClient/Renci.SshNet/ScpClient.cs

@@ -342,9 +342,9 @@ namespace Renci.SshNet
             }
         }
 
-        partial void SendData(ChannelSession channel, string command);
+        partial void SendData(IChannelSession channel, string command);
 
-        private void SendData(ChannelSession channel, byte[] buffer, int length)
+        private void SendData(IChannelSession channel, byte[] buffer, int length)
         {
             if (length == buffer.Length)
             {
@@ -356,7 +356,7 @@ namespace Renci.SshNet
             }
         }
 
-        private void SendData(ChannelSession channel, byte[] buffer)
+        private void SendData(IChannelSession channel, byte[] buffer)
         {
             channel.SendData(buffer);
         }

+ 40 - 8
Renci.SshClient/Renci.SshNet/Session.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Net;
 using System.Net.Sockets;
-using System.Runtime.CompilerServices;
 using System.Security.Cryptography;
 using System.Text;
 using System.Text.RegularExpressions;
@@ -656,6 +655,24 @@ namespace Renci.SshNet
             }
         }
 
+        /// <summary>
+        /// Create a new SSH session channel.
+        /// </summary>
+        /// <returns>
+        /// A new SSH session channel.
+        /// </returns>
+        IChannelSession ISession.CreateChannelSession()
+        {
+            return CreateClientChannel<ChannelSession>();
+        }
+
+        /// <summary>
+        /// Create a new client channel.
+        /// </summary>
+        /// <typeparam name="T">The type of the channel.</typeparam>
+        /// <returns>
+        /// A new client channel.
+        /// </returns>
         internal T CreateClientChannel<T>() where T : ClientChannel, new()
         {
             var channel = new T();
@@ -766,9 +783,24 @@ namespace Renci.SshNet
         }
 
         /// <summary>
-        /// Sends packet message to the server.
+        /// Sends a message to the server.
         /// </summary>
-        /// <param name="message">The message.</param>
+        /// <param name="message">The message to send.</param>
+        /// <exception cref="SshConnectionException">The client is not connected.</exception>
+        /// <exception cref="SshOperationTimeoutException">The operation timed out.</exception>
+        /// <exception cref="InvalidOperationException">The size of the packet exceeds the maximum size defined by the protocol.</exception>
+        void ISession.SendMessage(Message message)
+        {
+            SendMessage(message);
+        }
+
+        /// <summary>
+        /// Sends a message to the server.
+        /// </summary>
+        /// <param name="message">The message to send.</param>
+        /// <exception cref="SshConnectionException">The client is not connected.</exception>
+        /// <exception cref="SshOperationTimeoutException">The operation timed out.</exception>
+        /// <exception cref="InvalidOperationException">The size of the packet exceeds the maximum size defined by the protocol.</exception>
         internal void SendMessage(Message message)
         {
             if (this._socket == null || !this._socket.CanWrite())
@@ -1002,7 +1034,7 @@ namespace Renci.SshNet
 
             var disconnectMessage = new DisconnectMessage(reasonCode, message);
 
-            this.SendMessage(disconnectMessage);
+            SendMessage(disconnectMessage);
 
             this._isDisconnectMessageSent = true;
         }
@@ -1586,18 +1618,18 @@ namespace Renci.SshNet
         #region Message loading functions
 
         /// <summary>
-        /// Registers SSH Message with the session.
+        /// Registers SSH message with the session.
         /// </summary>
-        /// <param name="messageName">Name of the message.</param>
+        /// <param name="messageName">The name of the message to register with the session.</param>
         public void RegisterMessage(string messageName)
         {
             this.InternalRegisterMessage(messageName);
         }
 
         /// <summary>
-        /// Removes SSH message from the session
+        /// Unregister SSH message from the session.
         /// </summary>
-        /// <param name="messageName">Name of the message.</param>
+        /// <param name="messageName">The name of the message to unregister with the session.</param>
         public void UnRegisterMessage(string messageName)
         {
             this.InternalUnRegisterMessage(messageName);

+ 1 - 1
Renci.SshClient/Renci.SshNet/Shell.cs

@@ -15,7 +15,7 @@ namespace Renci.SshNet
     {
         private readonly Session _session;
 
-        private ChannelSession _channel;
+        private IChannelSession _channel;
 
         private EventWaitHandle _channelClosedWaitHandle;
 

+ 1 - 1
Renci.SshClient/Renci.SshNet/ShellStream.cs

@@ -19,7 +19,7 @@ namespace Renci.SshNet
 
         private const int _bufferSize = 1024;
 
-        private ChannelSession _channel;
+        private IChannelSession _channel;
 
         private readonly Encoding _encoding;
 

+ 6 - 6
Renci.SshClient/Renci.SshNet/SubsystemSession.cs

@@ -10,11 +10,11 @@ namespace Renci.SshNet.Sftp
     /// <summary>
     /// Base class for SSH subsystem implementations
     /// </summary>
-    public abstract class SubsystemSession : IDisposable
+    internal abstract class SubsystemSession : IDisposable
     {
-        private readonly Session _session;
+        private readonly ISession _session;
         private readonly string _subsystemName;
-        private ChannelSession _channel;
+        private IChannelSession _channel;
         private Exception _exception;
         private EventWaitHandle _errorOccuredWaitHandle = new ManualResetEvent(false);
         private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(false);
@@ -40,7 +40,7 @@ namespace Renci.SshNet.Sftp
         /// <value>
         /// The channel associated with this session.
         /// </value>
-        internal ChannelSession Channel
+        internal IChannelSession Channel
         {
             get { return _channel; }
         }
@@ -58,7 +58,7 @@ namespace Renci.SshNet.Sftp
         /// <param name="operationTimeout">The operation timeout.</param>
         /// <param name="encoding">The character encoding to use.</param>
         /// <exception cref="ArgumentNullException"><paramref name="session" /> or <paramref name="subsystemName" /> or <paramref name="encoding"/>is null.</exception>
-        protected SubsystemSession(Session session, string subsystemName, TimeSpan operationTimeout, Encoding encoding)
+        protected SubsystemSession(ISession session, string subsystemName, TimeSpan operationTimeout, Encoding encoding)
         {
             if (session == null)
                 throw new ArgumentNullException("session");
@@ -78,7 +78,7 @@ namespace Renci.SshNet.Sftp
         /// </summary>
         public void Connect()
         {
-            this._channel = this._session.CreateClientChannel<ChannelSession>();
+            this._channel = this._session.CreateChannelSession();
 
             this._session.ErrorOccured += Session_ErrorOccured;
             this._session.Disconnected += Session_Disconnected;