mirror of
https://github.com/telemt/telemt.git
synced 2026-04-17 18:44:10 +03:00
bump version to 3.3.20 and implement connection lease management for direct and middle relays
This commit is contained in:
114
src/stats/connection_lease_security_tests.rs
Normal file
114
src/stats/connection_lease_security_tests.rs
Normal file
@@ -0,0 +1,114 @@
|
||||
use super::*;
|
||||
use std::panic::{self, AssertUnwindSafe};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn direct_connection_lease_balances_on_drop() {
|
||||
let stats = Arc::new(Stats::new());
|
||||
assert_eq!(stats.get_current_connections_direct(), 0);
|
||||
|
||||
{
|
||||
let _lease = stats.acquire_direct_connection_lease();
|
||||
assert_eq!(stats.get_current_connections_direct(), 1);
|
||||
}
|
||||
|
||||
assert_eq!(stats.get_current_connections_direct(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn middle_connection_lease_balances_on_drop() {
|
||||
let stats = Arc::new(Stats::new());
|
||||
assert_eq!(stats.get_current_connections_me(), 0);
|
||||
|
||||
{
|
||||
let _lease = stats.acquire_me_connection_lease();
|
||||
assert_eq!(stats.get_current_connections_me(), 1);
|
||||
}
|
||||
|
||||
assert_eq!(stats.get_current_connections_me(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connection_lease_disarm_prevents_double_release() {
|
||||
let stats = Arc::new(Stats::new());
|
||||
|
||||
let mut lease = stats.acquire_direct_connection_lease();
|
||||
assert_eq!(stats.get_current_connections_direct(), 1);
|
||||
|
||||
stats.decrement_current_connections_direct();
|
||||
assert_eq!(stats.get_current_connections_direct(), 0);
|
||||
|
||||
lease.disarm();
|
||||
drop(lease);
|
||||
|
||||
assert_eq!(stats.get_current_connections_direct(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_connection_lease_balances_on_panic_unwind() {
|
||||
let stats = Arc::new(Stats::new());
|
||||
let stats_for_panic = stats.clone();
|
||||
|
||||
let panic_result = panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
let _lease = stats_for_panic.acquire_direct_connection_lease();
|
||||
panic!("intentional panic to verify lease drop path");
|
||||
}));
|
||||
|
||||
assert!(panic_result.is_err(), "panic must propagate from test closure");
|
||||
assert_eq!(
|
||||
stats.get_current_connections_direct(),
|
||||
0,
|
||||
"panic unwind must release direct route gauge"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn direct_connection_lease_balances_on_task_abort() {
|
||||
let stats = Arc::new(Stats::new());
|
||||
let stats_for_task = stats.clone();
|
||||
|
||||
let task = tokio::spawn(async move {
|
||||
let _lease = stats_for_task.acquire_direct_connection_lease();
|
||||
tokio::time::sleep(Duration::from_secs(60)).await;
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(20)).await;
|
||||
assert_eq!(stats.get_current_connections_direct(), 1);
|
||||
|
||||
task.abort();
|
||||
let joined = task.await;
|
||||
assert!(joined.is_err(), "aborted task must return a join error");
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(20)).await;
|
||||
assert_eq!(
|
||||
stats.get_current_connections_direct(),
|
||||
0,
|
||||
"aborted task must release direct route gauge"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn middle_connection_lease_balances_on_task_abort() {
|
||||
let stats = Arc::new(Stats::new());
|
||||
let stats_for_task = stats.clone();
|
||||
|
||||
let task = tokio::spawn(async move {
|
||||
let _lease = stats_for_task.acquire_me_connection_lease();
|
||||
tokio::time::sleep(Duration::from_secs(60)).await;
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(20)).await;
|
||||
assert_eq!(stats.get_current_connections_me(), 1);
|
||||
|
||||
task.abort();
|
||||
let joined = task.await;
|
||||
assert!(joined.is_err(), "aborted task must return a join error");
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(20)).await;
|
||||
assert_eq!(
|
||||
stats.get_current_connections_me(),
|
||||
0,
|
||||
"aborted task must release middle route gauge"
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ pub mod beobachten;
|
||||
pub mod telemetry;
|
||||
|
||||
use std::sync::atomic::{AtomicBool, AtomicU8, AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
use dashmap::DashMap;
|
||||
use parking_lot::Mutex;
|
||||
@@ -19,6 +20,45 @@ use tracing::debug;
|
||||
use crate::config::{MeTelemetryLevel, MeWriterPickMode};
|
||||
use self::telemetry::TelemetryPolicy;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum RouteConnectionGauge {
|
||||
Direct,
|
||||
Middle,
|
||||
}
|
||||
|
||||
pub struct RouteConnectionLease {
|
||||
stats: Arc<Stats>,
|
||||
gauge: RouteConnectionGauge,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
impl RouteConnectionLease {
|
||||
fn new(stats: Arc<Stats>, gauge: RouteConnectionGauge) -> Self {
|
||||
Self {
|
||||
stats,
|
||||
gauge,
|
||||
active: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn disarm(&mut self) {
|
||||
self.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RouteConnectionLease {
|
||||
fn drop(&mut self) {
|
||||
if !self.active {
|
||||
return;
|
||||
}
|
||||
match self.gauge {
|
||||
RouteConnectionGauge::Direct => self.stats.decrement_current_connections_direct(),
|
||||
RouteConnectionGauge::Middle => self.stats.decrement_current_connections_me(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============= Stats =============
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -285,6 +325,16 @@ impl Stats {
|
||||
pub fn decrement_current_connections_me(&self) {
|
||||
Self::decrement_atomic_saturating(&self.current_connections_me);
|
||||
}
|
||||
|
||||
pub fn acquire_direct_connection_lease(self: &Arc<Self>) -> RouteConnectionLease {
|
||||
self.increment_current_connections_direct();
|
||||
RouteConnectionLease::new(self.clone(), RouteConnectionGauge::Direct)
|
||||
}
|
||||
|
||||
pub fn acquire_me_connection_lease(self: &Arc<Self>) -> RouteConnectionLease {
|
||||
self.increment_current_connections_me();
|
||||
RouteConnectionLease::new(self.clone(), RouteConnectionGauge::Middle)
|
||||
}
|
||||
pub fn increment_handshake_timeouts(&self) {
|
||||
if self.telemetry_core_enabled() {
|
||||
self.handshake_timeouts.fetch_add(1, Ordering::Relaxed);
|
||||
@@ -1772,3 +1822,7 @@ mod tests {
|
||||
assert_eq!(checker.stats().total_entries, 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "connection_lease_security_tests.rs"]
|
||||
mod connection_lease_security_tests;
|
||||
|
||||
Reference in New Issue
Block a user