Repository navigation
Cover static-mode withholding of the connection packet (#64) - #69
Merged
Merged
Conversation
…packet Closes the gap this issue was filed for. A mutant that releases the server's withheld ID_NEW_INCOMING_CONNECTION at transport-up in STATIC mode only, leaving the interactive path correctly gated, passed all 23 existing tests in this suite. Static-mode gating had no guard at all. It is not testable through received packets. In static mode the server answers the client's request the instant it arrives, so a peer that released the packet early is indistinguishable from a correct one to any poll: by the time the test looks, the payload it should have waited for has arrived anyway. That is why the existing static tests, which assert the payload is readable once the packet surfaces, are satisfied by the mutant. The assertion is therefore the slot invariant -- the connection is never reported to the application while the remote's payload is still missing -- sampled continuously off the server's own RemoteSystemStruct via a RakPeer-derived inspector, the same approach SendGateBypass in this file already uses to reach protected internals. The client's payload is 48 KB so it splits across many datagrams and the handshake spends a long, reliably observable time in the gated state. The test also asserts it actually witnessed the gated window, so it cannot quietly degrade into proving nothing, and re-checks the large payload survived reassembly intact. Verified on macOS arm64: - against the static-only mutant: fails 20/20, ~240 ms, ~4.8M sampled violations - clean library: passes 30/30, and 32/32 across 4 parallel instances - full ctest 284/284 Refs #64
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 26 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the remaining item on #64.
The gap was real
Before writing anything I checked whether #66 had already closed it, since the withholding mechanism is shared (
SendSessionConfigResponse→ProduceWithheldConnectionPacketis the single release point, reached from both the static path and the interactiveAcceptSessionpath). It had not.A mutant that releases the server's withheld
ID_NEW_INCOMING_CONNECTIONat transport-up in static mode only, leaving the interactive path correctly gated:Passed all 23 tests in the suite. Static-mode gating was entirely unguarded.
Why it cannot be tested through received packets
In static mode the server answers the client's request the instant it arrives, so correct code and early-release code are indistinguishable to any poll — by the time the test looks, the payload it should have waited for has arrived anyway. This is exactly why the existing static tests, which assert the payload is readable once the connection packet surfaces, are satisfied by the mutant.
I also ruled out the alternatives rather than assuming:
OnNewConnectionfires fromCallPluginCallbacksinsideReceive()— the user thread, at dequeue time, not production time. It cannot witness the ordering. No hook observesAddPacketToProducer.ReliabilityLayerBlackHoleTestsdrives twoReliabilityLayerobjects directly; it never constructs aRakPeer, so it cannot reach the session handshake, which lives inRakPeer::RunUpdateCycle.RakNetSocket2Allocator::AllocRNS2is a static factory with no injection seam, and hand-crafting reliability-layer framing to feedOnRNS2Recvwould be a large, fragile piece of infrastructure.What the test does instead
Asserts the slot invariant — the connection is never reported to the application while the remote's payload is still missing — sampled continuously off the server's own
RemoteSystemStruct, via aRakPeer-derived inspector. That is the same techniqueSendGateBypassin this file already uses to reach protected internals, with the same caveat documented (the peer must still come fromGetInstance()).The client's payload is 48 KB, so it splits across many datagrams and the handshake spends a long, reliably observable time in the gated state.
Two guards against the test quietly degrading:
sawGatedState), so it cannot silently become a test that proves nothing — the failure mode that made the original gating test useless.Verification (macOS arm64)
ctestThe detection signal is millions of samples wide, not a marginal timing catch.
Note
The test spins without sleeping, deliberately — the gated window is short and every sample counts, and it breaks out as soon as the connection is reported with the payload in hand (~240 ms typically). It does not poll
Receive()during the loop, which is fine: the network thread does the work andReceive()only dequeues.