Skip to content

Commit

Permalink
Implement SUPPRESS GO-AHEAD.
Browse files Browse the repository at this point in the history
  • Loading branch information
HarryCordewener committed Jan 30, 2024
1 parent 0ff79e0 commit 2c0c6bb
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 4 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ This library is in a state where breaking changes to the interface are expected.
| [MSSP](https://tintin.mudhalla.net/protocols/mssp) | MSSP Negotiation | Full | Untested |
| [RFC 885](http://www.faqs.org/rfcs/rfc885.html) | End Of Record Negotiation | Full | Untested |
| [EOR](https://tintin.mudhalla.net/protocols/eor) | End Of Record Negotiation | Full | Untested |
| [MSDP](https://tintin.mudhalla.net/protocols/msdp) | Mud Server Data Protocol | Partial | Planned |
| [MSDP](https://tintin.mudhalla.net/protocols/msdp) | Mud Server Data Protocol | Partial | Partial Tested |
| [RFC 2066](http://www.faqs.org/rfcs/rfc2066.html) | Charset Negotiation | Partial | No TTABLE support |
| [RFC 858](http://www.faqs.org/rfcs/rfc858.html) | Suppress GOAHEAD Negotiation | No | Planned |
| [RFC 858](http://www.faqs.org/rfcs/rfc858.html) | Suppress GOAHEAD Negotiation | Full | Untested |
| [RFC 1572](http://www.faqs.org/rfcs/rfc1572.html) | New Environment Negotiation | No | Planned |
| [MNES](https://tintin.mudhalla.net/protocols/mnes) | Mud New Environment Negotiation | No | Planned |
| [MCCP](https://tintin.mudhalla.net/protocols/mccp) | Mud Client Compression Protocol | No | Rejects |
Expand Down
5 changes: 5 additions & 0 deletions TelnetNegotiationCore/Interpreters/TelnetEORInterpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ public async Task SendPromptAsync(byte[] send)
{
await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.EOR]);
}
// TODO: Tie into _doGA
if(_doEOR is not null or false)
{
await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.GA]);
}
}

/// <summary>
Expand Down
11 changes: 10 additions & 1 deletion TelnetNegotiationCore/Interpreters/TelnetStandardInterpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,16 @@ public TelnetInterpreter(TelnetMode mode, ILogger logger)
SupportedCharacterSets = new Lazy<byte[]>(CharacterSets, true);

var li = new List<Func<StateMachine<State, Trigger>, StateMachine<State, Trigger>>> {
SetupSafeNegotiation, SetupEORNegotiation, SetupMSSPNegotiation, SetupMSDPNegotiation, SetupGMCPNegotiation, SetupTelnetTerminalType, SetupCharsetNegotiation, SetupNAWS, SetupStandardProtocol
SetupSafeNegotiation,
SetupEORNegotiation,
SetupSuppressGANegotiation,
SetupMSSPNegotiation,
SetupMSDPNegotiation,
SetupGMCPNegotiation,
SetupTelnetTerminalType,
SetupCharsetNegotiation,
SetupNAWS,
SetupStandardProtocol
}.AggregateRight(TelnetStateMachine, (func, stateMachine) => func(stateMachine));

if (logger.IsEnabled(LogLevel.Trace))
Expand Down
107 changes: 107 additions & 0 deletions TelnetNegotiationCore/Interpreters/TelnetSuppressGAInterpreter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using Microsoft.Extensions.Logging;
using Stateless;
using System.Threading.Tasks;
using TelnetNegotiationCore.Models;

namespace TelnetNegotiationCore.Interpreters
{
public partial class TelnetInterpreter
{
private bool? _doGA = true;

/// <summary>
/// Character set Negotiation will set the Character Set and Character Page Server & Client have agreed to.
/// </summary>
/// <param name="tsm">The state machine.</param>
/// <returns>Itself</returns>
private StateMachine<State, Trigger> SetupSuppressGANegotiation(StateMachine<State, Trigger> tsm)
{
if (Mode == TelnetMode.Server)
{
tsm.Configure(State.Do)
.Permit(Trigger.SUPPRESSGOAHEAD, State.DoSUPPRESSGOAHEAD);

tsm.Configure(State.Dont)
.Permit(Trigger.SUPPRESSGOAHEAD, State.DontSUPPRESSGOAHEAD);

tsm.Configure(State.DoSUPPRESSGOAHEAD)
.SubstateOf(State.Accepting)
.OnEntryAsync(OnDoSuppressGAAsync);

tsm.Configure(State.DontSUPPRESSGOAHEAD)
.SubstateOf(State.Accepting)
.OnEntryAsync(OnDontSuppressGAAsync);

RegisterInitialWilling(WillingSuppressGAAsync);
}
else
{
tsm.Configure(State.Willing)
.Permit(Trigger.SUPPRESSGOAHEAD, State.WillSUPPRESSGOAHEAD);

tsm.Configure(State.Refusing)
.Permit(Trigger.SUPPRESSGOAHEAD, State.WontSUPPRESSGOAHEAD);

tsm.Configure(State.WontSUPPRESSGOAHEAD)
.SubstateOf(State.Accepting)
.OnEntryAsync(WontSuppressGAAsync);

tsm.Configure(State.WillSUPPRESSGOAHEAD)
.SubstateOf(State.Accepting)
.OnEntryAsync(OnWillSuppressGAAsync);
}

return tsm;
}


private async Task OnSUPPRESSGOAHEADPrompt()
{
_Logger.LogDebug("Connection: {ConnectionState}", "Server is prompting SUPPRESSGOAHEAD");
await (SignalOnPromptingAsync?.Invoke() ?? Task.CompletedTask);
}

private async Task OnDontSuppressGAAsync()
{
_Logger.LogDebug("Connection: {ConnectionState}", "Client won't do SUPPRESSGOAHEAD - do nothing");
_doGA = true;
await Task.CompletedTask;
}

private async Task WontSuppressGAAsync()
{
_Logger.LogDebug("Connection: {ConnectionState}", "Server won't do SUPPRESSGOAHEAD - do nothing");
_doGA = true;
await Task.CompletedTask;
}

/// <summary>
/// Announce we do SUPPRESSGOAHEAD negotiation to the client.
/// </summary>
private async Task WillingSuppressGAAsync()
{
_Logger.LogDebug("Connection: {ConnectionState}", "Announcing willingness to SUPPRESSGOAHEAD!");
await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.WILL, (byte)Trigger.SUPPRESSGOAHEAD]);
}

/// <summary>
/// Store that we are now in SUPPRESSGOAHEAD mode.
/// </summary>
private Task OnDoSuppressGAAsync(StateMachine<State, Trigger>.Transition _)
{
_Logger.LogDebug("Connection: {ConnectionState}", "Client supports End of Record.");
_doGA =false;
return Task.CompletedTask;
}

/// <summary>
/// Store that we are now in SUPPRESSGOAHEAD mode.
/// </summary>
private async Task OnWillSuppressGAAsync(StateMachine<State, Trigger>.Transition _)
{
_Logger.LogDebug("Connection: {ConnectionState}", "Server supports End of Record.");
_doGA = false;
await CallbackNegotiationAsync([(byte)Trigger.IAC, (byte)Trigger.DO, (byte)Trigger.SUPPRESSGOAHEAD]);
}
}
}
6 changes: 5 additions & 1 deletion TelnetNegotiationCore/Models/State.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ public enum State : sbyte
EvaluatingMSDP,
CompletingMSDP,
AlmostNegotiatingMSDP,
EscapingMSDP
EscapingMSDP,
DoSUPPRESSGOAHEAD,
DontSUPPRESSGOAHEAD,
WillSUPPRESSGOAHEAD,
WontSUPPRESSGOAHEAD
#endregion MSDP Negotiation
}
}
7 changes: 7 additions & 0 deletions TelnetNegotiationCore/Models/Trigger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,13 @@ public enum Trigger : short
/// </remarks>
NOP = 241,
/// <summary>
/// Go ahead. Used, under certain circumstances, to tell the other end that it can transmit.
/// </summary>
/// <remarks>
/// RFC 854: http://www.faqs.org/rfcs/rfc854.html
/// </remarks>
GA = 249,
/// <summary>
/// The start of sub-negotiation options.
/// </summary>
/// <remarks>
Expand Down

0 comments on commit 2c0c6bb

Please sign in to comment.