From 9475743b4e5784dece7f3ceb801eb89d869b3f78 Mon Sep 17 00:00:00 2001 From: 21pages Date: Fri, 9 May 2025 12:18:49 +0800 Subject: [PATCH] allow use websocket (#11677) 1. Enable the RustDesk client to use WebSocket for either controlling or being controlled. 2. Fix TCP sending `register_pk` frequently Note: 1. Because hbb_common directly uses `use_ws` to read config directly, rustdesk also directly reads config Signed-off-by: 21pages --- Cargo.lock | 23 +++- flutter/lib/consts.dart | 4 + .../desktop/pages/desktop_setting_page.dart | 112 +++++++++++++----- flutter/lib/mobile/pages/settings_page.dart | 20 ++++ flutter/lib/models/web_model.dart | 5 +- flutter/lib/web/bridge.dart | 44 +++++++ libs/hbb_common | 2 +- src/client.rs | 13 +- src/common.rs | 35 +++++- src/flutter_ffi.rs | 10 +- src/ipc.rs | 81 ++++++++++--- src/lang/ar.rs | 2 + src/lang/be.rs | 2 + src/lang/bg.rs | 2 + src/lang/ca.rs | 2 + src/lang/cn.rs | 2 + src/lang/cs.rs | 2 + src/lang/da.rs | 2 + src/lang/de.rs | 2 + src/lang/el.rs | 2 + src/lang/en.rs | 3 +- src/lang/eo.rs | 2 + src/lang/es.rs | 2 + src/lang/et.rs | 2 + src/lang/eu.rs | 2 + src/lang/fa.rs | 2 + src/lang/fr.rs | 2 + src/lang/ge.rs | 2 + src/lang/he.rs | 2 + src/lang/hr.rs | 2 + src/lang/hu.rs | 2 + src/lang/id.rs | 2 + src/lang/it.rs | 2 + src/lang/ja.rs | 2 + src/lang/ko.rs | 2 + src/lang/kz.rs | 2 + src/lang/lt.rs | 2 + src/lang/lv.rs | 2 + src/lang/nb.rs | 2 + src/lang/nl.rs | 2 + src/lang/pl.rs | 2 + src/lang/pt_PT.rs | 2 + src/lang/ptbr.rs | 2 + src/lang/ro.rs | 2 + src/lang/ru.rs | 2 + src/lang/sc.rs | 2 + src/lang/sk.rs | 2 + src/lang/sl.rs | 2 + src/lang/sq.rs | 2 + src/lang/sr.rs | 2 + src/lang/sv.rs | 2 + src/lang/ta.rs | 2 + src/lang/template.rs | 2 + src/lang/th.rs | 2 + src/lang/tr.rs | 2 + src/lang/tw.rs | 2 + src/lang/uk.rs | 2 + src/lang/vn.rs | 2 + src/rendezvous_mediator.rs | 25 +++- src/ui/index.tis | 1 + src/ui_interface.rs | 7 +- 61 files changed, 413 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcff3416c..33eff1175 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5724,7 +5724,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.4", "winreg 0.50.0", ] @@ -7051,8 +7051,15 @@ checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" dependencies = [ "futures-util", "log", + "native-tls", + "rustls 0.23.26", + "rustls-native-certs 0.8.1", + "rustls-pki-types", "tokio", + "tokio-native-tls", + "tokio-rustls 0.26.0", "tungstenite", + "webpki-roots 0.26.9", ] [[package]] @@ -7253,10 +7260,15 @@ dependencies = [ "http 1.3.1", "httparse", "log", + "native-tls", "rand 0.9.0", + "rustls 0.23.26", + "rustls-native-certs 0.8.1", + "rustls-pki-types", "sha1", "thiserror 2.0.11", "utf-8", + "webpki-roots 0.26.9", ] [[package]] @@ -7753,6 +7765,15 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "0.26.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29aad86cec885cafd03e8305fd727c418e970a521322c91688414d5b8efba16b" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "weezl" version = "0.1.8" diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 617c17e38..c2382bf20 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -147,9 +147,13 @@ const String kOptionDirectxCapture = "enable-directx-capture"; const String kOptionAllowRemoteCmModification = "allow-remote-cm-modification"; const String kOptionEnableTrustedDevices = "enable-trusted-devices"; +// network options +const String kOptionAllowWebSocket = "allow-websocket"; + // buildin opitons const String kOptionHideServerSetting = "hide-server-settings"; const String kOptionHideProxySetting = "hide-proxy-settings"; +const String kOptionHideWebSocketSetting = "hide-websocket-settings"; const String kOptionHideRemotePrinterSetting = "hide-remote-printer-settings"; const String kOptionHideSecuritySetting = "hide-security-settings"; const String kOptionHideNetworkSetting = "hide-network-settings"; diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index fc35687cf..351606d57 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1475,11 +1475,70 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { bind.mainGetBuildinOption(key: kOptionHideServerSetting) == 'Y'; final hideProxy = isWeb || bind.mainGetBuildinOption(key: kOptionHideProxySetting) == 'Y'; + // final hideWebSocket = isWeb || + // bind.mainGetBuildinOption(key: kOptionHideWebSocketSetting) == 'Y'; + final hideWebSocket = true; - if (hideServer && hideProxy) { + if (hideServer && hideProxy && hideWebSocket) { return Offstage(); } + // Helper function to create network setting ListTiles + Widget listTile({ + required IconData icon, + required String title, + VoidCallback? onTap, + Widget? trailing, + bool showTooltip = false, + String tooltipMessage = '', + }) { + final titleWidget = showTooltip + ? Row( + children: [ + Tooltip( + waitDuration: Duration(milliseconds: 1000), + message: translate(tooltipMessage), + child: Row( + children: [ + Text( + translate(title), + style: TextStyle(fontSize: _kContentFontSize), + ), + SizedBox(width: 5), + Icon( + Icons.help_outline, + size: 14, + color: Theme.of(context) + .textTheme + .titleLarge + ?.color + ?.withOpacity(0.7), + ), + ], + ), + ), + ], + ) + : Text( + translate(title), + style: TextStyle(fontSize: _kContentFontSize), + ); + + return ListTile( + leading: Icon(icon, color: _accentColor), + title: titleWidget, + enabled: !locked, + onTap: onTap, + trailing: trailing, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + contentPadding: EdgeInsets.symmetric(horizontal: 16), + minLeadingWidth: 0, + horizontalTitleGap: 10, + ); + } + return _Card( title: 'Network', children: [ @@ -1488,39 +1547,36 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (!hideServer) - ListTile( - leading: Icon(Icons.dns_outlined, color: _accentColor), - title: Text( - translate('ID/Relay Server'), - style: TextStyle(fontSize: _kContentFontSize), - ), - enabled: !locked, + listTile( + icon: Icons.dns_outlined, + title: 'ID/Relay Server', onTap: () => showServerSettings(gFFI.dialogManager), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - contentPadding: EdgeInsets.symmetric(horizontal: 16), - minLeadingWidth: 0, - horizontalTitleGap: 10, ), - if (!hideServer && !hideProxy) + if (!hideServer && (!hideProxy || !hideWebSocket)) Divider(height: 1, indent: 16, endIndent: 16), if (!hideProxy) - ListTile( - leading: - Icon(Icons.network_ping_outlined, color: _accentColor), - title: Text( - translate('Socks5/Http(s) Proxy'), - style: TextStyle(fontSize: _kContentFontSize), - ), - enabled: !locked, + listTile( + icon: Icons.network_ping_outlined, + title: 'Socks5/Http(s) Proxy', onTap: changeSocks5Proxy, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + ), + if (!hideProxy && !hideWebSocket) + Divider(height: 1, indent: 16, endIndent: 16), + if (!hideWebSocket) + listTile( + icon: Icons.web_asset_outlined, + title: 'Use WebSocket', + showTooltip: true, + tooltipMessage: 'websocket_tip', + trailing: Switch( + value: mainGetBoolOptionSync(kOptionAllowWebSocket), + onChanged: locked + ? null + : (value) { + mainSetBoolOption(kOptionAllowWebSocket, value); + setState(() {}); + }, ), - contentPadding: EdgeInsets.symmetric(horizontal: 16), - minLeadingWidth: 0, - horizontalTitleGap: 10, ), ], ), diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index 600f807e8..4681d2313 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -80,6 +80,7 @@ class _SettingsState extends State with WidgetsBindingObserver { var _enableDirectIPAccess = false; var _enableRecordSession = false; var _enableHardwareCodec = false; + var _allowWebSocket = false; var _autoRecordIncomingSession = false; var _autoRecordOutgoingSession = false; var _allowAutoDisconnect = false; @@ -91,6 +92,7 @@ class _SettingsState extends State with WidgetsBindingObserver { var _hideServer = false; var _hideProxy = false; var _hideNetwork = false; + var _hideWebSocket = false; var _enableTrustedDevices = false; _SettingsState() { @@ -105,6 +107,7 @@ class _SettingsState extends State with WidgetsBindingObserver { bind.mainGetOptionSync(key: kOptionEnableRecordSession)); _enableHardwareCodec = option2bool(kOptionEnableHwcodec, bind.mainGetOptionSync(key: kOptionEnableHwcodec)); + _allowWebSocket = mainGetBoolOptionSync(kOptionAllowWebSocket); _autoRecordIncomingSession = option2bool(kOptionAllowAutoRecordIncoming, bind.mainGetOptionSync(key: kOptionAllowAutoRecordIncoming)); _autoRecordOutgoingSession = option2bool(kOptionAllowAutoRecordOutgoing, @@ -120,6 +123,8 @@ class _SettingsState extends State with WidgetsBindingObserver { _hideProxy = bind.mainGetBuildinOption(key: kOptionHideProxySetting) == 'Y'; _hideNetwork = bind.mainGetBuildinOption(key: kOptionHideNetworkSetting) == 'Y'; + _hideWebSocket = + true; //bind.mainGetBuildinOption(key: kOptionHideWebSocketSetting) == 'Y'; _enableTrustedDevices = mainGetBoolOptionSync(kOptionEnableTrustedDevices); } @@ -667,6 +672,21 @@ class _SettingsState extends State with WidgetsBindingObserver { onPressed: (context) { changeSocks5Proxy(); }), + if (!disabledSettings && !_hideNetwork && !_hideWebSocket) + SettingsTile.switchTile( + title: Text(translate('Use WebSocket')), + initialValue: _allowWebSocket, + onToggle: isOptionFixed(kOptionAllowWebSocket) + ? null + : (v) async { + await mainSetBoolOption(kOptionAllowWebSocket, v); + final newValue = + await mainGetBoolOption(kOptionAllowWebSocket); + setState(() { + _allowWebSocket = newValue; + }); + }, + ), SettingsTile( title: Text(translate('Language')), leading: Icon(Icons.translate), diff --git a/flutter/lib/models/web_model.dart b/flutter/lib/models/web_model.dart index a4312d959..7fd6993db 100644 --- a/flutter/lib/models/web_model.dart +++ b/flutter/lib/models/web_model.dart @@ -49,14 +49,15 @@ class PlatformFFI { } bool registerEventHandler( - String eventName, String handlerName, HandleEvent handler) { + String eventName, String handlerName, HandleEvent handler, + {bool replace = false}) { debugPrint('registerEventHandler $eventName $handlerName'); var handlers = _eventHandlers[eventName]; if (handlers == null) { _eventHandlers[eventName] = {handlerName: handler}; return true; } else { - if (handlers.containsKey(handlerName)) { + if (!replace && handlers.containsKey(handlerName)) { return false; } else { handlers[handlerName] = handler; diff --git a/flutter/lib/web/bridge.dart b/flutter/lib/web/bridge.dart index 331012aa9..d831e7bdc 100644 --- a/flutter/lib/web/bridge.dart +++ b/flutter/lib/web/bridge.dart @@ -1852,5 +1852,49 @@ class RustdeskImpl { throw UnimplementedError("sessionGetConnToken"); } + String mainGetPrinterNames({dynamic hint}) { + return ''; + } + + Future sessionPrinterResponse( + {required UuidValue sessionId, + required int id, + required String path, + required String printerName, + dynamic hint}) { + throw UnimplementedError("sessionPrinterResponse"); + } + + Future mainGetCommon({required String key, dynamic hint}) { + throw UnimplementedError("mainGetCommon"); + } + + String mainGetCommonSync({required String key, dynamic hint}) { + throw UnimplementedError("mainGetCommonSync"); + } + + Future mainSetCommon( + {required String key, required String value, dynamic hint}) { + throw UnimplementedError("mainSetCommon"); + } + + Future sessionHandleScreenshot( + {required UuidValue sessionId, required String action, dynamic hint}) { + throw UnimplementedError("sessionHandleScreenshot"); + } + + String? sessionGetCommonSync( + {required UuidValue sessionId, + required String key, + required String param, + dynamic hint}) { + throw UnimplementedError("sessionGetCommonSync"); + } + + Future sessionTakeScreenshot( + {required UuidValue sessionId, required int display, dynamic hint}) { + throw UnimplementedError("sessionTakeScreenshot"); + } + void dispose() {} } diff --git a/libs/hbb_common b/libs/hbb_common index d64954ae2..7839dcf4e 160000 --- a/libs/hbb_common +++ b/libs/hbb_common @@ -1 +1 @@ -Subproject commit d64954ae2211e5154fd9036ec4862413f24bbd7b +Subproject commit 7839dcf4e4ddc3feab9b52b0ae1903d443bc084d diff --git a/src/client.rs b/src/client.rs index 137701c54..1372f93eb 100644 --- a/src/client.rs +++ b/src/client.rs @@ -46,7 +46,7 @@ use hbb_common::{ anyhow::{anyhow, Context}, bail, config::{ - self, Config, LocalConfig, PeerConfig, PeerInfoSerde, Resolution, CONNECT_TIMEOUT, + self, use_ws, Config, LocalConfig, PeerConfig, PeerInfoSerde, Resolution, CONNECT_TIMEOUT, READ_TIMEOUT, RELAY_PORT, RENDEZVOUS_PORT, RENDEZVOUS_SERVERS, }, fs::JobType, @@ -216,7 +216,8 @@ impl Client { if hbb_common::is_ip_str(peer) { return Ok(( ( - connect_tcp(check_port(peer, RELAY_PORT + 1), CONNECT_TIMEOUT).await?, + connect_tcp_local(check_port(peer, RELAY_PORT + 1), None, CONNECT_TIMEOUT) + .await?, true, None, ), @@ -226,7 +227,11 @@ impl Client { // Allow connect to {domain}:{port} if hbb_common::is_domain_port_str(peer) { return Ok(( - (connect_tcp(peer, CONNECT_TIMEOUT).await?, true, None), + ( + connect_tcp_local(peer, None, CONNECT_TIMEOUT).await?, + true, + None, + ), (0, "".to_owned()), )); } @@ -291,7 +296,7 @@ impl Client { log::info!("#{} punch attempt with {}, id: {}", i, my_addr, peer); let mut msg_out = RendezvousMessage::new(); use hbb_common::protobuf::Enum; - let nat_type = if interface.is_force_relay() { + let nat_type = if interface.is_force_relay() || use_ws() || Config::is_proxy() { NatType::SYMMETRIC } else { NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT) diff --git a/src/common.rs b/src/common.rs index 61569eb05..2daf3aa25 100644 --- a/src/common.rs +++ b/src/common.rs @@ -14,7 +14,7 @@ use hbb_common::{ anyhow::{anyhow, Context}, bail, base64, bytes::Bytes, - config::{self, Config, CONNECT_TIMEOUT, READ_TIMEOUT, RENDEZVOUS_PORT}, + config::{self, use_ws, Config, CONNECT_TIMEOUT, READ_TIMEOUT, RENDEZVOUS_PORT}, futures::future::join_all, futures_util::future::poll_fn, get_version_number, log, @@ -504,6 +504,27 @@ audio_rechannel!(audio_rechannel_8_5, 8, 5); audio_rechannel!(audio_rechannel_8_6, 8, 6); audio_rechannel!(audio_rechannel_8_7, 8, 7); +pub struct CheckTestNatType { + is_direct: bool, +} + +impl CheckTestNatType { + pub fn new() -> Self { + Self { + is_direct: Config::get_socks().is_none() && !config::use_ws(), + } + } +} + +impl Drop for CheckTestNatType { + fn drop(&mut self) { + let is_direct = Config::get_socks().is_none() && !config::use_ws(); + if self.is_direct != is_direct { + test_nat_type(); + } + } +} + pub fn test_nat_type() { use std::sync::atomic::{AtomicBool, Ordering}; std::thread::spawn(move || { @@ -514,9 +535,8 @@ pub fn test_nat_type() { IS_RUNNING.store(true, Ordering::SeqCst); #[cfg(not(any(target_os = "android", target_os = "ios")))] - let is_direct = crate::ipc::get_socks().is_none(); // sync socks BTW - #[cfg(any(target_os = "android", target_os = "ios"))] - let is_direct = Config::get_socks().is_none(); // sync socks BTW + crate::ipc::get_socks_ws(); + let is_direct = Config::get_socks().is_none() && !config::use_ws(); if !is_direct { Config::set_nat_type(NatType::SYMMETRIC as _); IS_RUNNING.store(false, Ordering::SeqCst); @@ -1319,6 +1339,13 @@ pub fn check_process(arg: &str, mut same_uid: bool) -> bool { } pub async fn secure_tcp(conn: &mut Stream, key: &str) -> ResultType<()> { + // Skip additional encryption when using WebSocket connections (wss://) + // as WebSocket Secure (wss://) already provides transport layer encryption. + // This doesn't affect the end-to-end encryption between clients, + // it only avoids redundant encryption between client and server. + if use_ws() { + return Ok(()); + } let rs_pk = get_rs_pk(key); let Some(rs_pk) = rs_pk else { bail!("Handshake failed: invalid public key from rendezvous server"); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index c1c34ef82..254a119d5 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -891,7 +891,10 @@ pub fn main_set_option(key: String, value: String) { ); } - if key.eq("custom-rendezvous-server") { + if key.eq("custom-rendezvous-server") + || key.eq(config::keys::OPTION_ALLOW_WEBSOCKET) + || key.eq("api-server") + { set_option(key, value.clone()); #[cfg(target_os = "android")] crate::rendezvous_mediator::RendezvousMediator::restart(); @@ -2533,7 +2536,10 @@ pub fn main_set_common(_key: String, _value: String) { ); } else if _key == "update-me" { if let Some(new_version_file) = get_download_file_from_url(&_value) { - log::debug!("New version file is downloaed, update begin, {:?}", new_version_file.to_str()); + log::debug!( + "New version file is downloaed, update begin, {:?}", + new_version_file.to_str() + ); if let Some(f) = new_version_file.to_str() { // 1.4.0 does not support "--update" // But we can assume that the new version supports it. diff --git a/src/ipc.rs b/src/ipc.rs index 0b214efd3..a74a0c103 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,4 +1,5 @@ use crate::{ + common::CheckTestNatType, privacy_mode::PrivacyModeState, ui_interface::{get_local_option, set_local_option}, }; @@ -22,7 +23,7 @@ pub use clipboard::ClipboardFile; use hbb_common::{ allow_err, bail, bytes, bytes_codec::BytesCodec, - config::{self, Config, Config2}, + config::{self, keys::OPTION_ALLOW_WEBSOCKET, Config, Config2}, futures::StreamExt as _, futures_util::sink::SinkExt, log, password_security as password, timeout, @@ -282,6 +283,7 @@ pub enum Data { ControllingSessionCount(usize), #[cfg(target_os = "windows")] PortForwardSessionCount(Option), + SocksWs(Option, String)>>), } #[tokio::main(flavor = "current_thread")] @@ -348,29 +350,40 @@ pub async fn new_listener(postfix: &str) -> ResultType { } } -pub struct CheckIfRestart(String, Vec, String, String); +pub struct CheckIfRestart { + stop_service: String, + rendezvous_servers: Vec, + audio_input: String, + voice_call_input: String, + ws: String, + api_server: String, +} impl CheckIfRestart { pub fn new() -> CheckIfRestart { - CheckIfRestart( - Config::get_option("stop-service"), - Config::get_rendezvous_servers(), - Config::get_option("audio-input"), - Config::get_option("voice-call-input"), - ) + CheckIfRestart { + stop_service: Config::get_option("stop-service"), + rendezvous_servers: Config::get_rendezvous_servers(), + audio_input: Config::get_option("audio-input"), + voice_call_input: Config::get_option("voice-call-input"), + ws: Config::get_option(OPTION_ALLOW_WEBSOCKET), + api_server: Config::get_option("api-server"), + } } } impl Drop for CheckIfRestart { fn drop(&mut self) { - if self.0 != Config::get_option("stop-service") - || self.1 != Config::get_rendezvous_servers() + if self.stop_service != Config::get_option("stop-service") + || self.rendezvous_servers != Config::get_rendezvous_servers() + || self.ws != Config::get_option(OPTION_ALLOW_WEBSOCKET) + || self.api_server != Config::get_option("api-server") { RendezvousMediator::restart(); } - if self.2 != Config::get_option("audio-input") { + if self.audio_input != Config::get_option("audio-input") { crate::audio_service::restart(); } - if self.3 != Config::get_option("voice-call-input") { + if self.voice_call_input != Config::get_option("voice-call-input") { crate::audio_service::set_voice_call_input_device( Some(Config::get_option("voice-call-input")), true, @@ -455,16 +468,29 @@ async fn handle(data: Data, stream: &mut Connection) { allow_err!(stream.send(&Data::Socks(Config::get_socks())).await); } Some(data) => { + let _nat = CheckTestNatType::new(); if data.proxy.is_empty() { Config::set_socks(None); } else { Config::set_socks(Some(data)); } - crate::common::test_nat_type(); RendezvousMediator::restart(); log::info!("socks updated"); } }, + Data::SocksWs(s) => match s { + None => { + allow_err!( + stream + .send(&Data::SocksWs(Some(Box::new(( + Config::get_socks(), + Config::get_option(OPTION_ALLOW_WEBSOCKET) + ))))) + .await + ); + } + _ => {} + }, #[cfg(feature = "flutter")] Data::VideoConnCount(None) => { let n = crate::server::AUTHED_CONNS @@ -501,7 +527,8 @@ async fn handle(data: Data, stream: &mut Connection) { None }; } else if name == "hide_cm" { - value = if crate::hbbs_http::sync::is_pro() || crate::common::is_custom_client() { + value = if crate::hbbs_http::sync::is_pro() || crate::common::is_custom_client() + { Some(hbb_common::password_security::hide_cm().to_string()) } else { None @@ -544,6 +571,7 @@ async fn handle(data: Data, stream: &mut Connection) { } Some(value) => { let _chk = CheckIfRestart::new(); + let _nat = CheckTestNatType::new(); if let Some(v) = value.get("privacy-mode-impl-key") { crate::privacy_mode::switch(v); } @@ -1113,6 +1141,7 @@ pub fn set_option(key: &str, value: &str) { #[tokio::main(flavor = "current_thread")] pub async fn set_options(value: HashMap) -> ResultType<()> { + let _nat = CheckTestNatType::new(); if let Ok(mut c) = connect(1000, "").await { c.send(&Data::Options(Some(value.clone()))).await?; // do not put below before connect, because we need to check should_exit @@ -1170,6 +1199,7 @@ pub async fn get_socks() -> Option { #[tokio::main(flavor = "current_thread")] pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> { + let _nat = CheckTestNatType::new(); Config::set_socks(if value.proxy.is_empty() { None } else { @@ -1182,6 +1212,29 @@ pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> { Ok(()) } +async fn get_socks_ws_(ms_timeout: u64) -> ResultType<(Option, String)> { + let mut c = connect(ms_timeout, "").await?; + c.send(&Data::SocksWs(None)).await?; + if let Some(Data::SocksWs(Some(value))) = c.next_timeout(ms_timeout).await? { + Config::set_socks(value.0.clone()); + Config::set_option(OPTION_ALLOW_WEBSOCKET.to_string(), value.1.clone()); + Ok(*value) + } else { + Ok(( + Config::get_socks(), + Config::get_option(OPTION_ALLOW_WEBSOCKET), + )) + } +} + +#[tokio::main(flavor = "current_thread")] +pub async fn get_socks_ws() -> (Option, String) { + get_socks_ws_(1_000).await.unwrap_or(( + Config::get_socks(), + Config::get_option(OPTION_ALLOW_WEBSOCKET), + )) +} + pub fn get_proxy_status() -> bool { Config::get_socks().is_some() } diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 3469a5801..b1a3193e6 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/be.rs b/src/lang/be.rs index d6ac708d4..dbf4f2422 100644 --- a/src/lang/be.rs +++ b/src/lang/be.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/bg.rs b/src/lang/bg.rs index 4e52f1f97..8f6b4536b 100644 --- a/src/lang/bg.rs +++ b/src/lang/bg.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 78e5577ca..8609332a2 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 86cefbdf6..8842d2b9b 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", "下载失败,您可以重试或者点击\"下载\"按钮,从发布网址下载,并手动升级。"), ("Auto update", ""), ("update-failed-check-msi-tip", "安装方式检测失败。请点击\"下载\"按钮,从发布网址下载,并手动升级。"), + ("websocket_tip", "使用 WebSocket 时,仅支持中继连接。"), + ("Use WebSocket", "使用 WebSocket"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 9422a0a7c..3354ba0c7 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 90029b99e..d5f8abc1e 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 3b683dacf..46bd4c1be 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", "Download fehlgeschlagen. Sie können es erneut versuchen oder auf die Schaltfläche \"Herunterladen\" klicken, um von der Versionsseite herunterzuladen und manuell zu aktualisieren."), ("Auto update", "Automatisch aktualisieren"), ("update-failed-check-msi-tip", "Prüfung der Installationsmethode fehlgeschlagen. Bitte klicken Sie auf die Schaltfläche \"Herunterladen\", um von der Versionsseite herunterzuladen und manuell zu aktualisieren."), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index d58a80ae5..01043a7ef 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/en.rs b/src/lang/en.rs index 92b9697fb..d0ee84239 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -257,6 +257,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("screenshot-action-tip", "Please select how to continue with the screenshot."), ("{}-to-update-tip", "{} will close now and install the new version."), ("download-new-version-failed-tip", "Download failed. You can try again or click the \"Download\" button to download from the release page and upgrade manually."), - ("update-failed-check-msi-tip", "Installation method check failed. Please click the \"Download\" button to download from the release page and upgrade manually.") + ("update-failed-check-msi-tip", "Installation method check failed. Please click the \"Download\" button to download from the release page and upgrade manually."), + ("websocket_tip", "When using WebSocket, only relay connections are supported."), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 8070f4d57..e6e151e5e 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index a109a15e9..27c4847f3 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/et.rs b/src/lang/et.rs index e40fd32ea..28987fbe3 100644 --- a/src/lang/et.rs +++ b/src/lang/et.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eu.rs b/src/lang/eu.rs index d01796d38..01e1068da 100644 --- a/src/lang/eu.rs +++ b/src/lang/eu.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index f8df1f5df..bb43dad54 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 603c150d5..21668b7fb 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ge.rs b/src/lang/ge.rs index ce0ab2287..0d9f68539 100644 --- a/src/lang/ge.rs +++ b/src/lang/ge.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/he.rs b/src/lang/he.rs index 3448b50c8..37280449c 100644 --- a/src/lang/he.rs +++ b/src/lang/he.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hr.rs b/src/lang/hr.rs index ab4df6eec..8b782873c 100644 --- a/src/lang/hr.rs +++ b/src/lang/hr.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 8ca0cdaca..ee8f53734 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 540286494..ee796e42b 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 865b10b2b..0a10f658a 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", "Download non riuscito.\nÈ possibile riprovare o selezionare 'Download' per scaricare e aggiornarlo manualmente."), ("Auto update", "Aggiornamento automatico"), ("update-failed-check-msi-tip", "Controllo metodo installazione non riuscito.\nSeleziona 'Download' per scaricare il programma e aggiornarlo manualmente."), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index b8ff5687c..42eda1c68 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 2c1e4fe43..0dded1ff2 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", "새 버전 다운로드에 실패했습니다"), ("Auto update", "자동 업데이트"), ("update-failed-check-msi-tip", "업데이트에 실패했습니다. .msi 설치 파일을 확인하세요."), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 45323affc..a68f19c63 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index adf0cccd5..7fbf6eea4 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index eaacf7621..8057ac862 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nb.rs b/src/lang/nb.rs index af2355e2c..07ed5a45b 100644 --- a/src/lang/nb.rs +++ b/src/lang/nb.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 82f980d98..608fabbde 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", "Fout bij het downloaden. Je kunt het opnieuw proberen of op de knop Downloaden klikken om de applicatie van de officiële website te downloaden en handmatig bij te werken."), ("Auto update", "Automatisch updaten"), ("update-failed-check-msi-tip", "Kan de installatiemethode niet bepalen. Klik op “Downloaden” om de applicatie van de officiële website te downloaden en handmatig bij te werken."), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 3cb3f24b2..6ca59e54b 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", "Pobieranie nie powiodło się. Możesz spróbować ponownie lub kliknąć przycisk \"Pobierz\", aby pobrać ze strony programu i uaktualnić ręcznie."), ("Auto update", "Automatyczna aktualizacja"), ("update-failed-check-msi-tip", "Sprawdzenie metody instalacji nie powiodło się. Kliknij przycisk \"Pobierz\", aby pobrać ze strony wydania i uaktualnić ręcznie."), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 67ad3e876..9f8fae3b8 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index cc37de1d5..e6d94db56 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 18111c6b3..a0cc49c66 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 90e4cde98..35e387d98 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", "Ошибка загрузки. Можно повторить попытку или нажать кнопку \"Скачать\", чтобы скачать приложение с официального сайта и обновить вручную."), ("Auto update", "Автоматическое обновление"), ("update-failed-check-msi-tip", "Невозможно определить метод установки. Нажмите кнопку \"Скачать\", чтобы скачать приложение с официального сайта и обновить его вручную."), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sc.rs b/src/lang/sc.rs index c0372896b..10ea9c52b 100644 --- a/src/lang/sc.rs +++ b/src/lang/sc.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 9ca482d24..97b21eeec 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index fffa2283c..206fec074 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 6c318dbc3..834098067 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 241be0419..79f0f46bc 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 523e4cd41..a06dacc39 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ta.rs b/src/lang/ta.rs index 1ba56301b..37303d2df 100644 --- a/src/lang/ta.rs +++ b/src/lang/ta.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 1e94b8ce8..e956f8ab5 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 6e9676b4e..e8185a0c1 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 1d63e0ba2..0eabb55a8 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 87144d797..c10c132ee 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/uk.rs b/src/lang/uk.rs index dcc06684a..34b77415e 100644 --- a/src/lang/uk.rs +++ b/src/lang/uk.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 8ec202f05..0e9834416 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("download-new-version-failed-tip", ""), ("Auto update", ""), ("update-failed-check-msi-tip", ""), + ("websocket_tip", ""), + ("Use WebSocket", ""), ].iter().cloned().collect(); } diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index d53fd0e05..b8f3de408 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -12,7 +12,9 @@ use uuid::Uuid; use hbb_common::{ allow_err, anyhow::{self, bail}, - config::{self, keys::*, option2bool, Config, CONNECT_TIMEOUT, REG_INTERVAL, RENDEZVOUS_PORT}, + config::{ + self, keys::*, option2bool, use_ws, Config, CONNECT_TIMEOUT, REG_INTERVAL, RENDEZVOUS_PORT, + }, futures::future::join_all, log, protobuf::Message as _, @@ -139,6 +141,7 @@ impl RendezvousMediator { pub async fn start_udp(server: ServerPtr, host: String) -> ResultType<()> { let host = check_port(&host, RENDEZVOUS_PORT); + log::info!("start udp: {host}"); let (mut socket, mut addr) = socket_client::new_udp_for(&host, CONNECT_TIMEOUT).await?; let mut rz = Self { addr: addr.clone(), @@ -323,6 +326,7 @@ impl RendezvousMediator { pub async fn start_tcp(server: ServerPtr, host: String) -> ResultType<()> { let host = check_port(&host, RENDEZVOUS_PORT); + log::info!("start tcp: {}", hbb_common::websocket::check_ws(&host)); let mut conn = connect_tcp(host.clone(), CONNECT_TIMEOUT).await?; let key = crate::get_key(true).await; crate::secure_tcp(&mut conn, &key).await?; @@ -336,7 +340,7 @@ impl RendezvousMediator { let mut last_register_sent: Option = None; let mut last_recv_msg = Instant::now(); // we won't support connecting to multiple rendzvous servers any more, so we can use a global variable here. - Config::set_host_key_confirmed(&host, false); + Config::set_host_key_confirmed(&rz.host_prefix, false); loop { let mut update_latency = || { let latency = last_register_sent @@ -350,6 +354,8 @@ impl RendezvousMediator { last_recv_msg = Instant::now(); let bytes = res.ok_or_else(|| anyhow::anyhow!("Rendezvous connection is reset by the peer"))??; if bytes.is_empty() { + // After fixing frequent register_pk, for websocket, nginx need to set proxy_read_timeout to more than 60 seconds, eg: 120s + // https://serverfault.com/questions/1060525/why-is-my-websocket-connection-gets-closed-in-60-seconds conn.send_bytes(bytes::Bytes::new()).await?; continue; // heartbeat } @@ -365,7 +371,7 @@ impl RendezvousMediator { bail!("Rendezvous connection is timeout"); } if (!Config::get_key_confirmed() || - !Config::get_host_key_confirmed(&host)) && + !Config::get_host_key_confirmed(&rz.host_prefix)) && last_register_sent.map(|x| x.elapsed().as_millis() as i64).unwrap_or(REG_INTERVAL) >= REG_INTERVAL { rz.register_pk(Sink::Stream(&mut conn)).await?; last_register_sent = Some(Instant::now()); @@ -380,7 +386,8 @@ impl RendezvousMediator { log::info!("start rendezvous mediator of {}", host); //If the investment agent type is http or https, then tcp forwarding is enabled. if (cfg!(debug_assertions) && option_env!("TEST_TCP").is_some()) - || Config::is_proxy() + || Config::is_proxy() + || use_ws() || get_builtin_option(config::keys::OPTION_DISABLE_UDP) == "Y" { Self::start_tcp(server, host).await @@ -449,7 +456,12 @@ impl RendezvousMediator { async fn handle_intranet(&self, fla: FetchLocalAddr, server: ServerPtr) -> ResultType<()> { let relay_server = self.get_relay_server(fla.relay_server.clone()); // nat64, go relay directly, because current hbbs will crash if demangle ipv6 address - if is_ipv4(&self.addr) && !config::is_disable_tcp_listen() && !Config::is_proxy() { + // websocket, go relay directly + if is_ipv4(&self.addr) + && !config::is_disable_tcp_listen() + && !Config::is_proxy() + && !use_ws() + { if let Err(err) = self .handle_intranet_(fla.clone(), server.clone(), relay_server.clone()) .await @@ -501,9 +513,12 @@ impl RendezvousMediator { async fn handle_punch_hole(&self, ph: PunchHole, server: ServerPtr) -> ResultType<()> { let relay_server = self.get_relay_server(ph.relay_server); + // for ensure, websocket go relay directly if ph.nat_type.enum_value() == Ok(NatType::SYMMETRIC) || Config::get_nat_type() == NatType::SYMMETRIC as i32 || config::is_disable_tcp_listen() + || use_ws() + || Config::is_proxy() { let uuid = Uuid::new_v4().to_string(); return self diff --git a/src/ui/index.tis b/src/ui/index.tis index eb76c6754..fd5058544 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -325,6 +325,7 @@ class MyIdMenu: Reactor.Component {
  • {translate('ID/Relay Server')}
  • {translate('IP Whitelisting')}
  • {translate('Socks5 Proxy')}
  • + { false &&
  • {svg_checkmark}{translate('Use WebSocket')}
  • }
  • {svg_checkmark}{translate("Enable service")}
  • {is_win && handler.is_installed() ? : ""} diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 1aa4130de..b1ce62643 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -429,7 +429,10 @@ pub fn set_option(key: String, value: String) { ipc::set_options(options.clone()).ok(); } #[cfg(any(target_os = "android", target_os = "ios"))] - Config::set_option(key, value); + { + let _nat = crate::CheckTestNatType::new(); + Config::set_option(key, value); + } } #[inline] @@ -479,12 +482,12 @@ pub fn set_socks(proxy: String, username: String, password: String) { ipc::set_socks(socks).ok(); #[cfg(target_os = "android")] { + let _nat = crate::CheckTestNatType::new(); if socks.proxy.is_empty() { Config::set_socks(None); } else { Config::set_socks(Some(socks)); } - crate::common::test_nat_type(); crate::RendezvousMediator::restart(); log::info!("socks updated"); }