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

CNA snapshot 009d40f5  ·  Known Issues › Current bugs  ·  source links pinned to 009d40f5

✓

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

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.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Known issues
Bug index