feat(server): add bandwidth-measure generation counter - #1963
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The relaxed atomics cannot provide coherent generation/value snapshots, and the new transitions lack tests.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Adds a generation counter so embedders can detect completed bandwidth-measurement windows.
Changes:
- Exposes configurable bandwidth-generation handles.
- Increments generation for successful and unusable measurements.
- Adds raw measurement inputs to debug logging.
Protocol review found no wire-format changes. Prose verification was skipped because no standalone documentation changed.
| File | Description |
|---|---|
crates/ironrdp-server/src/server.rs |
Stores, exposes, and updates generation state. |
crates/ironrdp-server/src/builder.rs |
Adds generation-handle injection. |
bandwidth_kbps alone reads as noise on a damage-driven video source: a single 1.25s measurement window catches either near-idle traffic (a handful of cursor/autodetect PDUs, ~1.8KB) or a real EGFX frame landing in it (tens of KB), so the same unthrottled link reports anywhere from ~11kbps to ~600kbps depending on what the encoder happened to be doing in that specific window. Logging time_delta_ms/byte_count alongside the computed figure makes that bimodality visible instead of looking like a calculation bug -- the formula (byte_count*8/time_delta_ms) was already correct; the volatility is inherent to counting real traffic over a short window against a bursty source, not a defect.
The bandwidth figure alone repeats too often to tell a fresh measurement window apart from a stale one (a quiet link reads the same low figure for several consecutive windows). Expose a counter that increments on every completed Bandwidth Measure transaction, successful or not, so a consumer can gate its own filtering logic on "a new window just closed" instead of diffing the value itself.
bcbbb9a to
ee87cf1
Compare
There was a problem hiding this comment.
Independently verified: the additive generation counter mirrors the existing autodetect handle family (builder field, initializers, RdpServer::new parameter, default, accessor) and increments at both Bandwidth Measure completion branches, consistent with AutoDetectManager's clearing semantics. No protocol or API break found. Three low-severity quality issues remain: the bundled log enrichment adds an unreachable!() panic in the PDU-handling loop to extract two debug fields (dead branch today, but a cross-crate invariant with a panic-free, shorter alternative); no test pins the increment-on-both-branches semantics (the None branch advances the generation while the figure reads u32::MAX); and the documented read-generation-then-bandwidth pairing has no cross-atomic ordering guarantee under Relaxed on weakly ordered targets. The two specialist let-else findings describe the same defect and were merged into one published finding.
…g panic path The generation counter is now incremented with Release after the bandwidth store, and the accessor documents an Acquire load and an at-least-as-new guarantee rather than an exact pair. The bandwidth log records the whole response instead of destructuring it behind an unreachable!(). Adds default and injection tests for the generation handle.
|
This pull request may overlap with #1964. Both pull requests currently modify the server's handling of PDUs received on the MCS message channel in crates/ironrdp-server/src/server.rs. This PR edits the AutoDetectOutcome::Bandwidth arms inside handle_message_channel_data; 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). |
ded2caa
into
Devolutions:master


Summary
autodetect_bandwidth_handle()(feat(server): expose measured bandwidth to the embedder #1734) exposes the latest BandwidthMeasure figure, but a consumer doing its own smoothing/filtering on
top of it (e.g. rejecting noisy low samples unless real demand
existed) needs to know when a new measurement window has closed,
not just what the figure currently reads. The figure itself is a bad
freshness signal: a quiet link reads the same low value for several
consecutive windows in a row, so diffing it cannot tell "fresh
window, same result" apart from "stale, no new window yet".
autodetect_bandwidth_generation, mirroringautodetect_bandwidth's exact shape: anArc<AtomicU32>field,autodetect_bandwidth_generation_handle()accessor, andwith_autodetect_bandwidth_generation_handle()builder method. Itincrements on every completed Bandwidth Measure transaction,
successful or not: a completed-but-unusable window still needs to
advance the generation so a consumer's own stale-demand bookkeeping
gets cleared instead of carrying over into the next window. The
server increments it with
Releaseafter storing the figure, so aconsumer that loads it with
Acquirereads a bandwidth value atleast as new as the generation it saw.
from just the computed
bandwidth_kbpsto the whole BandwidthMeasure Results response, which carries the raw
byte_count/time_delta_msinputs. Useful on itsown for anyone diagnosing why the figure looks noisy against a
bursty traffic source (as this crate's own damage-driven server
usage does): the raw inputs make it immediately visible whether a
low reading came from a genuinely idle window or a short one that
happened to close early.
Validation
cargo xtask check fmt/lints/tests/typos/locksall pass. testsuite-corecovers the generation handle's default and injection; the increment itself
runs in the private connection loop, which no harness reaches.
Notes
No public API break: both changes are purely additive to
RdpServerBuilderandRdpServer.