Skip to content

feat(session): handle slow-path graphics and pointer updates#1132

Open
Greg Lamberson (glamberson) wants to merge 2 commits intoDevolutions:masterfrom
glamberson:feat/slow-path-updates
Open

feat(session): handle slow-path graphics and pointer updates#1132
Greg Lamberson (glamberson) wants to merge 2 commits intoDevolutions:masterfrom
glamberson:feat/slow-path-updates

Conversation

@glamberson
Copy link
Contributor

@glamberson Greg Lamberson (glamberson) commented Feb 27, 2026

Summary

  • Add slow-path update parsing module (ironrdp-pdu::slow_path) that decodes the framing headers for graphics (updateType u16) and pointer (messageType u16 + pad u16) slow-path updates
  • Extract process_bitmap_update() and process_pointer_update() as public methods on fast_path::Processor, eliminating duplication between delivery paths
  • Route ShareDataPdu::Update and ShareDataPdu::Pointer through the shared bitmap/pointer pipeline instead of hitting the catch-all error in x224::Processor::process_io_channel()

Previously, any server sending slow-path graphics or pointer updates (e.g. XRDP login screen before autologon, or servers that don't negotiate fast-path output) would trigger unhandled PDU: Update PDU and kill the session. The payload structures are byte-for-byte identical between slow-path and fast-path; only the framing differs.

Unsupported slow-path types (drawing orders, palette) log warnings instead of terminating the connection.

Relates to

  • Cannot connect to XRDP #314 (Cannot connect to XRDP): slow-path updates are one of several interop gaps preventing XRDP connections. This PR addresses the session-layer update handling; other issues (TLS negotiation, bitmap row padding, DVC version) are covered by separate PRs.

Test plan

  • cargo xtask check fmt -v passes
  • cargo xtask check lints -v passes
  • cargo xtask check tests -v passes (all existing tests, no regressions)
  • Tested against XRDP 0.10.1 (Debian 13): master crashes with unhandled PDU: "Update PDU", this branch handles the slow-path Update PDU and progresses further into the session. A subsequent crash (BitmapData::decode size mismatch) is a pre-existing XRDP interop issue with compressed bitmaps, unrelated to this PR.
Copy link
Member

@CBenoit Benoît Cortier (CBenoit) left a comment

Choose a reason for hiding this comment

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

Thank you! I think the direction is good. I’ll review for deeply next week. Also waiting on the manual tests 👀

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds support for slow-path graphics and pointer updates to IronRDP, fixing connectivity issues with servers like XRDP that use slow-path output instead of fast-path. The implementation parses slow-path framing headers and routes the inner payload structures through the existing fast-path processing pipeline by extracting shared bitmap and pointer processing methods.

Changes:

  • Added ironrdp-pdu::slow_path module for parsing slow-path update framing headers
  • Extracted process_bitmap_update() and process_pointer_update() as public methods on fast_path::Processor to share processing logic between delivery paths
  • Routed ShareDataPdu::Update and ShareDataPdu::Pointer through new ProcessorOutput variants instead of hitting the catch-all error case

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
crates/ironrdp-pdu/src/basic_output/slow_path.rs New module implementing slow-path update parsing with functions to decode graphics (updateType) and pointer (messageType) framing headers
crates/ironrdp-pdu/src/basic_output/mod.rs Exports the new slow_path module
crates/ironrdp-pdu/src/lib.rs Re-exports slow_path module at crate level
crates/ironrdp-session/src/fast_path.rs Extracts bitmap and pointer processing logic into public methods shared by both fast-path and slow-path pipelines
crates/ironrdp-session/src/x224/mod.rs Adds GraphicsUpdate and PointerUpdate variants to ProcessorOutput enum and routes slow-path PDUs
crates/ironrdp-session/src/active_stage.rs Implements process_slow_path_graphics and process_slow_path_pointer helper functions that parse and route updates through the shared pipeline
Comments suppressed due to low confidence (1)

crates/ironrdp-pdu/src/basic_output/slow_path.rs:54

  • The documentation states "already consumed by read_graphics_update_type" which is correct, but could be clearer about the structure. Consider clarifying that the slow-path bitmap update contains two updateType fields: one in TS_UPDATE_HDR (consumed by read_graphics_update_type) and another in TS_UPDATE_BITMAP_DATA (consumed by BitmapUpdateData::decode). This would help readers understand the protocol structure without having to check the MS-RDPBCGR specification.
/// Decode a slow-path bitmap update. /// /// The cursor must be positioned right after the `updateType` field /// (i.e. already consumed by [`read_graphics_update_type`]). pub fn decode_slow_path_bitmap<'a>(src: &mut ReadCursor<'a>) -> DecodeResult<BitmapUpdateData<'a>> { BitmapUpdateData::decode(src) } 

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@glamberson
Copy link
Contributor Author

Thank you! I think the direction is good. I’ll review for deeply next week. Also waiting on the manual tests 👀

This is one of the identified residual issues from #314 which is resolved. I completed my testing and noted it above. Thanks.

IronRDP's session layer previously hit a catch-all error when a server sent slow-path graphics or pointer updates (ShareDataPdu::Update / ShareDataPdu::Pointer), killing the connection. This breaks interop with servers that use slow-path output, such as XRDP when fast-path negotiation doesn't happen or when the login screen is sent before autologon kicks in. The inner payload structures (BitmapUpdateData, PointerUpdateData, etc.) are byte-for-byte identical between slow-path and fast-path. The only difference is framing: slow-path wraps them in ShareDataHeader with a u16 updateType (graphics) or u16 messageType + u16 pad (pointer) prefix. This change: - Adds slow_path module to ironrdp-pdu with parsing for the slow-path framing headers (graphics updateType, pointer messageType + system pointer type dispatch) - Extracts process_bitmap_update() and process_pointer_update() as public methods on fast_path::Processor so both delivery paths share the same processing logic - Adds GraphicsUpdate/PointerUpdate variants to x224::ProcessorOutput - Routes slow-path updates through the shared bitmap/pointer pipeline in ActiveStage::process() Unsupported slow-path update types (drawing orders, palette) log warnings instead of terminating the session. Relates to Devolutions#314
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@glamberson
Copy link
Contributor Author

Greg Lamberson (glamberson) commented Mar 19, 2026

Great, I'll run my CI and this will be addressed for now. Thanks.

Replace unreachable!() with SessionError return in TryFrom for GraphicsUpdate/PointerUpdate variants. Add TODO for slow-path bulk decompression at the x224 dispatch site. Add slow-path decode tests in testsuite covering GraphicsUpdateType parsing, pointer messageType dispatch, and error cases for unknown types and short buffers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants