Skip to content

tcp: add removable full-close cancellation registration - #5

Open
polaris-arch wants to merge 4 commits into
MetaCubeX:masterfrom
polaris-arch:fix/tcp-close-cancellation
Open

polaris-arch wants to merge 4 commits into
MetaCubeX:masterfrom
polaris-arch:fix/tcp-close-cancellation

Conversation

@polaris-arch

@polaris-arch polaris-arch commented Nov 9, 2026 •

Copy link
Copy Markdown

Add removable full-close cancellation registration for work associated with a TCP connection: TCPConn.CancelOnClose(context.CancelFunc) func() bool.

Classification and normal-path reachability

This is a new optional lifecycle capability, not a demonstrated defect in ordinary TCP read/write behavior. Baseline 9a80a07e has no equivalent removable full-close notification. External work is affected only when a consumer explicitly registers it; an undefined-method baseline compile error is not a BUG reproduction.

A valid peer RST makes the established actor return an error; run/runPassive/runForwardedPassive call finish, which detaches registrations. Full application Close detaches before positive-linger waiting. Callbacks run synchronously outside the existing connection mutex, including registration after termination; they must only signal cancellation and must not wait for the actor/stack.

FIN, CloseRead, CloseWrite and I/O deadlines alone do not imply full termination. Notification does not itself discard queued reads. Source: registration implementation, Close/actor termination.

Ownership and minimal implementation

Active-list membership under the existing connection mutex is the ownership authority. A successful stop unlinks its node and clears references. Closure detaches the whole list under that same mutex before invoking callbacks, so a detached node loses stop even if its callback has not run. The notifier exclusively owns detached nodes and releases their references. No separate claimed flag, marking pass, watcher goroutine or global registry is needed.

Multiple independent registrations remain supported; no new duplicate-registration rejection/panic contract is introduced. A false stop means claimed or already removed, does not wait for callback completion and does not establish that the callback has run. The original actor done event is not equivalent to full application closure before linger; a wrapper observing only application Close would miss remote RST termination.

Executable capability tests

In a disposable checkout, using the recorded Go 1.26.10 toolchain:

git fetch https://github.com/polaris-arch/mipstack.git 5b6706cc9d94126c606c13ec0c9fe8f4f360b628
git checkout --detach 5b6706cc9d94126c606c13ec0c9fe8f4f360b628
go test -count=10 -timeout 2m -v -run '^TestTCPCancelOnClose' ./...
CGO_ENABLED=1 go test -race -count=5 -timeout 3m -run '^TestTCPCancelOnClose' ./...

Controlled protocol tests versus fault injection

Control Mechanism and assertion Evidence boundary
Payload followed by valid RST Manually pumped real stack receives controlled segments; pending context is canceled and queued payload stays readable Controlled protocol fault, not a sampled production event
Peer FIN with live registration Two real stacks exchange request/FIN/EOF and a reverse response; only subsequent full Close notifies once Real generated FIN, not a synthetic EOF substituted for termination
Positive linger, full Close, stack shutdown Real stack/socket operations; notification precedes linger completion Lifecycle boundary control
Local half-close and deadlines Neither claims the full-close registration Positive API controls
Independent registrations, middle removal, old stop versus replacement Only the correct live owner can detach Ownership-contract tests
Stop/claim races and callback re-entry Tests force terminal state/claim scheduling; callbacks may re-enter registration outside the mutex Explicit adversarial scheduling/defensive coverage, not wire-level reproduction

Final source 5b6706cc passes focused tests, race checks, full tests, vet and Windows/macOS compilation in exact-source validation. That run also passes real native-forwarder reset/FIN controls and full Mihomo default/with_gvisor, race, vet and tunnel cross-compilation with the preceding TFO/group patches, using a test-only dependency override.

Consumer MetaCubeX/mihomo#3438 still needs API acceptance and a production dependency-version update. No production event frequency, standalone process resource saving, or old-API performance comparison is claimed. The source review and exact-source validation are complete. The consumer dependency-version update belongs to #3438; it is not delivered by this API proposal.

@polaris-arch
polaris-arch marked this pull request as ready for review November 9, 2026 12:26
@polaris-arch
polaris-arch marked this pull request as draft November 9, 2026 14:10
@polaris-arch
polaris-arch marked this pull request as ready for review November 10, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant