From d02335eac775f4eeb4fccdaebf77bccb4ef4bebe Mon Sep 17 00:00:00 2001 From: Harry Cordewener Date: Mon, 8 Jan 2024 17:59:06 -0600 Subject: [PATCH] More Span, More NAWS --- .../MockPipelineClient.cs | 24 +++++++++--------- .../KestrelMockServer.cs | 25 +++++++++++++------ .../Interpreters/TelnetEORInterpreter.cs | 22 ++++++++-------- .../Interpreters/TelnetNAWSInterpreter.cs | 22 +++++++++++----- .../Interpreters/TelnetStandardInterpreter.cs | 2 +- 5 files changed, 58 insertions(+), 37 deletions(-) diff --git a/TelnetNegotiationCore.TestClient/MockPipelineClient.cs b/TelnetNegotiationCore.TestClient/MockPipelineClient.cs index f53834e..c569462 100644 --- a/TelnetNegotiationCore.TestClient/MockPipelineClient.cs +++ b/TelnetNegotiationCore.TestClient/MockPipelineClient.cs @@ -3,10 +3,8 @@ using TelnetNegotiationCore.Interpreters; using System.IO.Pipelines; using Pipelines.Sockets.Unofficial; -using System.Buffers; using System.Text; using TelnetNegotiationCore.Models; -using System.Net; using System.Collections.Immutable; namespace TelnetNegotiationCore.TestClient @@ -33,20 +31,23 @@ private async Task WriteToOutputStreamAsync(byte[] arg, PipeWriter writer) } public static Task WriteBackAsync(byte[] writeback, Encoding encoding, TelnetInterpreter t) => - Task.Run(() => Console.WriteLine(encoding.GetString(writeback))); + Task.Run(() => Console.WriteLine(encoding.GetString(writeback.AsSpan()))); - public Task SignalGMCPAsync((string module, string writeback) val) => - Task.Run(() => _Logger.Debug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback)); + public Task SignalGMCPAsync((string module, string writeback) val) + { + _Logger.Debug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback); + return Task.CompletedTask; + } - public Task SignalMSSPAsync(MSSPConfig val) => - Task.Run(() => _Logger.Debug("New MSSP: {@MSSP}", val)); + public Task SignalMSSPAsync(MSSPConfig val) + { + _Logger.Debug("New MSSP: {@MSSPConfig}", val); + return Task.CompletedTask; + } public Task SignalPromptAsync() => Task.Run(() => _Logger.Debug("Prompt")); - public Task SignalNAWSAsync(int height, int width) => - Task.Run(() => _Logger.Debug("Client Height and Width updated: {Height}x{Width}", height, width)); - public async Task StartAsync(string address, int port) { var client = new TcpClient(address, port); @@ -59,7 +60,6 @@ public async Task StartAsync(string address, int port) CallbackNegotiationAsync = (x) => WriteToOutputStreamAsync(x, pipe.Output), SignalOnGMCPAsync = SignalGMCPAsync, SignalOnMSSPAsync = SignalMSSPAsync, - SignalOnNAWSAsync = SignalNAWSAsync, SignalOnPromptingAsync = SignalPromptAsync, CharsetOrder = new[] { Encoding.GetEncoding("utf-8"), Encoding.GetEncoding("iso-8859-1") } }.BuildAsync(); @@ -68,7 +68,7 @@ public async Task StartAsync(string address, int port) while (true) { - var read = Console.ReadLine() + Environment.NewLine; + string read = Console.ReadLine() ?? string.Empty; if (telnet != null) { diff --git a/TelnetNegotiationCore.TestServer/KestrelMockServer.cs b/TelnetNegotiationCore.TestServer/KestrelMockServer.cs index 666c621..82955e0 100644 --- a/TelnetNegotiationCore.TestServer/KestrelMockServer.cs +++ b/TelnetNegotiationCore.TestServer/KestrelMockServer.cs @@ -16,7 +16,7 @@ public class KestrelMockServer : ConnectionHandler { private readonly ILogger _Logger; - public KestrelMockServer(ILogger logger = null): base() + public KestrelMockServer(ILogger logger = null) : base() { Console.OutputEncoding = Encoding.UTF8; _Logger = logger ?? Log.Logger.ForContext(); @@ -34,14 +34,23 @@ private async Task WriteToOutputStreamAsync(byte[] arg, PipeWriter writer) } } - public Task SignalGMCPAsync((string module, string writeback) val) => - Task.Run(() => _Logger.Debug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback)); + public Task SignalGMCPAsync((string module, string writeback) val) + { + _Logger.Debug("GMCP Signal: {Module}: {WriteBack}", val.module, val.writeback); + return Task.CompletedTask; + } - public Task SignalMSSPAsync(MSSPConfig val) => - Task.Run(() => _Logger.Debug("New MSSP: {@MSSPConfig}", val)); + public Task SignalMSSPAsync(MSSPConfig val) + { + _Logger.Debug("New MSSP: {@MSSPConfig}", val); + return Task.CompletedTask; + } - public Task SignalNAWSAsync(int height, int width) => - Task.Run(() => _Logger.Debug("Client Height and Width updated: {Height}x{Width}", height, width)); + public Task SignalNAWSAsync(int height, int width) + { + _Logger.Debug("Client Height and Width updated: {Height}x{Width}", height, width); + return Task.CompletedTask; + } public static async Task WriteBackAsync(byte[] writeback, Encoding encoding, TelnetInterpreter telnet) { @@ -59,7 +68,7 @@ public async override Task OnConnectedAsync(ConnectionContext connection) var telnet = await new TelnetInterpreter(TelnetInterpreter.TelnetMode.Server) { - CallbackOnSubmitAsync = (w,e,t) => WriteBackAsync(w,e,t), + CallbackOnSubmitAsync = (w, e, t) => WriteBackAsync(w, e, t), SignalOnGMCPAsync = SignalGMCPAsync, SignalOnMSSPAsync = SignalMSSPAsync, SignalOnNAWSAsync = SignalNAWSAsync, diff --git a/TelnetNegotiationCore/Interpreters/TelnetEORInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetEORInterpreter.cs index 2afaae9..17929b1 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetEORInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetEORInterpreter.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using Stateless; using TelnetNegotiationCore.Models; @@ -119,7 +120,15 @@ private async Task OnWillEORAsync(StateMachine.Transition _) /// A completed Task public async Task SendPromptAsync(byte[] send) { - await CallbackNegotiationAsync(send); + await CallbackNegotiationAsync(send); + if (_doEOR is null or false) + { + await CallbackNegotiationAsync(CurrentEncoding.GetBytes(Environment.NewLine)); + } + else + { + await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.EOR]); + } } /// @@ -129,15 +138,8 @@ public async Task SendPromptAsync(byte[] send) /// A completed Task public async Task SendAsync(byte[] send) { - if (_doEOR is null or false) - { - await CallbackNegotiationAsync(send); - } - else - { - await CallbackNegotiationAsync(send); - await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.EOR]); - } + await CallbackNegotiationAsync(send); + await CallbackNegotiationAsync(CurrentEncoding.GetBytes(Environment.NewLine)); } } } diff --git a/TelnetNegotiationCore/Interpreters/TelnetNAWSInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetNAWSInterpreter.cs index 297250c..ee2433b 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetNAWSInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetNAWSInterpreter.cs @@ -1,4 +1,5 @@ using System; +using System.Net.NetworkInformation; using System.Threading.Tasks; using OneOf; using Stateless; @@ -48,7 +49,7 @@ public partial class TelnetInterpreter /// /// This exists to avoid an infinite loop with badly conforming clients. /// - private bool _ClientWillingToDoNAWS = false; + private bool _WillingToDoNAWS = false; /// /// If the server you are connected to makes use of the client window in ways that are linked to its width and height, @@ -90,8 +91,8 @@ private StateMachine SetupNAWS(StateMachine tsm) .OnEntry(() => _Logger.Debug("Connection: {ConnectionState}", "Server won't do NAWS - do nothing")); tsm.Configure(State.DoNAWS) - .SubstateOf(State.Accepting); - // Fix this. We are a client. + .SubstateOf(State.Accepting) + .OnEntry(() => _WillingToDoNAWS = true); } tsm.Configure(State.WillDoNAWS) @@ -100,7 +101,7 @@ private StateMachine SetupNAWS(StateMachine tsm) tsm.Configure(State.WontDoNAWS) .SubstateOf(State.Accepting) - .OnEntry(() => _ClientWillingToDoNAWS = false); + .OnEntry(() => _WillingToDoNAWS = false); tsm.Configure(State.SubNegotiation) .Permit(Trigger.NAWS, State.NegotiatingNAWS); @@ -130,17 +131,26 @@ private StateMachine SetupNAWS(StateMachine tsm) return tsm; } + public async Task SendNAWS(short width, short height) + { + if(!_WillingToDoNAWS) await Task.CompletedTask; + + await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.SB, (byte)Trigger.NAWS, + .. BitConverter.GetBytes(width), .. BitConverter.GetBytes(height), + (byte)Trigger.IAC, (byte)Trigger.SE]); + } + /// /// Request NAWS from a client /// public async Task RequestNAWSAsync(StateMachine.Transition _) { - if (!_ClientWillingToDoNAWS) + if (!_WillingToDoNAWS) { _Logger.Debug("Connection: {ConnectionState}", "Requesting NAWS details from Client"); await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.DO, (byte)Trigger.NAWS]); - _ClientWillingToDoNAWS = true; + _WillingToDoNAWS = true; } } diff --git a/TelnetNegotiationCore/Interpreters/TelnetStandardInterpreter.cs b/TelnetNegotiationCore/Interpreters/TelnetStandardInterpreter.cs index 227f354..f940b27 100644 --- a/TelnetNegotiationCore/Interpreters/TelnetStandardInterpreter.cs +++ b/TelnetNegotiationCore/Interpreters/TelnetStandardInterpreter.cs @@ -208,7 +208,7 @@ private async Task WriteToBufferAndAdvanceAsync(OneOf b) private void WriteToOutput() { byte[] cp = new byte[_bufferPosition]; - Array.Copy(_buffer, cp, _bufferPosition); + _buffer.AsSpan().CopyTo(cp); _bufferPosition = 0; CallbackOnSubmitAsync.Invoke(cp, CurrentEncoding, this); }