mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-10-01 01:26:08 -04:00
dialinfoclass refactor, cleaning up network class detection
This commit is contained in:
parent
99dc4e16f9
commit
1156159748
@ -179,16 +179,24 @@ struct OperationInfoQ {
|
|||||||
nodeStatus @0 :NodeStatus; # node status update about the infoq sender
|
nodeStatus @0 :NodeStatus; # node status update about the infoq sender
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum NetworkClass {
|
enum NetworkClass {
|
||||||
server @0; # S = Device with public IP and no UDP firewall
|
inboundCapable @0; # I = Inbound capable without relay, may require signal
|
||||||
mapped @1; # M = Device with portmap behind any NAT
|
outboundOnly @1; # O = Outbound only, inbound relay required except with reverse connect signal
|
||||||
fullConeNAT @2; # F = Device without portmap behind full-cone NAT
|
webApp @2; # W = PWA, outbound relay is required in most cases
|
||||||
addressRestrictedNAT @3; # A = Device without portmap behind address-only restricted NAT
|
}
|
||||||
portRestrictedNAT @4; # P = Device without portmap behind address-and-port restricted NAT
|
|
||||||
outboundOnly @5; # O = Outbound only
|
enum DialInfoClass {
|
||||||
webApp @6; # W = PWA
|
direct @0; # D = Directly reachable with public IP and no firewall, with statically configured port
|
||||||
invalid @7; # I = Invalid
|
mapped @1; # M = Directly reachable with via portmap behind any NAT or firewalled with dynamically negotiated port
|
||||||
|
fullConeNAT @2; # F = Directly reachable device without portmap behind full-cone NAT
|
||||||
|
blocked @3; # B = Inbound blocked at firewall but may hole punch with public address
|
||||||
|
addressRestrictedNAT @4; # A = Device without portmap behind address-only restricted NAT
|
||||||
|
portRestrictedNAT @5; # P = Device without portmap behind address-and-port restricted NAT
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DialInfoDetail {
|
||||||
|
dialInfo @0; :DialInfo;
|
||||||
|
class @1; :DialInfoClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NodeStatus {
|
struct NodeStatus {
|
||||||
@ -209,7 +217,7 @@ struct ProtocolSet {
|
|||||||
struct NodeInfo {
|
struct NodeInfo {
|
||||||
networkClass @0 :NetworkClass; # network class of this node
|
networkClass @0 :NetworkClass; # network class of this node
|
||||||
outboundProtocols @1 :ProtocolSet; # protocols that can go outbound
|
outboundProtocols @1 :ProtocolSet; # protocols that can go outbound
|
||||||
dialInfoList @2 :List(DialInfo); # inbound dial info for this node
|
dialInfoDetailList @2 :List(DialInfoDetail); # inbound dial info details for this node
|
||||||
relayPeerInfo @3 :PeerInfo; # (optional) relay peer info for this node
|
relayPeerInfo @3 :PeerInfo; # (optional) relay peer info for this node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,34 @@ use crate::intf::*;
|
|||||||
use crate::routing_table::*;
|
use crate::routing_table::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct DiscoveryContext {
|
||||||
|
routing_table: RoutingTable,
|
||||||
|
external_ipv4: Option<Ipv4Addr>,
|
||||||
|
external_ipv6: Option<Ipv6Addr>,
|
||||||
|
network_class: Option<NetworkClass>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiscoveryContext {
|
||||||
|
pub fn new(routing_table: RoutingTable) -> Self {
|
||||||
|
Self {
|
||||||
|
routing_table,
|
||||||
|
external_ipv4: None,
|
||||||
|
external_ipv6: None,
|
||||||
|
network_class: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn upgrade_network_class(&mut self, network_class: NetworkClass) {
|
||||||
|
if let Some(old_nc) = self.network_class {
|
||||||
|
if network_class < old_nc {
|
||||||
|
self.network_class = Some(network_class);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.network_class = Some(network_class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Network {
|
impl Network {
|
||||||
// Ask for a public address check from a particular noderef
|
// Ask for a public address check from a particular noderef
|
||||||
async fn request_public_address(&self, node_ref: NodeRef) -> Option<SocketAddress> {
|
async fn request_public_address(&self, node_ref: NodeRef) -> Option<SocketAddress> {
|
||||||
@ -100,7 +128,12 @@ impl Network {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_udpv4_dialinfo(&self) -> Result<(), String> {
|
xxx split this routine up into helper routines that can be used by different protocols too.
|
||||||
|
|
||||||
|
pub async fn update_udpv4_dialinfo(
|
||||||
|
&self,
|
||||||
|
context: &mut DiscoveryContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
log_net!("looking for udpv4 public dial info");
|
log_net!("looking for udpv4 public dial info");
|
||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
|
|
||||||
@ -130,24 +163,41 @@ impl Network {
|
|||||||
// If our local interface list contains external1 then there is no NAT in place
|
// If our local interface list contains external1 then there is no NAT in place
|
||||||
if intf_addrs.contains(&external1) {
|
if intf_addrs.contains(&external1) {
|
||||||
// No NAT
|
// No NAT
|
||||||
// Do a validate_dial_info on the external address from a routed node
|
// Do a validate_dial_info on the external address from a redirected node
|
||||||
if self
|
if self
|
||||||
.validate_dial_info(node_b.clone(), external1_dial_info.clone(), true, false)
|
.validate_dial_info(node_b.clone(), external1_dial_info.clone(), true, false)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
// Add public dial info with Server network class
|
// Add public dial info with Direct dialinfo class
|
||||||
routing_table.register_public_dial_info(
|
routing_table.register_dial_info(
|
||||||
|
RoutingDomain::PublicInternet,
|
||||||
external1_dial_info,
|
external1_dial_info,
|
||||||
DialInfoOrigin::Discovered,
|
DialInfoClass::Direct,
|
||||||
Some(NetworkClass::Server),
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
// Attempt a UDP port mapping via all available and enabled mechanisms
|
||||||
|
else if let Some(external_mapped) = self
|
||||||
|
.try_port_mapping(&intf_addrs, ProtocolType::UDP, AddressType::IPV4)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
// Got a port mapping, let's use it
|
||||||
|
let external_mapped_dial_info = DialInfo::udp(external_mapped);
|
||||||
|
routing_table.register_dial_info(
|
||||||
|
RoutingDomain::PublicInternet,
|
||||||
|
external_mapped_dial_info,
|
||||||
|
DialInfoClass::Mapped,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Add public dial info with Blocked dialinfo class
|
||||||
|
routing_table.register_dial_info(
|
||||||
|
RoutingDomain::PublicInternet,
|
||||||
|
external1_dial_info,
|
||||||
|
DialInfoClass::Blocked,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
context.upgrade_network_class(NetworkClass::InboundCapable);
|
||||||
// No more retries
|
// No more retries
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
// UDP firewall?
|
|
||||||
log_net!("UDP static public dial info not reachable. UDP firewall may be blocking inbound to {:?} for {:?}",external1_dial_info, node_b);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// There is -some NAT-
|
// There is -some NAT-
|
||||||
// Attempt a UDP port mapping via all available and enabled mechanisms
|
// Attempt a UDP port mapping via all available and enabled mechanisms
|
||||||
@ -157,11 +207,12 @@ impl Network {
|
|||||||
{
|
{
|
||||||
// Got a port mapping, let's use it
|
// Got a port mapping, let's use it
|
||||||
let external_mapped_dial_info = DialInfo::udp(external_mapped);
|
let external_mapped_dial_info = DialInfo::udp(external_mapped);
|
||||||
routing_table.register_public_dial_info(
|
routing_table.register_dial_info(
|
||||||
|
RoutingDomain::PublicInternet,
|
||||||
external_mapped_dial_info,
|
external_mapped_dial_info,
|
||||||
DialInfoOrigin::Mapped,
|
DialInfoClass::Mapped,
|
||||||
Some(NetworkClass::Mapped),
|
|
||||||
);
|
);
|
||||||
|
context.upgrade_network_class(NetworkClass::InboundCapable);
|
||||||
|
|
||||||
// No more retries
|
// No more retries
|
||||||
break;
|
break;
|
||||||
@ -180,11 +231,12 @@ impl Network {
|
|||||||
{
|
{
|
||||||
// Yes, another machine can use the dial info directly, so Full Cone
|
// Yes, another machine can use the dial info directly, so Full Cone
|
||||||
// Add public dial info with full cone NAT network class
|
// Add public dial info with full cone NAT network class
|
||||||
routing_table.register_public_dial_info(
|
routing_table.register_dial_info(
|
||||||
|
RoutingDomain::PublicInternet,
|
||||||
external1_dial_info,
|
external1_dial_info,
|
||||||
DialInfoOrigin::Discovered,
|
DialInfoClass::FullConeNAT,
|
||||||
Some(NetworkClass::FullConeNAT),
|
|
||||||
);
|
);
|
||||||
|
context.upgrade_network_class(NetworkClass::InboundCapable);
|
||||||
|
|
||||||
// No more retries
|
// No more retries
|
||||||
break;
|
break;
|
||||||
@ -209,7 +261,7 @@ impl Network {
|
|||||||
// If we have two different external addresses, then this is a symmetric NAT
|
// If we have two different external addresses, then this is a symmetric NAT
|
||||||
if external2 != external1 {
|
if external2 != external1 {
|
||||||
// Symmetric NAT is outbound only, no public dial info will work
|
// Symmetric NAT is outbound only, no public dial info will work
|
||||||
self.inner.lock().network_class = Some(NetworkClass::OutboundOnly);
|
context.upgrade_network_class(NetworkClass::OutboundOnly);
|
||||||
|
|
||||||
// No more retries
|
// No more retries
|
||||||
break;
|
break;
|
||||||
@ -230,19 +282,20 @@ impl Network {
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
// Got a reply from a non-default port, which means we're only address restricted
|
// Got a reply from a non-default port, which means we're only address restricted
|
||||||
routing_table.register_public_dial_info(
|
routing_table.register_dial_info(
|
||||||
|
RoutingDomain::PublicInternet,
|
||||||
external1_dial_info,
|
external1_dial_info,
|
||||||
DialInfoOrigin::Discovered,
|
DialInfoClass::AddressRestrictedNAT,
|
||||||
Some(NetworkClass::AddressRestrictedNAT),
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Didn't get a reply from a non-default port, which means we are also port restricted
|
// Didn't get a reply from a non-default port, which means we are also port restricted
|
||||||
routing_table.register_public_dial_info(
|
routing_table.register_dial_info(
|
||||||
|
RoutingDomain::PublicInternet,
|
||||||
external1_dial_info,
|
external1_dial_info,
|
||||||
DialInfoOrigin::Discovered,
|
DialInfoClass::PortRestrictedNAT,
|
||||||
Some(NetworkClass::PortRestrictedNAT),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
context.upgrade_network_class(NetworkClass::InboundCapable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,18 +308,49 @@ impl Network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// xxx should verify hole punch capable somehow and switch to outbound-only if hole punch can't work
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_tcpv4_dialinfo(&self) -> Result<(), String> {
|
pub async fn update_tcpv4_dialinfo(
|
||||||
|
&self,
|
||||||
|
context: &mut DiscoveryContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
log_net!("looking for tcpv4 public dial info");
|
log_net!("looking for tcpv4 public dial info");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_wsv4_dialinfo(&self, context: &mut DiscoveryContext) -> Result<(), String> {
|
||||||
|
log_net!("looking for wsv4 public dial info");
|
||||||
// xxx
|
// xxx
|
||||||
//Err("unimplemented".to_owned())
|
//Err("unimplemented".to_owned())
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_wsv4_dialinfo(&self) -> Result<(), String> {
|
pub async fn update_udpv6_dialinfo(
|
||||||
log_net!("looking for wsv4 public dial info");
|
&self,
|
||||||
|
context: &mut DiscoveryContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
log_net!("looking for udpv6 public dial info");
|
||||||
|
// xxx
|
||||||
|
//Err("unimplemented".to_owned())
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_tcpv6_dialinfo(
|
||||||
|
&self,
|
||||||
|
context: &mut DiscoveryContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
log_net!("looking for tcpv6 public dial info");
|
||||||
|
// xxx
|
||||||
|
//Err("unimplemented".to_owned())
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_wsv6_dialinfo(&self, context: &mut DiscoveryContext) -> Result<(), String> {
|
||||||
|
log_net!("looking for wsv6 public dial info");
|
||||||
// xxx
|
// xxx
|
||||||
//Err("unimplemented".to_owned())
|
//Err("unimplemented".to_owned())
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -282,18 +366,25 @@ impl Network {
|
|||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut context = DiscoveryContext::default();
|
||||||
|
|
||||||
if protocol_config.inbound.contains(ProtocolType::UDP) {
|
if protocol_config.inbound.contains(ProtocolType::UDP) {
|
||||||
self.update_udpv4_dialinfo().await?;
|
self.update_udpv4_dialinfo(&mut context).await?;
|
||||||
|
self.update_udpv6_dialinfo(&mut context).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if protocol_config.inbound.contains(ProtocolType::TCP) {
|
if protocol_config.inbound.contains(ProtocolType::TCP) {
|
||||||
self.update_tcpv4_dialinfo().await?;
|
self.update_tcpv4_dialinfo(&mut context).await?;
|
||||||
|
self.update_tcpv6_dialinfo(&mut context).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if protocol_config.inbound.contains(ProtocolType::WS) {
|
if protocol_config.inbound.contains(ProtocolType::WS) {
|
||||||
self.update_wsv4_dialinfo().await?;
|
self.update_wsv4_dialinfo(&mut context).await?;
|
||||||
|
self.update_wsv6_dialinfo(&mut context).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.inner.lock().network_class = context.network_class;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,9 @@ impl RoutingTable {
|
|||||||
// does it have matching public dial info?
|
// does it have matching public dial info?
|
||||||
entry
|
entry
|
||||||
.node_info()
|
.node_info()
|
||||||
.first_filtered_dial_info(|di| di.matches_filter(&dial_info_filter1))
|
.first_filtered_dial_info_detail(|did| {
|
||||||
|
did.matches_filter(&dial_info_filter1)
|
||||||
|
})
|
||||||
.is_some()
|
.is_some()
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
@ -55,11 +57,7 @@ impl RoutingTable {
|
|||||||
node_info: NodeInfo {
|
node_info: NodeInfo {
|
||||||
network_class: netman.get_network_class().unwrap_or(NetworkClass::Invalid),
|
network_class: netman.get_network_class().unwrap_or(NetworkClass::Invalid),
|
||||||
outbound_protocols: netman.get_protocol_config().unwrap_or_default().outbound,
|
outbound_protocols: netman.get_protocol_config().unwrap_or_default().outbound,
|
||||||
dial_info_list: self
|
dial_info_detail_list: self.dial_info_details(RoutingDomain::PublicInternet),
|
||||||
.dial_info_details(RoutingDomain::PublicInternet)
|
|
||||||
.iter()
|
|
||||||
.map(|did| did.dial_info.clone())
|
|
||||||
.collect(),
|
|
||||||
relay_peer_info: relay_node.map(|rn| Box::new(rn.peer_info())),
|
relay_peer_info: relay_node.map(|rn| Box::new(rn.peer_info())),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,6 @@ pub use stats_accounting::*;
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
|
|
||||||
pub enum DialInfoOrigin {
|
|
||||||
Static,
|
|
||||||
Discovered,
|
|
||||||
Mapped,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
|
||||||
pub enum RoutingDomain {
|
pub enum RoutingDomain {
|
||||||
PublicInternet,
|
PublicInternet,
|
||||||
@ -40,19 +33,6 @@ pub struct RoutingDomainDetail {
|
|||||||
dial_info_details: Vec<DialInfoDetail>,
|
dial_info_details: Vec<DialInfoDetail>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)]
|
|
||||||
pub struct DialInfoDetail {
|
|
||||||
pub dial_info: DialInfo,
|
|
||||||
pub origin: DialInfoOrigin,
|
|
||||||
pub timestamp: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MatchesDialInfoFilter for DialInfoDetail {
|
|
||||||
fn matches_filter(&self, filter: &DialInfoFilter) -> bool {
|
|
||||||
self.dial_info.matches_filter(filter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RoutingTableInner {
|
struct RoutingTableInner {
|
||||||
network_manager: NetworkManager,
|
network_manager: NetworkManager,
|
||||||
node_id: DHTKey,
|
node_id: DHTKey,
|
||||||
@ -223,28 +203,40 @@ impl RoutingTable {
|
|||||||
|
|
||||||
pub fn all_filtered_dial_info_details(
|
pub fn all_filtered_dial_info_details(
|
||||||
&self,
|
&self,
|
||||||
domain: RoutingDomain,
|
domain: Option<RoutingDomain>,
|
||||||
filter: &DialInfoFilter,
|
filter: &DialInfoFilter,
|
||||||
) -> Vec<DialInfoDetail> {
|
) -> Vec<DialInfoDetail> {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
Self::with_routing_domain(&*inner, domain, |rd| {
|
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
|
|
||||||
|
if domain == None || domain == Some(RoutingDomain::Local) {
|
||||||
|
Self::with_routing_domain(&*inner, RoutingDomain::Local, |rd| {
|
||||||
for did in rd.dial_info_details {
|
for did in rd.dial_info_details {
|
||||||
if did.matches_filter(filter) {
|
if did.matches_filter(filter) {
|
||||||
ret.push(did.clone());
|
ret.push(did.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if domain == None || domain == Some(RoutingDomain::PublicInternet) {
|
||||||
|
Self::with_routing_domain(&*inner, RoutingDomain::PublicInternet, |rd| {
|
||||||
|
for did in rd.dial_info_details {
|
||||||
|
if did.matches_filter(filter) {
|
||||||
|
ret.push(did.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ret.remove_duplicates();
|
||||||
ret
|
ret
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_dial_info(
|
pub fn register_dial_info(
|
||||||
&self,
|
&self,
|
||||||
domain: RoutingDomain,
|
domain: RoutingDomain,
|
||||||
dial_info: DialInfo,
|
dial_info: DialInfo,
|
||||||
origin: DialInfoOrigin,
|
class: DialInfoClass,
|
||||||
) {
|
) {
|
||||||
let timestamp = get_timestamp();
|
|
||||||
let enable_local_peer_scope = {
|
let enable_local_peer_scope = {
|
||||||
let config = self.network_manager().config();
|
let config = self.network_manager().config();
|
||||||
let c = config.get();
|
let c = config.get();
|
||||||
@ -267,8 +259,7 @@ impl RoutingTable {
|
|||||||
Self::with_routing_domain_mut(&mut *inner, domain, |rd| {
|
Self::with_routing_domain_mut(&mut *inner, domain, |rd| {
|
||||||
rd.dial_info_details.push(DialInfoDetail {
|
rd.dial_info_details.push(DialInfoDetail {
|
||||||
dial_info: dial_info.clone(),
|
dial_info: dial_info.clone(),
|
||||||
origin,
|
class,
|
||||||
timestamp,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -285,7 +276,7 @@ impl RoutingTable {
|
|||||||
}
|
}
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
debug!(" Origin: {:?}", origin);
|
debug!(" Class: {:?}", class);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_dial_info_details(&self, domain: RoutingDomain) {
|
pub fn clear_dial_info_details(&self, domain: RoutingDomain) {
|
||||||
@ -611,7 +602,7 @@ impl RoutingTable {
|
|||||||
log_rtab!("--- bootstrap_task");
|
log_rtab!("--- bootstrap_task");
|
||||||
|
|
||||||
// Map all bootstrap entries to a single key with multiple dialinfo
|
// Map all bootstrap entries to a single key with multiple dialinfo
|
||||||
let mut bsmap: BTreeMap<DHTKey, Vec<DialInfo>> = BTreeMap::new();
|
let mut bsmap: BTreeMap<DHTKey, Vec<DialInfoDetail>> = BTreeMap::new();
|
||||||
for b in bootstrap {
|
for b in bootstrap {
|
||||||
let ndis = NodeDialInfo::from_str(b.as_str())
|
let ndis = NodeDialInfo::from_str(b.as_str())
|
||||||
.map_err(map_to_string)
|
.map_err(map_to_string)
|
||||||
@ -620,7 +611,10 @@ impl RoutingTable {
|
|||||||
bsmap
|
bsmap
|
||||||
.entry(node_id)
|
.entry(node_id)
|
||||||
.or_insert_with(Vec::new)
|
.or_insert_with(Vec::new)
|
||||||
.push(ndis.dial_info);
|
.push(DialInfoDetail {
|
||||||
|
dial_info: ndis.dial_info,
|
||||||
|
class: DialInfoClass::Direct,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
log_rtab!(" bootstrap list: {:?}", bsmap);
|
log_rtab!(" bootstrap list: {:?}", bsmap);
|
||||||
|
|
||||||
@ -634,7 +628,7 @@ impl RoutingTable {
|
|||||||
NodeInfo {
|
NodeInfo {
|
||||||
network_class: NetworkClass::Server, // Bootstraps are always full servers
|
network_class: NetworkClass::Server, // Bootstraps are always full servers
|
||||||
outbound_protocols: ProtocolSet::empty(), // Bootstraps do not participate in relaying and will not make outbound requests
|
outbound_protocols: ProtocolSet::empty(), // Bootstraps do not participate in relaying and will not make outbound requests
|
||||||
dial_info_list: v, // Dial info is as specified in the bootstrap list
|
dial_info_detail_list: v, // Dial info is as specified in the bootstrap list
|
||||||
relay_peer_info: None, // Bootstraps never require a relay themselves
|
relay_peer_info: None, // Bootstraps never require a relay themselves
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -90,30 +90,42 @@ impl NodeRef {
|
|||||||
nr
|
nr
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn first_filtered_dial_info(&self) -> Option<DialInfo> {
|
pub fn first_filtered_dial_info_detail(
|
||||||
|
&self,
|
||||||
|
routing_domain: Option<RoutingDomain>,
|
||||||
|
) -> Option<DialInfoDetail> {
|
||||||
self.operate(|e| {
|
self.operate(|e| {
|
||||||
if matches!(
|
if (routing_domain == None || routing_domain == Some(RoutingDomain::LocalNetwork))
|
||||||
|
&& matches!(
|
||||||
self.filter.map(|f| f.peer_scope).unwrap_or(PeerScope::All),
|
self.filter.map(|f| f.peer_scope).unwrap_or(PeerScope::All),
|
||||||
PeerScope::All | PeerScope::Local
|
PeerScope::All | PeerScope::Local
|
||||||
) {
|
)
|
||||||
e.local_node_info().first_filtered_dial_info(|di| {
|
{
|
||||||
|
e.local_node_info()
|
||||||
|
.first_filtered_dial_info(|di| {
|
||||||
if let Some(filter) = self.filter {
|
if let Some(filter) = self.filter {
|
||||||
di.matches_filter(&filter)
|
di.matches_filter(&filter)
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.map(|di| DialInfoDetail {
|
||||||
|
class: DialInfoClass::Direct,
|
||||||
|
dial_info: di,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if matches!(
|
if (routing_domain == None || routing_domain == Some(RoutingDomain::PublicInternet))
|
||||||
|
&& matches!(
|
||||||
self.filter.map(|f| f.peer_scope).unwrap_or(PeerScope::All),
|
self.filter.map(|f| f.peer_scope).unwrap_or(PeerScope::All),
|
||||||
PeerScope::All | PeerScope::Global
|
PeerScope::All | PeerScope::Global
|
||||||
) {
|
)
|
||||||
e.node_info().first_filtered_dial_info(|di| {
|
{
|
||||||
|
e.node_info().first_filtered_dial_info_detail(|did| {
|
||||||
if let Some(filter) = self.filter {
|
if let Some(filter) = self.filter {
|
||||||
di.matches_filter(&filter)
|
did.matches_filter(&filter)
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -125,34 +137,47 @@ impl NodeRef {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_filtered_dial_info<F>(&self) -> Vec<DialInfo> {
|
pub fn all_filtered_dial_info_details<F>(
|
||||||
|
&self,
|
||||||
|
routing_domain: Option<RoutingDomain>,
|
||||||
|
) -> Vec<DialInfoDetail> {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
self.operate(|e| {
|
self.operate(|e| {
|
||||||
if matches!(
|
if (routing_domain == None || routing_domain == Some(RoutingDomain::LocalNetwork))
|
||||||
|
&& matches!(
|
||||||
self.filter.map(|f| f.peer_scope).unwrap_or(PeerScope::All),
|
self.filter.map(|f| f.peer_scope).unwrap_or(PeerScope::All),
|
||||||
PeerScope::All | PeerScope::Global
|
PeerScope::All | PeerScope::Local
|
||||||
) {
|
)
|
||||||
out.append(&mut e.node_info().all_filtered_dial_info(|di| {
|
{
|
||||||
|
for di in e.local_node_info().all_filtered_dial_info(|di| {
|
||||||
if let Some(filter) = self.filter {
|
if let Some(filter) = self.filter {
|
||||||
di.matches_filter(&filter)
|
di.matches_filter(&filter)
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}))
|
}) {
|
||||||
|
out.push(DialInfoDetail {
|
||||||
|
class: DialInfoClass::Direct,
|
||||||
|
dial_info: di,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if matches!(
|
}
|
||||||
|
if (routing_domain == None || routing_domain == Some(RoutingDomain::PublicInternet))
|
||||||
|
&& matches!(
|
||||||
self.filter.map(|f| f.peer_scope).unwrap_or(PeerScope::All),
|
self.filter.map(|f| f.peer_scope).unwrap_or(PeerScope::All),
|
||||||
PeerScope::All | PeerScope::Local
|
PeerScope::All | PeerScope::Global
|
||||||
) {
|
)
|
||||||
out.append(&mut e.local_node_info().all_filtered_dial_info(|di| {
|
{
|
||||||
|
out.append(&mut e.node_info().all_filtered_dial_info_details(|did| {
|
||||||
if let Some(filter) = self.filter {
|
if let Some(filter) = self.filter {
|
||||||
di.matches_filter(&filter)
|
did.matches_filter(&filter)
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
out.remove_duplicates();
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
veilid-core/src/rpc_processor/coders/dial_info_class.rs
Normal file
23
veilid-core/src/rpc_processor/coders/dial_info_class.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub fn encode_dial_info_class(dial_info_class: DialInfoClass) -> veilid_capnp::DialInfoClass {
|
||||||
|
match dial_info_class {
|
||||||
|
DialInfoClass::Direct => veilid_capnp::DialInfoClass::Direct,
|
||||||
|
DialInfoClass::Mapped => veilid_capnp::DialInfoClass::Mapped,
|
||||||
|
DialInfoClass::FullConeNAT => veilid_capnp::DialInfoClass::FullConeNAT,
|
||||||
|
DialInfoClass::Blocked => veilid_capnp::DialInfoClass::Blocked,
|
||||||
|
DialInfoClass::AddressRestrictedNAT => veilid_capnp::DialInfoClass::AddressRestrictedNAT,
|
||||||
|
DialInfoClass::PortRestrictedNAT => veilid_capnp::DialInfoClass::PortRestrictedNAT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_dial_info_class(dial_info_class: veilid_capnp::DialInfoClass) -> DialInfoClass {
|
||||||
|
match dial_info_class {
|
||||||
|
veilid_capnp::DialInfoClass::Direct => DialInfoClass::Direct,
|
||||||
|
veilid_capnp::DialInfoClass::Mapped => DialInfoClass::Mapped,
|
||||||
|
veilid_capnp::DialInfoClass::FullConeNAT => DialInfoClass::FullConeNAT,
|
||||||
|
veilid_capnp::DialInfoClass::Blocked => DialInfoClass::Blocked,
|
||||||
|
veilid_capnp::DialInfoClass::AddressRestrictedNAT => DialInfoClass::AddressRestrictedNAT,
|
||||||
|
veilid_capnp::DialInfoClass::PortRestrictedNAT => DialInfoClass::PortRestrictedNAT,
|
||||||
|
}
|
||||||
|
}
|
33
veilid-core/src/rpc_processor/coders/dial_info_detail.rs
Normal file
33
veilid-core/src/rpc_processor/coders/dial_info_detail.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use crate::*;
|
||||||
|
use rpc_processor::*;
|
||||||
|
|
||||||
|
pub fn encode_dial_info_detail(
|
||||||
|
dial_info_detail: &DialInfoDetail,
|
||||||
|
builder: &mut veilid_capnp::dial_info_detail::Builder,
|
||||||
|
) -> Result<(), RPCError> {
|
||||||
|
let mut di_builder = builder.reborrow().init_dial_info();
|
||||||
|
encode_dial_info(&node_info.dial_info, &mut di_builder)?;
|
||||||
|
|
||||||
|
builder.set_class(encode_dial_info_class(dial_info_detail.class));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_dial_info_detail(
|
||||||
|
reader: &veilid_capnp::dial_info_detail::Reader,
|
||||||
|
) -> Result<DialInfoDetail, RPCError> {
|
||||||
|
let dial_info = decode_dial_info(
|
||||||
|
&reader
|
||||||
|
.reborrow()
|
||||||
|
.get_dial_info()
|
||||||
|
.map_err(map_error_capnp_error!())?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let dial_info_class = decode_dial_info_class(
|
||||||
|
reader
|
||||||
|
.reborrow()
|
||||||
|
.get_class()
|
||||||
|
.map_err(map_error_capnp_notinschema!())?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(DialInfoDetail { dial_info, class })
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
mod address;
|
mod address;
|
||||||
mod dial_info;
|
mod dial_info;
|
||||||
|
mod dial_info_class;
|
||||||
|
mod dial_info_detail;
|
||||||
mod network_class;
|
mod network_class;
|
||||||
mod node_dial_info;
|
mod node_dial_info;
|
||||||
mod node_info;
|
mod node_info;
|
||||||
@ -15,6 +17,8 @@ mod socket_address;
|
|||||||
|
|
||||||
pub use address::*;
|
pub use address::*;
|
||||||
pub use dial_info::*;
|
pub use dial_info::*;
|
||||||
|
pub use dial_info_class::*;
|
||||||
|
pub use dial_info_detail::*;
|
||||||
pub use network_class::*;
|
pub use network_class::*;
|
||||||
pub use node_dial_info::*;
|
pub use node_dial_info::*;
|
||||||
pub use node_info::*;
|
pub use node_info::*;
|
||||||
|
@ -10,17 +10,19 @@ pub fn encode_node_info(
|
|||||||
let mut ps_builder = builder.reborrow().init_outbound_protocols();
|
let mut ps_builder = builder.reborrow().init_outbound_protocols();
|
||||||
encode_protocol_set(&node_info.outbound_protocols, &mut ps_builder)?;
|
encode_protocol_set(&node_info.outbound_protocols, &mut ps_builder)?;
|
||||||
|
|
||||||
let mut dil_builder = builder.reborrow().init_dial_info_list(
|
let mut didl_builder = builder.reborrow().init_dial_info_detail_list(
|
||||||
node_info
|
node_info
|
||||||
.dial_info_list
|
.dial_info_detail_list
|
||||||
.len()
|
.len()
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(map_error_protocol!("too many dial infos in node info"))?,
|
.map_err(map_error_protocol!(
|
||||||
|
"too many dial info details in node info"
|
||||||
|
))?,
|
||||||
);
|
);
|
||||||
|
|
||||||
for idx in 0..node_info.dial_info_list.len() {
|
for idx in 0..node_info.dial_info_detail_list.len() {
|
||||||
let mut di_builder = dil_builder.reborrow().get(idx as u32);
|
let mut did_builder = didl_builder.reborrow().get(idx as u32);
|
||||||
encode_dial_info(&node_info.dial_info_list[idx], &mut di_builder)?;
|
encode_dial_info_detail(&node_info.dial_info_detail_list[idx], &mut did_builder)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(rpi) = &node_info.relay_peer_info {
|
if let Some(rpi) = &node_info.relay_peer_info {
|
||||||
@ -49,18 +51,18 @@ pub fn decode_node_info(
|
|||||||
.map_err(map_error_capnp_error!())?,
|
.map_err(map_error_capnp_error!())?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let dil_reader = reader
|
let didl_reader = reader
|
||||||
.reborrow()
|
.reborrow()
|
||||||
.get_dial_info_list()
|
.get_dial_info_detail_list()
|
||||||
.map_err(map_error_capnp_error!())?;
|
.map_err(map_error_capnp_error!())?;
|
||||||
let mut dial_info_list = Vec::<DialInfo>::with_capacity(
|
let mut dial_info_detail_list = Vec::<DialInfo>::with_capacity(
|
||||||
dil_reader
|
didl_reader
|
||||||
.len()
|
.len()
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(map_error_protocol!("too many dial infos"))?,
|
.map_err(map_error_protocol!("too many dial info details"))?,
|
||||||
);
|
);
|
||||||
for di in dil_reader.iter() {
|
for di in dil_reader.iter() {
|
||||||
dial_info_list.push(decode_dial_info(&di)?)
|
dial_info_detail_list.push(decode_dial_info_detail(&di)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
let relay_peer_info = if allow_relay_peer_info {
|
let relay_peer_info = if allow_relay_peer_info {
|
||||||
@ -82,7 +84,7 @@ pub fn decode_node_info(
|
|||||||
Ok(NodeInfo {
|
Ok(NodeInfo {
|
||||||
network_class,
|
network_class,
|
||||||
outbound_protocols,
|
outbound_protocols,
|
||||||
dial_info_list,
|
dial_info_detail_list,
|
||||||
relay_peer_info,
|
relay_peer_info,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1349,12 +1349,16 @@ impl RPCProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Gets a 'RespondTo::Sender' that contains either our dial info,
|
// Gets a 'RespondTo::Sender' that contains either our dial info,
|
||||||
// or None if the peer has seen our dial info before
|
// or None if the peer has seen our dial info before or our node info is not yet valid
|
||||||
pub fn get_respond_to_sender(&self, peer: NodeRef) -> RespondTo {
|
// because of an unknown network class
|
||||||
if peer.has_seen_our_node_info() {
|
pub fn make_respond_to_sender(&self, peer: NodeRef) -> RespondTo {
|
||||||
|
let our_node_info = self.routing_table().get_own_peer_info().node_info;
|
||||||
|
if peer.has_seen_our_node_info()
|
||||||
|
|| matches!(our_node_info.network_class, NetworkClass::Invalid)
|
||||||
|
{
|
||||||
RespondTo::Sender(None)
|
RespondTo::Sender(None)
|
||||||
} else {
|
} else {
|
||||||
RespondTo::Sender(Some(self.routing_table().get_own_peer_info().node_info))
|
RespondTo::Sender(Some(our_node_info))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1366,7 +1370,7 @@ impl RPCProcessor {
|
|||||||
let mut question = info_q_msg.init_root::<veilid_capnp::operation::Builder>();
|
let mut question = info_q_msg.init_root::<veilid_capnp::operation::Builder>();
|
||||||
question.set_op_id(self.get_next_op_id());
|
question.set_op_id(self.get_next_op_id());
|
||||||
let mut respond_to = question.reborrow().init_respond_to();
|
let mut respond_to = question.reborrow().init_respond_to();
|
||||||
self.get_respond_to_sender(peer.clone())
|
self.make_respond_to_sender(peer.clone())
|
||||||
.encode(&mut respond_to)?;
|
.encode(&mut respond_to)?;
|
||||||
let detail = question.reborrow().init_detail();
|
let detail = question.reborrow().init_detail();
|
||||||
let mut iqb = detail.init_info_q();
|
let mut iqb = detail.init_info_q();
|
||||||
|
@ -236,78 +236,56 @@ pub struct SenderInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
||||||
pub enum NetworkClass {
|
pub enum DialInfoClass {
|
||||||
Server = 0, // S = Device with public IP and no UDP firewall
|
Direct = 0, // D = Directly reachable with public IP and no firewall, with statically configured port
|
||||||
Mapped = 1, // M = Device with portmap behind any NAT
|
Mapped = 1, // M = Directly reachable with via portmap behind any NAT or firewalled with dynamically negotiated port
|
||||||
FullConeNAT = 2, // F = Device without portmap behind full-cone NAT
|
FullConeNAT = 2, // F = Directly reachable device without portmap behind full-cone NAT
|
||||||
AddressRestrictedNAT = 3, // A = Device without portmap behind address-only restricted NAT
|
Blocked = 3, // B = Inbound blocked at firewall but may hole punch with public address
|
||||||
PortRestrictedNAT = 4, // P = Device without portmap behind address-and-port restricted NAT
|
AddressRestrictedNAT = 4, // A = Device without portmap behind address-only restricted NAT
|
||||||
OutboundOnly = 5, // O = Outbound only
|
PortRestrictedNAT = 5, // P = Device without portmap behind address-and-port restricted NAT
|
||||||
WebApp = 6, // W = PWA
|
|
||||||
Invalid = 7, // I = Invalid network class, unreachable or can not send packets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkClass {
|
impl DialInfoClass {
|
||||||
// Can the node receive inbound requests without a relay?
|
|
||||||
pub fn inbound_capable(&self) -> bool {
|
|
||||||
matches!(
|
|
||||||
self,
|
|
||||||
Self::Server
|
|
||||||
| Self::Mapped
|
|
||||||
| Self::FullConeNAT
|
|
||||||
| Self::AddressRestrictedNAT
|
|
||||||
| Self::PortRestrictedNAT
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should an outbound relay be kept available?
|
|
||||||
pub fn outbound_wants_relay(&self) -> bool {
|
|
||||||
matches!(self, Self::WebApp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is a signal required to do an inbound hole-punch?
|
// Is a signal required to do an inbound hole-punch?
|
||||||
pub fn inbound_requires_signal(&self) -> bool {
|
pub fn requires_signal(&self) -> bool {
|
||||||
matches!(self, Self::AddressRestrictedNAT | Self::PortRestrictedNAT)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is some relay required either for signal or inbound relay or outbound relay?
|
|
||||||
pub fn needs_relay(&self) -> bool {
|
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
Self::AddressRestrictedNAT
|
Self::Blocked | Self::AddressRestrictedNAT | Self::PortRestrictedNAT
|
||||||
| Self::PortRestrictedNAT
|
|
||||||
| Self::OutboundOnly
|
|
||||||
| Self::WebApp
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must keepalive be used to preserve the public dialinfo in use?
|
// Does a relay node need to be allocated for this dial info?
|
||||||
// Keepalive can be to either a
|
// For full cone NAT, the relay itself may not be used but the keepalive sent to it
|
||||||
pub fn dialinfo_requires_keepalive(&self) -> bool {
|
// is required to keep the NAT mapping valid in the router state table
|
||||||
|
pub fn requires_relay(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
Self::FullConeNAT
|
Self::FullConeNAT
|
||||||
|
| Self::Blocked
|
||||||
| Self::AddressRestrictedNAT
|
| Self::AddressRestrictedNAT
|
||||||
| Self::PortRestrictedNAT
|
| Self::PortRestrictedNAT
|
||||||
| Self::OutboundOnly
|
|
||||||
| Self::WebApp
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Can this node assist with signalling? Yes but only if it doesn't require signalling, itself.
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
|
||||||
pub fn can_signal(&self) -> bool {
|
pub struct DialInfoDetail {
|
||||||
self.inbound_capable() && !self.inbound_requires_signal()
|
pub dial_info: DialInfo,
|
||||||
}
|
pub class: DialInfoClass,
|
||||||
|
}
|
||||||
|
|
||||||
// Can this node relay be an inbound relay?
|
impl MatchesDialInfoFilter for DialInfoDetail {
|
||||||
pub fn can_inbound_relay(&self) -> bool {
|
fn matches_filter(&self, filter: &DialInfoFilter) -> bool {
|
||||||
matches!(self, Self::Server | Self::Mapped | Self::FullConeNAT)
|
self.dial_info.matches_filter(filter)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Is this node capable of validating dial info
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
||||||
pub fn can_validate_dial_info(&self) -> bool {
|
pub enum NetworkClass {
|
||||||
matches!(self, Self::Server | Self::Mapped | Self::FullConeNAT)
|
InboundCapable = 0, // I = Inbound capable without relay, may require signal
|
||||||
}
|
OutboundOnly = 1, // O = Outbound only, inbound relay required except with reverse connect signal
|
||||||
|
WebApp = 2, // W = PWA, outbound relay is required in most cases
|
||||||
|
Invalid = 3, // X = Invalid network class, we don't know how to reach this node
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NetworkClass {
|
impl Default for NetworkClass {
|
||||||
@ -316,6 +294,13 @@ impl Default for NetworkClass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NetworkClass {
|
||||||
|
// Should an outbound relay be kept available?
|
||||||
|
pub fn outbound_wants_relay(&self) -> bool {
|
||||||
|
matches!(self, Self::WebApp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct NodeStatus {
|
pub struct NodeStatus {
|
||||||
pub will_route: bool,
|
pub will_route: bool,
|
||||||
@ -329,39 +314,39 @@ pub struct NodeStatus {
|
|||||||
pub struct NodeInfo {
|
pub struct NodeInfo {
|
||||||
pub network_class: NetworkClass,
|
pub network_class: NetworkClass,
|
||||||
pub outbound_protocols: ProtocolSet,
|
pub outbound_protocols: ProtocolSet,
|
||||||
pub dial_info_list: Vec<DialInfo>,
|
pub dial_info_detail_list: Vec<DialInfoDetail>,
|
||||||
pub relay_peer_info: Option<Box<PeerInfo>>,
|
pub relay_peer_info: Option<Box<PeerInfo>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeInfo {
|
impl NodeInfo {
|
||||||
pub fn first_filtered_dial_info<F>(&self, filter: F) -> Option<DialInfo>
|
pub fn first_filtered_dial_info_detail<F>(&self, filter: F) -> Option<DialInfoDetail>
|
||||||
where
|
where
|
||||||
F: Fn(&DialInfo) -> bool,
|
F: Fn(&DialInfoDetail) -> bool,
|
||||||
{
|
{
|
||||||
for di in &self.dial_info_list {
|
for did in &self.dial_info_detail_list {
|
||||||
if filter(di) {
|
if filter(&did) {
|
||||||
return Some(di.clone());
|
return Some(did.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_filtered_dial_info<F>(&self, filter: F) -> Vec<DialInfo>
|
pub fn all_filtered_dial_info_details<F>(&self, filter: F) -> Vec<DialInfoDetail>
|
||||||
where
|
where
|
||||||
F: Fn(&DialInfo) -> bool,
|
F: Fn(&DialInfoDetail) -> bool,
|
||||||
{
|
{
|
||||||
let mut dial_info_list = Vec::new();
|
let mut dial_info_detail_list = Vec::new();
|
||||||
|
|
||||||
for di in &self.dial_info_list {
|
for did in &self.dial_info_detail_list {
|
||||||
if filter(di) {
|
if filter(&did) {
|
||||||
dial_info_list.push(di.clone());
|
dial_info_detail_list.push(did.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dial_info_list
|
dial_info_detail_list
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_any_dial_info(&self) -> bool {
|
pub fn has_any_dial_info(&self) -> bool {
|
||||||
!self.dial_info_list.is_empty()
|
!self.dial_info_detail_list.is_empty()
|
||||||
|| !self
|
|| !self
|
||||||
.relay_peer_info
|
.relay_peer_info
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -370,7 +355,55 @@ impl NodeInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_direct_dial_info(&self) -> bool {
|
pub fn has_direct_dial_info(&self) -> bool {
|
||||||
!self.dial_info_list.is_empty()
|
!self.dial_info_detail_list.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is some relay required either for signal or inbound relay or outbound relay?
|
||||||
|
pub fn requires_relay(&self) -> bool {
|
||||||
|
match self.network_class {
|
||||||
|
NetworkClass::InboundCapable => {
|
||||||
|
for did in &self.dial_info_detail_list {
|
||||||
|
if did.class.requires_relay() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NetworkClass::OutboundOnly => {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
NetworkClass::WebApp => {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
NetworkClass::Invalid => {}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can this node assist with signalling? Yes but only if it doesn't require signalling, itself.
|
||||||
|
pub fn can_signal(&self) -> bool {
|
||||||
|
// Must be inbound capable
|
||||||
|
if !matches!(self.network_class, NetworkClass::InboundCapable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Do any of our dial info require signalling? if so, we can't offer signalling
|
||||||
|
for did in &self.dial_info_detail_list {
|
||||||
|
if did.class.requires_signal() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can this node relay be an inbound relay?
|
||||||
|
pub fn can_inbound_relay(&self) -> bool {
|
||||||
|
// For now this is the same
|
||||||
|
self.can_signal()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this node capable of validating dial info
|
||||||
|
pub fn can_validate_dial_info(&self) -> bool {
|
||||||
|
// For now this is the same
|
||||||
|
self.can_signal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,13 +707,6 @@ pub struct DialInfoWSS {
|
|||||||
pub request: String,
|
pub request: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
|
|
||||||
#[serde(tag = "kind")]
|
|
||||||
pub enum DialInfoClass {
|
|
||||||
Direct,
|
|
||||||
Relay,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
|
||||||
#[serde(tag = "kind")]
|
#[serde(tag = "kind")]
|
||||||
// The derived ordering here is the order of preference, lower is preferred for connections
|
// The derived ordering here is the order of preference, lower is preferred for connections
|
||||||
|
@ -168,3 +168,20 @@ pub fn listen_address_to_socket_addrs(listen_address: &str) -> Result<Vec<Socket
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Dedup<T: PartialEq + Clone> {
|
||||||
|
fn remove_duplicates(&mut self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq + Clone> Dedup<T> for Vec<T> {
|
||||||
|
fn remove_duplicates(&mut self) {
|
||||||
|
let mut already_seen = Vec::new();
|
||||||
|
self.retain(|item| match already_seen.contains(item) {
|
||||||
|
true => false,
|
||||||
|
_ => {
|
||||||
|
already_seen.push(item.clone());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user