route work

This commit is contained in:
John Smith 2022-10-21 21:27:07 -04:00
parent a1b40c79f1
commit be55a42878
9 changed files with 175 additions and 144 deletions

View File

@ -1021,7 +1021,7 @@ impl NetworkManager {
// We expect the inbound noderef to be the same as the target noderef // We expect the inbound noderef to be the same as the target noderef
// if they aren't the same, we should error on this and figure out what then hell is up // if they aren't the same, we should error on this and figure out what then hell is up
if target_nr != inbound_nr { if target_nr.node_id() != inbound_nr.node_id() {
bail!("unexpected noderef mismatch on reverse connect"); bail!("unexpected noderef mismatch on reverse connect");
} }
@ -1122,7 +1122,7 @@ impl NetworkManager {
// We expect the inbound noderef to be the same as the target noderef // We expect the inbound noderef to be the same as the target noderef
// if they aren't the same, we should error on this and figure out what then hell is up // if they aren't the same, we should error on this and figure out what then hell is up
if target_nr != inbound_nr { if target_nr.node_id() != inbound_nr.node_id() {
bail!( bail!(
"unexpected noderef mismatch on hole punch {}, expected {}", "unexpected noderef mismatch on hole punch {}, expected {}",
inbound_nr, inbound_nr,

View File

@ -7,7 +7,7 @@ use routing_table::*;
use stop_token::future::FutureExt; use stop_token::future::FutureExt;
use xx::*; use xx::*;
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug)]
pub enum ReceiptEvent { pub enum ReceiptEvent {
ReturnedOutOfBand, ReturnedOutOfBand,
ReturnedInBand { inbound_noderef: NodeRef }, ReturnedInBand { inbound_noderef: NodeRef },

View File

@ -2,18 +2,6 @@ use super::*;
use crate::veilid_api::*; use crate::veilid_api::*;
use serde::*; use serde::*;
/// Options for safety routes (sender privacy)
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct SafetySpec {
/// preferred safety route if it still exists
pub preferred_route: Option<DHTKey>,
/// 0 = no safety route, just use node's node id, more hops is safer but slower
pub hop_count: usize,
/// prefer reliability over speed
pub stability: Stability,
/// prefer connection-oriented sequenced protocols
pub sequencing: Sequencing,
}
/// Compiled route (safety route + private route) /// Compiled route (safety route + private route)
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -98,15 +86,6 @@ pub struct RouteSpecStore {
cache: RouteSpecStoreCache, cache: RouteSpecStoreCache,
} }
/// The choice of safety route including in compiled routes
#[derive(Debug, Clone)]
pub enum SafetySelection {
/// Don't use a safety route, only specify the sequencing preference
Unsafe(Sequencing),
/// Use a safety route and parameters specified by a SafetySpec
Safe(SafetySpec),
}
fn route_hops_to_hop_cache(hops: &[DHTKey]) -> Vec<u8> { fn route_hops_to_hop_cache(hops: &[DHTKey]) -> Vec<u8> {
let mut cache: Vec<u8> = Vec::with_capacity(hops.len() * DHT_KEY_LENGTH); let mut cache: Vec<u8> = Vec::with_capacity(hops.len() * DHT_KEY_LENGTH);
for hop in hops { for hop in hops {

View File

@ -204,21 +204,34 @@ fn first_filtered_dial_info_detail(
from_node: &NodeInfo, from_node: &NodeInfo,
to_node: &NodeInfo, to_node: &NodeInfo,
dial_info_filter: &DialInfoFilter, dial_info_filter: &DialInfoFilter,
reliable: bool, xxx continue here sequencing: Sequencing,
) -> Option<DialInfoDetail> { ) -> Option<DialInfoDetail> {
let direct_dial_info_filter = dial_info_filter.clone().filtered( let dial_info_filter = dial_info_filter.clone().filtered(
&DialInfoFilter::all() &DialInfoFilter::all()
.with_address_type_set(from_node.address_types) .with_address_type_set(from_node.address_types)
.with_protocol_type_set(from_node.outbound_protocols), .with_protocol_type_set(from_node.outbound_protocols),
); );
// Get first filtered dialinfo // Get first filtered dialinfo
let sort = if reliable { let (sort, dial_info_filter) = match sequencing {
Some(DialInfoDetail::ordered_sequencing_sort) Sequencing::NoPreference => (None, dial_info_filter),
} else { Sequencing::PreferOrdered => (
None Some(DialInfoDetail::ordered_sequencing_sort),
dial_info_filter,
),
Sequencing::EnsureOrdered => (
Some(DialInfoDetail::ordered_sequencing_sort),
dial_info_filter.filtered(
&DialInfoFilter::all().with_protocol_type_set(ProtocolType::all_ordered_set()),
),
),
}; };
let direct_filter = |did: &DialInfoDetail| did.matches_filter(&direct_dial_info_filter); // If the filter is dead then we won't be able to connect
if dial_info_filter.is_dead() {
return None;
}
let direct_filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter);
// Get the best match dial info for node B if we have it // Get the best match dial info for node B if we have it
to_node.first_filtered_dial_info_detail(sort, direct_filter) to_node.first_filtered_dial_info_detail(sort, direct_filter)
@ -242,11 +255,11 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
node_b_id: &DHTKey, node_b_id: &DHTKey,
node_b: &NodeInfo, node_b: &NodeInfo,
dial_info_filter: DialInfoFilter, dial_info_filter: DialInfoFilter,
reliable: bool, sequencing: Sequencing,
) -> ContactMethod { ) -> ContactMethod {
// Get the best match dial info for node B if we have it // Get the best match dial info for node B if we have it
if let Some(target_did) = if let Some(target_did) =
first_filtered_dial_info_detail(node_a, node_b, &dial_info_filter, reliable) first_filtered_dial_info_detail(node_a, node_b, &dial_info_filter, sequencing)
{ {
// Do we need to signal before going inbound? // Do we need to signal before going inbound?
if !target_did.class.requires_signal() { if !target_did.class.requires_signal() {
@ -267,7 +280,7 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
node_a, node_a,
&inbound_relay.signed_node_info.node_info, &inbound_relay.signed_node_info.node_info,
&dial_info_filter, &dial_info_filter,
reliable, sequencing,
) )
.is_some() .is_some()
{ {
@ -280,7 +293,7 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
node_b, node_b,
node_a, node_a,
&dial_info_filter, &dial_info_filter,
reliable, sequencing,
) { ) {
// Ensure we aren't on the same public IP address (no hairpin nat) // Ensure we aren't on the same public IP address (no hairpin nat)
if reverse_did.dial_info.to_ip_addr() if reverse_did.dial_info.to_ip_addr()
@ -306,14 +319,14 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
node_a, node_a,
node_b, node_b,
&udp_dial_info_filter, &udp_dial_info_filter,
reliable, sequencing,
) { ) {
// Does node A have a direct udp dialinfo that node B can reach? // Does node A have a direct udp dialinfo that node B can reach?
if let Some(reverse_udp_did) = first_filtered_dial_info_detail( if let Some(reverse_udp_did) = first_filtered_dial_info_detail(
node_b, node_b,
node_a, node_a,
&udp_dial_info_filter, &udp_dial_info_filter,
reliable, sequencing,
) { ) {
// Ensure we aren't on the same public IP address (no hairpin nat) // Ensure we aren't on the same public IP address (no hairpin nat)
if reverse_udp_did.dial_info.to_ip_addr() if reverse_udp_did.dial_info.to_ip_addr()
@ -341,7 +354,7 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
node_a, node_a,
&inbound_relay.signed_node_info.node_info, &inbound_relay.signed_node_info.node_info,
&dial_info_filter, &dial_info_filter,
reliable, sequencing,
) )
.is_some() .is_some()
{ {
@ -412,7 +425,7 @@ impl RoutingDomainDetail for LocalNetworkRoutingDomainDetail {
_node_b_id: &DHTKey, _node_b_id: &DHTKey,
node_b: &NodeInfo, node_b: &NodeInfo,
dial_info_filter: DialInfoFilter, dial_info_filter: DialInfoFilter,
reliable: bool, sequencing: Sequencing,
) -> ContactMethod { ) -> ContactMethod {
// Scope the filter down to protocols node A can do outbound // Scope the filter down to protocols node A can do outbound
let dial_info_filter = dial_info_filter.filtered( let dial_info_filter = dial_info_filter.filtered(
@ -421,17 +434,25 @@ impl RoutingDomainDetail for LocalNetworkRoutingDomainDetail {
.with_protocol_type_set(node_a.outbound_protocols), .with_protocol_type_set(node_a.outbound_protocols),
); );
// Get first filtered dialinfo
let (sort, dial_info_filter) = match sequencing {
Sequencing::NoPreference => (None, dial_info_filter),
Sequencing::PreferOrdered => (
Some(DialInfoDetail::ordered_sequencing_sort),
dial_info_filter,
),
Sequencing::EnsureOrdered => (
Some(DialInfoDetail::ordered_sequencing_sort),
dial_info_filter.filtered(
&DialInfoFilter::all().with_protocol_type_set(ProtocolType::all_ordered_set()),
),
),
};
// If the filter is dead then we won't be able to connect // If the filter is dead then we won't be able to connect
if dial_info_filter.is_dead() { if dial_info_filter.is_dead() {
return ContactMethod::Unreachable; return ContactMethod::Unreachable;
} }
// Get first filtered dialinfo
let sort = if reliable {
Some(DialInfoDetail::ordered_sequencing_sort)
} else {
None
};
let filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter); let filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter);
let opt_target_did = node_b.first_filtered_dial_info_detail(sort, filter); let opt_target_did = node_b.first_filtered_dial_info_detail(sort, filter);

View File

@ -8,7 +8,7 @@ pub enum Destination {
/// The node to send to /// The node to send to
target: NodeRef, target: NodeRef,
/// Require safety route or not /// Require safety route or not
safety_spec: Option<SafetySpec>, safety_selection: SafetySelection,
}, },
/// Send to node for relay purposes /// Send to node for relay purposes
Relay { Relay {
@ -17,16 +17,14 @@ pub enum Destination {
/// The final destination the relay should send to /// The final destination the relay should send to
target: DHTKey, target: DHTKey,
/// Require safety route or not /// Require safety route or not
safety_spec: Option<SafetySpec>, safety_selection: SafetySelection,
}, },
/// Send to private route (privateroute) /// Send to private route (privateroute)
PrivateRoute { PrivateRoute {
/// A private route to send to /// A private route to send to
private_route: PrivateRoute, private_route: PrivateRoute,
/// Require safety route or not /// Require safety route or not
safety_spec: Option<SafetySpec>, safety_selection: SafetySelection,
/// Prefer reliability or not
reliable: bool,
}, },
} }
@ -34,70 +32,66 @@ impl Destination {
pub fn direct(target: NodeRef) -> Self { pub fn direct(target: NodeRef) -> Self {
Self::Direct { Self::Direct {
target, target,
safety_spec: None, safety_selection: SafetySelection::Unsafe(target.sequencing()),
} }
} }
pub fn relay(relay: NodeRef, target: DHTKey) -> Self { pub fn relay(relay: NodeRef, target: DHTKey) -> Self {
Self::Relay { Self::Relay {
relay, relay,
target, target,
safety_spec: None, safety_selection: SafetySelection::Unsafe(relay.sequencing()),
} }
} }
pub fn private_route(private_route: PrivateRoute, reliable: bool) -> Self { pub fn private_route(private_route: PrivateRoute, safety_selection: SafetySelection) -> Self {
Self::PrivateRoute { Self::PrivateRoute {
private_route, private_route,
safety_spec: None, safety_selection,
reliable,
} }
} }
pub fn with_safety(self, safety_spec: SafetySpec) -> Self { pub fn with_safety(self, safety_selection: SafetySelection) -> Self {
match self { match self {
Destination::Direct { Destination::Direct {
target, target,
safety_spec: _, safety_selection: _,
} => Self::Direct { } => Self::Direct {
target, target,
safety_spec: Some(safety_spec), safety_selection,
}, },
Destination::Relay { Destination::Relay {
relay, relay,
target, target,
safety_spec: _, safety_selection: _,
} => Self::Relay { } => Self::Relay {
relay, relay,
target, target,
safety_spec: Some(safety_spec), safety_selection,
}, },
Destination::PrivateRoute { Destination::PrivateRoute {
private_route, private_route,
safety_spec: _, safety_selection: _,
reliable,
} => Self::PrivateRoute { } => Self::PrivateRoute {
private_route, private_route,
safety_spec: Some(safety_spec), safety_selection,
reliable,
}, },
} }
} }
pub fn get_safety_spec(&self) -> &Option<SafetySpec> { pub fn get_safety_selection(&self) -> &SafetySelection {
match self { match self {
Destination::Direct { Destination::Direct {
target: _, target: _,
safety_spec, safety_selection,
} => safety_spec, } => safety_selection,
Destination::Relay { Destination::Relay {
relay: _, relay: _,
target: _, target: _,
safety_spec, safety_selection,
} => safety_spec, } => safety_selection,
Destination::PrivateRoute { Destination::PrivateRoute {
private_route: _, private_route: _,
safety_spec, safety_selection,
reliable: _, } => safety_selection,
} => safety_spec,
} }
} }
} }
@ -107,30 +101,40 @@ impl fmt::Display for Destination {
match self { match self {
Destination::Direct { Destination::Direct {
target, target,
safety_spec, safety_selection,
} => { } => {
let sr = if safety_spec.is_some() { "+SR" } else { "" }; let sr = if matches!(safety_selection, SafetySelection::Safe(_)) {
"+SR"
} else {
""
};
write!(f, "{}{}", target, sr) write!(f, "{}{}", target, sr)
} }
Destination::Relay { Destination::Relay {
relay, relay,
target, target,
safety_spec, safety_selection,
} => { } => {
let sr = if safety_spec.is_some() { "+SR" } else { "" }; let sr = if matches!(safety_selection, SafetySelection::Safe(_)) {
"+SR"
} else {
""
};
write!(f, "{}@{}{}", target.encode(), relay, sr) write!(f, "{}@{}{}", target.encode(), relay, sr)
} }
Destination::PrivateRoute { Destination::PrivateRoute {
private_route, private_route,
safety_spec, safety_selection,
reliable,
} => { } => {
let sr = if safety_spec.is_some() { "+SR" } else { "" }; let sr = if matches!(safety_selection, SafetySelection::Safe(_)) {
let rl = if *reliable { "+RL" } else { "" }; "+SR"
} else {
""
};
write!(f, "{}{}{}", private_route, sr, rl) write!(f, "{}{}", private_route, sr)
} }
} }
} }

View File

@ -400,9 +400,8 @@ impl RPCProcessor {
// Wrap an operation with a private route inside a safety route // Wrap an operation with a private route inside a safety route
pub(super) fn wrap_with_route( pub(super) fn wrap_with_route(
&self, &self,
safety_spec: Option<SafetySpec>, safety_selection: SafetySelection,
private_route: PrivateRoute, private_route: PrivateRoute,
reliable: bool,
message_data: Vec<u8>, message_data: Vec<u8>,
) -> Result<NetworkResult<RenderedOperation>, RPCError> { ) -> Result<NetworkResult<RenderedOperation>, RPCError> {
let routing_table = self.routing_table(); let routing_table = self.routing_table();
@ -412,7 +411,7 @@ impl RPCProcessor {
let compiled_route: CompiledRoute = let compiled_route: CompiledRoute =
match self.routing_table().with_route_spec_store_mut(|rss, rti| { match self.routing_table().with_route_spec_store_mut(|rss, rti| {
// Compile the safety route with the private route // Compile the safety route with the private route
rss.compile_safety_route(rti, routing_table, safety_spec, private_route, reliable) rss.compile_safety_route(rti, routing_table, safety_selection, private_route)
})? { })? {
Some(cr) => cr, Some(cr) => cr,
None => { None => {
@ -456,7 +455,6 @@ impl RPCProcessor {
let out_node_id = compiled_route.first_hop.node_id(); let out_node_id = compiled_route.first_hop.node_id();
let out_hop_count = (1 + sr_hop_count + pr_hop_count) as usize; let out_hop_count = (1 + sr_hop_count + pr_hop_count) as usize;
let out = RenderedOperation { let out = RenderedOperation {
message: out_message, message: out_message,
node_id: out_node_id, node_id: out_node_id,
@ -491,12 +489,12 @@ impl RPCProcessor {
match dest { match dest {
Destination::Direct { Destination::Direct {
target: ref node_ref, target: ref node_ref,
safety_spec, safety_selection,
} }
| Destination::Relay { | Destination::Relay {
relay: ref node_ref, relay: ref node_ref,
target: _, target: _,
safety_spec, safety_selection,
} => { } => {
// Send to a node without a private route // Send to a node without a private route
// -------------------------------------- // --------------------------------------
@ -505,7 +503,7 @@ impl RPCProcessor {
let (node_ref, node_id) = if let Destination::Relay { let (node_ref, node_id) = if let Destination::Relay {
relay: _, relay: _,
target: ref dht_key, target: ref dht_key,
safety_spec: _, safety_selection: _,
} = dest } = dest
{ {
(node_ref.clone(), dht_key.clone()) (node_ref.clone(), dht_key.clone())
@ -515,8 +513,13 @@ impl RPCProcessor {
}; };
// Handle the existence of safety route // Handle the existence of safety route
match safety_spec { match safety_selection {
None => { SafetySelection::Unsafe(sequencing) => {
// Apply safety selection sequencing requirement if it is more strict than the node_ref's sequencing requirement
if sequencing > node_ref.sequencing() {
node_ref.set_sequencing(sequencing)
}
// If no safety route is being used, and we're not sending to a private // If no safety route is being used, and we're not sending to a private
// route, we can use a direct envelope instead of routing // route, we can use a direct envelope instead of routing
out = NetworkResult::value(RenderedOperation { out = NetworkResult::value(RenderedOperation {
@ -526,25 +529,24 @@ impl RPCProcessor {
hop_count: 1, hop_count: 1,
}); });
} }
Some(safety_spec) => { SafetySelection::Safe(_) => {
// No private route was specified for the request // No private route was specified for the request
// but we are using a safety route, so we must create an empty private route // but we are using a safety route, so we must create an empty private route
let private_route = PrivateRoute::new_stub(node_id); let private_route = PrivateRoute::new_stub(node_id);
// Wrap with safety route // Wrap with safety route
out = self.wrap_with_route(Some(safety_spec), private_route, message)?; out = self.wrap_with_route(safety_selection, private_route, message)?;
} }
}; };
} }
Destination::PrivateRoute { Destination::PrivateRoute {
private_route, private_route,
safety_spec, safety_selection,
reliable, xxxx does this need to be here? what about None safety spec, reliable is in there, does it need to not be? or something?
} => { } => {
// Send to private route // Send to private route
// --------------------- // ---------------------
// Reply with 'route' operation // Reply with 'route' operation
out = self.wrap_with_route(safety_spec, private_route, reliable, message)?; out = self.wrap_with_route(safety_selection, private_route, message)?;
} }
} }
@ -559,9 +561,12 @@ impl RPCProcessor {
// Don't do this if the sender is to remain private // Don't do this if the sender is to remain private
// Otherwise we would be attaching the original sender's identity to the final destination, // Otherwise we would be attaching the original sender's identity to the final destination,
// thus defeating the purpose of the safety route entirely :P // thus defeating the purpose of the safety route entirely :P
if dest.get_safety_spec().is_some() { match dest.get_safety_selection() {
SafetySelection::Unsafe(_) => {}
SafetySelection::Safe(_) => {
return None; return None;
} }
}
// Don't do this if our own signed node info isn't valid yet // Don't do this if our own signed node info isn't valid yet
let routing_table = self.routing_table(); let routing_table = self.routing_table();
if !routing_table.has_valid_own_node_info(RoutingDomain::PublicInternet) { if !routing_table.has_valid_own_node_info(RoutingDomain::PublicInternet) {
@ -571,7 +576,7 @@ impl RPCProcessor {
match dest { match dest {
Destination::Direct { Destination::Direct {
target, target,
safety_spec: _, safety_selection: _,
} => { } => {
// If the target has seen our node info already don't do this // If the target has seen our node info already don't do this
if target.has_seen_our_node_info(RoutingDomain::PublicInternet) { if target.has_seen_our_node_info(RoutingDomain::PublicInternet) {
@ -582,7 +587,7 @@ impl RPCProcessor {
Destination::Relay { Destination::Relay {
relay: _, relay: _,
target, target,
safety_spec: _, safety_selection: _,
} => { } => {
if let Some(target) = routing_table.lookup_node_ref(*target) { if let Some(target) = routing_table.lookup_node_ref(*target) {
if target.has_seen_our_node_info(RoutingDomain::PublicInternet) { if target.has_seen_our_node_info(RoutingDomain::PublicInternet) {
@ -595,8 +600,7 @@ impl RPCProcessor {
} }
Destination::PrivateRoute { Destination::PrivateRoute {
private_route: _, private_route: _,
safety_spec: _, safety_selection: _,
reliable: _,
} => None, } => None,
} }
} }
@ -741,6 +745,7 @@ impl RPCProcessor {
Destination::relay(peer_noderef, sender_id) Destination::relay(peer_noderef, sender_id)
} }
} }
//xxx needs to know what route the request came in on in order to reply over that same route as the preferred safety route
RespondTo::PrivateRoute(pr) => Destination::private_route( RespondTo::PrivateRoute(pr) => Destination::private_route(
pr.clone(), pr.clone(),
request request

View File

@ -7,6 +7,9 @@ impl RPCProcessor {
pub(crate) async fn process_route(&self, msg: RPCMessage) -> Result<(), RPCError> { pub(crate) async fn process_route(&self, msg: RPCMessage) -> Result<(), RPCError> {
// xxx do not process latency for routed messages // xxx do not process latency for routed messages
// tracing::Span::current().record("res", &tracing::field::display(res)); // tracing::Span::current().record("res", &tracing::field::display(res));
xxx continue here
Err(RPCError::unimplemented("process_route")) Err(RPCError::unimplemented("process_route"))
} }
} }

View File

@ -420,6 +420,28 @@ pub enum Stability {
Reliable, Reliable,
} }
/// The choice of safety route including in compiled routes
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum SafetySelection {
/// Don't use a safety route, only specify the sequencing preference
Unsafe(Sequencing),
/// Use a safety route and parameters specified by a SafetySpec
Safe(SafetySpec),
}
/// Options for safety routes (sender privacy)
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct SafetySpec {
/// preferred safety route if it still exists
pub preferred_route: Option<DHTKey>,
/// 0 = no safety route, just use node's node id, more hops is safer but slower
pub hop_count: usize,
/// prefer reliability over speed
pub stability: Stability,
/// prefer connection-oriented sequenced protocols
pub sequencing: Sequencing,
}
// Keep member order appropriate for sorting < preference // Keep member order appropriate for sorting < preference
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, Hash)] #[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, Hash)]
pub struct DialInfoDetail { pub struct DialInfoDetail {
@ -1551,8 +1573,8 @@ impl DialInfo {
} }
pub fn ordered_sequencing_sort(a: &DialInfo, b: &DialInfo) -> core::cmp::Ordering { pub fn ordered_sequencing_sort(a: &DialInfo, b: &DialInfo) -> core::cmp::Ordering {
let ca = a.protocol_type().sort_order(true); let ca = a.protocol_type().sort_order(Sequencing::EnsureOrdered);
let cb = b.protocol_type().sort_order(true); let cb = b.protocol_type().sort_order(Sequencing::EnsureOrdered);
if ca < cb { if ca < cb {
return core::cmp::Ordering::Less; return core::cmp::Ordering::Less;
} }

View File

@ -10,10 +10,8 @@ pub enum Target {
pub struct RoutingContextInner {} pub struct RoutingContextInner {}
pub struct RoutingContextUnlockedInner { pub struct RoutingContextUnlockedInner {
/// Enforce use of private routing /// Safety routing requirements
privacy: usize, safety_selection: SafetySelection,
/// Choose reliable protocols over unreliable/faster protocols when available
reliable: bool,
} }
impl Drop for RoutingContextInner { impl Drop for RoutingContextInner {
@ -41,8 +39,7 @@ impl RoutingContext {
api, api,
inner: Arc::new(Mutex::new(RoutingContextInner {})), inner: Arc::new(Mutex::new(RoutingContextInner {})),
unlocked_inner: Arc::new(RoutingContextUnlockedInner { unlocked_inner: Arc::new(RoutingContextUnlockedInner {
privacy: 0, safety_selection: SafetySelection::Unsafe(Sequencing::NoPreference),
reliable: false,
}), }),
} }
} }
@ -54,42 +51,52 @@ impl RoutingContext {
api: self.api.clone(), api: self.api.clone(),
inner: Arc::new(Mutex::new(RoutingContextInner {})), inner: Arc::new(Mutex::new(RoutingContextInner {})),
unlocked_inner: Arc::new(RoutingContextUnlockedInner { unlocked_inner: Arc::new(RoutingContextUnlockedInner {
privacy: c.network.rpc.default_route_hop_count as usize, safety_selection: SafetySelection::Safe(SafetySpec {
reliable: self.unlocked_inner.reliable, preferred_route: None,
hop_count: c.network.rpc.default_route_hop_count as usize,
stability: Stability::LowLatency,
sequencing: Sequencing::NoPreference,
}),
}), }),
}) })
} }
pub fn with_privacy(self, hops: usize) -> Result<Self, VeilidAPIError> { pub fn with_privacy(self, safety_spec: SafetySpec) -> Result<Self, VeilidAPIError> {
let config = self.api.config()?;
let c = config.get();
let privacy = if hops > 0 && hops <= c.network.rpc.max_route_hop_count as usize {
hops
} else {
return Err(VeilidAPIError::invalid_argument(
"hops value is too large",
"hops",
hops,
));
};
Ok(Self { Ok(Self {
api: self.api.clone(), api: self.api.clone(),
inner: Arc::new(Mutex::new(RoutingContextInner {})), inner: Arc::new(Mutex::new(RoutingContextInner {})),
unlocked_inner: Arc::new(RoutingContextUnlockedInner { unlocked_inner: Arc::new(RoutingContextUnlockedInner {
privacy, safety_selection: SafetySelection::Safe(safety_spec),
reliable: self.unlocked_inner.reliable,
}), }),
}) })
} }
pub fn with_reliability(self) -> Self { pub fn with_sequencing(self, sequencing: Sequencing) -> Self {
Self { Self {
api: self.api.clone(), api: self.api.clone(),
inner: Arc::new(Mutex::new(RoutingContextInner {})), inner: Arc::new(Mutex::new(RoutingContextInner {})),
unlocked_inner: Arc::new(RoutingContextUnlockedInner { unlocked_inner: Arc::new(RoutingContextUnlockedInner {
privacy: self.unlocked_inner.privacy, safety_selection: match self.unlocked_inner.safety_selection {
reliable: true, SafetySelection::Unsafe(_) => SafetySelection::Unsafe(sequencing),
SafetySelection::Safe(safety_spec) => SafetySelection::Safe(SafetySpec {
preferred_route: safety_spec.preferred_route,
hop_count: safety_spec.hop_count,
stability: safety_spec.stability,
sequencing,
}), }),
},
}),
}
}
pub fn sequencing(&self) -> Sequencing {
match self.unlocked_inner.safety_selection {
SafetySelection::Unsafe(sequencing) => sequencing,
SafetySelection::Safe(safety_spec) => safety_spec.sequencing,
}
}
pub fn safety_spec(&self) -> Option<SafetySpec> {
match self.unlocked_inner.safety_selection {
SafetySelection::Unsafe(_) => None,
SafetySelection::Safe(safety_spec) => Some(safety_spec.clone()),
} }
} }
@ -111,27 +118,17 @@ impl RoutingContext {
Ok(None) => return Err(VeilidAPIError::NodeNotFound { node_id }), Ok(None) => return Err(VeilidAPIError::NodeNotFound { node_id }),
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
}; };
// Apply reliability sort // Apply sequencing to match safety selection
if self.unlocked_inner.reliable { nr.set_sequencing(self.sequencing());
nr.set_reliable();
}
Ok(rpc_processor::Destination::Direct { Ok(rpc_processor::Destination::Direct {
target: nr, target: nr,
safety_spec: Some(routing_table::SafetySpec { safety_selection: self.unlocked_inner.safety_selection,
preferred_route: None,
hop_count: self.unlocked_inner.privacy,
reliable: self.unlocked_inner.reliable,
}),
}) })
} }
Target::PrivateRoute(pr) => Ok(rpc_processor::Destination::PrivateRoute { Target::PrivateRoute(pr) => Ok(rpc_processor::Destination::PrivateRoute {
private_route: pr, private_route: pr,
safety_spec: Some(routing_table::SafetySpec { safety_selection: self.unlocked_inner.safety_selection,
preferred_route: None,
hop_count: self.unlocked_inner.privacy,
reliable: self.unlocked_inner.reliable,
}),
reliable: self.unlocked_inner.reliable,
}), }),
} }
} }