CodeVetter · Repo Unpack · Data flow
rustdesk/rustdesk
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.
- 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`.
- 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).
- 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`.
- 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).
- 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.
- 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`.
- 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.
- 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)
- 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.
- 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.
- 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.