Преглед изворни кода

Introduce specialized GlobalRequestMessage classes for tcpip-forward and cancel-tcpip-forward.

drieseng пре 9 година
родитељ
комит
5916656d66

+ 0 - 31
src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToGlobalRequestName.cs

@@ -1,31 +0,0 @@
-using System.Text;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Renci.SshNet.Messages.Connection;
-
-namespace Renci.SshNet.Tests.Classes.Common
-{
-    [TestClass]
-    public class ExtensionsTest_ToGlobalRequestName
-    {
-        [TestMethod]
-        public void TcpipForward()
-        {
-            var data = Encoding.ASCII.GetBytes("tcpip-forward");
-
-            var actual = data.ToGlobalRequestName();
-
-            Assert.AreEqual(GlobalRequestName.TcpIpForward, actual);
-        }
-
-        [TestMethod]
-        public void CancelTcpipForward()
-        {
-            var data = Encoding.ASCII.GetBytes("cancel-tcpip-forward");
-
-            var actual = data.ToGlobalRequestName();
-
-            Assert.AreEqual(GlobalRequestName.CancelTcpIpForward, actual);
-        }
-
-    }
-}

+ 2 - 4
src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStarted_ChannelBound.cs

@@ -112,9 +112,8 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<TcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.TcpIpForward &&
                                 g.AddressToBind == ForwardedPort.BoundHost &&
                                 g.PortToBind == ForwardedPort.BoundPort)))
                 .Callback(
@@ -140,9 +139,8 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<CancelTcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.CancelTcpIpForward &&
                                 g.AddressToBind == ForwardedPort.BoundHost && g.PortToBind == ForwardedPort.BoundPort))).Callback(
                                     () =>
                                         {

+ 4 - 5
src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStopped.cs

@@ -61,9 +61,8 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<TcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.TcpIpForward &&
                                 g.AddressToBind == ForwardedPort.BoundHost &&
                                 g.PortToBind == ForwardedPort.BoundPort)))
                 .Callback(
@@ -74,10 +73,10 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<CancelTcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.CancelTcpIpForward &&
-                                g.AddressToBind == ForwardedPort.BoundHost && g.PortToBind == ForwardedPort.BoundPort)))
+                                g.AddressToBind == ForwardedPort.BoundHost &&
+                                g.PortToBind == ForwardedPort.BoundPort)))
                 .Callback(
                     () =>
                         _sessionMock.Raise(s => s.RequestSuccessReceived += null,

+ 4 - 5
src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs

@@ -37,10 +37,10 @@ namespace Renci.SshNet.Tests.Classes
                 _sessionMock.Setup(
                     p =>
                         p.SendMessage(
-                            It.Is<GlobalRequestMessage>(
+                            It.Is<CancelTcpIpForwardGlobalRequestMessage>(
                                 g =>
-                                    g.RequestName == GlobalRequestName.CancelTcpIpForward &&
-                                    g.AddressToBind == _forwardedPort.BoundHost && g.PortToBind == _forwardedPort.BoundPort)));
+                                    g.AddressToBind == _forwardedPort.BoundHost &&
+                                    g.PortToBind == _forwardedPort.BoundPort)));
                 _sessionMock.Setup(p => p.MessageListenerCompleted).Returns(new ManualResetEvent(true));
                 _forwardedPort.Dispose();
                 _forwardedPort = null;
@@ -68,9 +68,8 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<TcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.TcpIpForward &&
                                 g.AddressToBind == _forwardedPort.BoundHost &&
                                 g.PortToBind == _forwardedPort.BoundPort)))
                 .Callback(

+ 4 - 5
src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs

@@ -38,10 +38,10 @@ namespace Renci.SshNet.Tests.Classes
                 _sessionMock.Setup(
                     p =>
                         p.SendMessage(
-                            It.Is<GlobalRequestMessage>(
+                            It.Is<CancelTcpIpForwardGlobalRequestMessage>(
                                 g =>
-                                    g.RequestName == GlobalRequestName.CancelTcpIpForward &&
-                                    g.AddressToBind == _forwardedPort.BoundHost && g.PortToBind == _forwardedPort.BoundPort)));
+                                    g.AddressToBind == _forwardedPort.BoundHost &&
+                                    g.PortToBind == _forwardedPort.BoundPort)));
                 _sessionMock.Setup(p => p.MessageListenerCompleted).Returns(new ManualResetEvent(true));
                 _forwardedPort.Dispose();
                 _forwardedPort = null;
@@ -69,9 +69,8 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<TcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.TcpIpForward &&
                                 g.AddressToBind == _forwardedPort.BoundHost &&
                                 g.PortToBind == _forwardedPort.BoundPort)))
                 .Callback(

+ 7 - 8
src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStopped.cs

@@ -37,10 +37,10 @@ namespace Renci.SshNet.Tests.Classes
                 _sessionMock.Setup(
                     p =>
                         p.SendMessage(
-                            It.Is<GlobalRequestMessage>(
+                            It.Is<CancelTcpIpForwardGlobalRequestMessage>(
                                 g =>
-                                    g.RequestName == GlobalRequestName.CancelTcpIpForward &&
-                                    g.AddressToBind == _forwardedPort.BoundHost && g.PortToBind == _forwardedPort.BoundPort)));
+                                    g.AddressToBind == _forwardedPort.BoundHost &&
+                                    g.PortToBind == _forwardedPort.BoundPort)));
                 _sessionMock.Setup(p => p.MessageListenerCompleted).Returns(new ManualResetEvent(true));
                 _forwardedPort.Dispose();
                 _forwardedPort = null;
@@ -68,9 +68,8 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<TcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.TcpIpForward &&
                                 g.AddressToBind == _forwardedPort.BoundHost &&
                                 g.PortToBind == _forwardedPort.BoundPort)))
                 .Callback(
@@ -82,10 +81,10 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<CancelTcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.CancelTcpIpForward &&
-                                g.AddressToBind == _forwardedPort.BoundHost && g.PortToBind == _forwardedPort.BoundPort)))
+                                g.AddressToBind == _forwardedPort.BoundHost &&
+                                g.PortToBind == _forwardedPort.BoundPort)))
                 .Callback(
                     () =>
                         _sessionMock.Raise(s => s.RequestSuccessReceived += null,

+ 3 - 6
src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Started.cs

@@ -37,10 +37,8 @@ namespace Renci.SshNet.Tests.Classes
                 _sessionMock.Setup(
                     p =>
                         p.SendMessage(
-                            It.Is<GlobalRequestMessage>(
-                                g =>
-                                    g.RequestName == GlobalRequestName.CancelTcpIpForward &&
-                                    g.AddressToBind == _forwardedPort.BoundHost && g.PortToBind == _forwardedPort.BoundPort)));
+                            It.Is<CancelTcpIpForwardGlobalRequestMessage>(
+                                g => g.AddressToBind == _forwardedPort.BoundHost && g.PortToBind == _forwardedPort.BoundPort)));
                 _sessionMock.Setup(p => p.MessageListenerCompleted).Returns(new ManualResetEvent(true));
                 _forwardedPort.Dispose();
                 _forwardedPort = null;
@@ -68,9 +66,8 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<TcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.TcpIpForward &&
                                 g.AddressToBind == _forwardedPort.BoundHost &&
                                 g.PortToBind == _forwardedPort.BoundPort)))
                 .Callback(

+ 4 - 5
src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortNeverStarted.cs

@@ -37,10 +37,10 @@ namespace Renci.SshNet.Tests.Classes
                 _sessionMock.Setup(
                     p =>
                         p.SendMessage(
-                            It.Is<GlobalRequestMessage>(
+                            It.Is<CancelTcpIpForwardGlobalRequestMessage>(
                                 g =>
-                                    g.RequestName == GlobalRequestName.CancelTcpIpForward &&
-                                    g.AddressToBind == _forwardedPort.BoundHost && g.PortToBind == _forwardedPort.BoundPort)));
+                                    g.AddressToBind == _forwardedPort.BoundHost &&
+                                    g.PortToBind == _forwardedPort.BoundPort)));
                 _sessionMock.Setup(p => p.MessageListenerCompleted).Returns(new ManualResetEvent(true));
                 _forwardedPort.Dispose();
                 _forwardedPort = null;
@@ -68,9 +68,8 @@ namespace Renci.SshNet.Tests.Classes
             _sessionMock.Setup(
                 p =>
                     p.SendMessage(
-                        It.Is<GlobalRequestMessage>(
+                        It.Is<TcpIpForwardGlobalRequestMessage>(
                             g =>
-                                g.RequestName == GlobalRequestName.TcpIpForward &&
                                 g.AddressToBind == _forwardedPort.BoundHost &&
                                 g.PortToBind == _forwardedPort.BoundPort)))
                 .Callback(

+ 14 - 18
src/Renci.SshNet.Tests/Classes/Messages/Connection/GlobalRequestMessageTest.cs

@@ -1,6 +1,8 @@
 using Renci.SshNet.Messages.Connection;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using System;
+using System.Globalization;
+using System.Text;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Messages.Connection
@@ -12,30 +14,24 @@ namespace Renci.SshNet.Tests.Classes.Messages.Connection
     [TestClass]
     public class GlobalRequestMessageTest : TestBase
     {
-        /// <summary>
-        ///A test for GlobalRequestMessage Constructor
-        ///</summary>
         [TestMethod]
-        [Ignore] // placeholder
-        public void GlobalRequestMessageConstructorTest()
+        public void DefaultCtor()
         {
-            GlobalRequestMessage target = new GlobalRequestMessage();
-            Assert.Inconclusive("TODO: Implement code to verify target");
+            new GlobalRequestMessage();
         }
 
-        /// <summary>
-        ///A test for GlobalRequestMessage Constructor
-        ///</summary>
         [TestMethod]
-        [Ignore] // placeholder
-        public void GlobalRequestMessageConstructorTest2()
+        public void Ctor_RequestNameAndWantReply()
         {
-            GlobalRequestName requestName = new GlobalRequestName(); // TODO: Initialize to an appropriate value
-            bool wantReply = false; // TODO: Initialize to an appropriate value
-            string addressToBind = string.Empty; // TODO: Initialize to an appropriate value
-            uint portToBind = 0; // TODO: Initialize to an appropriate value
-            GlobalRequestMessage target = new GlobalRequestMessage(requestName, wantReply, addressToBind, portToBind);
-            Assert.Inconclusive("TODO: Implement code to verify target");
+            var requestName = new Random().Next().ToString(CultureInfo.InvariantCulture);
+
+            var target = new GlobalRequestMessage(Encoding.ASCII.GetBytes(requestName), true);
+            Assert.AreEqual(requestName, target.RequestName);
+            Assert.IsTrue(target.WantReply);
+
+            target = new GlobalRequestMessage(Encoding.ASCII.GetBytes(requestName), false);
+            Assert.AreEqual(requestName, target.RequestName);
+            Assert.IsFalse(target.WantReply);
         }
     }
 }

+ 12 - 2
src/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs

@@ -1,4 +1,5 @@
 using System.Net.Sockets;
+using System.Text;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Renci.SshNet.Messages.Connection;
 
@@ -10,14 +11,23 @@ namespace Renci.SshNet.Tests.Classes
     [TestClass]
     public class SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace : SessionTest_ConnectedBase
     {
+        private GlobalRequestMessage _globalRequestMessage;
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _globalRequestMessage = new GlobalRequestMessage(Encoding.ASCII.GetBytes("ping-mocana-com"), false);
+        }
+
         protected override void Act()
         {
         }
 
         protected override void ClientAuthentication_Callback()
         {
-            var globalRequestMessage = new GlobalRequestMessage(GlobalRequestName.TcpIpForward, false, "address", 70);
-            var globalRequest = globalRequestMessage.GetPacket(8, null);
+            
+            var globalRequest = _globalRequestMessage.GetPacket(8, null);
             ServerSocket.Send(globalRequest, 4, globalRequest.Length - 4, SocketFlags.None);
         }
 

+ 0 - 1
src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj

@@ -148,7 +148,6 @@
     <Compile Include="Classes\Common\ExtensionsTest_IsEqualTo_ByteArray.cs" />
     <Compile Include="Classes\Common\ExtensionsTest_Take_Count.cs" />
     <Compile Include="Classes\Common\ExtensionsTest_Take_OffsetAndCount.cs" />
-    <Compile Include="Classes\Common\ExtensionsTest_ToGlobalRequestName.cs" />
     <Compile Include="Classes\Common\ExtensionsTest_TrimLeadingZeros.cs" />
     <Compile Include="Classes\ConnectionInfoTest_Authenticate_Failure.cs" />
     <Compile Include="Classes\ConnectionInfoTest_Authenticate_Success.cs" />

+ 8 - 0
src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs

@@ -5,6 +5,14 @@ namespace Renci.SshNet.Abstractions
     internal static class DiagnosticAbstraction
     {
 #if FEATURE_DIAGNOSTICS_TRACESOURCE
+
+        private static readonly SourceSwitch SourceSwitch = new SourceSwitch("SshNetSwitch");
+
+        public static bool IsEnabled(TraceEventType traceEventType)
+        {
+            return SourceSwitch.ShouldTrace(traceEventType);
+        }
+
         private static readonly TraceSource Loggging =
 #if DEBUG
             new TraceSource("SshNet.Logging", SourceLevels.All);

+ 0 - 27
src/Renci.SshNet/Common/Extensions.cs

@@ -32,19 +32,6 @@ namespace Renci.SshNet
             return value.All(char.IsWhiteSpace);
         }
 
-        internal static byte[] ToArray(this GlobalRequestName globalRequestName)
-        {
-            switch (globalRequestName)
-            {
-                case GlobalRequestName.TcpIpForward:
-                    return SshData.Ascii.GetBytes("tcpip-forward");
-                case GlobalRequestName.CancelTcpIpForward:
-                    return SshData.Ascii.GetBytes("cancel-tcpip-forward");
-                default:
-                    throw new NotSupportedException(string.Format("Global request name '{0}' is not supported.", globalRequestName));
-            }
-        }
-
         internal static byte[] ToArray(this ServiceName serviceName)
         {
             switch (serviceName)
@@ -72,20 +59,6 @@ namespace Renci.SshNet
             }
         }
 
-        internal static GlobalRequestName ToGlobalRequestName(this byte[] data)
-        {
-            var sshGlobalRequestName = SshData.Ascii.GetString(data, 0, data.Length);
-            switch (sshGlobalRequestName)
-            {
-                case "tcpip-forward":
-                    return GlobalRequestName.TcpIpForward;
-                case "cancel-tcpip-forward":
-                    return GlobalRequestName.CancelTcpIpForward;
-                default:
-                    throw new NotSupportedException(string.Format("Global request name '{0}' is not supported.", sshGlobalRequestName));
-            }
-        }
-
         internal static BigInteger ToBigInteger(this byte[] data)
         {
             var reversed = new byte[data.Length];

+ 18 - 0
src/Renci.SshNet/Common/SshData.cs

@@ -278,6 +278,24 @@ namespace Renci.SshNet.Common
             return _stream.ReadBinary();
         }
 
+        //protected byte[] ReadBinaryDebug()
+        //{
+        //    DiagnosticAbstraction.Log("Stream Position:" + _stream.Position);
+        //    var data = _stream.ReadBytes(4);
+        //    DiagnosticAbstraction.Log("Binary Length Bytes:" + Session.ToHex(data, 0));
+        //    var length = (uint)(data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]);
+        //    DiagnosticAbstraction.Log("Binary Length:" + length);
+
+        //    if (length > int.MaxValue)
+        //    {
+        //        throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Data longer than {0} is not supported.", int.MaxValue));
+        //    }
+
+        //    var binary = _stream.ReadBytes((int) length);
+        //    DiagnosticAbstraction.Log("Binary Bytes:" + Session.ToHex(binary, 0));
+        //    return binary;
+        //}
+
         /// <summary>
         /// Reads next name-list data type from internal buffer.
         /// </summary>

+ 2 - 2
src/Renci.SshNet/ForwardedPortRemote.cs

@@ -150,7 +150,7 @@ namespace Renci.SshNet
                 Session.ChannelOpenReceived += Session_ChannelOpening;
 
                 // send global request to start forwarding
-                Session.SendMessage(new GlobalRequestMessage(GlobalRequestName.TcpIpForward, true, BoundHost, BoundPort));
+                Session.SendMessage(new TcpIpForwardGlobalRequestMessage(BoundHost, BoundPort));
                 // wat for response on global request to start direct tcpip
                 Session.WaitOnHandle(_globalRequestResponse);
 
@@ -188,7 +188,7 @@ namespace Renci.SshNet
             base.StopPort(timeout);
 
             // send global request to cancel direct tcpip
-            Session.SendMessage(new GlobalRequestMessage(GlobalRequestName.CancelTcpIpForward, true, BoundHost, BoundPort));
+            Session.SendMessage(new CancelTcpIpForwardGlobalRequestMessage(BoundHost, BoundPort));
             // wait for response on global request to cancel direct tcpip or completion of message
             // listener loop (in which case response on global request can never be received)
             WaitHandle.WaitAny(new[] { _globalRequestResponse, Session.MessageListenerCompleted }, timeout);

+ 66 - 0
src/Renci.SshNet/Messages/Connection/CancelTcpIpForwardGlobalRequestMessage.cs

@@ -0,0 +1,66 @@
+using System;
+
+namespace Renci.SshNet.Messages.Connection
+{
+    internal class CancelTcpIpForwardGlobalRequestMessage : GlobalRequestMessage
+    {
+        private byte[] _addressToBind;
+
+        public CancelTcpIpForwardGlobalRequestMessage(string addressToBind, uint portToBind)
+            : base(Ascii.GetBytes("cancel-tcpip-forward"), true)
+        {
+            AddressToBind = addressToBind;
+            PortToBind = portToBind;
+        }
+
+        /// <summary>
+        /// Gets the address to bind to.
+        /// </summary>
+        public string AddressToBind
+        {
+            get { return Utf8.GetString(_addressToBind, 0, _addressToBind.Length); }
+            private set { _addressToBind = Utf8.GetBytes(value); }
+        }
+
+        /// <summary>
+        /// Gets port number to bind to.
+        /// </summary>
+        public uint PortToBind { get; private set; }
+
+        /// <summary>
+        /// Gets the size of the message in bytes.
+        /// </summary>
+        /// <value>
+        /// The size of the messages in bytes.
+        /// </value>
+        protected override int BufferCapacity
+        {
+            get
+            {
+                var capacity = base.BufferCapacity;
+                capacity += 4; // AddressToBind length
+                capacity += _addressToBind.Length; // AddressToBind
+                capacity += 4; // PortToBind
+                return capacity;
+            }
+        }
+
+        /// <summary>
+        /// Called when type specific data need to be loaded.
+        /// </summary>
+        protected override void LoadData()
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Called when type specific data need to be saved.
+        /// </summary>
+        protected override void SaveData()
+        {
+            base.SaveData();
+            WriteBinaryString(_addressToBind);
+            Write(PortToBind);
+        }
+    }
+}

+ 66 - 0
src/Renci.SshNet/Messages/Connection/TcpIpForwardGlobalRequestMessage.cs

@@ -0,0 +1,66 @@
+using System;
+
+namespace Renci.SshNet.Messages.Connection
+{
+    internal class TcpIpForwardGlobalRequestMessage : GlobalRequestMessage
+    {
+        private byte[] _addressToBind;
+
+        public TcpIpForwardGlobalRequestMessage(string addressToBind, uint portToBind)
+            : base(Ascii.GetBytes("tcpip-forward"), true)
+        {
+            AddressToBind = addressToBind;
+            PortToBind = portToBind;
+        }
+
+        /// <summary>
+        /// Gets the address to bind to.
+        /// </summary>
+        public string AddressToBind
+        {
+            get { return Utf8.GetString(_addressToBind, 0, _addressToBind.Length); }
+            private set { _addressToBind = Utf8.GetBytes(value); }
+        }
+
+        /// <summary>
+        /// Gets port number to bind to.
+        /// </summary>
+        public uint PortToBind { get; private set; }
+
+        /// <summary>
+        /// Gets the size of the message in bytes.
+        /// </summary>
+        /// <value>
+        /// The size of the messages in bytes.
+        /// </value>
+        protected override int BufferCapacity
+        {
+            get
+            {
+                var capacity = base.BufferCapacity;
+                capacity += 4; // AddressToBind length
+                capacity += _addressToBind.Length; // AddressToBind
+                capacity += 4; // PortToBind
+                return capacity;
+            }
+        }
+
+        /// <summary>
+        /// Called when type specific data need to be loaded.
+        /// </summary>
+        protected override void LoadData()
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Called when type specific data need to be saved.
+        /// </summary>
+        protected override void SaveData()
+        {
+            base.SaveData();
+            WriteBinaryString(_addressToBind);
+            Write(PortToBind);
+        }
+    }
+}

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

@@ -155,6 +155,8 @@
     <Compile Include="IServiceFactory.NET.cs" />
     <Compile Include="ISession.cs" />
     <Compile Include="ISubsystemSession.cs" />
+    <Compile Include="Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs" />
+    <Compile Include="Messages\Connection\TcpIpForwardGlobalRequestMessage.cs" />
     <Compile Include="Messages\Transport\KeyExchangeEcdhInitMessage.cs" />
     <Compile Include="Messages\Transport\KeyExchangeEcdhReplyMessage.cs" />
     <Compile Include="Netconf\INetConfSession.cs" />