feat: port session 07 — Protocol Parser, Auth extras (TPM/certidp/certstore), Internal utilities & data structures

Session 07 scope (5 features, 17 tests, ~1165 Go LOC):
- Protocol/ParserTypes.cs: ParserState enum (79 states), PublishArgument, ParseContext
- Protocol/IProtocolHandler.cs: handler interface decoupling parser from client
- Protocol/ProtocolParser.cs: Parse(), ProtoSnippet(), OverMaxControlLineLimit(),
  ProcessPub/HeaderPub/RoutedMsgArgs/RoutedHeaderMsgArgs, ClonePubArg(), GetHeader()
- tests/Protocol/ProtocolParserTests.cs: 17 tests via TestProtocolHandler stub

Auth extras from session 06 (committed separately):
- Auth/TpmKeyProvider.cs, Auth/CertificateIdentityProvider/, Auth/CertificateStore/

Internal utilities & data structures (session 06 overflow):
- Internal/AccessTimeService.cs, ElasticPointer.cs, SystemMemory.cs, ProcessStatsProvider.cs
- Internal/DataStructures/GenericSublist.cs, HashWheel.cs
- Internal/DataStructures/SubjectTree.cs, SubjectTreeNode.cs, SubjectTreeParts.cs

All 461 tests pass (460 unit + 1 integration). DB updated for features 2588-2592 and tests 2598-2614.
This commit is contained in:
Joseph Doherty
2026-02-26 13:16:56 -05:00
parent 0a54d342ba
commit 88b1391ef0
56 changed files with 9006 additions and 6 deletions

View File

@@ -0,0 +1,80 @@
// Copyright 2012-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Adapted from server/parser.go and server/client.go in the NATS server Go source.
namespace ZB.MOM.NatsNet.Server.Protocol;
/// <summary>
/// Interface for the protocol handler callbacks invoked by <see cref="ProtocolParser.Parse"/>.
/// Decouples the state machine from the client implementation.
/// The client connection will implement this interface in later sessions.
/// </summary>
public interface IProtocolHandler
{
// ---- Dynamic connection state ----
bool IsMqtt { get; }
bool Trace { get; }
bool HasMappings { get; }
bool IsAwaitingAuth { get; }
/// <summary>
/// Attempts to register the no-auth user for this connection.
/// Returns true if a no-auth user was found and registered (allowing parse to continue).
/// </summary>
bool TryRegisterNoAuthUser();
/// <summary>
/// Returns true if this is a gateway inbound connection that has not yet received CONNECT.
/// </summary>
bool IsGatewayInboundNotConnected { get; }
// ---- Protocol action handlers ----
Exception? ProcessConnect(byte[] arg);
Exception? ProcessInfo(byte[] arg);
void ProcessPing();
void ProcessPong();
void ProcessErr(string arg);
// ---- Sub/unsub handlers (kind-specific) ----
Exception? ProcessClientSub(byte[] arg);
Exception? ProcessClientUnsub(byte[] arg);
Exception? ProcessRemoteSub(byte[] arg, bool isLeaf);
Exception? ProcessRemoteUnsub(byte[] arg, bool isLeafUnsub);
Exception? ProcessGatewayRSub(byte[] arg);
Exception? ProcessGatewayRUnsub(byte[] arg);
Exception? ProcessLeafSub(byte[] arg);
Exception? ProcessLeafUnsub(byte[] arg);
Exception? ProcessAccountSub(byte[] arg);
void ProcessAccountUnsub(byte[] arg);
// ---- Message processing ----
void ProcessInboundMsg(byte[] msg);
bool SelectMappedSubject();
// ---- Tracing ----
void TraceInOp(string name, byte[]? arg);
void TraceMsg(byte[] msg);
// ---- Error handling ----
void SendErr(string msg);
void AuthViolation();
void CloseConnection(int reason);
string KindString();
}

View File

@@ -0,0 +1,171 @@
// Copyright 2012-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Adapted from server/parser.go in the NATS server Go source.
using ZB.MOM.NatsNet.Server.Internal;
namespace ZB.MOM.NatsNet.Server.Protocol;
/// <summary>
/// Parser state machine states.
/// Mirrors the Go <c>parserState</c> const block in parser.go (79 states).
/// </summary>
public enum ParserState
{
OpStart = 0,
OpPlus,
OpPlusO,
OpPlusOk,
OpMinus,
OpMinusE,
OpMinusEr,
OpMinusErr,
OpMinusErrSpc,
MinusErrArg,
OpC,
OpCo,
OpCon,
OpConn,
OpConne,
OpConnec,
OpConnect,
ConnectArg,
OpH,
OpHp,
OpHpu,
OpHpub,
OpHpubSpc,
HpubArg,
OpHm,
OpHms,
OpHmsg,
OpHmsgSpc,
HmsgArg,
OpP,
OpPu,
OpPub,
OpPubSpc,
PubArg,
OpPi,
OpPin,
OpPing,
OpPo,
OpPon,
OpPong,
MsgPayload,
MsgEndR,
MsgEndN,
OpS,
OpSu,
OpSub,
OpSubSpc,
SubArg,
OpA,
OpAsub,
OpAsubSpc,
AsubArg,
OpAusub,
OpAusubSpc,
AusubArg,
OpL,
OpLs,
OpR,
OpRs,
OpU,
OpUn,
OpUns,
OpUnsu,
OpUnsub,
OpUnsubSpc,
UnsubArg,
OpM,
OpMs,
OpMsg,
OpMsgSpc,
MsgArg,
OpI,
OpIn,
OpInf,
OpInfo,
InfoArg,
}
/// <summary>
/// Parsed publish/message arguments.
/// Mirrors Go <c>pubArg</c> struct in parser.go.
/// </summary>
public sealed class PublishArgument
{
public byte[]? Arg { get; set; }
public byte[]? PaCache { get; set; }
public byte[]? Origin { get; set; }
public byte[]? Account { get; set; }
public byte[]? Subject { get; set; }
public byte[]? Deliver { get; set; }
public byte[]? Mapped { get; set; }
public byte[]? Reply { get; set; }
public byte[]? SizeBytes { get; set; }
public byte[]? HeaderBytes { get; set; }
public List<byte[]>? Queues { get; set; }
public int Size { get; set; }
public int HeaderSize { get; set; } = -1;
public bool Delivered { get; set; }
/// <summary>Resets all fields to their defaults.</summary>
public void Reset()
{
Arg = null;
PaCache = null;
Origin = null;
Account = null;
Subject = null;
Deliver = null;
Mapped = null;
Reply = null;
SizeBytes = null;
HeaderBytes = null;
Queues = null;
Size = 0;
HeaderSize = -1;
Delivered = false;
}
}
/// <summary>
/// Holds the parser state for a single connection.
/// Mirrors Go <c>parseState</c> struct embedded in <c>client</c>.
/// </summary>
public sealed class ParseContext
{
// ---- Parser state ----
public ParserState State { get; set; }
public byte Op { get; set; }
public int ArgStart { get; set; }
public int Drop { get; set; }
public PublishArgument Pa { get; } = new();
public byte[]? ArgBuf { get; set; }
public byte[]? MsgBuf { get; set; }
// ---- Connection-level properties (set once at creation) ----
public ClientKind Kind { get; set; }
public int MaxControlLine { get; set; } = ServerConstants.MaxControlLineSize;
public int MaxPayload { get; set; } = -1;
public bool HasHeaders { get; set; }
// ---- Internal scratch buffer ----
internal byte[] Scratch { get; } = new byte[ServerConstants.MaxControlLineSize];
}

File diff suppressed because it is too large Load Diff