diff --git a/veilid-core/src/network_manager/mod.rs b/veilid-core/src/network_manager/mod.rs index 4f370784..504b27fc 100644 --- a/veilid-core/src/network_manager/mod.rs +++ b/veilid-core/src/network_manager/mod.rs @@ -112,7 +112,7 @@ struct ClientWhitelistEntry { // Mechanism required to contact another node #[derive(Clone, Debug)] -enum ContactMethod { +pub(crate) enum ContactMethod { Unreachable, // Node is not reachable by any means Direct(DialInfo), // Contact the node directly SignalReverse(NodeRef, NodeRef), // Request via signal the node connect back directly @@ -1054,7 +1054,7 @@ impl NetworkManager { // Figure out how to reach a node #[instrument(level = "trace", skip(self), ret)] - fn get_contact_method(&self, target_node_ref: NodeRef) -> ContactMethod { + pub(crate) fn get_contact_method(&self, target_node_ref: NodeRef) -> ContactMethod { // Try local first let out = self.get_contact_method_local(target_node_ref.clone()); if !matches!(out, ContactMethod::Unreachable) { diff --git a/veilid-core/src/routing_table/bucket_entry.rs b/veilid-core/src/routing_table/bucket_entry.rs index dd9742da..b3b340df 100644 --- a/veilid-core/src/routing_table/bucket_entry.rs +++ b/veilid-core/src/routing_table/bucket_entry.rs @@ -165,7 +165,9 @@ impl BucketEntryInner { pub fn set_last_connection(&mut self, last_connection: ConnectionDescriptor, timestamp: u64) { self.last_connection = Some((last_connection, timestamp)); } - + pub fn clear_last_connection(&mut self) { + self.last_connection = None; + } pub fn last_connection(&self) -> Option<(ConnectionDescriptor, u64)> { self.last_connection } diff --git a/veilid-core/src/routing_table/mod.rs b/veilid-core/src/routing_table/mod.rs index 1426c930..584df8ab 100644 --- a/veilid-core/src/routing_table/mod.rs +++ b/veilid-core/src/routing_table/mod.rs @@ -370,17 +370,37 @@ impl RoutingTable { // Attempt to empty the routing table // should only be performed when there are no node_refs (detached) - pub fn purge(&self) { + pub fn purge_buckets(&self) { let mut inner = self.inner.write(); log_rtab!( - "Starting routing table purge. Table currently has {} nodes", + "Starting routing table buckets purge. Table currently has {} nodes", inner.bucket_entry_count ); for bucket in &mut inner.buckets { bucket.kick(0); } log_rtab!(debug - "Routing table purge complete. Routing table now has {} nodes", + "Routing table buckets purge complete. Routing table now has {} nodes", + inner.bucket_entry_count + ); + } + + // Attempt to remove last_connections from entries + pub fn purge_last_connections(&self) { + let mut inner = self.inner.write(); + log_rtab!( + "Starting routing table last_connections purge. Table currently has {} nodes", + inner.bucket_entry_count + ); + for bucket in &mut inner.buckets { + for entry in bucket.entries() { + entry.1.with_mut(|e| { + e.clear_last_connection(); + }); + } + } + log_rtab!(debug + "Routing table last_connections purge complete. Routing table now has {} nodes", inner.bucket_entry_count ); } diff --git a/veilid-core/src/veilid_api/debug.rs b/veilid-core/src/veilid_api/debug.rs index d9b39dc8..067e400d 100644 --- a/veilid-core/src/veilid_api/debug.rs +++ b/veilid-core/src/veilid_api/debug.rs @@ -201,8 +201,20 @@ impl VeilidAPI { ) { apibail_internal!("Must be detached to purge"); } - self.network_manager()?.routing_table().purge(); + self.network_manager()?.routing_table().purge_buckets(); Ok("Buckets purged".to_owned()) + } else if args[0] == "connections" { + // Purge connection table + let connection_manager = self.network_manager()?.connection_manager(); + connection_manager.shutdown().await; + connection_manager.startup().await; + + // Eliminate last_connections from routing table entries + self.network_manager()? + .routing_table() + .purge_last_connections(); + + Ok("Connections purged".to_owned()) } else { Err(VeilidAPIError::InvalidArgument { context: "debug_purge".to_owned(), @@ -244,6 +256,59 @@ impl VeilidAPI { Ok("Detached".to_owned()) } + async fn debug_contact(&self, args: String) -> Result { + let args: Vec = args.split_whitespace().map(|s| s.to_owned()).collect(); + + let node_id = get_debug_argument_at(&args, 0, "debug_contact", "node_id", get_dht_key)?; + + let network_manager = self.network_manager()?; + let routing_table = network_manager.routing_table(); + + let nr = match routing_table.lookup_node_ref(node_id) { + Some(nr) => nr, + None => return Ok("Node id not found in routing table".to_owned()), + }; + + let cm = network_manager.get_contact_method(nr); + + Ok(format!("{:#?}", cm)) + } + + async fn debug_ping(&self, args: String) -> Result { + let args: Vec = args.split_whitespace().map(|s| s.to_owned()).collect(); + + let node_id = get_debug_argument_at(&args, 0, "debug_ping", "node_id", get_dht_key)?; + + let routing_table = self.network_manager()?.routing_table(); + + let nr = match routing_table.lookup_node_ref(node_id) { + Some(nr) => nr, + None => return Ok("Node id not found in routing table".to_owned()), + }; + + let rpc = self.network_manager()?.rpc_processor(); + + // Dump routing table entry + let out = match rpc + .rpc_call_status(nr) + .await + .map_err(VeilidAPIError::internal)? + { + NetworkResult::Value(v) => v, + NetworkResult::Timeout => { + return Ok("Timeout".to_owned()); + } + NetworkResult::NoConnection(e) => { + return Ok(format!("NoConnection({})", e)); + } + NetworkResult::InvalidMessage(e) => { + return Ok(format!("InvalidMessage({})", e)); + } + }; + + Ok(format!("{:#?}", out)) + } + pub async fn debug_help(&self, _args: String) -> Result { Ok(r#">>> Debug commands: help @@ -253,10 +318,12 @@ impl VeilidAPI { entry [node_id] nodeinfo config [key [new value]] - purge buckets + purge [buckets|connections] attach detach restart network + ping [node_id] + contact [node_id] "# .to_owned()) } @@ -282,6 +349,10 @@ impl VeilidAPI { self.debug_entries(rest).await } else if arg == "entry" { self.debug_entry(rest).await + } else if arg == "ping" { + self.debug_ping(rest).await + } else if arg == "contact" { + self.debug_contact(rest).await } else if arg == "nodeinfo" { self.debug_nodeinfo(rest).await } else if arg == "purge" {