- close_webrtc is no longer async (hbb_common 88f965f), so the ten call
sites in port_forward and io_loop - all inside select! arms or futures
the UI can abandon - can no longer be cancelled mid-teardown, which
left the pc unclosable and its session entry stranded. Client's own
spawn_close_webrtc went with it: the runtime-teardown guard it existed
for now lives in close_detached, so both Drop paths share one
implementation.
- webrtc_relayed() returns None when no candidate pair is selected or
the pc closed under a concurrent teardown, and both call sites read
that as "not relayed", i.e. direct. A TURN-relayed session could
therefore be shown to the user as peer-to-peer. Claiming a direct path
needs evidence of one, so an unknown answer now counts as relayed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ExUfAkYbq8UC9pQCiLy8TQ
- prefer-P2P racing (race_transports_prefer_webrtc) across punch and RelayResponse; ICE bridge with 400ms candidate resend
- controlled-side answerer and ICE routing; sign local DTLS fingerprint into SignedId, controller verifies the binding fail-closed
- fix pc leaks: close_webrtc() on insecure-decline paths (io_loop, port_forward); compute direct before disarming the offerer guard
- point hbb_common to the WebRTC data-plane commit 9f5a296
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(clipboard): optionally sync clipboard between connected sessions
Clipboard content received from a remote session is written to the local
clipboard with an owner marker, so the client clipboard loop deliberately
skips re-broadcasting it to avoid echo loops. As a result, text copied in
one remote window could not be pasted in another connected remote window.
Add an opt-in local option (allow-sync-clipboard-between-sessions) that
relays Clipboard/MultiClipboards messages received from one session to
all other connected sessions, excluding the source session. Per-session
clipboard permissions and view-only mode are still respected via the
existing send path, and the owner marker on the receiving peers prevents
any echo back.
Desktop (flutter) only; file clipboard is not affected.
* fix(lang): propagate sync-clipboard-between-sessions-tip to all locale files
Add the new key to template.rs and every locale file per the localization
convention, move the en.rs entry to the end of the list, and drop comments
that only restated the names next to them.
* fix(lang): add the 'Sync clipboard between sessions' label to the localization catalog
The checkbox label goes through translate(), so add it to template.rs
and every locale file so non-English locales can translate it. en.rs is
skipped since the English display text is identical to the key.
* fix(clipboard): check the source session's full clipboard permission before relaying
The relay was gated only by the incoming clipboard_allowed check
(!disable_clipboard && !view_only). Gate it with
is_text_clipboard_required() instead, which additionally respects the
source session's server_clipboard_enabled and server_keyboard_enabled
state, matching the predicate already applied to destination sessions.
A message arriving after the source permission was revoked (or from a
non-conforming peer) is no longer propagated to other sessions. The
existing local update_clipboard behavior is unchanged.
* fix(lang): translate the new clipboard sync entries in all locale files
Fill the 'Sync clipboard between sessions' label and its tooltip in
every locale file instead of leaving them blank, following each file's
existing terminology. template.rs keeps the empty master entries.
* fix(flutter): dispose the settings PageController and order dispose() correctly
`dispose()` began with `super.dispose()`, so the mixin chain marked the State
defunct before the WidgetsBindingObserver registration and the periodic timer
were released. The `PageController` was never disposed at all: `Get.delete`
only runs `onDelete()` for a `GetLifeCycleBase`, and a plain `ChangeNotifier`
is not one, so every open/close of the Settings tab leaked one controller with
its listener still attached.
Also guard `switch2page` on the `Rx<SettingsTabKey>` registration it actually
reads rather than only the `PageController` — now that both are really
deleted, a partial teardown would throw into the catch and silently open the
wrong tab — and re-check `mounted` after the await in the `_videoConnTimer`
tick, which `Timer::cancel` cannot stop once the body has started.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refact: finish the plugin-framework removal sweep
#15854 removed the feature but stopped short of its leftovers:
- `Uninstall`, `Enable`, `Disable`, `Options` and `Please install plugins`
were consumed only by the deleted `flutter/lib/plugin/**`; drop them from
template.rs and the 50 locale files (250 dead entries). `Update` and
`Install` stay, still used by desktop_home_page.dart.
- The server no longer sends `PrvOnFailedPlugin`, and the client no longer
offers to install plugins when privacy mode fails to turn on.
- Drop the MSI `F_Client_Plugins` / `F_Server_Plugins` localization strings;
no `.wxs` references them.
- `_DisplayMenu`'s constructor became a pure pass-through once `pluginItem`
was removed, and the cfg inside `handle_input` repeats the one on the
function itself.
- Normalize `src/lang/sl.rs` to 0644, the only executable file under src/.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(client): handle legacy privacy mode plugin failures
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: fufesou <linlong1266@gmail.com>
* fix(clipboard): clean up stale Linux FUSE mounts
Recover Linux file clipboard FUSE mount points before remounting and stop treating a cached
context as valid when the mount has already gone away.
This fixes the desktop file manager copy failure that shows dialogs such as
"Error while copying a" and "There was an error copying the file into xxx".
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(clipboard): fuse, reduce dups
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix: clear Linux file clipboard before unmounting FUSE
Ensure Linux client teardown clears RustDesk file clipboard URLs while
the FUSE context is still available. Also prefer fusermount before
umount to avoid noisy unprivileged teardown attempts.
Signed-off-by: fufesou <linlong1266@gmail.com>
* fix(clipboard): return and log errors
Signed-off-by: fufesou <linlong1266@gmail.com>
---------
Signed-off-by: fufesou <linlong1266@gmail.com>
- Route Windows server-to-client file reads through CM instead of the connection layer
- Add FS IPC commands (ReadFile, CancelRead, SendConfirmForRead, ReadAllFiles) and CM data messages
(ReadJobInitResult, FileBlockFromCM, FileReadDone, FileReadError, FileDigestFromCM, AllFilesResult)
- Track pending read validations and read jobs to coordinate CM-driven file transfers and clean them up
on completion, cancellation, and errors
- Enforce a configurable file-transfer-max-files limit for ReadAllFiles and add stronger file name/path
validation on the CM side
- Improve Flutter file transfer UX and robustness:
- Use explicit percent/percentText progress fields
- Derive speed and cancel actions from the active job
- Handle job errors via FileModel.handleJobError and complete pending recursive tasks on failure
- Wrap recursive directory operations in try/catch and await sendRemoveEmptyDir when removing empty directories
Signed-off-by: fufesou <linlong1266@gmail.com>
1. Update kcp-sys to send KCP in frames to avoid potential crashes.
2. Fix the issue when the controling side is closed, the kcp connection close is not immediately recognized by the controlled end.
* Unless the controling side receives the close reason, force the sending of the close reason to the controlled end when using KCP, and delay for 30ms to ensure the message is sent successfully.
* Move the CloseReason receiving forward, as this message needs to be received when unauthorized, especially for kcp.
Signed-off-by: 21pages <sunboeasy@gmail.com>
1. Fix auto record outgoing sessions ignore record permission
2. Stop record if record permission changed
3. Update hwcodec
4. Make video thread finish faster when connection closed
Signed-off-by: 21pages <sunboeasy@gmail.com>
* seperate video decoding thread for each display
1. Separate Video Decoding Thread for Each Display
2. Fix Decode Errors When Clearing the Queue
Previously, on-flight frames after clearing the queue could not be decoded successfully. This issue can be resolved by setting a discard_queue flag when sending a refresh message. The flag will be reset upon receiving a keyframe.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* update video format along with fps to flutter
Signed-off-by: 21pages <sunboeasy@gmail.com>
* Fix keyframe interval when auto record outgoing sessions
Signed-off-by: 21pages <sunboeasy@gmail.com>
---------
Signed-off-by: 21pages <sunboeasy@gmail.com>
1. Dropping frames can cause this error, reset encoder when this
happens.
2. There are some logic error for clear video queue, because video queue
message is not cleared. This need to be fixed.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* Add option auto record outgoing session
* In the same connection, all displays and all windows share the same
recording state.
todo:
Android check external storage permission
Known issue:
* Sciter old issue, stop the process directly without stop record, the record file can't play.
Signed-off-by: 21pages <sunboeasy@gmail.com>