# rustdesk/rustdesk — codebase unpack

> Canonical page: https://codevetter.com/unpack/rustdesk

This is a deterministic Repo Unpack scan of rustdesk/rustdesk — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: c6a358afbe37c518689a6157a8e8cdbd645dcc5d (2026-09-22)
- Last upstream commit: Update lang.rs - Splits ambiguous pt into pt-pt and pt-br (#16155)
- Generated by codevetter 1.12.0 on 2026-09-22
- 856 files scanned · 12.2 MB

## Languages

- Rust: 287 files
- Markdown: 81 files
- C: 22 files
- C++: 20 files
- YAML: 20 files
- Shell: 18 files
- Python: 15 files
- Kotlin: 13 files

## Repository structure

- flutter/ — 262 files
- src/ — 202 files
- libs/ — 154 files
- res/ — 123 files
- docs/ — 63 files
- .github/ — 18 files
- fastlane/ — 14 files
- flatpak/ — 2 files

Probable source entrypoint: `Cargo.toml` (inferred from the tree, not upstream docs)

## Package

- Cargo.toml: RustDesk v1.5.0 — 80 declared dependencies

## Structural health signals

Average score 6/10 across 96 files; 51 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- c6a358afbe37 (2026-09-22) Update lang.rs - Splits ambiguous pt into pt-pt and pt-br (#16155)
- 458ffe44c610 (2026-09-22) Update Ukrainian README (#16309)
- 2e7255f08333 (2026-09-22) fix: suppress heartbeat HTTP retry and TCP proxy logs (#16273)
- 12f61b1fda04 (2026-09-22) Fix/drm rotated cursor (#16242)
- 6a0eb9a1fda5 (2026-09-22) fix(terminal): preserve trackpad scrolling in alternate screen

## Overview

RustDesk is an open-source remote desktop client (v1.5.0) written in Rust with a Flutter UI, covering Windows, macOS, Linux, Android, and iOS. A single binary multiplexes roles via CLI flags: `--server` runs the controlled-side host (screen capture, input injection, clipboard, audio, file transfer), `--cm` runs the connection-manager approval UI, and bare launch runs the Flutter main window; outgoing connections punch via UDP/TCP/WebRTC through a rendezvous server (hbbs) with relay (hbbr) fallback. The wire protocol is protobuf over `hbb_common`'s `Stream`, secured by NaCl sign/box_ key exchange, and the shared protocol crate `libs/hbb_common` is a git submodule also used by the server project.

## System map

One Cargo package (`rustdesk`, lib name `librustdesk`, crate-type cdylib+staticlib+rlib) produces the main `rustdesk` binary plus helper bins `service` (macOS) and `naming`, while `libs/portable` builds a self-extracting portable packer. `src/` holds the cross-platform core; `src/platform/` and `src/server/` hold OS- and host-side code; `flutter/` is the current UI (legacy Sciter UI in `src/ui/` is deprecated); `libs/` is a Cargo workspace of vendored crates. `libs/hbb_common` is a git submodule shared with rustdesk-server — it is empty in this clone. CI is GitHub Actions driven by `flutter-build.yml` (reusable) and `flutter-ci.yml` (PR gate).
- The crate builds as `librustdesk` with crate-type [cdylib, staticlib, rlib] so the same code backs the desktop binary, the Flutter dynamic library, and mobile FFI; `default-run = "rustdesk"` and extra bins `naming` (src/naming.rs) and `service` (src/service.rs) are declared. — [Cargo.toml#L11-21](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L11-L21) [src/service.rs#L1-19](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/service.rs#L1-L19)
- The default `main()` in src/main.rs is a thin shell: it calls `core_main::core_main()` and, if it returns Some(args), starts the UI via `ui::start(args)`; under feature `flutter` or mobile targets, `main` only runs `common::global_init()` + rendezvous/NAT diagnostics because the real app entry is the Flutter engine loading the library. — [src/main.rs#L8-33](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/main.rs#L8-L33) [src/core_main.rs#L26-32](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L26-L32)
- core_main() is the CLI dispatcher: flags like `--server`, `--tray`, `--cm`, `--service`, `--install`, `--password`, `--get-id`, `--option`, `--assign`, `--deploy`, `--connect`/`--file-transfer`/`--terminal`/`--rdp` are parsed positionally from std::env::args and each maps to a subsystem call. — [src/core_main.rs#L51-82](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L51-L82) [src/core_main.rs#L373-730](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L373-L730)
- Workspace members are libs/scrap (screen capture), libs/hbb_common (protocol/Config submodule), libs/base (client-only protos+fs+keys), libs/enigo (input injection), libs/clipboard, libs/virtual_display(+dylib), libs/portable, libs/remote_printer; `vdi/host` is excluded. — [Cargo.toml#L213-215](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L213-L215) [libs/base/src/lib.rs#L1-7](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/libs/base/src/lib.rs#L1-L7)
- crates-io is patched: `libxdo-sys` is replaced by libs/libxdo-sys-stub (so builds work without libxdo on Wayland-only systems), and `tungstenite`, `webrtc`, `webrtc-util`, `webrtc-sctp` are pinned by git rev to rustdesk-org forks carrying custom fixes (incremental ws read buffer, Windows IPv6 ICE, SCTP congestion-control off by default). — [Cargo.toml#L219-253](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L219-L253)
- Feature flags gate major subsystems: `flutter` (flutter_rust_bridge =1.80), `hwcodec`/`vram`/`mediacodec` (hardware codecs via scrap), `drm` and separately `drm-wake` (Linux DRM/KMS capture plus an opt-in synthetic pointer wake), `unix-file-copy-paste`, `inline` (legacy Sciter in-process UI), and resampler backends `use_dasp`(default)/`use_rubato`/`use_samplerate`. — [Cargo.toml#L23-48](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L23-L48)
- Server-side runtime is `Server` in src/server.rs: a `ServerPtr = Arc<RwLock<Server>>` holding `connections: HashMap<i32, ConnInner>` and `services: HashMap<String, Box<dyn Service>>`; `new()` registers audio, display, clipboard, input (cursor/pos/window-focus), and (Windows+flutter) printer services. — [src/server.rs#L112-178](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L112-L178)
- IPC between the privileged `--server` process, the user UI process, and the `--cm` connection manager uses parity_tokio_ipc (Unix sockets / Windows named pipes) framed by BytesCodec and serde-tagged JSON `enum Data` (Login, Authorize, Close, SyncConfig, FS, ClipboardFile, SwitchSides*, UrlLink, DataPortableService, ...). — [src/ipc.rs#L79-81](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L79-L81) [src/ipc.rs#L321-438](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L321-L438) [src/ipc.rs#L668-681](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L668-L681)
- The Flutter UI lives in flutter/ (package flutter_hbb 1.5.0+68): lib/main.dart dispatches on boot args — `multi_window <id> <json>` for remote/file-transfer/camera/port-forward/terminal windows, `--cm` for the connection manager, `--install` for the install page, default for the main window; state uses provider/getX and FFI goes through flutter_rust_bridge 1.80. — [flutter/lib/main.dart#L38-118](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/lib/main.dart#L38-L118) [flutter/pubspec.yaml#L1-60](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/pubspec.yaml#L1-L60) [Cargo.toml#L77](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L77)
- Rust↔Flutter bridge: src/flutter_ffi.rs exposes hundreds of `pub fn` (session_add_sync, session_start, peer_get_sessions_count, start_global_event_stream...) generated into `src/bridge_generated.rs` (mod declared in lib.rs), while Rust pushes events back over `StreamSink` global event streams keyed by app type (`main`, `cm`). — [src/flutter_ffi.rs#L87-100](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter_ffi.rs#L87-L100) [src/lib.rs#L34-39](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/lib.rs#L34-L39) [src/flutter.rs#L34-38](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter.rs#L34-L38)
- Build tooling: `build.py` drives cargo build + flutter build + packaging per-OS; `build.rs` (cc, hbb_common, os-version) compiles platform C/C++; `vcpkg.json` + vcpkg install libvpx/libyuv/opus/aom for native codec deps; the Dockerfile builds a Debian trixie image with vcpkg, cmake 3.30.6, gtk/xcb/pulse dev packages for Linux builds. — [build.py#L1-60](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/build.py#L1-L60) [build.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/build.rs) [vcpkg.json](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/vcpkg.json) [Dockerfile#L1-42](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Dockerfile#L1-L42)
- Release profile sets lto, codegen-units=1, panic='abort', strip — and panic=abort means any panic in the Rust core kills the whole process including the Flutter UI. — [Cargo.toml#L282-288](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L282-L288)
- CI: .github/workflows/flutter-ci.yml is the PR/push gate that simply calls the reusable flutter-build.yml with upload-artifact=false; flutter-build.yml pins RUST_VERSION 1.75 (1.81 macOS), FLUTTER_VERSION 3.24.5 (3.44.9 for Windows arm64), NDK r28c, and a fixed VCPKG_COMMIT_ID. — [.github/workflows/flutter-ci.yml#L1-21](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/.github/workflows/flutter-ci.yml#L1-L21) [.github/workflows/flutter-build.yml#L15-45](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/.github/workflows/flutter-build.yml#L15-L45)

## Feature catalog

User-facing features map to ConnType variants (default remote desktop, file transfer, view camera, port forward/RDP, terminal) chosen per session, plus host-side services (video, audio, clipboard, input, printer, terminal). Administrative surface is a large CLI (install/service/config/password/deploy) plus TCP/IPC control channels. Monetized/enterprise features hang off the optional api-server (hbbs_http: account, strategy sync, address book, audit upload) and the `--deploy`/`--assign` device-registration commands.
- Outgoing session types are selected in `session_add` by booleans → ConnType: FILE_TRANSFER, VIEW_CAMERA, TERMINAL, PORT_FORWARD, RDP, or DEFAULT_CONN; Flutter passes them from `flutter/lib/main.dart`'s WindowType dispatch (RemoteDesktop, FileTransfer, ViewCamera, PortForward, Terminal). — [src/flutter.rs#L1265-1344](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter.rs#L1265-L1344) [flutter/lib/main.dart#L64-101](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/lib/main.dart#L64-L101)
- Remote desktop video: `src/server/video_service.rs` captures via `scrap::Capturer` per display (VideoSource::Monitor) or camera, encodes VP8/VP9/AV1 (`VpxEncoderConfig`, `AomEncoderConfig`) or hardware encoders behind `hwcodec`/`vram` features, with `VideoQoS` adaptation and DXGI recovery logic on Windows. — [src/server/video_service.rs#L41-80](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/video_service.rs#L41-L80) [src/server.rs#L397-425](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L397-L425)
- File transfer runs through `base::fs` TransferJob machinery and `ipc::FS` messages (ReadDir/RemoveDir/NewWrite/WriteBlock/CheckDigest/Rename...); `Remote` in io_loop owns `read_jobs`/`write_jobs`/`remove_jobs` lists and `FileManager` is exposed via `file_trait`. — [src/ipc.rs#L140-238](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L140-L238) [src/client/io_loop.rs#L74-99](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client/io_loop.rs#L74-L99) [libs/base/src/fs.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/libs/base/src/fs.rs)
- Clipboard sync uses arboard + clipboard-master with a custom `dyn.com.rustdesk.owner` marker format, `CLIPBOARD_INTERVAL` 333ms polling, multi-clipboard support, and optional `unix-file-copy-paste` feature for file paste; a second `file-clipboard` service is registered when the feature is on. — [src/clipboard.rs#L10-31](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/clipboard.rs#L10-L31) [src/server.rs#L140-146](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L140-L146)
- Remote input: `libs/enigo` Enigo (keyboard/mouse injection) on the controlled side plus `input_service` services (cursor, pos, window_focus); relative-mouse MOUSE_TYPE_MOVE_RELATIVE=5 is supported by the Flutter client only; Linux Wayland input goes through uinput (`input_service::setup_uinput`, `server/uinput.rs`). — [src/common.rs#L67-92](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/common.rs#L67-L92) [src/server.rs#L148-160](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L148-L160) [src/server.rs#L678-681](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L678-L681)
- Remote terminal: `terminal_service` (desktop) with ConPTY via portable-pty on Windows and a separate `--terminal-helper` process (`server/terminal_helper::run_terminal_helper`) because ConPTY is incompatible with CreateProcessAsUserW; Flutter has a full terminal model layer (terminal_model, mouse handler, alt-screen scroll). — [src/core_main.rs#L702-712](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L702-L712) [Cargo.toml#L107](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L107) [flutter/lib/models/terminal_model.dart](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/lib/models/terminal_model.dart)
- TCP port forwarding and RDP tunneling: `src/port_forward.rs` + `port_forward_mux.rs` (Tunnel/Claim/CHANNEL_WINDOW) forward local ports through the encrypted session; `run_rdp` shells out to cmdkey/mstsc on Windows reading creds from rdp_username/rdp_password env vars. — [src/port_forward.rs#L1-30](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/port_forward.rs#L1-L30)
- Wake-on-LAN and LAN discovery: `wol-rs` dependency plus `lan::start_listening()` answering `PeerDiscovery` ping/pong UDP broadcasts gated by `enable-lan-discovery` option, reporting id/hostname/username/mac. — [src/lan.rs#L23-60](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/lan.rs#L23-L60) [Cargo.toml#L76](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L76)
- Auth features: permanent/temporary passwords, approve modes, ID whitelist (`OPTION_ID_WHITELIST`), IP whitelist (`whitelist`), 2FA TOTP via totp-rs stored encrypted in config (`auth_2fa::generate2fa`/`verify2fa`), trusted devices, and optional server-side strategies synced from the API. — [src/auth_2fa.rs#L76-100](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/auth_2fa.rs#L76-L100) [libs/base/src/config/keys.rs#L58-90](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/libs/base/src/config/keys.rs#L58-L90) [src/server/connection.rs#L78-81](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L78-L81)
- Privacy mode on Windows/macOS blanks/locks the physical display during a session via pluggable impls under src/privacy_mode/ (win_mag, win_exclude_from_capture, win_virtual_display, win_topmost_window, macos); a separate whiteboard overlay feature lives in src/whiteboard/ (client/server/per-OS backends) launched via the `--whiteboard` CLI flag. — [src/privacy_mode.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/privacy_mode.rs) [src/privacy_mode/win_mag.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/privacy_mode/win_mag.rs) [src/server/video_service.rs#L26-32](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/video_service.rs#L26-L32) [src/whiteboard/mod.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/whiteboard/mod.rs) [src/core_main.rs#L717-722](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L717-L722)
- Virtual display (Windows): `virtual_display_manager` drives either the RustDesk IDD driver (`rustdesk_idd`) or amyuni (`amyuni_idd`), selected by IDD_IMPL const; CLI `--install-idd`/`--uninstall-amyuni-idd` manage the driver. — [src/virtual_display_manager.rs#L6-34](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/virtual_display_manager.rs#L6-L34) [src/core_main.rs#L292-312](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L292-L312)
- Remote printing (Windows, flutter builds): `remote_printer` crate installs/updates a printer (`--install-remote-printer` CLI) and `printer_service` streams jobs; gated on Win10+. — [src/core_main.rs#L313-334](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L313-L334) [src/server.rs#L162-175](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L162-L175)
- Self-update: `updater.rs` runs an auto-update thread (first check after 30s, then daily, 30-min retry, skipped while sessions are active via `has_no_active_conns`); platform update paths include Windows `update_me`, macOS `update_from_dmg` with a root-owned flock at /var/run/rustdesk-update.lock. — [src/updater.rs#L27-116](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/updater.rs#L27-L116) [src/rendezvous_mediator.rs#L282-285](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/rendezvous_mediator.rs#L282-L285)
- Address book / account / audit: `hbbs_http` module talks to the self-hosted API server — `account.rs` (login/OIDC), `sync.rs` (heartbeat every 15s, sysinfo upload, strategy options), `record_upload.rs` (session recording upload), `downloader.rs`; Flutter models (ab_model, user_model, group_model) consume it. — [src/hbbs_http/sync.rs#L18-44](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/hbbs_http/sync.rs#L18-L44) [src/hbbs_http/account.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/hbbs_http/account.rs) [flutter/lib/models/ab_model.dart](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/lib/models/ab_model.dart)
- CLI admin surface includes `--password`, `--set-unlock-pin`, `--get-id`/`--set-id`, `--option` get/set, `--config` (decode server config from renamed exe string), `--import-config`, `--assign` (POST /api/devices/cli with Bearer token), `--deploy` (device deployment with distinct exit codes 1/3/5/6), `--check-hwcodec-config`, `--version`/`--build-date`. — [src/core_main.rs#L423-712](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L423-L712)

## Data flow

All remote traffic is protobuf `Message`/`RendezvousMessage` frames over a `Stream` abstraction (TCP, KCP/UDP, WebSocket, WebRTC datachannel) provided by hbb_common. Controlled side: rendezvous registration over UDP to hbbs, then per-connection streams multiplexed to named services via `ConnInner` send channels. Controlling side: Session/LoginConfigHandler state owned per session, decoded frames pushed to Flutter via StreamSink events or texture handles. Config is TOML files (Config/Config2/LocalConfig/PeerConfig) synchronized between the root service process and user process over IPC.
- Identity/registration flow: `RendezvousMediator::start_udp` opens UDP to the rendezvous server (RENDEZVOUS_PORT) and loops sending `register_peer` on a timer; `handle_resp` processes RegisterPeerResponse→register_pk, RegisterPkResponse (OK→key_confirmed, UUID_MISMATCH→handle_uuid_mismatch, NOT_DEPLOYED→NEEDS_DEPLOY+DEPLOY_RETRY_INTERVAL backoff), plus latency EMA updates into Config. — [src/rendezvous_mediator.rs#L367-485](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/rendezvous_mediator.rs#L367-L485) [src/rendezvous_mediator.rs#L487-534](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/rendezvous_mediator.rs#L487-L534)
- Inbound path: hbbs delivers PunchHole/relay requests → `accept_connection`/`create_relay_connection` → `create_tcp_connection` → `admit_unauthorized` (bounds unauthenticated conns) → `identity_handshake` (NaCl sign of IdPk + box_ key exchange; on WebRTC the DTLS fingerprint is signed into the identity) → `Connection::start`. — [src/server.rs#L211-326](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L211-L326) [src/server/connection.rs#L524-561](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L524-L561)
- Outbound path: `Remote::io_loop` → `Client::start` → `_start` sets up parallel transports — direct IP/domain shortcut, UDP punch socket + NAT test, IPv6 socket, optional WebRTC offerer — then `_start_inner` runs the rendezvous dance and a second offer-less request races a pure TCP punch fallback (`select_ok`/race_transports_prefer_webrtc). — [src/client/io_loop.rs#L151-220](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client/io_loop.rs#L151-L220) [src/client.rs#L409-580](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client.rs#L409-L580)
- Session crypto: `secure_connection` verifies the peer's signed IdPk against the rendezvous-server public key (custom `key` option or built-in RS_PUB_KEY), on WebRTC additionally binds the signed DTLS fingerprint to fail closed against SDP-swap MITM, then installs a symmetric key via PublicKey message + `conn.set_key`. — [src/client.rs#L1645-1758](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client.rs#L1645-L1758) [src/server.rs#L262-326](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L262-L326)
- After login the controlled `Connection` runs a `tokio::select!` loop over: peer messages (on_message), CM IPC channel (`rx_from_cm`: Authorize→send_logon_response_and_keep_alive, Close, CmWindowClosed...), authed IPC channel, video/main send queues (tx, tx_video), hbbs broadcast receiver, and timers (test_delay, file_timer, per-second). — [src/server/connection.rs#L734-779](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L734-L779) [src/server/connection.rs#L548-560](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L548-L560)
- Video frames flow display→`scrap::Capturer`→encoder→`Message`→`ServiceTmpl::send_video_frame_shared` to each subscribed `ConnInner`, whose `tx_video` queue is drained by the connection's send task; incoming `ConnInner::send` pushes `(Instant, Arc<Message>)` onto unbounded mpsc channels. — [src/server/service.rs#L231-243](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/service.rs#L231-L243) [src/server/connection.rs#L76](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L76) [src/server/connection.rs#L552-553](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L552-L553)
- UI data path on the controller: decoded frames/options go to `Session<T: InvokeUiSession>` which calls handler methods (FlutterHandler) that push JSON `{"name": event, ...}` onto per-app-type `GLOBAL_EVENT_STREAM` StreamSinks, or RGBA/texture via `EventToUI::Rgba/Texture`. — [src/flutter_ffi.rs#L96-100](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter_ffi.rs#L96-L100) [src/flutter.rs#L1550-1569](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter.rs#L1550-L1569) [src/ui_session_interface.rs#L57-75](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ui_session_interface.rs#L57-L75)
- Config persistence: `Config`/`Config2`/`LocalConfig`/`PeerConfig` (hbb_common TOML stores) are read/written through `ui_interface`/`ipc`; on Linux/macOS `sync_and_watch_config_dir` keeps the root service and user `--server` process configs in sync over IPC `Data::SyncConfig` every 0.3s, and `import_config` merges TOML by mtime. — [src/server.rs#L767-899](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L767-L899) [src/ipc.rs#L370](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L370) [src/core_main.rs#L739-763](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L739-L763)
- HTTP control plane: `hbbs_http::sync` posts heartbeat + sysinfo to `api-server` URL every 3s tick (15s heartbeat), downloads `StrategyOptions` (config_options + extra maps) that are applied into Config — meaning the server can remotely set any option key listed in libs/base/src/config/keys.rs. (inferred) — [src/hbbs_http/sync.rs#L18-50](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/hbbs_http/sync.rs#L18-L50) [libs/base/src/config/keys.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/libs/base/src/config/keys.rs)
- LAN discovery is a separate UDP broadcast channel on get_broadcast_port(): `PeerDiscovery` protobuf ping→pong carrying id/mac/hostname/username, independent of the rendezvous path. — [src/lan.rs#L23-60](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/lan.rs#L23-L60)
- Custom-client provisioning is embedded, not configured at runtime: `custom_server::get_custom_server_from_string` parses `host=,key=,api=,relay=` from the exe filename or a reversed base64/signed blob; `load_custom_client` runs at startup in core_main/flutter initialize. — [src/custom_server.rs#L21-80](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/custom_server.rs#L21-L80) [src/flutter_ffi.rs#L48-53](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter_ffi.rs#L48-L53)
- File-transfer data moves as `ipc::FS`/`FileAction` protobuf messages + raw bytes; `TransferJob` objects in libs/base/src/fs.rs own per-job state (read_jobs/write_jobs in both Remote and Connection), with digest checks (`CheckDigest`) for resume/overwrite detection. — [src/ipc.rs#L140-238](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L140-L238) [src/client/io_loop.rs#L82-84](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client/io_loop.rs#L82-L84) [libs/base/src/fs.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/libs/base/src/fs.rs)

## Behavior traces

Three flows verified end-to-end: (1) cold start → host registration, (2) outgoing remote-desktop session, (3) incoming controlled connection. A fourth — config sync between the privileged service and user process — is the persistence backbone. Function names below are the real call chain.
- STARTUP (desktop, no args): main() → core_main() → common::global_init() → load_custom_client() → windows bootstrap → arg scan → hbb_common::init_log → std::thread::spawn(crate::start_server) → returns Some(flutter_args) → ui::start (sciter) or Flutter engine main(). — [src/main.rs#L24-33](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/main.rs#L24-L33) [src/core_main.rs#L32-205](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L32-L205) [flutter/lib/main.dart#L38-118](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/lib/main.dart#L38-L118)
- STARTUP (host): start_server(is_server=true) → ipc::start("") listener thread → drm_capturer::warm_availability (linux+drm) → input_service::fix_key_down_timeout_loop / setup_uinput → wait_initial_config_sync → RendezvousMediator::start_all(). — [src/server.rs#L631-724](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L631-L724)
- STARTUP (registration): RendezvousMediator::start_all → test_nat_type → hbbs_http::sync::start → check_zombie → new_server() → spawn direct_server listener → lan::start_listening thread → loop{ per rendezvous host spawn Self::start → start_udp → register_peer on timer → handle_resp }. SHOULD_EXIT restarts all. — [src/rendezvous_mediator.rs#L274-352](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/rendezvous_mediator.rs#L274-L352) [src/rendezvous_mediator.rs#L367-485](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/rendezvous_mediator.rs#L367-L485)
- OUTGOING CONNECT (UI): Flutter connect → bind.sessionAdd/sessionStart (flutter_ffi) → flutter::session_add creates Session<FlutterHandler> + LoginConfigHandler.initialize → session_start_ → Remote::new + io_loop on a thread. — [src/flutter_ffi.rs#L138-140](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter_ffi.rs#L138-L140) [src/flutter.rs#L1265-1371](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter.rs#L1265-L1371) [src/client/io_loop.rs#L118-151](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client/io_loop.rs#L118-L151)
- OUTGOING CONNECT (network): Remote::io_loop → Client::start → _start → (ip/domain direct shortcut | rendezvous resolution) → UDP punch socket + test_udp_uat + ipv6 socket + WebRTCStream offerer → _start_inner + TCP-punch fallback raced → secure_connection (signed id + DTLS fingerprint bind + symmetric key) → LoginRequest sent → io_loop remote_loop on frames. — [src/client/io_loop.rs#L185-220](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client/io_loop.rs#L185-L220) [src/client.rs#L409-580](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client.rs#L409-L580) [src/client.rs#L1645-1758](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client.rs#L1645-L1758)
- INCOMING CONNECT: hbbs PunchHole → accept_connection → new_listener on the punched socket → create_tcp_connection → admit_unauthorized (64 global / 16 per-IP, oldest evicted) → stream.set_max_packet_length(128KiB) → identity_handshake → Connection::start → on_open → permission send_permission notices → select! loop → on_message → LoginRequest → check_login_scope + password/2FA or CM authorize → authorized=true → service subscription. — [src/server.rs#L180-258](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L180-L258) [src/server/connection.rs#L83-142](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L83-L142) [src/server/connection.rs#L2838-2932](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L2838-L2932)
- INCOMING CONNECT (auth gates): unauthorized conns die on `unauthorized_evicted` or `login_deadline` (LOGIN_GRACE=180s); login failures are bucketed [password, 2FA, id-whitelist] in LOGIN_FAILURES with 10-minute decay for whitelist rejects; on success `self.authorized=true; self.unauthorized_id=None` releases the slot. — [src/server/connection.rs#L78-103](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L78-L103) [src/server/connection.rs#L186-199](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L186-L199) [src/server/connection.rs#L1839-1887](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L1839-L1887)
- PERSISTENCE: Config::get/set writes TOML via hbb_common; user process start_server(is_server=false) first ipc::connect→Data::SyncConfig to pull config from the running server; Linux/macOS server waits up to 3s (CONFIG_SYNC_INITIAL_WAIT_SECS) for root→local sync, then `sync_and_watch_config_dir` pushes local changes back to root every 0.3s. — [src/server.rs#L689-723](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L689-L723) [src/server.rs#L767-899](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L767-L899)
- UNI-LINK dispatch: `rustdesk://`-style URIs or `--connect <id>` args are normalized in core_main_invoke_new_connection into `{prefix}{authority}/{id}?params` and forwarded to the running instance via D-Bus (linux), WM_USER+2 window message (windows), or ipc::send_url_scheme (macos); falls back to handling locally. — [src/core_main.rs#L771-863](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L771-L863)
- CM approval flow: pending conn sends ipc::Data::Login{...} to the CM ipc server (ui_cm_interface::start_ipc); Flutter `--cm` window shows the prompt; operator accept sends Data::Authorize back → conn.send_logon_response_and_keep_alive; Data::Close→send_close_reason_no_retry+on_close. — [src/server/connection.rs#L749-779](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L749-L779) [src/flutter.rs#L1572-1605](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter.rs#L1572-L1605) [src/ipc.rs#L323-357](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L323-L357)
- Service template loop: each registered Service runs ServiceTmpl::run/repeat thread that hibernates at HIBERNATE_TIMEOUT=30ms until a subscriber exists, calls state.init() on first subscriber and state.reset() when the last leaves — so capture/encode resources are only held during active sessions. — [src/server/service.rs#L255-329](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/service.rs#L255-L329)

## Testing signals

Rust tests are unit-style `#[cfg(test)]`/`#[test]` modules embedded across src/ and a dedicated directory for video_qos; Flutter tests use flutter_test in flutter/test. CI exercises builds heavily (flutter-build.yml matrix) and runs a small set of named cargo test filters on Linux plus one flutter test file; there is no end-to-end session/integration test harness — network paths are exercised only in production.
- Rust test framework is plain `cargo test` with tokio::test (tokio test-util in dev-dependencies) plus `hound` and `docopt` dev deps; tests live inline (mod tests) and in dedicated files like src/client/tests/, src/audio_resampler/*_tests.rs, src/server/video_qos/tests/. — [Cargo.toml#L270-273](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L270-L273) [src/client.rs#L101-103](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client.rs#L101-L103)
- src/server/video_qos/tests/ is the most systematic suite — separate files per concern (baseline, startup, jitter, adaptation, recovery, robustness, invariants, sim, smoke) testing the QoS bitrate controller. — [src/server/video_qos/tests/baseline.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/video_qos/tests/baseline.rs) [src/server/video_qos/tests/recovery.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/video_qos/tests/recovery.rs)
- Audio has dedicated test files on both sides: src/server/audio_service/audio_capture_encoder_tests.rs, audio_capture_queue_tests.rs, src/client/audio_playback_tests.rs, src/client/tests/audio_playback_recovery_tests.rs + audio_state_tests.rs, and src/audio_resampler/{tests,samplerate_tests,allocation_tests}.rs. — [src/server/audio_service/audio_capture_encoder_tests.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/audio_service/audio_capture_encoder_tests.rs) [src/client/tests/audio_playback_recovery_tests.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client/tests/audio_playback_recovery_tests.rs) [src/audio_resampler/tests.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/audio_resampler/tests.rs)
- CI runs targeted cargo tests only on the Linux build: `cargo test --locked --lib --features drm drm_capturer_tests`, `cargo test --locked --lib --features drm ipc::test`, and `cargo test --locked -p scrap --features drm hotspot_provenance_tests`/`hotspot_guess_tests`; comments note a test filter matching nothing exits 0, so names must be kept in sync. — [.github/workflows/flutter-build.yml#L2058-2087](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/.github/workflows/flutter-build.yml#L2058-L2087)
- Flutter side has 12 test files in flutter/test covering terminal model/mouse/scroll/keyboard, file_model, cm, cursor_size, quality_monitor_transport, input_modifier_utils, autocomplete_peer_merge, server_settings_dialog; CI runs just `flutter test --timeout 60s test/cursor_size_test.dart`. — [flutter/test/terminal_model_lifecycle_test.dart](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/test/terminal_model_lifecycle_test.dart) [flutter/test/file_model_test.dart](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/test/file_model_test.dart) [.github/workflows/flutter-build.yml#L877](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/.github/workflows/flutter-build.yml#L877)
- Security-adjacent logic has unit tests: login_failure_check, port_forward_mux, ipc, updater, ui_cm_interface, platform/{windows,linux,mod}, drm_capturer, rdp_input, wayland, terminal_service, portable_service, display_service all contain #[test]/#[tokio::test] markers. — [src/server/login_failure_check.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/login_failure_check.rs) [src/updater.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/updater.rs) [src/ipc.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs)
- core_main.rs has a test module verifying is_user_main_ipc_scope_cli_command matches exactly the management commands (--password/--set-unlock-pin/--get-id/--set-id/--config/--option/--assign/--deploy) and not runtime flags like --server/--cm/--connect. — [src/core_main.rs#L916-950](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L916-L950)
- UNCOVERED: the ~8000-line src/server/connection.rs auth/login/session state machine, src/client.rs's 5800-line transport selection (punch/relay/WebRTC racing), and the Flutter<->Rust session lifecycle have no integration tests; examples/ipc.rs is a manual docopt test harness for IPC only. (inferred) — [src/server/connection.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs) [src/client.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client.rs) [examples/ipc.rs#L1-30](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/examples/ipc.rs#L1-L30)
- Server::new_for_test() exists to construct a Server without real services for unit tests, indicating tests are expected to fake the service registry rather than hit real capture. — [src/server.rs#L121-128](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L121-L128)
- No fuzzing, no property tests, no network-mock harness found; CI 'playground.yml' is a maintainer scratch workflow, not a test gate; docs/CONTRIBUTING.md exists but the scan shows no dedicated testing doc. (inferred) — [.github/workflows/playground.yml](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/.github/workflows/playground.yml) [docs/CONTRIBUTING.md](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/docs/CONTRIBUTING.md)

## Risk map

The riskiest surface is the unauthenticated pre-login path (deliberately bounded by slot pools and message caps), the IPC bridge between privileged service and user processes (heavily hardened with uid/executable checks), and updater/portable paths that write executables and delete files. Heavy use of forked/patched crypto-adjacent deps (webrtc, tungstenite, kcp) and `panic=abort` release profile amplify small defects. The empty hbb_common submodule means the actual wire crypto/proto code cannot be audited in this clone.
- Unauthenticated-connection resource guards: MAX_UNAUTHORIZED_CONNS=64 global, 16 per address, LOGIN_GRACE=180s, MAX_UNAUTHORIZED_MESSAGE=128KiB, plus PunchPool caps (32 UDP + 32 TCP punches) and MAX_WEBRTC_ANSWERERS=16 — all tuned against pre-auth DoS; weakening any of these constants is a security regression. — [src/server/connection.rs#L83-141](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L83-L141) [src/rendezvous_mediator.rs#L62-119](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/rendezvous_mediator.rs#L62-L119)
- MITM hardening on WebRTC: the controlled side signs its DTLS fingerprint into IdPk and the controller fails closed on mismatch ('possible MITM' bails); removing the dtls_fingerprint_bound check would silently downgrade to an unauthenticated channel. — [src/server.rs#L270-278](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L270-L278) [src/client.rs#L1699-1731](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client.rs#L1699-L1731)
- IPC authentication is platform-specific and intricate: ipc/auth.rs has Windows executable-identity checks (ensure_peer_executable_matches_current_by_pid_opt, portable-service token handshake), Linux uid allow-listing (is_allowed_service_peer_uid, peer_uid_from_fd) and SCM_RIGHTS fd passing for DRM capture (ipc/drm.rs) — a privileged-root attack surface. — [src/ipc.rs#L49-78](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L49-L78) [src/ipc/auth.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc/auth.rs) [src/ipc/drm.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc/drm.rs)
- Path-traversal-hardened file deletion: portable packer's resolve_within rebuilds meta.toml-listed paths component-by-component rejecting prefixes/roots/parents/colons because meta.toml sits in a user-writable dir and drives deletion — prior-traversal-bug-shaped code. — [libs/portable/src/main.rs#L87-116](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/libs/portable/src/main.rs#L87-L116)
- Updater runs with root/service privileges: macOS update requires a root-owned /var/run/rustdesk-update.lock with O_NOFOLLOW + flock; Windows update_me/--update path and `platform::install_me` copy executables — a compromised api-server/URL could push code (update URLs come from config/options). (inferred) — [src/updater.rs#L27-58](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/updater.rs#L27-L58) [src/core_main.rs#L229-255](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L229-L255)
- Shell-out surface: core_main/platform code spawns pkill, caffeinate, cmdkey/mstsc (rdp), gtk_sudo::exec, terminal_helper ConPTY processes, and install/uninstall scripts; args are mostly fixed strings but `run_rdp` reads rdp_username/rdp_password env vars into cmdkey args. — [src/core_main.rs#L402-407](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L402-L407) [src/server.rs#L236-247](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L236-L247) [src/port_forward.rs#L19-30](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/port_forward.rs#L19-L30)
- panic='abort' in release profile + pervasive `.unwrap()` on locks (e.g. `server.write().unwrap()`, `conns.lock().unwrap()`) means any poisoning or panic aborts the whole process including active sessions; AGENTS.md bans unwrap but legacy code is full of it. (inferred) — [Cargo.toml#L282-286](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L282-L286) [src/server.rs#L221](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L221) [AGENTS.md](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/AGENTS.md)
- The strategy-sync path lets the self-hosted server push arbitrary Config options (`StrategyOptions.config_options` applied to Config) — a malicious/compromised api-server could flip security options like enable-lan-discovery or disable-clipboard on all clients. (inferred) — [src/hbbs_http/sync.rs#L45-51](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/hbbs_http/sync.rs#L45-L51) [src/hbbs_http/sync.rs#L85-130](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/hbbs_http/sync.rs#L85-L130)
- 2FA secret handling: TOTP secret is generated per generate2fa() and stored via encrypt_vec_or_original with a hardcoded "00" key context in config — obfuscation-grade encryption at rest, not real protection. — [src/auth_2fa.rs#L54-73](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/auth_2fa.rs#L54-L73) [src/auth_2fa.rs#L76-100](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/auth_2fa.rs#L76-L100)
- Legacy Sciter UI (src/ui/) still compiled when `flutter` feature is off and reachable via ui::start — deprecated but alive code paths (CUR_SESSION, SciterHandler) enlarge the maintenance/audit surface. — [src/ui.rs#L32-60](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ui.rs#L32-L60) [src/main.rs#L29-31](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/main.rs#L29-L31)
- Forked network stack risk: webrtc/webrtc-sctp/webrtc-util and tungstenite are pinned to rustdesk-org forks with custom congestion-control and parsing changes; upstream CVE fixes will not flow through cargo update and must be cherry-picked by rev. (inferred) — [Cargo.toml#L219-253](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L219-L253)

## Extension points

Extension happens at five seams: (1) the Service registry — implement `Service`/`Subscriber` and register in `server::new()`; (2) ConnType — add a variant through protos + session_add dispatch + Flutter WindowType; (3) option keys — append to libs/base/src/config/keys.rs and src/lang template; (4) CLI flags — extend the args[0] chain in core_main; (5) Flutter FFI — new pub fns in flutter_ffi.rs + flutter_rust_bridge codegen. Platform code goes in src/platform/*, not shared paths.
- Service plugin point: implement `trait Service` (or reuse ServiceTmpl<T: Subscriber>) and call `server.add_service(Box::new(...))` in `new()` — video services are even added dynamically at runtime via try_add_monitor_service/try_add_primary_camera_service keyed by `get_service_name(VideoSource, idx)`. — [src/server/service.rs#L9-23](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/service.rs#L9-L23) [src/server.rs#L130-178](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L130-L178) [src/server.rs#L402-425](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L402-L425)
- New connection type: add a ConnType in message proto (hbb_common/base protos), branch it in `session_add` (is_* bools), map it in `peer_get_sessions_count`, add a WindowType + kAppType in Flutter main.dart, and handle the login_request::Union arm in connection.rs. — [src/flutter.rs#L1279-1293](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter.rs#L1279-L1293) [src/flutter_ffi.rs#L108-123](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter_ffi.rs#L108-L123) [flutter/lib/main.dart#L64-101](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/lib/main.dart#L64-L101) [src/server/connection.rs#L2715-2761](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L2715-L2761)
- Option keys: single import path `base::config::keys` re-exports hbb_common's keys plus ~100 client keys; new options are added as `pub const OPTION_*` and consumed via config::option2bool/Config::get_option — server-pushed strategies can set them remotely. — [libs/base/src/config/keys.rs#L1-10](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/libs/base/src/config/keys.rs#L1-L10) [src/core_main.rs#L892-897](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L892-L897)
- CLI extension is a linear `else if args[0] == "--x"` chain in core_main; note the pattern of gating management commands behind `platform::is_installed() && is_root()` and routing root CLI to user IPC via UserMainIpcScope/is_user_main_ipc_scope_cli_command. — [src/core_main.rs#L373-730](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L373-L730) [src/core_main.rs#L876-889](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L876-L889) [src/ipc.rs#L109-133](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L109-L133)
- IPC message extension: add variants to serde-tagged `enum Data` (and FS/DataKeyboard/etc. sub-enums); both ipc::start listener handlers and ui_cm_interface consumers must be updated; FileBlockFromCM documents the raw-bytes side-channel protocol (send message then send_raw). — [src/ipc.rs#L321-438](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L321-L438)
- Flutter FFI extension: add `pub fn` in src/flutter_ffi.rs (naming convention: session_*, main_*, peer_*; SyncReturn for sync calls) and regenerate bridge_generated via flutter_rust_bridge 1.80; events to UI go through GLOBAL_EVENT_STREAM via push_global_event(channel, json). — [src/flutter_ffi.rs#L87-100](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter_ffi.rs#L87-L100) [src/flutter.rs#L1808](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/flutter.rs#L1808)
- Localization: add keys to src/lang/template.rs + every locale file per AGENTS.md rules (en.rs only when display differs from key; it.rs always empty string); keys are the English text themselves, sentence-case. — [AGENTS.md](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/AGENTS.md) [src/lang.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/lang.rs)
- Platform seams: src/platform/{windows.rs,linux.rs,macos.rs} + per-OS subdirs implement the hooks called from shared code (install_me, is_installed, elevate_or_run_as_system, check_autostart_config...); AGENTS.md mandates putting new platform logic in these modules with thin call-site hooks. — [src/platform/mod.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/platform/mod.rs) [src/platform/linux.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/platform/linux.rs) [src/platform/windows.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/platform/windows.rs) [AGENTS.md](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/AGENTS.md)
- Codec/capture backends are cfg-gated extensions in libs/scrap (dxgi, quartz, x11, wayland, android, drm capturer) and codec EncoderCfg dispatch in video_service — adding a capture backend means a new scrap module + feature flag + service wiring. — [libs/scrap/src/lib.rs#L1-25](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/libs/scrap/src/lib.rs#L1-L25) [src/server/video_service.rs#L41-53](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/video_service.rs#L41-L53) [Cargo.toml#L30-33](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L30-L33)
- Privacy-mode impls are pluggable per-OS under src/privacy_mode/ (win_mag, win_virtual_display, win_exclude_from_capture, win_topmost_window, macos) selected via is_current_privacy_mode_impl/PRIVACY_MODE_IMPL_* constants. — [src/privacy_mode.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/privacy_mode.rs) [src/privacy_mode/win_mag.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/privacy_mode/win_mag.rs) [src/server/video_service.rs#L28-31](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/video_service.rs#L28-L31)
- Custom-server branding is a deployment-time extension: embed signed CustomServer JSON (host/key/api/relay) via exe filename or config string — verified against a hardcoded sign::PublicKey — rather than a plugin API. — [src/custom_server.rs#L11-44](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/custom_server.rs#L11-L44)
- AGENTS.md's own extension doctrine: prefer purely additive #[cfg]-gated blocks and new functions over restructuring; 'feature off must run the old code'; shared-file changes should be thin one-line hooks — this is the enforced contribution contract. — [AGENTS.md](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/AGENTS.md)

## Contributor handoff

Read AGENTS.md first — it is the authoritative style/scope contract (no unwrap, no nested tokio runtimes, minimal diffs, additive-only changes, import/comment/localization rules). Build requires the hbb_common submodule and system deps (vcpkg/pkg-config for vpx/opus/aom); the pinned Rust 1.75 toolchain and Flutter 3.24.5 matter. Safe edit boundaries: new code in feature modules or src/platform/*; dangerous: shared protocol/session files and anything touching pre-auth limits.
- AGENTS.md is the governing doc (CLAUDE.md just @-imports it): bans unwrap/expect outside tests & lock acquisition, bans nested runtimes/block_on in async, bans locks across .await, mandates single-braced use blocks per crate, and requires a 'regression-surface' report for every change. — [AGENTS.md](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/AGENTS.md) [CLAUDE.md](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/CLAUDE.md)
- First files to read for any session work: src/core_main.rs (entry/CLI), src/server.rs + src/server/connection.rs (host), src/client.rs + src/client/io_loop.rs (controller), src/ipc.rs (inter-process Data enum), libs/base/src/config/keys.rs (all option names). — [src/core_main.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs) [src/server/connection.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs) [src/client.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/client.rs) [src/ipc.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs)
- Toolchain pins: rust-version 1.75 (Cargo.toml), CI RUST_VERSION 1.75 / macOS 1.81, Flutter 3.24.5 (3.44.9 win-arm64), flutter_rust_bridge '=1.80'/1.80.1 — mismatched frb versions regenerate incompatible bindings. — [Cargo.toml#L9](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L9) [Cargo.toml#L77](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Cargo.toml#L77) [flutter/pubspec.yaml](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/flutter/pubspec.yaml) [.github/workflows/flutter-build.yml#L15-30](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/.github/workflows/flutter-build.yml#L15-L30)
- Build commands: `cargo build --locked --features flutter` (desktop lib) or `python3 build.py` for full app packaging; quick checks: `cargo test --locked --lib --features drm` (Linux), `flutter test` in flutter/; vcpkg must provide libvpx/libyuv/opus/aom per Dockerfile. — [.github/workflows/flutter-build.yml#L555](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/.github/workflows/flutter-build.yml#L555) [.github/workflows/flutter-build.yml#L2080-2087](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/.github/workflows/flutter-build.yml#L2080-L2087) [Dockerfile#L36-38](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/Dockerfile#L36-L38)
- Editing `libs/hbb_common` costs a round-trip: it is shared with rustdesk-server — put client-only code in libs/base instead; base::config::keys re-exports the hbb_common keys so callers never import from two places. — [AGENTS.md](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/AGENTS.md) [libs/base/src/config/keys.rs#L1-7](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/libs/base/src/config/keys.rs#L1-L7)
- Known traps: `is_quick_support_exe` must stay in sync with libs/portable/src/main.rs; the CLI↔IPC routing list is_user_main_ipc_scope_cli_command has a regression test; IPC FileBlockFromCM requires message-then-send_raw ordering; tray icon assets are include_bytes!()'d from res/ (compile-time). — [src/core_main.rs#L952-959](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L952-L959) [src/core_main.rs#L916-950](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/core_main.rs#L916-L950) [src/ipc.rs#L411-435](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L411-L435) [src/tray.rs#L43-51](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/tray.rs#L43-L51)
- Process model trap: the same binary runs as service/root (--server), user GUI, tray, and --cm simultaneously; shared state does NOT cross processes — it goes through ipc::Data or Config file sync (sync_and_watch_config_dir); never assume a global static is visible to the other process. — [src/server.rs#L689-723](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server.rs#L689-L723) [src/ipc.rs#L321-438](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc.rs#L321-L438)
- Security-sensitive zones to touch carefully: pre-auth limits in connection.rs/rendezvous_mediator.rs (64/16/128KiB/180s/32-punch/16-answerer constants), ipc/auth.rs peer verification, updater.rs update paths, custom_server.rs signature verification — changes here need the 'regression surface' analysis AGENTS.md demands. — [src/server/connection.rs#L78-141](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/connection.rs#L78-L141) [src/ipc/auth.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ipc/auth.rs) [src/updater.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/updater.rs)
- Flutter-side session ownership: Session<T:InvokeUiSession> + LoginConfigHandler (ui_session_interface.rs) is the shared abstraction — Flutter implements it via FlutterHandler/event streams, legacy Sciter via remote::SciterHandler; new UI behavior should be added to the InvokeUiSession trait rather than bypassing it. — [src/ui_session_interface.rs#L57-75](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ui_session_interface.rs#L57-L75) [src/ui_session_interface.rs#L1679](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ui_session_interface.rs#L1679) [src/ui.rs#L32-35](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/ui.rs#L32-L35)
- cfg discipline: almost every module is gated per-OS/feature; `#[cfg(not(any(target_os="android",target_os="ios")))]` is the desktop idiom, `feature="flutter"` selects the UI backend, and imports must be folded into per-crate braced blocks with separate use only for differently-gated items. — [src/lib.rs#L1-75](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/lib.rs#L1-L75) [AGENTS.md](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/AGENTS.md)
- Testing expectation: add #[cfg(test)] mods or files next to the code (video_qos/tests pattern); CI only runs named filters on Linux and one flutter test file — a renamed test silently stops running because empty filters exit 0 (noted in workflow comments). — [.github/workflows/flutter-build.yml#L2058-2087](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/.github/workflows/flutter-build.yml#L2058-L2087) [src/server/video_qos/tests/smoke.rs](https://github.com/rustdesk/rustdesk/blob/c6a358afbe37c518689a6157a8e8cdbd645dcc5d/src/server/video_qos/tests/smoke.rs)

Source repository: https://github.com/rustdesk/rustdesk
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/rustdesk.json

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
