Skip to content

refactor(server): deliver USB completions through shared per-device state - #1808

Open
uchouT (uchouT) wants to merge 3 commits into
Devolutions:masterfrom
uchouT:urbdrc/server-comp
Open

refactor(server): deliver USB completions through shared per-device state#1808
uchouT (uchouT) wants to merge 3 commits into
Devolutions:masterfrom
uchouT:urbdrc/server-comp

Conversation

@uchouT

Copy link
Copy Markdown
Contributor

Reworks how ironrdp-server tracks a redirected USB device, so that
completions no longer round-trip through ServerEvent.

Per-device state (lifecycle, pending-request map, USB shared state) moves into
a single Arc<ServerUsbDevice> held by UsbDeviceHandle. The event loop's
router shares that state instead of owning a separate record.

The RDPEUSB backend now resolves a pending request directly through that shared
state, and UrbdrcDeviceServerMessage::IoComp is gone. A completion is already
fully decoded when the backend receives it, and delivering it needed nothing the
event loop owns; previously it was re-queued and could sit behind requests
waiting on a socket write. An I/O submission is also answered before its write,
so the caller owns cancel-on-drop as early as possible.

UrbdrcDeviceServer::abandon_unsent releases a request that was built but never
handed to the transport. Such a request is never answered by a completion, so
nothing else would ever release its tracking state. This is deliberately
separate from cancel_request: a cancelled request is still answered, with a
failure HRESULT per [MS-RDPEUSB] sections 3.3.5.3.1 and 3.3.5.3.6, so cancelling
must not release anything.

Two notes for review. RawPending is no longer re-exported from
ironrdp-server; it had no public constructor and no public producer, so no
downstream could obtain one, and this removes an unreachable export rather than
a usable API. Teardown now drains pending requests explicitly, because the
pending map outlives the router entry that used to own it and dropping that
entry no longer fails the waiting callers on its own.

Copilot AI balanced review requested due to automatic review settings August 26, 2026 16:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added maintainer-required Maintainer review or intervention is required risk/unknown Risk could not be determined automatically; needs maintainer-level scrutiny scope/core Touches the core architectural tier size/L Size: up to 899 counted lines and 20 files; exceeds M in either measure labels Aug 26, 2026
The lifecycle, pending-request map and USB shared state now live in a
single Arc<ServerUsbDevice> inside the handle.

Signed-off-by: uchouT <i@uchout.moe>
A transmitted request is always answered by a completion, and handling
that completion is what releases its tracking state. A request that
never reached the transport is never answered, so it needs an explicit
release. This is distinct from cancel_request, which stops a request
already in flight and must not release anything.

Signed-off-by: uchouT <i@uchout.moe>
The RDPEUSB backend now resolves a pending request directly through the
shared per-device state, so IoComp is gone from
UrbdrcDeviceServerMessage and completions no longer queue behind
requests waiting on a socket write.

Signed-off-by: uchouT <i@uchout.moe>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer-required Maintainer review or intervention is required risk/unknown Risk could not be determined automatically; needs maintainer-level scrutiny scope/core Touches the core architectural tier size/L Size: up to 899 counted lines and 20 files; exceeds M in either measure

Development

Successfully merging this pull request may close these issues.

2 participants