veilid/veilid-core/src/routing_table/routing_domains.rs

603 lines
23 KiB
Rust
Raw Normal View History

2022-09-03 17:57:25 +00:00
use super::*;
2022-10-13 02:53:40 +00:00
/// Mechanism required to contact another node
#[derive(Clone, Debug)]
2022-11-02 01:05:48 +00:00
pub enum ContactMethod {
2022-10-13 02:53:40 +00:00
/// Node is not reachable by any means
Unreachable,
/// Connection should have already existed
Existing,
/// Contact the node directly
Direct(DialInfo),
/// Request via signal the node connect back directly (relay, target)
2023-02-11 20:54:55 +00:00
SignalReverse(TypedKey, TypedKey),
2023-02-22 23:29:07 +00:00
/// Request via signal the node negotiate a hole punch (relay, target)
2023-02-11 20:54:55 +00:00
SignalHolePunch(TypedKey, TypedKey),
2022-10-13 02:53:40 +00:00
/// Must use an inbound relay to reach the node
2023-02-11 20:54:55 +00:00
InboundRelay(TypedKey),
2022-10-13 02:53:40 +00:00
/// Must use outbound relay to reach the node
2023-02-11 20:54:55 +00:00
OutboundRelay(TypedKey),
2022-10-13 02:53:40 +00:00
}
2022-10-09 18:59:01 +00:00
#[derive(Debug)]
pub struct RoutingDomainDetailCommon {
routing_domain: RoutingDomain,
network_class: Option<NetworkClass>,
outbound_protocols: ProtocolTypeSet,
inbound_protocols: ProtocolTypeSet,
address_types: AddressTypeSet,
2022-09-03 17:57:25 +00:00
relay_node: Option<NodeRef>,
2023-07-14 18:21:00 +00:00
relay_node_last_keepalive: Option<Timestamp>,
2023-07-04 04:24:55 +00:00
capabilities: Vec<Capability>,
2022-09-03 17:57:25 +00:00
dial_info_details: Vec<DialInfoDetail>,
2022-10-09 18:59:01 +00:00
// caches
cached_peer_info: Mutex<Option<PeerInfo>>,
2022-09-03 17:57:25 +00:00
}
2022-10-09 18:59:01 +00:00
impl RoutingDomainDetailCommon {
pub fn new(routing_domain: RoutingDomain) -> Self {
Self {
routing_domain,
network_class: Default::default(),
outbound_protocols: Default::default(),
inbound_protocols: Default::default(),
address_types: Default::default(),
relay_node: Default::default(),
2023-07-14 18:21:00 +00:00
relay_node_last_keepalive: Default::default(),
2023-07-04 04:24:55 +00:00
capabilities: Default::default(),
2022-10-09 18:59:01 +00:00
dial_info_details: Default::default(),
cached_peer_info: Mutex::new(Default::default()),
}
}
// Set from network manager
pub(super) fn setup_network(
&mut self,
outbound_protocols: ProtocolTypeSet,
inbound_protocols: ProtocolTypeSet,
address_types: AddressTypeSet,
2023-07-04 04:24:55 +00:00
capabilities: Vec<Capability>,
2022-10-09 18:59:01 +00:00
) {
self.outbound_protocols = outbound_protocols;
self.inbound_protocols = inbound_protocols;
self.address_types = address_types;
2023-07-04 04:24:55 +00:00
self.capabilities = capabilities;
2022-11-03 01:54:48 +00:00
self.clear_cache();
2022-10-09 18:59:01 +00:00
}
pub(super) fn set_network_class(&mut self, network_class: Option<NetworkClass>) {
self.network_class = network_class;
2022-11-03 01:54:48 +00:00
self.clear_cache();
2022-10-09 18:59:01 +00:00
}
pub fn network_class(&self) -> Option<NetworkClass> {
self.network_class
2022-09-03 17:57:25 +00:00
}
2022-10-09 18:59:01 +00:00
pub fn outbound_protocols(&self) -> ProtocolTypeSet {
self.outbound_protocols
}
pub fn inbound_protocols(&self) -> ProtocolTypeSet {
self.inbound_protocols
}
pub fn address_types(&self) -> AddressTypeSet {
self.address_types
}
2023-07-04 04:24:55 +00:00
pub fn capabilities(&self) -> Vec<Capability> {
self.capabilities.clone()
}
2022-10-09 18:59:01 +00:00
pub fn relay_node(&self) -> Option<NodeRef> {
2022-09-03 17:57:25 +00:00
self.relay_node.clone()
}
2023-07-14 18:21:00 +00:00
pub fn relay_node_last_keepalive(&self) -> Option<Timestamp> {
self.relay_node_last_keepalive
}
2022-10-09 18:59:01 +00:00
pub(super) fn set_relay_node(&mut self, opt_relay_node: Option<NodeRef>) {
2022-09-04 18:17:28 +00:00
self.relay_node = opt_relay_node.map(|nr| {
2022-10-09 18:59:01 +00:00
nr.filtered_clone(NodeRefFilter::new().with_routing_domain(self.routing_domain))
2022-11-03 01:54:48 +00:00
});
2023-07-14 18:21:00 +00:00
self.relay_node_last_keepalive = None;
2022-11-03 01:54:48 +00:00
self.clear_cache();
2022-09-03 17:57:25 +00:00
}
2023-07-14 18:21:00 +00:00
pub(super) fn set_relay_node_last_keepalive(&mut self, ts: Option<Timestamp>) {
self.relay_node_last_keepalive = ts;
}
2022-10-09 18:59:01 +00:00
pub fn dial_info_details(&self) -> &Vec<DialInfoDetail> {
2022-09-03 17:57:25 +00:00
&self.dial_info_details
}
2023-09-04 17:33:27 +00:00
pub(super) fn clear_dial_info_details(&mut self, address_type: Option<AddressType>, protocol_type: Option<ProtocolType>) {
self.dial_info_details.retain_mut(|e| {
let mut remove = true;
if let Some(pt) = protocol_type {
if pt != e.dial_info.protocol_type() {
remove = false;
}
}
if let Some(at) = address_type {
if at != e.dial_info.address_type() {
remove = false;
}
}
!remove
});
2022-11-03 01:54:48 +00:00
self.clear_cache();
2022-09-03 17:57:25 +00:00
}
2022-10-09 18:59:01 +00:00
pub(super) fn add_dial_info_detail(&mut self, did: DialInfoDetail) {
2022-09-03 17:57:25 +00:00
self.dial_info_details.push(did);
self.dial_info_details.sort();
2022-11-03 01:54:48 +00:00
self.clear_cache();
2022-09-03 17:57:25 +00:00
}
2022-10-09 18:59:01 +00:00
2023-07-14 23:14:12 +00:00
pub fn has_valid_network_class(&self) -> bool {
2022-10-09 18:59:01 +00:00
self.network_class.unwrap_or(NetworkClass::Invalid) != NetworkClass::Invalid
}
2022-11-09 22:11:35 +00:00
fn make_peer_info(&self, rti: &RoutingTableInner) -> PeerInfo {
2023-05-29 19:24:57 +00:00
let node_info = NodeInfo::new(
self.network_class.unwrap_or(NetworkClass::Invalid),
self.outbound_protocols,
self.address_types,
VALID_ENVELOPE_VERSIONS.to_vec(),
VALID_CRYPTO_KINDS.to_vec(),
2023-07-04 04:24:55 +00:00
self.capabilities.clone(),
2023-05-29 19:24:57 +00:00
self.dial_info_details.clone()
);
2022-11-09 22:11:35 +00:00
2023-08-24 21:17:48 +00:00
// Check if any of our dialinfo require a relay for signaling
// FullConeNAT requires a relay but it does not have to be published because it does not require signaling
2023-08-24 22:59:33 +00:00
let mut publish_relay = node_info.network_class().inbound_wants_relay() || node_info.network_class().outbound_wants_relay();
if !publish_relay {
// Check the dialinfo to see if they might want to publish a relay for signalling specifically
for did in self.dial_info_details() {
if did.class.requires_signal() {
publish_relay = true;
break;
}
}
}
2023-08-24 21:17:48 +00:00
let relay_info = if publish_relay {
self
2022-11-09 22:11:35 +00:00
.relay_node
.as_ref()
2022-11-10 03:27:37 +00:00
.and_then(|rn| {
let opt_relay_pi = rn.locked(rti).make_peer_info(self.routing_domain);
if let Some(relay_pi) = opt_relay_pi {
2023-05-29 19:24:57 +00:00
let (relay_ids, relay_sni) = relay_pi.destructure();
match relay_sni {
SignedNodeInfo::Direct(d) => Some((relay_ids, d)),
2022-11-10 03:27:37 +00:00
SignedNodeInfo::Relayed(_) => {
warn!("relay node should not have a relay itself! if this happens, a relay updated its signed node info and became a relay, which should cause the relay to be dropped");
None
},
}
} else {
None
}
2023-08-24 21:17:48 +00:00
})
} else {
None
};
2022-11-09 22:11:35 +00:00
2022-11-10 03:27:37 +00:00
let signed_node_info = match relay_info {
2023-02-22 23:29:07 +00:00
Some((relay_ids, relay_sdni)) => SignedNodeInfo::Relayed(
2023-02-08 02:44:50 +00:00
SignedRelayedNodeInfo::make_signatures(
2023-02-22 23:29:07 +00:00
rti.unlocked_inner.crypto(),
rti.unlocked_inner.node_id_typed_key_pairs(),
2022-11-09 22:11:35 +00:00
node_info,
2023-02-22 23:29:07 +00:00
relay_ids,
2022-11-10 03:27:37 +00:00
relay_sdni,
2022-11-09 22:11:35 +00:00
)
.unwrap(),
),
None => SignedNodeInfo::Direct(
2023-02-22 23:29:07 +00:00
SignedDirectNodeInfo::make_signatures(
rti.unlocked_inner.crypto(),
rti.unlocked_inner.node_id_typed_key_pairs(),
2022-11-09 22:11:35 +00:00
node_info,
)
2022-11-10 03:27:37 +00:00
.unwrap()
2022-11-09 22:11:35 +00:00
),
};
2023-02-22 23:29:07 +00:00
PeerInfo::new(rti.unlocked_inner.node_ids(), signed_node_info)
2022-11-09 22:11:35 +00:00
}
2022-11-03 01:54:48 +00:00
pub fn with_peer_info<F, R>(&self, rti: &RoutingTableInner, f: F) -> R
2022-10-09 18:59:01 +00:00
where
F: FnOnce(&PeerInfo) -> R,
{
2022-10-31 03:23:12 +00:00
let mut cpi = self.cached_peer_info.lock();
2022-10-09 18:59:01 +00:00
if cpi.is_none() {
// Regenerate peer info
2022-11-10 03:27:37 +00:00
let pi = self.make_peer_info(rti);
2022-10-09 18:59:01 +00:00
// Cache the peer info
*cpi = Some(pi);
}
f(cpi.as_ref().unwrap())
}
pub fn inbound_dial_info_filter(&self) -> DialInfoFilter {
DialInfoFilter::all()
.with_protocol_type_set(self.inbound_protocols)
.with_address_type_set(self.address_types)
}
pub fn outbound_dial_info_filter(&self) -> DialInfoFilter {
DialInfoFilter::all()
.with_protocol_type_set(self.outbound_protocols)
.with_address_type_set(self.address_types)
}
pub(super) fn clear_cache(&self) {
*self.cached_peer_info.lock() = None;
}
}
/// General trait for all routing domains
pub trait RoutingDomainDetail {
// Common accessors
fn common(&self) -> &RoutingDomainDetailCommon;
fn common_mut(&mut self) -> &mut RoutingDomainDetailCommon;
2022-10-13 02:53:40 +00:00
/// Can this routing domain contain a particular address
2022-10-09 18:59:01 +00:00
fn can_contain_address(&self, address: Address) -> bool;
2022-10-13 02:53:40 +00:00
/// Get the contact method required for node A to reach node B in this routing domain
/// Routing table must be locked for reading to use this function
fn get_contact_method(
&self,
rti: &RoutingTableInner,
2022-11-10 03:27:37 +00:00
peer_a: &PeerInfo,
peer_b: &PeerInfo,
2022-10-13 02:53:40 +00:00
dial_info_filter: DialInfoFilter,
2022-10-21 14:35:03 +00:00
sequencing: Sequencing,
2023-08-22 01:04:21 +00:00
dif_sort: Option<Arc<dyn Fn(&DialInfoDetail, &DialInfoDetail) -> core::cmp::Ordering>>,
2022-10-13 02:53:40 +00:00
) -> ContactMethod;
2022-10-09 18:59:01 +00:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Public Internet routing domain internals
#[derive(Debug)]
pub struct PublicInternetRoutingDomainDetail {
/// Common implementation for all routing domains
common: RoutingDomainDetailCommon,
}
impl Default for PublicInternetRoutingDomainDetail {
fn default() -> Self {
Self {
common: RoutingDomainDetailCommon::new(RoutingDomain::PublicInternet),
}
}
}
2023-06-24 15:16:34 +00:00
fn first_filtered_dial_info_detail_between_nodes(
2022-10-13 02:53:40 +00:00
from_node: &NodeInfo,
to_node: &NodeInfo,
dial_info_filter: &DialInfoFilter,
2022-10-22 01:27:07 +00:00
sequencing: Sequencing,
2023-08-22 01:04:21 +00:00
dif_sort: Option<Arc<dyn Fn(&DialInfoDetail, &DialInfoDetail) -> core::cmp::Ordering>>
2022-10-13 02:53:40 +00:00
) -> Option<DialInfoDetail> {
2022-10-22 01:27:07 +00:00
let dial_info_filter = dial_info_filter.clone().filtered(
2022-10-13 02:53:40 +00:00
&DialInfoFilter::all()
2023-05-29 19:24:57 +00:00
.with_address_type_set(from_node.address_types())
.with_protocol_type_set(from_node.outbound_protocols()),
2022-10-13 02:53:40 +00:00
);
2023-06-24 15:16:34 +00:00
// Apply sequencing and get sort
2023-08-22 01:04:21 +00:00
// Include sorting by external dial info sort for rotating through dialinfo
// based on an external preference table, for example the one kept by
// AddressFilter to deprioritize dialinfo that have recently failed to connect
2023-06-24 15:16:34 +00:00
let (ordered, dial_info_filter) = dial_info_filter.with_sequencing(sequencing);
2023-08-22 01:04:21 +00:00
let sort: Option<Box<dyn Fn(&DialInfoDetail, &DialInfoDetail) -> core::cmp::Ordering>> = if ordered {
if let Some(dif_sort) = dif_sort {
Some(Box::new(move |a, b| {
let mut ord = dif_sort(a,b);
if ord == core::cmp::Ordering::Equal {
ord = DialInfoDetail::ordered_sequencing_sort(a,b);
}
ord
}))
} else {
Some(Box::new(move |a,b| { DialInfoDetail::ordered_sequencing_sort(a,b) }))
}
2023-06-24 15:16:34 +00:00
} else {
2023-08-22 01:04:21 +00:00
if let Some(dif_sort) = dif_sort {
Some(Box::new(move |a,b| { dif_sort(a,b) }))
} else {
None
}
2022-10-13 02:53:40 +00:00
};
2023-06-24 15:16:34 +00:00
2022-10-22 01:27:07 +00:00
// If the filter is dead then we won't be able to connect
if dial_info_filter.is_dead() {
return None;
}
2022-10-13 02:53:40 +00:00
// Get the best match dial info for node B if we have it
2023-06-24 15:16:34 +00:00
let direct_filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter);
2022-10-13 02:53:40 +00:00
to_node.first_filtered_dial_info_detail(sort, direct_filter)
}
2022-10-09 18:59:01 +00:00
impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
fn common(&self) -> &RoutingDomainDetailCommon {
&self.common
}
fn common_mut(&mut self) -> &mut RoutingDomainDetailCommon {
&mut self.common
}
fn can_contain_address(&self, address: Address) -> bool {
address.is_global()
}
2022-10-13 02:53:40 +00:00
fn get_contact_method(
&self,
_rti: &RoutingTableInner,
2022-11-10 03:27:37 +00:00
peer_a: &PeerInfo,
peer_b: &PeerInfo,
2022-10-13 02:53:40 +00:00
dial_info_filter: DialInfoFilter,
2022-10-22 01:27:07 +00:00
sequencing: Sequencing,
2023-08-22 01:04:21 +00:00
dif_sort: Option<Arc<dyn Fn(&DialInfoDetail, &DialInfoDetail) -> core::cmp::Ordering>>,
2022-10-13 02:53:40 +00:00
) -> ContactMethod {
2022-11-10 03:27:37 +00:00
// Get the nodeinfos for convenience
2023-05-29 19:24:57 +00:00
let node_a = peer_a.signed_node_info().node_info();
let node_b = peer_b.signed_node_info().node_info();
2023-02-22 23:29:07 +00:00
// Get the node ids that would be used between these peers
2023-05-29 19:24:57 +00:00
let cck = common_crypto_kinds(&peer_a.node_ids().kinds(), &peer_b.node_ids().kinds());
2023-02-22 23:29:07 +00:00
let Some(best_ck) = cck.first().copied() else {
// No common crypto kinds between these nodes, can't contact
return ContactMethod::Unreachable;
};
2023-03-01 02:11:26 +00:00
2023-05-29 19:24:57 +00:00
//let node_a_id = peer_a.node_ids().get(best_ck).unwrap();
let node_b_id = peer_b.node_ids().get(best_ck).unwrap();
2023-02-22 23:29:07 +00:00
2022-10-13 02:53:40 +00:00
// Get the best match dial info for node B if we have it
if let Some(target_did) =
2023-08-22 01:04:21 +00:00
first_filtered_dial_info_detail_between_nodes(node_a, node_b, &dial_info_filter, sequencing, dif_sort.clone())
2022-10-13 02:53:40 +00:00
{
// Do we need to signal before going inbound?
if !target_did.class.requires_signal() {
// Go direct without signaling
return ContactMethod::Direct(target_did.dial_info);
}
// Get the target's inbound relay, it must have one or it is not reachable
2023-05-29 19:24:57 +00:00
if let Some(node_b_relay) = peer_b.signed_node_info().relay_info() {
2022-12-17 18:02:39 +00:00
2022-10-13 02:53:40 +00:00
// Note that relay_peer_info could be node_a, in which case a connection already exists
2022-12-17 18:02:39 +00:00
// and we only get here if the connection had dropped, in which case node_a is unreachable until
// it gets a new relay connection up
2023-05-29 19:24:57 +00:00
if peer_b.signed_node_info().relay_ids().contains_any(peer_a.node_ids()) {
2022-10-13 02:53:40 +00:00
return ContactMethod::Existing;
}
2023-02-22 23:29:07 +00:00
// Get best node id to contact relay with
2023-05-29 19:24:57 +00:00
let Some(node_b_relay_id) = peer_b.signed_node_info().relay_ids().get(best_ck) else {
2023-02-22 23:29:07 +00:00
// No best relay id
return ContactMethod::Unreachable;
};
2022-10-13 02:53:40 +00:00
// Can node A reach the inbound relay directly?
2023-06-24 15:16:34 +00:00
if first_filtered_dial_info_detail_between_nodes(
2022-10-13 02:53:40 +00:00
node_a,
2022-11-10 03:27:37 +00:00
node_b_relay,
2022-10-13 02:53:40 +00:00
&dial_info_filter,
2022-10-22 01:27:07 +00:00
sequencing,
2023-08-22 01:04:21 +00:00
dif_sort.clone(),
2022-10-13 02:53:40 +00:00
)
.is_some()
{
// Can node A receive anything inbound ever?
2023-05-29 19:24:57 +00:00
if matches!(node_a.network_class(), NetworkClass::InboundCapable) {
2022-10-13 02:53:40 +00:00
///////// Reverse connection
// Get the best match dial info for an reverse inbound connection from node B to node A
2023-06-24 15:16:34 +00:00
if let Some(reverse_did) = first_filtered_dial_info_detail_between_nodes(
2022-10-13 02:53:40 +00:00
node_b,
node_a,
&dial_info_filter,
2022-10-22 01:27:07 +00:00
sequencing,
2023-08-22 01:04:21 +00:00
dif_sort.clone()
2022-10-13 02:53:40 +00:00
) {
// Ensure we aren't on the same public IP address (no hairpin nat)
if reverse_did.dial_info.to_ip_addr()
!= target_did.dial_info.to_ip_addr()
{
// Can we receive a direct reverse connection?
if !reverse_did.class.requires_signal() {
return ContactMethod::SignalReverse(
2023-02-22 23:29:07 +00:00
node_b_relay_id,
node_b_id,
2022-10-13 02:53:40 +00:00
);
}
}
}
///////// UDP hole-punch
// Does node B have a direct udp dialinfo node A can reach?
let udp_dial_info_filter = dial_info_filter
.clone()
.filtered(&DialInfoFilter::all().with_protocol_type(ProtocolType::UDP));
2023-06-24 15:16:34 +00:00
if let Some(target_udp_did) = first_filtered_dial_info_detail_between_nodes(
2022-10-13 02:53:40 +00:00
node_a,
node_b,
&udp_dial_info_filter,
2022-10-22 01:27:07 +00:00
sequencing,
2023-08-22 01:04:21 +00:00
dif_sort.clone()
2022-10-13 02:53:40 +00:00
) {
// Does node A have a direct udp dialinfo that node B can reach?
2023-06-24 15:16:34 +00:00
if let Some(reverse_udp_did) = first_filtered_dial_info_detail_between_nodes(
2022-10-13 02:53:40 +00:00
node_b,
node_a,
&udp_dial_info_filter,
2022-10-22 01:27:07 +00:00
sequencing,
2023-08-22 01:04:21 +00:00
dif_sort.clone(),
2022-10-13 02:53:40 +00:00
) {
// Ensure we aren't on the same public IP address (no hairpin nat)
if reverse_udp_did.dial_info.to_ip_addr()
!= target_udp_did.dial_info.to_ip_addr()
{
// The target and ourselves have a udp dialinfo that they can reach
return ContactMethod::SignalHolePunch(
2023-02-22 23:29:07 +00:00
node_b_relay_id,
node_b_id,
2022-10-13 02:53:40 +00:00
);
}
}
}
// Otherwise we have to inbound relay
}
2023-02-22 23:29:07 +00:00
return ContactMethod::InboundRelay(node_b_relay_id);
2022-10-13 02:53:40 +00:00
}
}
}
// If the node B has no direct dial info, it needs to have an inbound relay
2023-05-29 19:24:57 +00:00
else if let Some(node_b_relay) = peer_b.signed_node_info().relay_info() {
2023-02-22 23:29:07 +00:00
2022-12-17 18:02:39 +00:00
// Note that relay_peer_info could be node_a, in which case a connection already exists
2023-07-19 18:44:58 +00:00
// and we only get here if the connection had dropped, in which case node_b is unreachable until
2022-12-17 18:02:39 +00:00
// it gets a new relay connection up
2023-05-29 19:24:57 +00:00
if peer_b.signed_node_info().relay_ids().contains_any(peer_a.node_ids()) {
2022-12-17 18:02:39 +00:00
return ContactMethod::Existing;
}
2022-11-10 03:27:37 +00:00
2023-02-22 23:29:07 +00:00
// Get best node id to contact relay with
2023-05-29 19:24:57 +00:00
let Some(node_b_relay_id) = peer_b.signed_node_info().relay_ids().get(best_ck) else {
2023-02-22 23:29:07 +00:00
// No best relay id
return ContactMethod::Unreachable;
};
2022-10-13 02:53:40 +00:00
// Can we reach the full relay?
2023-06-24 15:16:34 +00:00
if first_filtered_dial_info_detail_between_nodes(
2022-10-13 02:53:40 +00:00
node_a,
2022-11-10 03:27:37 +00:00
&node_b_relay,
2022-10-13 02:53:40 +00:00
&dial_info_filter,
2022-10-22 01:27:07 +00:00
sequencing,
2023-08-22 01:04:21 +00:00
dif_sort.clone()
2022-10-13 02:53:40 +00:00
)
.is_some()
{
2023-02-22 23:29:07 +00:00
return ContactMethod::InboundRelay(node_b_relay_id);
2022-10-13 02:53:40 +00:00
}
}
// If node A can't reach the node by other means, it may need to use its own relay
2023-07-19 18:44:58 +00:00
if peer_a.signed_node_info().node_info().network_class().outbound_wants_relay() {
if let Some(node_a_relay_id) = peer_a.signed_node_info().relay_ids().get(best_ck) {
// Ensure it's not our relay we're trying to reach
if node_a_relay_id != node_b_id {
return ContactMethod::OutboundRelay(node_a_relay_id);
}
2023-07-13 23:54:08 +00:00
}
2022-10-13 02:53:40 +00:00
}
ContactMethod::Unreachable
}
2022-09-03 17:57:25 +00:00
}
/// Local Network routing domain internals
2022-10-09 18:59:01 +00:00
#[derive(Debug)]
pub struct LocalNetworkRoutingDomainDetail {
2022-09-03 17:57:25 +00:00
/// The local networks this domain will communicate with
local_networks: Vec<(IpAddr, IpAddr)>,
2022-10-09 18:59:01 +00:00
/// Common implementation for all routing domains
common: RoutingDomainDetailCommon,
}
impl Default for LocalNetworkRoutingDomainDetail {
fn default() -> Self {
Self {
local_networks: Default::default(),
common: RoutingDomainDetailCommon::new(RoutingDomain::LocalNetwork),
}
}
2022-09-03 17:57:25 +00:00
}
2022-10-09 18:59:01 +00:00
impl LocalNetworkRoutingDomainDetail {
2022-09-04 19:40:35 +00:00
pub fn set_local_networks(&mut self, mut local_networks: Vec<(IpAddr, IpAddr)>) -> bool {
2022-09-03 17:57:25 +00:00
local_networks.sort();
if local_networks == self.local_networks {
return false;
}
self.local_networks = local_networks;
true
}
}
2022-10-09 18:59:01 +00:00
impl RoutingDomainDetail for LocalNetworkRoutingDomainDetail {
fn common(&self) -> &RoutingDomainDetailCommon {
&self.common
}
fn common_mut(&mut self) -> &mut RoutingDomainDetailCommon {
&mut self.common
}
2022-09-03 17:57:25 +00:00
fn can_contain_address(&self, address: Address) -> bool {
let ip = address.to_ip_addr();
2022-09-04 19:40:35 +00:00
for localnet in &self.local_networks {
2022-09-03 17:57:25 +00:00
if ipaddr_in_network(ip, localnet.0, localnet.1) {
return true;
}
}
false
}
2022-10-13 02:53:40 +00:00
fn get_contact_method(
&self,
_rti: &RoutingTableInner,
2022-11-10 03:27:37 +00:00
peer_a: &PeerInfo,
peer_b: &PeerInfo,
2022-10-13 02:53:40 +00:00
dial_info_filter: DialInfoFilter,
2022-10-22 01:27:07 +00:00
sequencing: Sequencing,
2023-08-22 01:04:21 +00:00
dif_sort: Option<Arc<dyn Fn(&DialInfoDetail, &DialInfoDetail) -> core::cmp::Ordering>>,
2022-10-13 02:53:40 +00:00
) -> ContactMethod {
// Scope the filter down to protocols node A can do outbound
let dial_info_filter = dial_info_filter.filtered(
&DialInfoFilter::all()
2023-05-29 19:24:57 +00:00
.with_address_type_set(peer_a.signed_node_info().node_info().address_types())
.with_protocol_type_set(peer_a.signed_node_info().node_info().outbound_protocols()),
2022-10-13 02:53:40 +00:00
);
2022-11-10 03:27:37 +00:00
2023-08-22 01:04:21 +00:00
// Apply sequencing and get sort
// Include sorting by external dial info sort for rotating through dialinfo
// based on an external preference table, for example the one kept by
// AddressFilter to deprioritize dialinfo that have recently failed to connect
let (ordered, dial_info_filter) = dial_info_filter.with_sequencing(sequencing);
let sort: Option<Box<dyn Fn(&DialInfoDetail, &DialInfoDetail) -> core::cmp::Ordering>> = if ordered {
if let Some(dif_sort) = dif_sort {
Some(Box::new(move |a, b| {
let mut ord = dif_sort(a,b);
if ord == core::cmp::Ordering::Equal {
ord = DialInfoDetail::ordered_sequencing_sort(a,b);
}
ord
}))
} else {
Some(Box::new(move |a,b| { DialInfoDetail::ordered_sequencing_sort(a,b) }))
}
} else {
if let Some(dif_sort) = dif_sort {
Some(Box::new(move |a,b| { dif_sort(a,b) }))
} else {
None
}
2022-10-22 01:27:07 +00:00
};
2023-08-22 01:04:21 +00:00
2022-10-13 02:53:40 +00:00
// If the filter is dead then we won't be able to connect
if dial_info_filter.is_dead() {
return ContactMethod::Unreachable;
}
let filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter);
2023-05-29 19:24:57 +00:00
let opt_target_did = peer_b.signed_node_info().node_info().first_filtered_dial_info_detail(sort, filter);
2022-10-13 02:53:40 +00:00
if let Some(target_did) = opt_target_did {
return ContactMethod::Direct(target_did.dial_info);
}
ContactMethod::Unreachable
}
2022-09-03 17:57:25 +00:00
}