diff --git a/veilid-core/src/routing_table/route_spec_store/mod.rs b/veilid-core/src/routing_table/route_spec_store/mod.rs index 11410b74..32fd3d79 100644 --- a/veilid-core/src/routing_table/route_spec_store/mod.rs +++ b/veilid-core/src/routing_table/route_spec_store/mod.rs @@ -1462,14 +1462,14 @@ impl RouteSpecStore { Ok(out) } - /// Import a remote private route for compilation + /// Import a remote private route set blob for compilation /// It is safe to import the same route more than once and it will return the same route id /// Returns a route set id #[cfg_attr( feature = "verbose-tracing", instrument(level = "trace", skip(self, blob), ret, err) )] - pub fn import_remote_private_route(&self, blob: Vec) -> VeilidAPIResult { + pub fn import_remote_private_route_blob(&self, blob: Vec) -> VeilidAPIResult { let cur_ts = get_aligned_timestamp(); // decode the pr blob @@ -1502,6 +1502,46 @@ impl RouteSpecStore { Ok(id) } + /// Add a single remote private route for compilation + /// It is safe to add the same route more than once and it will return the same route id + /// Returns a route set id + #[cfg_attr( + feature = "verbose-tracing", + instrument(level = "trace", skip(self, blob), ret, err) + )] + pub fn add_remote_private_route( + &self, + private_route: PrivateRoute, + ) -> VeilidAPIResult { + let cur_ts = get_aligned_timestamp(); + + // Make a single route set + let private_routes = vec![private_route]; + + // make the route id + let id = self.generate_remote_route_id(&private_routes)?; + + // validate the private routes + let inner = &mut *self.inner.lock(); + for private_route in &private_routes { + // ensure private route has first hop + if !matches!(private_route.hops, PrivateRouteHops::FirstHop(_)) { + apibail_generic!("private route must have first hop"); + } + + // ensure this isn't also an allocated route + // if inner.content.get_id_by_key(&private_route.public_key.value).is_some() { + // bail!("should not import allocated route"); + // } + } + + inner + .cache + .cache_remote_private_route(cur_ts, id, private_routes); + + Ok(id) + } + /// Release a remote private route that is no longer in use #[cfg_attr( feature = "verbose-tracing", diff --git a/veilid-core/src/rpc_processor/destination.rs b/veilid-core/src/rpc_processor/destination.rs index 13f40a63..808b7cb4 100644 --- a/veilid-core/src/rpc_processor/destination.rs +++ b/veilid-core/src/rpc_processor/destination.rs @@ -114,7 +114,7 @@ impl Destination { } } - pub fn get_target(&self) -> Target { + pub fn get_target(&self, rss: RouteSpecStore) -> Result { match self { Destination::Direct { node, @@ -124,11 +124,36 @@ impl Destination { relay: _, node, safety_selection: _, - } => Target::NodeId(node.best_node_id()), + } => Ok(Target::NodeId(node.best_node_id())), Destination::PrivateRoute { private_route, safety_selection: _, - } => Target::PrivateRoute(private_route.public_key.value), + } => { + // Add the remote private route if we're going to keep the id + let route_id = rss + .add_remote_private_route(private_route.clone()) + .map_err(RPCError::protocol)?; + + Ok(Target::PrivateRoute(route_id)) + } + } + } + + pub fn get_private_route(&self) -> Option { + match self { + Destination::Direct { + node: _, + safety_selection: _, + } + | Destination::Relay { + relay: _, + node: _, + safety_selection: _, + } => None, + Destination::PrivateRoute { + private_route, + safety_selection: _, + } => Some(private_route.clone()), } } } diff --git a/veilid-core/src/rpc_processor/rpc_set_value.rs b/veilid-core/src/rpc_processor/rpc_set_value.rs index 2e7f7f12..36bead3a 100644 --- a/veilid-core/src/rpc_processor/rpc_set_value.rs +++ b/veilid-core/src/rpc_processor/rpc_set_value.rs @@ -188,6 +188,8 @@ impl RPCProcessor { ) ->RPCNetworkResult<()> { // Ignore if disabled let routing_table = self.routing_table(); + let rss = routing_table.route_spec_store(); + let opi = routing_table.get_own_peer_info(msg.header.routing_domain()); if !opi .signed_node_info() @@ -224,7 +226,7 @@ impl RPCProcessor { // Get target for ValueChanged notifications let dest = network_result_try!(self.get_respond_to_destination(&msg)); - let target = dest.get_target(); + let target = dest.get_target(rss)?; // Get the nodes that we know about that are closer to the the key than our own node let routing_table = self.routing_table(); diff --git a/veilid-core/src/rpc_processor/rpc_watch_value.rs b/veilid-core/src/rpc_processor/rpc_watch_value.rs index 84bc900d..77351cc8 100644 --- a/veilid-core/src/rpc_processor/rpc_watch_value.rs +++ b/veilid-core/src/rpc_processor/rpc_watch_value.rs @@ -145,6 +145,9 @@ impl RPCProcessor { #[cfg_attr(feature="verbose-tracing", instrument(level = "trace", skip(self, msg), fields(msg.operation.op_id), ret, err))] pub(crate) async fn process_watch_value_q(&self, msg: RPCMessage) -> RPCNetworkResult<()> { + let routing_table = self.routing_table(); + let rss = routing_table.route_spec_store(); + // Ensure this never came over a private route, safety route is okay though match &msg.header.detail { RPCMessageHeaderDetail::Direct(_) | RPCMessageHeaderDetail::SafetyRouted(_) => {} @@ -177,7 +180,7 @@ impl RPCProcessor { // Get target for ValueChanged notifications let dest = network_result_try!(self.get_respond_to_destination(&msg)); - let target = dest.get_target(); + let target = dest.get_target(rss)?; #[cfg(feature = "debug-dht")] { @@ -195,7 +198,6 @@ impl RPCProcessor { } // Get the nodes that we know about that are closer to the the key than our own node - let routing_table = self.routing_table(); let closer_to_key_peers = network_result_try!( routing_table.find_preferred_peers_closer_to_key(key, vec![CAP_DHT]) ); diff --git a/veilid-core/src/veilid_api/api.rs b/veilid-core/src/veilid_api/api.rs index 4e202853..12e282a5 100644 --- a/veilid-core/src/veilid_api/api.rs +++ b/veilid-core/src/veilid_api/api.rs @@ -295,7 +295,7 @@ impl VeilidAPI { /// Returns a route id that can be used to send private messages to the node creating this route. pub fn import_remote_private_route(&self, blob: Vec) -> VeilidAPIResult { let rss = self.routing_table()?.route_spec_store(); - rss.import_remote_private_route(blob) + rss.import_remote_private_route_blob(blob) } /// Release either a locally allocated or remotely imported private route diff --git a/veilid-core/src/veilid_api/debug.rs b/veilid-core/src/veilid_api/debug.rs index f67ca339..e7a4f10a 100644 --- a/veilid-core/src/veilid_api/debug.rs +++ b/veilid-core/src/veilid_api/debug.rs @@ -1307,7 +1307,7 @@ impl VeilidAPI { .map_err(VeilidAPIError::generic)?; let rss = self.routing_table()?.route_spec_store(); let route_id = rss - .import_remote_private_route(blob_dec) + .import_remote_private_route_blob(blob_dec) .map_err(VeilidAPIError::generic)?; let mut dc = DEBUG_CACHE.lock();