clean up handling of errors in route spec store
This commit is contained in:
parent
353c907497
commit
97be49a9a7
@ -50,7 +50,11 @@ impl Network {
|
|||||||
let mut add = false;
|
let mut add = false;
|
||||||
|
|
||||||
if let Some(edi) = existing_dial_info.get(&(pt, at)) {
|
if let Some(edi) = existing_dial_info.get(&(pt, at)) {
|
||||||
if did.class <= edi.class {
|
// Is the dial info class better than our existing dial info?
|
||||||
|
// Or is the new dial info the same class, but different? Only change if things are different.
|
||||||
|
if did.class < edi.class
|
||||||
|
|| (did.class == edi.class && did.dial_info != edi.dial_info)
|
||||||
|
{
|
||||||
// Better or same dial info class was found, clear existing dialinfo for this pt/at pair
|
// Better or same dial info class was found, clear existing dialinfo for this pt/at pair
|
||||||
// Only keep one dial info per protocol/address type combination
|
// Only keep one dial info per protocol/address type combination
|
||||||
clear = true;
|
clear = true;
|
||||||
|
@ -924,7 +924,7 @@ impl BucketEntry {
|
|||||||
|
|
||||||
impl Drop for BucketEntry {
|
impl Drop for BucketEntry {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.ref_count.load(Ordering::Relaxed) != 0 {
|
if self.ref_count.load(Ordering::Acquire) != 0 {
|
||||||
#[cfg(feature = "tracking")]
|
#[cfg(feature = "tracking")]
|
||||||
{
|
{
|
||||||
println!("NodeRef Tracking");
|
println!("NodeRef Tracking");
|
||||||
|
@ -379,7 +379,7 @@ impl NodeRef {
|
|||||||
entry: Arc<BucketEntry>,
|
entry: Arc<BucketEntry>,
|
||||||
filter: Option<NodeRefFilter>,
|
filter: Option<NodeRefFilter>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
entry.ref_count.fetch_add(1u32, Ordering::Relaxed);
|
entry.ref_count.fetch_add(1u32, Ordering::AcqRel);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
common: NodeRefBaseCommon {
|
common: NodeRefBaseCommon {
|
||||||
@ -438,7 +438,7 @@ impl Clone for NodeRef {
|
|||||||
self.common
|
self.common
|
||||||
.entry
|
.entry
|
||||||
.ref_count
|
.ref_count
|
||||||
.fetch_add(1u32, Ordering::Relaxed);
|
.fetch_add(1u32, Ordering::AcqRel);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
common: NodeRefBaseCommon {
|
common: NodeRefBaseCommon {
|
||||||
@ -479,7 +479,7 @@ impl Drop for NodeRef {
|
|||||||
.common
|
.common
|
||||||
.entry
|
.entry
|
||||||
.ref_count
|
.ref_count
|
||||||
.fetch_sub(1u32, Ordering::Relaxed)
|
.fetch_sub(1u32, Ordering::AcqRel)
|
||||||
- 1;
|
- 1;
|
||||||
if new_ref_count == 0 {
|
if new_ref_count == 0 {
|
||||||
// get node ids with inner unlocked because nothing could be referencing this entry now
|
// get node ids with inner unlocked because nothing could be referencing this entry now
|
||||||
|
@ -17,6 +17,9 @@ use crate::veilid_api::*;
|
|||||||
|
|
||||||
use permutation::*;
|
use permutation::*;
|
||||||
|
|
||||||
|
// NOCOMMIT
|
||||||
|
//static DEBUG_COUNT: Mutex<i32> = Mutex::new(10);
|
||||||
|
|
||||||
/// The size of the remote private route cache
|
/// The size of the remote private route cache
|
||||||
const REMOTE_PRIVATE_ROUTE_CACHE_SIZE: usize = 1024;
|
const REMOTE_PRIVATE_ROUTE_CACHE_SIZE: usize = 1024;
|
||||||
/// Remote private route cache entries expire in 5 minutes if they haven't been used
|
/// Remote private route cache entries expire in 5 minutes if they haven't been used
|
||||||
@ -151,20 +154,21 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Purge the route spec store
|
/// Purge the route spec store
|
||||||
pub async fn purge(&self) -> EyreResult<()> {
|
pub async fn purge(&self) -> VeilidAPIResult<()> {
|
||||||
{
|
{
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
inner.content = Default::default();
|
inner.content = Default::default();
|
||||||
inner.cache = Default::default();
|
inner.cache = Default::default();
|
||||||
}
|
}
|
||||||
self.save().await
|
self.save().await.map_err(VeilidAPIError::internal)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new route
|
/// Create a new route
|
||||||
/// Prefers nodes that are not currently in use by another route
|
/// Prefers nodes that are not currently in use by another route
|
||||||
/// The route is not yet tested for its reachability
|
/// The route is not yet tested for its reachability
|
||||||
/// Returns None if no route could be allocated at this time
|
/// Returns Err(VeilidAPIError::TryAgain) if no route could be allocated at this time
|
||||||
/// Returns Some route id string
|
/// Returns other errors on failure
|
||||||
|
/// Returns Ok(route id string) on success
|
||||||
#[instrument(level = "trace", skip(self), ret, err)]
|
#[instrument(level = "trace", skip(self), ret, err)]
|
||||||
pub fn allocate_route(
|
pub fn allocate_route(
|
||||||
&self,
|
&self,
|
||||||
@ -174,7 +178,7 @@ impl RouteSpecStore {
|
|||||||
hop_count: usize,
|
hop_count: usize,
|
||||||
directions: DirectionSet,
|
directions: DirectionSet,
|
||||||
avoid_nodes: &[TypedKey],
|
avoid_nodes: &[TypedKey],
|
||||||
) -> EyreResult<Option<RouteId>> {
|
) -> VeilidAPIResult<RouteId> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let routing_table = self.unlocked_inner.routing_table.clone();
|
let routing_table = self.unlocked_inner.routing_table.clone();
|
||||||
let rti = &mut *routing_table.inner.write();
|
let rti = &mut *routing_table.inner.write();
|
||||||
@ -203,21 +207,29 @@ impl RouteSpecStore {
|
|||||||
hop_count: usize,
|
hop_count: usize,
|
||||||
directions: DirectionSet,
|
directions: DirectionSet,
|
||||||
avoid_nodes: &[TypedKey],
|
avoid_nodes: &[TypedKey],
|
||||||
) -> EyreResult<Option<RouteId>> {
|
) -> VeilidAPIResult<RouteId> {
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
|
|
||||||
if hop_count < 1 {
|
if hop_count < 1 {
|
||||||
bail!("Not allocating route less than one hop in length");
|
apibail_invalid_argument!(
|
||||||
|
"Not allocating route less than one hop in length",
|
||||||
|
"hop_count",
|
||||||
|
hop_count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if hop_count > self.unlocked_inner.max_route_hop_count {
|
if hop_count > self.unlocked_inner.max_route_hop_count {
|
||||||
bail!("Not allocating route longer than max route hop count");
|
apibail_invalid_argument!(
|
||||||
|
"Not allocating route longer than max route hop count",
|
||||||
|
"hop_count",
|
||||||
|
hop_count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we have a valid network class so our peer info is useful
|
// Ensure we have a valid network class so our peer info is useful
|
||||||
if !rti.has_valid_network_class(RoutingDomain::PublicInternet) {
|
if !rti.has_valid_network_class(RoutingDomain::PublicInternet) {
|
||||||
log_rtab!(debug "unable to allocate route until we have a valid PublicInternet network class");
|
log_rtab!(debug "unable to allocate route until we have a valid PublicInternet network class");
|
||||||
return Ok(None);
|
apibail_try_again!();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get our peer info
|
// Get our peer info
|
||||||
@ -370,7 +382,7 @@ impl RouteSpecStore {
|
|||||||
// If we couldn't find enough nodes, wait until we have more nodes in the routing table
|
// If we couldn't find enough nodes, wait until we have more nodes in the routing table
|
||||||
if nodes.len() < hop_count {
|
if nodes.len() < hop_count {
|
||||||
log_rtab!(debug "not enough nodes to construct route at this time");
|
log_rtab!(debug "not enough nodes to construct route at this time");
|
||||||
return Ok(None);
|
apibail_try_again!();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get peer info for everything
|
// Get peer info for everything
|
||||||
@ -523,7 +535,7 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
if route_nodes.is_empty() {
|
if route_nodes.is_empty() {
|
||||||
log_rtab!(debug "unable to find unique route at this time");
|
log_rtab!(debug "unable to find unique route at this time");
|
||||||
return Ok(None);
|
apibail_try_again!();
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(perm_func);
|
drop(perm_func);
|
||||||
@ -579,7 +591,7 @@ impl RouteSpecStore {
|
|||||||
// Keep route in spec store
|
// Keep route in spec store
|
||||||
inner.content.add_detail(id, rssd);
|
inner.content.add_detail(id, rssd);
|
||||||
|
|
||||||
Ok(Some(id))
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// validate data using a private route's key and signature chain
|
/// validate data using a private route's key and signature chain
|
||||||
@ -651,17 +663,21 @@ impl RouteSpecStore {
|
|||||||
feature = "verbose-tracing",
|
feature = "verbose-tracing",
|
||||||
instrument(level = "trace", skip(self), ret, err)
|
instrument(level = "trace", skip(self), ret, err)
|
||||||
)]
|
)]
|
||||||
async fn test_allocated_route(&self, private_route_id: RouteId) -> EyreResult<bool> {
|
async fn test_allocated_route(&self, private_route_id: RouteId) -> VeilidAPIResult<bool> {
|
||||||
// Make loopback route to test with
|
// Make loopback route to test with
|
||||||
let dest = {
|
let dest = {
|
||||||
// Get the best private route for this id
|
// Get the best private route for this id
|
||||||
let (key, hop_count) = {
|
let (key, hop_count) = {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let Some(rssd) = inner.content.get_detail(&private_route_id) else {
|
let Some(rssd) = inner.content.get_detail(&private_route_id) else {
|
||||||
bail!("route id not allocated");
|
apibail_invalid_argument!(
|
||||||
|
"route id not allocated",
|
||||||
|
"private_route_id",
|
||||||
|
private_route_id
|
||||||
|
);
|
||||||
};
|
};
|
||||||
let Some(key) = rssd.get_best_route_set_key() else {
|
let Some(key) = rssd.get_best_route_set_key() else {
|
||||||
bail!("no best key to test allocated route");
|
apibail_internal!("no best key to test allocated route");
|
||||||
};
|
};
|
||||||
// Match the private route's hop length for safety route length
|
// Match the private route's hop length for safety route length
|
||||||
let hop_count = rssd.hop_count();
|
let hop_count = rssd.hop_count();
|
||||||
@ -703,12 +719,12 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self), ret, err)]
|
#[instrument(level = "trace", skip(self), ret, err)]
|
||||||
async fn test_remote_route(&self, private_route_id: RouteId) -> EyreResult<bool> {
|
async fn test_remote_route(&self, private_route_id: RouteId) -> VeilidAPIResult<bool> {
|
||||||
// Make private route test
|
// Make private route test
|
||||||
let dest = {
|
let dest = {
|
||||||
// Get the route to test
|
// Get the route to test
|
||||||
let Some(private_route) = self.best_remote_private_route(&private_route_id) else {
|
let Some(private_route) = self.best_remote_private_route(&private_route_id) else {
|
||||||
bail!("no best key to test remote route");
|
apibail_internal!("no best key to test remote route");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Always test routes with safety routes that are more likely to succeed
|
// Always test routes with safety routes that are more likely to succeed
|
||||||
@ -777,7 +793,7 @@ impl RouteSpecStore {
|
|||||||
feature = "verbose-tracing",
|
feature = "verbose-tracing",
|
||||||
instrument(level = "trace", skip(self), ret, err)
|
instrument(level = "trace", skip(self), ret, err)
|
||||||
)]
|
)]
|
||||||
pub async fn test_route(&self, id: RouteId) -> EyreResult<bool> {
|
pub async fn test_route(&self, id: RouteId) -> VeilidAPIResult<bool> {
|
||||||
let is_remote = self.is_route_id_remote(&id);
|
let is_remote = self.is_route_id_remote(&id);
|
||||||
if is_remote {
|
if is_remote {
|
||||||
self.test_remote_route(id).await
|
self.test_remote_route(id).await
|
||||||
@ -904,13 +920,14 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compiles a safety route to the private route, with caching
|
/// Compiles a safety route to the private route, with caching
|
||||||
/// Returns an Err() if the parameters are wrong
|
/// Returns Err(VeilidAPIError::TryAgain) if no allocation could happen at this time (not an error)
|
||||||
/// Returns Ok(None) if no allocation could happen at this time (not an error)
|
/// Returns other Err() if the parameters are wrong
|
||||||
|
/// Returns Ok(compiled route) on success
|
||||||
pub fn compile_safety_route(
|
pub fn compile_safety_route(
|
||||||
&self,
|
&self,
|
||||||
safety_selection: SafetySelection,
|
safety_selection: SafetySelection,
|
||||||
mut private_route: PrivateRoute,
|
mut private_route: PrivateRoute,
|
||||||
) -> EyreResult<Option<CompiledRoute>> {
|
) -> VeilidAPIResult<CompiledRoute> {
|
||||||
// let profile_start_ts = get_timestamp();
|
// let profile_start_ts = get_timestamp();
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let routing_table = self.unlocked_inner.routing_table.clone();
|
let routing_table = self.unlocked_inner.routing_table.clone();
|
||||||
@ -920,7 +937,7 @@ impl RouteSpecStore {
|
|||||||
let crypto_kind = private_route.crypto_kind();
|
let crypto_kind = private_route.crypto_kind();
|
||||||
let crypto = routing_table.crypto();
|
let crypto = routing_table.crypto();
|
||||||
let Some(vcrypto) = crypto.get(crypto_kind) else {
|
let Some(vcrypto) = crypto.get(crypto_kind) else {
|
||||||
bail!("crypto not supported for route");
|
apibail_generic!("crypto not supported for route");
|
||||||
};
|
};
|
||||||
let pr_pubkey = private_route.public_key.value;
|
let pr_pubkey = private_route.public_key.value;
|
||||||
let pr_hopcount = private_route.hop_count as usize;
|
let pr_hopcount = private_route.hop_count as usize;
|
||||||
@ -928,7 +945,11 @@ impl RouteSpecStore {
|
|||||||
|
|
||||||
// Check private route hop count isn't larger than the max route hop count plus one for the 'first hop' header
|
// Check private route hop count isn't larger than the max route hop count plus one for the 'first hop' header
|
||||||
if pr_hopcount > (max_route_hop_count + 1) {
|
if pr_hopcount > (max_route_hop_count + 1) {
|
||||||
bail!("private route hop count too long");
|
apibail_invalid_argument!(
|
||||||
|
"private route hop count too long",
|
||||||
|
"private_route.hop_count",
|
||||||
|
pr_hopcount
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// See if we are using a safety route, if not, short circuit this operation
|
// See if we are using a safety route, if not, short circuit this operation
|
||||||
let safety_spec = match safety_selection {
|
let safety_spec = match safety_selection {
|
||||||
@ -937,24 +958,26 @@ impl RouteSpecStore {
|
|||||||
// Safety route stub with the node's public key as the safety route key since it's the 0th hop
|
// Safety route stub with the node's public key as the safety route key since it's the 0th hop
|
||||||
SafetySelection::Unsafe(sequencing) => {
|
SafetySelection::Unsafe(sequencing) => {
|
||||||
let Some(pr_first_hop_node) = private_route.pop_first_hop() else {
|
let Some(pr_first_hop_node) = private_route.pop_first_hop() else {
|
||||||
bail!("compiled private route should have first hop");
|
apibail_generic!("compiled private route should have first hop");
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt_first_hop = match pr_first_hop_node {
|
let opt_first_hop = match pr_first_hop_node {
|
||||||
RouteNode::NodeId(id) => {
|
RouteNode::NodeId(id) => rti
|
||||||
rti.lookup_node_ref(routing_table.clone(), TypedKey::new(crypto_kind, id))?
|
.lookup_node_ref(routing_table.clone(), TypedKey::new(crypto_kind, id))
|
||||||
}
|
.map_err(VeilidAPIError::internal)?,
|
||||||
RouteNode::PeerInfo(pi) => Some(rti.register_node_with_peer_info(
|
RouteNode::PeerInfo(pi) => Some(
|
||||||
|
rti.register_node_with_peer_info(
|
||||||
routing_table.clone(),
|
routing_table.clone(),
|
||||||
RoutingDomain::PublicInternet,
|
RoutingDomain::PublicInternet,
|
||||||
*pi,
|
*pi,
|
||||||
false,
|
false,
|
||||||
)?),
|
)
|
||||||
|
.map_err(VeilidAPIError::internal)?,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
if opt_first_hop.is_none() {
|
if opt_first_hop.is_none() {
|
||||||
// Can't reach this private route any more
|
// Can't reach this private route any more
|
||||||
log_rtab!(debug "can't reach private route any more");
|
apibail_generic!("can't reach private route any more");
|
||||||
return Ok(None);
|
|
||||||
}
|
}
|
||||||
let mut first_hop = opt_first_hop.unwrap();
|
let mut first_hop = opt_first_hop.unwrap();
|
||||||
|
|
||||||
@ -963,14 +986,14 @@ impl RouteSpecStore {
|
|||||||
|
|
||||||
// Return the compiled safety route
|
// Return the compiled safety route
|
||||||
//println!("compile_safety_route profile (stub): {} us", (get_timestamp() - profile_start_ts));
|
//println!("compile_safety_route profile (stub): {} us", (get_timestamp() - profile_start_ts));
|
||||||
return Ok(Some(CompiledRoute {
|
return Ok(CompiledRoute {
|
||||||
safety_route: SafetyRoute::new_stub(
|
safety_route: SafetyRoute::new_stub(
|
||||||
routing_table.node_id(crypto_kind),
|
routing_table.node_id(crypto_kind),
|
||||||
private_route,
|
private_route,
|
||||||
),
|
),
|
||||||
secret: routing_table.node_id_secret_key(crypto_kind),
|
secret: routing_table.node_id_secret_key(crypto_kind),
|
||||||
first_hop,
|
first_hop,
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -983,9 +1006,9 @@ impl RouteSpecStore {
|
|||||||
pr_pubkey
|
pr_pubkey
|
||||||
} else {
|
} else {
|
||||||
let Some(avoid_node_id) = private_route.first_hop_node_id() else {
|
let Some(avoid_node_id) = private_route.first_hop_node_id() else {
|
||||||
bail!("compiled private route should have first hop");
|
apibail_generic!("compiled private route should have first hop");
|
||||||
};
|
};
|
||||||
let Some(sr_pubkey) = self.get_route_for_safety_spec_inner(
|
self.get_route_for_safety_spec_inner(
|
||||||
inner,
|
inner,
|
||||||
rti,
|
rti,
|
||||||
crypto_kind,
|
crypto_kind,
|
||||||
@ -993,22 +1016,17 @@ impl RouteSpecStore {
|
|||||||
Direction::Outbound.into(),
|
Direction::Outbound.into(),
|
||||||
&[avoid_node_id],
|
&[avoid_node_id],
|
||||||
)?
|
)?
|
||||||
else {
|
|
||||||
// No safety route could be found for this spec
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
sr_pubkey
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Look up a few things from the safety route detail we want for the compiled route and don't borrow inner
|
// Look up a few things from the safety route detail we want for the compiled route and don't borrow inner
|
||||||
let Some(safety_route_id) = inner.content.get_id_by_key(&sr_pubkey) else {
|
let Some(safety_route_id) = inner.content.get_id_by_key(&sr_pubkey) else {
|
||||||
bail!("route id missing");
|
apibail_generic!("safety route id missing");
|
||||||
};
|
};
|
||||||
let Some(safety_rssd) = inner.content.get_detail(&safety_route_id) else {
|
let Some(safety_rssd) = inner.content.get_detail(&safety_route_id) else {
|
||||||
bail!("route set detail missing");
|
apibail_internal!("safety route set detail missing");
|
||||||
};
|
};
|
||||||
let Some(safety_rsd) = safety_rssd.get_route_by_key(&sr_pubkey) else {
|
let Some(safety_rsd) = safety_rssd.get_route_by_key(&sr_pubkey) else {
|
||||||
bail!("route detail missing");
|
apibail_internal!("safety route detail missing");
|
||||||
};
|
};
|
||||||
|
|
||||||
// We can optimize the peer info in this safety route if it has been successfully
|
// We can optimize the peer info in this safety route if it has been successfully
|
||||||
@ -1040,7 +1058,7 @@ impl RouteSpecStore {
|
|||||||
};
|
};
|
||||||
// Return compiled route
|
// Return compiled route
|
||||||
//println!("compile_safety_route profile (cached): {} us", (get_timestamp() - profile_start_ts));
|
//println!("compile_safety_route profile (cached): {} us", (get_timestamp() - profile_start_ts));
|
||||||
return Ok(Some(compiled_route));
|
return Ok(compiled_route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1071,10 +1089,10 @@ impl RouteSpecStore {
|
|||||||
// Encrypt the previous blob ENC(nonce, DH(PKhop,SKsr))
|
// Encrypt the previous blob ENC(nonce, DH(PKhop,SKsr))
|
||||||
let dh_secret = vcrypto
|
let dh_secret = vcrypto
|
||||||
.cached_dh(&safety_rsd.hops[h], &safety_rsd.secret_key)
|
.cached_dh(&safety_rsd.hops[h], &safety_rsd.secret_key)
|
||||||
.wrap_err("dh failed")?;
|
.map_err(VeilidAPIError::internal)?;
|
||||||
let enc_msg_data = vcrypto
|
let enc_msg_data = vcrypto
|
||||||
.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)
|
.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)
|
||||||
.wrap_err("encryption failed")?;
|
.map_err(VeilidAPIError::internal)?;
|
||||||
|
|
||||||
// Make route hop data
|
// Make route hop data
|
||||||
let route_hop_data = RouteHopData {
|
let route_hop_data = RouteHopData {
|
||||||
@ -1098,7 +1116,7 @@ impl RouteSpecStore {
|
|||||||
})
|
})
|
||||||
.flatten();
|
.flatten();
|
||||||
if pi.is_none() {
|
if pi.is_none() {
|
||||||
bail!("peer info should exist for route but doesn't");
|
apibail_internal!("peer info should exist for route but doesn't");
|
||||||
}
|
}
|
||||||
RouteNode::PeerInfo(Box::new(pi.unwrap()))
|
RouteNode::PeerInfo(Box::new(pi.unwrap()))
|
||||||
},
|
},
|
||||||
@ -1123,10 +1141,10 @@ impl RouteSpecStore {
|
|||||||
// Encode first RouteHopData
|
// Encode first RouteHopData
|
||||||
let dh_secret = vcrypto
|
let dh_secret = vcrypto
|
||||||
.cached_dh(&safety_rsd.hops[0], &safety_rsd.secret_key)
|
.cached_dh(&safety_rsd.hops[0], &safety_rsd.secret_key)
|
||||||
.map_err(RPCError::map_internal("dh failed"))?;
|
.map_err(VeilidAPIError::internal)?;
|
||||||
let enc_msg_data = vcrypto
|
let enc_msg_data = vcrypto
|
||||||
.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)
|
.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)
|
||||||
.map_err(RPCError::map_internal("encryption failed"))?;
|
.map_err(VeilidAPIError::internal)?;
|
||||||
|
|
||||||
let route_hop_data = RouteHopData {
|
let route_hop_data = RouteHopData {
|
||||||
nonce,
|
nonce,
|
||||||
@ -1159,7 +1177,7 @@ impl RouteSpecStore {
|
|||||||
|
|
||||||
// Return compiled route
|
// Return compiled route
|
||||||
//println!("compile_safety_route profile (uncached): {} us", (get_timestamp() - profile_start_ts));
|
//println!("compile_safety_route profile (uncached): {} us", (get_timestamp() - profile_start_ts));
|
||||||
Ok(Some(compiled_route))
|
Ok(compiled_route)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an allocated route that matches a particular safety spec
|
/// Get an allocated route that matches a particular safety spec
|
||||||
@ -1175,14 +1193,22 @@ impl RouteSpecStore {
|
|||||||
safety_spec: &SafetySpec,
|
safety_spec: &SafetySpec,
|
||||||
direction: DirectionSet,
|
direction: DirectionSet,
|
||||||
avoid_nodes: &[TypedKey],
|
avoid_nodes: &[TypedKey],
|
||||||
) -> EyreResult<Option<PublicKey>> {
|
) -> VeilidAPIResult<PublicKey> {
|
||||||
// Ensure the total hop count isn't too long for our config
|
// Ensure the total hop count isn't too long for our config
|
||||||
let max_route_hop_count = self.unlocked_inner.max_route_hop_count;
|
let max_route_hop_count = self.unlocked_inner.max_route_hop_count;
|
||||||
if safety_spec.hop_count == 0 {
|
if safety_spec.hop_count == 0 {
|
||||||
bail!("safety route hop count is zero");
|
apibail_invalid_argument!(
|
||||||
|
"safety route hop count is zero",
|
||||||
|
"safety_spec.hop_count",
|
||||||
|
safety_spec.hop_count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if safety_spec.hop_count > max_route_hop_count {
|
if safety_spec.hop_count > max_route_hop_count {
|
||||||
bail!("safety route hop count too long");
|
apibail_invalid_argument!(
|
||||||
|
"safety route hop count too long",
|
||||||
|
"safety_spec.hop_count",
|
||||||
|
safety_spec.hop_count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if the preferred route is here
|
// See if the preferred route is here
|
||||||
@ -1192,7 +1218,7 @@ impl RouteSpecStore {
|
|||||||
if let Some(preferred_key) = preferred_rssd.get_route_set_keys().get(crypto_kind) {
|
if let Some(preferred_key) = preferred_rssd.get_route_set_keys().get(crypto_kind) {
|
||||||
// Only use the preferred route if it doesn't contain the avoid nodes
|
// Only use the preferred route if it doesn't contain the avoid nodes
|
||||||
if !preferred_rssd.contains_nodes(avoid_nodes) {
|
if !preferred_rssd.contains_nodes(avoid_nodes) {
|
||||||
return Ok(Some(preferred_key.value));
|
return Ok(preferred_key.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1213,8 +1239,7 @@ impl RouteSpecStore {
|
|||||||
sr_route_id
|
sr_route_id
|
||||||
} else {
|
} else {
|
||||||
// No route found, gotta allocate one
|
// No route found, gotta allocate one
|
||||||
let Some(sr_route_id) = self
|
self.allocate_route_inner(
|
||||||
.allocate_route_inner(
|
|
||||||
inner,
|
inner,
|
||||||
rti,
|
rti,
|
||||||
&[crypto_kind],
|
&[crypto_kind],
|
||||||
@ -1223,12 +1248,7 @@ impl RouteSpecStore {
|
|||||||
safety_spec.hop_count,
|
safety_spec.hop_count,
|
||||||
direction,
|
direction,
|
||||||
avoid_nodes,
|
avoid_nodes,
|
||||||
)
|
)?
|
||||||
.map_err(RPCError::internal)?
|
|
||||||
else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
sr_route_id
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let sr_pubkey = inner
|
let sr_pubkey = inner
|
||||||
@ -1240,7 +1260,7 @@ impl RouteSpecStore {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.value;
|
.value;
|
||||||
|
|
||||||
Ok(Some(sr_pubkey))
|
Ok(sr_pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a private route to use for the answer to question
|
/// Get a private route to use for the answer to question
|
||||||
@ -1253,7 +1273,7 @@ impl RouteSpecStore {
|
|||||||
crypto_kind: CryptoKind,
|
crypto_kind: CryptoKind,
|
||||||
safety_spec: &SafetySpec,
|
safety_spec: &SafetySpec,
|
||||||
avoid_nodes: &[TypedKey],
|
avoid_nodes: &[TypedKey],
|
||||||
) -> EyreResult<Option<PublicKey>> {
|
) -> VeilidAPIResult<PublicKey> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let routing_table = self.unlocked_inner.routing_table.clone();
|
let routing_table = self.unlocked_inner.routing_table.clone();
|
||||||
let rti = &mut *routing_table.inner.write();
|
let rti = &mut *routing_table.inner.write();
|
||||||
@ -1273,30 +1293,35 @@ impl RouteSpecStore {
|
|||||||
key: &PublicKey,
|
key: &PublicKey,
|
||||||
rsd: &RouteSpecDetail,
|
rsd: &RouteSpecDetail,
|
||||||
optimized: bool,
|
optimized: bool,
|
||||||
) -> EyreResult<PrivateRoute> {
|
) -> VeilidAPIResult<PrivateRoute> {
|
||||||
let routing_table = self.unlocked_inner.routing_table.clone();
|
let routing_table = self.unlocked_inner.routing_table.clone();
|
||||||
let rti = &*routing_table.inner.read();
|
let rti = &*routing_table.inner.read();
|
||||||
|
|
||||||
// Ensure we get the crypto for it
|
// Ensure we get the crypto for it
|
||||||
let crypto = routing_table.network_manager().crypto();
|
let crypto = routing_table.network_manager().crypto();
|
||||||
let Some(vcrypto) = crypto.get(rsd.crypto_kind) else {
|
let Some(vcrypto) = crypto.get(rsd.crypto_kind) else {
|
||||||
bail!("crypto not supported for route");
|
apibail_invalid_argument!(
|
||||||
|
"crypto not supported for route",
|
||||||
|
"rsd.crypto_kind",
|
||||||
|
rsd.crypto_kind
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure our network class is valid before attempting to assemble any routes
|
// Ensure our network class is valid before attempting to assemble any routes
|
||||||
if !rti.has_valid_network_class(RoutingDomain::PublicInternet) {
|
if !rti.has_valid_network_class(RoutingDomain::PublicInternet) {
|
||||||
let peer_info = rti.get_own_peer_info(RoutingDomain::PublicInternet);
|
log_rtab!(debug "unable to assemble route until we have a valid PublicInternet network class");
|
||||||
bail!(
|
apibail_try_again!();
|
||||||
"can't make private routes until our node info is valid: {:?}",
|
|
||||||
peer_info
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make innermost route hop to our own node
|
// Make innermost route hop to our own node
|
||||||
let mut route_hop = RouteHop {
|
let mut route_hop = RouteHop {
|
||||||
node: if optimized {
|
node: if optimized {
|
||||||
let Some(node_id) = routing_table.node_ids().get(rsd.crypto_kind) else {
|
let Some(node_id) = routing_table.node_ids().get(rsd.crypto_kind) else {
|
||||||
bail!("missing node id for crypto kind");
|
apibail_invalid_argument!(
|
||||||
|
"missing node id for crypto kind",
|
||||||
|
"rsd.crypto_kind",
|
||||||
|
rsd.crypto_kind
|
||||||
|
);
|
||||||
};
|
};
|
||||||
RouteNode::NodeId(node_id.value)
|
RouteNode::NodeId(node_id.value)
|
||||||
} else {
|
} else {
|
||||||
@ -1320,12 +1345,9 @@ impl RouteSpecStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Encrypt the previous blob ENC(nonce, DH(PKhop,SKpr))
|
// Encrypt the previous blob ENC(nonce, DH(PKhop,SKpr))
|
||||||
let dh_secret = vcrypto
|
let dh_secret = vcrypto.cached_dh(&rsd.hops[h], &rsd.secret_key)?;
|
||||||
.cached_dh(&rsd.hops[h], &rsd.secret_key)
|
let enc_msg_data =
|
||||||
.wrap_err("dh failed")?;
|
vcrypto.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)?;
|
||||||
let enc_msg_data = vcrypto
|
|
||||||
.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)
|
|
||||||
.wrap_err("encryption failed")?;
|
|
||||||
let route_hop_data = RouteHopData {
|
let route_hop_data = RouteHopData {
|
||||||
nonce,
|
nonce,
|
||||||
blob: enc_msg_data,
|
blob: enc_msg_data,
|
||||||
@ -1346,7 +1368,7 @@ impl RouteSpecStore {
|
|||||||
})
|
})
|
||||||
.flatten();
|
.flatten();
|
||||||
if pi.is_none() {
|
if pi.is_none() {
|
||||||
bail!("peer info should exist for route but doesn't",);
|
apibail_internal!("peer info should exist for route but doesn't");
|
||||||
}
|
}
|
||||||
RouteNode::PeerInfo(Box::new(pi.unwrap()))
|
RouteNode::PeerInfo(Box::new(pi.unwrap()))
|
||||||
},
|
},
|
||||||
@ -1373,13 +1395,13 @@ impl RouteSpecStore {
|
|||||||
&self,
|
&self,
|
||||||
key: &PublicKey,
|
key: &PublicKey,
|
||||||
optimized: Option<bool>,
|
optimized: Option<bool>,
|
||||||
) -> EyreResult<PrivateRoute> {
|
) -> VeilidAPIResult<PrivateRoute> {
|
||||||
let inner = &*self.inner.lock();
|
let inner = &*self.inner.lock();
|
||||||
let Some(rsid) = inner.content.get_id_by_key(key) else {
|
let Some(rsid) = inner.content.get_id_by_key(key) else {
|
||||||
bail!("route key does not exist");
|
apibail_invalid_argument!("route key does not exist", "key", key);
|
||||||
};
|
};
|
||||||
let Some(rssd) = inner.content.get_detail(&rsid) else {
|
let Some(rssd) = inner.content.get_detail(&rsid) else {
|
||||||
bail!("route id does not exist");
|
apibail_internal!("route id does not exist");
|
||||||
};
|
};
|
||||||
|
|
||||||
// See if we can optimize this compilation yet
|
// See if we can optimize this compilation yet
|
||||||
@ -1406,10 +1428,10 @@ impl RouteSpecStore {
|
|||||||
&self,
|
&self,
|
||||||
id: &RouteId,
|
id: &RouteId,
|
||||||
optimized: Option<bool>,
|
optimized: Option<bool>,
|
||||||
) -> EyreResult<Vec<PrivateRoute>> {
|
) -> VeilidAPIResult<Vec<PrivateRoute>> {
|
||||||
let inner = &*self.inner.lock();
|
let inner = &*self.inner.lock();
|
||||||
let Some(rssd) = inner.content.get_detail(id) else {
|
let Some(rssd) = inner.content.get_detail(id) else {
|
||||||
bail!("route id does not exist");
|
apibail_invalid_argument!("route id does not exist", "id", id);
|
||||||
};
|
};
|
||||||
|
|
||||||
// See if we can optimize this compilation yet
|
// See if we can optimize this compilation yet
|
||||||
@ -1433,7 +1455,7 @@ impl RouteSpecStore {
|
|||||||
feature = "verbose-tracing",
|
feature = "verbose-tracing",
|
||||||
instrument(level = "trace", skip(self, blob), ret, err)
|
instrument(level = "trace", skip(self, blob), ret, err)
|
||||||
)]
|
)]
|
||||||
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> EyreResult<RouteId> {
|
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> VeilidAPIResult<RouteId> {
|
||||||
let cur_ts = get_aligned_timestamp();
|
let cur_ts = get_aligned_timestamp();
|
||||||
|
|
||||||
// decode the pr blob
|
// decode the pr blob
|
||||||
@ -1450,7 +1472,7 @@ impl RouteSpecStore {
|
|||||||
for private_route in &private_routes {
|
for private_route in &private_routes {
|
||||||
// ensure private route has first hop
|
// ensure private route has first hop
|
||||||
if !matches!(private_route.hops, PrivateRouteHops::FirstHop(_)) {
|
if !matches!(private_route.hops, PrivateRouteHops::FirstHop(_)) {
|
||||||
bail!("private route must have first hop");
|
apibail_generic!("private route must have first hop");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure this isn't also an allocated route
|
// ensure this isn't also an allocated route
|
||||||
@ -1528,7 +1550,7 @@ impl RouteSpecStore {
|
|||||||
&self,
|
&self,
|
||||||
key: &PublicKey,
|
key: &PublicKey,
|
||||||
cur_ts: Timestamp,
|
cur_ts: Timestamp,
|
||||||
) -> EyreResult<()> {
|
) -> VeilidAPIResult<()> {
|
||||||
let our_node_info_ts = self
|
let our_node_info_ts = self
|
||||||
.unlocked_inner
|
.unlocked_inner
|
||||||
.routing_table
|
.routing_table
|
||||||
@ -1550,7 +1572,7 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bail!("private route is missing from store: {}", key);
|
apibail_invalid_argument!("private route is missing from store", "key", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the route statistics for any route we know about, local or remote
|
/// Get the route statistics for any route we know about, local or remote
|
||||||
@ -1603,10 +1625,10 @@ impl RouteSpecStore {
|
|||||||
/// Mark route as published
|
/// Mark route as published
|
||||||
/// When first deserialized, routes must be re-published in order to ensure they remain
|
/// When first deserialized, routes must be re-published in order to ensure they remain
|
||||||
/// in the RouteSpecStore.
|
/// in the RouteSpecStore.
|
||||||
pub fn mark_route_published(&self, id: &RouteId, published: bool) -> EyreResult<()> {
|
pub fn mark_route_published(&self, id: &RouteId, published: bool) -> VeilidAPIResult<()> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let Some(rssd) = inner.content.get_detail_mut(id) else {
|
let Some(rssd) = inner.content.get_detail_mut(id) else {
|
||||||
bail!("route does not exist");
|
apibail_invalid_argument!("route does not exist", "id", id);
|
||||||
};
|
};
|
||||||
rssd.set_published(published);
|
rssd.set_published(published);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1624,13 +1646,13 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert private route list to binary blob
|
/// Convert private route list to binary blob
|
||||||
pub fn private_routes_to_blob(private_routes: &[PrivateRoute]) -> EyreResult<Vec<u8>> {
|
pub fn private_routes_to_blob(private_routes: &[PrivateRoute]) -> VeilidAPIResult<Vec<u8>> {
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
|
|
||||||
// Serialize count
|
// Serialize count
|
||||||
let pr_count = private_routes.len();
|
let pr_count = private_routes.len();
|
||||||
if pr_count > MAX_CRYPTO_KINDS {
|
if pr_count > MAX_CRYPTO_KINDS {
|
||||||
bail!("too many crypto kinds to encode blob");
|
apibail_internal!("too many crypto kinds to encode blob");
|
||||||
}
|
}
|
||||||
let pr_count = pr_count as u8;
|
let pr_count = pr_count as u8;
|
||||||
buffer.push(pr_count);
|
buffer.push(pr_count);
|
||||||
@ -1641,25 +1663,31 @@ impl RouteSpecStore {
|
|||||||
let mut pr_builder = pr_message.init_root::<veilid_capnp::private_route::Builder>();
|
let mut pr_builder = pr_message.init_root::<veilid_capnp::private_route::Builder>();
|
||||||
|
|
||||||
encode_private_route(private_route, &mut pr_builder)
|
encode_private_route(private_route, &mut pr_builder)
|
||||||
.wrap_err("failed to encode private route")?;
|
.map_err(VeilidAPIError::internal)?;
|
||||||
|
|
||||||
capnp::serialize_packed::write_message(&mut buffer, &pr_message)
|
capnp::serialize_packed::write_message(&mut buffer, &pr_message)
|
||||||
.map_err(RPCError::internal)
|
.map_err(RPCError::internal)?;
|
||||||
.wrap_err("failed to convert builder to vec")?;
|
|
||||||
}
|
}
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert binary blob to private route
|
/// Convert binary blob to private route vector
|
||||||
pub fn blob_to_private_routes(crypto: Crypto, blob: Vec<u8>) -> EyreResult<Vec<PrivateRoute>> {
|
pub fn blob_to_private_routes(
|
||||||
|
crypto: Crypto,
|
||||||
|
blob: Vec<u8>,
|
||||||
|
) -> VeilidAPIResult<Vec<PrivateRoute>> {
|
||||||
// Deserialize count
|
// Deserialize count
|
||||||
if blob.is_empty() {
|
if blob.is_empty() {
|
||||||
bail!("not deserializing empty private route blob");
|
apibail_invalid_argument!(
|
||||||
|
"not deserializing empty private route blob",
|
||||||
|
"blob.is_empty",
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pr_count = blob[0] as usize;
|
let pr_count = blob[0] as usize;
|
||||||
if pr_count > MAX_CRYPTO_KINDS {
|
if pr_count > MAX_CRYPTO_KINDS {
|
||||||
bail!("too many crypto kinds to decode blob");
|
apibail_invalid_argument!("too many crypto kinds to decode blob", "blob[0]", pr_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deserialize stream of private routes
|
// Deserialize stream of private routes
|
||||||
@ -1670,18 +1698,17 @@ impl RouteSpecStore {
|
|||||||
&mut pr_slice,
|
&mut pr_slice,
|
||||||
capnp::message::ReaderOptions::new(),
|
capnp::message::ReaderOptions::new(),
|
||||||
)
|
)
|
||||||
.map_err(RPCError::internal)
|
.map_err(|e| VeilidAPIError::invalid_argument("failed to read blob", "e", e))?;
|
||||||
.wrap_err("failed to make message reader")?;
|
|
||||||
|
|
||||||
let pr_reader = reader
|
let pr_reader = reader
|
||||||
.get_root::<veilid_capnp::private_route::Reader>()
|
.get_root::<veilid_capnp::private_route::Reader>()
|
||||||
.map_err(RPCError::internal)
|
.map_err(VeilidAPIError::internal)?;
|
||||||
.wrap_err("failed to make reader for private_route")?;
|
let private_route = decode_private_route(&pr_reader).map_err(|e| {
|
||||||
let private_route =
|
VeilidAPIError::invalid_argument("failed to decode private route", "e", e)
|
||||||
decode_private_route(&pr_reader).wrap_err("failed to decode private route")?;
|
})?;
|
||||||
private_route
|
private_route.validate(crypto.clone()).map_err(|e| {
|
||||||
.validate(crypto.clone())
|
VeilidAPIError::invalid_argument("failed to validate private route", "e", e)
|
||||||
.wrap_err("failed to validate private route")?;
|
})?;
|
||||||
|
|
||||||
out.push(private_route);
|
out.push(private_route);
|
||||||
}
|
}
|
||||||
@ -1693,7 +1720,7 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generate RouteId from typed key set of route public keys
|
/// Generate RouteId from typed key set of route public keys
|
||||||
fn generate_allocated_route_id(&self, rssd: &RouteSetSpecDetail) -> EyreResult<RouteId> {
|
fn generate_allocated_route_id(&self, rssd: &RouteSetSpecDetail) -> VeilidAPIResult<RouteId> {
|
||||||
let route_set_keys = rssd.get_route_set_keys();
|
let route_set_keys = rssd.get_route_set_keys();
|
||||||
let crypto = self.unlocked_inner.routing_table.crypto();
|
let crypto = self.unlocked_inner.routing_table.crypto();
|
||||||
|
|
||||||
@ -1708,7 +1735,7 @@ impl RouteSpecStore {
|
|||||||
idbytes.extend_from_slice(&tk.value.bytes);
|
idbytes.extend_from_slice(&tk.value.bytes);
|
||||||
}
|
}
|
||||||
let Some(best_kind) = best_kind else {
|
let Some(best_kind) = best_kind else {
|
||||||
bail!("no compatible crypto kinds in route");
|
apibail_internal!("no compatible crypto kinds in route");
|
||||||
};
|
};
|
||||||
let vcrypto = crypto.get(best_kind).unwrap();
|
let vcrypto = crypto.get(best_kind).unwrap();
|
||||||
|
|
||||||
@ -1716,7 +1743,10 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generate RouteId from set of private routes
|
/// Generate RouteId from set of private routes
|
||||||
fn generate_remote_route_id(&self, private_routes: &[PrivateRoute]) -> EyreResult<RouteId> {
|
fn generate_remote_route_id(
|
||||||
|
&self,
|
||||||
|
private_routes: &[PrivateRoute],
|
||||||
|
) -> VeilidAPIResult<RouteId> {
|
||||||
let crypto = self.unlocked_inner.routing_table.crypto();
|
let crypto = self.unlocked_inner.routing_table.crypto();
|
||||||
|
|
||||||
let mut idbytes = Vec::with_capacity(PUBLIC_KEY_LENGTH * private_routes.len());
|
let mut idbytes = Vec::with_capacity(PUBLIC_KEY_LENGTH * private_routes.len());
|
||||||
@ -1731,7 +1761,7 @@ impl RouteSpecStore {
|
|||||||
idbytes.extend_from_slice(&private_route.public_key.value.bytes);
|
idbytes.extend_from_slice(&private_route.public_key.value.bytes);
|
||||||
}
|
}
|
||||||
let Some(best_kind) = best_kind else {
|
let Some(best_kind) = best_kind else {
|
||||||
bail!("no compatible crypto kinds in route");
|
apibail_internal!("no compatible crypto kinds in route");
|
||||||
};
|
};
|
||||||
let vcrypto = crypto.get(best_kind).unwrap();
|
let vcrypto = crypto.get(best_kind).unwrap();
|
||||||
|
|
||||||
|
@ -205,15 +205,19 @@ impl RoutingTable {
|
|||||||
for _n in 0..routes_to_allocate {
|
for _n in 0..routes_to_allocate {
|
||||||
// Parameters here must be the most inclusive safety route spec
|
// Parameters here must be the most inclusive safety route spec
|
||||||
// These will be used by test_remote_route as well
|
// These will be used by test_remote_route as well
|
||||||
if let Some(k) = rss.allocate_route(
|
match rss.allocate_route(
|
||||||
&VALID_CRYPTO_KINDS,
|
&VALID_CRYPTO_KINDS,
|
||||||
Stability::default(),
|
Stability::default(),
|
||||||
Sequencing::EnsureOrdered,
|
Sequencing::EnsureOrdered,
|
||||||
default_route_hop_count,
|
default_route_hop_count,
|
||||||
DirectionSet::all(),
|
DirectionSet::all(),
|
||||||
&[],
|
&[],
|
||||||
)? {
|
) {
|
||||||
newly_allocated_routes.push(k);
|
Err(VeilidAPIError::TryAgain) => {}
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
Ok(v) => {
|
||||||
|
newly_allocated_routes.push(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,17 +180,20 @@ impl RPCProcessor {
|
|||||||
SafetySelection::Safe(safety_spec) => {
|
SafetySelection::Safe(safety_spec) => {
|
||||||
// Sent directly but with a safety route, respond to private route
|
// Sent directly but with a safety route, respond to private route
|
||||||
let crypto_kind = target.best_node_id().kind;
|
let crypto_kind = target.best_node_id().kind;
|
||||||
let Some(pr_key) = rss
|
let pr_key = match rss.get_private_route_for_safety_spec(
|
||||||
.get_private_route_for_safety_spec(
|
|
||||||
crypto_kind,
|
crypto_kind,
|
||||||
safety_spec,
|
safety_spec,
|
||||||
&target.node_ids(),
|
&target.node_ids(),
|
||||||
)
|
) {
|
||||||
.map_err(RPCError::internal)?
|
Err(VeilidAPIError::TryAgain) => {
|
||||||
else {
|
|
||||||
return Ok(NetworkResult::no_connection_other(
|
return Ok(NetworkResult::no_connection_other(
|
||||||
"no private route for response at this time",
|
"no private route for response at this time",
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(RPCError::internal(e));
|
||||||
|
}
|
||||||
|
Ok(v) => v,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the assembled route for response
|
// Get the assembled route for response
|
||||||
@ -216,13 +219,20 @@ impl RPCProcessor {
|
|||||||
|
|
||||||
let mut avoid_nodes = relay.node_ids();
|
let mut avoid_nodes = relay.node_ids();
|
||||||
avoid_nodes.add_all(&target.node_ids());
|
avoid_nodes.add_all(&target.node_ids());
|
||||||
let Some(pr_key) = rss
|
let pr_key = match rss.get_private_route_for_safety_spec(
|
||||||
.get_private_route_for_safety_spec(crypto_kind, safety_spec, &avoid_nodes)
|
crypto_kind,
|
||||||
.map_err(RPCError::internal)?
|
safety_spec,
|
||||||
else {
|
&avoid_nodes,
|
||||||
|
) {
|
||||||
|
Err(VeilidAPIError::TryAgain) => {
|
||||||
return Ok(NetworkResult::no_connection_other(
|
return Ok(NetworkResult::no_connection_other(
|
||||||
"no private route for response at this time",
|
"no private route for response at this time",
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(RPCError::internal(e));
|
||||||
|
}
|
||||||
|
Ok(v) => v,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the assembled route for response
|
// Get the assembled route for response
|
||||||
@ -282,19 +292,21 @@ impl RPCProcessor {
|
|||||||
private_route.public_key.value
|
private_route.public_key.value
|
||||||
} else {
|
} else {
|
||||||
// Get the private route to respond to that matches the safety route spec we sent the request with
|
// Get the private route to respond to that matches the safety route spec we sent the request with
|
||||||
let Some(pr_key) = rss
|
match rss.get_private_route_for_safety_spec(
|
||||||
.get_private_route_for_safety_spec(
|
|
||||||
crypto_kind,
|
crypto_kind,
|
||||||
safety_spec,
|
safety_spec,
|
||||||
&[avoid_node_id],
|
&[avoid_node_id],
|
||||||
)
|
) {
|
||||||
.map_err(RPCError::internal)?
|
Err(VeilidAPIError::TryAgain) => {
|
||||||
else {
|
|
||||||
return Ok(NetworkResult::no_connection_other(
|
return Ok(NetworkResult::no_connection_other(
|
||||||
"no private route for response at this time",
|
"no private route for response at this time",
|
||||||
));
|
));
|
||||||
};
|
}
|
||||||
pr_key
|
Err(e) => {
|
||||||
|
return Err(RPCError::internal(e));
|
||||||
|
}
|
||||||
|
Ok(v) => v,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the assembled route for response
|
// Get the assembled route for response
|
||||||
|
@ -652,14 +652,16 @@ impl RPCProcessor {
|
|||||||
// Compile the safety route with the private route
|
// Compile the safety route with the private route
|
||||||
let compiled_route: CompiledRoute = match rss
|
let compiled_route: CompiledRoute = match rss
|
||||||
.compile_safety_route(safety_selection, remote_private_route)
|
.compile_safety_route(safety_selection, remote_private_route)
|
||||||
.map_err(RPCError::internal)?
|
|
||||||
{
|
{
|
||||||
Some(cr) => cr,
|
Err(VeilidAPIError::TryAgain) => {
|
||||||
None => {
|
|
||||||
return Ok(NetworkResult::no_connection_other(
|
return Ok(NetworkResult::no_connection_other(
|
||||||
"private route could not be compiled at this time",
|
"private route could not be compiled at this time",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(RPCError::internal(e));
|
||||||
|
}
|
||||||
|
Ok(v) => v,
|
||||||
};
|
};
|
||||||
let sr_is_stub = compiled_route.safety_route.is_stub();
|
let sr_is_stub = compiled_route.safety_route.is_stub();
|
||||||
let sr_pubkey = compiled_route.safety_route.public_key.value;
|
let sr_pubkey = compiled_route.safety_route.public_key.value;
|
||||||
|
@ -261,40 +261,28 @@ impl VeilidAPI {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let rss = self.routing_table()?.route_spec_store();
|
let rss = self.routing_table()?.route_spec_store();
|
||||||
let r = rss
|
let route_id = rss.allocate_route(
|
||||||
.allocate_route(
|
|
||||||
crypto_kinds,
|
crypto_kinds,
|
||||||
stability,
|
stability,
|
||||||
sequencing,
|
sequencing,
|
||||||
default_route_hop_count,
|
default_route_hop_count,
|
||||||
Direction::Inbound.into(),
|
Direction::Inbound.into(),
|
||||||
&[],
|
&[],
|
||||||
)
|
)?;
|
||||||
.map_err(VeilidAPIError::internal)?;
|
if !rss.test_route(route_id).await? {
|
||||||
let Some(route_id) = r else {
|
|
||||||
apibail_generic!("unable to allocate route");
|
|
||||||
};
|
|
||||||
if !rss
|
|
||||||
.test_route(route_id)
|
|
||||||
.await
|
|
||||||
.map_err(VeilidAPIError::no_connection)?
|
|
||||||
{
|
|
||||||
rss.release_route(route_id);
|
rss.release_route(route_id);
|
||||||
apibail_generic!("allocated route failed to test");
|
apibail_generic!("allocated route failed to test");
|
||||||
}
|
}
|
||||||
let private_routes = rss
|
let private_routes = rss.assemble_private_routes(&route_id, Some(true))?;
|
||||||
.assemble_private_routes(&route_id, Some(true))
|
|
||||||
.map_err(VeilidAPIError::generic)?;
|
|
||||||
let blob = match RouteSpecStore::private_routes_to_blob(&private_routes) {
|
let blob = match RouteSpecStore::private_routes_to_blob(&private_routes) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
rss.release_route(route_id);
|
rss.release_route(route_id);
|
||||||
apibail_internal!(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
rss.mark_route_published(&route_id, true)
|
rss.mark_route_published(&route_id, true)?;
|
||||||
.map_err(VeilidAPIError::internal)?;
|
|
||||||
|
|
||||||
Ok((route_id, blob))
|
Ok((route_id, blob))
|
||||||
}
|
}
|
||||||
@ -305,7 +293,6 @@ impl VeilidAPI {
|
|||||||
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> VeilidAPIResult<RouteId> {
|
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> VeilidAPIResult<RouteId> {
|
||||||
let rss = self.routing_table()?.route_spec_store();
|
let rss = self.routing_table()?.route_spec_store();
|
||||||
rss.import_remote_private_route(blob)
|
rss.import_remote_private_route(blob)
|
||||||
.map_err(|e| VeilidAPIError::invalid_argument(e, "blob", "private route blob"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release either a locally allocated or remotely imported private route
|
/// Release either a locally allocated or remotely imported private route
|
||||||
|
@ -1096,8 +1096,7 @@ impl VeilidAPI {
|
|||||||
directions,
|
directions,
|
||||||
&[],
|
&[],
|
||||||
) {
|
) {
|
||||||
Ok(Some(v)) => format!("{}", v),
|
Ok(v) => v.to_string(),
|
||||||
Ok(None) => "<unavailable>".to_string(),
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
format!("Route allocation failed: {}", e)
|
format!("Route allocation failed: {}", e)
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ rt-tokio = [
|
|||||||
"tokio-util",
|
"tokio-util",
|
||||||
"opentelemetry/rt-tokio",
|
"opentelemetry/rt-tokio",
|
||||||
]
|
]
|
||||||
|
debug-load = ["dep:ctor", "dep:libc-print", "dep:android_log-sys", "dep:oslog"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
veilid-core = { path = "../../veilid-core", default-features = false }
|
veilid-core = { path = "../../veilid-core", default-features = false }
|
||||||
@ -56,9 +57,8 @@ allo-isolate = "0.1.20"
|
|||||||
ffi-support = "0.4.4"
|
ffi-support = "0.4.4"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
hostname = "0.3.1"
|
hostname = "0.3.1"
|
||||||
# loader debugging
|
ctor = { version = "0.2.5", optional = true }
|
||||||
ctor = "0.2.5"
|
libc-print = { version = "0.1.22", optional = true }
|
||||||
libc-print = "0.1.22"
|
|
||||||
|
|
||||||
|
|
||||||
# Dependencies for WASM builds only
|
# Dependencies for WASM builds only
|
||||||
@ -68,8 +68,8 @@ libc-print = "0.1.22"
|
|||||||
[target.'cfg(target_os = "android")'.dependencies]
|
[target.'cfg(target_os = "android")'.dependencies]
|
||||||
jni = "0.21.1"
|
jni = "0.21.1"
|
||||||
paranoid-android = "0.2.1"
|
paranoid-android = "0.2.1"
|
||||||
android_log-sys = "0.3.1"
|
android_log-sys = { version = "0.3.1", optional = true }
|
||||||
|
|
||||||
# Dependencies for Android builds only
|
# Dependencies for Android builds only
|
||||||
[target.'cfg(target_os = "ios")'.dependencies]
|
[target.'cfg(target_os = "ios")'.dependencies]
|
||||||
oslog = { version = "0.2.0", default-features = false }
|
oslog = { version = "0.2.0", default-features = false, optional = true }
|
||||||
|
@ -17,6 +17,8 @@ use veilid_core::tools::*;
|
|||||||
use veilid_core::Encodable as _;
|
use veilid_core::Encodable as _;
|
||||||
|
|
||||||
// Detect flutter load/unload
|
// Detect flutter load/unload
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature="debug-load")] {
|
||||||
#[ctor::ctor]
|
#[ctor::ctor]
|
||||||
fn onload() {
|
fn onload() {
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
@ -49,6 +51,8 @@ fn onunload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Globals
|
// Globals
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -413,7 +413,7 @@ impl AssemblyBuffer {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Get a message seq
|
// Get a message seq
|
||||||
let seq = self.unlocked_inner.next_seq.fetch_add(1, Ordering::Relaxed);
|
let seq = self.unlocked_inner.next_seq.fetch_add(1, Ordering::AcqRel);
|
||||||
|
|
||||||
// Chunk it up
|
// Chunk it up
|
||||||
let mut offset = 0usize;
|
let mut offset = 0usize;
|
||||||
|
@ -271,7 +271,7 @@ pub async fn test_many_frags_with_drops() {
|
|||||||
let first = first.clone();
|
let first = first.clone();
|
||||||
async move {
|
async move {
|
||||||
// Send only first packet, drop rest
|
// Send only first packet, drop rest
|
||||||
if first.swap(false, Ordering::Relaxed) {
|
if first.swap(false, Ordering::AcqRel) {
|
||||||
net_tx
|
net_tx
|
||||||
.send_async((framed_chunk, remote_addr))
|
.send_async((framed_chunk, remote_addr))
|
||||||
.await
|
.await
|
||||||
@ -306,7 +306,7 @@ pub async fn test_many_frags_with_drops() {
|
|||||||
Ok(NetworkResult::Value(()))
|
Ok(NetworkResult::Value(()))
|
||||||
));
|
));
|
||||||
|
|
||||||
first.store(true, Ordering::Relaxed);
|
first.store(true, Ordering::Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("all_sent len={}", all_sent.len());
|
println!("all_sent len={}", all_sent.len());
|
||||||
|
@ -58,7 +58,7 @@ impl<E: Send + 'static> TickTask<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&self) -> bool {
|
pub fn is_running(&self) -> bool {
|
||||||
self.running.load(core::sync::atomic::Ordering::Relaxed)
|
self.running.load(core::sync::atomic::Ordering::Acquire)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn stop(&self) -> Result<(), E> {
|
pub async fn stop(&self) -> Result<(), E> {
|
||||||
@ -120,9 +120,9 @@ impl<E: Send + 'static> TickTask<E> {
|
|||||||
let running = self.running.clone();
|
let running = self.running.clone();
|
||||||
let routine = self.routine.get().unwrap()(stop_token, last_timestamp_us, now);
|
let routine = self.routine.get().unwrap()(stop_token, last_timestamp_us, now);
|
||||||
let wrapped_routine = Box::pin(async move {
|
let wrapped_routine = Box::pin(async move {
|
||||||
running.store(true, core::sync::atomic::Ordering::Relaxed);
|
running.store(true, core::sync::atomic::Ordering::Release);
|
||||||
let out = routine.await;
|
let out = routine.await;
|
||||||
running.store(false, core::sync::atomic::Ordering::Relaxed);
|
running.store(false, core::sync::atomic::Ordering::Release);
|
||||||
out
|
out
|
||||||
});
|
});
|
||||||
match self.single_future.single_spawn(wrapped_routine).await {
|
match self.single_future.single_spawn(wrapped_routine).await {
|
||||||
|
@ -18,21 +18,21 @@ extern "C" {
|
|||||||
|
|
||||||
pub fn is_browser() -> bool {
|
pub fn is_browser() -> bool {
|
||||||
static CACHE: AtomicI8 = AtomicI8::new(-1);
|
static CACHE: AtomicI8 = AtomicI8::new(-1);
|
||||||
let cache = CACHE.load(Ordering::Relaxed);
|
let cache = CACHE.load(Ordering::AcqRel);
|
||||||
if cache != -1 {
|
if cache != -1 {
|
||||||
return cache != 0;
|
return cache != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = Reflect::has(global().as_ref(), &"navigator".into()).unwrap_or_default();
|
let res = Reflect::has(global().as_ref(), &"navigator".into()).unwrap_or_default();
|
||||||
|
|
||||||
CACHE.store(res as i8, Ordering::Relaxed);
|
CACHE.store(res as i8, Ordering::AcqRel);
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_browser_https() -> bool {
|
pub fn is_browser_https() -> bool {
|
||||||
static CACHE: AtomicI8 = AtomicI8::new(-1);
|
static CACHE: AtomicI8 = AtomicI8::new(-1);
|
||||||
let cache = CACHE.load(Ordering::Relaxed);
|
let cache = CACHE.load(Ordering::AcqRel);
|
||||||
if cache != -1 {
|
if cache != -1 {
|
||||||
return cache != 0;
|
return cache != 0;
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ pub fn is_browser_https() -> bool {
|
|||||||
.map(|res| res.is_truthy())
|
.map(|res| res.is_truthy())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
CACHE.store(res as i8, Ordering::Relaxed);
|
CACHE.store(res as i8, Ordering::AcqRel);
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ pub fn initialize_veilid_wasm() {
|
|||||||
static INITIALIZED: AtomicBool = AtomicBool::new(false);
|
static INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||||
#[wasm_bindgen()]
|
#[wasm_bindgen()]
|
||||||
pub fn initialize_veilid_core(platform_config: String) {
|
pub fn initialize_veilid_core(platform_config: String) {
|
||||||
if INITIALIZED.swap(true, Ordering::Relaxed) {
|
if INITIALIZED.swap(true, Ordering::AcqRel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let platform_config: VeilidWASMConfig = veilid_core::deserialize_json(&platform_config)
|
let platform_config: VeilidWASMConfig = veilid_core::deserialize_json(&platform_config)
|
||||||
|
@ -30,7 +30,7 @@ pub struct VeilidClient {}
|
|||||||
#[wasm_bindgen(js_class = veilidClient)]
|
#[wasm_bindgen(js_class = veilidClient)]
|
||||||
impl VeilidClient {
|
impl VeilidClient {
|
||||||
pub async fn initializeCore(platformConfig: VeilidWASMConfig) {
|
pub async fn initializeCore(platformConfig: VeilidWASMConfig) {
|
||||||
if INITIALIZED.swap(true, Ordering::Relaxed) {
|
if INITIALIZED.swap(true, Ordering::AcqRel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
|
Loading…
Reference in New Issue
Block a user