mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-14 00:11:01 +03:00
review: reject a disconnected cached session, tidy the detector
hbb_common: `is_reusable_for` now also rejects a session ICE reports Disconnected, so a caller is not handed one that already carries the hint; and the receive-progress test no longer races `next()` against a sleeping sibling. Here: the `is_some()` guard on the progress comparison was dead, since a transport answers `None` for its whole life and `None != None` is already false. The parting-send deadline is a `Duration` like every other constant around it rather than bare milliseconds. And the comments are cut back to what is not already evident from the code they sit on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns
This commit is contained in:
Submodule libs/hbb_common updated: c50c1fef32...166bb3d2ac
@@ -15,24 +15,19 @@ use crate::{
|
|||||||
// Restart msgbox text is kept as a legacy UI fallback; Flutter handles the type as a control event.
|
// Restart msgbox text is kept as a legacy UI fallback; Flutter handles the type as a control event.
|
||||||
const RESTART_REMOTE_DEVICE_NO_DATA_TIMEOUT: Duration = Duration::from_secs(5);
|
const RESTART_REMOTE_DEVICE_NO_DATA_TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
const KCP_CLOSE_REASON_FLUSH_DELAY: Duration = Duration::from_millis(30);
|
const KCP_CLOSE_REASON_FLUSH_DELAY: Duration = Duration::from_millis(30);
|
||||||
const KCP_CLOSE_REASON_GONE_TIMEOUT: u64 = 500;
|
// Deadline for the parting close-reason send once the peer is presumed gone; KCP waits for send
|
||||||
// A peer that is killed, logged out or rebooted sends nothing at all over UDP, so the session
|
// capacity with no deadline of its own.
|
||||||
// sees silence and only a timeout ends it. These bound that wait for the two transports that
|
const KCP_CLOSE_REASON_GONE_DEADLINE: Duration = Duration::from_millis(500);
|
||||||
// have a liveness signal of their own; TCP and WebSocket are left exactly as they were, and the
|
|
||||||
// 30s timeout below still backs all of them.
|
|
||||||
//
|
|
||||||
// Neither is a hard upper bound on how soon this notices: sends are awaited inline in this same
|
|
||||||
// loop, so one in progress keeps the tick below from running. WebRTC caps that at its existing
|
|
||||||
// send timeout; KCP sets none, so a large message can delay the check by however long it takes
|
|
||||||
// to drain. Removing that needs the framing work that would stop one message owning the link.
|
|
||||||
//
|
|
||||||
// Grace after ICE reports Disconnected, which it does ~5s after it stops hearing from the peer,
|
// Grace after ICE reports Disconnected, which it does ~5s after it stops hearing from the peer,
|
||||||
// for ~8s in total. Disconnected is transient by design, so this waits out a Wi-Fi roam or a
|
// for ~8s in total. Disconnected is transient by design, so this waits out a Wi-Fi roam or a
|
||||||
// sleep/wake rather than acting on the first hint.
|
// sleep/wake rather than acting on the first hint.
|
||||||
const WEBRTC_SUSPECT_GRACE: Duration = Duration::from_secs(3);
|
const WEBRTC_SUSPECT_GRACE: Duration = Duration::from_secs(3);
|
||||||
// KCP has no equivalent hint, only how long since a packet last arrived; its endpoint pings an
|
// KCP gets no such hint, only how long since a packet arrived; its endpoint pings an idle peer
|
||||||
// idle peer about every 2s, so this is several missed pings.
|
// about every 2s, so this is several missed pings, and matches the 8s WebRTC arrives at.
|
||||||
const KCP_PEER_SILENCE_LIMIT: Duration = Duration::from_secs(8);
|
const KCP_PEER_SILENCE_LIMIT: Duration = Duration::from_secs(8);
|
||||||
|
// Neither is a hard upper bound: sends are awaited inline in this loop, so one in progress keeps
|
||||||
|
// the tick that checks them from running, capped only by the transport's own send timeout.
|
||||||
|
// Removing that needs the framing work that would stop one message owning the link.
|
||||||
#[cfg(feature = "unix-file-copy-paste")]
|
#[cfg(feature = "unix-file-copy-paste")]
|
||||||
use crate::{clipboard::try_empty_clipboard_files, clipboard_file::unix_file_clip};
|
use crate::{clipboard::try_empty_clipboard_files, clipboard_file::unix_file_clip};
|
||||||
use base::{
|
use base::{
|
||||||
@@ -317,8 +312,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
// Not `last_recv_time` alone: a message larger than the transport's
|
// Not `last_recv_time` alone: a message larger than the transport's
|
||||||
// fragment size yields nothing until its last fragment, so a peer
|
// fragment size yields nothing until its last fragment, so a peer
|
||||||
// sending one steadily - a clipboard image is the case that occurs -
|
// sending one steadily - a clipboard image is the case that occurs -
|
||||||
// would otherwise be timed out mid-transfer. Transports that report no
|
// would otherwise be timed out mid-transfer.
|
||||||
// progress leave this at its starting value and are unaffected.
|
|
||||||
if last_recv_time.max(last_rx_progress_at).elapsed() >= SEC30 {
|
if last_recv_time.max(last_rx_progress_at).elapsed() >= SEC30 {
|
||||||
self.handler.msgbox("error", "Connection Error", "Timeout", "");
|
self.handler.msgbox("error", "Connection Error", "Timeout", "");
|
||||||
break;
|
break;
|
||||||
@@ -340,10 +334,10 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
self.handler.msgbox("restarting-show", "Restarting remote device", "Connection in progress. Please wait.", "");
|
self.handler.msgbox("restarting-show", "Restarting remote device", "Connection in progress. Please wait.", "");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Bytes seen by the transport, so a message too large to have arrived
|
|
||||||
// whole still counts, and it clears a suspicion ICE raised late.
|
|
||||||
let rx_progress = peer.rx_progress();
|
let rx_progress = peer.rx_progress();
|
||||||
let progressed = rx_progress.is_some() && rx_progress != last_rx_progress;
|
// `None` for transports that report none, and it never changes for a
|
||||||
|
// given one, so they are inert here.
|
||||||
|
let progressed = rx_progress != last_rx_progress;
|
||||||
last_rx_progress = rx_progress;
|
last_rx_progress = rx_progress;
|
||||||
if progressed {
|
if progressed {
|
||||||
last_rx_progress_at = Instant::now();
|
last_rx_progress_at = Instant::now();
|
||||||
@@ -409,14 +403,10 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
s.send(()).ok();
|
s.send(()).ok();
|
||||||
}
|
}
|
||||||
if kcp.is_some() {
|
if kcp.is_some() {
|
||||||
// Bounded once the peer has been declared gone: KCP waits for send capacity
|
// Attempted rather than skipped even here: if the loss was one-way the peer
|
||||||
// with no deadline of its own, and a queue that a dead peer will never drain
|
// does get it, and drops its side instead of waiting out its own timeout.
|
||||||
// would hold this thread until the endpoint reaps the connection. Still
|
|
||||||
// attempted rather than skipped - if the loss was one-way the peer does get
|
|
||||||
// it, and drops its side of the session instead of waiting out its own
|
|
||||||
// timeout.
|
|
||||||
if peer_gone {
|
if peer_gone {
|
||||||
peer.set_send_timeout(KCP_CLOSE_REASON_GONE_TIMEOUT);
|
peer.set_send_timeout(KCP_CLOSE_REASON_GONE_DEADLINE.as_millis() as u64);
|
||||||
}
|
}
|
||||||
// Send the close reason if it hasn't been sent yet, as KCP cannot detect the socket close event.
|
// Send the close reason if it hasn't been sent yet, as KCP cannot detect the socket close event.
|
||||||
self.send_close_reason(&mut peer, "kcp").await;
|
self.send_close_reason(&mut peer, "kcp").await;
|
||||||
|
|||||||
Reference in New Issue
Block a user