CNA-BUG-211: Agent::Stop can wait up to about six seconds for a connection that the accept loop takes around the time Stop runs
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
Stop shuts down only a client already published as activeClient_, and the worker never re-checks stopping_ after accepting. A connection accepted just before Stop, or during the accept poll of up to 200 ms that follows Stop setting stopping_, is therefore never shut down, and join waits on that client's handshake reads, up to 3 s for the header and 3 s for the payload.
- Identifier
CNA-BUG-211- Category
- Bug
- Subsystem
- Diagnostics & Inspector
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- CNA::Inspector::Agent::Stop() and ~Agent()
Expected behaviour
Stop is built to return promptly: it sets stopping_, shuts the active client socket down under socketMutex_ so that a blocked receive returns, and joins a worker whose accept loop wakes every 200 ms.
Actual behaviour at TARGET
Agent::Impl::Run publishes an accepted socket as activeClient_ (under socketMutex_) only after AcceptTcp returns, and HandleClient starts the handshake without re-checking stopping_. Stop sets stopping_, shuts down whatever activeClient_ holds at that moment (InvalidSocket when nothing is published) and joins. The worker only notices stopping_ when its 200 ms accept poll times out, and the poll returns at once when a connection arrives, so a connection accepted just before Stop or at any point in that interval is published after Stop's shutdown step and served anyway. HandleClient then blocks in ReceivePacket, which applies HandshakeTimeoutMilliseconds (3,000) to the 24-byte header and again to the payload. A client that sends a valid ClientHello at once ends the wait early; a silent local peer holds Stop, and therefore a game's ~Agent, for about 3 s, and one that sends a complete header and withholds the payload for up to about 6 s.
Source locations
modules/inspector/src/Agent.cpp— Agent::Impl::Stop, Agent::Impl::Run, Agent::Impl::HandleClientmodules/inspector/src/InternalSocket.cpp— AcceptTcp, ReceiveExact, ReceivePacket
Evidence
Checked by reading Agent.cpp and InternalSocket.cpp at 009d40f5. Not executed; the window's width was not measured.
Independent re-verification: Checked by reading Agent.cpp and InternalSocket.cpp at 009d40f5. Not executed; the window follows from the 200 ms accept poll and is not measured.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
No test calls Stop explicitly or with a client attached (see the Inspector test-gap entry).
Regression test
Re-check stopping_ after publishing activeClient_ (or shut the new socket down there when stopping), then test: connect a silent client, call Stop, and assert it returns well under the handshake timeout, repeated to cover the window.
Blast radius
Applications that stop or destroy the agent while a local peer is connecting; the delay is bounded and nothing is exposed.
Workaround
No workaround is known.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Inspector: security model
- Known issues
- Bug index