perf(net): frame recurring sends in place

Write normal game-message and ACK packet framing directly into bounded stack spans, hash fragments without materialization, and send the populated slice to the socket. Preserve exact wire bytes and ISAAC failure ordering with differential and zero-allocation tests.
This commit is contained in:
Erik 2026-07-25 06:02:52 +02:00
parent e928c5dd02
commit 41c1a59392
7 changed files with 485 additions and 31 deletions

View file

@ -520,8 +520,6 @@ public static class PacketCodec
/// </param>
public static byte[] Encode(PacketHeader header, ReadOnlySpan<byte> body, IsaacRandom? outboundIsaac)
{
header.DataSize = checked((ushort)body.Length);
// Parse the optional-section length out of the body so we can hash
// it separately from any subsequent fragments. Without the BlobFragments
// flag, the entire body IS the optional section. With BlobFragments,
@ -541,43 +539,129 @@ public static class PacketCodec
if (optionalLen < 0)
throw new ArgumentException("body's optional section is malformed", nameof(body));
uint optionalHash = Hash32.Calculate(body.Slice(0, optionalLen));
byte[] datagram = new byte[PacketHeader.Size + body.Length];
body.CopyTo(datagram.AsSpan(PacketHeader.Size));
FinalizeInPlace(
header,
datagram,
body.Length,
optionalLen,
outboundIsaac);
return datagram;
}
// Hash any fragments in the body tail.
uint fragmentHash = 0;
if (header.HasFlag(PacketHeaderFlags.BlobFragments))
/// <summary>
/// Finalize a packet whose body has already been written immediately
/// after the fixed header in <paramref name="datagram"/>. Computes the
/// exact optional/fragment hash, consumes the outbound ISAAC word when
/// required, and writes the fixed header in place.
/// </summary>
internal static int FinalizeInPlace(
PacketHeader header,
Span<byte> datagram,
int bodyLength,
int optionalLength,
IsaacRandom? outboundIsaac)
{
if ((uint)bodyLength > ushort.MaxValue)
{
var tail = body.Slice(optionalLen);
while (tail.Length > 0)
{
var (frag, consumed) = MessageFragment.TryParse(tail);
if (frag is null || consumed == 0)
throw new ArgumentException("body contains a malformed fragment", nameof(body));
fragmentHash += CalculateFragmentHash32(frag.Value);
tail = tail.Slice(consumed);
}
throw new ArgumentOutOfRangeException(
nameof(bodyLength));
}
uint headerHash = header.CalculateHeaderHash32();
uint payloadHash = optionalHash + fragmentHash;
int datagramLength = checked(PacketHeader.Size + bodyLength);
if (datagram.Length < datagramLength)
{
throw new ArgumentException(
$"datagram must be at least {datagramLength} bytes",
nameof(datagram));
}
if ((uint)optionalLength > (uint)bodyLength)
{
throw new ArgumentOutOfRangeException(
nameof(optionalLength));
}
ReadOnlySpan<byte> body = datagram.Slice(
PacketHeader.Size,
bodyLength);
uint payloadHash = CalculatePayloadHash(
body,
header.Flags,
optionalLength);
header.DataSize = checked((ushort)bodyLength);
uint headerHash = header.CalculateHeaderHash32();
if (header.HasFlag(PacketHeaderFlags.EncryptedChecksum))
{
if (outboundIsaac is null)
{
throw new InvalidOperationException(
"EncryptedChecksum flag set but no ISAAC keystream provided");
}
uint isaacKey = outboundIsaac.Next();
header.Checksum = headerHash + (isaacKey ^ payloadHash);
header.Checksum =
headerHash + (isaacKey ^ payloadHash);
}
else
{
header.Checksum = headerHash + payloadHash;
}
byte[] datagram = new byte[PacketHeader.Size + body.Length];
header.Pack(datagram);
body.CopyTo(datagram.AsSpan(PacketHeader.Size));
return datagram;
return datagramLength;
}
private static uint CalculatePayloadHash(
ReadOnlySpan<byte> body,
PacketHeaderFlags flags,
int optionalLength)
{
uint optionalHash = Hash32.Calculate(
body.Slice(0, optionalLength));
if ((flags & PacketHeaderFlags.BlobFragments) == 0)
{
if (optionalLength != body.Length)
{
throw new ArgumentException(
"non-fragment body contains bytes outside the optional section",
nameof(body));
}
return optionalHash;
}
uint fragmentHash = 0;
ReadOnlySpan<byte> remaining =
body.Slice(optionalLength);
while (!remaining.IsEmpty)
{
if (!MessageFragment.TryParseLayout(
remaining,
out _,
out int payloadLength,
out int consumed))
{
throw new ArgumentException(
"body contains a malformed fragment",
nameof(body));
}
fragmentHash +=
Hash32.Calculate(
remaining.Slice(
0,
MessageFragmentHeader.Size))
+ Hash32.Calculate(
remaining.Slice(
MessageFragmentHeader.Size,
payloadLength));
remaining = remaining.Slice(consumed);
}
return optionalHash + fragmentHash;
}
/// <summary>