From 1048fc6bb99a1a29e3e29c9571a1cf6e3301bf16 Mon Sep 17 00:00:00 2001 From: Christien Rioux Date: Mon, 8 Jul 2024 18:26:26 -0400 Subject: [PATCH] add StartupDisposition to handle waiting for binding without reporting errors --- veilid-core/src/attachment_manager.rs | 95 ++-- veilid-core/src/network_manager/mod.rs | 43 +- veilid-core/src/network_manager/native/mod.rs | 416 +++++++++--------- .../src/network_manager/native/network_tcp.rs | 7 +- .../src/network_manager/native/network_udp.rs | 7 +- .../network_manager/native/start_protocols.rs | 46 +- veilid-core/src/network_manager/wasm/mod.rs | 145 +++--- .../routing_table/routing_domain_editor.rs | 32 +- 8 files changed, 441 insertions(+), 350 deletions(-) diff --git a/veilid-core/src/attachment_manager.rs b/veilid-core/src/attachment_manager.rs index a2254429..6a1a3a55 100644 --- a/veilid-core/src/attachment_manager.rs +++ b/veilid-core/src/attachment_manager.rs @@ -219,46 +219,61 @@ impl AttachmentManager { let netman = self.network_manager(); let mut restart; - loop { + let mut restart_delay; + while self.inner.lock().maintain_peers { restart = false; - if let Err(err) = netman.startup().await { - error!("network startup failed: {}", err); - netman.shutdown().await; - restart = true; - } else { - log_net!(debug "started maintaining peers"); - while self.inner.lock().maintain_peers { - // tick network manager - if let Err(err) = netman.tick().await { - error!("Error in network manager: {}", err); - self.inner.lock().maintain_peers = false; - restart = true; - break; + restart_delay = 1; + + match netman.startup().await { + Err(err) => { + error!("network startup failed: {}", err); + restart = true; + } + Ok(StartupDisposition::BindRetry) => { + info!("waiting for network to bind..."); + restart = true; + restart_delay = 10; + } + Ok(StartupDisposition::Success) => { + log_net!(debug "started maintaining peers"); + + while self.inner.lock().maintain_peers { + // tick network manager + let next_tick_ts = get_timestamp() + 1_000_000u64; + if let Err(err) = netman.tick().await { + error!("Error in network manager: {}", err); + self.inner.lock().maintain_peers = false; + restart = true; + break; + } + + // see if we need to restart the network + if netman.network_needs_restart() { + info!("Restarting network"); + restart = true; + break; + } + + // Update attachment and network readiness state + // and possibly send a VeilidUpdate::Attachment + self.update_attachment(); + + // sleep should be at the end in case maintain_peers changes state + let wait_duration = next_tick_ts + .saturating_sub(get_timestamp()) + .clamp(0, 1_000_000u64); + sleep((wait_duration / 1_000) as u32).await; + } + log_net!(debug "stopped maintaining peers"); + + if !restart { + self.update_attaching_detaching_state(AttachmentState::Detaching); + log_net!(debug "attachment stopping"); } - // see if we need to restart the network - if netman.network_needs_restart() { - info!("Restarting network"); - restart = true; - break; - } - - // Update attachment and network readiness state - // and possibly send a VeilidUpdate::Attachment - self.update_attachment(); - - // sleep should be at the end in case maintain_peers changes state - sleep(1000).await; + log_net!(debug "stopping network"); + netman.shutdown().await; } - log_net!(debug "stopped maintaining peers"); - - if !restart { - self.update_attaching_detaching_state(AttachmentState::Detaching); - log_net!(debug "attachment stopping"); - } - - log_net!(debug "stopping network"); - netman.shutdown().await; } if !restart { @@ -266,8 +281,14 @@ impl AttachmentManager { } log_net!(debug "completely restarting attachment"); + // chill out for a second first, give network stack time to settle out - sleep(1000).await; + for _ in 0..restart_delay { + if !self.inner.lock().maintain_peers { + break; + } + sleep(1000).await; + } } self.update_attaching_detaching_state(AttachmentState::Detached); diff --git a/veilid-core/src/network_manager/mod.rs b/veilid-core/src/network_manager/mod.rs index fd46ebf7..3e7bd2ae 100644 --- a/veilid-core/src/network_manager/mod.rs +++ b/veilid-core/src/network_manager/mod.rs @@ -136,6 +136,12 @@ enum SendDataToExistingFlowResult { NotSent(Vec), } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum StartupDisposition { + Success, + BindRetry, +} + // The mutable state of the network manager struct NetworkManagerInner { stats: NetworkManagerStats, @@ -388,10 +394,10 @@ impl NetworkManager { } #[instrument(level = "debug", skip_all, err)] - pub async fn internal_startup(&self) -> EyreResult<()> { + pub async fn internal_startup(&self) -> EyreResult { if self.unlocked_inner.components.read().is_some() { log_net!(debug "NetworkManager::internal_startup already started"); - return Ok(()); + return Ok(StartupDisposition::Success); } // Clean address filter for things that should not be persistent @@ -423,26 +429,37 @@ impl NetworkManager { // Start network components connection_manager.startup().await; - net.startup().await?; + match net.startup().await? { + StartupDisposition::Success => {} + StartupDisposition::BindRetry => { + return Ok(StartupDisposition::BindRetry); + } + } rpc_processor.startup().await?; receipt_manager.startup().await?; log_net!("NetworkManager::internal_startup end"); - Ok(()) + Ok(StartupDisposition::Success) } #[instrument(level = "debug", skip_all, err)] - pub async fn startup(&self) -> EyreResult<()> { - if let Err(e) = self.internal_startup().await { - self.shutdown().await; - return Err(e); + pub async fn startup(&self) -> EyreResult { + match self.internal_startup().await { + Ok(StartupDisposition::Success) => { + // Inform api clients that things have changed + self.send_network_update(); + Ok(StartupDisposition::Success) + } + Ok(StartupDisposition::BindRetry) => { + self.shutdown().await; + Ok(StartupDisposition::BindRetry) + } + Err(e) => { + self.shutdown().await; + Err(e) + } } - - // Inform api clients that things have changed - self.send_network_update(); - - Ok(()) } #[instrument(level = "debug", skip_all)] diff --git a/veilid-core/src/network_manager/native/mod.rs b/veilid-core/src/network_manager/native/mod.rs index fefe2224..815ed96f 100644 --- a/veilid-core/src/network_manager/native/mod.rs +++ b/veilid-core/src/network_manager/native/mod.rs @@ -709,216 +709,238 @@ impl Network { ///////////////////////////////////////////////////////////////// - #[instrument(level = "debug", err, skip_all)] - pub async fn startup(&self) -> EyreResult<()> { - self.inner.lock().network_started = None; - let startup_func = async { - // initialize interfaces - self.unlocked_inner.interfaces.refresh().await?; + pub async fn startup_internal(&self) -> EyreResult { + // initialize interfaces + self.unlocked_inner.interfaces.refresh().await?; - // build the set of networks we should consider for the 'LocalNetwork' routing domain - let mut local_networks: HashSet<(IpAddr, IpAddr)> = HashSet::new(); - self.unlocked_inner - .interfaces - .with_interfaces(|interfaces| { - log_net!(debug "interfaces: {:#?}", interfaces); + // build the set of networks we should consider for the 'LocalNetwork' routing domain + let mut local_networks: HashSet<(IpAddr, IpAddr)> = HashSet::new(); + self.unlocked_inner + .interfaces + .with_interfaces(|interfaces| { + log_net!(debug "interfaces: {:#?}", interfaces); - for intf in interfaces.values() { - // Skip networks that we should never encounter - if intf.is_loopback() || !intf.is_running() { - continue; - } - // Add network to local networks table - for addr in &intf.addrs { - let netmask = addr.if_addr().netmask(); - let network_ip = ipaddr_apply_netmask(addr.if_addr().ip(), netmask); - local_networks.insert((network_ip, netmask)); - } + for intf in interfaces.values() { + // Skip networks that we should never encounter + if intf.is_loopback() || !intf.is_running() { + continue; } - }); - let local_networks: Vec<(IpAddr, IpAddr)> = local_networks.into_iter().collect(); - self.unlocked_inner - .routing_table - .configure_local_network_routing_domain(local_networks); - - // determine if we have ipv4/ipv6 addresses - { - let mut inner = self.inner.lock(); - - let stable_interface_addresses = self.get_stable_interface_addresses(); - - inner.enable_ipv4 = false; - for addr in stable_interface_addresses.iter().copied() { - if addr.is_ipv4() { - log_net!(debug "enable address {:?} as ipv4", addr); - inner.enable_ipv4 = true; - } else if addr.is_ipv6() { - let address = Address::from_ip_addr(addr); - if address.is_global() { - log_net!(debug "enable address {:?} as ipv6 global", address); - inner.enable_ipv6_global = true; - } else if address.is_local() { - log_net!(debug "enable address {:?} as ipv6 local", address); - inner.enable_ipv6_local = true; - } + // Add network to local networks table + for addr in &intf.addrs { + let netmask = addr.if_addr().netmask(); + let network_ip = ipaddr_apply_netmask(addr.if_addr().ip(), netmask); + local_networks.insert((network_ip, netmask)); } } - inner.stable_interface_addresses_at_startup = stable_interface_addresses; - } + }); + let local_networks: Vec<(IpAddr, IpAddr)> = local_networks.into_iter().collect(); + self.unlocked_inner + .routing_table + .configure_local_network_routing_domain(local_networks); - // Build our protocol config to share it with other nodes - let protocol_config = { - let mut inner = self.inner.lock(); + // determine if we have ipv4/ipv6 addresses + { + let mut inner = self.inner.lock(); - // Create stop source - inner.stop_source = Some(StopSource::new()); + let stable_interface_addresses = self.get_stable_interface_addresses(); - // get protocol config - let protocol_config = { - let c = self.config.get(); - let mut inbound = ProtocolTypeSet::new(); - - if c.network.protocol.udp.enabled { - inbound.insert(ProtocolType::UDP); + inner.enable_ipv4 = false; + for addr in stable_interface_addresses.iter().copied() { + if addr.is_ipv4() { + log_net!(debug "enable address {:?} as ipv4", addr); + inner.enable_ipv4 = true; + } else if addr.is_ipv6() { + let address = Address::from_ip_addr(addr); + if address.is_global() { + log_net!(debug "enable address {:?} as ipv6 global", address); + inner.enable_ipv6_global = true; + } else if address.is_local() { + log_net!(debug "enable address {:?} as ipv6 local", address); + inner.enable_ipv6_local = true; } - if c.network.protocol.tcp.listen { - inbound.insert(ProtocolType::TCP); - } - if c.network.protocol.ws.listen { - inbound.insert(ProtocolType::WS); - } - if c.network.protocol.wss.listen { - inbound.insert(ProtocolType::WSS); - } - - let mut outbound = ProtocolTypeSet::new(); - if c.network.protocol.udp.enabled { - outbound.insert(ProtocolType::UDP); - } - if c.network.protocol.tcp.connect { - outbound.insert(ProtocolType::TCP); - } - if c.network.protocol.ws.connect { - outbound.insert(ProtocolType::WS); - } - if c.network.protocol.wss.connect { - outbound.insert(ProtocolType::WSS); - } - - 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); - } - - // set up the routing table's network config - // if we have static public dialinfo, upgrade our network class - let public_internet_capabilities = { - PUBLIC_INTERNET_CAPABILITIES - .iter() - .copied() - .filter(|cap| !c.capabilities.disable.contains(cap)) - .collect::>() - }; - let local_network_capabilities = { - LOCAL_NETWORK_CAPABILITIES - .iter() - .copied() - .filter(|cap| !c.capabilities.disable.contains(cap)) - .collect::>() - }; - - ProtocolConfig { - outbound, - inbound, - family_global, - family_local, - public_internet_capabilities, - local_network_capabilities, - } - }; - inner.protocol_config = protocol_config.clone(); - - protocol_config - }; - - // Start editing routing table - let mut editor_public_internet = self - .unlocked_inner - .routing_table - .edit_routing_domain(RoutingDomain::PublicInternet); - let mut editor_local_network = self - .unlocked_inner - .routing_table - .edit_routing_domain(RoutingDomain::LocalNetwork); - - // start listeners - if protocol_config.inbound.contains(ProtocolType::UDP) { - self.bind_udp_protocol_handlers( - &mut editor_public_internet, - &mut editor_local_network, - ) - .await?; - } - if protocol_config.inbound.contains(ProtocolType::WS) { - self.start_ws_listeners(&mut editor_public_internet, &mut editor_local_network) - .await?; - } - if protocol_config.inbound.contains(ProtocolType::WSS) { - self.start_wss_listeners(&mut editor_public_internet, &mut editor_local_network) - .await?; - } - if protocol_config.inbound.contains(ProtocolType::TCP) { - self.start_tcp_listeners(&mut editor_public_internet, &mut editor_local_network) - .await?; - } - - editor_public_internet.setup_network( - protocol_config.outbound, - protocol_config.inbound, - protocol_config.family_global, - protocol_config.public_internet_capabilities, - ); - editor_local_network.setup_network( - protocol_config.outbound, - protocol_config.inbound, - protocol_config.family_local, - protocol_config.local_network_capabilities, - ); - let detect_address_changes = { - let c = self.config.get(); - c.network.detect_address_changes - }; - if !detect_address_changes { - let inner = self.inner.lock(); - if !inner.static_public_dialinfo.is_empty() { - editor_public_internet.set_network_class(Some(NetworkClass::InboundCapable)); } } - - // commit routing table edits - editor_public_internet.commit(true).await; - editor_local_network.commit(true).await; - - Ok(()) - }; - let res = startup_func.await; - if res.is_err() { - info!("network failed to start"); - self.inner.lock().network_started = Some(false); - return res; + inner.stable_interface_addresses_at_startup = stable_interface_addresses; } - info!("network started"); - self.inner.lock().network_started = Some(true); - Ok(()) + // Build our protocol config to share it with other nodes + let protocol_config = { + let mut inner = self.inner.lock(); + + // Create stop source + inner.stop_source = Some(StopSource::new()); + + // get protocol config + let protocol_config = { + let c = self.config.get(); + let mut inbound = ProtocolTypeSet::new(); + + if c.network.protocol.udp.enabled { + inbound.insert(ProtocolType::UDP); + } + if c.network.protocol.tcp.listen { + inbound.insert(ProtocolType::TCP); + } + if c.network.protocol.ws.listen { + inbound.insert(ProtocolType::WS); + } + if c.network.protocol.wss.listen { + inbound.insert(ProtocolType::WSS); + } + + let mut outbound = ProtocolTypeSet::new(); + if c.network.protocol.udp.enabled { + outbound.insert(ProtocolType::UDP); + } + if c.network.protocol.tcp.connect { + outbound.insert(ProtocolType::TCP); + } + if c.network.protocol.ws.connect { + outbound.insert(ProtocolType::WS); + } + if c.network.protocol.wss.connect { + outbound.insert(ProtocolType::WSS); + } + + 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); + } + + // set up the routing table's network config + // if we have static public dialinfo, upgrade our network class + let public_internet_capabilities = { + PUBLIC_INTERNET_CAPABILITIES + .iter() + .copied() + .filter(|cap| !c.capabilities.disable.contains(cap)) + .collect::>() + }; + let local_network_capabilities = { + LOCAL_NETWORK_CAPABILITIES + .iter() + .copied() + .filter(|cap| !c.capabilities.disable.contains(cap)) + .collect::>() + }; + + ProtocolConfig { + outbound, + inbound, + family_global, + family_local, + public_internet_capabilities, + local_network_capabilities, + } + }; + inner.protocol_config = protocol_config.clone(); + + protocol_config + }; + + // Start editing routing table + let mut editor_public_internet = self + .unlocked_inner + .routing_table + .edit_routing_domain(RoutingDomain::PublicInternet); + let mut editor_local_network = self + .unlocked_inner + .routing_table + .edit_routing_domain(RoutingDomain::LocalNetwork); + + // start listeners + if protocol_config.inbound.contains(ProtocolType::UDP) { + let res = self + .bind_udp_protocol_handlers(&mut editor_public_internet, &mut editor_local_network) + .await; + if !matches!(res, Ok(StartupDisposition::Success)) { + return res; + } + } + if protocol_config.inbound.contains(ProtocolType::WS) { + let res = self + .start_ws_listeners(&mut editor_public_internet, &mut editor_local_network) + .await; + if !matches!(res, Ok(StartupDisposition::Success)) { + return res; + } + } + if protocol_config.inbound.contains(ProtocolType::WSS) { + let res = self + .start_wss_listeners(&mut editor_public_internet, &mut editor_local_network) + .await; + if !matches!(res, Ok(StartupDisposition::Success)) { + return res; + } + } + if protocol_config.inbound.contains(ProtocolType::TCP) { + let res = self + .start_tcp_listeners(&mut editor_public_internet, &mut editor_local_network) + .await; + if !matches!(res, Ok(StartupDisposition::Success)) { + return res; + } + } + + editor_public_internet.setup_network( + protocol_config.outbound, + protocol_config.inbound, + protocol_config.family_global, + protocol_config.public_internet_capabilities, + ); + editor_local_network.setup_network( + protocol_config.outbound, + protocol_config.inbound, + protocol_config.family_local, + protocol_config.local_network_capabilities, + ); + let detect_address_changes = { + let c = self.config.get(); + c.network.detect_address_changes + }; + if !detect_address_changes { + let inner = self.inner.lock(); + if !inner.static_public_dialinfo.is_empty() { + editor_public_internet.set_network_class(Some(NetworkClass::InboundCapable)); + } + } + + // commit routing table edits + editor_public_internet.commit(true).await; + editor_local_network.commit(true).await; + + Ok(StartupDisposition::Success) + } + + #[instrument(level = "debug", err, skip_all)] + pub async fn startup(&self) -> EyreResult { + self.inner.lock().network_started = None; + + match self.startup_internal().await { + Ok(StartupDisposition::Success) => { + info!("network started"); + self.inner.lock().network_started = Some(true); + Ok(StartupDisposition::Success) + } + Ok(StartupDisposition::BindRetry) => { + debug!("network bind retry"); + self.inner.lock().network_started = Some(false); + Ok(StartupDisposition::BindRetry) + } + Err(e) => { + debug!("network failed to start"); + self.inner.lock().network_started = Some(false); + Err(e) + } + } } pub fn needs_restart(&self) -> bool { diff --git a/veilid-core/src/network_manager/native/network_tcp.rs b/veilid-core/src/network_manager/native/network_tcp.rs index 2eba6d3e..aeff8359 100644 --- a/veilid-core/src/network_manager/native/network_tcp.rs +++ b/veilid-core/src/network_manager/native/network_tcp.rs @@ -349,7 +349,7 @@ impl Network { bind_set: NetworkBindSet, is_tls: bool, new_protocol_accept_handler: Box, - ) -> EyreResult> { + ) -> EyreResult>> { let mut out = Vec::::new(); for ip_addr in bind_set.addrs { @@ -404,7 +404,8 @@ impl Network { } if !bind_set.search { - bail!("unable to bind to tcp {}", addr); + log_net!(debug "unable to bind to tcp {}", addr); + return Ok(None); } if port == 65535u16 { @@ -419,6 +420,6 @@ impl Network { } } - Ok(out) + Ok(Some(out)) } } diff --git a/veilid-core/src/network_manager/native/network_udp.rs b/veilid-core/src/network_manager/native/network_udp.rs index 19dbbf3c..6e082992 100644 --- a/veilid-core/src/network_manager/native/network_udp.rs +++ b/veilid-core/src/network_manager/native/network_udp.rs @@ -151,7 +151,7 @@ impl Network { pub(super) async fn create_udp_protocol_handlers( &self, bind_set: NetworkBindSet, - ) -> EyreResult> { + ) -> EyreResult>> { let mut out = Vec::::new(); for ip_addr in bind_set.addrs { @@ -175,7 +175,8 @@ impl Network { } if !bind_set.search { - bail!("unable to bind to udp {}", addr); + log_net!(debug "unable to bind to udp {}", addr); + return Ok(None); } if port == 65535u16 { @@ -189,7 +190,7 @@ impl Network { } } } - Ok(out) + Ok(Some(out)) } ///////////////////////////////////////////////////////////////// diff --git a/veilid-core/src/network_manager/native/start_protocols.rs b/veilid-core/src/network_manager/native/start_protocols.rs index bd428f0c..fc037de5 100644 --- a/veilid-core/src/network_manager/native/start_protocols.rs +++ b/veilid-core/src/network_manager/native/start_protocols.rs @@ -140,7 +140,7 @@ impl Network { &self, editor_public_internet: &mut RoutingDomainEditor, editor_local_network: &mut RoutingDomainEditor, - ) -> EyreResult<()> { + ) -> EyreResult { log_net!("UDP: binding protocol handlers"); let routing_table = self.routing_table(); let (listen_address, public_address, detect_address_changes) = { @@ -170,7 +170,10 @@ impl Network { ); } - let mut local_dial_info_list = self.create_udp_protocol_handlers(bind_set).await?; + let Some(mut local_dial_info_list) = self.create_udp_protocol_handlers(bind_set).await? + else { + return Ok(StartupDisposition::BindRetry); + }; local_dial_info_list.sort(); let mut static_public = false; @@ -241,14 +244,16 @@ impl Network { } // Now create tasks for udp listeners - self.create_udp_listener_tasks().await + self.create_udp_listener_tasks().await?; + + Ok(StartupDisposition::Success) } pub(super) async fn start_ws_listeners( &self, editor_public_internet: &mut RoutingDomainEditor, editor_local_network: &mut RoutingDomainEditor, - ) -> EyreResult<()> { + ) -> EyreResult { log_net!("WS: binding protocol handlers"); let routing_table = self.routing_table(); let (listen_address, url, path, detect_address_changes) = { @@ -277,13 +282,16 @@ impl Network { bind_set.port, bind_set.addrs ); } - let socket_addresses = self + let Some(socket_addresses) = self .start_tcp_listener( bind_set, false, Box::new(|c, t| Box::new(WebsocketProtocolHandler::new(c, t))), ) - .await?; + .await? + else { + return Ok(StartupDisposition::BindRetry); + }; log_net!("WS: protocol handlers started on {:#?}", socket_addresses); let mut static_public = false; @@ -353,14 +361,14 @@ impl Network { Self::add_preferred_local_address(&mut inner, PeerAddress::new(sa, ProtocolType::WS)); } - Ok(()) + Ok(StartupDisposition::Success) } pub(super) async fn start_wss_listeners( &self, editor_public_internet: &mut RoutingDomainEditor, editor_local_network: &mut RoutingDomainEditor, - ) -> EyreResult<()> { + ) -> EyreResult { log_net!("WSS: binding protocol handlers"); let (listen_address, url, _detect_address_changes) = { @@ -389,13 +397,17 @@ impl Network { ); } - let socket_addresses = self + let Some(socket_addresses) = self .start_tcp_listener( bind_set, true, Box::new(|c, t| Box::new(WebsocketProtocolHandler::new(c, t))), ) - .await?; + .await? + else { + return Ok(StartupDisposition::BindRetry); + }; + log_net!("WSS: protocol handlers started on {:#?}", socket_addresses); // NOTE: No interface dial info for WSS, as there is no way to connect to a local dialinfo via TLS @@ -448,14 +460,14 @@ impl Network { Self::add_preferred_local_address(&mut inner, PeerAddress::new(sa, ProtocolType::WSS)); } - Ok(()) + Ok(StartupDisposition::Success) } pub(super) async fn start_tcp_listeners( &self, editor_public_internet: &mut RoutingDomainEditor, editor_local_network: &mut RoutingDomainEditor, - ) -> EyreResult<()> { + ) -> EyreResult { log_net!("TCP: binding protocol handlers"); let routing_table = self.routing_table(); @@ -484,13 +496,17 @@ impl Network { bind_set.port, bind_set.addrs ); } - let socket_addresses = self + let Some(socket_addresses) = self .start_tcp_listener( bind_set, false, Box::new(|c, _| Box::new(RawTcpProtocolHandler::new(c))), ) - .await?; + .await? + else { + return Ok(StartupDisposition::BindRetry); + }; + log_net!("TCP: protocol handlers started on {:#?}", socket_addresses); let mut static_public = false; @@ -546,6 +562,6 @@ impl Network { Self::add_preferred_local_address(&mut inner, PeerAddress::new(sa, ProtocolType::TCP)); } - Ok(()) + Ok(StartupDisposition::Success) } } diff --git a/veilid-core/src/network_manager/wasm/mod.rs b/veilid-core/src/network_manager/wasm/mod.rs index b3576b8a..0340c9f7 100644 --- a/veilid-core/src/network_manager/wasm/mod.rs +++ b/veilid-core/src/network_manager/wasm/mod.rs @@ -333,83 +333,92 @@ impl Network { ///////////////////////////////////////////////////////////////// - pub async fn startup(&self) -> EyreResult<()> { - self.inner.lock().network_started = None; - let startup_func = async { - log_net!(debug "starting network"); - // get protocol config - let protocol_config = { - let c = self.config.get(); - let inbound = ProtocolTypeSet::new(); - let mut outbound = ProtocolTypeSet::new(); + pub async fn startup_internal(&self) -> EyreResult { + log_net!(debug "starting network"); + // get protocol config + let protocol_config = { + let c = self.config.get(); + let inbound = ProtocolTypeSet::new(); + let mut outbound = ProtocolTypeSet::new(); - if c.network.protocol.ws.connect { - outbound.insert(ProtocolType::WS); - } - if c.network.protocol.wss.connect { - outbound.insert(ProtocolType::WSS); - } + if c.network.protocol.ws.connect { + outbound.insert(ProtocolType::WS); + } + if c.network.protocol.wss.connect { + outbound.insert(ProtocolType::WSS); + } - let supported_address_types: AddressTypeSet = if is_ipv6_supported() { - AddressType::IPV4 | AddressType::IPV6 - } else { - AddressType::IPV4.into() - }; - - let family_global = supported_address_types; - let family_local = supported_address_types; - - let public_internet_capabilities = { - PUBLIC_INTERNET_CAPABILITIES - .iter() - .copied() - .filter(|cap| !c.capabilities.disable.contains(cap)) - .collect::>() - }; - - ProtocolConfig { - outbound, - inbound, - family_global, - family_local, - local_network_capabilities: vec![], - public_internet_capabilities, - } + let supported_address_types: AddressTypeSet = if is_ipv6_supported() { + AddressType::IPV4 | AddressType::IPV6 + } else { + AddressType::IPV4.into() }; - self.inner.lock().protocol_config = protocol_config.clone(); - // Start editing routing table - let mut editor_public_internet = self - .unlocked_inner - .routing_table - .edit_routing_domain(RoutingDomain::PublicInternet); + let family_global = supported_address_types; + let family_local = supported_address_types; - // set up the routing table's network config - // if we have static public dialinfo, upgrade our network class + let public_internet_capabilities = { + PUBLIC_INTERNET_CAPABILITIES + .iter() + .copied() + .filter(|cap| !c.capabilities.disable.contains(cap)) + .collect::>() + }; - editor_public_internet.setup_network( - protocol_config.outbound, - protocol_config.inbound, - protocol_config.family_global, - protocol_config.public_internet_capabilities.clone(), - ); - editor_public_internet.set_network_class(Some(NetworkClass::WebApp)); - - // commit routing table edits - editor_public_internet.commit(true).await; - Ok(()) + ProtocolConfig { + outbound, + inbound, + family_global, + family_local, + local_network_capabilities: vec![], + public_internet_capabilities, + } }; + self.inner.lock().protocol_config = protocol_config.clone(); - let res = startup_func.await; - if res.is_err() { - info!("network failed to start"); - self.inner.lock().network_started = Some(false); - return res; + // Start editing routing table + let mut editor_public_internet = self + .unlocked_inner + .routing_table + .edit_routing_domain(RoutingDomain::PublicInternet); + + // set up the routing table's network config + // if we have static public dialinfo, upgrade our network class + + editor_public_internet.setup_network( + protocol_config.outbound, + protocol_config.inbound, + protocol_config.family_global, + protocol_config.public_internet_capabilities.clone(), + ); + editor_public_internet.set_network_class(Some(NetworkClass::WebApp)); + + // commit routing table edits + editor_public_internet.commit(true).await; + + Ok(StartupDisposition::Success) + } + + pub async fn startup(&self) -> EyreResult { + self.inner.lock().network_started = None; + + match self.startup_internal().await { + Ok(StartupDisposition::Success) => { + info!("network started"); + self.inner.lock().network_started = Some(true); + Ok(StartupDisposition::Success) + } + Ok(StartupDisposition::BindRetry) => { + debug!("network bind retry"); + self.inner.lock().network_started = Some(false); + Ok(StartupDisposition::BindRetry) + } + Err(e) => { + debug!("network failed to start"); + self.inner.lock().network_started = Some(false); + Err(e) + } } - - info!("network started"); - self.inner.lock().network_started = Some(true); - Ok(()) } pub fn needs_restart(&self) -> bool { diff --git a/veilid-core/src/routing_table/routing_domain_editor.rs b/veilid-core/src/routing_table/routing_domain_editor.rs index f7976faf..30fe97df 100644 --- a/veilid-core/src/routing_table/routing_domain_editor.rs +++ b/veilid-core/src/routing_table/routing_domain_editor.rs @@ -149,19 +149,21 @@ impl RoutingDomainEditor { address_type, protocol_type, } => { - if address_type.is_some() || protocol_type.is_some() { - info!( - "[{:?}] cleared dial info: {}:{}", - self.routing_domain, - address_type - .map(|at| format!("{:?}", at)) - .unwrap_or("---".to_string()), - protocol_type - .map(|at| format!("{:?}", at)) - .unwrap_or("---".to_string()), - ); - } else { - info!("[{:?}] cleared all dial info", self.routing_domain); + if !detail.common_mut().dial_info_details().is_empty() { + if address_type.is_some() || protocol_type.is_some() { + info!( + "[{:?}] cleared dial info: {}:{}", + self.routing_domain, + address_type + .map(|at| format!("{:?}", at)) + .unwrap_or("---".to_string()), + protocol_type + .map(|at| format!("{:?}", at)) + .unwrap_or("---".to_string()), + ); + } else { + info!("[{:?}] cleared all dial info", self.routing_domain); + } } detail .common_mut() @@ -169,7 +171,9 @@ impl RoutingDomainEditor { peer_info_changed = true; } RoutingDomainChange::ClearRelayNode => { - info!("[{:?}] cleared relay node", self.routing_domain); + if detail.common_mut().relay_node().is_some() { + info!("[{:?}] cleared relay node", self.routing_domain); + } detail.common_mut().set_relay_node(None); peer_info_changed = true; }