Repository navigation
feat(server): measure bandwidth on the UDP tunnel when EGFX uses it - #2031
Greg Lamberson (glamberson) wants to merge 10 commits into
Conversation
|
This pull request may overlap with #2021. This PR contains the same server-side feature This notice is advisory only. Automated review continues as usual, and how these pull requests relate is for maintainers and authors to decide. Note LLM-assisted content (no human feedback). |
|
For context, #2009 is the client side of this. It answers the RTT and bandwidth requests Windows sends in tunnel sub-headers, and it reads a sub-header as the auto-detect structure itself, the same way your latest commit does. I ran your Start ( The two branches do conflict in |
20f4ae7 to
6a57c9b
Compare
6a57c9b to
29d1ad7
Compare
d04020e to
e0649ad
Compare
There was a problem hiding this comment.
Independent review of PR #2031 (bandwidth measurement bracketed around large EGFX writes, with Start/Stop/Results carried as RDP_TUNNEL_SUBHEADERs over the reliable UDP tunnel). The change is sound: the manager state machine (Bracketing/AwaitingResults states, pacing, expiry of stalled measurements), the tunnel sub-header encode/decode helpers, and the shared record_autodetect_response path are coherent, protocol-consistent, and tested. All four validated specialist candidates were verified against the head tree and confirmed: the local bandwidth computation diverges from the now-orphaned PDU helper's zero-timeDelta semantics, a redundant bool remains in the EGFX routing code, the testsuite mirrors BW_BRACKET_MIN_BYTES instead of importing it via the PR's own __test mechanism, and the AwaitingResults since_ms Option exists only because build_bandwidth_measure cannot see the clock its caller has. No correctness defects were found independently; the four published findings are low-to-me…
- [skeptical] measured_bandwidth_kbps diverges from the orphaned pdu computed_bandwidth_kbps helper — medium 🟠 — crates/ironrdp-server/src/autodetect.rs
The PR replaces the call to AutoDetectResponse::computed_bandwidth_kbps with a local fn whose semantics differ: timeDelta 0 is clamped to 1 ms instead of yielding None. ironrdp-pdu still ships computed_bandwidth_kbps (documented 'None if timeDelta is zero', with tests pinning that behavior), and after this PR nothing in the workspace calls it outside its own tests. The workspace therefore carries two divergent definitions of the same derivation, and the deliberate semantic change (a real, bounded measurement vs. a discarded one) is made without touching the helper's docs/tests. Move the changed semantics into computed_bandwidth_kbps (updating its tests and noting the API change) or justify in code why the server must diverge. - [code-compressor] route_over_udp bool is now redundant with udp_route — low 🟡 — crates/ironrdp-server/src/server.rs
The refactor leaves route_over_udp read exactly once, only to set udp_route = Some(udp_transport); udp_route alone drives the final dispatch. The intermediate bool can be deleted by folding the tunnel_for_outgoing_channel comparison directly into the if, removing a binding that carries the same fact as udp_route. No behavior change; purely local polish. - [code-compressor] AwaitingResults::since_ms Option exists only because build_bandwidth_measure takes no clock — low 🟡 — crates/ironrdp-server/src/autodetect.rs
The tick-window path sets since_ms: None at Stop time, and expire_stale_probes carries a branch that stamps it on the first expiry pass that sees it. That lazy-stamp state (an Option, a mutation inside a match on &mut self.pending_bw, a documented subtlety, and a dedicated two-pass test) exists solely because build_bandwidth_measure cannot know the current time, while its single production caller already has monotonic_now_ms available. Taking now_ms and stamping at Stop-send removes the Option, the branch, and the test, at the cost of a public-signature change and a slightly tighter expiry window. Current form is correct; optional compression.
|
Fair point, and the two functions differ in more than the zero time. This one came in with #2021's first commit, which replaced the server's call to |
|
Right, that binding was left over from the routing change. On master the flag was read again at the end of the function, and with |
|
Thanks, that's a fair simplification, and the production caller does have a clock. I'm leaving it, because |
The doc on measured_bandwidth_kbps now says why it differs from AutoDetectResponse::computed_bandwidth_kbps in ironrdp-pdu. A zero time is a bounded measurement here, and zero bytes clears the figure. dispatch_egfx_messages compares the tunnel type directly in the if, since udp_route carries the routing decision.
There was a problem hiding this comment.
PR 2031 brackets large EGFX writes with Bandwidth Measure Start/Stop on both TCP and the reliable UDP tunnel, carrying auto-detect requests/results as RDP_TUNNEL_SUBHEADERs whose two header bytes double as the auto-detect header, and adds expiry for stalled measurements. Verified against the head: the lifecycle is closed on both paths and backstopped by expire_stale_probes; the sub-header wire form matches MS-RDPEMT 2.2.1.1.1 and is pinned by tests; responses are handled from either transport. Of the two candidates, the skeptical formula-divergence finding is valid in root cause but factually wrong that the divergence is unenforced: this PR's own tests fail if the call reverts to the ironrdp-pdu helper, so only the overflow-policy divergence remains unpinned (refined). The code-compressor inline suggestion is a neutral style tradeoff whose own rationale concedes keeping the documented wrapper is reasonable; it is rejected.
- [skeptical] Bandwidth formula diverges from ironrdp-pdu helper by design; divergence is test-pinned, only overflow policy is not — low 🟡 — crates/ironrdp-server/src/autodetect.rs
measured_bandwidth_kbps reimplements AutoDetectResponse::computed_bandwidth_kbps with deliberate zero-case differences: time_delta_ms is floored to 1 ms instead of failing, and a zero byte_count clears the figure instead of reporting Some(0). Unlike the original candidate claimed, this is enforced rather than only explained: zero_time_delta_counts_as_one_millisecond and zero_byte_count_ages_out_a_previous_bandwidth_figure (both in this PR) fail if the call is swapped back to the helper, so a revert cannot silently regress fast-link or empty measurements. The residual, unpinned divergence is overflow behavior: the helper truncates with `as u32` while measured_bandwidth_kbps saturates at u32::MAX; a test at the u32::MAX boundary would pin that too. Documentation-only follow-up; no correctness impact.
|
Good catch, the overflow policy was the one difference nothing pinned. I added |
A figure that doesn't fit in 32 bits saturates at u32::MAX in measured_bandwidth_kbps, where the ironrdp-pdu helper wraps, and no test pinned it. A new test feeds a 1 ms result with u32::MAX bytes. The doc now says why it matters. The client supplies both numbers, and u32::MAX also reads as not measured in the exposed bandwidth handle.
Summary
Validation
cargo xtask check fmt/lints/tests/typos/locksall pass. Tests inironrdp-testsuite-corecover the sub-header encoding of Start and the decoding of results arriving in tunnel sub-headers into the auto-detect manager, through a private__testfeature onironrdp-serverthat exposes those two functions, as well as the sub-header wire layout against the spec.Notes
Stacked on #2021 (bracketed measurement), whose commits come first in this branch; this PR's own changes are the commits from
feat(server): measure bandwidth on the UDP tunnel when EGFX uses itonward. #1954 and #2030 have merged.