From 54c403ebfb68caa5364ed72271f650ee5dcdc5ff Mon Sep 17 00:00:00 2001 From: Christien Rioux Date: Wed, 11 Oct 2023 23:12:54 -0400 Subject: [PATCH] keep network from going down when external ip addresses haven't changed --- .../native/discovery_context.rs | 43 +++++++++++++++++++ veilid-core/src/network_manager/native/mod.rs | 3 ++ .../native/network_class_discovery.rs | 41 +++++++++++++++--- 3 files changed, 80 insertions(+), 7 deletions(-) diff --git a/veilid-core/src/network_manager/native/discovery_context.rs b/veilid-core/src/network_manager/native/discovery_context.rs index 2837ed4c..d7b2376e 100644 --- a/veilid-core/src/network_manager/native/discovery_context.rs +++ b/veilid-core/src/network_manager/native/discovery_context.rs @@ -39,8 +39,11 @@ struct DiscoveryContextInner { struct DiscoveryContextUnlockedInner { routing_table: RoutingTable, net: Network, + clear_network_callback: ClearNetworkCallback, + // per-protocol intf_addrs: Vec, + existing_external_address: Option, protocol_type: ProtocolType, address_type: AddressType, } @@ -51,21 +54,45 @@ pub struct DiscoveryContext { inner: Arc>, } +pub type ClearNetworkCallback = Arc SendPinBoxFuture<()> + Send + Sync>; + impl DiscoveryContext { pub fn new( routing_table: RoutingTable, net: Network, protocol_type: ProtocolType, address_type: AddressType, + clear_network_callback: ClearNetworkCallback, ) -> Self { let intf_addrs = Self::get_local_addresses(routing_table.clone(), protocol_type, address_type); + // Get the existing external address to check to see if it has changed + let existing_dial_info = routing_table.all_filtered_dial_info_details( + RoutingDomain::PublicInternet.into(), + &DialInfoFilter::default() + .with_address_type(address_type) + .with_protocol_type(protocol_type), + ); + let existing_external_address = if existing_dial_info.len() == 1 { + Some( + existing_dial_info + .first() + .unwrap() + .dial_info + .socket_address(), + ) + } else { + None + }; + Self { unlocked_inner: Arc::new(DiscoveryContextUnlockedInner { routing_table, net, + clear_network_callback, intf_addrs, + existing_external_address, protocol_type, address_type, }), @@ -631,6 +658,22 @@ impl DiscoveryContext { return; } + // Did external addresses change from the last time we made dialinfo? + let some_clear_network_callback = { + let inner = self.inner.lock(); + let ext_1 = inner.external_1.as_ref().unwrap().address; + let ext_2 = inner.external_2.as_ref().unwrap().address; + if (ext_1 != ext_2) || Some(ext_1) != self.unlocked_inner.existing_external_address { + // External address was not found, or has changed, go ahead and clear the network so we can do better + Some(self.unlocked_inner.clear_network_callback.clone()) + } else { + None + } + }; + if let Some(clear_network_callback) = some_clear_network_callback { + clear_network_callback().await; + } + // UPNP Automatic Mapping /////////// if enable_upnp { diff --git a/veilid-core/src/network_manager/native/mod.rs b/veilid-core/src/network_manager/native/mod.rs index ead28274..2cca19ea 100644 --- a/veilid-core/src/network_manager/native/mod.rs +++ b/veilid-core/src/network_manager/native/mod.rs @@ -99,6 +99,8 @@ struct NetworkInner { enable_ipv6_local: bool, /// set if we need to calculate our public dial info again needs_public_dial_info_check: bool, + /// set if we have yet to clear the network during public dial info checking + network_already_cleared: bool, /// the punishment closure to enax public_dial_info_check_punishment: Option>, /// udp socket record for bound-first sockets, which are used to guarantee a port is available before @@ -148,6 +150,7 @@ impl Network { network_started: false, network_needs_restart: false, needs_public_dial_info_check: false, + network_already_cleared: false, public_dial_info_check_punishment: None, protocol_config: Default::default(), static_public_dialinfo: ProtocolTypeSet::empty(), diff --git a/veilid-core/src/network_manager/native/network_class_discovery.rs b/veilid-core/src/network_manager/native/network_class_discovery.rs index c0336fdd..44fe04b5 100644 --- a/veilid-core/src/network_manager/native/network_class_discovery.rs +++ b/veilid-core/src/network_manager/native/network_class_discovery.rs @@ -22,7 +22,6 @@ impl Network { editor.clear_dial_info_details(None, None); editor.set_network_class(Some(NetworkClass::OutboundOnly)); - editor.clear_relay_node(); editor.commit(true).await; } } @@ -103,7 +102,7 @@ impl Network { ) -> EyreResult<()> { // Figure out if we can optimize TCP/WS checking since they are often on the same port let (protocol_config, tcp_same_port) = { - let inner = self.inner.lock(); + let mut inner = self.inner.lock(); let protocol_config = inner.protocol_config.clone(); let tcp_same_port = if protocol_config.inbound.contains(ProtocolType::TCP) && protocol_config.inbound.contains(ProtocolType::WS) @@ -112,6 +111,10 @@ impl Network { } else { false }; + // Allow network to be cleared if external addresses change + inner.network_already_cleared = false; + + // (protocol_config, tcp_same_port) }; @@ -125,8 +128,7 @@ impl Network { .into_iter() .collect(); - // Clear public dialinfo and network class in prep for discovery - + // Set most permissive network config let mut editor = self .routing_table() .edit_routing_domain(RoutingDomain::PublicInternet); @@ -136,11 +138,30 @@ impl Network { protocol_config.family_global, protocol_config.public_internet_capabilities.clone(), ); - editor.clear_dial_info_details(None, None); - editor.set_network_class(None); - editor.clear_relay_node(); editor.commit(true).await; + // Create a callback to clear the network if we need to 'start over' + let this = self.clone(); + let clear_network_callback: ClearNetworkCallback = Arc::new(move || { + let this = this.clone(); + Box::pin(async move { + // Ensure we only do this once per network class discovery + { + let mut inner = this.inner.lock(); + if inner.network_already_cleared { + return; + } + inner.network_already_cleared = true; + } + let mut editor = this + .routing_table() + .edit_routing_domain(RoutingDomain::PublicInternet); + editor.clear_dial_info_details(None, None); + editor.set_network_class(None); + editor.commit(true).await; + }) + }); + // Process all protocol and address combinations let mut unord = FuturesUnordered::new(); // Do UDPv4+v6 at the same time as everything else @@ -152,6 +173,7 @@ impl Network { self.clone(), ProtocolType::UDP, AddressType::IPV4, + clear_network_callback.clone(), ); udpv4_context .discover(&mut unord) @@ -166,6 +188,7 @@ impl Network { self.clone(), ProtocolType::UDP, AddressType::IPV6, + clear_network_callback.clone(), ); udpv6_context .discover(&mut unord) @@ -182,6 +205,7 @@ impl Network { self.clone(), ProtocolType::TCP, AddressType::IPV4, + clear_network_callback.clone(), ); tcpv4_context .discover(&mut unord) @@ -195,6 +219,7 @@ impl Network { self.clone(), ProtocolType::WS, AddressType::IPV4, + clear_network_callback.clone(), ); wsv4_context .discover(&mut unord) @@ -211,6 +236,7 @@ impl Network { self.clone(), ProtocolType::TCP, AddressType::IPV6, + clear_network_callback.clone(), ); tcpv6_context .discover(&mut unord) @@ -225,6 +251,7 @@ impl Network { self.clone(), ProtocolType::WS, AddressType::IPV6, + clear_network_callback.clone(), ); wsv6_context .discover(&mut unord)