fix(session): hold --lock-on-disconnect while a reconnect is handshaking - #190
Merged
Merged
Conversation
A session only counts as live once FULLY connected (~10 s over ZeroTier), so a client that reconnected 12-22 s after leaving was locked underneath its own handshake (#181 follow-up; invisible with --auto-unlock, strands a remote user without it). src/lock_activity.rs wraps the connection handler — only with --lock-on-disconnect, so the default path is unchanged — to timestamp accepted connections and successful CredSSP authentications. At expiry the pending lock holds while there is activity since the disconnect: an authenticated reconnect within 30 s, or an accepted connection within 10 s (the timer can end mid-CredSSP). Each hold is capped at 30 s past the normal firing time, so an unauthenticated peer can only delay the lock, never prevent it. Activity from before the disconnect is ignored, and a later disconnect supersedes an earlier pending lock (LOCK_GENERATION). 8 new unit tests (the policy, the cap, pre-disconnect activity, the wrapper preserving the inner handler's verdict).
clintcan
added a commit
that referenced
this pull request
Sep 29, 2026
clintcan
added a commit
that referenced
this pull request
Sep 30, 2026
The client's microphone presents as "macrdp Microphone", a real macOS input device (#191). Opt-in and EXPERIMENTAL (--enable-microphone-redirection, or the GUI controller); the Core Audio driver ships in macrdp.app and installs from the controller. 16-bit PCM 44.1 kHz only. Protocol layer is vendored divergence (25); upstream ironrdp-rdpeai replaces it at the next pin bump. Also #190: --lock-on-disconnect holds while a reconnect is handshaking. Pre-tag gates: fmt clean (stable + nightly), clippy -D warnings clean, 259 tests passing. Docs: release-history, README status, CLAUDE.md status.
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.
Follow-up to #181, from the final review there.
Problem
--lock-on-disconnecttreats a client as back only onceSessionTrackercounts a fully connected session, which takes ~10 s over ZeroTier. A client that reconnects 12–22 s after leaving is locked underneath its own handshake. With--auto-unlockit self-corrects about 3 s later; with the lock alone, a remote user lands on a lock screen they can't get past.Fix
src/lock_activity.rswraps the connection handler to timestamp accepted connections and successful CredSSP authentications. The wrapper is installed only with--lock-on-disconnect, so the default connection path is unchanged, and it forwards every hook to the auth guard unchanged. When the lock comes due, it holds while there has been activity since the disconnect:Every hold is capped at 30 s past the normal firing time, so an unauthenticated peer opening connections can only delay the lock, never prevent it. Activity from before the disconnect (the departing session's own authentication) is ignored. A later disconnect supersedes an earlier pending lock (
LOCK_GENERATION), so leave → return → leave locks on the last disconnect's timer rather than the first.This is timestamp-based rather than a per-connection counter on purpose: during a live session the preemption race calls
on_acceptfor candidates that may never reachon_disconnected, so a counter would drift upward.Verification
-D warningsand stable + nightly fmt are clean.--shield-primary --lock-on-disconnect --auto-unlock, timer shortened to ~5.5 s so an ordinary reconnect lands mid-handshake), from a Windows 11 mstsc client:a client is reconnecting — holding the lock). mstsc's spare pre-auth connection kept the hold alive until the real one authenticated about 6 s later. The session came up and the lock was skipped. The old code would have locked about 6 s before the client was back.Residual
The 10 s pre-auth hold covers one slow-to-authenticate connection. In the live run, mstsc's spare connection used about 7.7 s of it before the real connection arrived; each new accept restarts the window, within the 30 s cap.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MtHRbjs42rW2fLZD1jqgwG