diff options
| author | David Lönnhager <david.l@mullvad.net> | 2024-03-05 17:12:57 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2024-03-13 17:34:06 +0100 |
| commit | f739f1ffc2a8eda716ee593eb27ed13ab43098a3 (patch) | |
| tree | 270d90bffed9c279c854d4d2dce7c7fc213aacd1 | |
| parent | c4af7a7289346ebb121c5906d819adf5c14f1dc5 (diff) | |
| download | mullvadvpn-f739f1ffc2a8eda716ee593eb27ed13ab43098a3.tar.xz mullvadvpn-f739f1ffc2a8eda716ee593eb27ed13ab43098a3.zip | |
Log when select functions are called an unusual number of times
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | talpid-core/src/dns/macos.rs | 4 | ||||
| -rw-r--r-- | talpid-core/src/offline/macos.rs | 2 | ||||
| -rw-r--r-- | talpid-routing/src/debounce.rs | 1 | ||||
| -rw-r--r-- | talpid-routing/src/unix/macos/mod.rs | 8 | ||||
| -rw-r--r-- | talpid-routing/src/unix/macos/routing_socket.rs | 2 | ||||
| -rw-r--r-- | talpid-types/Cargo.toml | 1 | ||||
| -rw-r--r-- | talpid-types/src/error.rs | 56 |
8 files changed, 75 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock index ab0433f672..cf5dece12a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3744,6 +3744,7 @@ dependencies = [ "base64 0.13.1", "ipnetwork", "jnix", + "log", "serde", "thiserror", "x25519-dalek", diff --git a/talpid-core/src/dns/macos.rs b/talpid-core/src/dns/macos.rs index c68165737f..82deb1bd67 100644 --- a/talpid-core/src/dns/macos.rs +++ b/talpid-core/src/dns/macos.rs @@ -88,6 +88,8 @@ impl State { interface: &str, servers: &[IpAddr], ) -> Result<()> { + talpid_types::detect_flood!(); + let servers: Vec<DnsServer> = servers.iter().map(|ip| ip.to_string()).collect(); let new_settings = DnsSettings::from_server_addresses(&servers, interface.to_string()); match &self.dns_settings { @@ -115,6 +117,8 @@ impl State { } fn on_changed_keys(&mut self, store: SCDynamicStore, changed_keys: CFArray<CFString>) { + talpid_types::detect_flood!(); + if let Some(expected_settings) = &self.dns_settings { for path in &changed_keys { let should_set_dns = match DnsSettings::load(&store, path.clone()).ok() { diff --git a/talpid-core/src/offline/macos.rs b/talpid-core/src/offline/macos.rs index 51596f77c2..2813dc4211 100644 --- a/talpid-core/src/offline/macos.rs +++ b/talpid-core/src/offline/macos.rs @@ -96,6 +96,8 @@ pub async fn spawn_monitor( let mut route_listener = route_listener.fuse(); loop { + talpid_types::detect_flood!(); + select! { _ = timeout => { // Update shared state diff --git a/talpid-routing/src/debounce.rs b/talpid-routing/src/debounce.rs index 2463b2c429..fe51447624 100644 --- a/talpid-routing/src/debounce.rs +++ b/talpid-routing/src/debounce.rs @@ -99,6 +99,7 @@ impl BurstGuard { /// Asynchronously trigger burst pub fn trigger(&self) { + talpid_types::detect_flood!(); self.trigger_with_period(self.buffer_period) } diff --git a/talpid-routing/src/unix/macos/mod.rs b/talpid-routing/src/unix/macos/mod.rs index 7a1c120621..448a87427c 100644 --- a/talpid-routing/src/unix/macos/mod.rs +++ b/talpid-routing/src/unix/macos/mod.rs @@ -158,12 +158,16 @@ impl RouteManagerImpl { let mut completion_tx = None; loop { + talpid_types::detect_flood!(); + futures::select_biased! { route_message = self.routing_table.next_message().fuse() => { self.handle_route_message(route_message); } _ = self.check_default_routes_restored.next() => { + talpid_types::detect_flood!(); + if self.check_default_routes_restored.is_terminated() { continue; } @@ -328,6 +332,8 @@ impl RouteManagerImpl { &mut self, message: std::result::Result<RouteSocketMessage, watch::Error>, ) { + talpid_types::detect_flood!(); + match message { Ok(RouteSocketMessage::DeleteRoute(route)) => { // Forget about applied route, if relevant @@ -380,6 +386,8 @@ impl RouteManagerImpl { /// server. The gateway of the relay route is set to the first interface in the network /// service order that has a working ifscoped default route. async fn refresh_routes(&mut self) -> Result<()> { + talpid_types::detect_flood!(); + self.update_best_default_route(interface::Family::V4)?; self.update_best_default_route(interface::Family::V6)?; diff --git a/talpid-routing/src/unix/macos/routing_socket.rs b/talpid-routing/src/unix/macos/routing_socket.rs index 835e7d6edc..ab02f1cff2 100644 --- a/talpid-routing/src/unix/macos/routing_socket.rs +++ b/talpid-routing/src/unix/macos/routing_socket.rs @@ -87,6 +87,8 @@ impl RoutingSocket { pub async fn wait_for_response(&mut self, response_num: i32) -> Result<Vec<u8>> { loop { + talpid_types::detect_flood!(); + let mut buffer = vec![0u8; 2048]; // do not truncate the buffer - trailing empty bytes won't be written but will be // assumed in the data format. diff --git a/talpid-types/Cargo.toml b/talpid-types/Cargo.toml index c44001b4cd..7582387b68 100644 --- a/talpid-types/Cargo.toml +++ b/talpid-types/Cargo.toml @@ -17,6 +17,7 @@ base64 = "0.13" x25519-dalek = { version = "2.0.1", features = ["static_secrets", "zeroize", "getrandom"] } thiserror = { workspace = true } zeroize = "1.5.7" +log = { workspace = true } [target.'cfg(target_os = "android")'.dependencies] jnix = { version = "0.5.1", features = ["derive"] } diff --git a/talpid-types/src/error.rs b/talpid-types/src/error.rs index 77f0664375..e4471eff29 100644 --- a/talpid-types/src/error.rs +++ b/talpid-types/src/error.rs @@ -68,3 +68,59 @@ macro_rules! win32_err { } }}; } + +pub mod flood { + #[doc(hidden)] + pub use log; + + use std::time::{Duration, Instant}; + + const CALLS_INTERVAL: Duration = Duration::from_secs(5); + const CALLS_THRESHOLD: usize = 1000; + + /// Log when a line is hit unusually frequently, that is, over `CALLS_THRESHOLD` times within a + /// period of `CALLS_INTERVAL`. + #[macro_export] + macro_rules! detect_flood { + () => {{ + static FLOOD: ::std::sync::Mutex<$crate::flood::DetectFlood> = + ::std::sync::Mutex::new($crate::flood::DetectFlood::new()); + if FLOOD.lock().unwrap().bump() { + $crate::flood::log::warn!( + "Flood: {}, line {}, col {}", + file!(), + line!(), + column!() + ); + } + }}; + } + + /// Used to detect code that is running too frequently + pub struct DetectFlood { + last_clear: Option<Instant>, + counter: usize, + } + + impl DetectFlood { + pub const fn new() -> Self { + DetectFlood { + last_clear: None, + counter: 0, + } + } + + pub fn bump(&mut self) -> bool { + let now = Instant::now(); + let last_clear = self.last_clear.get_or_insert(now); + if now.saturating_duration_since(*last_clear) >= CALLS_INTERVAL { + self.last_clear = Some(now); + self.counter = 0; + false + } else { + self.counter = self.counter.saturating_add(1); + self.counter == CALLS_THRESHOLD + } + } + } +} |
