clean up handling of errors in route spec store

This commit is contained in:
Christien Rioux 2023-10-20 22:39:09 -04:00
parent 353c907497
commit 97be49a9a7
17 changed files with 278 additions and 236 deletions

View File

@ -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;

View File

@ -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");

View File

@ -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

View File

@ -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();

View File

@ -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);
}
} }
} }

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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)
} }

View File

@ -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 }

View File

@ -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! {

View File

@ -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;

View File

@ -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());

View File

@ -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 {

View File

@ -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
} }

View File

@ -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)

View File

@ -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();