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)
|
|
|
|
SignalReverse(DHTKey, DHTKey),
|
|
|
|
/// Request via signal the node negotiate a hole punch (relay, target_node)
|
|
|
|
SignalHolePunch(DHTKey, DHTKey),
|
|
|
|
/// Must use an inbound relay to reach the node
|
|
|
|
InboundRelay(DHTKey),
|
|
|
|
/// Must use outbound relay to reach the node
|
|
|
|
OutboundRelay(DHTKey),
|
|
|
|
}
|
|
|
|
|
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>,
|
|
|
|
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(),
|
|
|
|
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,
|
|
|
|
) {
|
|
|
|
self.outbound_protocols = outbound_protocols;
|
|
|
|
self.inbound_protocols = inbound_protocols;
|
|
|
|
self.address_types = address_types;
|
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
|
|
|
|
}
|
|
|
|
pub fn relay_node(&self) -> Option<NodeRef> {
|
2022-09-03 17:57:25 +00:00
|
|
|
self.relay_node.clone()
|
|
|
|
}
|
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
|
|
|
});
|
|
|
|
self.clear_cache();
|
2022-09-03 17:57:25 +00:00
|
|
|
}
|
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
|
|
|
|
}
|
2022-10-09 18:59:01 +00:00
|
|
|
pub(super) fn clear_dial_info_details(&mut self) {
|
2022-09-03 17:57:25 +00:00
|
|
|
self.dial_info_details.clear();
|
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
|
|
|
|
|
|
|
pub fn has_valid_own_node_info(&self) -> bool {
|
|
|
|
self.network_class.unwrap_or(NetworkClass::Invalid) != NetworkClass::Invalid
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
let pi = PeerInfo::new(
|
2022-11-03 01:54:48 +00:00
|
|
|
NodeId::new(rti.unlocked_inner.node_id),
|
2022-10-09 18:59:01 +00:00
|
|
|
SignedNodeInfo::with_secret(
|
|
|
|
NodeInfo {
|
|
|
|
network_class: self.network_class.unwrap_or(NetworkClass::Invalid),
|
|
|
|
outbound_protocols: self.outbound_protocols,
|
|
|
|
address_types: self.address_types,
|
2022-10-30 23:29:31 +00:00
|
|
|
min_version: MIN_CRYPTO_VERSION,
|
|
|
|
max_version: MAX_CRYPTO_VERSION,
|
2022-10-09 18:59:01 +00:00
|
|
|
dial_info_detail_list: self.dial_info_details.clone(),
|
|
|
|
relay_peer_info: self
|
|
|
|
.relay_node
|
2022-10-31 03:23:12 +00:00
|
|
|
.as_ref()
|
2022-10-09 18:59:01 +00:00
|
|
|
.and_then(|rn| rn.make_peer_info(self.routing_domain).map(Box::new)),
|
|
|
|
},
|
2022-11-03 01:54:48 +00:00
|
|
|
NodeId::new(rti.unlocked_inner.node_id),
|
|
|
|
&rti.unlocked_inner.node_id_secret,
|
2022-10-09 18:59:01 +00:00
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
// 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,
|
|
|
|
node_a_id: &DHTKey,
|
|
|
|
node_a: &NodeInfo,
|
|
|
|
node_b_id: &DHTKey,
|
|
|
|
node_b: &NodeInfo,
|
|
|
|
dial_info_filter: DialInfoFilter,
|
2022-10-21 14:35:03 +00:00
|
|
|
sequencing: Sequencing,
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-13 02:53:40 +00:00
|
|
|
fn first_filtered_dial_info_detail(
|
|
|
|
from_node: &NodeInfo,
|
|
|
|
to_node: &NodeInfo,
|
|
|
|
dial_info_filter: &DialInfoFilter,
|
2022-10-22 01:27:07 +00:00
|
|
|
sequencing: Sequencing,
|
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()
|
|
|
|
.with_address_type_set(from_node.address_types)
|
|
|
|
.with_protocol_type_set(from_node.outbound_protocols),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Get first filtered dialinfo
|
2022-10-22 01:27:07 +00:00
|
|
|
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()),
|
|
|
|
),
|
|
|
|
),
|
2022-10-13 02:53:40 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
let direct_filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter);
|
2022-10-13 02:53:40 +00:00
|
|
|
|
|
|
|
// Get the best match dial info for node B if we have it
|
|
|
|
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,
|
|
|
|
node_a_id: &DHTKey,
|
|
|
|
node_a: &NodeInfo,
|
|
|
|
node_b_id: &DHTKey,
|
|
|
|
node_b: &NodeInfo,
|
|
|
|
dial_info_filter: DialInfoFilter,
|
2022-10-22 01:27:07 +00:00
|
|
|
sequencing: Sequencing,
|
2022-10-13 02:53:40 +00:00
|
|
|
) -> ContactMethod {
|
|
|
|
// Get the best match dial info for node B if we have it
|
|
|
|
if let Some(target_did) =
|
2022-10-22 01:27:07 +00:00
|
|
|
first_filtered_dial_info_detail(node_a, node_b, &dial_info_filter, sequencing)
|
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
|
2022-10-31 03:23:12 +00:00
|
|
|
if let Some(inbound_relay) = &node_b.relay_peer_info {
|
2022-10-13 02:53:40 +00:00
|
|
|
// Note that relay_peer_info could be node_a, in which case a connection already exists
|
|
|
|
// and we shouldn't have even gotten here
|
|
|
|
if inbound_relay.node_id.key == *node_a_id {
|
|
|
|
return ContactMethod::Existing;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can node A reach the inbound relay directly?
|
|
|
|
if first_filtered_dial_info_detail(
|
|
|
|
node_a,
|
|
|
|
&inbound_relay.signed_node_info.node_info,
|
|
|
|
&dial_info_filter,
|
2022-10-22 01:27:07 +00:00
|
|
|
sequencing,
|
2022-10-13 02:53:40 +00:00
|
|
|
)
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
// Can node A receive anything inbound ever?
|
|
|
|
if matches!(node_a.network_class, NetworkClass::InboundCapable) {
|
|
|
|
///////// Reverse connection
|
|
|
|
|
|
|
|
// Get the best match dial info for an reverse inbound connection from node B to node A
|
|
|
|
if let Some(reverse_did) = first_filtered_dial_info_detail(
|
|
|
|
node_b,
|
|
|
|
node_a,
|
|
|
|
&dial_info_filter,
|
2022-10-22 01:27:07 +00:00
|
|
|
sequencing,
|
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(
|
|
|
|
inbound_relay.node_id.key,
|
|
|
|
*node_b_id,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////// 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));
|
|
|
|
if let Some(target_udp_did) = first_filtered_dial_info_detail(
|
|
|
|
node_a,
|
|
|
|
node_b,
|
|
|
|
&udp_dial_info_filter,
|
2022-10-22 01:27:07 +00:00
|
|
|
sequencing,
|
2022-10-13 02:53:40 +00:00
|
|
|
) {
|
|
|
|
// Does node A have a direct udp dialinfo that node B can reach?
|
|
|
|
if let Some(reverse_udp_did) = first_filtered_dial_info_detail(
|
|
|
|
node_b,
|
|
|
|
node_a,
|
|
|
|
&udp_dial_info_filter,
|
2022-10-22 01:27:07 +00:00
|
|
|
sequencing,
|
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(
|
|
|
|
inbound_relay.node_id.key,
|
|
|
|
*node_b_id,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Otherwise we have to inbound relay
|
|
|
|
}
|
|
|
|
|
|
|
|
return ContactMethod::InboundRelay(inbound_relay.node_id.key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If the node B has no direct dial info, it needs to have an inbound relay
|
2022-10-31 03:23:12 +00:00
|
|
|
else if let Some(inbound_relay) = &node_b.relay_peer_info {
|
2022-10-13 02:53:40 +00:00
|
|
|
// Can we reach the full relay?
|
|
|
|
if first_filtered_dial_info_detail(
|
|
|
|
node_a,
|
|
|
|
&inbound_relay.signed_node_info.node_info,
|
|
|
|
&dial_info_filter,
|
2022-10-22 01:27:07 +00:00
|
|
|
sequencing,
|
2022-10-13 02:53:40 +00:00
|
|
|
)
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
return ContactMethod::InboundRelay(inbound_relay.node_id.key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If node A can't reach the node by other means, it may need to use its own relay
|
2022-10-31 03:23:12 +00:00
|
|
|
if let Some(outbound_relay) = &node_a.relay_peer_info {
|
2022-10-13 02:53:40 +00:00
|
|
|
return ContactMethod::OutboundRelay(outbound_relay.node_id.key);
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
_node_a_id: &DHTKey,
|
|
|
|
node_a: &NodeInfo,
|
|
|
|
_node_b_id: &DHTKey,
|
|
|
|
node_b: &NodeInfo,
|
|
|
|
dial_info_filter: DialInfoFilter,
|
2022-10-22 01:27:07 +00:00
|
|
|
sequencing: Sequencing,
|
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()
|
|
|
|
.with_address_type_set(node_a.address_types)
|
|
|
|
.with_protocol_type_set(node_a.outbound_protocols),
|
|
|
|
);
|
|
|
|
|
2022-10-22 01:27:07 +00:00
|
|
|
// 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()),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
};
|
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);
|
|
|
|
|
|
|
|
let opt_target_did = node_b.first_filtered_dial_info_detail(sort, filter);
|
|
|
|
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
|
|
|
}
|