From 54f867634053807bb0fd441bea9cb0674a441639 Mon Sep 17 00:00:00 2001 From: John Smith Date: Mon, 1 Aug 2022 21:06:31 -0400 Subject: [PATCH] filtering cleanup --- veilid-core/proto/veilid.capnp | 18 +- .../native/utils/network_interfaces/apple.rs | 2 +- veilid-core/src/network_manager/mod.rs | 253 +++++++++++++----- veilid-core/src/network_manager/native/mod.rs | 52 +++- veilid-core/src/network_manager/tasks.rs | 3 +- veilid-core/src/network_manager/wasm/mod.rs | 6 +- veilid-core/src/routing_table/find_nodes.rs | 4 +- veilid-core/src/routing_table/node_ref.rs | 98 +++---- .../rpc_processor/coders/address_type_set.rs | 25 ++ veilid-core/src/rpc_processor/coders/mod.rs | 6 +- .../src/rpc_processor/coders/node_info.rs | 15 +- .../src/rpc_processor/coders/protocol_set.rs | 33 --- .../rpc_processor/coders/protocol_type_set.rs | 33 +++ veilid-core/src/veilid_api/mod.rs | 174 +++++++----- 14 files changed, 487 insertions(+), 235 deletions(-) create mode 100644 veilid-core/src/rpc_processor/coders/address_type_set.rs delete mode 100644 veilid-core/src/rpc_processor/coders/protocol_set.rs create mode 100644 veilid-core/src/rpc_processor/coders/protocol_type_set.rs diff --git a/veilid-core/proto/veilid.capnp b/veilid-core/proto/veilid.capnp index 91593498..71533bad 100644 --- a/veilid-core/proto/veilid.capnp +++ b/veilid-core/proto/veilid.capnp @@ -207,20 +207,26 @@ struct NodeStatus { willValidateDialInfo @4 :Bool; } -struct ProtocolSet { +struct ProtocolTypeSet { udp @0 :Bool; tcp @1 :Bool; ws @2 :Bool; wss @3 :Bool; } +struct AddressTypeSet { + ipv4 @0 :Bool; + ipv6 @1 :Bool; +} + struct NodeInfo { networkClass @0 :NetworkClass; # network class of this node - outboundProtocols @1 :ProtocolSet; # protocols that can go outbound - minVersion @2 :UInt8; # minimum protocol version for rpc - maxVersion @3 :UInt8; # maximum protocol version for rpc - dialInfoDetailList @4 :List(DialInfoDetail); # inbound dial info details for this node - relayPeerInfo @5 :PeerInfo; # (optional) relay peer info for this node + outboundProtocols @1 :ProtocolTypeSet; # protocols that can go outbound + addressTypes @2 :AddressTypeSet; # address types supported + minVersion @3 :UInt8; # minimum protocol version for rpc + maxVersion @4 :UInt8; # maximum protocol version for rpc + dialInfoDetailList @5 :List(DialInfoDetail); # inbound dial info details for this node + relayPeerInfo @6 :PeerInfo; # (optional) relay peer info for this node } struct SignedNodeInfo { diff --git a/veilid-core/src/intf/native/utils/network_interfaces/apple.rs b/veilid-core/src/intf/native/utils/network_interfaces/apple.rs index 5eb242ea..97b6d8fd 100644 --- a/veilid-core/src/intf/native/utils/network_interfaces/apple.rs +++ b/veilid-core/src/intf/native/utils/network_interfaces/apple.rs @@ -413,7 +413,7 @@ impl PlatformSupportApple { } // Ask for all the addresses we have - let ifaddrs = IfAddrs::new().map_err(map_to_string)?; + let ifaddrs = IfAddrs::new().wrap_err("failed to get interface addresses")?; for ifaddr in ifaddrs.iter() { // Get the interface name let ifname = unsafe { CStr::from_ptr(ifaddr.ifa_name) } diff --git a/veilid-core/src/network_manager/mod.rs b/veilid-core/src/network_manager/mod.rs index 4941a8a2..242cfcbb 100644 --- a/veilid-core/src/network_manager/mod.rs +++ b/veilid-core/src/network_manager/mod.rs @@ -56,8 +56,10 @@ pub type BootstrapRecordMap = BTreeMap; #[derive(Copy, Clone, Debug, Default)] pub struct ProtocolConfig { - pub outbound: ProtocolSet, - pub inbound: ProtocolSet, + pub outbound: ProtocolTypeSet, + pub inbound: ProtocolTypeSet, + pub family_global: AddressTypeSet, + pub family_local: AddressTypeSet, } // Things we get when we start up and go away when we shut down @@ -135,6 +137,11 @@ struct NetworkManagerInner { client_whitelist: LruCache, relay_node: Option, public_address_check_cache: LruCache, + protocol_config: Option, + public_inbound_dial_info_filter: Option, + local_inbound_dial_info_filter: Option, + public_outbound_dial_info_filter: Option, + local_outbound_dial_info_filter: Option, } struct NetworkManagerUnlockedInner { @@ -166,6 +173,11 @@ impl NetworkManager { client_whitelist: LruCache::new_unbounded(), relay_node: None, public_address_check_cache: LruCache::new(8), + protocol_config: None, + public_inbound_dial_info_filter: None, + local_inbound_dial_info_filter: None, + public_outbound_dial_info_filter: None, + local_outbound_dial_info_filter: None, } } fn new_unlocked_inner(config: VeilidConfig) -> NetworkManagerUnlockedInner { @@ -343,6 +355,41 @@ impl NetworkManager { return Err(e); } + // Store copy of protocol config and dial info filters + { + let mut inner = self.inner.lock(); + let pc = inner + .components + .as_ref() + .unwrap() + .net + .get_protocol_config() + .unwrap(); + + inner.public_inbound_dial_info_filter = Some( + DialInfoFilter::global() + .with_protocol_type_set(pc.inbound) + .with_address_type_set(pc.family_global), + ); + inner.local_inbound_dial_info_filter = Some( + DialInfoFilter::local() + .with_protocol_type_set(pc.inbound) + .with_address_type_set(pc.family_local), + ); + inner.public_outbound_dial_info_filter = Some( + DialInfoFilter::global() + .with_protocol_type_set(pc.outbound) + .with_address_type_set(pc.family_global), + ); + inner.local_outbound_dial_info_filter = Some( + DialInfoFilter::local() + .with_protocol_type_set(pc.outbound) + .with_address_type_set(pc.family_local), + ); + + inner.protocol_config = Some(pc); + } + // Inform routing table entries that our dial info has changed self.send_node_info_updates(true).await; @@ -405,6 +452,11 @@ impl NetworkManager { let mut inner = self.inner.lock(); inner.components = None; inner.relay_node = None; + inner.public_inbound_dial_info_filter = None; + inner.local_inbound_dial_info_filter = None; + inner.public_outbound_dial_info_filter = None; + inner.local_outbound_dial_info_filter = None; + inner.protocol_config = None; } // send update @@ -544,11 +596,42 @@ impl NetworkManager { } // Return what protocols we have enabled - pub fn get_protocol_config(&self) -> Option { - if let Some(components) = &self.inner.lock().components { - components.net.get_protocol_config() - } else { - None + pub fn get_protocol_config(&self) -> ProtocolConfig { + let inner = self.inner.lock(); + inner.protocol_config.as_ref().unwrap().clone() + } + + // Return a dial info filter for what we can receive + pub fn get_inbound_dial_info_filter(&self, routing_domain: RoutingDomain) -> DialInfoFilter { + let inner = self.inner.lock(); + match routing_domain { + RoutingDomain::PublicInternet => inner + .public_inbound_dial_info_filter + .as_ref() + .unwrap() + .clone(), + RoutingDomain::LocalNetwork => inner + .local_inbound_dial_info_filter + .as_ref() + .unwrap() + .clone(), + } + } + + // Return a dial info filter for what we can send out + pub fn get_outbound_dial_info_filter(&self, routing_domain: RoutingDomain) -> DialInfoFilter { + let inner = self.inner.lock(); + match routing_domain { + RoutingDomain::PublicInternet => inner + .public_outbound_dial_info_filter + .as_ref() + .unwrap() + .clone(), + RoutingDomain::LocalNetwork => inner + .local_outbound_dial_info_filter + .as_ref() + .unwrap() + .clone(), } } @@ -692,15 +775,18 @@ impl NetworkManager { }; // Get the udp direct dialinfo for the hole punch - peer_nr.filter_protocols(ProtocolSet::only(ProtocolType::UDP)); + let outbound_dif = self + .get_outbound_dial_info_filter(RoutingDomain::PublicInternet) + .with_protocol_type(ProtocolType::UDP); + peer_nr.set_filter(Some(outbound_dif)); let hole_punch_dial_info_detail = peer_nr .first_filtered_dial_info_detail(Some(RoutingDomain::PublicInternet)) .ok_or_else(|| eyre!("No hole punch capable dialinfo found for node"))?; // Now that we picked a specific dialinfo, further restrict the noderef to the specific address type - let mut filter = peer_nr.take_filter().unwrap(); - filter.peer_scope = PeerScope::Global; - filter.address_type = Some(hole_punch_dial_info_detail.dial_info.address_type()); + let filter = peer_nr.take_filter().unwrap(); + let filter = + filter.with_address_type(hole_punch_dial_info_detail.dial_info.address_type()); peer_nr.set_filter(Some(filter)); // Do our half of the hole punch by sending an empty packet @@ -827,26 +913,11 @@ impl NetworkManager { Ok(()) } - // Figure out how to reach a node #[instrument(level = "trace", skip(self), ret)] - fn get_contact_method(&self, mut target_node_ref: NodeRef) -> ContactMethod { - let routing_table = self.routing_table(); - - // Get our network class and protocol config and node id - let our_network_class = self.get_network_class().unwrap_or(NetworkClass::Invalid); - let our_protocol_config = self.get_protocol_config().unwrap(); - + fn get_contact_method_public(&self, target_node_ref: NodeRef) -> ContactMethod { // Scope noderef down to protocols we can do outbound - if !target_node_ref.filter_protocols(our_protocol_config.outbound) { - return ContactMethod::Unreachable; - } - - // Get the best matching local direct dial info if we have it - let opt_target_local_did = - target_node_ref.first_filtered_dial_info_detail(Some(RoutingDomain::LocalNetwork)); - if let Some(target_local_did) = opt_target_local_did { - return ContactMethod::Direct(target_local_did.dial_info); - } + let public_outbound_dif = self.get_outbound_dial_info_filter(RoutingDomain::PublicInternet); + let target_node_ref = target_node_ref.filtered_clone(public_outbound_dif.clone()); // Get the best match internet dial info if we have it let opt_target_public_did = @@ -861,17 +932,25 @@ impl NetworkManager { // Get the target's inbound relay, it must have one or it is not reachable // Note that .relay() never returns our own node. We can't relay to ourselves. if let Some(inbound_relay_nr) = target_node_ref.relay() { + // Scope down to protocols we can do outbound + let inbound_relay_nr = inbound_relay_nr.filtered_clone(public_outbound_dif.clone()); // Can we reach the inbound relay? if inbound_relay_nr .first_filtered_dial_info_detail(Some(RoutingDomain::PublicInternet)) .is_some() { // Can we receive anything inbound ever? + let our_network_class = + self.get_network_class().unwrap_or(NetworkClass::Invalid); if matches!(our_network_class, NetworkClass::InboundCapable) { + let routing_table = self.routing_table(); + + ///////// Reverse connection + // Get the best match dial info for an reverse inbound connection - let reverse_dif = DialInfoFilter::global().with_protocol_set( - target_node_ref.outbound_protocols().unwrap_or_default(), - ); + let reverse_dif = self + .get_inbound_dial_info_filter(RoutingDomain::PublicInternet) + .filtered(target_node_ref.node_info_outbound_filter()); if let Some(reverse_did) = routing_table.first_filtered_dial_info_detail( Some(RoutingDomain::PublicInternet), &reverse_dif, @@ -885,35 +964,33 @@ impl NetworkManager { } } - // Does we and the target have outbound protocols to hole-punch? - if our_protocol_config.outbound.contains(ProtocolType::UDP) - && target_node_ref - .outbound_protocols() - .unwrap_or_default() - .contains(ProtocolType::UDP) - { - // Do the target and self nodes have a direct udp dialinfo - let udp_dif = - DialInfoFilter::global().with_protocol_type(ProtocolType::UDP); - let mut udp_target_nr = target_node_ref.clone(); - udp_target_nr.filter_protocols(ProtocolSet::only(ProtocolType::UDP)); - let target_has_udp_dialinfo = target_node_ref - .first_filtered_dial_info_detail(Some( - RoutingDomain::PublicInternet, - )) - .is_some(); - let self_has_udp_dialinfo = routing_table - .first_filtered_dial_info_detail( - Some(RoutingDomain::PublicInternet), - &udp_dif, - ) - .is_some(); - if target_has_udp_dialinfo && self_has_udp_dialinfo { - return ContactMethod::SignalHolePunch( - inbound_relay_nr, - udp_target_nr, - ); - } + ///////// UDP hole-punch + + // Does the target have a direct udp dialinfo we can reach? + let udp_target_nr = target_node_ref.filtered_clone( + DialInfoFilter::global().with_protocol_type(ProtocolType::UDP), + ); + let target_has_udp_dialinfo = udp_target_nr + .first_filtered_dial_info_detail(Some(RoutingDomain::PublicInternet)) + .is_some(); + + // Does the self node have a direct udp dialinfo the target can reach? + let inbound_udp_dif = self + .get_inbound_dial_info_filter(RoutingDomain::PublicInternet) + .filtered(target_node_ref.node_info_outbound_filter()) + .filtered( + DialInfoFilter::global().with_protocol_type(ProtocolType::UDP), + ); + let self_has_udp_dialinfo = routing_table + .first_filtered_dial_info_detail( + Some(RoutingDomain::PublicInternet), + &inbound_udp_dif, + ) + .is_some(); + + // Does the target and ourselves have a udp dialinfo that they can reach? + if target_has_udp_dialinfo && self_has_udp_dialinfo { + return ContactMethod::SignalHolePunch(inbound_relay_nr, udp_target_nr); } // Otherwise we have to inbound relay } @@ -922,7 +999,7 @@ impl NetworkManager { } } } - // If the other node is not inbound capable at all, it is using a full relay + // If the other node is not inbound capable at all, it needs to have an inbound relay else if let Some(target_inbound_relay_nr) = target_node_ref.relay() { // Can we reach the full relay? if target_inbound_relay_nr @@ -933,10 +1010,48 @@ impl NetworkManager { } } + ContactMethod::Unreachable + } + + #[instrument(level = "trace", skip(self), ret)] + fn get_contact_method_local(&self, target_node_ref: NodeRef) -> ContactMethod { + // Scope noderef down to protocols we can do outbound + let local_outbound_dif = self.get_outbound_dial_info_filter(RoutingDomain::LocalNetwork); + let target_node_ref = target_node_ref.filtered_clone(local_outbound_dif); + + // Get the best matching local direct dial info if we have it + // ygjghhtiygiukuymyg + if target_node_ref.is_filter_dead() { + return ContactMethod::Unreachable; + } + let opt_target_local_did = + target_node_ref.first_filtered_dial_info_detail(Some(RoutingDomain::LocalNetwork)); + if let Some(target_local_did) = opt_target_local_did { + return ContactMethod::Direct(target_local_did.dial_info); + } + return ContactMethod::Unreachable; + } + + // Figure out how to reach a node + #[instrument(level = "trace", skip(self), ret)] + fn get_contact_method(&self, target_node_ref: NodeRef) -> ContactMethod { + // Try local first + let out = self.get_contact_method_local(target_node_ref.clone()); + if !matches!(out, ContactMethod::Unreachable) { + return out; + } + + // Try public next + let out = self.get_contact_method_public(target_node_ref.clone()); + if !matches!(out, ContactMethod::Unreachable) { + return out; + } + // If we can't reach the node by other means, try our outbound relay if we have one if let Some(relay_node) = self.relay_node() { return ContactMethod::OutboundRelay(relay_node); } + // Otherwise, we can't reach this node debug!("unable to reach node {:?}", target_node_ref); ContactMethod::Unreachable @@ -1020,7 +1135,7 @@ impl NetworkManager { // Ensure we are filtered down to UDP (the only hole punch protocol supported today) assert!(target_nr .filter_ref() - .map(|dif| dif.protocol_set == ProtocolSet::only(ProtocolType::UDP)) + .map(|dif| dif.protocol_set == ProtocolTypeSet::only(ProtocolType::UDP)) .unwrap_or_default()); // Build a return receipt for the signal @@ -1118,11 +1233,13 @@ impl NetworkManager { .await? { None => { - return Ok(if descriptor.matches_peer_scope(PeerScope::Local) { - NetworkResult::value(SendDataKind::LocalDirect) - } else { - NetworkResult::value(SendDataKind::GlobalDirect) - }); + return Ok( + if descriptor.matches_peer_scope(PeerScopeSet::only(PeerScope::Local)) { + NetworkResult::value(SendDataKind::LocalDirect) + } else { + NetworkResult::value(SendDataKind::GlobalDirect) + }, + ); } Some(d) => d, } diff --git a/veilid-core/src/network_manager/native/mod.rs b/veilid-core/src/network_manager/native/mod.rs index 9b4605a9..7489f8e1 100644 --- a/veilid-core/src/network_manager/native/mod.rs +++ b/veilid-core/src/network_manager/native/mod.rs @@ -35,7 +35,7 @@ struct NetworkInner { network_started: bool, network_needs_restart: bool, protocol_config: Option, - static_public_dialinfo: ProtocolSet, + static_public_dialinfo: ProtocolTypeSet, network_class: Option, join_handles: Vec>, stop_source: Option, @@ -43,6 +43,9 @@ struct NetworkInner { tcp_port: u16, ws_port: u16, wss_port: u16, + enable_ipv4: bool, + enable_ipv6_global: bool, + enable_ipv6_local: bool, // udp bound_first_udp: BTreeMap>, inbound_udp_protocol_handlers: BTreeMap, @@ -79,7 +82,7 @@ impl Network { network_started: false, network_needs_restart: false, protocol_config: None, - static_public_dialinfo: ProtocolSet::empty(), + static_public_dialinfo: ProtocolTypeSet::empty(), network_class: None, join_handles: Vec::new(), stop_source: None, @@ -87,6 +90,9 @@ impl Network { tcp_port: 0u16, ws_port: 0u16, wss_port: 0u16, + enable_ipv4: true, + enable_ipv6_global: true, + enable_ipv6_local: true, bound_first_udp: BTreeMap::new(), inbound_udp_protocol_handlers: BTreeMap::new(), outbound_udpv4_protocol_handler: None, @@ -540,6 +546,24 @@ impl Network { // initialize interfaces self.unlocked_inner.interfaces.refresh().await?; + // determine if we have ipv4/ipv6 addresses + { + let mut inner = self.inner.lock(); + for addr in self.unlocked_inner.interfaces.best_addresses() { + if addr.is_ipv4() { + inner.enable_ipv4 = true; + } else if addr.is_ipv6() { + let address = crate::Address::from_ip_addr(addr); + if address.is_global() { + inner.enable_ipv6_global = true; + } else if address.is_local() { + inner.enable_ipv6_local = true; + } + } + } + } + + // Build our protocol config to share it with other nodes let protocol_config = { let mut inner = self.inner.lock(); @@ -549,7 +573,7 @@ impl Network { // get protocol config let protocol_config = { let c = self.config.get(); - let mut inbound = ProtocolSet::new(); + let mut inbound = ProtocolTypeSet::new(); if c.network.protocol.udp.enabled && c.capabilities.protocol_udp { inbound.insert(ProtocolType::UDP); @@ -564,7 +588,7 @@ impl Network { inbound.insert(ProtocolType::WSS); } - let mut outbound = ProtocolSet::new(); + let mut outbound = ProtocolTypeSet::new(); if c.network.protocol.udp.enabled && c.capabilities.protocol_udp { outbound.insert(ProtocolType::UDP); } @@ -578,7 +602,25 @@ impl Network { outbound.insert(ProtocolType::WSS); } - ProtocolConfig { inbound, outbound } + let mut family_global = AddressTypeSet::new(); + let mut family_local = AddressTypeSet::new(); + if inner.enable_ipv4 { + family_global.insert(AddressType::IPV4); + family_local.insert(AddressType::IPV4); + } + if inner.enable_ipv6_global { + family_global.insert(AddressType::IPV6); + } + if inner.enable_ipv6_local { + family_local.insert(AddressType::IPV6); + } + + ProtocolConfig { + inbound, + outbound, + family_global, + family_local, + } }; inner.protocol_config = Some(protocol_config); protocol_config diff --git a/veilid-core/src/network_manager/tasks.rs b/veilid-core/src/network_manager/tasks.rs index c4e37e36..09cab642 100644 --- a/veilid-core/src/network_manager/tasks.rs +++ b/veilid-core/src/network_manager/tasks.rs @@ -280,7 +280,8 @@ impl NetworkManager { k, SignedNodeInfo::with_no_signature(NodeInfo { network_class: NetworkClass::InboundCapable, // Bootstraps are always inbound capable - outbound_protocols: ProtocolSet::empty(), // Bootstraps do not participate in relaying and will not make outbound requests + outbound_protocols: ProtocolTypeSet::only(ProtocolType::UDP), // Bootstraps do not participate in relaying and will not make outbound requests, but will have UDP enabled + address_types: AddressTypeSet::all(), // Bootstraps are always IPV4 and IPV6 capable min_version: v.min_version, // Minimum protocol version specified in txt record max_version: v.max_version, // Maximum protocol version specified in txt record dial_info_detail_list: v.dial_info_details, // Dial info is as specified in the bootstrap list diff --git a/veilid-core/src/network_manager/wasm/mod.rs b/veilid-core/src/network_manager/wasm/mod.rs index 9da7863a..77043bc2 100644 --- a/veilid-core/src/network_manager/wasm/mod.rs +++ b/veilid-core/src/network_manager/wasm/mod.rs @@ -231,7 +231,11 @@ impl Network { outbound.insert(ProtocolType::WSS); } - ProtocolConfig { inbound, outbound } + // XXX: See issue #92 + let family_global = AddressSet::all(); + let family_local = AddressSet::all(); + + ProtocolConfig { inbound, outbound, family_global, family_local } }); self.inner.lock().network_started = true; diff --git a/veilid-core/src/routing_table/find_nodes.rs b/veilid-core/src/routing_table/find_nodes.rs index c488a772..ea00df8e 100644 --- a/veilid-core/src/routing_table/find_nodes.rs +++ b/veilid-core/src/routing_table/find_nodes.rs @@ -126,9 +126,11 @@ impl RoutingTable { pub fn get_own_node_info(&self) -> NodeInfo { let netman = self.network_manager(); let relay_node = netman.relay_node(); + let pc = netman.get_protocol_config(); NodeInfo { network_class: netman.get_network_class().unwrap_or(NetworkClass::Invalid), - outbound_protocols: netman.get_protocol_config().unwrap_or_default().outbound, + outbound_protocols: pc.outbound, + address_types: pc.family_global, min_version: MIN_VERSION, max_version: MAX_VERSION, dial_info_detail_list: self.dial_info_details(RoutingDomain::PublicInternet), diff --git a/veilid-core/src/routing_table/node_ref.rs b/veilid-core/src/routing_table/node_ref.rs index c9e84c73..31935706 100644 --- a/veilid-core/src/routing_table/node_ref.rs +++ b/veilid-core/src/routing_table/node_ref.rs @@ -50,19 +50,41 @@ impl NodeRef { self.filter = filter } - // Returns true if some protocols can still pass the filter and false if no protocols remain - pub fn filter_protocols(&mut self, protocol_set: ProtocolSet) -> bool { - if protocol_set != ProtocolSet::all() { - let mut dif = self.filter.clone().unwrap_or_default(); - dif.protocol_set &= protocol_set; - self.filter = Some(dif); + pub fn merge_filter(&mut self, filter: DialInfoFilter) { + if let Some(self_filter) = self.filter.take() { + self.filter = Some(self_filter.filtered(filter)); + } else { + self.filter = Some(filter); } - self.filter - .as_ref() - .map(|f| !f.protocol_set.is_empty()) - .unwrap_or(true) } + pub fn filtered_clone(&self, filter: DialInfoFilter) -> Self { + let mut out = self.clone(); + out.merge_filter(filter); + out + } + + pub fn is_filter_dead(&self) -> bool { + if let Some(filter) = &self.filter { + filter.is_dead() + } else { + false + } + } + + // Returns true if some protocols can still pass the filter and false if no protocols remain + // pub fn filter_protocols(&mut self, protocol_set: ProtocolSet) -> bool { + // if protocol_set != ProtocolSet::all() { + // let mut dif = self.filter.clone().unwrap_or_default(); + // dif.protocol_set &= protocol_set; + // self.filter = Some(dif); + // } + // self.filter + // .as_ref() + // .map(|f| !f.protocol_set.is_empty()) + // .unwrap_or(true) + // } + pub fn operate(&self, f: F) -> T where F: FnOnce(&BucketEntryInner) -> T, @@ -89,9 +111,23 @@ impl NodeRef { pub fn network_class(&self) -> Option { self.operate(|e| e.node_info().map(|n| n.network_class)) } - pub fn outbound_protocols(&self) -> Option { + pub fn outbound_protocols(&self) -> Option { self.operate(|e| e.node_info().map(|n| n.outbound_protocols)) } + pub fn address_types(&self) -> Option { + self.operate(|e| e.node_info().map(|n| n.address_types)) + } + pub fn node_info_outbound_filter(&self) -> DialInfoFilter { + let mut dif = DialInfoFilter::all(); + if let Some(outbound_protocols) = self.outbound_protocols() { + dif = dif.with_protocol_type_set(outbound_protocols); + } + if let Some(address_types) = self.address_types() { + dif = dif.with_address_type_set(address_types); + } + dif + } + pub fn relay(&self) -> Option { let target_rpi = self.operate(|e| e.node_info().map(|n| n.relay_peer_info))?; target_rpi.and_then(|t| { @@ -116,15 +152,7 @@ impl NodeRef { ) -> Option { self.operate(|e| { // Prefer local dial info first unless it is filtered out - if (routing_domain == None || routing_domain == Some(RoutingDomain::LocalNetwork)) - && matches!( - self.filter - .as_ref() - .map(|f| f.peer_scope) - .unwrap_or(PeerScope::All), - PeerScope::All | PeerScope::Local - ) - { + if routing_domain == None || routing_domain == Some(RoutingDomain::LocalNetwork) { e.local_node_info().and_then(|l| { l.first_filtered_dial_info(|di| { if let Some(filter) = self.filter.as_ref() { @@ -142,15 +170,7 @@ impl NodeRef { None } .or_else(|| { - if (routing_domain == None || routing_domain == Some(RoutingDomain::PublicInternet)) - && matches!( - self.filter - .as_ref() - .map(|f| f.peer_scope) - .unwrap_or(PeerScope::All), - PeerScope::All | PeerScope::Global - ) - { + if routing_domain == None || routing_domain == Some(RoutingDomain::PublicInternet) { e.node_info().and_then(|n| { n.first_filtered_dial_info_detail(|did| { if let Some(filter) = self.filter.as_ref() { @@ -174,15 +194,7 @@ impl NodeRef { let mut out = Vec::new(); self.operate(|e| { // Prefer local dial info first unless it is filtered out - if (routing_domain == None || routing_domain == Some(RoutingDomain::LocalNetwork)) - && matches!( - self.filter - .as_ref() - .map(|f| f.peer_scope) - .unwrap_or(PeerScope::All), - PeerScope::All | PeerScope::Local - ) - { + if routing_domain == None || routing_domain == Some(RoutingDomain::LocalNetwork) { if let Some(lni) = e.local_node_info() { for di in lni.all_filtered_dial_info(|di| { if let Some(filter) = self.filter.as_ref() { @@ -198,15 +210,7 @@ impl NodeRef { } } } - if (routing_domain == None || routing_domain == Some(RoutingDomain::PublicInternet)) - && matches!( - self.filter - .as_ref() - .map(|f| f.peer_scope) - .unwrap_or(PeerScope::All), - PeerScope::All | PeerScope::Global - ) - { + if routing_domain == None || routing_domain == Some(RoutingDomain::PublicInternet) { if let Some(ni) = e.node_info() { out.append(&mut ni.all_filtered_dial_info_details(|did| { if let Some(filter) = self.filter.as_ref() { diff --git a/veilid-core/src/rpc_processor/coders/address_type_set.rs b/veilid-core/src/rpc_processor/coders/address_type_set.rs new file mode 100644 index 00000000..67a40159 --- /dev/null +++ b/veilid-core/src/rpc_processor/coders/address_type_set.rs @@ -0,0 +1,25 @@ +use crate::*; +use rpc_processor::*; + +pub fn encode_address_type_set( + address_type_set: &AddressTypeSet, + builder: &mut veilid_capnp::address_type_set::Builder, +) -> Result<(), RPCError> { + builder.set_ipv4(address_type_set.contains(AddressType::IPV4)); + builder.set_ipv6(address_type_set.contains(AddressType::IPV6)); + + Ok(()) +} + +pub fn decode_address_type_set( + reader: &veilid_capnp::address_type_set::Reader, +) -> Result { + let mut out = AddressTypeSet::new(); + if reader.reborrow().get_ipv4() { + out.insert(AddressType::IPV4); + } + if reader.reborrow().get_ipv6() { + out.insert(AddressType::IPV6); + } + Ok(out) +} diff --git a/veilid-core/src/rpc_processor/coders/mod.rs b/veilid-core/src/rpc_processor/coders/mod.rs index 72590763..a22e3dfe 100644 --- a/veilid-core/src/rpc_processor/coders/mod.rs +++ b/veilid-core/src/rpc_processor/coders/mod.rs @@ -1,4 +1,5 @@ mod address; +mod address_type_set; mod block_id; mod dial_info; mod dial_info_class; @@ -11,7 +12,7 @@ mod nonce; mod operations; mod peer_info; mod private_safety_route; -mod protocol_set; +mod protocol_type_set; mod public_key; mod sender_info; mod signal_info; @@ -23,6 +24,7 @@ mod value_data; mod value_key; pub use address::*; +pub use address_type_set::*; pub use block_id::*; pub use dial_info::*; pub use dial_info_class::*; @@ -35,7 +37,7 @@ pub use nonce::*; pub use operations::*; pub use peer_info::*; pub use private_safety_route::*; -pub use protocol_set::*; +pub use protocol_type_set::*; pub use public_key::*; pub use sender_info::*; pub use signal_info::*; diff --git a/veilid-core/src/rpc_processor/coders/node_info.rs b/veilid-core/src/rpc_processor/coders/node_info.rs index e6382fe2..72e7f31e 100644 --- a/veilid-core/src/rpc_processor/coders/node_info.rs +++ b/veilid-core/src/rpc_processor/coders/node_info.rs @@ -8,7 +8,10 @@ pub fn encode_node_info( builder.set_network_class(encode_network_class(node_info.network_class)); let mut ps_builder = builder.reborrow().init_outbound_protocols(); - encode_protocol_set(&node_info.outbound_protocols, &mut ps_builder)?; + encode_protocol_type_set(&node_info.outbound_protocols, &mut ps_builder)?; + + let mut ats_builder = builder.reborrow().init_address_types(); + encode_address_type_set(&node_info.address_types, &mut ats_builder)?; builder.set_min_version(node_info.min_version); builder.set_max_version(node_info.max_version); @@ -47,13 +50,20 @@ pub fn decode_node_info( .map_err(RPCError::protocol)?, ); - let outbound_protocols = decode_protocol_set( + let outbound_protocols = decode_protocol_type_set( &reader .reborrow() .get_outbound_protocols() .map_err(RPCError::protocol)?, )?; + let address_types = decode_address_type_set( + &reader + .reborrow() + .get_address_types() + .map_err(RPCError::protocol)?, + )?; + let min_version = reader.reborrow().get_min_version(); let max_version = reader.reborrow().get_max_version(); @@ -90,6 +100,7 @@ pub fn decode_node_info( Ok(NodeInfo { network_class, outbound_protocols, + address_types, min_version, max_version, dial_info_detail_list, diff --git a/veilid-core/src/rpc_processor/coders/protocol_set.rs b/veilid-core/src/rpc_processor/coders/protocol_set.rs deleted file mode 100644 index 0fd3dc02..00000000 --- a/veilid-core/src/rpc_processor/coders/protocol_set.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::*; -use rpc_processor::*; - -pub fn encode_protocol_set( - protocol_set: &ProtocolSet, - builder: &mut veilid_capnp::protocol_set::Builder, -) -> Result<(), RPCError> { - builder.set_udp(protocol_set.contains(ProtocolType::UDP)); - builder.set_tcp(protocol_set.contains(ProtocolType::TCP)); - builder.set_ws(protocol_set.contains(ProtocolType::WS)); - builder.set_wss(protocol_set.contains(ProtocolType::WSS)); - - Ok(()) -} - -pub fn decode_protocol_set( - reader: &veilid_capnp::protocol_set::Reader, -) -> Result { - let mut out = ProtocolSet::new(); - if reader.reborrow().get_udp() { - out.insert(ProtocolType::UDP); - } - if reader.reborrow().get_tcp() { - out.insert(ProtocolType::TCP); - } - if reader.reborrow().get_ws() { - out.insert(ProtocolType::WS); - } - if reader.reborrow().get_wss() { - out.insert(ProtocolType::WSS); - } - Ok(out) -} diff --git a/veilid-core/src/rpc_processor/coders/protocol_type_set.rs b/veilid-core/src/rpc_processor/coders/protocol_type_set.rs new file mode 100644 index 00000000..37db7e19 --- /dev/null +++ b/veilid-core/src/rpc_processor/coders/protocol_type_set.rs @@ -0,0 +1,33 @@ +use crate::*; +use rpc_processor::*; + +pub fn encode_protocol_type_set( + protocol_type_set: &ProtocolTypeSet, + builder: &mut veilid_capnp::protocol_type_set::Builder, +) -> Result<(), RPCError> { + builder.set_udp(protocol_type_set.contains(ProtocolType::UDP)); + builder.set_tcp(protocol_type_set.contains(ProtocolType::TCP)); + builder.set_ws(protocol_type_set.contains(ProtocolType::WS)); + builder.set_wss(protocol_type_set.contains(ProtocolType::WSS)); + + Ok(()) +} + +pub fn decode_protocol_type_set( + reader: &veilid_capnp::protocol_type_set::Reader, +) -> Result { + let mut out = ProtocolTypeSet::new(); + if reader.reborrow().get_udp() { + out.insert(ProtocolType::UDP); + } + if reader.reborrow().get_tcp() { + out.insert(ProtocolType::TCP); + } + if reader.reborrow().get_ws() { + out.insert(ProtocolType::WS); + } + if reader.reborrow().get_wss() { + out.insert(ProtocolType::WSS); + } + Ok(out) +} diff --git a/veilid-core/src/veilid_api/mod.rs b/veilid-core/src/veilid_api/mod.rs index f4b3595b..9d1b3d7e 100644 --- a/veilid-core/src/veilid_api/mod.rs +++ b/veilid-core/src/veilid_api/mod.rs @@ -402,7 +402,8 @@ pub struct NodeStatus { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct NodeInfo { pub network_class: NetworkClass, - pub outbound_protocols: ProtocolSet, + pub outbound_protocols: ProtocolTypeSet, + pub address_types: AddressTypeSet, pub min_version: u8, pub max_version: u8, pub dial_info_detail_list: Vec, @@ -557,14 +558,23 @@ impl ProtocolType { ) } } +pub type ProtocolTypeSet = EnumSet; -pub type ProtocolSet = EnumSet; - -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)] +#[allow(clippy::derive_hash_xor_eq)] +#[derive(Debug, PartialOrd, Ord, Hash, Serialize, Deserialize, EnumSetType)] pub enum AddressType { IPV4, IPV6, } +pub type AddressTypeSet = EnumSet; + +#[allow(clippy::derive_hash_xor_eq)] +#[derive(Debug, Ord, PartialOrd, Hash, Serialize, Deserialize, EnumSetType)] +pub enum PeerScope { + Global, + Local, +} +pub type PeerScopeSet = EnumSet; #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)] pub enum Address { @@ -585,6 +595,12 @@ impl Address { SocketAddr::V6(v6) => Address::IPV6(*v6.ip()), } } + pub fn from_ip_addr(addr: IpAddr) -> Address { + match addr { + IpAddr::V4(v4) => Address::IPV4(v4), + IpAddr::V6(v6) => Address::IPV6(v6), + } + } pub fn address_type(&self) -> AddressType { match self { Address::IPV4(_) => AddressType::IPV4, @@ -715,17 +731,17 @@ impl FromStr for SocketAddress { #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct DialInfoFilter { - pub peer_scope: PeerScope, - pub protocol_set: ProtocolSet, - pub address_type: Option, + pub peer_scope_set: PeerScopeSet, + pub protocol_set: ProtocolTypeSet, + pub address_set: AddressTypeSet, } impl Default for DialInfoFilter { fn default() -> Self { Self { - peer_scope: PeerScope::All, - protocol_set: ProtocolSet::all(), - address_type: None, + peer_scope_set: PeerScopeSet::all(), + protocol_set: ProtocolTypeSet::all(), + address_set: AddressTypeSet::all(), } } } @@ -733,55 +749,72 @@ impl Default for DialInfoFilter { impl DialInfoFilter { pub fn all() -> Self { Self { - peer_scope: PeerScope::All, - protocol_set: ProtocolSet::all(), - address_type: None, + peer_scope_set: PeerScopeSet::all(), + protocol_set: ProtocolTypeSet::all(), + address_set: AddressTypeSet::all(), } } pub fn global() -> Self { Self { - peer_scope: PeerScope::Global, - protocol_set: ProtocolSet::all(), - address_type: None, + peer_scope_set: PeerScopeSet::only(PeerScope::Global), + protocol_set: ProtocolTypeSet::all(), + address_set: AddressTypeSet::all(), } } pub fn local() -> Self { Self { - peer_scope: PeerScope::Local, - protocol_set: ProtocolSet::all(), - address_type: None, + peer_scope_set: PeerScopeSet::only(PeerScope::Local), + protocol_set: ProtocolTypeSet::all(), + address_set: AddressTypeSet::all(), } } pub fn scoped(peer_scope: PeerScope) -> Self { Self { - peer_scope, - protocol_set: ProtocolSet::all(), - address_type: None, + peer_scope_set: PeerScopeSet::only(peer_scope), + protocol_set: ProtocolTypeSet::all(), + address_set: AddressTypeSet::all(), } } pub fn with_protocol_type(mut self, protocol_type: ProtocolType) -> Self { - self.protocol_set = ProtocolSet::only(protocol_type); + self.protocol_set = ProtocolTypeSet::only(protocol_type); self } - pub fn with_protocol_set(mut self, protocol_set: ProtocolSet) -> Self { + pub fn with_protocol_type_set(mut self, protocol_set: ProtocolTypeSet) -> Self { self.protocol_set = protocol_set; self } pub fn with_address_type(mut self, address_type: AddressType) -> Self { - self.address_type = Some(address_type); + self.address_set = AddressTypeSet::only(address_type); self } + pub fn with_address_type_set(mut self, address_set: AddressTypeSet) -> Self { + self.address_set = address_set; + self + } + pub fn filtered(mut self, other_dif: DialInfoFilter) -> Self { + self.peer_scope_set &= other_dif.peer_scope_set; + self.protocol_set &= other_dif.protocol_set; + self.address_set &= other_dif.address_set; + self + } + pub fn is_dead(&self) -> bool { + self.peer_scope_set.is_empty() + || self.protocol_set.is_empty() + || self.address_set.is_empty() + } } impl fmt::Debug for DialInfoFilter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { let mut out = String::new(); - out += &format!("{:?}", self.peer_scope); - if self.protocol_set != ProtocolSet::all() { + if self.peer_scope_set != PeerScopeSet::all() { + out += &format!("+{:?}", self.peer_scope_set); + } + if self.protocol_set != ProtocolTypeSet::all() { out += &format!("+{:?}", self.protocol_set); } - if let Some(at) = self.address_type { - out += &format!("+{:?}", at); + if self.address_set != AddressTypeSet::all() { + out += &format!("+{:?}", self.address_set); } write!(f, "[{}]", out) } @@ -1107,28 +1140,39 @@ impl DialInfo { let port = socket_address.port(); (address.is_global() || address.is_local()) && port > 0 } - pub fn matches_peer_scope(&self, scope: PeerScope) -> bool { - match scope { - PeerScope::All => true, - PeerScope::Global => self.is_global(), - PeerScope::Local => self.is_local(), + pub fn peer_scope(&self) -> Option { + let addr = self.socket_address().address(); + if addr.is_global() { + return Some(PeerScope::Global); + } + if addr.is_local() { + return Some(PeerScope::Local); + } + None + } + pub fn matches_peer_scope(&self, scope: PeerScopeSet) -> bool { + if let Some(ps) = self.peer_scope() { + scope.contains(ps) + } else { + false } } + pub fn make_filter(&self, scoped: bool) -> DialInfoFilter { DialInfoFilter { - peer_scope: if scoped { + peer_scope_set: if scoped { if self.is_global() { - PeerScope::Global + PeerScopeSet::only(PeerScope::Global) } else if self.is_local() { - PeerScope::Local + PeerScopeSet::only(PeerScope::Local) } else { - PeerScope::All + PeerScopeSet::empty() } } else { - PeerScope::All + PeerScopeSet::all() }, - protocol_set: ProtocolSet::only(self.protocol_type()), - address_type: Some(self.address_type()), + protocol_set: ProtocolTypeSet::only(self.protocol_type()), + address_set: AddressTypeSet::only(self.address_type()), } } @@ -1313,16 +1357,14 @@ impl DialInfo { impl MatchesDialInfoFilter for DialInfo { fn matches_filter(&self, filter: &DialInfoFilter) -> bool { - if !self.matches_peer_scope(filter.peer_scope) { + if !self.matches_peer_scope(filter.peer_scope_set) { return false; } if !filter.protocol_set.contains(self.protocol_type()) { return false; } - if let Some(at) = filter.address_type { - if self.address_type() != at { - return false; - } + if !filter.address_set.contains(self.address_type()) { + return false; } true } @@ -1330,18 +1372,6 @@ impl MatchesDialInfoFilter for DialInfo { ////////////////////////////////////////////////////////////////////////// -#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] -pub enum PeerScope { - All, - Global, - Local, -} -impl Default for PeerScope { - fn default() -> Self { - PeerScope::All - } -} - // Signed NodeInfo that can be passed around amongst peers and verifiable #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SignedNodeInfo { @@ -1487,27 +1517,35 @@ impl ConnectionDescriptor { pub fn address_type(&self) -> AddressType { self.remote.address_type() } - pub fn matches_peer_scope(&self, scope: PeerScope) -> bool { - match scope { - PeerScope::All => true, - PeerScope::Global => self.remote.socket_address.address().is_global(), - PeerScope::Local => self.remote.socket_address.address().is_local(), + pub fn peer_scope(&self) -> Option { + let addr = self.remote.socket_address.address(); + if addr.is_global() { + return Some(PeerScope::Global); + } + if addr.is_local() { + return Some(PeerScope::Local); + } + None + } + pub fn matches_peer_scope(&self, scope: PeerScopeSet) -> bool { + if let Some(ps) = self.peer_scope() { + scope.contains(ps) + } else { + false } } } impl MatchesDialInfoFilter for ConnectionDescriptor { fn matches_filter(&self, filter: &DialInfoFilter) -> bool { - if !self.matches_peer_scope(filter.peer_scope) { + if !self.matches_peer_scope(filter.peer_scope_set) { return false; } if !filter.protocol_set.contains(self.protocol_type()) { return false; } - if let Some(at) = filter.address_type { - if self.address_type() != at { - return false; - } + if !filter.address_set.contains(self.address_type()) { + return false; } true }