Quellcode durchsuchen

Separate creating, enabling/disabling, activating/deactivating of messages into SshMessageFactory.
Huge performance improvement in micro-benchmark.
Work in progress.

drieseng vor 9 Jahren
Ursprung
Commit
ee3f679aa3

+ 4 - 1
src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj

@@ -918,6 +918,9 @@
     <Compile Include="..\Renci.SshNet\SshCommand.cs">
       <Link>SshCommand.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\SshMessageFactory.cs">
+      <Link>SshMessageFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\SubsystemSession.cs">
       <Link>SubsystemSession.cs</Link>
     </Compile>
@@ -937,7 +940,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. 

+ 0 - 24
src/Renci.SshNet.NET35/Session.NET35.cs

@@ -58,29 +58,5 @@ namespace Renci.SshNet
                 HandleMessage(message);
             }
         }
-
-        partial void InternalRegisterMessage(string messageName)
-        {
-            lock (_messagesMetadata)
-            {
-                foreach (var m in from m in _messagesMetadata where m.Name == messageName select m)
-                {
-                    m.Enabled = true; 
-                    m.Activated = true;
-                }
-            }
-        }
-
-        partial void InternalUnRegisterMessage(string messageName)
-        {
-            lock (_messagesMetadata)
-            {
-                foreach (var m in from m in _messagesMetadata where m.Name == messageName select m)
-                {
-                    m.Enabled = false;
-                    m.Activated = false;
-                }
-            }
-        }
     }
 }

+ 0 - 24
src/Renci.SshNet.Silverlight/Session.SilverlightShared.cs

@@ -12,29 +12,5 @@ namespace Renci.SshNet
         {
             isConnected = (_socket != null && _socket.Connected);
         }
-
-        partial void InternalRegisterMessage(string messageName)
-        {
-            lock (_messagesMetadata)
-            {
-                foreach (var item in from m in _messagesMetadata where m.Name == messageName select m)
-                {
-                    item.Enabled = true;
-                    item.Activated = true;
-                }
-            }
-        }
-
-        partial void InternalUnRegisterMessage(string messageName)
-        {
-            lock (_messagesMetadata)
-            {
-                foreach (var item in from m in _messagesMetadata where m.Name == messageName select m)
-                {
-                    item.Enabled = false;
-                    item.Activated = false;
-                }
-            }
-        }
     }
 }

+ 4 - 1
src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj

@@ -892,6 +892,9 @@
     <Compile Include="..\Renci.SshNet\SshCommand.cs">
       <Link>SshCommand.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\SshMessageFactory.cs">
+      <Link>SshMessageFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\SubsystemSession.cs">
       <Link>SubsystemSession.cs</Link>
     </Compile>
@@ -912,7 +915,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. 

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

@@ -70,6 +70,9 @@
     <Compile Include="..\..\test\Renci.SshNet.Shared.Tests\Abstractions\ThreadAbstraction_ExecuteThread.cs">
       <Link>Classes\Abstractions\ThreadAbstraction_ExecuteThread.cs</Link>
     </Compile>
+    <Compile Include="..\..\test\Renci.SshNet.Shared.Tests\SshMessageFactoryTest.cs">
+      <Link>Classes\SshMessageFactoryTest.cs</Link>
+    </Compile>
     <Compile Include="Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs" />
     <Compile Include="Classes\Channels\ChannelDirectTcpipTest.cs" />
     <Compile Include="Classes\Channels\ChannelDirectTcpipTest_Close_SessionIsConnectedAndChannelIsOpen.cs" />

+ 3 - 0
src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj

@@ -960,6 +960,9 @@
     <Compile Include="..\Renci.SshNet\SshCommand.cs">
       <Link>SshCommand.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\SshMessageFactory.cs">
+      <Link>SshMessageFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\SubsystemSession.cs">
       <Link>SubsystemSession.cs</Link>
     </Compile>

+ 4 - 1
src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj

@@ -910,6 +910,9 @@
     <Compile Include="..\Renci.SshNet\SshCommand.cs">
       <Link>SshCommand.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\SshMessageFactory.cs">
+      <Link>SshMessageFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\SubsystemSession.cs">
       <Link>SubsystemSession.cs</Link>
     </Compile>
@@ -932,7 +935,7 @@
   <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).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. 

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

@@ -452,6 +452,7 @@
     </Compile>
     <Compile Include="SshClient.cs" />
     <Compile Include="SshCommand.cs" />
+    <Compile Include="SshMessageFactory.cs" />
     <Compile Include="SubsystemSession.cs" />
   </ItemGroup>
   <ItemGroup>

+ 0 - 20
src/Renci.SshNet/Session.NET40.cs

@@ -13,25 +13,5 @@ namespace Renci.SshNet
         {
             HandleMessage((dynamic)message);
         }
-
-        partial void InternalRegisterMessage(string messageName)
-        {
-            lock (_messagesMetadata)
-            {
-                Parallel.ForEach(
-                    from m in _messagesMetadata where m.Name == messageName select m,
-                    item => { item.Enabled = true; item.Activated = true; });
-            }
-        }
-
-        partial void InternalUnRegisterMessage(string messageName)
-        {
-            lock (_messagesMetadata)
-            {
-                Parallel.ForEach(
-                    from m in _messagesMetadata where m.Name == messageName select m,
-                    item => { item.Enabled = false; item.Activated = false; });
-            }
-        }
     }
 }

+ 11 - 82
src/Renci.SshNet/Session.cs

@@ -84,7 +84,7 @@ namespace Renci.SshNet
         /// <summary>
         /// Holds metada about session messages
         /// </summary>
-        private IEnumerable<MessageMetadata> _messagesMetadata;
+        private SshMessageFactory _sshMessageFactory;
 
         /// <summary>
         /// Holds connection socket.
@@ -523,7 +523,7 @@ namespace Renci.SshNet
                     Reset();
 
                     //  Build list of available messages while connecting
-                    _messagesMetadata = GetMessagesMetadata();
+                    _sshMessageFactory = new SshMessageFactory();
 
                     switch (ConnectionInfo.ProxyType)
                     {
@@ -621,6 +621,8 @@ namespace Renci.SshNet
                     ConnectionInfo.Authenticate(this, _serviceFactory);
                     _isAuthenticated = true;
 
+                    Thread.Sleep(2000);
+
                     //  Register Connection messages
                     RegisterMessage("SSH_MSG_GLOBAL_REQUEST");
                     RegisterMessage("SSH_MSG_REQUEST_SUCCESS");
@@ -864,49 +866,6 @@ namespace Renci.SshNet
             }
         }
 
-        private static IEnumerable<MessageMetadata> GetMessagesMetadata()
-        {
-            return new []
-                {
-                    new MessageMetadata { Name = "SSH_MSG_NEWKEYS", Number = 21, Type = typeof(NewKeysMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_REQUEST_FAILURE", Number = 82, Type = typeof(RequestFailureMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_KEXINIT", Number = 20, Type = typeof(KeyExchangeInitMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_OPEN_FAILURE", Number = 92, Type = typeof(ChannelOpenFailureMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_FAILURE", Number = 100, Type = typeof(ChannelFailureMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_EXTENDED_DATA", Number = 95, Type = typeof(ChannelExtendedDataMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_DATA", Number = 94, Type = typeof(ChannelDataMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_USERAUTH_REQUEST", Number = 50, Type = typeof(RequestMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_REQUEST", Number = 98, Type = typeof(ChannelRequestMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_USERAUTH_BANNER", Number = 53, Type = typeof(BannerMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_USERAUTH_INFO_RESPONSE", Number = 61, Type = typeof(InformationResponseMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_USERAUTH_FAILURE", Number = 51, Type = typeof(FailureMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_DEBUG", Number = 4, Type = typeof(DebugMessage), },
-                    new MessageMetadata { Name = "SSH_MSG_KEXDH_INIT", Number = 30, Type = typeof(KeyExchangeDhInitMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_GLOBAL_REQUEST", Number = 80, Type = typeof(GlobalRequestMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_OPEN", Number = 90, Type = typeof(ChannelOpenMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION", Number = 91, Type = typeof(ChannelOpenConfirmationMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_USERAUTH_INFO_REQUEST", Number = 60, Type = typeof(InformationRequestMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_UNIMPLEMENTED", Number = 3, Type = typeof(UnimplementedMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_REQUEST_SUCCESS", Number = 81, Type = typeof(RequestSuccessMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_SUCCESS", Number = 99, Type = typeof(ChannelSuccessMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", Number = 60, Type = typeof(PasswordChangeRequiredMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_DISCONNECT", Number = 1, Type = typeof(DisconnectMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_SERVICE_REQUEST", Number = 5, Type = typeof(ServiceRequestMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_KEX_DH_GEX_REQUEST", Number = 34, Type = typeof(KeyExchangeDhGroupExchangeRequest) },
-                    new MessageMetadata { Name = "SSH_MSG_KEX_DH_GEX_GROUP", Number = 31, Type = typeof(KeyExchangeDhGroupExchangeGroup) },
-                    new MessageMetadata { Name = "SSH_MSG_USERAUTH_SUCCESS", Number = 52, Type = typeof(SuccessMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_USERAUTH_PK_OK", Number = 60, Type = typeof(PublicKeyMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_IGNORE", Number = 2, Type = typeof(IgnoreMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_WINDOW_ADJUST", Number = 93, Type = typeof(ChannelWindowAdjustMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_EOF", Number = 96, Type = typeof(ChannelEofMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_CHANNEL_CLOSE", Number = 97, Type = typeof(ChannelCloseMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_SERVICE_ACCEPT", Number = 6, Type = typeof(ServiceAcceptMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_KEXDH_REPLY", Number = 31, Type = typeof(KeyExchangeDhReplyMessage) },
-                    new MessageMetadata { Name = "SSH_MSG_KEX_DH_GEX_INIT", Number = 32, Type = typeof(KeyExchangeDhGroupExchangeInit) },
-                    new MessageMetadata { Name = "SSH_MSG_KEX_DH_GEX_REPLY", Number = 33, Type = typeof(KeyExchangeDhGroupExchangeReply) }
-                };
-        }
-
         /// <summary>
         /// Receives the message from the server.
         /// </summary>
@@ -1332,12 +1291,8 @@ namespace Renci.SshNet
 
             _keyExchangeCompletedWaitHandle.Reset();
 
-            //  Disable all registered messages except key exchange related
-            foreach (var messageMetadata in _messagesMetadata)
-            {
-                if (messageMetadata.Activated && messageMetadata.Number > 2 && (messageMetadata.Number < 20 || messageMetadata.Number > 30))
-                    messageMetadata.Enabled = false;
-            }
+            // Disable messages that are not key exchange related
+            _sshMessageFactory.DisableNonKeyExchangeMessages();
 
             _keyExchange = _serviceFactory.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms,
                 message.KeyExchangeAlgorithms);
@@ -1395,12 +1350,8 @@ namespace Renci.SshNet
                 _keyExchange = null;
             }
 
-            //  Enable all active registered messages
-            foreach (var messageMetadata in _messagesMetadata)
-            {
-                if (messageMetadata.Activated)
-                    messageMetadata.Enabled = true;
-            }
+            // Enable activated messages that are not key exchange related
+            _sshMessageFactory.EnableActivatedMessages();
 
             var newKeysReceived = NewKeysReceived;
             if (newKeysReceived != null)
@@ -1662,7 +1613,7 @@ namespace Renci.SshNet
         /// <param name="messageName">The name of the message to register with the session.</param>
         public void RegisterMessage(string messageName)
         {
-            InternalRegisterMessage(messageName);
+            _sshMessageFactory.EnableAndActivateMessage(messageName);
         }
 
         /// <summary>
@@ -1671,7 +1622,7 @@ namespace Renci.SshNet
         /// <param name="messageName">The name of the message to unregister with the session.</param>
         public void UnRegisterMessage(string messageName)
         {
-            InternalUnRegisterMessage(messageName);
+            _sshMessageFactory.DisableAndDeactivateMessage(messageName);
         }
 
         /// <summary>
@@ -1686,12 +1637,7 @@ namespace Renci.SshNet
         private Message LoadMessage(byte[] data, int offset)
         {
             var messageType = data[offset];
-            var messageMetadata = (from m in _messagesMetadata where m.Number == messageType && m.Enabled && m.Activated select m).FirstOrDefault();
-            if (messageMetadata == null)
-                throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.", messageType));
-
-            var message = messageMetadata.Type.CreateInstance<Message>();
-
+            var message = _sshMessageFactory.Create(messageType);
             message.Load(data, offset);
 
             DiagnosticAbstraction.Log(string.Format("ReceiveMessage from server: '{0}': '{1}'.", message.GetType().Name, message));
@@ -1699,10 +1645,6 @@ namespace Renci.SshNet
             return message;
         }
 
-        partial void InternalRegisterMessage(string messageName);
-
-        partial void InternalUnRegisterMessage(string messageName);
-
         #endregion
 
         /// <summary>
@@ -2402,18 +2344,5 @@ namespace Renci.SshNet
         }
 
         #endregion ISession implementation
-
-        private class MessageMetadata
-        {
-            public string Name { get; set; }
-
-            public byte Number { get; set; }
-
-            public bool Enabled { get; set; }
-
-            public bool Activated { get; set; }
-
-            public Type Type { get; set; }
-        }
     }
 }

+ 191 - 0
src/Renci.SshNet/SshMessageFactory.cs

@@ -0,0 +1,191 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Renci.SshNet.Common;
+using Renci.SshNet.Messages;
+using Renci.SshNet.Messages.Authentication;
+using Renci.SshNet.Messages.Connection;
+using Renci.SshNet.Messages.Transport;
+
+namespace Renci.SshNet
+{
+    internal class SshMessageFactory
+    {
+        private readonly MessageMetadata[] _enabledMessagesByNumber;
+        private readonly bool[] _activatedMessagesById;
+
+        private static readonly MessageMetadata[] AllMessages;
+        private static readonly IDictionary<string, MessageMetadata> MessagesByName;
+
+        static SshMessageFactory()
+        {
+            AllMessages = new MessageMetadata[]
+            {
+                new MessageMetadata<KeyExchangeInitMessage>(0, "SSH_MSG_KEXINIT", 20),
+                new MessageMetadata<NewKeysMessage> (1, "SSH_MSG_NEWKEYS", 21),
+                new MessageMetadata<RequestFailureMessage> (2, "SSH_MSG_REQUEST_FAILURE", 82),
+                new MessageMetadata<ChannelOpenFailureMessage> (3, "SSH_MSG_CHANNEL_OPEN_FAILURE", 92),
+                new MessageMetadata<ChannelFailureMessage> (4, "SSH_MSG_CHANNEL_FAILURE", 100),
+                new MessageMetadata<ChannelExtendedDataMessage> (5, "SSH_MSG_CHANNEL_EXTENDED_DATA", 95),
+                new MessageMetadata<ChannelDataMessage> (6, "SSH_MSG_CHANNEL_DATA", 94),
+                new MessageMetadata<ChannelRequestMessage> (7, "SSH_MSG_CHANNEL_REQUEST", 98),
+                new MessageMetadata<BannerMessage> (8, "SSH_MSG_USERAUTH_BANNER", 53),
+                new MessageMetadata<InformationResponseMessage> (9, "SSH_MSG_USERAUTH_INFO_RESPONSE", 61),
+                new MessageMetadata<FailureMessage> (10, "SSH_MSG_USERAUTH_FAILURE", 51),
+                new MessageMetadata<DebugMessage> (11, "SSH_MSG_DEBUG", 4),
+                new MessageMetadata<GlobalRequestMessage> (12, "SSH_MSG_GLOBAL_REQUEST", 80),
+                new MessageMetadata<ChannelOpenMessage> (13, "SSH_MSG_CHANNEL_OPEN", 90),
+                new MessageMetadata<ChannelOpenConfirmationMessage> (14, "SSH_MSG_CHANNEL_OPEN_CONFIRMATION", 91),
+                new MessageMetadata<InformationRequestMessage> (15, "SSH_MSG_USERAUTH_INFO_REQUEST", 60),
+                new MessageMetadata<UnimplementedMessage> (16, "SSH_MSG_UNIMPLEMENTED", 3),
+                new MessageMetadata<RequestSuccessMessage> (17, "SSH_MSG_REQUEST_SUCCESS", 81),
+                new MessageMetadata<ChannelSuccessMessage> (18, "SSH_MSG_CHANNEL_SUCCESS", 99),
+                new MessageMetadata<PasswordChangeRequiredMessage> (19, "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", 60),
+                new MessageMetadata<DisconnectMessage> (20, "SSH_MSG_DISCONNECT", 1),
+                new MessageMetadata<SuccessMessage> (21, "SSH_MSG_USERAUTH_SUCCESS", 52),
+                new MessageMetadata<PublicKeyMessage> (22, "SSH_MSG_USERAUTH_PK_OK", 60),
+                new MessageMetadata<IgnoreMessage> (23, "SSH_MSG_IGNORE", 2),
+                new MessageMetadata<ChannelWindowAdjustMessage> (24, "SSH_MSG_CHANNEL_WINDOW_ADJUST", 93),
+                new MessageMetadata<ChannelEofMessage> (25, "SSH_MSG_CHANNEL_EOF", 96),
+                new MessageMetadata<ChannelCloseMessage> (26, "SSH_MSG_CHANNEL_CLOSE", 97),
+                new MessageMetadata<ServiceAcceptMessage> (27, "SSH_MSG_SERVICE_ACCEPT", 6),
+                new MessageMetadata<KeyExchangeDhGroupExchangeGroup> (28, "SSH_MSG_KEX_DH_GEX_GROUP", 31),
+                new MessageMetadata<KeyExchangeDhReplyMessage> (29, "SSH_MSG_KEXDH_REPLY", 31),
+                new MessageMetadata<KeyExchangeDhGroupExchangeReply> (30, "SSH_MSG_KEX_DH_GEX_REPLY", 33)
+            };
+
+            MessagesByName = new Dictionary<string, MessageMetadata>(31);
+            foreach (var messageMetadata in AllMessages)
+                MessagesByName.Add(messageMetadata.Name, messageMetadata);
+        }
+
+        public SshMessageFactory()
+        {
+            _activatedMessagesById = new bool[31];
+            _enabledMessagesByNumber = new MessageMetadata[101];
+        }
+
+        /// <summary>
+        /// Disables and deactivate all messages.
+        /// </summary>
+        public void Reset()
+        {
+            Array.Clear(_activatedMessagesById, 0, _activatedMessagesById.Length);
+            Array.Clear(_enabledMessagesByNumber, 0, _enabledMessagesByNumber.Length);
+        }
+
+        public Message Create(byte messageNumber)
+        {
+            var messageMetadata = _enabledMessagesByNumber[messageNumber];
+
+            if (messageMetadata == null)
+            {
+                throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.", messageNumber));
+            }
+
+            return messageMetadata.Create();
+        }
+
+        public void DisableNonKeyExchangeMessages()
+        {
+            foreach (var messageMetadata in AllMessages)
+            {
+                var messageNumber = messageMetadata.Number;
+                if ((messageNumber > 2 && messageNumber < 20) || messageNumber > 30)
+                {
+                    //Console.WriteLine("Disabling " + messageMetadata.Name + "...");
+                    _enabledMessagesByNumber[messageNumber] = null;
+                }
+            }
+        }
+
+        public void EnableActivatedMessages()
+        {
+            foreach (var messageMetadata in AllMessages)
+            {
+                if (!_activatedMessagesById[messageMetadata.Id])
+                    continue;
+
+                var enabledMessage = _enabledMessagesByNumber[messageMetadata.Number];
+                if (enabledMessage != null && enabledMessage != messageMetadata)
+                {
+                    throw new Exception("Message X is already enabled for Y");
+                }
+                _enabledMessagesByNumber[messageMetadata.Number] = messageMetadata;
+            }
+        }
+
+        public void EnableAndActivateMessage(string messageName)
+        {
+            lock (this)
+            {
+                MessageMetadata messageMetadata;
+
+                if (!MessagesByName.TryGetValue(messageName, out messageMetadata))
+                {
+                    throw new Exception("TODO");
+                }
+
+                var enabledMessage = _enabledMessagesByNumber[messageMetadata.Number];
+                if (enabledMessage != null && enabledMessage != messageMetadata)
+                {
+                    throw new Exception("Message X is already enabled for Y");
+                }
+                _enabledMessagesByNumber[messageMetadata.Number] = messageMetadata;
+
+                _activatedMessagesById[messageMetadata.Id] = true;
+            }
+        }
+
+        public void DisableAndDeactivateMessage(string messageName)
+        {
+            lock (this)
+            {
+                MessageMetadata messageMetadata;
+
+                if (!MessagesByName.TryGetValue(messageName, out messageMetadata))
+                {
+                    throw new Exception("TODO");
+                }
+
+                _activatedMessagesById[messageMetadata.Id] = false;
+
+                var enabledMetadata = _enabledMessagesByNumber[messageMetadata.Number];
+                if (enabledMetadata != null && enabledMetadata != messageMetadata)
+                    throw new Exception();
+                _enabledMessagesByNumber[messageMetadata.Number] = null;
+            }
+        }
+
+        private abstract class MessageMetadata
+        {
+            protected MessageMetadata(byte id, string name, byte number)
+            {
+                Id = id;
+                Name = name;
+                Number = number;
+            }
+
+            public readonly byte Id;
+
+            public readonly string Name;
+
+            public readonly byte Number;
+
+            public abstract Message Create();
+        }
+
+        private class MessageMetadata<T> : MessageMetadata where T : Message, new()
+        {
+            public MessageMetadata(byte id, string name, byte number)
+                : base(id, name, number)
+            {
+            }
+
+            public override Message Create()
+            {
+                return new T();
+            }
+        }
+    }
+}

+ 1 - 0
test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.projitems

@@ -12,5 +12,6 @@
     <Compile Include="$(MSBuildThisFileDirectory)Abstractions\CryptoAbstraction_GenerateRandom.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Abstractions\DnsAbstraction_GetHostAddresses.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Abstractions\ThreadAbstraction_ExecuteThread.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)SshMessageFactoryTest.cs" />
   </ItemGroup>
 </Project>

+ 632 - 0
test/Renci.SshNet.Shared.Tests/SshMessageFactoryTest.cs

@@ -0,0 +1,632 @@
+#if SILVERLIGHT
+using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
+#else
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
+using Renci.SshNet.Messages;
+using Renci.SshNet.Messages.Authentication;
+using Renci.SshNet.Messages.Connection;
+using Renci.SshNet.Messages.Transport;
+
+#endif
+
+namespace Renci.SshNet.Tests
+{
+    [TestClass]
+    public class SshMessageFactoryTest
+    {
+        private SshMessageFactory _sshMessageFactory;
+        private SshMessageFactoryOriginal _sshMessageFactoryOriginal;
+
+        [TestInitialize]
+        public void SetUp()
+        {
+            _sshMessageFactory = new SshMessageFactory();
+            _sshMessageFactoryOriginal = new SshMessageFactoryOriginal();
+        }
+
+        [TestMethod]
+        public void EnableInformationRequestMessage()
+        {
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
+            var message = _sshMessageFactory.Create(60);
+            Assert.AreEqual(typeof(InformationRequestMessage), message.GetType());
+        }
+
+        [TestMethod]
+        public void EnablePasswordChangeRequiredMessage()
+        {
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            var message = _sshMessageFactory.Create(60);
+            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), message.GetType());
+        }
+
+        [TestMethod]
+        public void Di()
+        {
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
+
+            _sshMessageFactory.DisableNonKeyExchangeMessages();
+
+            try
+            {
+                _sshMessageFactory.Create(6); // SSH_MSG_SERVICE_ACCEPT
+                Assert.Fail();
+            }
+            catch (SshException)
+            {
+            }
+
+            try
+            {
+                _sshMessageFactory.Create(60);
+                    // SSH_MSG_USERAUTH_PASSWD_CHANGEREQ or SSH_MSG_USERAUTH_INFO_REQUEST or SSH_MSG_USERAUTH_PK_OK
+                Assert.Fail();
+            }
+            catch (SshException)
+            {
+            }
+
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
+            var message = _sshMessageFactory.Create(60);
+            Assert.AreEqual(typeof(InformationRequestMessage), message.GetType());
+
+            _sshMessageFactory.EnableActivatedMessages();
+
+            var message2 = _sshMessageFactory.Create(60);
+            Assert.AreEqual(typeof(InformationRequestMessage), message2.GetType());
+        }
+
+        [TestMethod]
+        public void Performance_Ctor()
+        {
+            const int runCount = 100000;
+
+            // warm-up
+            for (var i = 0; i < 3; i++)
+            {
+                var sshMessageFactory = new SshMessageFactory();
+                var sshMessageFactoryOriginal = new SshMessageFactoryOriginal();
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            var stopwatch = new Stopwatch();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+            {
+                var sshMessageFactory = new SshMessageFactory();
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+
+            stopwatch.Reset();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+            {
+                var sshMessageFactory = new SshMessageFactoryOriginal();
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+        }
+
+        [TestMethod]
+        public void Performance_Create()
+        {
+            const int runCount = 10000000;
+            const string messageName = "SSH_MSG_CHANNEL_CLOSE";
+
+            _sshMessageFactory.EnableAndActivateMessage(messageName);
+            _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
+
+            // warm-up
+            for (var i = 0; i < 3; i++)
+            {
+                _sshMessageFactory.Create(97);
+                _sshMessageFactoryOriginal.Create(97);
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            var stopwatch = new Stopwatch();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+            {
+                var msg = _sshMessageFactory.Create(97);
+                if (msg == null)
+                    Console.WriteLine();
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+
+            stopwatch.Reset();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+            {
+                var msg = _sshMessageFactoryOriginal.Create(97);
+                if (msg == null)
+                    Console.WriteLine();
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+        }
+
+        [TestMethod]
+        public void Performance_EnableAndActivateMessage()
+        {
+            const int runCount = 1000000;
+            const string messageName = "SSH_MSG_CHANNEL_CLOSE";
+
+            // warm-up
+            for (var i = 0; i < 3; i++)
+            {
+                _sshMessageFactory.EnableAndActivateMessage(messageName);
+                _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            var stopwatch = new Stopwatch();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+                _sshMessageFactory.EnableAndActivateMessage(messageName);
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+
+            stopwatch.Reset();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+                _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+        }
+
+        [TestMethod]
+        public void Performance_DisableAndDeactivateMessage()
+        {
+            const int runCount = 1000000;
+            const string messageName = "SSH_MSG_CHANNEL_CLOSE";
+
+            // warm-up
+            for (var i = 0; i < 3; i++)
+            {
+                _sshMessageFactory.DisableAndDeactivateMessage(messageName);
+                _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            var stopwatch = new Stopwatch();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+                _sshMessageFactory.DisableAndDeactivateMessage(messageName);
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+
+            stopwatch.Reset();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+                _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+        }
+
+        [TestMethod]
+        public void Performance_DisableNonKeyExchangeMessages()
+        {
+            const int runCount = 1000000;
+
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_DEBUG");
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
+
+            _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
+            _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_DEBUG");
+            _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
+            _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
+
+            // warm-up
+            for (var i = 0; i < 3; i++)
+            {
+                _sshMessageFactory.DisableNonKeyExchangeMessages();
+                _sshMessageFactory.EnableActivatedMessages();
+
+                _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
+                _sshMessageFactoryOriginal.EnableActivatedMessages();
+            }
+
+            //Console.WriteLine("Starting test");
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            var stopwatch = new Stopwatch();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+            {
+                _sshMessageFactory.DisableNonKeyExchangeMessages();
+                _sshMessageFactory.EnableActivatedMessages();
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+
+            stopwatch.Reset();
+            stopwatch.Start();
+
+            for (var i = 0; i < runCount; i++)
+            {
+                _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
+                _sshMessageFactoryOriginal.EnableActivatedMessages();
+            }
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            GC.Collect();
+
+            stopwatch.Stop();
+
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+        }
+
+        internal class SshMessageFactoryOriginal
+        {
+            private readonly IEnumerable<MessageMetadata> _messagesMetadata;
+
+            public SshMessageFactoryOriginal()
+            {
+                _messagesMetadata = new[]
+                {
+                    new MessageMetadata {Name = "SSH_MSG_NEWKEYS", Number = 21, Type = typeof(NewKeysMessage)},
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_REQUEST_FAILURE",
+                        Number = 82,
+                        Type = typeof(RequestFailureMessage)
+                    },
+                    new MessageMetadata {Name = "SSH_MSG_KEXINIT", Number = 20, Type = typeof(KeyExchangeInitMessage)},
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_OPEN_FAILURE",
+                        Number = 92,
+                        Type = typeof(ChannelOpenFailureMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_FAILURE",
+                        Number = 100,
+                        Type = typeof(ChannelFailureMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_EXTENDED_DATA",
+                        Number = 95,
+                        Type = typeof(ChannelExtendedDataMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_DATA",
+                        Number = 94,
+                        Type = typeof(ChannelDataMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_USERAUTH_REQUEST",
+                        Number = 50,
+                        Type = typeof(RequestMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_REQUEST",
+                        Number = 98,
+                        Type = typeof(ChannelRequestMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_USERAUTH_BANNER",
+                        Number = 53,
+                        Type = typeof(BannerMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_USERAUTH_INFO_RESPONSE",
+                        Number = 61,
+                        Type = typeof(InformationResponseMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_USERAUTH_FAILURE",
+                        Number = 51,
+                        Type = typeof(FailureMessage)
+                    },
+                    new MessageMetadata {Name = "SSH_MSG_DEBUG", Number = 4, Type = typeof(DebugMessage),},
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_KEXDH_INIT",
+                        Number = 30,
+                        Type = typeof(KeyExchangeDhInitMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_GLOBAL_REQUEST",
+                        Number = 80,
+                        Type = typeof(GlobalRequestMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_OPEN",
+                        Number = 90,
+                        Type = typeof(ChannelOpenMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
+                        Number = 91,
+                        Type = typeof(ChannelOpenConfirmationMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_USERAUTH_INFO_REQUEST",
+                        Number = 60,
+                        Type = typeof(InformationRequestMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_UNIMPLEMENTED",
+                        Number = 3,
+                        Type = typeof(UnimplementedMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_REQUEST_SUCCESS",
+                        Number = 81,
+                        Type = typeof(RequestSuccessMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_SUCCESS",
+                        Number = 99,
+                        Type = typeof(ChannelSuccessMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ",
+                        Number = 60,
+                        Type = typeof(PasswordChangeRequiredMessage)
+                    },
+                    new MessageMetadata {Name = "SSH_MSG_DISCONNECT", Number = 1, Type = typeof(DisconnectMessage)},
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_SERVICE_REQUEST",
+                        Number = 5,
+                        Type = typeof(ServiceRequestMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_KEX_DH_GEX_REQUEST",
+                        Number = 34,
+                        Type = typeof(KeyExchangeDhGroupExchangeRequest)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_KEX_DH_GEX_GROUP",
+                        Number = 31,
+                        Type = typeof(KeyExchangeDhGroupExchangeGroup)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_USERAUTH_SUCCESS",
+                        Number = 52,
+                        Type = typeof(SuccessMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_USERAUTH_PK_OK",
+                        Number = 60,
+                        Type = typeof(PublicKeyMessage)
+                    },
+                    new MessageMetadata {Name = "SSH_MSG_IGNORE", Number = 2, Type = typeof(IgnoreMessage)},
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_WINDOW_ADJUST",
+                        Number = 93,
+                        Type = typeof(ChannelWindowAdjustMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_EOF",
+                        Number = 96,
+                        Type = typeof(ChannelEofMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_CHANNEL_CLOSE",
+                        Number = 97,
+                        Type = typeof(ChannelCloseMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_SERVICE_ACCEPT",
+                        Number = 6,
+                        Type = typeof(ServiceAcceptMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_KEXDH_REPLY",
+                        Number = 31,
+                        Type = typeof(KeyExchangeDhReplyMessage)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_KEX_DH_GEX_INIT",
+                        Number = 32,
+                        Type = typeof(KeyExchangeDhGroupExchangeInit)
+                    },
+                    new MessageMetadata
+                    {
+                        Name = "SSH_MSG_KEX_DH_GEX_REPLY",
+                        Number = 33,
+                        Type = typeof(KeyExchangeDhGroupExchangeReply)
+                    }
+                };
+            }
+
+            /// <summary>
+            /// Disables and deactivate all messages.
+            /// </summary>
+            public void Reset()
+            {
+                foreach (var messageMetadata in _messagesMetadata)
+                {
+                    messageMetadata.Activated = messageMetadata.Enabled = false;
+                }
+            }
+
+            public void EnableActivatedMessages()
+            {
+                foreach (var messageMetadata in _messagesMetadata)
+                {
+                    if (messageMetadata.Activated)
+                        messageMetadata.Enabled = true;
+                }
+            }
+
+            public Message Create(byte messageNumber)
+            {
+                var messageMetadata =
+                    (from m in _messagesMetadata where m.Number == messageNumber && m.Enabled && m.Activated select m)
+                        .FirstOrDefault();
+                if (messageMetadata == null)
+                    throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.",
+                        messageNumber));
+
+                return messageMetadata.Type.CreateInstance<Message>();
+            }
+
+            public void DisableNonKeyExchangeMessages()
+            {
+                foreach (var messageMetadata in _messagesMetadata)
+                {
+                    if (messageMetadata.Activated && messageMetadata.Number > 2 &&
+                        (messageMetadata.Number < 20 || messageMetadata.Number > 30))
+                    {
+                        //Console.WriteLine("Disabling " + messageMetadata.Name + "...");
+
+                        messageMetadata.Enabled = false;
+                    }
+                }
+            }
+
+            public void EnableAndActivateMessage(string messageName)
+            {
+                lock (_messagesMetadata)
+                {
+                    var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
+                    foreach (var messageMetadata in messagesMetadata)
+                        messageMetadata.Enabled = messageMetadata.Activated = true;
+                }
+            }
+
+            public void DisableAndDeactivateMessage(string messageName)
+            {
+                lock (_messagesMetadata)
+                {
+                    var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
+                    foreach (var messageMetadata in messagesMetadata)
+                        messageMetadata.Enabled = messageMetadata.Activated = false;
+                }
+            }
+
+            private class MessageMetadata
+            {
+                public string Name { get; set; }
+
+                public byte Number { get; set; }
+
+                public bool Enabled { get; set; }
+
+                public bool Activated { get; set; }
+
+                public Type Type { get; set; }
+            }
+        }
+    }
+}