/// <summary>The private implementation of <see cref="ReadByte"/>. This implementation is specific to the Telnet protocol.</summary> /// <returns>A <see cref="byte"/> of data destined for the application layer</returns> /// <remarks>Telnet option negotiation happens inside this method, hidden from the client</remarks> private byte GetApplicationInputByte() { // Keep reading bytes until we get one destined for the application layer while (true) { if (InputIsAvailable) { byte inputByte = ReadByteFromTCP(); if (inputByte == TelnetCommand.IAC) // Decide whether to send the input to the Application, or process it within the NVT { byte possibleCommandDescriptionByte = ReadByteFromTCP(); if (possibleCommandDescriptionByte != TelnetCommand.IAC) // The IAC meant that a Telnet command follows, and the inputByte we just read is a command type. { TelnetCommand cmd = TelnetCommand.OfType(possibleCommandDescriptionByte).IncomingOn(this); cmd.Process(); } else // The IAC is part of a two-byte escape sequence, meaning a literal 0xFF character is part of the Application data stream { OnByteReceived(TelnetCommand.IAC); return(TelnetCommand.IAC); } } else // inputByte was NOT an IAC, so send it to the Application { OnByteReceived(inputByte); return(inputByte); } } else // Now that there's no more input to be read, we can send queued telnet commands { SendQueuedTelnetCommands(); } } void SendQueuedTelnetCommands() { while (CommandsToBeSent.Count > 0) { byte[] output = CommandsToBeSent.SelectMany(command => command.TelnetForm).ToArray(); WriteByteArray(output); CommandsToBeSent.Clear(); } } }
/// <summary>Put the <see cref="TelnetCommand"/> <paramref name="commandToBeSent"/> in a queue so it can be sent when we finish reading input</summary> internal void EnqueueForSending(TelnetCommand commandToBeSent) => CommandsToBeSent.Add(commandToBeSent);