diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 1fa3255c9..74d993a64 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -350,7 +350,7 @@ class FfiModel with ChangeNotifier { } else if (type == 'elevation-error') { showElevationError(sessionId, type, title, text, dialogManager); } else if (type == 'relay-hint') { - showRelayHintDialog(sessionId, type, title, text, dialogManager); + showRelayHintDialog(sessionId, type, title, text, dialogManager, peerId); } else { var hasRetry = evt['hasRetry'] == 'true'; showMsgBox(sessionId, type, title, text, link, hasRetry, dialogManager); @@ -383,7 +383,7 @@ class FfiModel with ChangeNotifier { } void showRelayHintDialog(SessionID sessionId, String type, String title, - String text, OverlayDialogManager dialogManager) { + String text, OverlayDialogManager dialogManager, String peerId) { dialogManager.show(tag: '$sessionId-$type', (setState, close, context) { onClose() { closeConnection(); @@ -392,25 +392,24 @@ class FfiModel with ChangeNotifier { final style = ElevatedButton.styleFrom(backgroundColor: Colors.green[700]); + var hint = "\n\n${translate('relay_hint_tip')}"; + if (text.contains("10054") || text.contains("104")) { + hint = ""; + } + final alreadyForceAlwaysRelay = bind + .mainGetPeerOptionSync(id: peerId, key: 'force-always-relay') + .isNotEmpty; return CustomAlertDialog( title: null, - content: msgboxContent(type, title, - "${translate(text)}\n\n${translate('relay_hint_tip')}"), + content: msgboxContent(type, title, "${translate(text)}$hint"), actions: [ dialogButton('Close', onPressed: onClose, isOutline: true), dialogButton('Retry', onPressed: () => reconnect(dialogManager, sessionId, false)), - dialogButton('Connect via relay', - onPressed: () => reconnect(dialogManager, sessionId, true), - buttonStyle: style), - dialogButton('Always connect via relay', onPressed: () { - const option = 'force-always-relay'; - bind.sessionPeerOption( - sessionId: sessionId, - name: option, - value: bool2option(option, true)); - reconnect(dialogManager, sessionId, true); - }, buttonStyle: style), + if (!alreadyForceAlwaysRelay) + dialogButton('Connect via relay', + onPressed: () => reconnect(dialogManager, sessionId, true), + buttonStyle: style), ], onCancel: onClose, ); diff --git a/src/client.rs b/src/client.rs index a0a5e6cc0..281f1bb63 100644 --- a/src/client.rs +++ b/src/client.rs @@ -213,6 +213,8 @@ impl Client { conn_type: ConnType, interface: impl Interface, ) -> ResultType<(Stream, bool, Option>)> { + interface.update_direct(None); + interface.update_received(false); match Self::_start(peer, key, token, conn_type, interface).await { Err(err) => { let err_str = err.to_string(); @@ -353,15 +355,8 @@ impl Client { my_addr.is_ipv4(), ) .await?; - let pk = Self::secure_connection( - peer, - signed_id_pk, - key, - &mut conn, - false, - interface, - ) - .await?; + let pk = + Self::secure_connection(peer, signed_id_pk, key, &mut conn).await?; return Ok((conn, false, pk)); } _ => { @@ -459,6 +454,7 @@ impl Client { let mut conn = socket_client::connect_tcp_local(peer, Some(local_addr), connect_timeout).await; let mut direct = !conn.is_err(); + interface.update_direct(Some(direct)); if interface.is_force_relay() || conn.is_err() { if !relay_server.is_empty() { conn = Self::request_relay( @@ -471,6 +467,7 @@ impl Client { conn_type, ) .await; + interface.update_direct(Some(false)); if conn.is_err() { bail!( "Failed to connect via relay server: {}", @@ -490,8 +487,7 @@ impl Client { } let mut conn = conn?; log::info!("{:?} used to establish connection", start.elapsed()); - let pk = Self::secure_connection(peer_id, signed_id_pk, key, &mut conn, direct, interface) - .await?; + let pk = Self::secure_connection(peer_id, signed_id_pk, key, &mut conn).await?; Ok((conn, direct, pk)) } @@ -501,8 +497,6 @@ impl Client { signed_id_pk: Vec, key: &str, conn: &mut Stream, - direct: bool, - interface: impl Interface, ) -> ResultType>> { let rs_pk = get_rs_pk(if key.is_empty() { hbb_common::config::RS_PUB_KEY @@ -532,13 +526,7 @@ impl Client { }; match timeout(READ_TIMEOUT, conn.next()).await? { Some(res) => { - let bytes = match res { - Ok(bytes) => bytes, - Err(err) => { - interface.set_force_relay(direct, false, err.to_string()); - bail!("{}", err); - } - }; + let bytes = res?; if let Ok(msg_in) = Message::parse_from_bytes(&bytes) { if let Some(message::Union::SignedId(si)) = msg_in.union { if let Ok((id, their_pk_b)) = decode_id_pk(&si.id, &sign_pk) { @@ -1082,8 +1070,6 @@ pub struct LoginConfigHandler { pub direct: Option, pub received: bool, switch_uuid: Option, - pub success_time: Option, - pub direct_error_counter: usize, } impl Deref for LoginConfigHandler { @@ -1130,8 +1116,6 @@ impl LoginConfigHandler { self.direct = None; self.received = false; self.switch_uuid = switch_uuid; - self.success_time = None; - self.direct_error_counter = 0; } /// Check if the client should auto login. @@ -1759,20 +1743,6 @@ impl LoginConfigHandler { msg_out.set_misc(misc); msg_out } - - pub fn set_force_relay(&mut self, direct: bool, received: bool, err: String) { - self.force_relay = false; - if direct && !received { - let errno = errno::errno().0; - // TODO: check mac and ios - if cfg!(windows) && (errno == 10054 || err.contains("10054")) - || !cfg!(windows) && (errno == 104 || err.contains("104")) - { - self.force_relay = true; - self.set_option("force-always-relay".to_owned(), "Y".to_owned()); - } - } - } } /// Media data. @@ -2317,16 +2287,48 @@ pub trait Interface: Send + Clone + 'static + Sized { async fn handle_test_delay(&mut self, t: TestDelay, peer: &mut Stream); fn get_login_config_handler(&self) -> Arc>; - fn set_force_relay(&self, direct: bool, received: bool, err: String) { - self.get_login_config_handler() - .write() - .unwrap() - .set_force_relay(direct, received, err); - } + fn is_force_relay(&self) -> bool { self.get_login_config_handler().read().unwrap().force_relay } fn swap_modifier_mouse(&self, _msg: &mut hbb_common::protos::message::MouseEvent) {} + + fn update_direct(&self, direct: Option) { + self.get_login_config_handler().write().unwrap().direct = direct; + } + + fn update_received(&self, received: bool) { + self.get_login_config_handler().write().unwrap().received = received; + } + + fn on_establish_connection_error(&self, err: String) { + log::error!("Connection closed: {}", err); + let title = "Connection Error"; + let text = err.to_string(); + let lc = self.get_login_config_handler(); + let direct = lc.read().unwrap().direct; + let received = lc.read().unwrap().received; + let relay_condition = direct == Some(true) && !received; + + // force relay + let errno = errno::errno().0; + if relay_condition + && (cfg!(windows) && (errno == 10054 || err.contains("10054")) + || !cfg!(windows) && (errno == 104 || err.contains("104"))) + { + lc.write().unwrap().force_relay = true; + lc.write() + .unwrap() + .set_option("force-always-relay".to_owned(), "Y".to_owned()); + } + + // relay-hint + if cfg!(feature = "flutter") && relay_condition { + self.msgbox("relay-hint", title, &text, ""); + } else { + self.msgbox("error", title, &text, ""); + } + } } /// Data used by the client interface. diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 3a7c906c6..056f49190 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -124,7 +124,7 @@ impl Remote { { Ok((mut peer, direct, pk)) => { self.handler.set_connection_type(peer.is_secured(), direct); // flutter -> connection_ready - self.handler.set_connection_info(direct, false); + self.handler.update_direct(Some(direct)); if conn_type == ConnType::DEFAULT_CONN { self.handler .set_fingerprint(crate::common::pk_to_fingerprint(pk.unwrap_or_default())); @@ -160,24 +160,14 @@ impl Remote { if let Some(res) = res { match res { Err(err) => { - log::error!("Connection closed: {}", err); - self.handler.set_force_relay(direct, received, err.to_string()); - let msgtype = "error"; - let title = "Connection Error"; - let text = err.to_string(); - let show_relay_hint = self.handler.show_relay_hint(last_recv_time, msgtype, title, &text); - if show_relay_hint{ - self.handler.msgbox("relay-hint", title, &text, ""); - } else { - self.handler.msgbox(msgtype, title, &text, ""); - } + self.handler.on_establish_connection_error(err.to_string()); break; } Ok(ref bytes) => { last_recv_time = Instant::now(); if !received { received = true; - self.handler.set_connection_info(direct, true); + self.handler.update_received(true); } self.data_count.fetch_add(bytes.len(), Ordering::Relaxed); if !self.handle_msg_from_peer(bytes, &mut peer).await { @@ -271,8 +261,7 @@ impl Remote { } } Err(err) => { - self.handler - .msgbox("error", "Connection Error", &err.to_string(), ""); + self.handler.on_establish_connection_error(err.to_string()); } } #[cfg(not(any(target_os = "android", target_os = "ios")))] diff --git a/src/lang/en.rs b/src/lang/en.rs index 9d759ada4..53d325450 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -44,7 +44,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("wait_accept_uac_tip", "Please wait for the remote user to accept the UAC dialog."), ("still_click_uac_tip", "Still requires the remote user to click OK on the UAC window of running RustDesk."), ("config_microphone", "In order to speak remotely, you need to grant RustDesk \"Record Audio\" permissions."), - ("relay_hint_tip", "It may not be possible to connect directly, you can try to connect via relay. \nIn addition, if you want to use relay on your first try, you can add the \"/r\" suffix to the ID, or select the option \"Always connect via relay\" in the peer card."), + ("relay_hint_tip", "It may not be possible to connect directly; you can try connecting via relay. Additionally, if you want to use a relay on your first attempt, you can add the \"/r\" suffix to the ID or select the option \"Always connect via relay\" in the card of recent sessions."), ("No transfers in progress", ""), ("idd_driver_tip", "Install virtual display driver which is used when you have no physical displays."), ("confirm_idd_driver_tip", "The option to install the virtual display driver is checked. Note that a test certificate will be installed to trust the virtual display driver. This test certificate will only be used to trust Rustdesk drivers."), diff --git a/src/port_forward.rs b/src/port_forward.rs index d1450f09e..6a087abe2 100644 --- a/src/port_forward.rs +++ b/src/port_forward.rs @@ -81,7 +81,7 @@ pub async fn listen( }); } Err(err) => { - interface.msgbox("error", "Error", &err.to_string(), ""); + interface.on_establish_connection_error(err.to_string()); } _ => {} } @@ -112,43 +112,6 @@ async fn connect_and_login( key: &str, token: &str, is_rdp: bool, -) -> ResultType> { - let mut res = connect_and_login_2( - id, - password, - ui_receiver, - interface.clone(), - forward, - key, - token, - is_rdp, - ) - .await; - if res.is_err() && interface.is_force_relay() { - res = connect_and_login_2( - id, - password, - ui_receiver, - interface, - forward, - key, - token, - is_rdp, - ) - .await; - } - res -} - -async fn connect_and_login_2( - id: &str, - password: &str, - ui_receiver: &mut mpsc::UnboundedReceiver, - interface: impl Interface, - forward: &mut Framed, - key: &str, - token: &str, - is_rdp: bool, ) -> ResultType> { let conn_type = if is_rdp { ConnType::RDP @@ -157,6 +120,7 @@ async fn connect_and_login_2( }; let (mut stream, direct, _pk) = Client::start(id, key, token, conn_type, interface.clone()).await?; + interface.update_direct(Some(direct)); let mut interface = interface; let mut buffer = Vec::new(); let mut received = false; @@ -167,7 +131,10 @@ async fn connect_and_login_2( bail!("Timeout"); } Ok(Some(Ok(bytes))) => { - received = true; + if !received { + received = true; + interface.update_received(true); + } let msg_in = Message::parse_from_bytes(&bytes)?; match msg_in.union { Some(message::Union::Hash(hash)) => { @@ -191,8 +158,6 @@ async fn connect_and_login_2( } } Ok(Some(Err(err))) => { - log::error!("Connection closed: {}", err); - interface.set_force_relay(direct, received, err.to_string()); bail!("Connection closed: {}", err); } _ => { diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index e821b71dd..a22bc70d5 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -146,12 +146,6 @@ impl Session { self.lc.read().unwrap().conn_type.eq(&ConnType::RDP) } - pub fn set_connection_info(&mut self, direct: bool, received: bool) { - let mut lc = self.lc.write().unwrap(); - lc.direct = Some(direct); - lc.received = received; - } - pub fn get_view_style(&self) -> String { self.lc.read().unwrap().view_style.clone() } @@ -941,38 +935,6 @@ impl Session { pub fn close_voice_call(&self) { self.send(Data::CloseVoiceCall); } - - pub fn show_relay_hint( - &mut self, - last_recv_time: tokio::time::Instant, - msgtype: &str, - title: &str, - text: &str, - ) -> bool { - let duration = Duration::from_secs(3); - let counter_interval = 3; - let lock = self.lc.read().unwrap(); - let success_time = lock.success_time; - let direct = lock.direct.unwrap_or(false); - let received = lock.received; - drop(lock); - if let Some(success_time) = success_time { - if direct && last_recv_time.duration_since(success_time) < duration { - let retry_for_relay = direct && !received; - let retry = check_if_retry(msgtype, title, text, retry_for_relay); - if retry && !retry_for_relay { - self.lc.write().unwrap().direct_error_counter += 1; - if self.lc.read().unwrap().direct_error_counter % counter_interval == 0 { - #[cfg(feature = "flutter")] - return true; - } - } - } else { - self.lc.write().unwrap().direct_error_counter = 0; - } - } - false - } } pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { @@ -1060,9 +1022,9 @@ impl Interface for Session { } fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str) { - let direct = self.lc.read().unwrap().direct.unwrap_or_default(); + let direct = self.lc.read().unwrap().direct; let received = self.lc.read().unwrap().received; - let retry_for_relay = direct && !received; + let retry_for_relay = direct == Some(true) && !received; let retry = check_if_retry(msgtype, title, text, retry_for_relay); self.ui_handler.msgbox(msgtype, title, text, link, retry); } @@ -1119,7 +1081,6 @@ impl Interface for Session { "Connected, waiting for image...", "", ); - self.lc.write().unwrap().success_time = Some(tokio::time::Instant::now()); } self.on_connected(self.lc.read().unwrap().conn_type); #[cfg(windows)]