mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-10-01 01:26:08 -04:00
convert deferred stream processor to generic streams instead of flume channel
more aggressive relay reconnection more discovery context improvement
This commit is contained in:
parent
55f07d7bcc
commit
545b646d8f
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -6299,9 +6299,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "veilid-hashlink"
|
name = "veilid-hashlink"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a3dabbda02cfe176635dcaa18a021416ff2eb4d0b47a913e3fdc7f62049d7b1"
|
checksum = "2070d1d09dad90091d23e49743408f82f8874994dec5ae0a8d3689b061bba426"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown 0.14.5",
|
"hashbrown 0.14.5",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -88,7 +88,7 @@ enumset = { version = "1.1.3", features = ["serde"] }
|
|||||||
keyvaluedb = "0.1.2"
|
keyvaluedb = "0.1.2"
|
||||||
range-set-blaze = "0.1.16"
|
range-set-blaze = "0.1.16"
|
||||||
weak-table = "0.3.2"
|
weak-table = "0.3.2"
|
||||||
hashlink = { package = "veilid-hashlink", version = "0.1.0", features = [
|
hashlink = { package = "veilid-hashlink", version = "0.1.1", features = [
|
||||||
"serde_impl",
|
"serde_impl",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ struct ConnectionManagerInner {
|
|||||||
async_processor_jh: Option<MustJoinHandle<()>>,
|
async_processor_jh: Option<MustJoinHandle<()>>,
|
||||||
stop_source: Option<StopSource>,
|
stop_source: Option<StopSource>,
|
||||||
protected_addresses: HashMap<SocketAddress, ProtectedAddress>,
|
protected_addresses: HashMap<SocketAddress, ProtectedAddress>,
|
||||||
|
reconnection_processor: DeferredStreamProcessor,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ConnectionManagerArc {
|
struct ConnectionManagerArc {
|
||||||
@ -84,6 +85,7 @@ impl ConnectionManager {
|
|||||||
stop_source: StopSource,
|
stop_source: StopSource,
|
||||||
sender: flume::Sender<ConnectionManagerEvent>,
|
sender: flume::Sender<ConnectionManagerEvent>,
|
||||||
async_processor_jh: MustJoinHandle<()>,
|
async_processor_jh: MustJoinHandle<()>,
|
||||||
|
reconnection_processor: DeferredStreamProcessor,
|
||||||
) -> ConnectionManagerInner {
|
) -> ConnectionManagerInner {
|
||||||
ConnectionManagerInner {
|
ConnectionManagerInner {
|
||||||
next_id: 0.into(),
|
next_id: 0.into(),
|
||||||
@ -91,6 +93,7 @@ impl ConnectionManager {
|
|||||||
sender,
|
sender,
|
||||||
async_processor_jh: Some(async_processor_jh),
|
async_processor_jh: Some(async_processor_jh),
|
||||||
protected_addresses: HashMap::new(),
|
protected_addresses: HashMap::new(),
|
||||||
|
reconnection_processor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn new_arc(network_manager: NetworkManager) -> ConnectionManagerArc {
|
fn new_arc(network_manager: NetworkManager) -> ConnectionManagerArc {
|
||||||
@ -133,11 +136,6 @@ impl ConnectionManager {
|
|||||||
|
|
||||||
log_net!(debug "startup connection manager");
|
log_net!(debug "startup connection manager");
|
||||||
|
|
||||||
let mut inner = self.arc.inner.lock();
|
|
||||||
if inner.is_some() {
|
|
||||||
panic!("shouldn't start connection manager twice without shutting it down first");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create channel for async_processor to receive notifications of networking events
|
// Create channel for async_processor to receive notifications of networking events
|
||||||
let (sender, receiver) = flume::unbounded();
|
let (sender, receiver) = flume::unbounded();
|
||||||
|
|
||||||
@ -150,8 +148,21 @@ impl ConnectionManager {
|
|||||||
self.clone().async_processor(stop_source.token(), receiver),
|
self.clone().async_processor(stop_source.token(), receiver),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Spawn the reconnection processor
|
||||||
|
let mut reconnection_processor = DeferredStreamProcessor::new();
|
||||||
|
reconnection_processor.init().await;
|
||||||
|
|
||||||
// Store in the inner object
|
// Store in the inner object
|
||||||
*inner = Some(Self::new_inner(stop_source, sender, async_processor));
|
let mut inner = self.arc.inner.lock();
|
||||||
|
if inner.is_some() {
|
||||||
|
panic!("shouldn't start connection manager twice without shutting it down first");
|
||||||
|
}
|
||||||
|
*inner = Some(Self::new_inner(
|
||||||
|
stop_source,
|
||||||
|
sender,
|
||||||
|
async_processor,
|
||||||
|
reconnection_processor,
|
||||||
|
));
|
||||||
|
|
||||||
guard.success();
|
guard.success();
|
||||||
|
|
||||||
@ -175,7 +186,9 @@ impl ConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// Stop the reconnection processor
|
||||||
|
log_net!(debug "stopping reconnection processor task");
|
||||||
|
inner.reconnection_processor.terminate().await;
|
||||||
// Stop all the connections and the async processor
|
// Stop all the connections and the async processor
|
||||||
log_net!(debug "stopping async processor task");
|
log_net!(debug "stopping async processor task");
|
||||||
drop(inner.stop_source.take());
|
drop(inner.stop_source.take());
|
||||||
@ -278,11 +291,12 @@ impl ConnectionManager {
|
|||||||
&self,
|
&self,
|
||||||
inner: &mut ConnectionManagerInner,
|
inner: &mut ConnectionManagerInner,
|
||||||
prot_conn: ProtocolNetworkConnection,
|
prot_conn: ProtocolNetworkConnection,
|
||||||
|
opt_dial_info: Option<DialInfo>,
|
||||||
) -> EyreResult<NetworkResult<ConnectionHandle>> {
|
) -> EyreResult<NetworkResult<ConnectionHandle>> {
|
||||||
// Get next connection id to use
|
// Get next connection id to use
|
||||||
let id = inner.next_id;
|
let id = inner.next_id;
|
||||||
inner.next_id += 1u64;
|
inner.next_id += 1u64;
|
||||||
log_net!(debug
|
log_net!(
|
||||||
"on_new_protocol_network_connection: id={} prot_conn={:?}",
|
"on_new_protocol_network_connection: id={} prot_conn={:?}",
|
||||||
id,
|
id,
|
||||||
prot_conn
|
prot_conn
|
||||||
@ -294,7 +308,13 @@ impl ConnectionManager {
|
|||||||
None => bail!("not creating connection because we are stopping"),
|
None => bail!("not creating connection because we are stopping"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut conn = NetworkConnection::from_protocol(self.clone(), stop_token, prot_conn, id);
|
let mut conn = NetworkConnection::from_protocol(
|
||||||
|
self.clone(),
|
||||||
|
stop_token,
|
||||||
|
prot_conn,
|
||||||
|
id,
|
||||||
|
opt_dial_info,
|
||||||
|
);
|
||||||
let handle = conn.get_handle();
|
let handle = conn.get_handle();
|
||||||
|
|
||||||
// See if this should be a protected connection
|
// See if this should be a protected connection
|
||||||
@ -396,7 +416,7 @@ impl ConnectionManager {
|
|||||||
// Async lock on the remote address for atomicity per remote
|
// Async lock on the remote address for atomicity per remote
|
||||||
let _lock_guard = self.arc.address_lock_table.lock_tag(remote_addr).await;
|
let _lock_guard = self.arc.address_lock_table.lock_tag(remote_addr).await;
|
||||||
|
|
||||||
log_net!(debug "== get_or_create_connection dial_info={:?}", dial_info);
|
log_net!("== get_or_create_connection dial_info={:?}", dial_info);
|
||||||
|
|
||||||
// If any connection to this remote exists that has the same protocol, return it
|
// If any connection to this remote exists that has the same protocol, return it
|
||||||
// Any connection will do, we don't have to match the local address but if we can
|
// Any connection will do, we don't have to match the local address but if we can
|
||||||
@ -406,7 +426,7 @@ impl ConnectionManager {
|
|||||||
.connection_table
|
.connection_table
|
||||||
.get_best_connection_by_remote(best_port, peer_address)
|
.get_best_connection_by_remote(best_port, peer_address)
|
||||||
{
|
{
|
||||||
log_net!(debug
|
log_net!(
|
||||||
"== Returning best existing connection {:?}",
|
"== Returning best existing connection {:?}",
|
||||||
best_existing_conn
|
best_existing_conn
|
||||||
);
|
);
|
||||||
@ -468,7 +488,7 @@ impl ConnectionManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.on_new_protocol_network_connection(inner, prot_conn)
|
self.on_new_protocol_network_connection(inner, prot_conn, Some(dial_info))
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -502,7 +522,7 @@ impl ConnectionManager {
|
|||||||
// We don't care if this fails, since nobody here asked for the inbound connection.
|
// We don't care if this fails, since nobody here asked for the inbound connection.
|
||||||
// If it does, we just drop the connection
|
// If it does, we just drop the connection
|
||||||
|
|
||||||
let _ = self.on_new_protocol_network_connection(inner, prot_conn);
|
let _ = self.on_new_protocol_network_connection(inner, prot_conn, None);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// If this somehow happens, we're shutting down
|
// If this somehow happens, we're shutting down
|
||||||
@ -598,6 +618,9 @@ impl ConnectionManager {
|
|||||||
// See if we've had more than the threshold number of drops in the last span
|
// See if we've had more than the threshold number of drops in the last span
|
||||||
let cur_ts = Timestamp::now();
|
let cur_ts = Timestamp::now();
|
||||||
let duration = cur_ts.saturating_sub(pa.span_start_ts);
|
let duration = cur_ts.saturating_sub(pa.span_start_ts);
|
||||||
|
|
||||||
|
let mut reconnect = true;
|
||||||
|
|
||||||
if duration < PROTECTED_CONNECTION_DROP_SPAN {
|
if duration < PROTECTED_CONNECTION_DROP_SPAN {
|
||||||
pa.drops_in_span += 1;
|
pa.drops_in_span += 1;
|
||||||
log_net!(debug "== Protected connection dropped (count={}): {} -> {} for node {}", pa.drops_in_span, conn.connection_id(), conn.debug_print(Timestamp::now()), protect_nr);
|
log_net!(debug "== Protected connection dropped (count={}): {} -> {} for node {}", pa.drops_in_span, conn.connection_id(), conn.debug_print(Timestamp::now()), protect_nr);
|
||||||
@ -605,6 +628,7 @@ impl ConnectionManager {
|
|||||||
if pa.drops_in_span >= PROTECTED_CONNECTION_DROP_COUNT {
|
if pa.drops_in_span >= PROTECTED_CONNECTION_DROP_COUNT {
|
||||||
// Consider this as a failure to send if we've dropped the connection too many times in a single timespan
|
// Consider this as a failure to send if we've dropped the connection too many times in a single timespan
|
||||||
protect_nr.report_protected_connection_dropped();
|
protect_nr.report_protected_connection_dropped();
|
||||||
|
reconnect = false;
|
||||||
|
|
||||||
// Reset the drop counter
|
// Reset the drop counter
|
||||||
pa.drops_in_span = 0;
|
pa.drops_in_span = 0;
|
||||||
@ -618,6 +642,15 @@ impl ConnectionManager {
|
|||||||
log_net!(debug "== Protected connection dropped (count={}): {} -> {} for node {}", pa.drops_in_span, conn.connection_id(), conn.debug_print(Timestamp::now()), protect_nr);
|
log_net!(debug "== Protected connection dropped (count={}): {} -> {} for node {}", pa.drops_in_span, conn.connection_id(), conn.debug_print(Timestamp::now()), protect_nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reconnect the protected connection immediately
|
||||||
|
if reconnect {
|
||||||
|
if let Some(dial_info) = conn.dial_info() {
|
||||||
|
self.spawn_reconnector_inner(inner, dial_info);
|
||||||
|
} else {
|
||||||
|
log_net!(debug "Can't reconnect to accepted protected connection: {} -> {} for node {}", conn.connection_id(), conn.debug_print(Timestamp::now()), protect_nr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -627,6 +660,30 @@ impl ConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spawn_reconnector_inner(&self, inner: &mut ConnectionManagerInner, dial_info: DialInfo) {
|
||||||
|
let this = self.clone();
|
||||||
|
inner.reconnection_processor.add(
|
||||||
|
Box::pin(futures_util::stream::once(async { dial_info })),
|
||||||
|
move |dial_info| {
|
||||||
|
let this = this.clone();
|
||||||
|
Box::pin(async move {
|
||||||
|
match this.get_or_create_connection(dial_info.clone()).await {
|
||||||
|
Ok(NetworkResult::Value(conn)) => {
|
||||||
|
log_net!(debug "Reconnection successful to {}: {:?}", dial_info,conn);
|
||||||
|
}
|
||||||
|
Ok(res) => {
|
||||||
|
log_net!(debug "Reconnection unsuccessful to {}: {:?}", dial_info, res);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log_net!(debug "Reconnection error to {}: {}", dial_info, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn debug_print(&self) -> String {
|
pub async fn debug_print(&self) -> String {
|
||||||
//let inner = self.arc.inner.lock();
|
//let inner = self.arc.inner.lock();
|
||||||
format!(
|
format!(
|
||||||
|
@ -1210,7 +1210,7 @@ impl NetworkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Report peer info changes
|
// Report peer info changes
|
||||||
pub fn report_peer_info_change(&self, peer_info: Arc<PeerInfo>) {
|
pub fn report_peer_info_change(&mut self, peer_info: Arc<PeerInfo>) {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
if let Some(address_check) = inner.address_check.as_mut() {
|
if let Some(address_check) = inner.address_check.as_mut() {
|
||||||
address_check.report_peer_info_change(peer_info);
|
address_check.report_peer_info_change(peer_info);
|
||||||
|
@ -199,7 +199,6 @@ impl DiscoveryContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For each peer, ask them for our public address, filtering on desired dial info
|
// For each peer, ask them for our public address, filtering on desired dial info
|
||||||
let mut unord = FuturesUnordered::new();
|
|
||||||
|
|
||||||
let get_public_address_func = |node: NodeRef| {
|
let get_public_address_func = |node: NodeRef| {
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
@ -225,12 +224,12 @@ impl DiscoveryContext {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut external_address_infos = Vec::new();
|
let mut external_address_infos = Vec::new();
|
||||||
|
let mut unord = FuturesUnordered::new();
|
||||||
for node in nodes.iter().take(nodes.len() - 1).cloned() {
|
for node in nodes.iter().cloned() {
|
||||||
let gpa_future = get_public_address_func(node);
|
let gpa_future = get_public_address_func(node);
|
||||||
unord.push(gpa_future);
|
unord.push(gpa_future);
|
||||||
|
|
||||||
// Always process two at a time so we get both addresses in parallel if possible
|
// Always process N at a time so we get all addresses in parallel if possible
|
||||||
if unord.len() == EXTERNAL_INFO_VALIDATIONS {
|
if unord.len() == EXTERNAL_INFO_VALIDATIONS {
|
||||||
// Process one
|
// Process one
|
||||||
if let Some(Some(ei)) = unord.next().in_current_span().await {
|
if let Some(Some(ei)) = unord.next().in_current_span().await {
|
||||||
@ -280,10 +279,10 @@ impl DiscoveryContext {
|
|||||||
{
|
{
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner.external_info = external_address_infos;
|
inner.external_info = external_address_infos;
|
||||||
log_net!(debug "external_info ({:?}:{:?})[{}]",
|
log_net!(debug "External Addresses: ({:?}:{:?})[{}]",
|
||||||
self.unlocked_inner.protocol_type,
|
self.unlocked_inner.protocol_type,
|
||||||
self.unlocked_inner.address_type,
|
self.unlocked_inner.address_type,
|
||||||
inner.external_info.iter().map(|x| format!("{}",x.address)).collect::<Vec<_>>().join(", "));
|
inner.external_info.iter().map(|x| format!("{} <- {}",x.address, x.node)).collect::<Vec<_>>().join(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -30,6 +30,10 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
pub const UPDATE_NETWORK_CLASS_TASK_TICK_PERIOD_SECS: u32 = 1;
|
||||||
|
pub const NETWORK_INTERFACES_TASK_TICK_PERIOD_SECS: u32 = 1;
|
||||||
|
pub const UPNP_TASK_TICK_PERIOD_SECS: u32 = 1;
|
||||||
|
|
||||||
pub const PEEK_DETECT_LEN: usize = 64;
|
pub const PEEK_DETECT_LEN: usize = 64;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
@ -168,9 +172,15 @@ impl Network {
|
|||||||
routing_table,
|
routing_table,
|
||||||
connection_manager,
|
connection_manager,
|
||||||
interfaces: NetworkInterfaces::new(),
|
interfaces: NetworkInterfaces::new(),
|
||||||
update_network_class_task: TickTask::new("update_network_class_task", 1),
|
update_network_class_task: TickTask::new(
|
||||||
network_interfaces_task: TickTask::new("network_interfaces_task", 1),
|
"update_network_class_task",
|
||||||
upnp_task: TickTask::new("upnp_task", 1),
|
UPDATE_NETWORK_CLASS_TASK_TICK_PERIOD_SECS,
|
||||||
|
),
|
||||||
|
network_interfaces_task: TickTask::new(
|
||||||
|
"network_interfaces_task",
|
||||||
|
NETWORK_INTERFACES_TASK_TICK_PERIOD_SECS,
|
||||||
|
),
|
||||||
|
upnp_task: TickTask::new("upnp_task", UPNP_TASK_TICK_PERIOD_SECS),
|
||||||
network_task_lock: AsyncMutex::new(()),
|
network_task_lock: AsyncMutex::new(()),
|
||||||
igd_manager: igd_manager::IGDManager::new(config.clone()),
|
igd_manager: igd_manager::IGDManager::new(config.clone()),
|
||||||
}
|
}
|
||||||
|
@ -14,16 +14,15 @@ impl Network {
|
|||||||
let _guard = self.unlocked_inner.network_task_lock.lock().await;
|
let _guard = self.unlocked_inner.network_task_lock.lock().await;
|
||||||
|
|
||||||
// Do the public dial info check
|
// Do the public dial info check
|
||||||
let out = self.do_public_dial_info_check(stop_token, l, t).await;
|
let finished = self.do_public_dial_info_check(stop_token, l, t).await?;
|
||||||
|
|
||||||
// Done with public dial info check
|
// Done with public dial info check
|
||||||
{
|
if finished {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner.needs_public_dial_info_check = false;
|
inner.needs_public_dial_info_check = false;
|
||||||
inner.public_dial_info_check_punishment = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self, editor), err)]
|
#[instrument(level = "trace", skip(self, editor), err)]
|
||||||
@ -54,7 +53,7 @@ impl Network {
|
|||||||
stop_token: StopToken,
|
stop_token: StopToken,
|
||||||
_l: Timestamp,
|
_l: Timestamp,
|
||||||
_t: Timestamp,
|
_t: Timestamp,
|
||||||
) -> EyreResult<()> {
|
) -> EyreResult<bool> {
|
||||||
// Figure out if we can optimize TCP/WS checking since they are often on the same port
|
// Figure out if we can optimize TCP/WS checking since they are often on the same port
|
||||||
let (protocol_config, inbound_protocol_map) = {
|
let (protocol_config, inbound_protocol_map) = {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
@ -105,7 +104,7 @@ impl Network {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Set most permissive network config
|
// Set most permissive network config and start from scratch
|
||||||
let mut editor = self.routing_table().edit_public_internet_routing_domain();
|
let mut editor = self.routing_table().edit_public_internet_routing_domain();
|
||||||
editor.setup_network(
|
editor.setup_network(
|
||||||
protocol_config.outbound,
|
protocol_config.outbound,
|
||||||
@ -113,11 +112,9 @@ impl Network {
|
|||||||
protocol_config.family_global,
|
protocol_config.family_global,
|
||||||
protocol_config.public_internet_capabilities.clone(),
|
protocol_config.public_internet_capabilities.clone(),
|
||||||
);
|
);
|
||||||
editor.commit(true).await;
|
|
||||||
|
|
||||||
// Start from scratch
|
|
||||||
editor.clear_dial_info_details(None, None);
|
editor.clear_dial_info_details(None, None);
|
||||||
editor.set_network_class(None);
|
editor.set_network_class(None);
|
||||||
|
editor.commit(true).await;
|
||||||
|
|
||||||
// Process all protocol and address combinations
|
// Process all protocol and address combinations
|
||||||
let mut unord = FuturesUnordered::new();
|
let mut unord = FuturesUnordered::new();
|
||||||
@ -125,20 +122,15 @@ impl Network {
|
|||||||
for ((at, _llpt, port), protocols) in &inbound_protocol_map {
|
for ((at, _llpt, port), protocols) in &inbound_protocol_map {
|
||||||
let first_pt = protocols.first().unwrap();
|
let first_pt = protocols.first().unwrap();
|
||||||
|
|
||||||
let discovery_context = DiscoveryContext::new(
|
let discovery_context =
|
||||||
self.routing_table(),
|
DiscoveryContext::new(self.routing_table(), self.clone(), *first_pt, *at, *port);
|
||||||
self.clone(),
|
|
||||||
*first_pt,
|
|
||||||
*at,
|
|
||||||
*port,
|
|
||||||
// clear_network_callback.clone(),
|
|
||||||
);
|
|
||||||
discovery_context.discover(&mut unord).await;
|
discovery_context.discover(&mut unord).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for all discovery futures to complete and apply discoverycontexts
|
// Wait for all discovery futures to complete and apply discoverycontexts
|
||||||
let mut all_address_types = AddressTypeSet::new();
|
let mut all_address_types = AddressTypeSet::new();
|
||||||
let mut force_outbound_only = false;
|
let mut force_outbound_only = false;
|
||||||
|
let mut success = true;
|
||||||
loop {
|
loop {
|
||||||
match unord
|
match unord
|
||||||
.next()
|
.next()
|
||||||
@ -181,7 +173,8 @@ impl Network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Some(None)) => {
|
Ok(Some(None)) => {
|
||||||
// Found no new dial info for this protocol/address combination
|
// Found no dial info for this protocol/address combination
|
||||||
|
success = false;
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
// All done, normally
|
// All done, normally
|
||||||
@ -189,11 +182,16 @@ impl Network {
|
|||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// Stop token, exit early without error propagation
|
// Stop token, exit early without error propagation
|
||||||
return Ok(());
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !success {
|
||||||
|
log_net!(debug "Network class discovery failed, trying again");
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
// All done
|
// All done
|
||||||
log_net!(debug "Network class discovery finished with address_types {:?}", all_address_types);
|
log_net!(debug "Network class discovery finished with address_types {:?}", all_address_types);
|
||||||
|
|
||||||
@ -230,7 +228,7 @@ impl Network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make a dialinfo from an address and protocol type
|
/// Make a dialinfo from an address and protocol type
|
||||||
|
@ -82,16 +82,29 @@ pub struct NetworkConnectionStats {
|
|||||||
last_message_recv_time: Option<Timestamp>,
|
last_message_recv_time: Option<Timestamp>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a connection in the connection table for connection-oriented protocols
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(in crate::network_manager) struct NetworkConnection {
|
pub(in crate::network_manager) struct NetworkConnection {
|
||||||
|
/// A unique id for this connection
|
||||||
connection_id: NetworkConnectionId,
|
connection_id: NetworkConnectionId,
|
||||||
|
/// The dial info used to make this connection if it was made with 'connect'
|
||||||
|
/// None if the connection was 'accepted'
|
||||||
|
opt_dial_info: Option<DialInfo>,
|
||||||
|
/// The network flow 5-tuple this connection is over
|
||||||
flow: Flow,
|
flow: Flow,
|
||||||
|
/// Each connection has a processor and this is the task we wait for to ensure it exits cleanly
|
||||||
processor: Option<MustJoinHandle<()>>,
|
processor: Option<MustJoinHandle<()>>,
|
||||||
|
/// When this connection was connected or accepted
|
||||||
established_time: Timestamp,
|
established_time: Timestamp,
|
||||||
|
/// Statistics about network traffic
|
||||||
stats: Arc<Mutex<NetworkConnectionStats>>,
|
stats: Arc<Mutex<NetworkConnectionStats>>,
|
||||||
|
/// To send data out this connection, it is places in this channel
|
||||||
sender: flume::Sender<(Option<Id>, Vec<u8>)>,
|
sender: flume::Sender<(Option<Id>, Vec<u8>)>,
|
||||||
|
/// Drop this when we want to drop the connection
|
||||||
stop_source: Option<StopSource>,
|
stop_source: Option<StopSource>,
|
||||||
|
/// The node we are responsible for protecting the connection for if it is protected
|
||||||
protected_nr: Option<NodeRef>,
|
protected_nr: Option<NodeRef>,
|
||||||
|
/// The number of references to the network connection that exist (handles)
|
||||||
ref_count: usize,
|
ref_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +123,7 @@ impl NetworkConnection {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
connection_id: id,
|
connection_id: id,
|
||||||
|
opt_dial_info: None,
|
||||||
flow,
|
flow,
|
||||||
processor: None,
|
processor: None,
|
||||||
established_time: Timestamp::now(),
|
established_time: Timestamp::now(),
|
||||||
@ -129,6 +143,7 @@ impl NetworkConnection {
|
|||||||
manager_stop_token: StopToken,
|
manager_stop_token: StopToken,
|
||||||
protocol_connection: ProtocolNetworkConnection,
|
protocol_connection: ProtocolNetworkConnection,
|
||||||
connection_id: NetworkConnectionId,
|
connection_id: NetworkConnectionId,
|
||||||
|
opt_dial_info: Option<DialInfo>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Get flow
|
// Get flow
|
||||||
let flow = protocol_connection.flow();
|
let flow = protocol_connection.flow();
|
||||||
@ -164,6 +179,7 @@ impl NetworkConnection {
|
|||||||
// Return the connection
|
// Return the connection
|
||||||
Self {
|
Self {
|
||||||
connection_id,
|
connection_id,
|
||||||
|
opt_dial_info,
|
||||||
flow,
|
flow,
|
||||||
processor: Some(processor),
|
processor: Some(processor),
|
||||||
established_time: Timestamp::now(),
|
established_time: Timestamp::now(),
|
||||||
@ -183,6 +199,10 @@ impl NetworkConnection {
|
|||||||
self.flow
|
self.flow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dial_info(&self) -> Option<DialInfo> {
|
||||||
|
self.opt_dial_info.clone()
|
||||||
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
#[expect(dead_code)]
|
||||||
pub fn unique_flow(&self) -> UniqueFlow {
|
pub fn unique_flow(&self) -> UniqueFlow {
|
||||||
UniqueFlow {
|
UniqueFlow {
|
||||||
|
@ -230,6 +230,64 @@ impl RoutingTable {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn debug_info_entries_fastest(
|
||||||
|
&self,
|
||||||
|
min_state: BucketEntryState,
|
||||||
|
capabilities: Vec<FourCC>,
|
||||||
|
node_count: usize,
|
||||||
|
) -> String {
|
||||||
|
let cur_ts = Timestamp::now();
|
||||||
|
let mut filters = VecDeque::new();
|
||||||
|
filters.push_front(
|
||||||
|
Box::new(|rti: &RoutingTableInner, e: Option<Arc<BucketEntry>>| {
|
||||||
|
let Some(e) = e else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let cap_match = e.with(rti, |_rti, e| {
|
||||||
|
e.has_all_capabilities(RoutingDomain::PublicInternet, &capabilities)
|
||||||
|
});
|
||||||
|
let state = e.with(rti, |_rti, e| e.state(cur_ts));
|
||||||
|
state >= min_state && cap_match
|
||||||
|
}) as RoutingTableEntryFilter,
|
||||||
|
);
|
||||||
|
let nodes = self.find_preferred_fastest_nodes(
|
||||||
|
node_count,
|
||||||
|
filters,
|
||||||
|
|_rti, entry: Option<Arc<BucketEntry>>| {
|
||||||
|
NodeRef::new(self.clone(), entry.unwrap().clone())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let mut out = String::new();
|
||||||
|
for node in nodes {
|
||||||
|
out += &node.operate(|_rti, e| {
|
||||||
|
let state_reason = e.state_reason(cur_ts);
|
||||||
|
format!(
|
||||||
|
" {} [{}] {} [{}]\n",
|
||||||
|
node,
|
||||||
|
Self::format_state_reason(state_reason),
|
||||||
|
e.peer_stats()
|
||||||
|
.latency
|
||||||
|
.as_ref()
|
||||||
|
.map(|l| {
|
||||||
|
format!("{:.2}ms", timestamp_to_secs(l.average.as_u64()) * 1000.0)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| "???.??ms".to_string()),
|
||||||
|
if let Some(ni) = e.node_info(RoutingDomain::PublicInternet) {
|
||||||
|
ni.capabilities()
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(",")
|
||||||
|
} else {
|
||||||
|
"???".to_owned()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn debug_info_entry(&self, node_ref: NodeRef) -> String {
|
pub(crate) fn debug_info_entry(&self, node_ref: NodeRef) -> String {
|
||||||
let cur_ts = Timestamp::now();
|
let cur_ts = Timestamp::now();
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ use super::*;
|
|||||||
|
|
||||||
use futures_util::stream::{FuturesUnordered, StreamExt};
|
use futures_util::stream::{FuturesUnordered, StreamExt};
|
||||||
use futures_util::FutureExt;
|
use futures_util::FutureExt;
|
||||||
|
use stop_token::future::FutureExt as _;
|
||||||
|
|
||||||
const BACKGROUND_SAFETY_ROUTE_COUNT: usize = 2;
|
const BACKGROUND_SAFETY_ROUTE_COUNT: usize = 2;
|
||||||
|
|
||||||
@ -102,10 +103,10 @@ impl RoutingTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Test set of routes and remove the ones that don't test clean
|
/// Test set of routes and remove the ones that don't test clean
|
||||||
#[instrument(level = "trace", skip(self, _stop_token), err)]
|
#[instrument(level = "trace", skip(self, stop_token), err)]
|
||||||
async fn test_route_set(
|
async fn test_route_set(
|
||||||
&self,
|
&self,
|
||||||
_stop_token: StopToken,
|
stop_token: StopToken,
|
||||||
routes_needing_testing: Vec<RouteId>,
|
routes_needing_testing: Vec<RouteId>,
|
||||||
) -> EyreResult<()> {
|
) -> EyreResult<()> {
|
||||||
if routes_needing_testing.is_empty() {
|
if routes_needing_testing.is_empty() {
|
||||||
@ -152,7 +153,7 @@ impl RoutingTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for test_route futures to complete in parallel
|
// Wait for test_route futures to complete in parallel
|
||||||
while unord.next().await.is_some() {}
|
while let Ok(Some(())) = unord.next().timeout_at(stop_token.clone()).await {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process failed routes
|
// Process failed routes
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// Keep member order appropriate for sorting < preference
|
// Keep member order appropriate for sorting < preference
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct DialInfoDetail {
|
pub struct DialInfoDetail {
|
||||||
pub class: DialInfoClass,
|
pub class: DialInfoClass,
|
||||||
pub dial_info: DialInfo,
|
pub dial_info: DialInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for DialInfoDetail {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{:?}:{}", self.class, self.dial_info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MatchesDialInfoFilter for DialInfoDetail {
|
impl MatchesDialInfoFilter for DialInfoDetail {
|
||||||
fn matches_filter(&self, filter: &DialInfoFilter) -> bool {
|
fn matches_filter(&self, filter: &DialInfoFilter) -> bool {
|
||||||
self.dial_info.matches_filter(filter)
|
self.dial_info.matches_filter(filter)
|
||||||
|
@ -15,7 +15,7 @@ pub const CAP_BLOCKSTORE: Capability = FourCC(*b"BLOC");
|
|||||||
|
|
||||||
pub const DISTANCE_METRIC_CAPABILITIES: &[Capability] = &[CAP_DHT, CAP_DHT_WATCH];
|
pub const DISTANCE_METRIC_CAPABILITIES: &[Capability] = &[CAP_DHT, CAP_DHT_WATCH];
|
||||||
|
|
||||||
#[derive(Clone, Default, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct NodeInfo {
|
pub struct NodeInfo {
|
||||||
network_class: NetworkClass,
|
network_class: NetworkClass,
|
||||||
outbound_protocols: ProtocolTypeSet,
|
outbound_protocols: ProtocolTypeSet,
|
||||||
@ -26,6 +26,24 @@ pub struct NodeInfo {
|
|||||||
dial_info_detail_list: Vec<DialInfoDetail>,
|
dial_info_detail_list: Vec<DialInfoDetail>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for NodeInfo {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
// xxx: use field_with once that is on stable. trying to make this structure use fewer log lines when pretty printed
|
||||||
|
f.debug_struct("NodeInfo")
|
||||||
|
.field("network_class", &self.network_class)
|
||||||
|
.field(
|
||||||
|
"outbound_protocols",
|
||||||
|
&format!("{:?}", &self.outbound_protocols),
|
||||||
|
)
|
||||||
|
.field("address_types", &format!("{:?}", &self.address_types))
|
||||||
|
.field("envelope_support", &format!("{:?}", &self.envelope_support))
|
||||||
|
.field("crypto_support", &format!("{:?}", &self.crypto_support))
|
||||||
|
.field("capabilities", &format!("{:?}", &self.capabilities))
|
||||||
|
.field("dial_info_detail_list", &self.dial_info_detail_list)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NodeInfo {
|
impl NodeInfo {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
network_class: NetworkClass,
|
network_class: NetworkClass,
|
||||||
|
@ -743,6 +743,7 @@ impl StorageManagerInner {
|
|||||||
receiver: flume::Receiver<T>,
|
receiver: flume::Receiver<T>,
|
||||||
handler: impl FnMut(T) -> SendPinBoxFuture<bool> + Send + 'static,
|
handler: impl FnMut(T) -> SendPinBoxFuture<bool> + Send + 'static,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.deferred_result_processor.add(receiver, handler)
|
self.deferred_result_processor
|
||||||
|
.add(receiver.into_stream(), handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,9 +204,7 @@ impl StorageManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::collections::hash_map::Entry::Vacant(_) => {
|
std::collections::hash_map::Entry::Vacant(_) => {
|
||||||
panic!(
|
warn!("offline write work items should always be on offline_subkey_writes entries that exist: ignoring key {}", result.key)
|
||||||
"offline write work items should always be on offline_subkey_writes entries that exist"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,9 +610,12 @@ impl VeilidAPI {
|
|||||||
|
|
||||||
let mut min_state = BucketEntryState::Unreliable;
|
let mut min_state = BucketEntryState::Unreliable;
|
||||||
let mut capabilities = vec![];
|
let mut capabilities = vec![];
|
||||||
|
let mut fastest = false;
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if let Some(ms) = get_bucket_entry_state(&arg) {
|
if let Some(ms) = get_bucket_entry_state(&arg) {
|
||||||
min_state = ms;
|
min_state = ms;
|
||||||
|
} else if arg == "fastest" {
|
||||||
|
fastest = true;
|
||||||
} else {
|
} else {
|
||||||
for cap in arg.split(',') {
|
for cap in arg.split(',') {
|
||||||
if let Ok(capfcc) = FourCC::from_str(cap) {
|
if let Ok(capfcc) = FourCC::from_str(cap) {
|
||||||
@ -626,7 +629,10 @@ impl VeilidAPI {
|
|||||||
|
|
||||||
// Dump routing table entries
|
// Dump routing table entries
|
||||||
let routing_table = self.network_manager()?.routing_table();
|
let routing_table = self.network_manager()?.routing_table();
|
||||||
Ok(routing_table.debug_info_entries(min_state, capabilities))
|
Ok(match fastest {
|
||||||
|
true => routing_table.debug_info_entries_fastest(min_state, capabilities, 100000),
|
||||||
|
false => routing_table.debug_info_entries(min_state, capabilities),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_entry(&self, args: String) -> VeilidAPIResult<String> {
|
async fn debug_entry(&self, args: String) -> VeilidAPIResult<String> {
|
||||||
|
@ -398,10 +398,12 @@ async def test_dht_integration_writer_reader():
|
|||||||
for desc0 in records:
|
for desc0 in records:
|
||||||
while True:
|
while True:
|
||||||
rr = await rc0.inspect_dht_record(desc0.key, [])
|
rr = await rc0.inspect_dht_record(desc0.key, [])
|
||||||
if len(rr.offline_subkeys) == 0:
|
left = len(rr.offline_subkeys)
|
||||||
|
if left == 0:
|
||||||
await rc0.close_dht_record(desc0.key)
|
await rc0.close_dht_record(desc0.key)
|
||||||
break
|
break
|
||||||
time.sleep(1)
|
print(f' {left} left')
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
# read dht records on server 1
|
# read dht records on server 1
|
||||||
print(f'reading {COUNT} records')
|
print(f'reading {COUNT} records')
|
||||||
@ -455,13 +457,15 @@ async def test_dht_write_read_local():
|
|||||||
|
|
||||||
print(f' {n}')
|
print(f' {n}')
|
||||||
|
|
||||||
print(f'syncing records to the network')
|
print('syncing records to the network')
|
||||||
for desc0 in records:
|
for desc0 in records:
|
||||||
while True:
|
while True:
|
||||||
rr = await rc0.inspect_dht_record(desc0.key, [])
|
rr = await rc0.inspect_dht_record(desc0.key, [])
|
||||||
if len(rr.offline_subkeys) == 0:
|
left = len(rr.offline_subkeys)
|
||||||
|
if left == 0:
|
||||||
await rc0.close_dht_record(desc0.key)
|
await rc0.close_dht_record(desc0.key)
|
||||||
break
|
break
|
||||||
|
print(f' {left} left')
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
# read dht records on server 0
|
# read dht records on server 0
|
||||||
|
@ -9,6 +9,7 @@ use super::*;
|
|||||||
|
|
||||||
/// Background processor for streams
|
/// Background processor for streams
|
||||||
/// Handles streams to completion, passing each item from the stream to a callback
|
/// Handles streams to completion, passing each item from the stream to a callback
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct DeferredStreamProcessor {
|
pub struct DeferredStreamProcessor {
|
||||||
pub opt_deferred_stream_channel: Option<flume::Sender<SendPinBoxFuture<()>>>,
|
pub opt_deferred_stream_channel: Option<flume::Sender<SendPinBoxFuture<()>>>,
|
||||||
pub opt_stopper: Option<StopSource>,
|
pub opt_stopper: Option<StopSource>,
|
||||||
@ -98,9 +99,9 @@ impl DeferredStreamProcessor {
|
|||||||
/// * 'handler' is the callback to handle each item from the stream
|
/// * 'handler' is the callback to handle each item from the stream
|
||||||
///
|
///
|
||||||
/// Returns 'true' if the stream was added for processing, and 'false' if the stream could not be added, possibly due to not being initialized.
|
/// Returns 'true' if the stream was added for processing, and 'false' if the stream could not be added, possibly due to not being initialized.
|
||||||
pub fn add<T: Send + 'static>(
|
pub fn add<T: Send + 'static, S: futures_util::Stream<Item = T> + Unpin + Send + 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
receiver: flume::Receiver<T>,
|
mut receiver: S,
|
||||||
mut handler: impl FnMut(T) -> SendPinBoxFuture<bool> + Send + 'static,
|
mut handler: impl FnMut(T) -> SendPinBoxFuture<bool> + Send + 'static,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let Some(st) = self.opt_stopper.as_ref().map(|s| s.token()) else {
|
let Some(st) = self.opt_stopper.as_ref().map(|s| s.token()) else {
|
||||||
@ -110,7 +111,7 @@ impl DeferredStreamProcessor {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let drp = Box::pin(async move {
|
let drp = Box::pin(async move {
|
||||||
while let Ok(Ok(res)) = receiver.recv_async().timeout_at(st.clone()).await {
|
while let Ok(Some(res)) = receiver.next().timeout_at(st.clone()).await {
|
||||||
if !handler(res).await {
|
if !handler(res).await {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user