344 lines
10 KiB
Markdown
344 lines
10 KiB
Markdown
# RDP Service C# Target Architecture
|
|
|
|
Archived scope note: this document is retained as historical RDP runtime
|
|
research and is not the current source of truth for node-to-node transport.
|
|
Fabric transport is now QUIC-only between nodes; use
|
|
`docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md`,
|
|
`docs/architecture/FABRIC_FIRST_TRANSPORT_AND_STRESS_PLAN.md`, and
|
|
`docs/architecture/SECURE_ACCESS_FABRIC_TARGET.md` for the active transport
|
|
model.
|
|
|
|
## Status
|
|
|
|
Superseded.
|
|
|
|
The active direction is now documented in:
|
|
|
|
- `docs/architecture/RDP_SERVICE_CPP_PERFORMANCE_TARGET.md`
|
|
|
|
The C++ worker remains the primary RDP runtime. This C# document is retained only
|
|
as historical/research context and must not be used for implementation unless
|
|
explicitly re-approved.
|
|
|
|
## Problem Statement
|
|
|
|
The current RDP MVP proved the platform lifecycle, but its rendering model is not
|
|
production-grade:
|
|
|
|
- FreeRDP connects to the target RDP server.
|
|
- The worker reads the GDI framebuffer.
|
|
- The worker publishes full or cropped BGRA frames through RAP direct WSS.
|
|
- The Windows client renders those frames as a custom viewer.
|
|
|
|
This is not how high-performance RDP clients work. On a fast LAN, the network is
|
|
not the main bottleneck. The bottleneck is that the service is repeatedly copying
|
|
and publishing screen images instead of consuming the RDP graphics protocol as a
|
|
graphics protocol.
|
|
|
|
Observable symptoms:
|
|
|
|
- delayed visual feedback after input
|
|
- unreliable first-click behavior
|
|
- poor hover behavior
|
|
- high CPU/memory pressure from framebuffer copies
|
|
- unnecessary 1280x720 BGRA full-frame payloads
|
|
- fragile coupling between input, render snapshots, and UI timing
|
|
|
|
## External Reference Model
|
|
|
|
Microsoft RDP performance is based on graphics protocol features rather than
|
|
screen scraping:
|
|
|
|
- RDP Graphics Pipeline Extension (`MS-RDPEGFX`) uses a dynamic virtual channel
|
|
for graphics pipeline updates.
|
|
- RDP supports adaptive graphics, delta detection, caching, mixed-mode encoding,
|
|
RemoteFX Progressive, H.264/AVC, AVC444, and HEVC in modern environments.
|
|
- FreeRDP documentation describes the RDP GFX Pipeline (`rdpgfx`) and codecs such
|
|
as RemoteFX Progressive, H.264 AVC420/AVC444, ClearCodec, and ZGFX.
|
|
|
|
References:
|
|
|
|
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegfx/da5c75f9-cd99-450c-98c4-014a496942b0
|
|
- https://learn.microsoft.com/en-us/azure/virtual-desktop/graphics-encoding
|
|
- https://freerdp-freerdp.mintlify.app/concepts/codecs
|
|
|
|
## Target Decision
|
|
|
|
Replace the internal RDP engine with a C# implementation owned by this project.
|
|
|
|
The new service:
|
|
|
|
- is a RAP RDP service adapter, not a generic local RDP client UI
|
|
- speaks standard RDP to the target Windows RDP server
|
|
- keeps RDP protocol details inside the RDP service boundary
|
|
- preserves current backend and cluster data-plane contracts
|
|
- does not use FreeRDP as the runtime RDP engine
|
|
- does not require the local Windows desktop client to become mstsc
|
|
|
|
The local Windows client remains a RAP client. It receives RAP display/input/
|
|
clipboard/file messages over the existing direct worker WSS data-plane.
|
|
|
|
## What Must Not Change
|
|
|
|
The following are outside this rewrite:
|
|
|
|
- backend organization/auth/session lifecycle
|
|
- PostgreSQL source-of-truth model
|
|
- Redis live coordination model
|
|
- worker registration and lease semantics
|
|
- data_plane_token model
|
|
- direct_worker_wss transport contract
|
|
- backend gateway fallback
|
|
- clipboard/file policy semantics
|
|
- file upload policy semantics
|
|
- session attach/detach/reattach/takeover/terminate semantics
|
|
|
|
Only the RDP service adapter internals change.
|
|
|
|
## Service Boundary
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
Client["Windows RAP Client"]
|
|
Backend["Backend Control Plane"]
|
|
Worker["RDP Service Node"]
|
|
Engine["C# RDP Protocol Engine"]
|
|
Target["Target Windows RDP Server"]
|
|
|
|
Client <--> |"direct_worker_wss RAP channels"| Worker
|
|
Backend <--> |"assignments, leases, audit"| Worker
|
|
Worker --> Engine
|
|
Engine <--> |"standard RDP"| Target
|
|
```
|
|
|
|
The RDP service owns:
|
|
|
|
- RDP negotiation and transport
|
|
- NLA/CredSSP/TLS integration
|
|
- input translation to RDP fast-path input
|
|
- graphics channel parsing
|
|
- virtual channel handling for clipboard and future file features
|
|
- conversion from RDP graphics units to RAP render messages
|
|
- session runtime ownership and reconnect/takeover binding
|
|
|
|
The data-plane layer owns:
|
|
|
|
- data_plane_token validation
|
|
- direct WSS connection binding
|
|
- logical channel priority
|
|
- reliable/droppable semantics
|
|
- fallback compatibility
|
|
|
|
## New RDP Service Components
|
|
|
|
### `Rap.Rdp.Service`
|
|
|
|
Host process.
|
|
|
|
Responsibilities:
|
|
|
|
- load worker/RDP service configuration
|
|
- register worker capabilities with existing coordination layer later
|
|
- expose the existing direct WSS endpoint later
|
|
- create and supervise RDP sessions
|
|
- keep the current C++ worker active until cutover
|
|
|
|
### `Rap.Rdp.Core`
|
|
|
|
Pure C# protocol and runtime boundaries.
|
|
|
|
Responsibilities:
|
|
|
|
- define RDP session lifecycle interfaces
|
|
- define protocol engine interfaces
|
|
- define graphics/input/clipboard/file abstractions
|
|
- avoid any dependency on WPF or backend repositories
|
|
|
|
### `Rap.Rdp.Protocol`
|
|
|
|
Future implementation module.
|
|
|
|
Responsibilities:
|
|
|
|
- implement RDP connection sequence from Microsoft Open Specifications
|
|
- implement security/NLA/CredSSP/TLS
|
|
- implement core channels and fast-path input
|
|
- implement graphics pipeline negotiation
|
|
- implement virtual channel framing
|
|
|
|
This module must not depend on the Windows desktop UI.
|
|
|
|
### `Rap.Rdp.DataPlane`
|
|
|
|
Future adapter module.
|
|
|
|
Responsibilities:
|
|
|
|
- map RAP direct WSS JSON/binary envelopes to the protocol engine
|
|
- keep input highest priority
|
|
- keep render latest-frame or latest-update droppable
|
|
- keep clipboard/file reliable and policy-gated
|
|
|
|
## Graphics Strategy
|
|
|
|
The new render path must not use framebuffer screen scraping as the primary
|
|
production path.
|
|
|
|
Priority order:
|
|
|
|
1. RDPGFX graphics pipeline channel.
|
|
2. Surface/dirty-region updates.
|
|
3. Encoded graphics payloads where available.
|
|
4. Raw bitmap fallback only for compatibility/debug.
|
|
|
|
Target RAP render message classes:
|
|
|
|
- `surface.create`
|
|
- `surface.delete`
|
|
- `surface.map`
|
|
- `surface.region`
|
|
- `surface.codec_frame`
|
|
- `cursor.update`
|
|
- `frame.ack`
|
|
|
|
The first usable implementation may still decode some graphics to BGRA, but only
|
|
as a controlled fallback. It must not become the permanent production model.
|
|
|
|
## Input Strategy
|
|
|
|
Input must be independent from render.
|
|
|
|
Rules:
|
|
|
|
- mouse down/up, wheel, and keyboard down/up are reliable and ordered
|
|
- pointer move is coalesced latest-only
|
|
- pointer position is explicitly sent before button-down when needed
|
|
- input never waits behind render
|
|
- no UI focus event may be inserted into the same ordered sequence in a way that
|
|
consumes the first remote click
|
|
|
|
The current double-click regression is treated as a bug caused by the RAP-side
|
|
focus/input sequencing, not as a normal RDP behavior.
|
|
|
|
## Clipboard And File Strategy
|
|
|
|
Existing policy semantics remain:
|
|
|
|
- clipboard modes stay enforced in backend, gateway/data-plane, and RDP service
|
|
- file transfer modes stay enforced in backend, gateway/data-plane, and RDP service
|
|
- text clipboard maps to RDP clipboard virtual channel
|
|
- restricted drive visibility remains a separate policy-controlled feature
|
|
|
|
The C# rewrite must not expand clipboard/file scope while replacing render/input.
|
|
|
|
## Staged Migration Plan
|
|
|
|
### RDP-C#-0: Documentation And Skeleton
|
|
|
|
Create a buildable C# RDP service skeleton with interfaces only.
|
|
|
|
No runtime cutover.
|
|
|
|
### RDP-C#-1: Control-Plane Compatible Worker Shell
|
|
|
|
Implement worker registration, heartbeats, lease renewal, assignment consumption,
|
|
and direct WSS token validation in C# using existing contracts.
|
|
|
|
The C++ worker remains default.
|
|
|
|
### RDP-C#-2: RDP Handshake Probe
|
|
|
|
Implement a non-viewing RDP connection probe:
|
|
|
|
- TCP/TLS
|
|
- basic RDP negotiation
|
|
- NLA/CredSSP if required
|
|
- connect/disconnect lifecycle
|
|
- failure reporting
|
|
|
|
No rendering yet.
|
|
|
|
### RDP-C#-3: Input-Only Protocol Path
|
|
|
|
After a connected session, send fast-path keyboard/mouse input to the RDP server.
|
|
|
|
Use diagnostic-only graphics or no graphics.
|
|
|
|
### RDP-C#-4: Basic Graphics Protocol Path
|
|
|
|
Implement the simplest RDP graphics path needed to display a desktop without
|
|
FreeRDP.
|
|
|
|
Allowed as temporary fallback:
|
|
|
|
- raw bitmap updates
|
|
- dirty-region bitmap updates
|
|
|
|
Not acceptable as final production:
|
|
|
|
- repeated full-frame screenshot capture
|
|
|
|
### RDP-C#-5: RDPGFX Foundation
|
|
|
|
Implement RDPGFX channel negotiation and surface update handling.
|
|
|
|
### RDP-C#-6: Codec Path
|
|
|
|
Implement or relay supported encoded graphics modes:
|
|
|
|
- RemoteFX Progressive where practical
|
|
- H.264/AVC420/AVC444 where negotiated
|
|
- client-side decode through platform APIs where possible
|
|
|
|
### RDP-C#-7: Runtime Cutover
|
|
|
|
Enable the C# RDP service per worker/resource via feature flag.
|
|
|
|
Rollback must switch back to the current C++ worker without changing backend
|
|
contracts.
|
|
|
|
## Performance Requirements
|
|
|
|
Target for LAN:
|
|
|
|
- first frame under 2 seconds after successful RDP login
|
|
- click to visible response under 150 ms for normal UI
|
|
- keypress to visible response under 150 ms for text input
|
|
- pointer hover response under 100 ms where the target OS emits hover changes
|
|
- no unbounded frame queue
|
|
- no render work on UI thread except final apply
|
|
- no full-frame publish loop for static desktops
|
|
|
|
## Risks
|
|
|
|
- Implementing RDP from specs is substantial.
|
|
- NLA/CredSSP correctness is security-sensitive.
|
|
- Graphics codecs are complex.
|
|
- Some target servers may negotiate older bitmap paths.
|
|
- AVC/AVC444 decode support differs by client platform.
|
|
- A partial RDP engine must not be switched into production before smoke proof.
|
|
|
|
## Recommended Immediate Next Step
|
|
|
|
Proceed with RDP-C#-0 only.
|
|
|
|
Goal:
|
|
Create a buildable C# RDP service skeleton and protocol boundaries, without
|
|
switching runtime traffic away from the current worker.
|
|
|
|
Strict rules:
|
|
|
|
- do not change backend contracts
|
|
- do not change cluster transport
|
|
- do not remove C++ worker
|
|
- do not use FreeRDP in the new C# service
|
|
- do not use third-party RDP libraries
|
|
- do not claim the C# engine is runtime-ready
|
|
|
|
Deliver:
|
|
|
|
- buildable `workers/rdp-service-csharp`
|
|
- interfaces for protocol engine, data-plane bridge, graphics sink, input source
|
|
- README with migration stages
|
|
- docs update marking current C++/FreeRDP path as compat MVP runtime
|