Commit Graph

17 Commits

Author SHA1 Message Date
xuwenwei 9442a13533 Force direct=true when same-LAN punch succeeds (is_local=true)
Before this fix, RustDesk would fall back to relay even when the
TCP hole-punch actually succeeded AND the server told us this is a
same-LAN connection (is_local=true). The reason: when 'force_relay'
is set in LoginConfig (or the peer id has an /r suffix), connect()
unconditionally goes through request_relay() — which is wasteful
on a same-LAN punch that's already succeeded.

Symptoms user reported:
  - Home Mac ↔ Office Mac (both on 192.168.31.x)
  - Server confirms is_local=true (logged in RustDesk log)
  - TCP Hole Punched succeeds (192.168.31.111:59050)
  - But the punch-status banner shows '中继模式' and the
    file-transfer menu item stays hidden
  - All because the connect() path took the relay branch

After this fix:
  - If is_local && punch succeeded, direct = true
  - The relay fallback is only entered when is_local is false
    (genuinely remote peer) or when the punch actually failed
  - The banner flips to green  and file transfer reappears

Verified by reading the Rust log captured from the user's session:
  TCP Hole Punched 265195446 = 192.168.31.111:59050  (is_local: true)
  #1 request relay attempt  (should now be skipped)
  Relay connection with TCP punch succeeded (should now be skipped)
2026-06-09 15:03:28 +08:00
xuwenwei 8ef7ff1ce9 Hide 'Transfer file' and 'TCP tunneling' menu items in relay mode
Plan B for the punch UI: don't just grey out file transfer — hide it
entirely when the connection is relay. The user can't try to use it,
and we save the toast explanation.

When punch succeeds (P2P, direct), the menu items reappear.

Applied to:
  - Transfer file
  - TCP tunneling

(Leaving View camera and Terminal in the menu regardless of mode —
  they don't use server bandwidth significantly.)
2026-06-09 12:04:18 +08:00
xuwenwei 4ecbcaf252 punch banner: revert broken '重试直连' button, keep status banner
The '重试直连' button couldn't resolve the FFI 'bind' symbol
in this file's scope (Dart top-level identifier resolution quirk
when bind is re-exported from models/model.dart through common.dart).

Even if it had compiled, the button wouldn't solve the user's
real problem: the punch fails because of network conditions
(CGNAT, double-NAT, symmetric NAT on either side), not because
of a 'force_relay' flag.

What stays working:
  - Green  banner when P2P succeeded
  - Orange ⚠ banner when relay fallback
  - File-transfer menu item is intercepted with a toast on relay

Next steps for the user to actually get P2P:
  - Test on the same LAN (not via 4G/5G or CGNAT)
  - Check router has UPnP enabled
  - If still fails, ask the hbbs maintainer to improve is_local
    detection (compare LAN subnets, not just public IP)
2026-06-09 11:56:21 +08:00
xuwenwei 6811508178 Add '重试直连' button to punch-status banner
In relay mode, the banner now exposes a single button that calls
sessionReconnect(sessionId, forceRelay=false). This:
  - resets the is_force_relay flag in the Session lc state
  - triggers a fresh punch attempt (with the same direct_failures counter,
    which only shortens the punch timeout, never skips the attempt)
  - if punch succeeds, banner flips to green and file transfer re-enables

The button is disabled (greyed out) if sessionId is not yet known.

User's setup has both Macs with global IPv6 (2409:8a1e::, China Mobile),
but punch still falls back to relay. Common cause: CGNAT, double-NAT, or
symmetric NAT. The retry button lets the user test network conditions
without restarting the app.

Removed: my earlier attempt at main_get_logs / session_get_session_id FFI
bridges — couldn't find the right log path / session API, and the
sessionId is already exposed via RemotePage.sessionId getter.
2026-06-09 11:30:15 +08:00
xuwenwei f5a6b033ff Reduce force-off to only 4: audio, camera, tunnel, privacy-mode
User clarified: only these 4 should default-off. The other 5 I had
forced off (keyboard, clipboard, file-transfer, terminal, remote-restart)
should be on by default (RustDesk's normal behavior).

What I force off now (OVERWRITE_SETTINGS = N, user cannot override):
  - enable-audio
  - enable-camera
  - enable-tunnel
  - enable-privacy-mode

What stays at RustDesk's default (on, user-configurable):
  - enable-keyboard
  - enable-clipboard
  - enable-file-transfer
  - enable-terminal
  - enable-remote-restart
  - enable-record-session

Old config had no leftover enable-* values, so this is a clean transition.
2026-06-09 11:15:30 +08:00
xuwenwei a92b7c22bc Also force off enable-terminal and enable-remote-restart
User screenshot showed these two checkboxes were still on. The previous
OVERWRITE list missed them. Now all 9 sensitive/bandwidth-heavy options
are force-off (user cannot override from UI):
  - enable-keyboard, enable-clipboard, enable-file-transfer
  - enable-tunnel, enable-record-session, enable-camera
  - enable-audio
  - enable-terminal, enable-remote-restart
2026-06-09 10:45:42 +08:00
xuwenwei 86c30f5f0f Move 7 default-off settings to OVERWRITE_SETTINGS (user cannot override)
Previous commit (6d587a8) used DEFAULT_SETTINGS, which is the lowest
priority — user config (RustDesk2.toml) wins. The user complained that
'Enable keyboard/mouse' and 'Enable clipboard' were 'default on', which
turned out to be old config values from a previous build session.

OVERWRITE_SETTINGS is the highest priority — user cannot override it from
the UI. This is the right mechanism for security/billing policy:
  - enable-keyboard, enable-clipboard: user said 'default on is wrong'
  - enable-file-transfer: server bandwidth killer (1 GB upload = 2 GB)
  - enable-tunnel: server-as-jump-host risk
  - enable-record-session, enable-camera, enable-audio: rare-use, default-off

The 2 NAT-punch force-on options (enable-udp-punch, enable-ipv6-punch)
are unchanged — they live in OVERWRITE_LOCAL_SETTINGS, which is also
highest priority but for local-only options (UDP punch is per-machine).
2026-06-09 10:30:18 +08:00
xuwenwei 8a5ba65132 Add P2P/relay status banner + gate file-transfer menu on relay
Custom fork feature: surface NAT-punch result to the user so they know
whether the connection is going through their 21117 server (relay) or
directly between the two machines (P2P).

Three changes:

1. flutter/lib/common/shared_state.dart: add ConnectionType.isP2P getter
   (true = direct, false = relay) and a top-level isDirectConnection(peerId)
   helper that returns true when state is unknown (so UI doesn't briefly
   grey out before the connection establishes).

2. flutter/lib/desktop/widgets/punch_status_banner.dart (new): a small
   Positioned banner at the top of the connection page.
   - P2P success: green  banner: 'P2P 直连成功 — 走的是两台机器之间的网络,可放心传文件'
   - Relay fallback: orange ⚠ banner: '中继模式 — 视频/控制走服务器 21117 中转,请勿传大文件'
   The banner is reactive (Obx on ConnectionType.direct Rx<String>).

3. flutter/lib/common/widgets/toolbar.dart: wrap the 'Transfer file' and
   'TCP tunneling' menu items' onPressed with an isDirectConnection() guard.
   On relay mode, the menu still shows but the click is intercepted with a
   toast explaining why the action is blocked.

4. flutter/lib/desktop/pages/remote_page.dart: add the banner via
   Positioned(top: 0, left: 0, right: 0) at the end of bodyWidget's Stack.

Why this matters: user has 4 users on 5 Mbps server (114.55.133.123).
When NAT punch fails and the session goes through relay, file transfers
would saturate the server bandwidth. Showing the relay state + blocking
the file-transfer menu protects the server without requiring the user
to remember the technical detail.
2026-06-09 01:24:54 +08:00
xuwenwei 6d587a840e Default-off 6 options (file-transfer, clipboard, keyboard, tunnel, record-session, camera) + force-on 2 NAT punch options
For 4 users on 5 Mbps server (114.55.133.123) where file transfers were saturating bandwidth:

Turn OFF by default (users can still flip on per-session):
- enable-file-transfer: THE KILLER (1 GB upload = 2 GB server bandwidth)
- enable-clipboard: 50 kbps + privacy
- enable-keyboard: only needed for typing-on-remote
- enable-tunnel: prevents using server as jump host
- enable-record-session: only when explicitly recording
- enable-camera: 500 kbps; rarely used for support
- enable-audio: (already in c94a72a)

Force ON (overrides RustDesk's conservative default for self-hosted servers):
- enable-udp-punch, enable-ipv6-punch: src/common.rs:1107 turns these off
  when rendezvous server is non-public. That's a safety measure meant for
  untrusted public servers, but our self-hosted server is fully trusted.
  Force-enabling boosts P2P success rate → less relay (21117) traffic →
  less server bandwidth.
2026-06-09 00:31:42 +08:00
xuwenwei 0532fafe9f BUILD.md: document the Rust source edit (custom.txt path is broken for unsigned forks) 2026-06-08 23:36:50 +08:00
xuwenwei d49ba37c1c Revert "Default 'enable-audio' to off via custom.txt (read by Rust load_custom_client)"
This reverts commit a5b0c523fc.
2026-06-08 23:36:09 +08:00
xuwenwei c94a72aa94 Hardcode enable-audio=N as default (bypasses custom.txt signature check)
RustDesk's read_custom_client() at src/common.rs:2191 expects base64-decoded
ed25519-signed content, not plain JSON. Our custom.txt (plain JSON) fails the
decode64 check and returns early, so DEFAULT_SETTINGS stays empty.

Fix: inject 'enable-audio' = 'N' directly into DEFAULT_SETTINGS at the end of
load_custom_client(), outside the read_custom_client() call. entry().or_insert()
preserves the priority chain (OVERWRITE_SETTINGS → CONFIG2 → DEFAULT_SETTINGS),
so the user can still flip the option on in Settings.

Verified with debug eprintln that DEFAULT_SETTINGS.get("enable-audio") returns
Some("N") at startup. UI now shows 'Enable audio' unchecked in Settings →
Permissions.
2026-06-08 23:35:13 +08:00
xuwenwei 4c34dc1d36 Document custom.txt default-settings mechanism in BUILD.md 2026-06-08 23:13:15 +08:00
xuwenwei a5b0c523fc Default 'enable-audio' to off via custom.txt (read by Rust load_custom_client)
- Added flutter/macos/Runner/custom.txt with default-settings.enable-audio=N
- Added custom.txt to Xcode Copy Bundle Resources (PBXResourcesBuildPhase)
- RustDesk's load_custom_client() reads this file and injects into DEFAULT_SETTINGS
- Users can still toggle 'Enable audio' in Settings; this just flips the default

This addresses the user's request to disable all 4 audio behaviors by default
(play remote sound, hear remote mic, voice call, capture host audio), all of
which share the single 'enable-audio' option.
2026-06-08 23:12:09 +08:00
xuwenwei cb8de0f28a Add BUILD.md and res/post-build-mac.sh
- BUILD.md: complete build instructions for macOS desktop (Xcode 26.5,
  Flutter 3.44, Dart 3.12, VCPKG, all patches explained)
- res/post-build-mac.sh: re-sign + install to /Applications + create dmg,
  run after every 'flutter build macos --release'

Key issues documented in BUILD.md:
  * Re-signing is mandatory (codesign --force --deep -s -)
  * Use hdiutil for dmg, not create-dmg (macos-alias is x86_64 broken)
  * libclang must be arm64 (use Xcode CLT, not homebrew llvm)
  * EXCLUDED_ARCHS=x86_64 for arm64-only Rust dylib
2026-06-08 21:57:18 +08:00
xuwenwei d3b6026bfd Initial commit: RustDesk 1.4.7 macOS desktop port
- Filled empty libs/hbb_common/ submodule (cloned from rustdesk/hbb_common)
- Patched Flutter 3.44 / Dart 3.12 compatibility:
  * flutter/lib/generated_bridge.dart: asTypedList with cast<>, DartPort=Int64
  * flutter/lib/common.dart: DialogTheme->DialogThemeData, TabBarTheme->TabBarThemeData
  * flutter/pubspec.yaml: extended_text 14.0.0->15.0.2, google_fonts override 5.0.0
  * flutter/macos/Runner/Configs/Release.xcconfig: EXCLUDED_ARCHS=x86_64
- Build verified: cargo check + cargo build --features flutter + cargo build --release --features flutter
- Verified flutter build macos --debug and --release both produce working .app
- Verified .dmg installer (27MB arm64) created via hdiutil
- Build deps: Xcode 26.5, CocoaPods 1.16.2, Flutter 3.44, VCPKG arm64-osx
2026-06-08 21:43:20 +08:00
xuwenwei 3d8db09123 添加 README.md 2026-06-08 18:07:43 +08:00