Skip to content

chore: bump IronRDP pin 879ffed8 → a5d1c682 (−2 vendored forks, −1 divergence) - #178

Merged
clintcan merged 15 commits into
mainfrom
chore/pin-bump-a5d1c682
Aug 6, 2026
Merged

chore: bump IronRDP pin 879ffed8 → a5d1c682 (−2 vendored forks, −1 divergence)#178
clintcan merged 15 commits into
mainfrom
chore/pin-bump-a5d1c682

Conversation

@clintcan

@clintcan clintcan commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Bumps the IronRDP dependency pin 879ffed8a5d1c682 (133 commits) and shrinks vendored divergence. No user-facing behavior change — the default runtime path is functionally unchanged.

What lands

  • Pin bump to a5d1c682 across all git-pinned ironrdp crates + the two-sided [patch] wiring.
  • ironrdp-rdpeusb fork retired — its lenient USB-3 caps decode landed upstream; the USB URBDRC server (src/rdpeusb.rs) was ported to a5d1c682's split control/device PDUs (not blindly adopted — the mstsc-strict interop fixes were preserved).
  • ironrdp-async fork dropped — v0.9.4 vendored it to guard read_by_hint against the pre-auth framing DoS, but a5d1c682 already carries #1515's find_size hardening, so the pin fixes the DoS upstream.
  • Upstream API changes absorbed into src/: honor-client-desktop-size, rdpsnd format selection (#1359 — the crate now owns it, so macrdp's choose_audio_format divergence is gone), egfx frame-ack (#1345).
  • De-drift: harvested divergence docs(h264): disconnect-side capture — on_close never fires (structural) #7 (the QOI --qoi-force-rgb workaround — a5d1c682 has #1335+#1341, so qoi_encode converges to upstream's always-Rgb form). docs(h264): reconnect-blank is two stacked mstsc bugs (full xrdp mirror tried) #9 (honor-size) assessed + deferred (documented in the vendored-server divergence log).
  • Version 0.9.3 → 0.9.5.

Verification

  • Green under rustup stable 1.95: build --all-targets + 203 tests + clippy -D warnings + fmt — macrdp AND the vendored server.
  • Live-verified: FreeRDP (CredSSP/audit, rdpsnd AAC #1359, EGFX H.264 #1345), mstsc Xbox-controller USB redirect (the div-16 rdpeusb port against the strict client), the 3 in-tree abuse-fuzz harnesses (incl. the find_size DoS — clean-rejects on the bump).
  • 24h+ soak clean on the Mac mini: 0 panics, 0 restarts, RSS bounded (~50 MB), serving clients throughout.

Net: −2 vendored forks, −1 divergence, current with upstream.

clintcan added 15 commits August 5, 2026 11:32
…etire rdpeusb [WIP]

Bump all 15 git-pinned ironrdp crates 879ffed8 -> a5d1c682 (upstream master
2026-08-03) and the [dependencies] version constraints to match (ironrdp
0.14->0.17, server 0.10->0.13, acceptor 0.8->0.10, pdu 0.7->0.9, core 0.1->0.2,
rdpsnd 0.7->0.9, rdpdr 0.5->0.7, egfx 0.1->0.3, dvc 0.5->0.8, svc 0.6->0.8,
cliprdr 0.5->0.7, displaycontrol 0.5->0.8, connector/tokio 0.8->0.10).

Retire the ironrdp-rdpeusb fork: all four divergences merged upstream
(#1418/#1513/#1420/#1321), so its [patch] entry becomes a git-pin (upstream is
publish=false) and vendor/ironrdp-rdpeusb/ can be deleted.

WIP: the kept vendored forks (server/acceptor/rdpdr/dvc/rdpeudp) still declare
the old crate versions + APIs, so the tree does not resolve/build yet — the
per-fork re-vendor + src re-wire follows in subsequent commits.
…d1c682

- rdpeudp (macrdp-authored, no upstream twin): bump its ironrdp-core dep 0.1->0.2
  + its standalone [patch] rev. Builds clean, all 53 crate tests pass (the
  additive-core keystone holds).
- rdpdr: ZERO upstream source churn 879ffed..a5d1c682 (only Cargo.toml/CHANGELOG),
  so the fork source was already current; bump package version 0.5->0.7 + dep
  versions (core 0.2/error 0.2/pdu 0.9/svc 0.8) + rust-version 1.94. Added a
  standalone [patch] for isolated validation. Builds clean.
- dvc: real re-vendor (upstream churned lib/client/server). Refreshed those three
  files verbatim from a5d1c682, kept pdu.rs/complete_data.rs (upstream-unchanged,
  carry div1). Re-applied div1 (Soft-Sync: SoftSyncResponse arm + get_channel_id_by_name
  in server.rs against the new DynamicChannelAllocator, SoftSyncRequest arm in
  client.rs). RETIRED div2 (the processor.close hook) — upstream #1302 now owns it
  via Drop + remove_by_channel_id. Bump version 0.5->0.8 + deps, drop unused slab,
  add standalone [patch]. Builds clean.

Each validated by a standalone 'cargo build' against the a5d1c682 git deps.
Remaining: acceptor (M3c re-apply) + server (the bulk) + src/ + workspace build.
Refresh connection.rs verbatim from a5d1c682 and re-apply only the surviving
divergences (Approach B — the authoritative upstream base + macrdp-only additions),
because upstream absorbed far more than the dry-run mapped:

RETIRED (now upstream in a5d1c682, NOT re-applied):
- div(1) honor-size incl. the #1404 operator max -> unified
  honor_client_desktop_size: Option<DesktopSize> (#1373+#1404)
- div(2) keyboard_layout (#1397)
- div(3) read-side multitransport_flags (#1453)
- the MCS message-channel allocation + SC_MCS_MSGCHANNEL grant + join
- advertise_extended_client_data (upstream now always advertises EXTENDED_CLIENT_DATA)

KEPT (macrdp-only, re-applied as pure additions):
- div(3) M3c OFFER half: multitransport_offer/offered + setter, MultitransportOffer
  type + lib.rs re-export, SC_MULTITRANSPORT advertise in create_gcc_blocks (re-gated
  on multitransport_offer.is_some()), the Server-Initiate-Multitransport emit in
  LicensingExchange reconciled onto upstream's message_channel_id + multitransport_flags,
  and the CapabilitiesWaitConfirm channel-skip
- div(4) client fingerprint fields (name/version/build)

QA: connection.rs vs a5d1c682 = 142 pure additions + 2 intended modifications
(let mut written; multi_transport_channel populate); lib.rs = only the re-export;
finalization.rs = only the channel-skip (26/0); channel_connection/credssp/util
byte-identical. Standalone cargo build + clippy clean, my additions fmt-clean.

Downstream TODO for the server fork + main.rs: adopt the
set_honor_client_desktop_size(Option<DesktopSize>) signature (bool -> Option).
…mp [WIP]

Bump the vendored server Cargo.toml to a5d1c682: version 0.10->0.13, rust 1.94,
all ironrdp deps to their a5d1c682 versions (async 0.10, ainput 0.8, core 0.2,
pdu 0.9, svc 0.8, cliprdr 0.7, displaycontrol 0.8, echo 0.4, dvc 0.8, tokio 0.10,
acceptor 0.10, graphics 0.9, rdpsnd 0.9, rdpdr 0.7, egfx 0.3). Add the nscodec
feature + ironrdp-nscodec dep (div-6 retires into upstream #1332's crate). Add a
standalone [patch] (vendored siblings by path + the rest git-pinned + two-sided
dvc) so the server crate builds in isolation for incremental validation — like the
other five forks. Untrack the pre-existing vendor/ironrdp-server/Cargo.lock (now
covered by vendor/*/Cargo.lock).

STANDALONE BUILD ESTABLISHED: resolution + all deps compile; the (unchanged) server
source produces a bounded 33-error surface (egfx,nscodec; no multitransport yet) —
the reconciliation is an API-break fix-up, NOT a refactor: rdpeusb.rs (26, the
evolved ironrdp-rdpeusb PDU API) + server.rs (7, the honor-size/autodetect/egfx
external touch points). macrdp's own server.rs (auth/preemption logic) is kept.
Source reconciliation is the next step, now with an incremental safety net.
…liprdr) [WIP]

- honor-size: reconcile macrdp's (bool, Option<max>) onto the acceptor's unified
  set_honor_client_desktop_size(Option<DesktopSize>) (Some(max)=honor+clamp, None=off).
- autodetect: a5d1c682 moved it out of ShareDataPdu into rdp::autodetect on the MCS
  message channel. macrdp doesn't use RDP network-autodetect (div-15 kernel RTT), so
  adapt the (dead) request arm to AutoDetectReqPdu + drop the response arm.
- cliprdr: cover the new ClipboardMessage::SendInitiateFileCopy variant (same
  initiate_file_copy call; macrdp drives copy via its own ServerEvent::ClipboardFileCopy).

server.rs down 7->1 error (egfx,nscodec build); the remaining one is the
egfx_on_udp_handle multitransport-cfg artifact (resolves under the real config).
rdpeusb.rs (26, the evolved ironrdp-rdpeusb PDU API) is next.
…Us [WIP]

Adopt-vs-port decision: PORT now, ADOPT (retire the fork) later. rdpeusb.rs is the
most interop-fragile file in the tree (dozens of live-debugged FreeRDP-lenient/
mstsc-strict fixes) and USB can't be live-re-verified without an entitled build +
hardware, so a mechanical port preserving every fix byte-for-byte beats swapping in
uchouT's #1417 server unverified. a5d1c682 keeps the low-level wire types public +
DvcEncode; only the reshaping changed:

- UrbdrcServerPdu -> UrbdrcServer{Control,Device}Pdu (channel split); ditto the client
  enums. Device process() decodes DevicePdu first, falls back to ControlPdu for the
  CAPABILITIES-interface caps response (the per-device handshake mstsc REQUIRES).
- Flat TsUrb enum -> two-level TsUrbIn/TsUrbOut { header, kind: TsUrb{In,Out}Kind };
  the TS_URB header is hoisted out of each payload struct.
- UrbFunction variants -> URB_FUNCTION_* newtype consts.
- Hand-built RIMCALL_RELEASE SharedMsgHeader -> first-class InterfaceRelease PDU.
- UsbDvcPdu/UsbHeaderMsg -> one generic UsbDvc<T: Encode> (wire types are DvcEncode).
- setup_to_typed_urb returns (UrbFunction, TsUrbInKind); TsUrbOutKind lacking CtlFeatReq
  now type-enforces the force_transfer_in rule.

Every interop fix (typed control URBs, alt-0 config filter, SHORT_TRANSFER_OK,
decode-tolerance, per-device caps handshake, closed()-race) preserved byte-identical.
Standalone vendored server builds clean (default + egfx,nscodec); rdpeusb
rustfmt/clippy clean. Live USB re-verification deferred to hardware.

Also gate the egfx_on_udp_handle field init with #[cfg(feature = "multitransport")]
to match its gated declaration (a default/egfx build previously failed E0560).
… (div-12) [WIP]

The re-vendored acceptor advertises EXTENDED_CLIENT_DATA unconditionally (upstream
a5d1c682 always sets ResponseFlags::EXTENDED_CLIENT_DATA_SUPPORTED), so the M3c
multitransport offer path no longer needs the set_advertise_extended_client_data(true)
call — it was retired from the re-vendored acceptor. The offer alone drives the
multitransport negotiation now.

Completes the vendored ironrdp-server compilation: builds clean across the full feature
matrix (default, egfx, nscodec, multitransport, helper), 0 errors. gfx/handler/sound/
builder API breaks the pin bump anticipated did not materialize (already covered by the
earlier server.rs commits).
…1345 egfx) [WIP]

- audio.rs: adopt the #1359 RdpsndServerHandler rewrite. The crate now owns format
  selection (new choose_format) AND the client-list wFormatNo arithmetic, so macrdp's
  local choose_audio_format is DELETED — a hard-won divergence (the "wFormatNo indexes
  the CLIENT's list" fix) absorbed upstream. choose_format returns common.first() (the
  crate orders common by our server preference, AAC-ahead-of-PCM); start now takes the
  NegotiatedFormat and returns Result, reading use_aac from format.format(). Replaced the
  3 wFormatNo unit tests with one guarding the macrdp-side AAC-ordering invariant that
  choose_format = common.first() relies on.
- h264.rs: on_frame_ack gained a 4th param (total_frames_decoded, #1345); accepted but
  unused — macrdp derives its decode-backlog floor from frame_id.
- conn_test.rs: mirror the RdpsndServerHandler change in the NoAudio test double, and add
  the new ironrdp_connector::Config.connection_type field (Lan, the canonical default
  used by the client config / testsuite / web).

Full workspace builds clean (egfx + multitransport); cargo test 203 passed / 0 failed /
3 ignored. macrdp src/ clippy + fmt clean. nscodec confirmed still unconditional (in-tree
encoder, no feature gate) — no regression. Live A/V re-verification deferred to the soak.
The fork's four divergences all merged upstream (div1 #1418 SupportedUsbVer newtype,
div2 #1513 usb_device match, div3 #1420 UsbConfigDesc.trailing, div4 #1321 completion
guards) and src/rdpeusb.rs is now ported to a5d1c682's split URBDRC PDUs, so
ironrdp-rdpeusb resolves purely via a git-rev [patch.crates-io] — the vendored copy was
unreferenced. Delete it (18 files) + refresh the now-stale "VENDORED" / "can be deleted"
comments. Workspace builds clean; 203 tests pass. First whole vendored fork fully retired
by the bump.
…ean the vendored server [WIP]

Two finalization steps on the vendored ironrdp-server fork:

FMT — the verbatim-from-a5d1c682 files carry IronRDP's style (max_width=120); macrdp's
DIVERGENCE files had drifted narrower (and my rdpeusb.rs port was default-100-fmt'd), so a
plain `cargo fmt` would have churned the whole crate off upstream style. Add
vendor/ironrdp-server/rustfmt.toml (max_width=120 + reorder_imports — the stable-safe
subset of IronRDP's repo config; imports_granularity/group_imports are nightly-only) and
format the divergence files to match, using STABLE rustfmt so the result is reproducible
with the default toolchain. No verbatim upstream file is touched.

CLIPPY — the crate had 25 pre-existing warnings, ALL in macrdp's divergence files (none in
the rdpeusb.rs port). `cargo clippy --fix` applied 18 machine-safe simplifications
(collapsible_if x17 + a redundant async-closure call); the remaining 7 are intentional
patterns given targeted #[allow] with reasons (large_enum_variant on two transient
select-race enums, too_many_arguments on RdpServer::new, new_ret_no_self on a DVC-message
constructor) plus one real manual_clamp fix and a doc_lazy_continuation blank-line fix.

macrdp is a single package, so `cargo fmt --all` / clippy from the repo root do NOT reach
this vendored crate — check it via --manifest-path. Crate is now fmt-clean (stable) +
clippy-clean; full workspace builds; 203 tests pass.
…0.9.5

main advanced to v0.9.4 (the pre-auth framing DoS hotfix) while this branch was
in flight. Reconcile:
- keep the branch's a5d1c682 pins (Cargo.toml/Cargo.lock)
- DROP vendor/ironrdp-async: v0.9.4 vendored it to guard read_by_hint, but
  a5d1c682 already carries upstream #1515 (find_size hardening), so the pin now
  fixes the DoS upstream — the vendor dir is redundant
- version 0.9.3 -> 0.9.5 (past the published 0.9.4)
- docs (CLAUDE/README/release-history) merged cleanly from v0.9.4

macrdp fully green after the merge: build --all-targets, 203 tests, clippy, fmt
(+ vendored server build/fmt). A pre-existing vendored-server clippy
let_unit_value drift (newer clippy 1.97, unrelated to this merge) is fixed next.
…erver)

clippy 1.97's let_unit_value now flags `let gfx_handle = attach_channels_impl(..)`
and the `let _ = gfx_handle;` consumers when the egfx feature is off (the fn
returns () there). Pre-existing under the newer toolchain, NOT from the v0.9.4
merge (the lines are unchanged since 2918040). Targeted #[allow]+reason at the
four sites (server.rs 963/1385/1408/1449), matching the existing divergence
clippy pattern — no logic change (security-critical divergence-23 preemption
code). Vendored server clippy + fmt clean; macrdp unaffected (builds with egfx,
so the allows are inert there).
…5+#1341

a5d1c682 has the real QOI fix (server-side always-Rgb #1335 + client-side Rgba
decode #1341), so macrdp's --qoi-force-rgb workaround is redundant. Converge
qoi_encode to upstream's exact always-*x form; delete the QOI_FORCE_RGB static +
set_qoi_force_rgb setter + lib.rs re-export (vendored server), and the
--qoi-force-rgb CLI flag + wiring + configuration.md entry (macrdp). Always-Rgb
is now the behavior, matching upstream. Divergence log (7) marked harvested.

QA green: build --all-targets, 203 tests, clippy -D warnings, fmt — macrdp AND
the vendored server (default features incl. qoi).
@clintcan
clintcan merged commit 4fa7c8f into main Aug 6, 2026
4 checks passed
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