diff --git a/.gitmodules b/.gitmodules index 6e234a46..91ffedf1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "external/mdns"] path = external/mdns url = ../mdns.git +[submodule "external/hashlink"] + path = external/hashlink + url = ../hashlink.git diff --git a/Cargo.lock b/Cargo.lock index 21bdbf74..1a108738 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4201,6 +4201,7 @@ dependencies = [ "generic-array 0.14.5", "getrandom 0.2.5", "hashbrown 0.12.0", + "hashlink", "hex", "ifstructs", "jni", diff --git a/external/hashlink b/external/hashlink new file mode 160000 index 00000000..f5846ec3 --- /dev/null +++ b/external/hashlink @@ -0,0 +1 @@ +Subproject commit f5846ec3ff06865a204114bd710253e7e67e4498 diff --git a/veilid-core/Cargo.toml b/veilid-core/Cargo.toml index 940b310b..9e67e71d 100644 --- a/veilid-core/Cargo.toml +++ b/veilid-core/Cargo.toml @@ -26,6 +26,7 @@ generic-array = "^0" secrecy = "^0" chacha20poly1305 = "^0" uluru = "^3" +hashlink = "^0" serde-big-array = "^0" futures-util = { version = "^0", default_features = false, features = ["alloc"] } parking_lot = "^0" diff --git a/veilid-core/src/connection_manager.rs b/veilid-core/src/connection_manager.rs index 793bc356..67e5feb3 100644 --- a/veilid-core/src/connection_manager.rs +++ b/veilid-core/src/connection_manager.rs @@ -4,8 +4,8 @@ use crate::network_connection::*; use crate::network_manager::*; use crate::xx::*; use crate::*; -use futures_util::future::{select, Either}; use futures_util::stream::{FuturesUnordered, StreamExt}; +use futures_util::{select, FutureExt}; const CONNECTION_PROCESSOR_CHANNEL_SIZE: usize = 128usize; @@ -162,12 +162,28 @@ impl ConnectionManager { Box::pin(async move { // let descriptor = conn.connection_descriptor(); + let inactivity_timeout = this + .network_manager() + .config() + .get() + .network + .connection_inactivity_timeout_ms; loop { - let res = conn.clone().recv().await; - let message = match res { - Ok(v) => v, - Err(e) => { - log_net!(error e); + // process inactivity timeout on receives only + // if you want a keepalive, it has to be requested from the other side + let message = select! { + res = conn.recv().fuse() => { + match res { + Ok(v) => v, + Err(e) => { + log_net!(error e); + break; + } + } + } + _ = intf::sleep(inactivity_timeout).fuse()=> { + // timeout + log_net!("connection timeout on {:?}", descriptor); break; } }; @@ -201,8 +217,8 @@ impl ConnectionManager { FuturesUnordered::new(); loop { // Either process an existing connection, or receive a new one to add to our list - match select(connection_futures.next(), Box::pin(rx.recv_async())).await { - Either::Left((x, _)) => { + select! { + x = connection_futures.next().fuse() => { // Processed some connection to completion, or there are none left match x { Some(()) => { @@ -222,7 +238,7 @@ impl ConnectionManager { } } } - Either::Right((x, _)) => { + x = rx.recv_async().fuse() => { // Got a new connection future match x { Ok(v) => { diff --git a/veilid-core/src/dht/crypto.rs b/veilid-core/src/dht/crypto.rs index a85d9dd5..a6051500 100644 --- a/veilid-core/src/dht/crypto.rs +++ b/veilid-core/src/dht/crypto.rs @@ -8,7 +8,6 @@ use core::convert::TryInto; use curve25519_dalek as cd; use ed25519_dalek as ed; use serde::{Deserialize, Serialize}; -use serde_big_array::*; use uluru; use x25519_dalek as xd; @@ -18,11 +17,6 @@ pub type Nonce = [u8; 24]; const DH_CACHE_SIZE: usize = 1024; pub const ENCRYPTION_OVERHEAD: usize = 16; -big_array! { - BigArray; - DH_CACHE_SIZE -} - type DHCache = uluru::LRUCache; #[derive(Serialize, Deserialize)] diff --git a/veilid-core/src/network_connection.rs b/veilid-core/src/network_connection.rs index 5241934e..b96ab058 100644 --- a/veilid-core/src/network_connection.rs +++ b/veilid-core/src/network_connection.rs @@ -55,16 +55,21 @@ impl DummyNetworkConnection { /////////////////////////////////////////////////////////// // Top-level protocol independent network connection object -#[derive(Debug)] -struct NetworkConnectionInner { +#[derive(Debug, Clone)] +pub struct NetworkConnectionStats { last_message_sent_time: Option, last_message_recv_time: Option, + established_time: u64, +} + +#[derive(Debug)] +struct NetworkConnectionInner { + stats: NetworkConnectionStats, } #[derive(Debug)] struct NetworkConnectionArc { descriptor: ConnectionDescriptor, - established_time: u64, protocol_connection: ProtocolNetworkConnection, inner: Mutex, } @@ -84,8 +89,11 @@ impl Eq for NetworkConnection {} impl NetworkConnection { fn new_inner() -> NetworkConnectionInner { NetworkConnectionInner { - last_message_sent_time: None, - last_message_recv_time: None, + stats: NetworkConnectionStats { + last_message_sent_time: None, + last_message_recv_time: None, + established_time: intf::get_timestamp(), + }, } } fn new_arc( @@ -94,7 +102,6 @@ impl NetworkConnection { ) -> NetworkConnectionArc { NetworkConnectionArc { descriptor, - established_time: intf::get_timestamp(), protocol_connection, inner: Mutex::new(Self::new_inner()), } @@ -136,7 +143,7 @@ impl NetworkConnection { let out = self.arc.protocol_connection.send(message).await; if out.is_ok() { let mut inner = self.arc.inner.lock(); - inner.last_message_sent_time.max_assign(Some(ts)); + inner.stats.last_message_sent_time.max_assign(Some(ts)); } out } @@ -145,8 +152,13 @@ impl NetworkConnection { let out = self.arc.protocol_connection.recv().await; if out.is_ok() { let mut inner = self.arc.inner.lock(); - inner.last_message_recv_time.max_assign(Some(ts)); + inner.stats.last_message_recv_time.max_assign(Some(ts)); } out } + + pub fn stats(&self) -> NetworkConnectionStats { + let inner = self.arc.inner.lock(); + inner.stats.clone() + } } diff --git a/veilid-core/src/network_manager.rs b/veilid-core/src/network_manager.rs index fe1dae4b..062fd989 100644 --- a/veilid-core/src/network_manager.rs +++ b/veilid-core/src/network_manager.rs @@ -11,6 +11,8 @@ use xx::*; //////////////////////////////////////////////////////////////////////////////////////// pub const MAX_MESSAGE_SIZE: usize = MAX_ENVELOPE_SIZE; +pub const IPADDR_TABLE_SIZE: usize = 1024; +pub const IPADDR_MAX_INACTIVE_DURATION_US: u64 = 300_000_000u64; // 5 minutes #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum NetworkClass { @@ -79,11 +81,33 @@ struct NetworkComponents { receipt_manager: ReceiptManager, } +// Statistics per address +#[derive(Clone, Default)] +pub struct PerAddressStats { + last_seen_ts: u64, + transfer_stats_accounting: TransferStatsAccounting, + transfer_stats: TransferStatsDownUp, +} + +// Statistics about the low-level network +#[derive(Clone, Default)] +pub struct NetworkManagerStats { + self_stats: PerAddressStats, + per_address_stats: HashMap, + recent_addresses: VecDeque, +} + // The mutable state of the network manager -pub struct NetworkManagerInner { +struct NetworkManagerInner { routing_table: Option, components: Option, network_class: Option, + stats: NetworkManagerStats, +} + +struct NetworkManagerUnlockedInner { + // Background processes + rolling_transfers_task: TickTask, } #[derive(Clone)] @@ -92,6 +116,7 @@ pub struct NetworkManager { table_store: TableStore, crypto: Crypto, inner: Arc>, + unlocked_inner: Arc, } impl NetworkManager { @@ -100,16 +125,34 @@ impl NetworkManager { routing_table: None, components: None, network_class: None, + stats: NetworkManagerStats::default(), + } + } + fn new_unlocked_inner(_config: VeilidConfig) -> NetworkManagerUnlockedInner { + //let c = config.get(); + NetworkManagerUnlockedInner { + rolling_transfers_task: TickTask::new(ROLLING_TRANSFERS_INTERVAL_SECS), } } pub fn new(config: VeilidConfig, table_store: TableStore, crypto: Crypto) -> Self { - Self { - config, + let this = Self { + config: config.clone(), table_store, crypto, inner: Arc::new(Mutex::new(Self::new_inner())), + unlocked_inner: Arc::new(Self::new_unlocked_inner(config)), + }; + // Set rolling transfers tick task + { + let this2 = this.clone(); + this.unlocked_inner + .rolling_transfers_task + .set_routine(move |l, t| { + Box::pin(this2.clone().rolling_transfers_task_routine(l, t)) + }); } + this } pub fn config(&self) -> VeilidConfig { self.config.clone() @@ -546,4 +589,76 @@ impl NetworkManager { // Inform caller that we dealt with the envelope locally Ok(true) } + + // Compute transfer statistics for the low level network + async fn rolling_transfers_task_routine(self, last_ts: u64, cur_ts: u64) -> Result<(), String> { + log_net!("--- network manager rolling_transfers task"); + let inner = &mut *self.inner.lock(); + + // Roll the low level network transfer stats for our address + inner + .stats + .self_stats + .transfer_stats_accounting + .roll_transfers(last_ts, cur_ts, &mut inner.stats.self_stats.transfer_stats); + + // Roll all per-address transfers + let mut dead_addrs: HashSet = HashSet::new(); + for (addr, stats) in &mut inner.stats.per_address_stats { + stats.transfer_stats_accounting.roll_transfers( + last_ts, + cur_ts, + &mut stats.transfer_stats, + ); + + // While we're here, lets see if this address has timed out + if cur_ts - stats.last_seen_ts >= IPADDR_MAX_INACTIVE_DURATION_US { + // it's dead, put it in the dead list + dead_addrs.insert(*addr); + } + } + + // Remove the dead addresses from our tables + for da in &dead_addrs { + inner.stats.per_address_stats.remove(da); + } + inner + .stats + .recent_addresses + .retain(|a| !dead_addrs.contains(a)); + Ok(()) + } + + // Callbacks from low level network for statistics gathering + fn packet_sent(&self, addr: IpAddr, bytes: u64) { + let inner = &mut *self.inner.lock(); + inner + .stats + .self_stats + .transfer_stats_accounting + .add_up(bytes); + inner + .stats + .per_address_stats + .entry(addr) + .or_default() + .transfer_stats_accounting + .add_up(bytes); + } + + fn packet_rcvd(&self, addr: IpAddr, bytes: u64) { + let inner = &mut *self.inner.lock(); + inner + .stats + .self_stats + .transfer_stats_accounting + .add_down(bytes); + inner + .stats + .per_address_stats + .entry(addr) + .or_default() + .transfer_stats_accounting + .add_down(bytes); + } } diff --git a/veilid-core/src/routing_table/bucket_entry.rs b/veilid-core/src/routing_table/bucket_entry.rs index 00827e80..64c63d9a 100644 --- a/veilid-core/src/routing_table/bucket_entry.rs +++ b/veilid-core/src/routing_table/bucket_entry.rs @@ -32,7 +32,8 @@ pub struct BucketEntry { min_max_version: Option<(u8, u8)>, last_connection: Option<(ConnectionDescriptor, u64)>, dial_infos: Vec, - stats_accounting: StatsAccounting, + latency_stats_accounting: LatencyStatsAccounting, + transfer_stats_accounting: TransferStatsAccounting, peer_stats: PeerStats, } @@ -44,7 +45,8 @@ impl BucketEntry { min_max_version: None, last_connection: None, dial_infos: Vec::new(), - stats_accounting: StatsAccounting::new(), + latency_stats_accounting: LatencyStatsAccounting::new(), + transfer_stats_accounting: TransferStatsAccounting::new(), peer_stats: PeerStats { time_added: now, last_seen: None, @@ -133,13 +135,16 @@ impl BucketEntry { ///// stats methods // called every ROLLING_TRANSFERS_INTERVAL_SECS seconds pub(super) fn roll_transfers(&mut self, last_ts: u64, cur_ts: u64) { - self.stats_accounting - .roll_transfers(last_ts, cur_ts, &mut self.peer_stats.transfer); + self.transfer_stats_accounting.roll_transfers( + last_ts, + cur_ts, + &mut self.peer_stats.transfer, + ); } // Called for every round trip packet we receive fn record_latency(&mut self, latency: u64) { - self.peer_stats.latency = Some(self.stats_accounting.record_latency(latency)); + self.peer_stats.latency = Some(self.latency_stats_accounting.record_latency(latency)); } ///// state machine handling @@ -255,7 +260,7 @@ impl BucketEntry { pub(super) fn ping_sent(&mut self, ts: u64, bytes: u64) { self.peer_stats.ping_stats.total_sent += 1; - self.stats_accounting.add_up(bytes); + self.transfer_stats_accounting.add_up(bytes); self.peer_stats.ping_stats.in_flight += 1; self.peer_stats.ping_stats.last_pinged = Some(ts); // if we haven't heard from this node yet and it's our first attempt at contacting it @@ -265,14 +270,14 @@ impl BucketEntry { } } pub(super) fn ping_rcvd(&mut self, ts: u64, bytes: u64) { - self.stats_accounting.add_down(bytes); + self.transfer_stats_accounting.add_down(bytes); self.touch_last_seen(ts); } pub(super) fn pong_sent(&mut self, _ts: u64, bytes: u64) { - self.stats_accounting.add_up(bytes); + self.transfer_stats_accounting.add_up(bytes); } pub(super) fn pong_rcvd(&mut self, send_ts: u64, recv_ts: u64, bytes: u64) { - self.stats_accounting.add_down(bytes); + self.transfer_stats_accounting.add_down(bytes); self.peer_stats.ping_stats.in_flight -= 1; self.peer_stats.ping_stats.total_returned += 1; self.peer_stats.ping_stats.consecutive_pongs += 1; @@ -294,7 +299,7 @@ impl BucketEntry { self.peer_stats.ping_stats.first_consecutive_pong_time = None; } pub(super) fn question_sent(&mut self, ts: u64, bytes: u64) { - self.stats_accounting.add_up(bytes); + self.transfer_stats_accounting.add_up(bytes); // if we haven't heard from this node yet and it's our first attempt at contacting it // then we set the last_seen time if self.peer_stats.last_seen.is_none() { @@ -302,14 +307,14 @@ impl BucketEntry { } } pub(super) fn question_rcvd(&mut self, ts: u64, bytes: u64) { - self.stats_accounting.add_down(bytes); + self.transfer_stats_accounting.add_down(bytes); self.touch_last_seen(ts); } pub(super) fn answer_sent(&mut self, _ts: u64, bytes: u64) { - self.stats_accounting.add_up(bytes); + self.transfer_stats_accounting.add_up(bytes); } pub(super) fn answer_rcvd(&mut self, send_ts: u64, recv_ts: u64, bytes: u64) { - self.stats_accounting.add_down(bytes); + self.transfer_stats_accounting.add_down(bytes); self.record_latency(recv_ts - send_ts); self.touch_last_seen(recv_ts); } diff --git a/veilid-core/src/routing_table/debug.rs b/veilid-core/src/routing_table/debug.rs index 62e8a4dd..fb37e0b6 100644 --- a/veilid-core/src/routing_table/debug.rs +++ b/veilid-core/src/routing_table/debug.rs @@ -7,8 +7,14 @@ impl RoutingTable { out += "Routing Table Info:\n"; out += &format!(" Node Id: {}\n", inner.node_id.encode()); - out += &format!(" Stats Accounting: {:#?}\n\n", inner.stats_accounting); - out += &format!(" Transfer Stats: {:#?}\n\n", inner.transfer_stats); + out += &format!( + " Self Transfer Stats Accounting: {:#?}\n\n", + inner.self_transfer_stats_accounting + ); + out += &format!( + " Self Transfer Stats: {:#?}\n\n", + inner.self_transfer_stats + ); out } diff --git a/veilid-core/src/routing_table/mod.rs b/veilid-core/src/routing_table/mod.rs index ad8b131a..0ed18164 100644 --- a/veilid-core/src/routing_table/mod.rs +++ b/veilid-core/src/routing_table/mod.rs @@ -50,12 +50,14 @@ struct RoutingTableInner { buckets: Vec, dial_info_details: Vec, bucket_entry_count: usize, + // Waiters eventual_changed_dial_info: Eventual, + // Transfer stats for this node - stats_accounting: StatsAccounting, - // latency: Option, - transfer_stats: TransferStatsDownUp, + self_latency_stats_accounting: LatencyStatsAccounting, + self_transfer_stats_accounting: TransferStatsAccounting, + self_transfer_stats: TransferStatsDownUp, } struct RoutingTableUnlockedInner { @@ -83,8 +85,9 @@ impl RoutingTable { dial_info_details: Vec::new(), bucket_entry_count: 0, eventual_changed_dial_info: Eventual::new(), - stats_accounting: StatsAccounting::new(), - transfer_stats: TransferStatsDownUp::default(), + self_latency_stats_accounting: LatencyStatsAccounting::new(), + self_transfer_stats_accounting: TransferStatsAccounting::new(), + self_transfer_stats: TransferStatsDownUp::default(), } } fn new_unlocked_inner(config: VeilidConfig) -> RoutingTableUnlockedInner { @@ -609,9 +612,11 @@ impl RoutingTable { let inner = &mut *self.inner.lock(); // Roll our own node's transfers - inner - .stats_accounting - .roll_transfers(last_ts, cur_ts, &mut inner.transfer_stats); + inner.self_transfer_stats_accounting.roll_transfers( + last_ts, + cur_ts, + &mut inner.self_transfer_stats, + ); // Roll all bucket entry transfers for b in &mut inner.buckets { @@ -649,25 +654,37 @@ impl RoutingTable { // Stats Accounting pub fn ping_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) { - self.inner.lock().stats_accounting.add_up(bytes); + self.inner + .lock() + .self_transfer_stats_accounting + .add_up(bytes); node_ref.operate(|e| { e.ping_sent(ts, bytes); }) } pub fn ping_rcvd(&self, node_ref: NodeRef, ts: u64, bytes: u64) { - self.inner.lock().stats_accounting.add_down(bytes); + self.inner + .lock() + .self_transfer_stats_accounting + .add_down(bytes); node_ref.operate(|e| { e.ping_rcvd(ts, bytes); }) } pub fn pong_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) { - self.inner.lock().stats_accounting.add_up(bytes); + self.inner + .lock() + .self_transfer_stats_accounting + .add_up(bytes); node_ref.operate(|e| { e.pong_sent(ts, bytes); }) } pub fn pong_rcvd(&self, node_ref: NodeRef, send_ts: u64, recv_ts: u64, bytes: u64) { - self.inner.lock().stats_accounting.add_down(bytes); + self.inner + .lock() + .self_transfer_stats_accounting + .add_down(bytes); node_ref.operate(|e| { e.pong_rcvd(send_ts, recv_ts, bytes); }) @@ -678,25 +695,37 @@ impl RoutingTable { }) } pub fn question_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) { - self.inner.lock().stats_accounting.add_up(bytes); + self.inner + .lock() + .self_transfer_stats_accounting + .add_up(bytes); node_ref.operate(|e| { e.question_sent(ts, bytes); }) } pub fn question_rcvd(&self, node_ref: NodeRef, ts: u64, bytes: u64) { - self.inner.lock().stats_accounting.add_down(bytes); + self.inner + .lock() + .self_transfer_stats_accounting + .add_down(bytes); node_ref.operate(|e| { e.question_rcvd(ts, bytes); }) } pub fn answer_sent(&self, node_ref: NodeRef, ts: u64, bytes: u64) { - self.inner.lock().stats_accounting.add_up(bytes); + self.inner + .lock() + .self_transfer_stats_accounting + .add_up(bytes); node_ref.operate(|e| { e.answer_sent(ts, bytes); }) } pub fn answer_rcvd(&self, node_ref: NodeRef, send_ts: u64, recv_ts: u64, bytes: u64) { - self.inner.lock().stats_accounting.add_down(bytes); + self.inner + .lock() + .self_transfer_stats_accounting + .add_down(bytes); node_ref.operate(|e| { e.answer_rcvd(send_ts, recv_ts, bytes); }) diff --git a/veilid-core/src/routing_table/stats_accounting.rs b/veilid-core/src/routing_table/stats_accounting.rs index e63ffcd1..31c86765 100644 --- a/veilid-core/src/routing_table/stats_accounting.rs +++ b/veilid-core/src/routing_table/stats_accounting.rs @@ -19,16 +19,14 @@ pub struct TransferCount { } #[derive(Debug, Clone, Default)] -pub struct StatsAccounting { - rolling_latencies: VecDeque, +pub struct TransferStatsAccounting { rolling_transfers: VecDeque, current_transfer: TransferCount, } -impl StatsAccounting { +impl TransferStatsAccounting { pub fn new() -> Self { Self { - rolling_latencies: VecDeque::new(), rolling_transfers: VecDeque::new(), current_transfer: TransferCount::default(), } @@ -79,6 +77,19 @@ impl StatsAccounting { transfer_stats.down.average /= len; transfer_stats.up.average /= len; } +} + +#[derive(Debug, Clone, Default)] +pub struct LatencyStatsAccounting { + rolling_latencies: VecDeque, +} + +impl LatencyStatsAccounting { + pub fn new() -> Self { + Self { + rolling_latencies: VecDeque::new(), + } + } pub fn record_latency(&mut self, latency: u64) -> veilid_api::LatencyStats { while self.rolling_latencies.len() >= ROLLING_LATENCIES_SIZE { diff --git a/veilid-core/src/tests/common/test_veilid_config.rs b/veilid-core/src/tests/common/test_veilid_config.rs index cc3c1fb1..7bcc8580 100644 --- a/veilid-core/src/tests/common/test_veilid_config.rs +++ b/veilid-core/src/tests/common/test_veilid_config.rs @@ -187,6 +187,7 @@ fn config_callback(key: String) -> ConfigCallbackReturn { "protected_store.delete" => Ok(Box::new(false)), "network.max_connections" => Ok(Box::new(16u32)), "network.connection_initial_timeout_ms" => Ok(Box::new(2_000u32)), + "network.connection_inactivity_timeout_ms" => Ok(Box::new(60_000u32)), "network.node_id" => Ok(Box::new(dht::key::DHTKey::default())), "network.node_id_secret" => Ok(Box::new(dht::key::DHTKeySecret::default())), "network.bootstrap" => Ok(Box::new(Vec::::new())), @@ -291,6 +292,7 @@ pub async fn test_config() { assert_eq!(inner.protected_store.delete, false); assert_eq!(inner.network.max_connections, 16); assert_eq!(inner.network.connection_initial_timeout_ms, 2_000u32); + assert_eq!(inner.network.connection_inactivity_timeout_ms, 60_000u32); assert!(!inner.network.node_id.valid); assert!(!inner.network.node_id_secret.valid); assert_eq!(inner.network.bootstrap, Vec::::new()); diff --git a/veilid-core/src/veilid_api/mod.rs b/veilid-core/src/veilid_api/mod.rs index 29962de2..312b7f54 100644 --- a/veilid-core/src/veilid_api/mod.rs +++ b/veilid-core/src/veilid_api/mod.rs @@ -880,12 +880,6 @@ pub struct LatencyStats { pub slowest: u64, // slowest latency in the ROLLING_LATENCIES_SIZE last latencies } -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct TransferStatsDownUp { - pub down: TransferStats, - pub up: TransferStats, -} - #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct TransferStats { pub total: u64, // total amount transferred ever @@ -894,6 +888,12 @@ pub struct TransferStats { pub minimum: u64, // minimum rate over the ROLLING_TRANSFERS_SIZE last amounts } +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct TransferStatsDownUp { + pub down: TransferStats, + pub up: TransferStats, +} + #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct PingStats { pub in_flight: u32, // number of pings issued that have yet to be answered diff --git a/veilid-core/src/veilid_config.rs b/veilid-core/src/veilid_config.rs index 3a3f1f1a..36d7d409 100644 --- a/veilid-core/src/veilid_config.rs +++ b/veilid-core/src/veilid_config.rs @@ -128,6 +128,7 @@ pub struct VeilidConfigLeases { pub struct VeilidConfigNetwork { pub max_connections: u32, pub connection_initial_timeout_ms: u32, + pub connection_inactivity_timeout_ms: u32, pub node_id: key::DHTKey, pub node_id_secret: key::DHTKeySecret, pub bootstrap: Vec, @@ -282,6 +283,7 @@ impl VeilidConfig { get_config!(inner.network.node_id_secret); get_config!(inner.network.max_connections); get_config!(inner.network.connection_initial_timeout_ms); + get_config!(inner.network.connection_inactivity_timeout_ms); get_config!(inner.network.bootstrap); get_config!(inner.network.dht.resolve_node_timeout_ms); get_config!(inner.network.dht.resolve_node_count); diff --git a/veilid-core/src/xx/mod.rs b/veilid-core/src/xx/mod.rs index 488b149e..b0055419 100644 --- a/veilid-core/src/xx/mod.rs +++ b/veilid-core/src/xx/mod.rs @@ -31,8 +31,12 @@ cfg_if! { if #[cfg(target_arch = "wasm32")] { pub use alloc::string::String; pub use alloc::vec::Vec; + pub use alloc::collections::LinkedList; + pub use alloc::collections::VecDeque; pub use alloc::collections::btree_map::BTreeMap; pub use alloc::collections::btree_set::BTreeSet; + pub use hashbrown::hash_map::HashMap; + pub use hashbrown::hash_set::HashSet; pub use alloc::boxed::Box; pub use alloc::borrow::{Cow, ToOwned}; pub use wasm_bindgen::prelude::*; @@ -54,8 +58,12 @@ cfg_if! { } else { pub use std::string::String; pub use std::vec::Vec; + pub use std::collections::LinkedList; + pub use std::collections::VecDeque; pub use std::collections::btree_map::BTreeMap; pub use std::collections::btree_set::BTreeSet; + pub use std::collections::hash_map::HashMap; + pub use std::collections::hash_set::HashSet; pub use std::boxed::Box; pub use std::borrow::{Cow, ToOwned}; pub use std::cmp; diff --git a/veilid-flutter/example/lib/config.dart b/veilid-flutter/example/lib/config.dart index af3533b0..61a32bc2 100644 --- a/veilid-flutter/example/lib/config.dart +++ b/veilid-flutter/example/lib/config.dart @@ -40,6 +40,7 @@ Future getDefaultVeilidConfig() async { network: VeilidConfigNetwork( maxConnections: 16, connectionInitialTimeoutMs: 2000, + connectionInactivityTimeoutMs: 60000, nodeId: "", nodeIdSecret: "", bootstrap: [], diff --git a/veilid-flutter/lib/veilid.dart b/veilid-flutter/lib/veilid.dart index 5232b6f2..62a12546 100644 --- a/veilid-flutter/lib/veilid.dart +++ b/veilid-flutter/lib/veilid.dart @@ -516,6 +516,7 @@ class VeilidConfigLeases { class VeilidConfigNetwork { int maxConnections; int connectionInitialTimeoutMs; + int connectionInactivityTimeoutMs; String nodeId; String nodeIdSecret; List bootstrap; @@ -533,6 +534,7 @@ class VeilidConfigNetwork { VeilidConfigNetwork({ required this.maxConnections, required this.connectionInitialTimeoutMs, + required this.connectionInactivityTimeoutMs, required this.nodeId, required this.nodeIdSecret, required this.bootstrap, @@ -552,6 +554,7 @@ class VeilidConfigNetwork { return { 'max_connections': maxConnections, 'connection_initial_timeout_ms': connectionInitialTimeoutMs, + 'connection_inactivity_timeout_ms': connectionInactivityTimeoutMs, 'node_id': nodeId, 'node_id_secret': nodeIdSecret, 'bootstrap': bootstrap, @@ -571,6 +574,8 @@ class VeilidConfigNetwork { VeilidConfigNetwork.fromJson(Map json) : maxConnections = json['max_connections'], connectionInitialTimeoutMs = json['connection_initial_timeout_ms'], + connectionInactivityTimeoutMs = + json['connection_inactivity_timeout_ms'], nodeId = json['node_id'], nodeIdSecret = json['node_id_secret'], bootstrap = json['bootstrap'], diff --git a/veilid-server/src/settings.rs b/veilid-server/src/settings.rs index 90793a8b..78e50139 100644 --- a/veilid-server/src/settings.rs +++ b/veilid-server/src/settings.rs @@ -50,6 +50,7 @@ core: network: max_connections: 16 connection_initial_timeout_ms: 2000 + connection_inactivity_timeout_ms: 60000 node_id: '' node_id_secret: '' bootstrap: [] @@ -523,6 +524,7 @@ pub struct Leases { pub struct Network { pub max_connections: u32, pub connection_initial_timeout_ms: u32, + pub connection_inactivity_timeout_ms: u32, pub node_id: veilid_core::DHTKey, pub node_id_secret: veilid_core::DHTKeySecret, pub bootstrap: Vec, @@ -794,6 +796,9 @@ impl Settings { "network.connection_initial_timeout_ms" => { Ok(Box::new(inner.core.network.connection_initial_timeout_ms)) } + "network.connection_inactivity_timeout_ms" => Ok(Box::new( + inner.core.network.connection_inactivity_timeout_ms, + )), "network.node_id" => Ok(Box::new(inner.core.network.node_id)), "network.node_id_secret" => Ok(Box::new(inner.core.network.node_id_secret)), "network.bootstrap" => Ok(Box::new( @@ -1131,6 +1136,7 @@ mod tests { assert_eq!(s.core.network.max_connections, 16); assert_eq!(s.core.network.connection_initial_timeout_ms, 2_000u32); + assert_eq!(s.core.network.connection_inactivity_timeout_ms, 60_000u32); assert_eq!(s.core.network.node_id, veilid_core::DHTKey::default()); assert_eq!( s.core.network.node_id_secret,