allow use websocket (#11677)
Some checks are pending
CI / x86_64-unknown-linux-gnu (ubuntu-22.04) (push) Waiting to run
Full Flutter CI / run-ci (push) Waiting to run

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 <sunboeasy@gmail.com>
This commit is contained in:
21pages 2025-05-09 12:18:49 +08:00 committed by GitHub
parent 86bbdf7a5d
commit 9475743b4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
61 changed files with 413 additions and 64 deletions

23
Cargo.lock generated
View file

@ -5724,7 +5724,7 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"webpki-roots", "webpki-roots 0.25.4",
"winreg 0.50.0", "winreg 0.50.0",
] ]
@ -7051,8 +7051,15 @@ checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"log", "log",
"native-tls",
"rustls 0.23.26",
"rustls-native-certs 0.8.1",
"rustls-pki-types",
"tokio", "tokio",
"tokio-native-tls",
"tokio-rustls 0.26.0",
"tungstenite", "tungstenite",
"webpki-roots 0.26.9",
] ]
[[package]] [[package]]
@ -7253,10 +7260,15 @@ dependencies = [
"http 1.3.1", "http 1.3.1",
"httparse", "httparse",
"log", "log",
"native-tls",
"rand 0.9.0", "rand 0.9.0",
"rustls 0.23.26",
"rustls-native-certs 0.8.1",
"rustls-pki-types",
"sha1", "sha1",
"thiserror 2.0.11", "thiserror 2.0.11",
"utf-8", "utf-8",
"webpki-roots 0.26.9",
] ]
[[package]] [[package]]
@ -7753,6 +7765,15 @@ version = "0.25.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" 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]] [[package]]
name = "weezl" name = "weezl"
version = "0.1.8" version = "0.1.8"

View file

@ -147,9 +147,13 @@ const String kOptionDirectxCapture = "enable-directx-capture";
const String kOptionAllowRemoteCmModification = "allow-remote-cm-modification"; const String kOptionAllowRemoteCmModification = "allow-remote-cm-modification";
const String kOptionEnableTrustedDevices = "enable-trusted-devices"; const String kOptionEnableTrustedDevices = "enable-trusted-devices";
// network options
const String kOptionAllowWebSocket = "allow-websocket";
// buildin opitons // buildin opitons
const String kOptionHideServerSetting = "hide-server-settings"; const String kOptionHideServerSetting = "hide-server-settings";
const String kOptionHideProxySetting = "hide-proxy-settings"; const String kOptionHideProxySetting = "hide-proxy-settings";
const String kOptionHideWebSocketSetting = "hide-websocket-settings";
const String kOptionHideRemotePrinterSetting = "hide-remote-printer-settings"; const String kOptionHideRemotePrinterSetting = "hide-remote-printer-settings";
const String kOptionHideSecuritySetting = "hide-security-settings"; const String kOptionHideSecuritySetting = "hide-security-settings";
const String kOptionHideNetworkSetting = "hide-network-settings"; const String kOptionHideNetworkSetting = "hide-network-settings";

View file

@ -1475,11 +1475,70 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin {
bind.mainGetBuildinOption(key: kOptionHideServerSetting) == 'Y'; bind.mainGetBuildinOption(key: kOptionHideServerSetting) == 'Y';
final hideProxy = final hideProxy =
isWeb || bind.mainGetBuildinOption(key: kOptionHideProxySetting) == 'Y'; 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(); 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( return _Card(
title: 'Network', title: 'Network',
children: [ children: [
@ -1488,39 +1547,36 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (!hideServer) if (!hideServer)
ListTile( listTile(
leading: Icon(Icons.dns_outlined, color: _accentColor), icon: Icons.dns_outlined,
title: Text( title: 'ID/Relay Server',
translate('ID/Relay Server'),
style: TextStyle(fontSize: _kContentFontSize),
),
enabled: !locked,
onTap: () => showServerSettings(gFFI.dialogManager), 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), Divider(height: 1, indent: 16, endIndent: 16),
if (!hideProxy) if (!hideProxy)
ListTile( listTile(
leading: icon: Icons.network_ping_outlined,
Icon(Icons.network_ping_outlined, color: _accentColor), title: 'Socks5/Http(s) Proxy',
title: Text(
translate('Socks5/Http(s) Proxy'),
style: TextStyle(fontSize: _kContentFontSize),
),
enabled: !locked,
onTap: changeSocks5Proxy, 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,
), ),
], ],
), ),

View file

@ -80,6 +80,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
var _enableDirectIPAccess = false; var _enableDirectIPAccess = false;
var _enableRecordSession = false; var _enableRecordSession = false;
var _enableHardwareCodec = false; var _enableHardwareCodec = false;
var _allowWebSocket = false;
var _autoRecordIncomingSession = false; var _autoRecordIncomingSession = false;
var _autoRecordOutgoingSession = false; var _autoRecordOutgoingSession = false;
var _allowAutoDisconnect = false; var _allowAutoDisconnect = false;
@ -91,6 +92,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
var _hideServer = false; var _hideServer = false;
var _hideProxy = false; var _hideProxy = false;
var _hideNetwork = false; var _hideNetwork = false;
var _hideWebSocket = false;
var _enableTrustedDevices = false; var _enableTrustedDevices = false;
_SettingsState() { _SettingsState() {
@ -105,6 +107,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
bind.mainGetOptionSync(key: kOptionEnableRecordSession)); bind.mainGetOptionSync(key: kOptionEnableRecordSession));
_enableHardwareCodec = option2bool(kOptionEnableHwcodec, _enableHardwareCodec = option2bool(kOptionEnableHwcodec,
bind.mainGetOptionSync(key: kOptionEnableHwcodec)); bind.mainGetOptionSync(key: kOptionEnableHwcodec));
_allowWebSocket = mainGetBoolOptionSync(kOptionAllowWebSocket);
_autoRecordIncomingSession = option2bool(kOptionAllowAutoRecordIncoming, _autoRecordIncomingSession = option2bool(kOptionAllowAutoRecordIncoming,
bind.mainGetOptionSync(key: kOptionAllowAutoRecordIncoming)); bind.mainGetOptionSync(key: kOptionAllowAutoRecordIncoming));
_autoRecordOutgoingSession = option2bool(kOptionAllowAutoRecordOutgoing, _autoRecordOutgoingSession = option2bool(kOptionAllowAutoRecordOutgoing,
@ -120,6 +123,8 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
_hideProxy = bind.mainGetBuildinOption(key: kOptionHideProxySetting) == 'Y'; _hideProxy = bind.mainGetBuildinOption(key: kOptionHideProxySetting) == 'Y';
_hideNetwork = _hideNetwork =
bind.mainGetBuildinOption(key: kOptionHideNetworkSetting) == 'Y'; bind.mainGetBuildinOption(key: kOptionHideNetworkSetting) == 'Y';
_hideWebSocket =
true; //bind.mainGetBuildinOption(key: kOptionHideWebSocketSetting) == 'Y';
_enableTrustedDevices = mainGetBoolOptionSync(kOptionEnableTrustedDevices); _enableTrustedDevices = mainGetBoolOptionSync(kOptionEnableTrustedDevices);
} }
@ -667,6 +672,21 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
onPressed: (context) { onPressed: (context) {
changeSocks5Proxy(); 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( SettingsTile(
title: Text(translate('Language')), title: Text(translate('Language')),
leading: Icon(Icons.translate), leading: Icon(Icons.translate),

View file

@ -49,14 +49,15 @@ class PlatformFFI {
} }
bool registerEventHandler( bool registerEventHandler(
String eventName, String handlerName, HandleEvent handler) { String eventName, String handlerName, HandleEvent handler,
{bool replace = false}) {
debugPrint('registerEventHandler $eventName $handlerName'); debugPrint('registerEventHandler $eventName $handlerName');
var handlers = _eventHandlers[eventName]; var handlers = _eventHandlers[eventName];
if (handlers == null) { if (handlers == null) {
_eventHandlers[eventName] = {handlerName: handler}; _eventHandlers[eventName] = {handlerName: handler};
return true; return true;
} else { } else {
if (handlers.containsKey(handlerName)) { if (!replace && handlers.containsKey(handlerName)) {
return false; return false;
} else { } else {
handlers[handlerName] = handler; handlers[handlerName] = handler;

View file

@ -1852,5 +1852,49 @@ class RustdeskImpl {
throw UnimplementedError("sessionGetConnToken"); throw UnimplementedError("sessionGetConnToken");
} }
String mainGetPrinterNames({dynamic hint}) {
return '';
}
Future<void> sessionPrinterResponse(
{required UuidValue sessionId,
required int id,
required String path,
required String printerName,
dynamic hint}) {
throw UnimplementedError("sessionPrinterResponse");
}
Future<String> mainGetCommon({required String key, dynamic hint}) {
throw UnimplementedError("mainGetCommon");
}
String mainGetCommonSync({required String key, dynamic hint}) {
throw UnimplementedError("mainGetCommonSync");
}
Future<void> mainSetCommon(
{required String key, required String value, dynamic hint}) {
throw UnimplementedError("mainSetCommon");
}
Future<String> 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<void> sessionTakeScreenshot(
{required UuidValue sessionId, required int display, dynamic hint}) {
throw UnimplementedError("sessionTakeScreenshot");
}
void dispose() {} void dispose() {}
} }

@ -1 +1 @@
Subproject commit d64954ae2211e5154fd9036ec4862413f24bbd7b Subproject commit 7839dcf4e4ddc3feab9b52b0ae1903d443bc084d

View file

@ -46,7 +46,7 @@ use hbb_common::{
anyhow::{anyhow, Context}, anyhow::{anyhow, Context},
bail, bail,
config::{ 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, READ_TIMEOUT, RELAY_PORT, RENDEZVOUS_PORT, RENDEZVOUS_SERVERS,
}, },
fs::JobType, fs::JobType,
@ -216,7 +216,8 @@ impl Client {
if hbb_common::is_ip_str(peer) { if hbb_common::is_ip_str(peer) {
return Ok(( 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, true,
None, None,
), ),
@ -226,7 +227,11 @@ impl Client {
// Allow connect to {domain}:{port} // Allow connect to {domain}:{port}
if hbb_common::is_domain_port_str(peer) { if hbb_common::is_domain_port_str(peer) {
return Ok(( return Ok((
(connect_tcp(peer, CONNECT_TIMEOUT).await?, true, None), (
connect_tcp_local(peer, None, CONNECT_TIMEOUT).await?,
true,
None,
),
(0, "".to_owned()), (0, "".to_owned()),
)); ));
} }
@ -291,7 +296,7 @@ impl Client {
log::info!("#{} punch attempt with {}, id: {}", i, my_addr, peer); log::info!("#{} punch attempt with {}, id: {}", i, my_addr, peer);
let mut msg_out = RendezvousMessage::new(); let mut msg_out = RendezvousMessage::new();
use hbb_common::protobuf::Enum; 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 NatType::SYMMETRIC
} else { } else {
NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT) NatType::from_i32(my_nat_type).unwrap_or(NatType::UNKNOWN_NAT)

View file

@ -14,7 +14,7 @@ use hbb_common::{
anyhow::{anyhow, Context}, anyhow::{anyhow, Context},
bail, base64, bail, base64,
bytes::Bytes, 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::future::join_all,
futures_util::future::poll_fn, futures_util::future::poll_fn,
get_version_number, log, 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_6, 8, 6);
audio_rechannel!(audio_rechannel_8_7, 8, 7); 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() { pub fn test_nat_type() {
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
std::thread::spawn(move || { std::thread::spawn(move || {
@ -514,9 +535,8 @@ pub fn test_nat_type() {
IS_RUNNING.store(true, Ordering::SeqCst); IS_RUNNING.store(true, Ordering::SeqCst);
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
let is_direct = crate::ipc::get_socks().is_none(); // sync socks BTW crate::ipc::get_socks_ws();
#[cfg(any(target_os = "android", target_os = "ios"))] let is_direct = Config::get_socks().is_none() && !config::use_ws();
let is_direct = Config::get_socks().is_none(); // sync socks BTW
if !is_direct { if !is_direct {
Config::set_nat_type(NatType::SYMMETRIC as _); Config::set_nat_type(NatType::SYMMETRIC as _);
IS_RUNNING.store(false, Ordering::SeqCst); 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<()> { 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 rs_pk = get_rs_pk(key);
let Some(rs_pk) = rs_pk else { let Some(rs_pk) = rs_pk else {
bail!("Handshake failed: invalid public key from rendezvous server"); bail!("Handshake failed: invalid public key from rendezvous server");

View file

@ -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()); set_option(key, value.clone());
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
crate::rendezvous_mediator::RendezvousMediator::restart(); crate::rendezvous_mediator::RendezvousMediator::restart();
@ -2533,7 +2536,10 @@ pub fn main_set_common(_key: String, _value: String) {
); );
} else if _key == "update-me" { } else if _key == "update-me" {
if let Some(new_version_file) = get_download_file_from_url(&_value) { 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() { if let Some(f) = new_version_file.to_str() {
// 1.4.0 does not support "--update" // 1.4.0 does not support "--update"
// But we can assume that the new version supports it. // But we can assume that the new version supports it.

View file

@ -1,4 +1,5 @@
use crate::{ use crate::{
common::CheckTestNatType,
privacy_mode::PrivacyModeState, privacy_mode::PrivacyModeState,
ui_interface::{get_local_option, set_local_option}, ui_interface::{get_local_option, set_local_option},
}; };
@ -22,7 +23,7 @@ pub use clipboard::ClipboardFile;
use hbb_common::{ use hbb_common::{
allow_err, bail, bytes, allow_err, bail, bytes,
bytes_codec::BytesCodec, bytes_codec::BytesCodec,
config::{self, Config, Config2}, config::{self, keys::OPTION_ALLOW_WEBSOCKET, Config, Config2},
futures::StreamExt as _, futures::StreamExt as _,
futures_util::sink::SinkExt, futures_util::sink::SinkExt,
log, password_security as password, timeout, log, password_security as password, timeout,
@ -282,6 +283,7 @@ pub enum Data {
ControllingSessionCount(usize), ControllingSessionCount(usize),
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
PortForwardSessionCount(Option<usize>), PortForwardSessionCount(Option<usize>),
SocksWs(Option<Box<(Option<config::Socks5Server>, String)>>),
} }
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
@ -348,29 +350,40 @@ pub async fn new_listener(postfix: &str) -> ResultType<Incoming> {
} }
} }
pub struct CheckIfRestart(String, Vec<String>, String, String); pub struct CheckIfRestart {
stop_service: String,
rendezvous_servers: Vec<String>,
audio_input: String,
voice_call_input: String,
ws: String,
api_server: String,
}
impl CheckIfRestart { impl CheckIfRestart {
pub fn new() -> CheckIfRestart { pub fn new() -> CheckIfRestart {
CheckIfRestart( CheckIfRestart {
Config::get_option("stop-service"), stop_service: Config::get_option("stop-service"),
Config::get_rendezvous_servers(), rendezvous_servers: Config::get_rendezvous_servers(),
Config::get_option("audio-input"), audio_input: Config::get_option("audio-input"),
Config::get_option("voice-call-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 { impl Drop for CheckIfRestart {
fn drop(&mut self) { fn drop(&mut self) {
if self.0 != Config::get_option("stop-service") if self.stop_service != Config::get_option("stop-service")
|| self.1 != Config::get_rendezvous_servers() || 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(); RendezvousMediator::restart();
} }
if self.2 != Config::get_option("audio-input") { if self.audio_input != Config::get_option("audio-input") {
crate::audio_service::restart(); 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( crate::audio_service::set_voice_call_input_device(
Some(Config::get_option("voice-call-input")), Some(Config::get_option("voice-call-input")),
true, true,
@ -455,16 +468,29 @@ async fn handle(data: Data, stream: &mut Connection) {
allow_err!(stream.send(&Data::Socks(Config::get_socks())).await); allow_err!(stream.send(&Data::Socks(Config::get_socks())).await);
} }
Some(data) => { Some(data) => {
let _nat = CheckTestNatType::new();
if data.proxy.is_empty() { if data.proxy.is_empty() {
Config::set_socks(None); Config::set_socks(None);
} else { } else {
Config::set_socks(Some(data)); Config::set_socks(Some(data));
} }
crate::common::test_nat_type();
RendezvousMediator::restart(); RendezvousMediator::restart();
log::info!("socks updated"); 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")] #[cfg(feature = "flutter")]
Data::VideoConnCount(None) => { Data::VideoConnCount(None) => {
let n = crate::server::AUTHED_CONNS let n = crate::server::AUTHED_CONNS
@ -501,7 +527,8 @@ async fn handle(data: Data, stream: &mut Connection) {
None None
}; };
} else if name == "hide_cm" { } 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()) Some(hbb_common::password_security::hide_cm().to_string())
} else { } else {
None None
@ -544,6 +571,7 @@ async fn handle(data: Data, stream: &mut Connection) {
} }
Some(value) => { Some(value) => {
let _chk = CheckIfRestart::new(); let _chk = CheckIfRestart::new();
let _nat = CheckTestNatType::new();
if let Some(v) = value.get("privacy-mode-impl-key") { if let Some(v) = value.get("privacy-mode-impl-key") {
crate::privacy_mode::switch(v); crate::privacy_mode::switch(v);
} }
@ -1113,6 +1141,7 @@ pub fn set_option(key: &str, value: &str) {
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
pub async fn set_options(value: HashMap<String, String>) -> ResultType<()> { pub async fn set_options(value: HashMap<String, String>) -> ResultType<()> {
let _nat = CheckTestNatType::new();
if let Ok(mut c) = connect(1000, "").await { if let Ok(mut c) = connect(1000, "").await {
c.send(&Data::Options(Some(value.clone()))).await?; c.send(&Data::Options(Some(value.clone()))).await?;
// do not put below before connect, because we need to check should_exit // do not put below before connect, because we need to check should_exit
@ -1170,6 +1199,7 @@ pub async fn get_socks() -> Option<config::Socks5Server> {
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> { pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> {
let _nat = CheckTestNatType::new();
Config::set_socks(if value.proxy.is_empty() { Config::set_socks(if value.proxy.is_empty() {
None None
} else { } else {
@ -1182,6 +1212,29 @@ pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> {
Ok(()) Ok(())
} }
async fn get_socks_ws_(ms_timeout: u64) -> ResultType<(Option<config::Socks5Server>, 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<config::Socks5Server>, String) {
get_socks_ws_(1_000).await.unwrap_or((
Config::get_socks(),
Config::get_option(OPTION_ALLOW_WEBSOCKET),
))
}
pub fn get_proxy_status() -> bool { pub fn get_proxy_status() -> bool {
Config::get_socks().is_some() Config::get_socks().is_some()
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", "下载失败,您可以重试或者点击\"下载\"按钮,从发布网址下载,并手动升级。"), ("download-new-version-failed-tip", "下载失败,您可以重试或者点击\"下载\"按钮,从发布网址下载,并手动升级。"),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", "安装方式检测失败。请点击\"下载\"按钮,从发布网址下载,并手动升级。"), ("update-failed-check-msi-tip", "安装方式检测失败。请点击\"下载\"按钮,从发布网址下载,并手动升级。"),
("websocket_tip", "使用 WebSocket 时,仅支持中继连接。"),
("Use WebSocket", "使用 WebSocket"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -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."), ("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"), ("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."), ("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(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -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."), ("screenshot-action-tip", "Please select how to continue with the screenshot."),
("{}-to-update-tip", "{} will close now and install the new version."), ("{}-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."), ("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(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -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."), ("download-new-version-failed-tip", "Download non riuscito.\nÈ possibile riprovare o selezionare 'Download' per scaricare e aggiornarlo manualmente."),
("Auto update", "Aggiornamento automatico"), ("Auto update", "Aggiornamento automatico"),
("update-failed-check-msi-tip", "Controllo metodo installazione non riuscito.\nSeleziona 'Download' per scaricare il programma e aggiornarlo manualmente."), ("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(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", "새 버전 다운로드에 실패했습니다"), ("download-new-version-failed-tip", "새 버전 다운로드에 실패했습니다"),
("Auto update", "자동 업데이트"), ("Auto update", "자동 업데이트"),
("update-failed-check-msi-tip", "업데이트에 실패했습니다. .msi 설치 파일을 확인하세요."), ("update-failed-check-msi-tip", "업데이트에 실패했습니다. .msi 설치 파일을 확인하세요."),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -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."), ("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"), ("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."), ("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(); ].iter().cloned().collect();
} }

View file

@ -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."), ("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"), ("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."), ("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(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", "Ошибка загрузки. Можно повторить попытку или нажать кнопку \"Скачать\", чтобы скачать приложение с официального сайта и обновить вручную."), ("download-new-version-failed-tip", "Ошибка загрузки. Можно повторить попытку или нажать кнопку \"Скачать\", чтобы скачать приложение с официального сайта и обновить вручную."),
("Auto update", "Автоматическое обновление"), ("Auto update", "Автоматическое обновление"),
("update-failed-check-msi-tip", "Невозможно определить метод установки. Нажмите кнопку \"Скачать\", чтобы скачать приложение с официального сайта и обновить его вручную."), ("update-failed-check-msi-tip", "Невозможно определить метод установки. Нажмите кнопку \"Скачать\", чтобы скачать приложение с официального сайта и обновить его вручную."),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -694,5 +694,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("download-new-version-failed-tip", ""), ("download-new-version-failed-tip", ""),
("Auto update", ""), ("Auto update", ""),
("update-failed-check-msi-tip", ""), ("update-failed-check-msi-tip", ""),
("websocket_tip", ""),
("Use WebSocket", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View file

@ -12,7 +12,9 @@ use uuid::Uuid;
use hbb_common::{ use hbb_common::{
allow_err, allow_err,
anyhow::{self, bail}, 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, futures::future::join_all,
log, log,
protobuf::Message as _, protobuf::Message as _,
@ -139,6 +141,7 @@ impl RendezvousMediator {
pub async fn start_udp(server: ServerPtr, host: String) -> ResultType<()> { pub async fn start_udp(server: ServerPtr, host: String) -> ResultType<()> {
let host = check_port(&host, RENDEZVOUS_PORT); 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 socket, mut addr) = socket_client::new_udp_for(&host, CONNECT_TIMEOUT).await?;
let mut rz = Self { let mut rz = Self {
addr: addr.clone(), addr: addr.clone(),
@ -323,6 +326,7 @@ impl RendezvousMediator {
pub async fn start_tcp(server: ServerPtr, host: String) -> ResultType<()> { pub async fn start_tcp(server: ServerPtr, host: String) -> ResultType<()> {
let host = check_port(&host, RENDEZVOUS_PORT); 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 mut conn = connect_tcp(host.clone(), CONNECT_TIMEOUT).await?;
let key = crate::get_key(true).await; let key = crate::get_key(true).await;
crate::secure_tcp(&mut conn, &key).await?; crate::secure_tcp(&mut conn, &key).await?;
@ -336,7 +340,7 @@ impl RendezvousMediator {
let mut last_register_sent: Option<Instant> = None; let mut last_register_sent: Option<Instant> = None;
let mut last_recv_msg = Instant::now(); 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. // 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 { loop {
let mut update_latency = || { let mut update_latency = || {
let latency = last_register_sent let latency = last_register_sent
@ -350,6 +354,8 @@ impl RendezvousMediator {
last_recv_msg = Instant::now(); last_recv_msg = Instant::now();
let bytes = res.ok_or_else(|| anyhow::anyhow!("Rendezvous connection is reset by the peer"))??; let bytes = res.ok_or_else(|| anyhow::anyhow!("Rendezvous connection is reset by the peer"))??;
if bytes.is_empty() { 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?; conn.send_bytes(bytes::Bytes::new()).await?;
continue; // heartbeat continue; // heartbeat
} }
@ -365,7 +371,7 @@ impl RendezvousMediator {
bail!("Rendezvous connection is timeout"); bail!("Rendezvous connection is timeout");
} }
if (!Config::get_key_confirmed() || 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 { 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?; rz.register_pk(Sink::Stream(&mut conn)).await?;
last_register_sent = Some(Instant::now()); last_register_sent = Some(Instant::now());
@ -381,6 +387,7 @@ impl RendezvousMediator {
//If the investment agent type is http or https, then tcp forwarding is enabled. //If the investment agent type is http or https, then tcp forwarding is enabled.
if (cfg!(debug_assertions) && option_env!("TEST_TCP").is_some()) 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" || get_builtin_option(config::keys::OPTION_DISABLE_UDP) == "Y"
{ {
Self::start_tcp(server, host).await Self::start_tcp(server, host).await
@ -449,7 +456,12 @@ impl RendezvousMediator {
async fn handle_intranet(&self, fla: FetchLocalAddr, server: ServerPtr) -> ResultType<()> { async fn handle_intranet(&self, fla: FetchLocalAddr, server: ServerPtr) -> ResultType<()> {
let relay_server = self.get_relay_server(fla.relay_server.clone()); let relay_server = self.get_relay_server(fla.relay_server.clone());
// nat64, go relay directly, because current hbbs will crash if demangle ipv6 address // 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 if let Err(err) = self
.handle_intranet_(fla.clone(), server.clone(), relay_server.clone()) .handle_intranet_(fla.clone(), server.clone(), relay_server.clone())
.await .await
@ -501,9 +513,12 @@ impl RendezvousMediator {
async fn handle_punch_hole(&self, ph: PunchHole, server: ServerPtr) -> ResultType<()> { async fn handle_punch_hole(&self, ph: PunchHole, server: ServerPtr) -> ResultType<()> {
let relay_server = self.get_relay_server(ph.relay_server); 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) if ph.nat_type.enum_value() == Ok(NatType::SYMMETRIC)
|| Config::get_nat_type() == NatType::SYMMETRIC as i32 || Config::get_nat_type() == NatType::SYMMETRIC as i32
|| config::is_disable_tcp_listen() || config::is_disable_tcp_listen()
|| use_ws()
|| Config::is_proxy()
{ {
let uuid = Uuid::new_v4().to_string(); let uuid = Uuid::new_v4().to_string();
return self return self

View file

@ -325,6 +325,7 @@ class MyIdMenu: Reactor.Component {
<li #custom-server>{translate('ID/Relay Server')}</li> <li #custom-server>{translate('ID/Relay Server')}</li>
<li #whitelist title={translate('whitelist_tip')}>{translate('IP Whitelisting')}</li> <li #whitelist title={translate('whitelist_tip')}>{translate('IP Whitelisting')}</li>
<li #socks5-server>{translate('Socks5 Proxy')}</li> <li #socks5-server>{translate('Socks5 Proxy')}</li>
{ false && <li #allow-websocket><span>{svg_checkmark}</span>{translate('Use WebSocket')}</li> }
<div .separator /> <div .separator />
<li #stop-service class={service_stopped ? "line-through" : "selected"}><span>{svg_checkmark}</span>{translate("Enable service")}</li> <li #stop-service class={service_stopped ? "line-through" : "selected"}><span>{svg_checkmark}</span>{translate("Enable service")}</li>
{is_win && handler.is_installed() ? <ShareRdp /> : ""} {is_win && handler.is_installed() ? <ShareRdp /> : ""}

View file

@ -429,7 +429,10 @@ pub fn set_option(key: String, value: String) {
ipc::set_options(options.clone()).ok(); ipc::set_options(options.clone()).ok();
} }
#[cfg(any(target_os = "android", target_os = "ios"))] #[cfg(any(target_os = "android", target_os = "ios"))]
Config::set_option(key, value); {
let _nat = crate::CheckTestNatType::new();
Config::set_option(key, value);
}
} }
#[inline] #[inline]
@ -479,12 +482,12 @@ pub fn set_socks(proxy: String, username: String, password: String) {
ipc::set_socks(socks).ok(); ipc::set_socks(socks).ok();
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
{ {
let _nat = crate::CheckTestNatType::new();
if socks.proxy.is_empty() { if socks.proxy.is_empty() {
Config::set_socks(None); Config::set_socks(None);
} else { } else {
Config::set_socks(Some(socks)); Config::set_socks(Some(socks));
} }
crate::common::test_nat_type();
crate::RendezvousMediator::restart(); crate::RendezvousMediator::restart();
log::info!("socks updated"); log::info!("socks updated");
} }