<PackageReference Include="SSH.NET" Version="2016.0.0-beta2" />

SshMessageFactory

using Renci.SshNet.Common; using Renci.SshNet.Messages; using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages.Connection; using Renci.SshNet.Messages.Transport; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; namespace Renci.SshNet { internal class SshMessageFactory { internal abstract class MessageMetadata { public readonly byte Id; public readonly string Name; public readonly byte Number; protected MessageMetadata(byte id, string name, byte number) { Id = id; Name = name; Number = number; } public abstract Message Create(); } internal 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(); } } private readonly MessageMetadata[] _enabledMessagesByNumber; private readonly bool[] _activatedMessagesById; internal static readonly MessageMetadata[] AllMessages; private static readonly IDictionary<string, MessageMetadata> MessagesByName; internal const byte HighestMessageNumber = 100; internal const int TotalMessageCount = 31; static SshMessageFactory() { AllMessages = new MessageMetadata[31] { 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>(AllMessages.Length); MessageMetadata[] allMessages = AllMessages; foreach (MessageMetadata messageMetadata in allMessages) { MessagesByName.Add(messageMetadata.Name, messageMetadata); } } public SshMessageFactory() { _activatedMessagesById = new bool[31]; _enabledMessagesByNumber = new MessageMetadata[101]; } public void Reset() { Array.Clear(_activatedMessagesById, 0, _activatedMessagesById.Length); Array.Clear(_enabledMessagesByNumber, 0, _enabledMessagesByNumber.Length); } public Message Create(byte messageNumber) { if (messageNumber > 100) throw CreateMessageTypeNotSupportedException(messageNumber); MessageMetadata messageMetadata = _enabledMessagesByNumber[messageNumber]; if (messageMetadata == null) { if (AllMessages.FirstOrDefault((MessageMetadata p) => p.Number == messageNumber) == null) throw CreateMessageTypeNotSupportedException(messageNumber); throw new SshException(string.Format(CultureInfo.InvariantCulture, "Message type {0} is not valid in the current context.", new object[1] { messageNumber })); } return messageMetadata.Create(); } public void DisableNonKeyExchangeMessages() { MessageMetadata[] allMessages = AllMessages; for (int i = 0; i < allMessages.Length; i++) { byte number = allMessages[i].Number; if ((number > 2 && number < 20) || number > 30) _enabledMessagesByNumber[number] = null; } } public void EnableActivatedMessages() { MessageMetadata[] allMessages = AllMessages; int num = 0; MessageMetadata messageMetadata; MessageMetadata messageMetadata2; while (true) { if (num >= allMessages.Length) return; messageMetadata = allMessages[num]; if (_activatedMessagesById[messageMetadata.Id]) { messageMetadata2 = _enabledMessagesByNumber[messageMetadata.Number]; if (messageMetadata2 != null && messageMetadata2 != messageMetadata) break; _enabledMessagesByNumber[messageMetadata.Number] = messageMetadata; } num++; } throw CreateMessageTypeAlreadyEnabledForOtherMessageException(messageMetadata.Number, messageMetadata.Name, messageMetadata2.Name); } public void EnableAndActivateMessage(string messageName) { if (messageName == null) throw new ArgumentNullException("messageName"); lock (this) { if (!MessagesByName.TryGetValue(messageName, out MessageMetadata value)) throw CreateMessageNotSupportedException(messageName); MessageMetadata messageMetadata = _enabledMessagesByNumber[value.Number]; if (messageMetadata != null && messageMetadata != value) throw CreateMessageTypeAlreadyEnabledForOtherMessageException(value.Number, value.Name, messageMetadata.Name); _enabledMessagesByNumber[value.Number] = value; _activatedMessagesById[value.Id] = true; } } public void DisableAndDeactivateMessage(string messageName) { if (messageName == null) throw new ArgumentNullException("messageName"); lock (this) { if (!MessagesByName.TryGetValue(messageName, out MessageMetadata value)) throw CreateMessageNotSupportedException(messageName); MessageMetadata messageMetadata = _enabledMessagesByNumber[value.Number]; if (messageMetadata != null && messageMetadata != value) throw CreateMessageTypeAlreadyEnabledForOtherMessageException(value.Number, value.Name, messageMetadata.Name); _activatedMessagesById[value.Id] = false; _enabledMessagesByNumber[value.Number] = null; } } private static SshException CreateMessageTypeNotSupportedException(byte messageNumber) { throw new SshException(string.Format(CultureInfo.InvariantCulture, "Message type {0} is not supported.", new object[1] { messageNumber })); } private static SshException CreateMessageNotSupportedException(string messageName) { throw new SshException(string.Format(CultureInfo.InvariantCulture, "Message '{0}' is not supported.", new object[1] { messageName })); } private static SshException CreateMessageTypeAlreadyEnabledForOtherMessageException(byte messageNumber, string messageName, string currentEnabledForMessageName) { throw new SshException(string.Format(CultureInfo.InvariantCulture, "Cannot enable message '{0}'. Message type {1} is already enabled for '{2}'.", new object[3] { messageName, messageNumber, currentEnabledForMessageName })); } } }