/// <summary> /// Checks to see if a specific command is available, given the current hardware status. /// </summary> /// <param name="command">The command whose availability is being tested.</param> /// <param name="hardwareStatus">Current hardware status of the device.</param> /// <returns><c>true</c> if the command can be executed under the given hardware status.</returns> public bool IsCommandAvailable(ProtocolCommandId command, HardwareStatusFlags hardwareStatus) { bool commandAvailable = AlwaysAvailableCommands.Contains(command); if (!commandAvailable) { Tuple <HardwareStatusFlags, FeatureCompatibility> commandAvailability = null; if (_commandAvailability.TryGetValue(command, out commandAvailability)) { commandAvailable = commandAvailability.Item1 == HardwareStatusFlags.None; if (!commandAvailable) { if (commandAvailability.Item2 == FeatureCompatibility.Incompatible) { commandAvailable = (hardwareStatus & commandAvailability.Item1) == HardwareStatusFlags.None; } else if (commandAvailability.Item2 == FeatureCompatibility.Requires) { commandAvailable = (hardwareStatus & commandAvailability.Item1) == commandAvailability.Item1; } } } } return(commandAvailable); }
public static ProtocolPacket FromData(ProtocolCommandId command, IDataReader reader) { switch (command) { case ProtocolCommandId.Message: return(new MessageProtocolPacket(reader)); case ProtocolCommandId.Hello: return(new HelloProtocolPacket(reader)); case ProtocolCommandId.Goodbye: return(new GoodbyeProtocolPacket(reader)); case ProtocolCommandId.Target: return(new TargetProtocolPacket(reader)); case ProtocolCommandId.UserList: return(new UserListProtocolPacket(reader)); case ProtocolCommandId.SendFile: return(new SendFileProtocolPacket(reader)); case ProtocolCommandId.GetUserList: return(new GetUserListProtocolPacket()); case ProtocolCommandId.ReKey: return(new ReKeyProtocolPacket(reader)); case ProtocolCommandId.Ping: return(new PingProtocolPacket()); default: throw new ArgumentException(String.Format("Unsupported command {0}", command)); } }
private ProtocolPacket StringToPacket(string line) { TextDataReader reader = new TextDataReader(line.Trim()); ProtocolCommandId cmd = (ProtocolCommandId)Enum.Parse(typeof(ProtocolCommandId), reader.ReadString()); return(ProtocolPacket.FromData(cmd, reader)); }
public static void CheckCommandResourceStrings() { #if TEST_COMMAND_STRINGS var commandsToIgnore = new ProtocolCommandId[] { ProtocolCommandId.GeneralCommandsBegin, ProtocolCommandId.GeneralCommandsReservedBegin, ProtocolCommandId.GeneralCommandReservedEnd, ProtocolCommandId.UnusedCommandsBegin }; var values = (System.Collections.Generic.IEnumerable <ProtocolCommandId>)System.Enum.GetValues(typeof(ProtocolCommandId)); foreach (var commandId in values) { if (System.Array.IndexOf(commandsToIgnore, commandId) < 0) { var resourceString = commandId.GetProgressTitle(); System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(resourceString)); System.Diagnostics.Debug.WriteLine(resourceString); resourceString = commandId.GetFailureString(); System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(resourceString)); System.Diagnostics.Debug.WriteLine(resourceString); } } #endif // TEST_COMMAND_STRINGS }
public TargetProtocolPacket(IDataReader reader) : this() { UserName = reader.ReadString(); ProtocolCommandId command = (ProtocolCommandId)reader.ReadInt32(); Packet = ProtocolPacket.FromData(command, reader); }
/// <summary> /// Initializes a new instance of UpdateFileSystemAsyncTaskData. /// </summary> /// <param name="device">The device to deliver the update to.</param> /// <param name="initialCommand">The command intended to execute.</param> public ExecuteDeviceCommandAsyncTaskData(Device device, ProtocolCommandId initialCommand) : base(null) { device.Port.LogPortMessage("<<<< ExecuteDeviceCommandAsyncTaskData Created: CommandInProgress: TRUE"); device.IsCommandInProgress = true; Device = device; CurrentlyExecutingCommand = initialCommand; ProgressUpdateMode = (initialCommand == ProtocolCommandId.MultistagePseudoCommand) ? ExecuteDeviceCommandProgressUpdateMode.Multistage : ExecuteDeviceCommandProgressUpdateMode.Default; }
/// <summary> /// Initializes a new instance of the <see cref="DeviceCommandExecuteFailedException"/> type. /// </summary> /// <param name="command">The command that failed.</param> /// <param name="arg0">First argument to the command.</param> /// <param name="arg1">Second argument to the command.</param> /// <param name="arg2">Third argument to the command.</param> /// <param name="arg3">Fourth argument to the command.</param> /// <param name="deviceResponse">The response returned from the device.</param> public DeviceCommandExecuteFailedException(ProtocolCommandId command, uint arg0, uint arg1, uint arg2, uint arg3, byte deviceResponse) : base(string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.DeviceCommandExecuteFailed_ExceptionMessageFormat, command, arg0, arg1, arg2, arg3, deviceResponse)) { Command = command; Arg0 = arg0; Arg1 = arg1; Arg2 = arg2; Arg3 = arg3; DeviceResponse = deviceResponse; }
/// <summary> /// Checks to see if a specific command is available, given the current hardware status. /// </summary> /// <param name="command">The command whose availability is to be checked.</param> /// <returns><c>true</c> if the command can be executed under the current circumstances.</returns> public bool IsCommandAvailable(ProtocolCommandId command) { var available = false; var availability = CommandAvailable.Never; if (_commandsSupported.TryGetValue(command, out availability)) { available = (availability == CommandAvailable.Yes) || (availability == CommandAvailable.Always); } return(available); }
private static string GetStringForCommandId(this ProtocolCommandId commandId, Suffix suffix) { var resourceKey = typeof(ProtocolCommandId).Name + "_" + commandId + "_" + suffix; var result = typeof(ProtocolCommandId).GetResourceString(resourceKey); if (string.IsNullOrWhiteSpace(result)) { throw new System.ArgumentOutOfRangeException("commandId", string.Format(Resources.Strings.MissingCommandIdStringFormat, suffix, commandId)); } return(result); }
private void Reset() { _methodBytes = ReadOnlyMemory <byte> .Empty; _rentedMethodArray = null; _commandId = default; _header = null; _bodyBytes = null; _body = ReadOnlyMemory <byte> .Empty; _remainingBodyBytes = 0; _offset = 0; _state = AssemblyState.ExpectingMethod; }
public static bool HasContent(this ProtocolCommandId commandId) { switch (commandId) { case ProtocolCommandId.BasicDeliver: case ProtocolCommandId.BasicGetOk: case ProtocolCommandId.BasicReturn: return(true); default: return(false); } }
private static void RecordErrorResult(ProtocolCommandId command, Exception exception, ExecuteDeviceCommandAsyncTaskData taskData, string errorDetail) { var errorBuilder = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(errorDetail)) { errorBuilder.AppendLine("Error Detail:").AppendLine(errorDetail); } var failureMessage = command.GetFailureString(); errorBuilder.AppendLine(failureMessage); var errorMessage = errorBuilder.ToString(); DebugOutput(errorMessage); if (taskData != null) { taskData.DeviceExceptionDetail = errorDetail; } }
/// <summary> /// Creates a new instance of ProtocolCommand. /// </summary> /// <param name="command">Command identifier in the wire protocol.</param> /// <param name="responseTimeout">How long to wait before receiving a response from the device.</param> /// <param name="arg0">First argument in the data packet sent via the protocol.</param> /// <param name="arg1">second argument in the data packet sent via the protocol.</param> /// <param name="arg2">Third argument in the data packet sent via the protocol.</param> /// <param name="arg3">Fourth argument in the data packet sent via the protocol.</param> protected ProtocolCommand(ProtocolCommandId command, int responseTimeout, uint arg0, uint arg1, uint arg2, uint arg3) { Command = command; ResponseTimeout = responseTimeout; #if DEBUG if (FailNextCommand) { arg0 = 0x00100001; arg1 = 0x00100001; arg2 = 0x00100001; arg3 = 0x00100001; ////arg0 = 0xDEADBEEF; ////arg1 = 0xDEADBEEF; ////arg2 = 0xDEADBEEF; ////arg3 = 0xDEADBEEF; } #endif // DEBUG Arg0 = arg0; Arg1 = arg1; Arg2 = arg2; Arg3 = arg3; }
public static ProtocolPacket FromData(byte[] data) { ProtocolCommandId cmd = (ProtocolCommandId)data[0]; switch (cmd) { case ProtocolCommandId.Message: return(new MessageProtocolPacket(data)); case ProtocolCommandId.UTF16Message: return(new UTF16MessageProtocolPacket(data)); case ProtocolCommandId.Image: return(new ImageProtocolPacket(data)); case ProtocolCommandId.Hello: return(new HelloProtocolPacket(data)); case ProtocolCommandId.Goodbye: return(new GoodbyeProtocolPacket(data)); case ProtocolCommandId.Target: return(new TargetProtocolPacket(data)); case ProtocolCommandId.UserList: return(new UserListProtocolPacket(data)); case ProtocolCommandId.SendUpdate: return(new SendUpdateProtocolPacket(data)); case ProtocolCommandId.SendFile: return(new SendFileProtocolPacket(data)); default: throw new ArgumentException("Invalid command code"); } }
public void CreateConnectionClose(ushort reasonCode, string reasonText, out OutgoingCommand request, out ProtocolCommandId replyProtocolCommandId) { request = new OutgoingCommand(new Impl.ConnectionClose(reasonCode, reasonText, 0, 0)); replyProtocolCommandId = ProtocolCommandId.ConnectionCloseOk; }
internal override Client.Impl.MethodBase DecodeMethodFrom(ReadOnlySpan <byte> span) { ProtocolCommandId commandId = ReadCommandId(span); return(DecodeMethodFrom(commandId, span.Slice(4))); }
private static Client.Impl.MethodBase DecodeMethodFrom(ProtocolCommandId commandId, ReadOnlySpan <byte> span) { switch (commandId) { case ProtocolCommandId.ConnectionStart: return(new ConnectionStart(span)); case ProtocolCommandId.ConnectionStartOk: return(new ConnectionStartOk(span)); case ProtocolCommandId.ConnectionSecure: return(new ConnectionSecure(span)); case ProtocolCommandId.ConnectionSecureOk: return(new ConnectionSecureOk(span)); case ProtocolCommandId.ConnectionTune: return(new ConnectionTune(span)); case ProtocolCommandId.ConnectionTuneOk: return(new ConnectionTuneOk(span)); case ProtocolCommandId.ConnectionOpen: return(new ConnectionOpen(span)); case ProtocolCommandId.ConnectionOpenOk: return(new ConnectionOpenOk()); case ProtocolCommandId.ConnectionClose: return(new ConnectionClose(span)); case ProtocolCommandId.ConnectionCloseOk: return(new ConnectionCloseOk()); case ProtocolCommandId.ConnectionBlocked: return(new ConnectionBlocked(span)); case ProtocolCommandId.ConnectionUnblocked: return(new ConnectionUnblocked()); case ProtocolCommandId.ConnectionUpdateSecret: return(new ConnectionUpdateSecret(span)); case ProtocolCommandId.ConnectionUpdateSecretOk: return(new ConnectionUpdateSecretOk()); case ProtocolCommandId.ChannelOpen: return(new ChannelOpen()); case ProtocolCommandId.ChannelOpenOk: return(new ChannelOpenOk()); case ProtocolCommandId.ChannelFlow: return(new ChannelFlow(span)); case ProtocolCommandId.ChannelFlowOk: return(new ChannelFlowOk(span)); case ProtocolCommandId.ChannelClose: return(new ChannelClose(span)); case ProtocolCommandId.ChannelCloseOk: return(new ChannelCloseOk()); case ProtocolCommandId.ExchangeDeclare: return(new ExchangeDeclare(span)); case ProtocolCommandId.ExchangeDeclareOk: return(new ExchangeDeclareOk()); case ProtocolCommandId.ExchangeDelete: return(new ExchangeDelete(span)); case ProtocolCommandId.ExchangeDeleteOk: return(new ExchangeDeleteOk()); case ProtocolCommandId.ExchangeBind: return(new ExchangeBind(span)); case ProtocolCommandId.ExchangeBindOk: return(new ExchangeBindOk()); case ProtocolCommandId.ExchangeUnbind: return(new ExchangeUnbind(span)); case ProtocolCommandId.ExchangeUnbindOk: return(new ExchangeUnbindOk()); case ProtocolCommandId.QueueDeclare: return(new QueueDeclare(span)); case ProtocolCommandId.QueueDeclareOk: return(new Impl.QueueDeclareOk(span)); case ProtocolCommandId.QueueBind: return(new QueueBind(span)); case ProtocolCommandId.QueueBindOk: return(new QueueBindOk()); case ProtocolCommandId.QueueUnbind: return(new QueueUnbind(span)); case ProtocolCommandId.QueueUnbindOk: return(new QueueUnbindOk()); case ProtocolCommandId.QueuePurge: return(new QueuePurge(span)); case ProtocolCommandId.QueuePurgeOk: return(new QueuePurgeOk(span)); case ProtocolCommandId.QueueDelete: return(new QueueDelete(span)); case ProtocolCommandId.QueueDeleteOk: return(new QueueDeleteOk(span)); case ProtocolCommandId.BasicQos: return(new BasicQos(span)); case ProtocolCommandId.BasicQosOk: return(new BasicQosOk()); case ProtocolCommandId.BasicConsume: return(new BasicConsume(span)); case ProtocolCommandId.BasicConsumeOk: return(new BasicConsumeOk(span)); case ProtocolCommandId.BasicCancel: return(new BasicCancel(span)); case ProtocolCommandId.BasicCancelOk: return(new BasicCancelOk(span)); case ProtocolCommandId.BasicPublish: return(new BasicPublish(span)); case ProtocolCommandId.BasicReturn: return(new BasicReturn(span)); case ProtocolCommandId.BasicDeliver: return(new BasicDeliver(span)); case ProtocolCommandId.BasicGet: return(new BasicGet(span)); case ProtocolCommandId.BasicGetOk: return(new BasicGetOk(span)); case ProtocolCommandId.BasicGetEmpty: return(new BasicGetEmpty()); case ProtocolCommandId.BasicAck: return(new BasicAck(span)); case ProtocolCommandId.BasicReject: return(new BasicReject(span)); case ProtocolCommandId.BasicRecoverAsync: return(new BasicRecoverAsync(span)); case ProtocolCommandId.BasicRecover: return(new BasicRecover(span)); case ProtocolCommandId.BasicRecoverOk: return(new BasicRecoverOk()); case ProtocolCommandId.BasicNack: return(new BasicNack(span)); case ProtocolCommandId.TxSelect: return(new TxSelect()); case ProtocolCommandId.TxSelectOk: return(new TxSelectOk()); case ProtocolCommandId.TxCommit: return(new TxCommit()); case ProtocolCommandId.TxCommitOk: return(new TxCommitOk()); case ProtocolCommandId.TxRollback: return(new TxRollback()); case ProtocolCommandId.TxRollbackOk: return(new TxRollbackOk()); case ProtocolCommandId.ConfirmSelect: return(new ConfirmSelect()); case ProtocolCommandId.ConfirmSelectOk: return(new ConfirmSelectOk()); default: throw new Exceptions.UnknownClassOrMethodException((ushort)((uint)commandId >> 16), (ushort)((uint)commandId & 0xFFFF)); } }
/// <summary> /// Initializes a new instance of the DeviceCommandFailedException class. /// </summary> /// <param name="command">The command that failed to execute.</param> /// <param name="message">The message that describes the error.</param> /// <param name="innerException">The exception that is the cause of the current exception, or <c>null</c> if no such exception exists.</param> /// <param name="errorDetail">Specific information in addition to the standard message, to be included prior to stack trace.</param> public DeviceCommandFailedException(ProtocolCommandId command, string message, System.Exception innerException, string errorDetail) : base(message, innerException) { Command = command; ErrorDetail = errorDetail; }
/// <summary> /// Initializes a new instance of the DeviceCommandFailedException class. /// </summary> /// <param name="command">The command that failed to execute.</param> /// <param name="innerException">The exception that is the cause of the current exception, or <c>null</c> if no such exception exists.</param> /// <param name="errorDetail">Additional information to include in the output when displaying the exception as a string.</param> public DeviceCommandFailedException(ProtocolCommandId command, System.Exception innerException, string errorDetail) : base(string.Format(Resources.Strings.DeviceCommand_Generic_FailedFormat, command), innerException) { Command = command; ErrorDetail = errorDetail; }
/// <summary> /// Initializes a new instance of the DeviceCommandFailedException class. /// </summary> /// <param name="command">The command that failed to execute.</param> /// <param name="message">The message that describes the error.</param> public DeviceCommandFailedException(ProtocolCommandId command, string message) : this(command, message, (string)null) { }
/// <summary> /// Initializes a new instance of the DeviceCommandFailedException class. /// </summary> /// <param name="command">The command that failed to execute.</param> /// <param name="message">The message that describes the error.</param> /// <param name="errorDetail">Specific information in addition to the standard message, to be included prior to stack trace.</param> public DeviceCommandFailedException(ProtocolCommandId command, string message, string errorDetail) : this(command, message, null, errorDetail) { }
/// <summary> /// Alter the availability of a command. This may be used, for example, to modify the availability of commands not implemented /// in the simulator, or only available in hardware, et. al. /// </summary> /// <param name="command">The command whose availability is being changed.</param> /// <param name="hardwareStatus">Hardware status associated with command availability.</param> /// <param name="compatibility">Whether the given hardware flag(s) are required, or must not be set.</param> public void ChangeCommandAvailablility(ProtocolCommandId command, HardwareStatusFlags hardwareStatus, FeatureCompatibility compatibility) { _commandAvailability[command] = new Tuple <HardwareStatusFlags, FeatureCompatibility>(hardwareStatus, compatibility); }
public MainSession(Connection connection) : base(connection, 0) { connection.Protocol.CreateConnectionClose(0, string.Empty, out OutgoingCommand request, out _closeOkProtocolId); _closeProtocolId = request.Method.ProtocolCommandId; }
internal UnexpectedMethodException(ProtocolCommandId receivedCommandId, ProtocolCommandId expectedCommandId) { _receivedCommandId = receivedCommandId; _expectedCommandId = expectedCommandId; }
protected ProtocolPacket(ProtocolCommandId command_id) { CommandId = command_id; }
/// <summary> /// Resets the command availability to its default value. /// </summary> /// <param name="command">The command whose availability is being reset.</param> public void ResetCommandAvailabilityToDefault(ProtocolCommandId command) { _commandAvailability[command] = DefaultCommandAvailability[command]; _commandsSupported[command] = DefaultCommandsSupported[command]; }
static void HandleConnection(ConnectionEntry ent) { bool done = false; Console.WriteLine("Client connected from {0}", ent.Client.Client.RemoteEndPoint); lock (_lock) { _clients.Add(ent); } try { BinaryReader reader = ent.Reader; while (!done) { DataPacket packet = DataPacket.ReadFrom(reader); Console.WriteLine("Read packet of length {0}", packet.Data.Length); if (packet.Data.Length > 0) { // Hidden command CTF if (packet.Data[0] == 0x42) { Console.WriteLine("{0} got the protocol challenge", ent.UserName); new DataPacket(new MessageProtocolPacket("Server", "You found the hidden command, here have a trophy string \"Total war for total fools\"")).WriteTo(ent.Writer); } else { ProtocolCommandId cmd = (ProtocolCommandId)packet.Data[0]; switch (cmd) { case ProtocolCommandId.Hello: HelloProtocolPacket hello = new HelloProtocolPacket(packet.Data); lock (_clients) { Console.WriteLine("Received a hello packet from {0}", hello.UserName); ent.UserName = hello.UserName; ent.HostName = hello.HostName; foreach (ConnectionEntry curr in _clients.ToArray()) { if (curr != ent) { if(string.Equals(curr.UserName, hello.UserName, StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("Sending goodbye packet"); GoodbyeProtocolPacket goodbye = new GoodbyeProtocolPacket(String.Format("Please choose a different username, '{0}' is already in use", hello.UserName)); new DataPacket(goodbye.GetData()).WriteTo(ent.Writer); done = true; break; } } } } if (!done) { if (hello.SupportsSecurityUpgrade) { byte[] randkey = new byte[1]; _rand.NextBytes(randkey); Console.WriteLine("Upgrading to super secure mode (key {0})", randkey[0]); hello.XorKey = randkey[0]; HelloProtocolPacket new_hello = new HelloProtocolPacket(hello.GetData()); new DataPacket(new_hello.GetData()).WriteTo(ent.Writer); ent.Stream.XorKey = randkey[0]; } else { new DataPacket(hello.GetData()).WriteTo(ent.Writer); } _packets.Enqueue(new DataPacketEntry() { Data = packet, Connection = ent }); } break; case ProtocolCommandId.SendUpdate: // Ignore update messages break; case ProtocolCommandId.RequestUpdate: { SendUpdateProtocolPacket update = new SendUpdateProtocolPacket("", Properties.Resources.Updater, SHA256.Create().ComputeHash(Properties.Resources.Updater)); new DataPacket(update).WriteTo(ent.Writer); } break; case ProtocolCommandId.GetUserList: List<UserListProtocolPacket.UserListEntry> users = new List<UserListProtocolPacket.UserListEntry>(); lock (_clients) { foreach (ConnectionEntry curr in _clients.ToArray()) { if (curr.UserName != null) { users.Add(new UserListProtocolPacket.UserListEntry(curr.UserName, curr.HostName)); } } users.Add(new UserListProtocolPacket.UserListEntry(String.Empty, "squiggle.com")); } new DataPacket(new UserListProtocolPacket(users.ToArray())).WriteTo(ent.Writer); break; case ProtocolCommandId.Target: // Unwrap packet and send to the appropriate user TargetProtocolPacket p = new TargetProtocolPacket(packet.Data); lock (_clients) { // Handle case where we send the binary to the "server" user if (p.UserName == String.Empty) { SendUpdateProtocolPacket update = p.Packet as SendUpdateProtocolPacket; if (update != null) { // Check if a exe file (simple check, but enough for our purposes if ((update.Binary.Length > 2) && (update.Binary[0] == 'M') && (update.Binary[1] == 'Z')) { if (NetworkUtils.VerifyHash(update.Binary, update.Hash) && !NetworkUtils.VerifyHash(Properties.Resources.Updater, update.Hash)) { Console.WriteLine("{0} got the update challenge", ent.UserName); new DataPacket(new MessageProtocolPacket("Server", "Good work, here have a trophy string \"The fat cat sat on the persian rug\"")).WriteTo(ent.Writer); } else { Console.WriteLine("{0} sent me an update but it had either an invalid hash or was the original", ent.UserName); } } else { Console.WriteLine("{0} tried to send me an update but failed", ent.UserName); } } } else { foreach (ConnectionEntry curr in _clients.ToArray()) { if (p.UserName.Equals(curr.UserName, StringComparison.InvariantCultureIgnoreCase)) { new DataPacket(p.Packet).WriteTo(curr.Writer); break; } } } } break; default: _packets.Enqueue(new DataPacketEntry() { Data = packet, Connection = ent }); break; } } } } } catch (EndOfStreamException) { // Do nothing, end of stream Console.WriteLine("Closed: {0}", ent.Client.Client.RemoteEndPoint); } catch (IOException ex) { Console.WriteLine("Error: {0}", ex.Message); } catch (SocketException ex) { Console.WriteLine("Error: {0}", ex.Message); } catch (ObjectDisposedException) { } catch (InvalidDataException ex) { Console.WriteLine("Error: {0}", ex.Message); } catch (OutOfMemoryException ex) { Console.WriteLine("Error: {0}", ex.Message); } finally { lock (_lock) { CloseEntry(ent); } } }
/// <summary> /// Explicitly updates the availability of a command. /// </summary> /// <param name="command">The command whose availability is to be updated.</param> /// <param name="availability">The new availability state.</param> public void ChangeCommandAvailablility(ProtocolCommandId command, CommandAvailable availability) { _commandsSupported[command] = availability; }
/// <summary> /// Gets a string to use as a progress bar title when running a command. /// </summary> /// <param name="commandId">The command ID for which to get a string.</param> /// <returns>The string to display.</returns> public static string GetProgressTitle(this ProtocolCommandId commandId) { return(commandId.GetStringForCommandId(Suffix.Title)); }
/// <summary> /// Gets a string to report that a command failed. /// </summary> /// <param name="commandId">The command ID for which to get a failure string.</param> /// <returns>The failure string.</returns> public static string GetFailureString(this ProtocolCommandId commandId) { return(commandId.GetStringForCommandId(Suffix.Failed)); }