-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Webrtc #579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rustdesk
wants to merge
35
commits into
main
Choose a base branch
from
webrtc
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Webrtc #579
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
d4e7273
feat: add rendezvous WebRTC signaling fields
rustdesk 9277af2
feat: support trickle ICE in WebRTCStream
rustdesk 1998a19
fix: route WebRTC ICE without requester id
rustdesk f98f3e8
feat: WebRTC data-plane framing, DTLS binding, and pc-leak fixes
rustdesk 0952f18
fix: preserve WebRTC endpoint and send semantics
rustdesk 6aa8fbe
docs: webrtc 0.13 MSRV pin rationale and upgrade checklist
rustdesk d18dcee
feat: add LogThrottle for sites whose rate a peer controls
rustdesk 5a45b6b
fix: cap the log file by size, and keep LogThrottle usable after pois…
rustdesk 0a36139
fix(webrtc): reject malformed fragment framing, correct receive-path …
rustdesk 7c4456b
proto: drop the reserved tag in PunchHole
rustdesk a992c64
proto: webrtc_all_ice — full-ICE offers under transport-forced relay
rustdesk eed7052
webrtc: declare the ICE policy inside the offer envelope, not a proto…
rustdesk 137bb36
fmt the envelope-marker test
rustdesk 24ae0c4
config: OPTION_ENABLE_WEBRTC, defaulted like the punch options
rustdesk 0d2ca8a
log_throttle: add throttled_log!, the general per-call-site form
rustdesk a0d995f
webrtc: detach teardown, bound reassembly before growing, vet the dat…
rustdesk dccf317
webrtc: fix the send/cache/ICE-lifetime findings; bound log retention…
rustdesk 6677318
webrtc: make the cache guard actually apply; drop unusable ICE servers
rustdesk 73007cb
webrtc: split the send budget, make close_webrtc uncancellable, resto…
rustdesk 4d1b977
stream: close the peer connection on drop
rustdesk ddea60c
webrtc: hand whole messages out of the read buffer instead of copying…
rustdesk 2cb8d0c
webrtc: reject data channels effectively; hand the permit to a desync…
rustdesk 5897012
webrtc: trim the comments to AGENTS.md length
rustdesk 1f8463d
config: add OPTION_ENABLE_KCP_CC to config::keys
rustdesk 01ee2f4
webrtc: own every peer connection's I/O on a process-lifetime runtime
rustdesk db7723e
config: add OPTION_ENABLE_TCP_PUNCH
rustdesk 3e79687
webrtc: keep ICE candidates out of the trickle offer
rustdesk 748eefd
webrtc: address review of the trickle-offer change
rustdesk a96ec7f
webrtc/tests: look for a session that outlasts the window, not an idl…
rustdesk cc8537c
webrtc/tests: close the stream a lost cancellation hands back
rustdesk 6b8182e
webrtc: record why WebRTCStream has no Drop
rustdesk 7ea29ba
webrtc: stop gathering link-local IPv6 host candidates
rustdesk e2aa383
webrtc: report the family of the nominated ICE pair
rustdesk 2f75365
config: name the KCP congestion-control option for what it does
rustdesk 96933d6
webrtc: choose ICE servers by network, and expose the STUN half
rustdesk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| use std::sync::Mutex; | ||
| use std::time::{Duration, Instant}; | ||
|
|
||
| /// Collapses a log site whose call rate is set by someone else — a peer's message rate, or a | ||
| /// retry loop — into at most one line per interval. | ||
| /// | ||
| /// Debug output is written to the log file, so a site that fires per received packet lets a | ||
| /// peer decide how much a machine writes to disk. Dropping the line entirely instead would | ||
| /// hide real faults, so keep one line per interval and carry the count of everything | ||
| /// suppressed since the last one. | ||
| /// | ||
| /// Prefer the [`throttled_log!`](crate::throttled_log) macro, which declares the static for | ||
| /// you. Reach for this type directly only when the count belongs somewhere other than the end | ||
| /// of the line, or when the decision drives more than a log call. | ||
| /// | ||
| /// Declare one per site (they do not share counts): | ||
| /// | ||
| /// ```ignore | ||
| /// static DROPPED_ICE: LogThrottle = LogThrottle::new(Duration::from_secs(60)); | ||
| /// | ||
| /// if let Some(n) = DROPPED_ICE.due() { | ||
| /// log::debug!("dropped {n} ICE candidate(s) with no route"); | ||
| /// } | ||
| /// ``` | ||
| pub struct LogThrottle { | ||
| interval: Duration, | ||
| state: Mutex<ThrottleState>, | ||
| } | ||
|
|
||
| struct ThrottleState { | ||
| suppressed: u64, | ||
| last: Option<Instant>, | ||
| } | ||
|
|
||
| impl LogThrottle { | ||
| pub const fn new(interval: Duration) -> Self { | ||
| Self { | ||
| interval, | ||
| state: Mutex::new(ThrottleState { | ||
| suppressed: 0, | ||
| last: None, | ||
| }), | ||
| } | ||
| } | ||
|
|
||
| /// Record one occurrence. Returns the number of occurrences to report (including this one) | ||
| /// when a line is due, or `None` while still inside the interval. | ||
| /// | ||
| /// The first occurrence after a quiet period always reports, so an isolated fault is not | ||
| /// delayed by the interval. | ||
| pub fn due(&self) -> Option<u64> { | ||
| // A poisoned lock only means some other thread panicked while holding it; the guarded | ||
| // data is two plain counters that are still usable, and going silent for the rest of | ||
| // the process would be worse than a stale count. | ||
| let mut state = self | ||
| .state | ||
| .lock() | ||
| .unwrap_or_else(|poisoned| poisoned.into_inner()); | ||
| state.suppressed += 1; | ||
| // `map_or(true, ..)` rather than clippy's preferred `is_none_or`: that was stabilized in | ||
| // Rust 1.82 and this crate builds on the 1.75 pinned by CI. | ||
| #[allow(clippy::unnecessary_map_or)] | ||
| let due = state | ||
| .last | ||
| .map_or(true, |last| last.elapsed() >= self.interval); | ||
| if !due { | ||
| return None; | ||
| } | ||
| state.last = Some(Instant::now()); | ||
| Some(std::mem::replace(&mut state.suppressed, 0)) | ||
| } | ||
| } | ||
|
|
||
| /// Log at most one line per interval from this call site, suffixed with the number of | ||
| /// occurrences it stands for. | ||
| /// | ||
| /// Each expansion declares its own hidden static, so two sites never share a count and | ||
| /// adding one is a single line: | ||
| /// | ||
| /// ```ignore | ||
| /// throttled_log!(Duration::from_secs(5), warn, "rejected ipc peer {peer_pid:?}"); | ||
| /// ``` | ||
| /// | ||
| /// An isolated event logs unchanged; a burst collapses to `... (x47)`. The count includes | ||
| /// the occurrence being reported, so it reads as a total rather than as "and N more". | ||
| #[macro_export] | ||
| macro_rules! throttled_log { | ||
| ($interval:expr, $level:ident, $($arg:tt)+) => {{ | ||
| static THROTTLE: $crate::log_throttle::LogThrottle = | ||
| $crate::log_throttle::LogThrottle::new($interval); | ||
| if let Some(n) = THROTTLE.due() { | ||
| if n > 1 { | ||
| $crate::log::$level!("{} (x{})", format_args!($($arg)+), n); | ||
| } else { | ||
| $crate::log::$level!("{}", format_args!($($arg)+)); | ||
| } | ||
| } | ||
| }}; | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| // Two directions of one socket need two throttles: an ICMP error on a connected socket is | ||
| // reported once and cleared, so the steady state alternates (send succeeds, the next recv | ||
| // reports it) and anything shared between them is reset by the succeeding side every cycle. | ||
| #[test] | ||
| fn separate_throttles_do_not_reset_each_other() { | ||
| let send = LogThrottle::new(Duration::from_secs(60)); | ||
| let recv = LogThrottle::new(Duration::from_secs(60)); | ||
| assert_eq!(recv.due(), Some(1)); | ||
| for _ in 0..1_000 { | ||
| // The send side succeeding must not hand the recv side a fresh emit slot. | ||
| assert_eq!(recv.due(), None); | ||
| } | ||
| assert_eq!( | ||
| send.due(), | ||
| Some(1), | ||
| "the other direction keeps its own slot" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn first_call_reports_immediately() { | ||
| let t = LogThrottle::new(Duration::from_secs(60)); | ||
| assert_eq!(t.due(), Some(1)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn calls_inside_the_interval_are_counted_not_reported() { | ||
| let t = LogThrottle::new(Duration::from_secs(60)); | ||
| assert_eq!(t.due(), Some(1)); | ||
| for _ in 0..100 { | ||
| assert_eq!(t.due(), None); | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn the_next_due_line_carries_everything_suppressed() { | ||
| let t = LogThrottle::new(Duration::ZERO); | ||
| assert_eq!(t.due(), Some(1)); | ||
| // A zero interval is always due, so each call reports exactly itself. | ||
| assert_eq!(t.due(), Some(1)); | ||
|
|
||
| let t = LogThrottle::new(Duration::from_millis(30)); | ||
| assert_eq!(t.due(), Some(1)); | ||
| assert_eq!(t.due(), None); | ||
| assert_eq!(t.due(), None); | ||
| std::thread::sleep(Duration::from_millis(40)); | ||
| // The two suppressed calls plus this one. | ||
| assert_eq!(t.due(), Some(3)); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: rustdesk/hbb_common
Length of output: 1116
🌐 Web query:
Rustdoc code-block languages ignore no_compile_check # no_run compile_fail💡 Result:
There is no official code-block attribute named no_compile_check in Rustdoc [1][2][3]. If you are looking for ways to control how Rustdoc handles code blocks, the following standard attributes are available: 1. ignore: Tells Rustdoc to ignore the code block entirely when running tests [2][3]. While the code will not be tested (neither compiled nor run), it will still be syntax-highlighted as Rust code if you specify rust [4]. 2. no_run: Compiles the code but does not execute it [2][3]. This is useful for code that might be unsafe, requires network access, or demonstrates behaviors that cannot be run in a standard test environment [2]. 3. compile_fail: Asserts that the code should fail to compile [2][3]. If the code compiles successfully, the test will fail [2]. If you intended to write a code block that should not be interpreted as Rust code at all (and thus not tested), you should use the text language identifier instead of rust [2]. For example:
text This block is treated as text and will not be tested by rustdoc.There have been discussions within the Rust community regarding a potential no_compile attribute to distinguish between "ignored" (but still compiled) and "do not compile" states, but this has not been implemented as a standard code-block attribute [5][6].Citations:
no_compiledoctest attribute rust-lang/rust#96573🌐 Web query:
doc test ignored rust code still compiled not linted💡 Result:
In Rust documentation tests, annotating a code block with the ignore attribute (e.g.,
ignore) instructs the test runner to skip execution [1][6]. However, this does not mean the code is completely ignored by the toolchain: 1. Compilation and Linting: By design, the ignore attribute does not prevent the code from being parsed or linted by rustdoc [1][2][4]. Because rustdoc must still parse the block to identify it as a code example, it will still trigger certain lints, such as rustdoc::invalid_rust_codeblocks, if the content contains invalid syntax [9][10]. The block is not treated as a standard, runnable test, but it is still subject to the initial processing phases of the documentation test pipeline [2][4]. 2. Behavior with --ignored: It is a common point of confusion that code blocks marked with ignore are still technically included in the test suite [2][4]. When running cargo test, they are reported as ignored [3][7]. If you explicitly run the test suite with the --ignored flag (e.g., cargo test --doc -- --ignored), the runner may attempt to compile and execute them, depending on the current version of the toolchain and the specific configuration [2][4][7]. 3. Alternatives: Because ignore is often used for non-compilable snippets (like pseudocode or documentation that should not be tested), users frequently request a way to truly "disable" a block [2][4]. Official recommendations for such cases include: - Using the text language tag instead of rust (e.g.,text) if you do not want the code to be treated as Rust code at all [1][2]. - Using hidden lines (#) to make the snippet compilable while showing only the relevant parts to the reader [1][3]. - If you need to ensure code does not compile, use the compile_fail attribute, though this still subjects the code to the compilation process [1][2].Citations:
Make the Rustdoc example compilable or use a plain text block.
The ignored example still shows unresolved
DurationandLogThrottle, so a caller who copies it into another module cannot compile it. AddDuration,LogThrottle, andhbb_common::as needed, then dropignore; or usetextif the example is only illustrative.🤖 Prompt for AI Agents