CodeVetter · Repo Unpack · Behavior traces
rustdesk/rustdesk
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().
- 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().
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.