perf(net): borrow inbound packet storage

Decode headers, optional fields, fragments, and single-fragment messages directly over pooled datagrams. Copy only fragment state that crosses a datagram lifetime, preserve synchronous dispatch and ACK ordering, and lock the path to the owned decoder with differential and zero-allocation tests.
This commit is contained in:
Erik 2026-07-25 05:58:55 +02:00
parent 7211bb1bf7
commit e928c5dd02
18 changed files with 1329 additions and 66 deletions

View file

@ -0,0 +1,74 @@
namespace AcDream.Core.Net.Packets;
/// <summary>
/// Allocation-free decoded packet view. Every memory member borrows the
/// caller's datagram and is valid only while that owner retains the buffer.
/// </summary>
internal readonly record struct BorrowedPacket(
PacketHeader Header,
BorrowedOptionalHeader Optional,
ReadOnlyMemory<byte> Body,
ReadOnlyMemory<byte> FragmentBytes,
int FragmentCount)
{
public BorrowedFragmentEnumerable Fragments =>
new(FragmentBytes);
}
internal readonly record struct BorrowedOptionalHeader(
uint AckSequence,
double TimeSync,
float EchoRequestClientTime,
uint FlowBytes,
ushort FlowInterval,
double ConnectRequestServerTime,
ulong ConnectRequestCookie,
uint ConnectRequestClientId,
uint ConnectRequestServerSeed,
uint ConnectRequestClientSeed,
ReadOnlyMemory<byte> RawBytes,
ReadOnlyMemory<byte> RetransmitRequestBytes,
int RetransmitRequestCount);
internal readonly record struct BorrowedPacketDecodeResult(
BorrowedPacket Packet,
PacketCodec.DecodeError Error)
{
public bool IsOk => Error == PacketCodec.DecodeError.None;
}
internal readonly record struct BorrowedMessageFragment(
MessageFragmentHeader Header,
ReadOnlyMemory<byte> Payload);
internal readonly struct BorrowedFragmentEnumerable(
ReadOnlyMemory<byte> encoded)
{
public Enumerator GetEnumerator() => new(encoded);
internal struct Enumerator(ReadOnlyMemory<byte> remaining)
{
private ReadOnlyMemory<byte> _remaining = remaining;
public BorrowedMessageFragment Current { get; private set; }
public bool MoveNext()
{
if (_remaining.IsEmpty)
return false;
if (!MessageFragment.TryParseBorrowed(
_remaining,
out BorrowedMessageFragment fragment,
out int consumed))
{
throw new InvalidOperationException(
"validated packet contained an invalid fragment");
}
Current = fragment;
_remaining = _remaining.Slice(consumed);
return true;
}
}
}

View file

@ -95,6 +95,80 @@ public sealed class FragmentAssembler
return combined;
}
/// <summary>
/// Production borrowed-memory path. A complete single-fragment message
/// is returned as a view into the current datagram. Multi-fragment
/// payloads are copied only because they must survive that datagram's
/// pooled lifetime.
/// </summary>
internal bool TryIngest(
in BorrowedMessageFragment fragment,
out ReadOnlyMemory<byte> message,
out ushort messageQueue)
{
MessageFragmentHeader header = fragment.Header;
message = ReadOnlyMemory<byte>.Empty;
messageQueue = 0;
if (header.Count == 1 && header.Index == 0)
{
message = fragment.Payload;
messageQueue = header.Queue;
return true;
}
if (!_inFlight.TryGetValue(
header.Sequence,
out PartialMessage? partial))
{
partial = new PartialMessage(
header.Count,
header.Queue);
_inFlight[header.Sequence] = partial;
}
else if (partial.TotalFragments != header.Count
|| partial.Queue != header.Queue)
{
// Same sequence with conflicting identity is malformed. Preserve
// the first accepted partial instead of corrupting its layout.
return false;
}
if (partial.Fragments[header.Index] is null)
{
partial.Fragments[header.Index] =
fragment.Payload.ToArray();
partial.ReceivedCount++;
}
if (partial.ReceivedCount < partial.TotalFragments)
return false;
int totalBytes = 0;
for (int index = 0;
index < partial.TotalFragments;
index++)
{
totalBytes += partial.Fragments[index]!.Length;
}
var combined = new byte[totalBytes];
int offset = 0;
for (int index = 0;
index < partial.TotalFragments;
index++)
{
byte[] payload = partial.Fragments[index]!;
payload.CopyTo(combined, offset);
offset += payload.Length;
}
_inFlight.Remove(header.Sequence);
message = combined;
messageQueue = partial.Queue;
return true;
}
/// <summary>Discard all in-flight partial messages.</summary>
public void DropAll() => _inFlight.Clear();

View file

@ -20,25 +20,75 @@ public readonly record struct MessageFragment(MessageFragmentHeader Header, byte
/// </summary>
public static (MessageFragment? fragment, int consumed) TryParse(ReadOnlySpan<byte> source)
{
if (source.Length < MessageFragmentHeader.Size)
if (!TryParseLayout(
source,
out MessageFragmentHeader header,
out int payloadLength,
out int consumed))
{
return (null, 0);
}
var header = MessageFragmentHeader.Unpack(source);
byte[] payload = source
.Slice(MessageFragmentHeader.Size, payloadLength)
.ToArray();
return (new MessageFragment(header, payload), consumed);
}
internal static bool TryParseBorrowed(
ReadOnlyMemory<byte> source,
out BorrowedMessageFragment fragment,
out int consumed)
{
if (!TryParseLayout(
source.Span,
out MessageFragmentHeader header,
out int payloadLength,
out consumed))
{
fragment = default;
return false;
}
fragment = new BorrowedMessageFragment(
header,
source.Slice(
MessageFragmentHeader.Size,
payloadLength));
return true;
}
internal static bool TryParseLayout(
ReadOnlySpan<byte> source,
out MessageFragmentHeader header,
out int payloadLength,
out int consumed)
{
header = default;
payloadLength = 0;
consumed = 0;
if (source.Length < MessageFragmentHeader.Size)
return false;
header = MessageFragmentHeader.Unpack(source);
// TotalSize is the fragment's own size including its header. Anything
// smaller than the header or larger than the max fragment size is
// wire corruption and we refuse to parse.
if (header.TotalSize < MessageFragmentHeader.Size
|| header.TotalSize > MessageFragmentHeader.MaxFragmentSize)
|| header.TotalSize > MessageFragmentHeader.MaxFragmentSize
|| header.Count == 0
|| header.Index >= header.Count)
{
return (null, 0);
return false;
}
int payloadLength = header.TotalSize - MessageFragmentHeader.Size;
payloadLength =
header.TotalSize - MessageFragmentHeader.Size;
if (source.Length < header.TotalSize)
return (null, 0);
return false;
var payload = source.Slice(MessageFragmentHeader.Size, payloadLength).ToArray();
return (new MessageFragment(header, payload), header.TotalSize);
consumed = header.TotalSize;
return true;
}
}

View file

@ -115,6 +115,373 @@ public static class PacketCodec
return new PacketDecodeResult(packet, DecodeError.None);
}
/// <summary>
/// Decode and verify one packet without materializing packet, optional-
/// header, fragment-list, body, or fragment-payload objects. Returned
/// memory borrows <paramref name="datagram"/> and must not outlive it.
/// </summary>
internal static BorrowedPacketDecodeResult TryDecodeBorrowed(
ReadOnlyMemory<byte> datagram,
IsaacRandom? inboundIsaac)
{
ReadOnlySpan<byte> wire = datagram.Span;
if (wire.Length < PacketHeader.Size)
{
return new BorrowedPacketDecodeResult(
default,
DecodeError.TooShort);
}
PacketHeader header = PacketHeader.Unpack(wire);
int bodyLength = header.DataSize;
if (wire.Length - PacketHeader.Size < bodyLength)
{
return new BorrowedPacketDecodeResult(
default,
DecodeError.HeaderSizeExceedsBuffer);
}
ReadOnlyMemory<byte> body = datagram.Slice(
PacketHeader.Size,
bodyLength);
if (!TryParseBorrowedOptional(
body,
header.Flags,
out BorrowedOptionalHeader optional,
out int optionalConsumed))
{
return new BorrowedPacketDecodeResult(
default,
DecodeError.InvalidOptionalHeader);
}
ReadOnlyMemory<byte> fragmentBytes =
ReadOnlyMemory<byte>.Empty;
int fragmentCount = 0;
uint fragmentHash = 0;
if (header.HasFlag(PacketHeaderFlags.BlobFragments))
{
fragmentBytes = body.Slice(optionalConsumed);
ReadOnlySpan<byte> remaining = fragmentBytes.Span;
while (!remaining.IsEmpty)
{
if (!MessageFragment.TryParseLayout(
remaining,
out _,
out int payloadLength,
out int consumed))
{
return new BorrowedPacketDecodeResult(
default,
DecodeError.InvalidFragment);
}
fragmentHash +=
Hash32.Calculate(
remaining.Slice(
0,
MessageFragmentHeader.Size))
+ Hash32.Calculate(
remaining.Slice(
MessageFragmentHeader.Size,
payloadLength));
fragmentCount++;
remaining = remaining.Slice(consumed);
}
}
uint headerHash = header.CalculateHeaderHash32();
uint optionalHash = Hash32.Calculate(
optional.RawBytes.Span);
uint payloadHash = optionalHash + fragmentHash;
if (header.HasFlag(
PacketHeaderFlags.EncryptedChecksum))
{
if (inboundIsaac is null)
{
return new BorrowedPacketDecodeResult(
default,
DecodeError.ChecksumMismatch);
}
uint expectedKey =
(header.Checksum - headerHash) ^ payloadHash;
uint isaacKey = inboundIsaac.Next();
if (expectedKey != isaacKey)
{
return new BorrowedPacketDecodeResult(
default,
DecodeError.ChecksumMismatch);
}
}
else if (header.Checksum != headerHash + payloadHash)
{
return new BorrowedPacketDecodeResult(
default,
DecodeError.ChecksumMismatch);
}
return new BorrowedPacketDecodeResult(
new BorrowedPacket(
header,
optional,
body,
fragmentBytes,
fragmentCount),
DecodeError.None);
}
private static bool TryParseBorrowedOptional(
ReadOnlyMemory<byte> bodyMemory,
PacketHeaderFlags flags,
out BorrowedOptionalHeader optional,
out int consumed)
{
ReadOnlySpan<byte> body = bodyMemory.Span;
int position = 0;
uint ackSequence = 0;
double timeSync = 0;
float echoRequestClientTime = 0;
uint flowBytes = 0;
ushort flowInterval = 0;
double connectRequestServerTime = 0;
ulong connectRequestCookie = 0;
uint connectRequestClientId = 0;
uint connectRequestServerSeed = 0;
uint connectRequestClientSeed = 0;
int retransmitOffset = 0;
int retransmitCount = 0;
if (HasFlag(flags, PacketHeaderFlags.ServerSwitch)
&& !Take(body, ref position, 8))
{
return Invalid(out optional, out consumed);
}
if (HasFlag(flags, PacketHeaderFlags.RequestRetransmit))
{
if (!Take(body, ref position, 4))
return Invalid(out optional, out consumed);
uint count = System.Buffers.Binary.BinaryPrimitives
.ReadUInt32LittleEndian(
body.Slice(position - 4));
if (count > 1024
|| body.Length - position < (int)count * 4)
{
return Invalid(out optional, out consumed);
}
retransmitOffset = position;
retransmitCount = checked((int)count);
position += retransmitCount * 4;
}
if (HasFlag(flags, PacketHeaderFlags.RejectRetransmit))
{
if (!Take(body, ref position, 4))
return Invalid(out optional, out consumed);
uint count = System.Buffers.Binary.BinaryPrimitives
.ReadUInt32LittleEndian(
body.Slice(position - 4));
if (count > 1024
|| body.Length - position < (int)count * 4)
{
return Invalid(out optional, out consumed);
}
position += checked((int)count * 4);
}
if (HasFlag(flags, PacketHeaderFlags.AckSequence))
{
if (!Take(body, ref position, 4))
return Invalid(out optional, out consumed);
ackSequence =
System.Buffers.Binary.BinaryPrimitives
.ReadUInt32LittleEndian(
body.Slice(position - 4));
}
if (HasFlag(flags, PacketHeaderFlags.LoginRequest))
{
position = body.Length;
optional = BuildOptional(
bodyMemory,
position,
ackSequence,
timeSync,
echoRequestClientTime,
flowBytes,
flowInterval,
connectRequestServerTime,
connectRequestCookie,
connectRequestClientId,
connectRequestServerSeed,
connectRequestClientSeed,
retransmitOffset,
retransmitCount);
consumed = position;
return true;
}
if (HasFlag(flags, PacketHeaderFlags.WorldLoginRequest)
&& !Take(body, ref position, 8))
{
return Invalid(out optional, out consumed);
}
if (HasFlag(flags, PacketHeaderFlags.ConnectRequest))
{
if (body.Length - position < 32)
return Invalid(out optional, out consumed);
connectRequestServerTime =
BitConverter.Int64BitsToDouble(
System.Buffers.Binary.BinaryPrimitives
.ReadInt64LittleEndian(
body.Slice(position)));
connectRequestCookie =
System.Buffers.Binary.BinaryPrimitives
.ReadUInt64LittleEndian(
body.Slice(position + 8));
connectRequestClientId =
System.Buffers.Binary.BinaryPrimitives
.ReadUInt32LittleEndian(
body.Slice(position + 16));
connectRequestServerSeed =
System.Buffers.Binary.BinaryPrimitives
.ReadUInt32LittleEndian(
body.Slice(position + 20));
connectRequestClientSeed =
System.Buffers.Binary.BinaryPrimitives
.ReadUInt32LittleEndian(
body.Slice(position + 24));
position += 32;
}
if (HasFlag(flags, PacketHeaderFlags.ConnectResponse)
&& !Take(body, ref position, 8))
{
return Invalid(out optional, out consumed);
}
if (HasFlag(flags, PacketHeaderFlags.CICMDCommand)
&& !Take(body, ref position, 8))
{
return Invalid(out optional, out consumed);
}
if (HasFlag(flags, PacketHeaderFlags.TimeSync))
{
if (!Take(body, ref position, 8))
return Invalid(out optional, out consumed);
timeSync = BitConverter.Int64BitsToDouble(
System.Buffers.Binary.BinaryPrimitives
.ReadInt64LittleEndian(
body.Slice(position - 8)));
}
if (HasFlag(flags, PacketHeaderFlags.EchoRequest))
{
if (!Take(body, ref position, 4))
return Invalid(out optional, out consumed);
echoRequestClientTime =
System.Buffers.Binary.BinaryPrimitives
.ReadSingleLittleEndian(
body.Slice(position - 4));
}
if (HasFlag(flags, PacketHeaderFlags.Flow))
{
if (!Take(body, ref position, 6))
return Invalid(out optional, out consumed);
flowBytes =
System.Buffers.Binary.BinaryPrimitives
.ReadUInt32LittleEndian(
body.Slice(position - 6));
flowInterval =
System.Buffers.Binary.BinaryPrimitives
.ReadUInt16LittleEndian(
body.Slice(position - 2));
}
optional = BuildOptional(
bodyMemory,
position,
ackSequence,
timeSync,
echoRequestClientTime,
flowBytes,
flowInterval,
connectRequestServerTime,
connectRequestCookie,
connectRequestClientId,
connectRequestServerSeed,
connectRequestClientSeed,
retransmitOffset,
retransmitCount);
consumed = position;
return true;
}
private static BorrowedOptionalHeader BuildOptional(
ReadOnlyMemory<byte> body,
int consumed,
uint ackSequence,
double timeSync,
float echoRequestClientTime,
uint flowBytes,
ushort flowInterval,
double connectRequestServerTime,
ulong connectRequestCookie,
uint connectRequestClientId,
uint connectRequestServerSeed,
uint connectRequestClientSeed,
int retransmitOffset,
int retransmitCount) =>
new(
ackSequence,
timeSync,
echoRequestClientTime,
flowBytes,
flowInterval,
connectRequestServerTime,
connectRequestCookie,
connectRequestClientId,
connectRequestServerSeed,
connectRequestClientSeed,
body.Slice(0, consumed),
retransmitCount == 0
? ReadOnlyMemory<byte>.Empty
: body.Slice(
retransmitOffset,
retransmitCount * 4),
retransmitCount);
private static bool Invalid(
out BorrowedOptionalHeader optional,
out int consumed)
{
optional = default;
consumed = 0;
return false;
}
private static bool HasFlag(
PacketHeaderFlags all,
PacketHeaderFlags bit) =>
(all & bit) != 0;
private static bool Take(
ReadOnlySpan<byte> body,
ref int position,
int count)
{
if (body.Length - position < count)
return false;
position += count;
return true;
}
/// <summary>
/// Assemble a datagram from a header and an optional-section body.
/// Computes the checksum (both unencrypted and ISAAC-encrypted forms)