1use crate::InterfaceId;
6use crate::dns::DNS_PORT;
7use crate::telemetry::{NetworkEventMetadata, TelemetryEvent, TelemetrySender};
8use anyhow::Context as _;
9use assert_matches::assert_matches;
10use async_utils::stream::{StreamItem, StreamWithEpitaph, Tagged, WithEpitaph as _, WithTag as _};
11use dns_server_watcher::DnsServers;
12use fidl::endpoints::{ControlHandle as _, RequestStream as _};
13use futures::StreamExt as _;
14use log::{debug, error, info, warn};
15use policy_properties::NetworkTokenExt as _;
16use std::collections::HashMap;
17use std::collections::hash_map::Entry;
18
19mod reachability;
20mod token_registry;
21
22use fidl_fuchsia_net as fnet;
23use fidl_fuchsia_net_name as fnet_name;
24use fidl_fuchsia_net_policy_properties as fnp_properties;
25use fidl_fuchsia_net_policy_socketproxy as fnp_socketproxy;
26use fidl_fuchsia_net_reachability as freachability;
27use fidl_fuchsia_posix_socket as fposix_socket;
28use fuchsia_inspect_derive::{IValue, Inspect, Unit, WithInspect as _};
29pub use reachability::ReachabilityWatcherConnectionId;
30use reachability::{ReachabilityHandler, ReachabilityStream};
31
32#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub enum NetworkId {
38 Fuchsia(InterfaceId),
39 Delegated(InterfaceId),
40}
41
42impl std::fmt::Display for NetworkId {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match self {
45 NetworkId::Fuchsia(interface_id) => write!(f, "fuchsia:{interface_id}"),
46 NetworkId::Delegated(interface_id) => write!(f, "delegated:{interface_id}"),
47 }
48 }
49}
50
51impl NetworkId {
52 pub fn get(&self) -> InterfaceId {
53 match self {
54 NetworkId::Fuchsia(interface_id) => *interface_id,
55 NetworkId::Delegated(interface_id) => *interface_id,
56 }
57 }
58
59 pub fn fuchsia<I: Into<InterfaceId>>(id: I) -> Self {
60 NetworkId::Fuchsia(id.into())
61 }
62
63 pub fn delegated<I: Into<InterfaceId>>(id: I) -> Self {
64 NetworkId::Delegated(id.into())
65 }
66
67 pub fn is_fuchsia(&self) -> bool {
68 matches!(self, NetworkId::Fuchsia(_))
69 }
70}
71
72pub(crate) fn determine_interface_state_changed(
80 prev: &fidl_fuchsia_net_interfaces::Properties,
81 curr: &fidl_fuchsia_net_interfaces_ext::Properties<
82 fidl_fuchsia_net_interfaces_ext::DefaultInterest,
83 >,
84) -> Option<bool> {
85 let was_candidate = (prev.has_default_ipv4_route.unwrap_or(curr.has_default_ipv4_route)
86 || prev.has_default_ipv6_route.unwrap_or(curr.has_default_ipv6_route))
87 && prev.online.unwrap_or(curr.online);
88 let is_candidate = (curr.has_default_ipv4_route || curr.has_default_ipv6_route) && curr.online;
89 (is_candidate != was_candidate).then_some(is_candidate)
90}
91
92#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
93pub(crate) struct NetworkTokenContents {
94 network_id: NetworkId,
95 is_default: bool,
96}
97
98macro_rules! connection_id {
104 ($id:ident => $allocator:ident) => {
105 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
107 pub struct $id(usize);
108
109 #[doc = concat!("Mints unique [`", stringify!($id), "`]s.")]
110 #[derive(Default)]
111 pub struct $allocator(usize);
112
113 impl $allocator {
114 pub fn allocate(&mut self) -> $id {
115 let id = $id(self.0);
116 self.0 += 1;
117 id
118 }
119 }
120 };
121}
122pub(crate) use connection_id;
123
124mod id {
125 connection_id!(NetworksConnectionId => NetworksConnectionIdAllocator);
127
128 connection_id!(PropertyWatcherConnectionId => PropertyWatcherConnectionIdAllocator);
130}
131
132pub use id::{NetworksConnectionId, PropertyWatcherConnectionId};
133use id::{NetworksConnectionIdAllocator, PropertyWatcherConnectionIdAllocator};
134
135#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
136pub struct UpdateGeneration {
137 default_network: usize,
140
141 properties: usize,
144}
145
146#[derive(Clone, Debug, Default)]
147pub struct UpdateGenerations {
148 default_network: HashMap<NetworksConnectionId, usize>,
149 properties: HashMap<PropertyWatcherConnectionId, usize>,
150}
151
152impl UpdateGenerations {
153 fn default_network(&self, id: &NetworksConnectionId) -> Option<usize> {
154 self.default_network.get(id).copied()
155 }
156
157 fn set_default_network(&mut self, id: NetworksConnectionId, generation: UpdateGeneration) {
158 *self.default_network.entry(id).or_default() = generation.default_network;
159 }
160
161 fn remove_default(&mut self, id: &NetworksConnectionId) -> Option<usize> {
162 self.default_network.remove(id)
163 }
164
165 fn properties(&self, id: &PropertyWatcherConnectionId) -> Option<usize> {
166 self.properties.get(id).copied()
167 }
168
169 fn set_properties(&mut self, id: PropertyWatcherConnectionId, generation: UpdateGeneration) {
170 *self.properties.entry(id).or_default() = generation.properties;
171 }
172
173 fn remove_properties(&mut self, id: &PropertyWatcherConnectionId) -> Option<usize> {
174 self.properties.remove(id)
175 }
176}
177
178trait SetMark {
179 fn set_mark(&mut self, domain: fnet::MarkDomain, value: Option<u32>);
180}
181
182impl SetMark for fnet::Marks {
183 fn set_mark(&mut self, domain: fnet::MarkDomain, value: Option<u32>) {
184 match domain {
185 fnet::MarkDomain::Mark1 => self.mark_1 = value,
186 fnet::MarkDomain::Mark2 => self.mark_2 = value,
187 }
188 }
189}
190
191#[derive(Debug)]
194struct Registration {
195 token: fnp_properties::NetworkToken,
196 properties: fnp_properties::PropertyInterest,
197 responder: Option<fnp_properties::PropertyWatcherWatchResponder>,
198 control_handle: fnp_properties::PropertyWatcherControlHandle,
201}
202
203impl Registration {
204 fn close(&mut self, epitaph: Option<zx::Status>) {
209 match epitaph {
212 Some(status) => self.control_handle.shutdown_with_epitaph(status),
213 None => self.control_handle.shutdown(),
214 }
215 self.responder = None;
217 }
218}
219
220#[derive(Debug)]
222struct NetworksClient {
223 responder: Option<fnp_properties::NetworksWatchDefaultResponder>,
225 control_handle: fnp_properties::NetworksControlHandle,
228}
229
230impl NetworksClient {
231 fn close(&mut self, epitaph: Option<zx::Status>) {
236 match epitaph {
239 Some(status) => self.control_handle.shutdown_with_epitaph(status),
240 None => self.control_handle.shutdown(),
241 }
242 self.responder = None;
244 }
245}
246
247#[derive(Debug, PartialEq, Default, Clone)]
248struct NetworkProperties {
249 socket_marks: Option<fnet::Marks>,
250 dns_servers: Vec<fnet_name::DnsServer_>,
251 #[allow(dead_code)]
253 connectivity_state: Option<fnp_socketproxy::ConnectivityState>,
254 name: Option<String>,
255 network_type: Option<fnp_socketproxy::NetworkType>,
256}
257
258impl NetworkProperties {
259 fn get_marks(&self) -> Option<&fnet::Marks> {
260 self.socket_marks.as_ref()
261 }
262}
263
264#[derive(Default, Clone)]
266struct RegisteredNetworks {
267 default_network: Option<NetworkId>,
270 starnix_default: Option<NetworkId>,
272 networks: HashMap<NetworkId, NetworkProperties>,
273 dns_servers: Vec<fnet_name::DnsServer_>,
274}
275
276impl RegisteredNetworks {
277 fn calculate_active_default(&self) -> Option<NetworkId> {
281 let first_fuchsia = self.networks.keys().filter(|id| id.is_fuchsia()).cloned().min();
284 if let Some(fd) = first_fuchsia {
285 return Some(fd);
286 }
287
288 if let Some(starnix_default) = self.starnix_default {
290 assert!(self.networks.contains_key(&starnix_default));
292 }
293 self.starnix_default
294 }
295
296 fn handle_default_network_update(&mut self) -> Option<DefaultChangedEvent> {
301 let next_default = self.calculate_active_default();
302 if next_default != self.default_network {
303 let old_default = self.default_network;
304 self.default_network = next_default;
305 Some(DefaultChangedEvent { previous_default: old_default })
306 } else {
307 None
308 }
309 }
310
311 fn apply(&mut self, update: NetworkRegistryUpdate) -> RegistryUpdateResult {
312 match update {
313 NetworkRegistryUpdate::UnsetDefaultNetwork => {
314 self.starnix_default = None;
316 RegistryUpdateResult {
317 event: UpdateApplied::None,
318 default_changed: self.handle_default_network_update(),
319 }
320 }
321 NetworkRegistryUpdate::ChangeNetwork(network_id, network_change) => {
322 match network_change {
323 NetworkUpdate::Properties(event) => RegistryUpdateResult {
324 event: self.handle_changed_network(network_id, event),
325 default_changed: self.handle_default_network_update(),
326 },
327 NetworkUpdate::Remove => {
328 if self.starnix_default == Some(network_id) {
329 error!("Cannot remove the default delegated network. Update ignored.");
330 RegistryUpdateResult {
331 event: UpdateApplied::None,
332 default_changed: None,
333 }
334 } else if self.networks.remove(&network_id).is_some() {
335 RegistryUpdateResult {
337 event: UpdateApplied::NetworkRemoved(network_id),
338 default_changed: self.handle_default_network_update(),
339 }
340 } else {
341 error!(
342 "Cannot remove a non-existent network ({network_id:?}). \
343 Update ignored."
344 );
345 RegistryUpdateResult {
346 event: UpdateApplied::None,
347 default_changed: None,
348 }
349 }
350 }
351 NetworkUpdate::MakeDefault => {
352 match network_id {
353 NetworkId::Fuchsia(_) => {}
356 NetworkId::Delegated(_) => self.starnix_default = Some(network_id),
357 }
358 let default_changed = self.handle_default_network_update();
359 RegistryUpdateResult { event: UpdateApplied::None, default_changed }
360 }
361 }
362 }
363 NetworkRegistryUpdate::UpdateDns(dns_servers) => {
364 let event = if self.dns_servers != dns_servers {
365 self.dns_servers = dns_servers;
366 UpdateApplied::DnsChanged
367 } else {
368 UpdateApplied::None
369 };
370 RegistryUpdateResult { event, default_changed: None }
371 }
372 }
373 }
374
375 fn handle_changed_network(
380 &mut self,
381 network_id: NetworkId,
382 event: NetworkPropertiesChange,
383 ) -> UpdateApplied {
384 let NetworkPropertiesChange {
385 added,
386 marks: socket_marks,
387 dns_servers: changed_dns_servers,
388 connectivity_state,
389 name,
390 network_type,
391 } = event;
392 let entry = self.networks.entry(network_id);
393 let result = match (added, &entry, network_id, socket_marks) {
394 (true, Entry::Occupied(_), _, _) => Err("add already added network"),
395 (false, Entry::Vacant(_), _, _) => Err("update a non-added network"),
396 (_, _, NetworkId::Fuchsia(_), Some(_)) => Err("have a fuchsia network with marks"),
397 (_, _, NetworkId::Delegated(_), None) => Err("have a delegated network without marks"),
398 (_, entry, NetworkId::Fuchsia(_), None) => {
399 let new_dns = changed_dns_servers.unwrap_or_default();
400 let changed_dns = match entry {
401 Entry::Occupied(e) => e.get().dns_servers != new_dns,
402 Entry::Vacant(_) => true,
405 };
406 Ok((
407 NetworkProperties { dns_servers: new_dns, ..Default::default() },
408 added,
409 changed_dns,
410 ))
411 }
412 (_, entry, NetworkId::Delegated(_), Some(socket_marks)) => {
413 let new_dns = changed_dns_servers.unwrap_or_default();
414 let (changed_marks, changed_dns) = match entry {
415 Entry::Occupied(e) => {
416 (e.get().get_marks() != Some(&socket_marks), e.get().dns_servers != new_dns)
417 }
418 Entry::Vacant(_) => (true, true),
421 };
422 Ok((
423 NetworkProperties {
424 socket_marks: Some(socket_marks),
425 dns_servers: new_dns,
426 ..Default::default()
427 },
428 changed_marks,
429 changed_dns,
430 ))
431 }
432 };
433
434 match result {
435 Ok((mut properties, changed_marks, changed_dns)) => {
436 properties.connectivity_state = connectivity_state;
437 properties.network_type = network_type;
438 properties.name = name.clone();
439 let _ = entry.insert_entry(properties);
440 UpdateApplied::NetworkChanged {
441 network_id,
442 added,
443 changed_marks,
444 changed_dns,
445 name,
446 network_type,
447 }
448 }
449 Err(e) => {
450 error!("Cannot {e}. Update ignored.");
451 UpdateApplied::None
452 }
453 }
454 }
455
456 pub fn consolidated_dns_servers(&self) -> Vec<fnet_name::DnsServer_> {
461 if let Some(NetworkId::Fuchsia(if_id)) = self.default_network {
462 self.networks
463 .get(&NetworkId::Fuchsia(if_id))
464 .map(|p| p.dns_servers.clone())
465 .unwrap_or_default()
466 } else {
467 self.networks
468 .iter()
469 .filter(|(id, _)| matches!(id, NetworkId::Delegated(_)))
470 .flat_map(|(_, p)| &p.dns_servers)
471 .cloned()
472 .collect()
473 }
474 }
475
476 fn update_inspect(&self, node: &fuchsia_inspect::Node) {
477 node.clear_recorded();
478
479 if let Some(default_network) = &self.default_network {
480 node.record_string("default_network", default_network.to_string());
481 }
482
483 if let Some(starnix_default) = &self.starnix_default {
484 node.record_string("starnix_default", starnix_default.to_string());
485 }
486
487 let mut sorted_networks: Vec<_> = self.networks.iter().collect();
488 sorted_networks.sort_by_key(|(id, _)| *id);
489
490 for (network_id, properties) in sorted_networks {
491 let network_node_name = match network_id {
492 NetworkId::Fuchsia(InterfaceId(id)) => format!("fuchsia_{id}"),
493 NetworkId::Delegated(InterfaceId(id)) => {
494 format!("delegated_{id}")
495 }
496 };
497
498 node.record_child(network_node_name, |net_node| {
499 if let Some(name) = &properties.name {
500 net_node.record_string("name", name);
501 }
502 if let Some(network_type) = &properties.network_type {
503 net_node.record_string("network_type", network_type.as_str());
504 }
505 if let Some(connectivity_state) = &properties.connectivity_state {
506 net_node.record_string("connectivity_state", connectivity_state.as_str());
507 }
508 });
509 }
510 }
511}
512
513trait NetworkTypeInspectExt {
514 fn as_str(&self) -> &'static str;
515}
516
517impl NetworkTypeInspectExt for fnp_socketproxy::NetworkType {
518 fn as_str(&self) -> &'static str {
519 match self {
520 fnp_socketproxy::NetworkType::Unknown => "Unknown",
521 fnp_socketproxy::NetworkType::Ethernet => "Ethernet",
522 fnp_socketproxy::NetworkType::Wifi => "Wifi",
523 fnp_socketproxy::NetworkType::Bluetooth => "Bluetooth",
524 fnp_socketproxy::NetworkType::Cellular => "Cellular",
525 fnp_socketproxy::NetworkType::__SourceBreaking { .. } => "Unknown",
526 }
527 }
528}
529
530trait ConnectivityStateInspectExt {
531 fn as_str(&self) -> &'static str;
532}
533
534impl ConnectivityStateInspectExt for fnp_socketproxy::ConnectivityState {
535 fn as_str(&self) -> &'static str {
536 match self {
537 fnp_socketproxy::ConnectivityState::NoConnectivity => "NoConnectivity",
538 fnp_socketproxy::ConnectivityState::LocalConnectivity => "LocalConnectivity",
539 fnp_socketproxy::ConnectivityState::PartialConnectivity => "PartialConnectivity",
540 fnp_socketproxy::ConnectivityState::FullConnectivity => "FullConnectivity",
541 fnp_socketproxy::ConnectivityState::__SourceBreaking { .. } => "Unknown",
542 }
543 }
544}
545
546trait PropertyUpdates {
548 fn add_socket_marks(
549 &mut self,
550 network_registry: &RegisteredNetworks,
551 network: &NetworkTokenContents,
552 watched_properties: fnp_properties::PropertyInterest,
553 );
554 fn add_dns(
555 &mut self,
556 network_registry: &RegisteredNetworks,
557 network: &NetworkTokenContents,
558 watched_properties: fnp_properties::PropertyInterest,
559 );
560}
561
562impl PropertyUpdates for fnp_properties::PropertyUpdate {
563 fn add_socket_marks(
564 &mut self,
565 network_registry: &RegisteredNetworks,
566 network: &NetworkTokenContents,
567 watched_properties: fnp_properties::PropertyInterest,
568 ) {
569 if !watched_properties.contains(fnp_properties::PropertyInterest::SOCKET_MARKS) {
570 return;
571 }
572
573 match network_registry.networks.get(&network.network_id) {
574 Some(network) => {
575 if let Some(socket_marks) = network.get_marks() {
576 self.socket_marks = Some(socket_marks.clone());
577 }
578 return;
579 }
580 None => {
581 error!(
582 "State is inconsistent. We attempted to add marks for a \
583 network that is not known: {:?}",
584 network.network_id
585 );
586 }
587 }
588 }
589
590 fn add_dns(
591 &mut self,
592 network_registry: &RegisteredNetworks,
593 network: &NetworkTokenContents,
594 watched_properties: fnp_properties::PropertyInterest,
595 ) {
596 if !watched_properties.contains(fnp_properties::PropertyInterest::DNS_CONFIGURATION) {
597 return;
598 }
599
600 let interface_id = network.network_id;
601 self.dns_configuration = Some(fnp_properties::DnsConfiguration {
602 servers: Some(
603 network_registry
604 .dns_servers
605 .iter()
606 .filter(|d| {
607 match &d.source {
608 Some(source) => match source {
609 fnet_name::DnsServerSource::StaticSource(_) => true,
610 fnet_name::DnsServerSource::SocketProxy(
614 fnet_name::SocketProxyDnsServerSource {
615 source_interface, ..
616 },
617 ) => match (interface_id, source_interface) {
618 (_, None) => true,
619 (id1, Some(id2)) => {
620 Ok(id1)
621 == InterfaceId::try_from(*id2)
622 .map(|id| NetworkId::delegated(id))
623 }
624 },
625 fnet_name::DnsServerSource::Dhcp(
626 fnet_name::DhcpDnsServerSource { source_interface, .. },
627 )
628 | fnet_name::DnsServerSource::Ndp(
629 fnet_name::NdpDnsServerSource { source_interface, .. },
630 )
631 | fnet_name::DnsServerSource::Dhcpv6(
632 fnet_name::Dhcpv6DnsServerSource { source_interface, .. },
633 ) => match (interface_id, source_interface) {
634 (_, None) => true,
635 (id1, Some(id2)) => {
636 Ok(id1)
637 == InterfaceId::try_from(*id2)
638 .map(|id| NetworkId::fuchsia(id))
639 }
640 },
641
642 _ => {
643 error!("unhandled DnsServerSource: {source:?}");
644 false
645 }
646 },
647
648 None => true,
650 }
651 })
652 .cloned()
653 .collect::<Vec<_>>(),
654 ),
655 ..Default::default()
656 });
657 }
658}
659
660#[derive(Clone, Debug, Default)]
662pub struct NetworkPropertiesChange {
663 pub added: bool,
666 pub marks: Option<fnet::Marks>,
668 pub dns_servers: Option<Vec<fnet_name::DnsServer_>>,
670 pub connectivity_state: Option<fnp_socketproxy::ConnectivityState>,
672 pub name: Option<String>,
674 pub network_type: Option<fnp_socketproxy::NetworkType>,
676}
677
678#[derive(Debug, Clone)]
679pub enum NetworkUpdate {
680 Properties(NetworkPropertiesChange),
682 Remove,
683 MakeDefault,
684}
685
686#[derive(Debug, PartialEq, Eq, Clone)]
687struct DefaultChangedEvent {
688 previous_default: Option<NetworkId>,
689}
690
691#[derive(Debug, PartialEq, Eq)]
692struct RegistryUpdateResult {
693 event: UpdateApplied,
694 default_changed: Option<DefaultChangedEvent>,
697}
698
699#[derive(Debug, PartialEq, Eq, Clone)]
700enum UpdateApplied {
701 None,
703
704 DnsChanged,
706
707 NetworkChanged {
709 network_id: NetworkId,
710 added: bool,
711 changed_marks: bool,
712 changed_dns: bool,
713 name: Option<String>,
714 network_type: Option<fnp_socketproxy::NetworkType>,
715 },
716
717 NetworkRemoved(NetworkId),
719}
720
721#[derive(Debug, Clone)]
722pub enum NetworkRegistryUpdate {
723 UnsetDefaultNetwork,
724 ChangeNetwork(NetworkId, NetworkUpdate),
725 UpdateDns(Vec<fnet_name::DnsServer_>),
726}
727
728impl NetworkRegistryUpdate {
729 pub fn unset_default() -> Self {
730 NetworkRegistryUpdate::UnsetDefaultNetwork
731 }
732
733 pub fn dns(dns_servers: &DnsServers) -> Self {
734 NetworkRegistryUpdate::UpdateDns(dns_servers.consolidated_dns_servers())
737 }
738}
739
740struct ValidatedNetwork {
747 network_id: NetworkId,
748 marks: fnet::Marks,
749 dns_servers: Vec<fnet_name::DnsServer_>,
750 connectivity: Option<fnp_socketproxy::ConnectivityState>,
751 name: Option<String>,
752 network_type: Option<fnp_socketproxy::NetworkType>,
753}
754
755#[derive(Debug, PartialEq, Eq)]
756enum NetworkValidationError {
757 MissingNetworkId,
758 MissingNetworkInfo,
759}
760
761impl From<NetworkValidationError> for fnp_socketproxy::NetworkRegistryAddError {
762 fn from(error: NetworkValidationError) -> Self {
763 match error {
764 NetworkValidationError::MissingNetworkId => Self::MissingNetworkId,
765 NetworkValidationError::MissingNetworkInfo => Self::MissingNetworkInfo,
766 }
767 }
768}
769
770impl From<NetworkValidationError> for fnp_socketproxy::NetworkRegistryUpdateError {
771 fn from(error: NetworkValidationError) -> Self {
772 match error {
773 NetworkValidationError::MissingNetworkId => Self::MissingNetworkId,
774 NetworkValidationError::MissingNetworkInfo => Self::MissingNetworkInfo,
775 }
776 }
777}
778
779impl TryFrom<fnp_socketproxy::Network> for ValidatedNetwork {
780 type Error = NetworkValidationError;
781
782 fn try_from(network: fnp_socketproxy::Network) -> Result<Self, Self::Error> {
783 let raw_network_id = network.network_id.ok_or(NetworkValidationError::MissingNetworkId)?;
784 let network_id = InterfaceId::try_from(raw_network_id)
785 .map(NetworkId::delegated)
786 .map_err(|_| NetworkValidationError::MissingNetworkId)?;
787 let Some(fnp_socketproxy::NetworkInfo::Starnix(info)) = network.info else {
788 return Err(NetworkValidationError::MissingNetworkInfo);
789 };
790
791 let mut marks = fnet::Marks::default();
792 marks.set_mark(fnet::MARK_DOMAIN_SO_MARK, info.mark);
793
794 let dns_servers =
795 NetpolNetworksService::extract_dns_servers(&network.dns_servers, raw_network_id.into());
796
797 Ok(Self {
798 network_id,
799 marks,
800 dns_servers,
801 connectivity: network.connectivity,
802 name: network.name,
803 network_type: network.network_type,
804 })
805 }
806}
807
808#[derive(Debug, Default, PartialEq)]
813pub struct DelegatedNetworkUpdateResult {
814 pub dns_servers: Option<Vec<fnet_name::DnsServer_>>,
817}
818
819pub enum NetworkRequestStream {
824 Networks(fnp_properties::NetworksRequestStream),
825 NetworkTokenResolver(fnp_properties::NetworkTokenResolverRequestStream),
826 PropertyWatcher {
827 connection_id: PropertyWatcherConnectionId,
828 stream: fnp_properties::PropertyWatcherRequestStream,
829 },
830 DelegatedNetworks(fnp_socketproxy::NetworkRegistryRequestStream),
831 Reachability(freachability::MonitorRequestStream),
832}
833
834impl From<fnp_properties::NetworksRequestStream> for NetworkRequestStream {
835 fn from(s: fnp_properties::NetworksRequestStream) -> Self {
836 Self::Networks(s)
837 }
838}
839impl From<fnp_properties::NetworkTokenResolverRequestStream> for NetworkRequestStream {
840 fn from(s: fnp_properties::NetworkTokenResolverRequestStream) -> Self {
841 Self::NetworkTokenResolver(s)
842 }
843}
844
845impl From<fnp_socketproxy::NetworkRegistryRequestStream> for NetworkRequestStream {
846 fn from(s: fnp_socketproxy::NetworkRegistryRequestStream) -> Self {
847 Self::DelegatedNetworks(s)
848 }
849}
850
851impl From<freachability::MonitorRequestStream> for NetworkRequestStream {
852 fn from(s: freachability::MonitorRequestStream) -> Self {
853 Self::Reachability(s)
854 }
855}
856
857impl From<(PropertyWatcherConnectionId, fnp_properties::PropertyWatcherRequestStream)>
858 for NetworkRequestStream
859{
860 fn from(
861 s: (PropertyWatcherConnectionId, fnp_properties::PropertyWatcherRequestStream),
862 ) -> Self {
863 let (connection_id, stream) = s;
864 Self::PropertyWatcher { connection_id, stream }
865 }
866}
867
868pub(crate) type ConnectionStream<Id, S> = StreamWithEpitaph<Tagged<Id, S>, Id>;
873
874fn split_connection_item<Id, T>(item: StreamItem<(Id, T), Id>) -> (Id, Option<T>) {
877 match item {
878 StreamItem::Item((id, request)) => (id, Some(request)),
879 StreamItem::Epitaph(id) => (id, None),
880 }
881}
882
883type DelegatedNetworksStream = StreamWithEpitaph<fnp_socketproxy::NetworkRegistryRequestStream, ()>;
886
887enum NetworkRequestStreamInner {
890 Networks(ConnectionStream<NetworksConnectionId, fnp_properties::NetworksRequestStream>),
891 NetworkTokenResolver(fnp_properties::NetworkTokenResolverRequestStream),
892 PropertyWatcher(
893 ConnectionStream<PropertyWatcherConnectionId, fnp_properties::PropertyWatcherRequestStream>,
894 ),
895 DelegatedNetworks(DelegatedNetworksStream),
896 Reachability(ReachabilityStream),
897}
898
899impl futures::Stream for NetworkRequestStreamInner {
900 type Item = NetworkRequest;
901
902 fn poll_next(
903 mut self: std::pin::Pin<&mut Self>,
904 cx: &mut std::task::Context<'_>,
905 ) -> std::task::Poll<Option<Self::Item>> {
906 match *self {
907 NetworkRequestStreamInner::Networks(ref mut stream) => {
908 stream.poll_next_unpin(cx).map(|o| {
909 o.map(split_connection_item)
910 .map(|(id, request)| NetworkAttributesRequest { id, request })
911 .map(NetworkRequest::NetworkAttributes)
912 })
913 }
914 NetworkRequestStreamInner::NetworkTokenResolver(ref mut stream) => {
915 stream.poll_next_unpin(cx).map(|o| {
916 o.map(|request| NetworkTokenResolverRequest { request })
917 .map(NetworkRequest::NetworkTokenResolver)
918 })
919 }
920 NetworkRequestStreamInner::PropertyWatcher(ref mut stream) => {
921 stream.poll_next_unpin(cx).map(|o| {
922 o.map(split_connection_item)
923 .map(|(id, request)| PropertyWatcherRequest { id, request })
924 .map(NetworkRequest::PropertyWatcher)
925 })
926 }
927 NetworkRequestStreamInner::DelegatedNetworks(ref mut stream) => {
928 stream.poll_next_unpin(cx).map(|o| {
929 o.map(|item| match item {
930 StreamItem::Item(request) => {
931 DelegatedNetworksRequest { request: Some(request) }
932 }
933 StreamItem::Epitaph(()) => DelegatedNetworksRequest { request: None },
934 })
935 .map(NetworkRequest::DelegatedNetworks)
936 })
937 }
938 NetworkRequestStreamInner::Reachability(ref mut stream) => {
939 stream.poll_next_unpin(cx).map(|o| {
940 o.map(split_connection_item)
941 .map(|(id, request)| ReachabilityRequest { id, request })
942 .map(NetworkRequest::Reachability)
943 })
944 }
945 }
946 }
947}
948
949pub struct NetworkAttributesRequest {
953 pub id: NetworksConnectionId,
954 pub request: Option<Result<fnp_properties::NetworksRequest, fidl::Error>>,
955}
956
957pub struct NetworkTokenResolverRequest {
959 pub request: Result<fnp_properties::NetworkTokenResolverRequest, fidl::Error>,
960}
961
962pub struct PropertyWatcherRequest {
966 pub id: PropertyWatcherConnectionId,
967 pub request: Option<Result<fnp_properties::PropertyWatcherRequest, fidl::Error>>,
968}
969
970pub struct DelegatedNetworksRequest {
973 pub request: Option<Result<fnp_socketproxy::NetworkRegistryRequest, fidl::Error>>,
974}
975
976pub struct ReachabilityRequest {
979 pub id: ReachabilityWatcherConnectionId,
980 pub request: Option<Result<freachability::MonitorRequest, fidl::Error>>,
983}
984
985pub enum NetworkRequest {
988 NetworkAttributes(NetworkAttributesRequest),
989 NetworkTokenResolver(NetworkTokenResolverRequest),
990 PropertyWatcher(PropertyWatcherRequest),
991 DelegatedNetworks(DelegatedNetworksRequest),
992 Reachability(ReachabilityRequest),
993}
994
995impl futures::Stream for NetpolNetworksService {
996 type Item = NetworkRequest;
997
998 fn poll_next(
999 mut self: std::pin::Pin<&mut Self>,
1000 cx: &mut std::task::Context<'_>,
1001 ) -> std::task::Poll<Option<Self::Item>> {
1002 self.streams.poll_next_unpin(cx)
1003 }
1004}
1005
1006impl futures::stream::FusedStream for NetpolNetworksService {
1007 fn is_terminated(&self) -> bool {
1008 self.streams.is_terminated()
1009 }
1010}
1011
1012#[derive(Unit, Debug, Default, Clone)]
1013struct MethodInspect {
1014 successes: u32,
1015 errors: u32,
1016}
1017
1018#[derive(Unit, Debug, Default, Clone)]
1019struct RegistryMetrics {
1020 default_network_id: Option<u32>,
1021 adds: MethodInspect,
1022 removes: MethodInspect,
1023 set_defaults: MethodInspect,
1027 updates: MethodInspect,
1028}
1029
1030#[derive(Inspect, Default)]
1031struct OperationsMetrics {
1032 delegated: IValue<RegistryMetrics>,
1033 inspect_node: fuchsia_inspect::Node,
1034}
1035
1036impl OperationsMetrics {
1037 fn record_set_default(
1038 &mut self,
1039 result: &Result<(), fnp_socketproxy::NetworkRegistrySetDefaultError>,
1040 ) {
1041 let mut delegated = self.delegated.as_mut();
1042 match result {
1043 Ok(()) => delegated.set_defaults.successes += 1,
1044 Err(_) => delegated.set_defaults.errors += 1,
1045 }
1046 }
1047
1048 fn record_add(&mut self, result: &Result<(), fnp_socketproxy::NetworkRegistryAddError>) {
1049 let mut delegated = self.delegated.as_mut();
1050 match result {
1051 Ok(()) => delegated.adds.successes += 1,
1052 Err(_) => delegated.adds.errors += 1,
1053 }
1054 }
1055
1056 fn record_update(&mut self, result: &Result<(), fnp_socketproxy::NetworkRegistryUpdateError>) {
1057 let mut delegated = self.delegated.as_mut();
1058 match result {
1059 Ok(()) => delegated.updates.successes += 1,
1060 Err(_) => delegated.updates.errors += 1,
1061 }
1062 }
1063
1064 fn record_remove(&mut self, result: &Result<(), fnp_socketproxy::NetworkRegistryRemoveError>) {
1065 let mut delegated = self.delegated.as_mut();
1066 match result {
1067 Ok(()) => delegated.removes.successes += 1,
1068 Err(_) => delegated.removes.errors += 1,
1069 }
1070 }
1071}
1072
1073#[derive(Default)]
1074pub struct NetpolNetworksService {
1075 current_generation: UpdateGeneration,
1077 generations_by_connection: UpdateGenerations,
1079 networks_clients: HashMap<NetworksConnectionId, NetworksClient>,
1081 delegated_networks_client: Option<fnp_socketproxy::NetworkRegistryControlHandle>,
1083 tokens: token_registry::TokenRegistry<NetworkTokenContents>,
1084 property_watchers: HashMap<PropertyWatcherConnectionId, Registration>,
1086 network_registry: RegisteredNetworks,
1088 telemetry: Option<TelemetrySender>,
1089 next_networks_id: NetworksConnectionIdAllocator,
1091 next_watcher_id: PropertyWatcherConnectionIdAllocator,
1093 reachability_handler: ReachabilityHandler,
1095 streams: futures::stream::SelectAll<NetworkRequestStreamInner>,
1097
1098 metrics: OperationsMetrics,
1100 networks_inspect_node: Option<fuchsia_inspect::Node>,
1102}
1103
1104impl NetpolNetworksService {
1105 pub fn with_operations_inspect(
1106 mut self,
1107 parent: &fuchsia_inspect::Node,
1108 name: impl AsRef<str>,
1109 ) -> Result<Self, fuchsia_inspect_derive::AttachError> {
1110 self.metrics = OperationsMetrics::default().with_inspect(parent, name)?;
1111 Ok(self)
1112 }
1113
1114 pub fn with_network_registry_inspect(
1115 mut self,
1116 parent: &fuchsia_inspect::Node,
1117 name: impl AsRef<str>,
1118 ) -> Self {
1119 let network_registry_node = parent.create_child(name.as_ref());
1120 self.network_registry.update_inspect(&network_registry_node);
1121 self.networks_inspect_node = Some(network_registry_node);
1122 self
1123 }
1124
1125 pub fn with_inspect(
1126 self,
1127 telemetry_parent: &fuchsia_inspect::Node,
1128 operations_name: impl AsRef<str>,
1129 networks_parent: &fuchsia_inspect::Node,
1130 networks_name: impl AsRef<str>,
1131 ) -> Result<Self, fuchsia_inspect_derive::AttachError> {
1132 let service = self.with_operations_inspect(telemetry_parent, operations_name)?;
1133 Ok(service.with_network_registry_inspect(networks_parent, networks_name))
1134 }
1135
1136 pub fn synthesize_reachability_snapshot(&self) -> freachability::Snapshot {
1137 ReachabilityHandler::synthesize_snapshot(
1138 self.network_registry
1139 .default_network
1140 .and_then(|id| self.network_registry.networks.get(&id)),
1141 )
1142 }
1143
1144 fn maybe_notify_watchers(&mut self) {
1145 let current_snapshot = self.synthesize_reachability_snapshot();
1146 self.reachability_handler.maybe_notify_watchers(¤t_snapshot);
1147 }
1148
1149 fn handle_reachability_request(
1150 &mut self,
1151 id: ReachabilityWatcherConnectionId,
1152 request: Option<Result<freachability::MonitorRequest, fidl::Error>>,
1153 ) {
1154 let current_snapshot = self.synthesize_reachability_snapshot();
1155 self.reachability_handler.handle_request(¤t_snapshot, id, request);
1156 }
1157
1158 #[cfg(test)]
1159 pub fn reachability_watcher_count(&self) -> usize {
1160 self.reachability_handler.watcher_count()
1161 }
1162
1163 pub fn set_telemetry(&mut self, telemetry: TelemetrySender) {
1164 self.telemetry = Some(telemetry);
1165 }
1166
1167 pub fn add_stream<S: Into<NetworkRequestStream>>(&mut self, s: S) {
1168 match s.into() {
1169 NetworkRequestStream::Networks(stream) => {
1170 let id = self.next_networks_id.allocate();
1171 let previous = self.networks_clients.insert(
1172 id,
1173 NetworksClient { responder: None, control_handle: stream.control_handle() },
1174 );
1175 assert!(previous.is_none(), "networks client {id:?} is already registered");
1176 self.streams
1177 .push(NetworkRequestStreamInner::Networks(stream.tagged(id).with_epitaph(id)));
1178 }
1179 NetworkRequestStream::NetworkTokenResolver(stream) => {
1180 self.streams.push(NetworkRequestStreamInner::NetworkTokenResolver(stream));
1181 }
1182 NetworkRequestStream::DelegatedNetworks(stream) => {
1183 if self.delegated_networks_client.is_some() {
1184 warn!(
1185 "Only one connection to \
1186 fuchsia.net.policy.socketproxy/NetworkRegistry is allowed at a time"
1187 );
1188 stream.control_handle().shutdown_with_epitaph(zx::Status::ALREADY_EXISTS);
1189 } else {
1190 self.delegated_networks_client = Some(stream.control_handle());
1191 self.streams.push(NetworkRequestStreamInner::DelegatedNetworks(
1192 stream.with_epitaph(()),
1193 ));
1194 }
1195 }
1196 NetworkRequestStream::PropertyWatcher { connection_id, stream } => {
1197 self.streams.push(NetworkRequestStreamInner::PropertyWatcher(
1198 stream.tagged(connection_id).with_epitaph(connection_id),
1199 ));
1200 }
1201 NetworkRequestStream::Reachability(stream) => {
1202 if let Some(reachability_stream) = self.reachability_handler.add_stream(stream) {
1203 self.streams.push(NetworkRequestStreamInner::Reachability(reachability_stream));
1204 }
1205 }
1206 }
1207 }
1208
1209 pub async fn handle_event(
1210 &mut self,
1211 event: NetworkRequest,
1212 ) -> Result<DelegatedNetworkUpdateResult, anyhow::Error> {
1213 match event {
1214 NetworkRequest::NetworkAttributes(NetworkAttributesRequest { id, request }) => {
1215 self.handle_network_attributes_request(id, request).await?;
1216 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
1217 }
1218 NetworkRequest::NetworkTokenResolver(NetworkTokenResolverRequest { request }) => {
1219 self.handle_network_token_resolver_request(request).await?;
1220 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
1221 }
1222 NetworkRequest::DelegatedNetworks(DelegatedNetworksRequest { request }) => {
1223 Ok(self.handle_delegated_networks_update(request).await)
1224 }
1225 NetworkRequest::PropertyWatcher(PropertyWatcherRequest { id, request }) => {
1226 self.handle_property_watcher_request(id, request).await?;
1227 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
1228 }
1229 NetworkRequest::Reachability(ReachabilityRequest { id, request }) => {
1230 self.handle_reachability_request(id, request);
1231 Ok(DelegatedNetworkUpdateResult { dns_servers: None })
1232 }
1233 }
1234 }
1235
1236 pub fn consolidated_dns_servers(&self) -> Vec<fnet_name::DnsServer_> {
1238 self.network_registry.consolidated_dns_servers()
1239 }
1240
1241 pub async fn handle_network_attributes_request(
1249 &mut self,
1250 id: NetworksConnectionId,
1251 req: Option<Result<fnp_properties::NetworksRequest, fidl::Error>>,
1252 ) -> Result<(), anyhow::Error> {
1253 let mut entry = assert_matches!(
1254 self.networks_clients.entry(id),
1255 Entry::Occupied(entry) => entry,
1256 "request for unknown networks client {id:?}"
1257 );
1258
1259 let req = match req {
1260 Some(Ok(req)) => req,
1261 Some(Err(e)) => {
1262 error!("Networks client {id:?} stream error: {e}");
1266 entry.get_mut().close(None);
1267 return Ok(());
1268 }
1269 None => {
1272 let _: NetworksClient = entry.remove();
1273 let _: Option<_> = self.generations_by_connection.remove_default(&id);
1274 return Ok(());
1275 }
1276 };
1277 match req {
1278 fnp_properties::NetworksRequest::WatchDefault { responder } => {
1279 let client = entry.get_mut();
1280 if client.responder.is_some() {
1281 warn!(
1282 "Only one call to fuchsia.net.policy.properties/Networks.WatchDefault \
1283 may be active per connection"
1284 );
1285 client.close(Some(zx::Status::ALREADY_EXISTS));
1287 } else {
1288 let network_id =
1289 if self.generations_by_connection.default_network(&id).unwrap_or_default()
1290 < self.current_generation.default_network
1291 {
1292 self.network_registry.default_network
1293 } else {
1294 None
1295 };
1296 if let Some(network_id) = network_id {
1297 self.generations_by_connection
1298 .set_default_network(id, self.current_generation);
1299 let token = self
1300 .tokens
1301 .ensure_token(NetworkTokenContents { network_id, is_default: true })
1302 .get()
1303 .duplicate()
1304 .context("could not duplicate token")?;
1305 responder
1306 .send(fnp_properties::NetworksWatchDefaultResponse::Network(token))?;
1307 } else {
1308 client.responder = Some(responder);
1309 }
1310 }
1311 }
1312 fnp_properties::NetworksRequest::WatchProperties {
1313 payload:
1314 fnp_properties::NetworksWatchPropertiesRequest {
1315 network, properties, watcher, ..
1316 },
1317 responder,
1318 } => match (network, properties, watcher) {
1319 (None, _, _) | (_, None, _) | (_, _, None) => {
1320 responder.send(Err(fnp_properties::WatchError::MissingRequiredArgument))?
1321 }
1322 (Some(network), Some(properties), Some(watcher)) => {
1323 if properties == fnp_properties::PropertyInterest::default() {
1324 responder.send(Err(fnp_properties::WatchError::NoProperties))?
1325 } else {
1326 match self.tokens.get_contents(&network) {
1327 Err(e) => {
1328 warn!("Unknown network token. ({network:?}: {e})");
1329 responder
1330 .send(Err(fnp_properties::WatchError::InvalidNetworkToken))?
1331 }
1332 Ok(_network_contents) => {
1333 let watcher_stream = watcher.into_stream();
1337 let watcher_id = self.next_watcher_id.allocate();
1338 let registration = Registration {
1339 token: network,
1340 properties,
1341 responder: None,
1342 control_handle: watcher_stream.control_handle(),
1343 };
1344 let previous =
1345 self.property_watchers.insert(watcher_id, registration);
1346 assert!(
1347 previous.is_none(),
1348 "property watcher {watcher_id:?} is already registered"
1349 );
1350 self.add_stream((watcher_id, watcher_stream));
1351 responder.send(Ok(()))?;
1352 }
1353 }
1354 }
1355 }
1356 },
1357 fnp_properties::NetworksRequest::_UnknownMethod { ordinal, .. } => {
1358 warn!("Received unexpected request {ordinal}")
1359 }
1360 }
1361
1362 Ok(())
1363 }
1364
1365 pub async fn handle_property_watcher_request(
1373 &mut self,
1374 id: PropertyWatcherConnectionId,
1375 req: Option<Result<fnp_properties::PropertyWatcherRequest, fidl::Error>>,
1376 ) -> Result<(), anyhow::Error> {
1377 let mut entry = assert_matches!(
1378 self.property_watchers.entry(id),
1379 Entry::Occupied(entry) => entry,
1380 "request for unknown property watcher {id:?}"
1381 );
1382
1383 let req = match req {
1384 Some(Ok(req)) => req,
1385 Some(Err(e)) => {
1386 error!("Property watcher {id:?} stream error: {e}");
1390 entry.get_mut().close(None);
1391 return Ok(());
1392 }
1393 None => {
1396 let _: Registration = entry.remove();
1397 let _: Option<_> = self.generations_by_connection.remove_properties(&id);
1398 return Ok(());
1399 }
1400 };
1401 match req {
1402 fnp_properties::PropertyWatcherRequest::Watch { responder } => {
1403 let registration = entry.get_mut();
1404 if registration.responder.is_some() {
1405 warn!(
1406 "Only one call to \
1407 fuchsia.net.policy.properties/PropertyWatcher.Watch may be \
1408 active per connection"
1409 );
1410 registration.close(Some(zx::Status::ALREADY_EXISTS));
1412 } else {
1413 registration.responder = Some(responder);
1414 match self.tokens.get_contents(®istration.token) {
1415 Ok(network_contents) => {
1416 let is_initial =
1419 self.generations_by_connection.properties(&id).is_none();
1420 if is_initial
1421 || self
1422 .generations_by_connection
1423 .properties(&id)
1424 .unwrap_or_default()
1425 < self.current_generation.properties
1426 {
1427 let mut updates = fnp_properties::PropertyUpdate::default();
1428 updates.add_socket_marks(
1429 &self.network_registry,
1430 &network_contents,
1431 registration.properties,
1432 );
1433 updates.add_dns(
1434 &self.network_registry,
1435 &network_contents,
1436 registration.properties,
1437 );
1438 let network_is_known = self
1439 .network_registry
1440 .networks
1441 .contains_key(&network_contents.network_id);
1442 if (is_initial && network_is_known)
1443 || updates != fnp_properties::PropertyUpdate::default()
1444 {
1445 self.generations_by_connection
1446 .set_properties(id, self.current_generation);
1447 if let Some(responder) = registration.responder.take() {
1448 responder.send(Ok(&updates))?;
1449 }
1450 }
1451 }
1452 }
1453 Err(e) => {
1456 if e != zx::Status::NOT_FOUND {
1457 warn!("Unexpected error fetching token contents: {e}");
1458 }
1459 let _: Option<_> =
1460 self.generations_by_connection.remove_properties(&id);
1461 if let Some(responder) = registration.responder.take() {
1462 if let Err(e) = responder
1463 .send(Err(fnp_properties::PropertyWatcherError::NetworkGone))
1464 {
1465 warn!("Could not send to responder: {e}");
1466 }
1467 registration.close(None);
1468 }
1469 }
1470 }
1471 }
1472 }
1473 }
1474
1475 Ok(())
1476 }
1477
1478 pub async fn handle_delegated_networks_update(
1493 &mut self,
1494 update: Option<Result<fnp_socketproxy::NetworkRegistryRequest, fidl::Error>>,
1495 ) -> DelegatedNetworkUpdateResult {
1496 use fnp_socketproxy::{
1497 NetworkRegistryAddError, NetworkRegistryRemoveError, NetworkRegistryRequest,
1498 NetworkRegistrySetDefaultError, NetworkRegistryUpdateError,
1499 };
1500
1501 let control_handle = assert_matches!(
1502 self.delegated_networks_client.as_ref(),
1503 Some(control_handle) => control_handle,
1504 "request with no active delegated networks client"
1505 );
1506
1507 let req = match update {
1508 Some(Ok(req)) => req,
1509 Some(Err(e)) => {
1510 error!("Delegated networks client stream error: {e}");
1514 control_handle.shutdown();
1515 return DelegatedNetworkUpdateResult { dns_servers: None };
1516 }
1517 None => {
1520 let _: Option<_> = self.delegated_networks_client.take();
1521 return self.clear_delegated_networks().await;
1522 }
1523 };
1524
1525 let action_result = match req {
1526 NetworkRegistryRequest::SetDefault { network_id, responder } => {
1527 let set_default_result = match network_id {
1528 fposix_socket::OptionalUint32::Value(interface_id) => {
1529 match InterfaceId::try_from(interface_id) {
1530 Ok(id) => {
1531 let delegated_id = NetworkId::delegated(id);
1532 if self.network_registry.networks.contains_key(&delegated_id) {
1533 self.update(NetworkRegistryUpdate::ChangeNetwork(
1534 delegated_id,
1535 NetworkUpdate::MakeDefault,
1536 ))
1537 .await;
1538 Ok(())
1539 } else {
1540 Err(NetworkRegistrySetDefaultError::NotFound)
1541 }
1542 }
1543 Err(_) => Err(NetworkRegistrySetDefaultError::NotFound),
1544 }
1545 }
1546 fposix_socket::OptionalUint32::Unset(_) => {
1547 self.update(NetworkRegistryUpdate::unset_default()).await;
1548 Ok(())
1549 }
1550 };
1551
1552 self.metrics.record_set_default(&set_default_result);
1553
1554 self.respond_to_delegated_network_update(
1555 set_default_result,
1556 |reply| responder.send(reply),
1557 "failed to send SetDefault result",
1558 )
1559 }
1560 NetworkRegistryRequest::Add { network, responder } => {
1561 let add_result = match ValidatedNetwork::try_from(network).map_err(Into::into) {
1562 Ok(valid) => {
1563 if self.network_registry.networks.contains_key(&valid.network_id) {
1564 Err(NetworkRegistryAddError::DuplicateNetworkId)
1565 } else {
1566 self.update(NetworkRegistryUpdate::ChangeNetwork(
1567 valid.network_id,
1568 NetworkUpdate::Properties(NetworkPropertiesChange {
1569 added: true,
1570 marks: Some(valid.marks),
1571 dns_servers: Some(valid.dns_servers),
1572 connectivity_state: valid.connectivity,
1573 name: valid.name,
1574 network_type: valid.network_type,
1575 }),
1576 ))
1577 .await;
1578 Ok(())
1579 }
1580 }
1581 Err(e) => Err(e),
1582 };
1583
1584 self.metrics.record_add(&add_result);
1585
1586 self.respond_to_delegated_network_update(
1587 add_result,
1588 |reply| responder.send(reply),
1589 "failed to send Add result",
1590 )
1591 }
1592 NetworkRegistryRequest::Update { network, responder } => {
1593 let update_result = match ValidatedNetwork::try_from(network).map_err(Into::into) {
1594 Ok(valid) => {
1595 if !self.network_registry.networks.contains_key(&valid.network_id) {
1596 Err(NetworkRegistryUpdateError::NotFound)
1597 } else {
1598 self.update(NetworkRegistryUpdate::ChangeNetwork(
1599 valid.network_id,
1600 NetworkUpdate::Properties(NetworkPropertiesChange {
1601 added: false,
1602 marks: Some(valid.marks),
1603 dns_servers: Some(valid.dns_servers),
1604 connectivity_state: valid.connectivity,
1605 name: valid.name,
1606 network_type: valid.network_type,
1607 }),
1608 ))
1609 .await;
1610 Ok(())
1611 }
1612 }
1613 Err(e) => Err(e),
1614 };
1615
1616 self.metrics.record_update(&update_result);
1617
1618 self.respond_to_delegated_network_update(
1619 update_result,
1620 |reply| responder.send(reply),
1621 "failed to send Update result",
1622 )
1623 }
1624 NetworkRegistryRequest::Remove { network_id, responder } => {
1625 let remove_result = match InterfaceId::try_from(network_id) {
1626 Ok(id) => {
1627 let delegated_id = NetworkId::delegated(id);
1628 if self.network_registry.starnix_default == Some(delegated_id) {
1629 Err(NetworkRegistryRemoveError::CannotRemoveDefaultNetwork)
1630 } else if !self.network_registry.networks.contains_key(&delegated_id) {
1631 Err(NetworkRegistryRemoveError::NotFound)
1632 } else {
1633 self.update(NetworkRegistryUpdate::ChangeNetwork(
1634 delegated_id,
1635 NetworkUpdate::Remove,
1636 ))
1637 .await;
1638 Ok(())
1639 }
1640 }
1641 Err(_) => Err(NetworkRegistryRemoveError::NotFound),
1642 };
1643
1644 self.metrics.record_remove(&remove_result);
1645
1646 self.respond_to_delegated_network_update(
1647 remove_result,
1648 |reply| responder.send(reply),
1649 "failed to send Remove result",
1650 )
1651 }
1652 };
1653
1654 action_result
1655 }
1656
1657 async fn clear_delegated_networks(&mut self) -> DelegatedNetworkUpdateResult {
1661 if self.network_registry.starnix_default.is_some() {
1664 self.update(NetworkRegistryUpdate::unset_default()).await;
1665 }
1666
1667 let delegated_ids = self
1668 .network_registry
1669 .networks
1670 .keys()
1671 .filter(|id| match id {
1672 NetworkId::Delegated(_) => true,
1673 NetworkId::Fuchsia(_) => false,
1674 })
1675 .copied()
1676 .collect::<Vec<_>>();
1677
1678 for id in &delegated_ids {
1679 self.update(NetworkRegistryUpdate::ChangeNetwork(*id, NetworkUpdate::Remove)).await;
1680 }
1681
1682 DelegatedNetworkUpdateResult {
1683 dns_servers: (!delegated_ids.is_empty())
1684 .then(|| self.network_registry.consolidated_dns_servers()),
1685 }
1686 }
1687
1688 fn respond_to_delegated_network_update<E, F>(
1691 &self,
1692 operation_result: Result<(), E>,
1693 send_response: F,
1694 context_message: &'static str,
1695 ) -> DelegatedNetworkUpdateResult
1696 where
1697 F: FnOnce(Result<(), E>) -> Result<(), fidl::Error>,
1698 {
1699 let dns_servers = operation_result
1701 .as_ref()
1702 .ok()
1703 .map(|()| self.network_registry.consolidated_dns_servers());
1704
1705 if let Err(e) = send_response(operation_result) {
1707 if !e.is_closed() {
1708 error!(
1709 "Failed to send delegated network update result \
1710 for {context_message}: {e}"
1711 );
1712 }
1713 }
1714
1715 DelegatedNetworkUpdateResult { dns_servers }
1716 }
1717
1718 fn extract_dns_servers(
1723 dns_servers: &Option<fnp_socketproxy::NetworkDnsServers>,
1724 network_id: u64,
1725 ) -> Vec<fnet_name::DnsServer_> {
1726 let make_server = |address| fnet_name::DnsServer_ {
1727 address: Some(address),
1728 source: Some(fnet_name::DnsServerSource::SocketProxy(
1729 fnet_name::SocketProxyDnsServerSource {
1730 source_interface: Some(network_id),
1731 ..Default::default()
1732 },
1733 )),
1734 ..Default::default()
1735 };
1736
1737 dns_servers
1738 .as_ref()
1739 .map(|dns| {
1740 dns.v4
1741 .as_ref()
1742 .into_iter()
1743 .flatten()
1744 .map(|&address| {
1745 make_server(fnet::SocketAddress::Ipv4(fnet::Ipv4SocketAddress {
1746 address,
1747 port: DNS_PORT,
1748 }))
1749 })
1750 .chain(dns.v6.as_ref().into_iter().flatten().map(|&address| {
1751 make_server(fnet::SocketAddress::Ipv6(fnet::Ipv6SocketAddress {
1752 address,
1753 port: DNS_PORT,
1754 zone_index: 0,
1755 }))
1756 }))
1757 .collect()
1758 })
1759 .unwrap_or_default()
1760 }
1761
1762 pub(crate) async fn handle_network_token_resolver_request(
1763 &mut self,
1764 request: Result<fnp_properties::NetworkTokenResolverRequest, fidl::Error>,
1765 ) -> Result<(), anyhow::Error> {
1766 use fnp_properties::NetworkTokenResolverResolveTokenError as ResolveTokenError;
1767
1768 let request = request.context("while handling NetworkTokenResolver request")?;
1769 match request {
1770 fnp_properties::NetworkTokenResolverRequest::ResolveToken { token, responder } => {
1771 let maybe_contents = self.tokens.get_contents(&token).copied();
1772 match maybe_contents {
1773 Err(e) => {
1774 warn!("Unknown network token. ({token:?}: {e})");
1775 responder.send(Err(ResolveTokenError::InvalidNetworkToken))?;
1776 }
1777 Ok(contents) => {
1778 if contents.is_default {
1779 let query = NetworkTokenContents { is_default: false, ..contents };
1782 if let Some(tok) = self.tokens.get_token(&query) {
1783 responder.send(tok.duplicate().map_err(|e| {
1784 warn!("Encountered issue duplicating generated token. {e}");
1785 ResolveTokenError::InvalidNetworkToken
1786 }))?;
1787 } else {
1788 warn!("Requested canonical version of unregistered network.");
1789 responder.send(Err(ResolveTokenError::InvalidNetworkToken))?;
1790 }
1791 } else {
1792 responder.send(Ok(token))?;
1793 }
1794 }
1795 }
1796 }
1797 fidl_fuchsia_net_policy_properties::NetworkTokenResolverRequest::_UnknownMethod {
1798 ordinal,
1799 control_handle,
1800 method_type,
1801 ..
1802 } => warn!(
1803 "Encountered unknown method call on NetworkTokenResolver: {ordinal} \
1804 {control_handle:?} {method_type:?}"
1805 ),
1806 }
1807
1808 Ok(())
1809 }
1810
1811 async fn changed_default_network(
1812 &mut self,
1813 previous_default_network: Option<NetworkId>,
1814 property_watchers: &mut HashMap<PropertyWatcherConnectionId, Registration>,
1815 ) {
1816 for (id, registration) in property_watchers.iter_mut() {
1817 if let Ok(contents) = self.tokens.get_contents(®istration.token) {
1818 if contents.is_default {
1819 let _: Option<_> = self.generations_by_connection.remove_properties(id);
1820 if let Some(responder) = registration.responder.take() {
1821 if let Err(e) =
1822 responder.send(Err(fnp_properties::PropertyWatcherError::NetworkGone))
1823 {
1824 warn!("Could not send to responder: {e}");
1825 }
1826 registration.close(None);
1827 }
1828 }
1829 }
1830 }
1831 self.tokens.drop_if(|&c| {
1832 c.is_default && previous_default_network.is_some_and(|i| i == c.network_id)
1833 });
1834 }
1835
1836 pub async fn update(&mut self, update: NetworkRegistryUpdate) {
1837 let RegistryUpdateResult { event, default_changed } = self.network_registry.apply(update);
1838
1839 if default_changed.is_some() {
1840 self.metrics.delegated.as_mut().default_network_id =
1841 self.network_registry.starnix_default.map(|id| id.get().get() as u32);
1842 }
1843 if let Some(networks_node) = &self.networks_inspect_node {
1844 self.network_registry.update_inspect(networks_node);
1845 }
1846
1847 if let UpdateApplied::None = event {
1848 if default_changed.is_none() {
1849 return;
1851 }
1852 }
1853
1854 if event != UpdateApplied::None {
1855 self.current_generation.properties += 1;
1856 }
1857
1858 let mut property_watchers = HashMap::new();
1859 std::mem::swap(&mut self.property_watchers, &mut property_watchers);
1860
1861 match event {
1863 UpdateApplied::NetworkChanged { network_id, added: true, .. } => {
1864 let _ = self
1865 .tokens
1866 .ensure_token(NetworkTokenContents { network_id, is_default: false });
1867 }
1868 UpdateApplied::NetworkRemoved(network_id) => {
1869 info!("Removing network {network_id}. Reporting NETWORK_GONE to watchers.");
1870 for (id, registration) in property_watchers.iter_mut() {
1874 if let Ok(network) = self.tokens.get_contents(®istration.token) {
1875 if network.network_id == network_id {
1876 let _: Option<_> = self.generations_by_connection.remove_properties(id);
1877 if let Some(responder) = registration.responder.take() {
1878 if let Err(e) = responder
1879 .send(Err(fnp_properties::PropertyWatcherError::NetworkGone))
1880 {
1881 warn!("Could not send to responder: {e}");
1882 }
1883 registration.close(None);
1884 }
1885 }
1886 }
1887 }
1888 self.tokens.drop_if(|c| !c.is_default && c.network_id == network_id);
1889 }
1890 UpdateApplied::NetworkChanged { added: false, .. }
1891 | UpdateApplied::DnsChanged
1892 | UpdateApplied::None => {}
1893 }
1894
1895 if let Some(DefaultChangedEvent { previous_default }) = default_changed {
1897 self.notify_default_network_changed(previous_default, &mut property_watchers).await;
1898 std::mem::swap(&mut self.property_watchers, &mut property_watchers);
1899 self.maybe_notify_watchers();
1900 return;
1901 }
1902
1903 if let UpdateApplied::NetworkChanged { network_id, .. } = event {
1904 if let Some(telemetry) = &self.telemetry {
1905 if let Some(props) = self.network_registry.networks.get(&network_id) {
1906 telemetry.send(TelemetryEvent::NetworkChanged(NetworkEventMetadata {
1907 id: network_id.get().get(),
1908 name: props.name.clone(),
1909 transport: props
1910 .network_type
1911 .unwrap_or(fnp_socketproxy::NetworkType::Unknown),
1912 is_fuchsia_provisioned: network_id.is_fuchsia(),
1913 connectivity_state: props.connectivity_state,
1914 }));
1915 }
1916 }
1917 }
1918
1919 for (id, mut registration) in property_watchers {
1920 let mut updates = fnp_properties::PropertyUpdate::default();
1921 match self.tokens.get_contents(®istration.token) {
1922 Ok(network) => match event {
1923 UpdateApplied::NetworkChanged {
1924 network_id,
1925 changed_marks,
1926 changed_dns,
1927 ..
1928 } => {
1929 if network.network_id == network_id {
1930 if changed_marks {
1931 updates.add_socket_marks(
1932 &self.network_registry,
1933 &network,
1934 registration.properties,
1935 );
1936 }
1937 if changed_dns {
1938 updates.add_dns(
1939 &self.network_registry,
1940 &network,
1941 registration.properties,
1942 );
1943 }
1944 }
1945 }
1946 UpdateApplied::DnsChanged => {
1947 updates.add_dns(&self.network_registry, &network, registration.properties);
1948 }
1949 UpdateApplied::NetworkRemoved(_id) => {}
1950 UpdateApplied::None => {}
1951 },
1952 Err(e) => {
1953 debug!(
1954 "Token {:?} not found for watcher {:?};
1955 network was likely removed while idle ({})",
1956 registration.token, id, e
1957 );
1958 }
1959 }
1960
1961 let has_updates = updates != fnp_properties::PropertyUpdate::default();
1964 if self.generations_by_connection.properties(&id).is_some() {
1965 match (has_updates, registration.responder.take()) {
1966 (true, Some(responder)) => {
1967 self.generations_by_connection.set_properties(id, self.current_generation);
1969 if let Err(e) = responder.send(Ok(&updates)) {
1970 warn!("Failed to send watch updates: {}", e);
1971 }
1972 }
1973 (false, maybe_responder) => {
1974 self.generations_by_connection.set_properties(id, self.current_generation);
1976 registration.responder = maybe_responder;
1977 }
1978 (true, None) => {
1979 }
1983 }
1984 }
1985
1986 assert_matches!(
1987 self.property_watchers.insert(id, registration),
1988 None,
1989 "Re-inserted in an existing registration slot."
1990 );
1991 }
1992 self.maybe_notify_watchers();
1993 }
1994
1995 async fn notify_default_network_changed(
1996 &mut self,
1997 old_default: Option<NetworkId>,
1998 property_watchers: &mut HashMap<PropertyWatcherConnectionId, Registration>,
1999 ) {
2000 self.changed_default_network(old_default, property_watchers).await;
2001 let default_network = self.network_registry.default_network;
2002 if let Some(telemetry) = &self.telemetry {
2003 match default_network {
2004 Some(default_network) => {
2005 if let Some(props) = self.network_registry.networks.get(&default_network) {
2006 telemetry.send(TelemetryEvent::DefaultNetworkChanged(
2007 NetworkEventMetadata {
2008 id: default_network.get().get(),
2009 name: props.name.clone(),
2010 transport: props
2011 .network_type
2012 .unwrap_or(fnp_socketproxy::NetworkType::Unknown),
2013 is_fuchsia_provisioned: default_network.is_fuchsia(),
2014 connectivity_state: props.connectivity_state,
2015 },
2016 ));
2017 } else {
2018 warn!("Could not fetch network data for default network.");
2019 }
2020 }
2021 None => telemetry.send(TelemetryEvent::DefaultNetworkLost),
2022 }
2023 }
2024 self.current_generation.default_network += 1;
2025 let responders = self
2028 .networks_clients
2029 .iter_mut()
2030 .filter_map(|(id, client)| client.responder.take().map(|responder| (*id, responder)));
2031 for (id, responder) in responders {
2032 self.generations_by_connection.set_default_network(id, self.current_generation);
2033 let response = match default_network {
2034 Some(network_id) => {
2035 match self
2036 .tokens
2037 .ensure_token(NetworkTokenContents { network_id, is_default: true })
2038 .get()
2039 .duplicate()
2040 {
2041 Ok(token) => fnp_properties::NetworksWatchDefaultResponse::Network(token),
2042 Err(e) => {
2043 warn!("Could not duplicate token: {e}");
2044 continue;
2045 }
2046 }
2047 }
2048 None => fnp_properties::NetworksWatchDefaultResponse::NoDefaultNetwork(
2049 fnp_properties::Empty,
2050 ),
2051 };
2052 if let Err(e) = responder.send(response) {
2053 warn!("Could not send to responder: {e}");
2054 }
2055 }
2056 }
2057}
2058
2059#[cfg(test)]
2060mod tests {
2061 use super::*;
2062 use assert_matches::assert_matches;
2063 use diagnostics_assertions::assert_data_tree;
2064 use fnp_socketproxy::{
2065 NetworkInfo, NetworkRegistryAddError, NetworkRegistryMarker, NetworkRegistryRemoveError,
2066 NetworkRegistrySetDefaultError, NetworkRegistryUpdateError, StarnixNetworkInfo,
2067 };
2068 use futures::FutureExt as _;
2069 use std::num::NonZeroU64;
2070 use test_case::test_case;
2071
2072 const ID_1: InterfaceId = InterfaceId(NonZeroU64::new(1).unwrap());
2073 const ID_2: InterfaceId = InterfaceId(NonZeroU64::new(2).unwrap());
2074 const NAME_1: &str = "testif1";
2075 const NAME_2: &str = "testif2";
2076
2077 const FUCHSIA_ID_1: NetworkId = NetworkId::Fuchsia(ID_1);
2078 const FUCHSIA_ID_2: NetworkId = NetworkId::Fuchsia(ID_2);
2079 const DELEGATED_ID_1: NetworkId = NetworkId::Delegated(ID_1);
2080 const DELEGATED_ID_2: NetworkId = NetworkId::Delegated(ID_2);
2081
2082 #[derive(Clone, Copy)]
2083 struct TestNetwork {
2084 id: NetworkId,
2085 name: &'static str,
2086 network_type: fnp_socketproxy::NetworkType,
2087 }
2088
2089 #[derive(Default)]
2090 struct AppliedChanges {
2091 added: bool,
2092 changed_marks: bool,
2093 changed_dns: bool,
2094 }
2095
2096 impl TestNetwork {
2097 fn added(&self, added: bool) -> NetworkPropertiesChange {
2098 NetworkPropertiesChange {
2099 added,
2100 name: Some(self.name.to_string()),
2101 network_type: Some(self.network_type),
2102 ..Default::default()
2103 }
2104 }
2105
2106 fn change_with(
2107 &self,
2108 added: bool,
2109 marks: Option<fnet::Marks>,
2110 dns_servers: Option<Vec<fnet_name::DnsServer_>>,
2111 connectivity_state: Option<fnp_socketproxy::ConnectivityState>,
2112 ) -> NetworkPropertiesChange {
2113 NetworkPropertiesChange {
2114 added,
2115 marks,
2116 dns_servers,
2117 connectivity_state,
2118 name: Some(self.name.to_string()),
2119 network_type: Some(self.network_type),
2120 }
2121 }
2122
2123 fn applied(&self, changes: AppliedChanges) -> UpdateApplied {
2124 let AppliedChanges { added, changed_marks, changed_dns } = changes;
2125 UpdateApplied::NetworkChanged {
2126 network_id: self.id,
2127 added,
2128 changed_marks,
2129 changed_dns,
2130 name: Some(self.name.to_string()),
2131 network_type: Some(self.network_type),
2132 }
2133 }
2134 }
2135
2136 const DELEGATED_NET_1: TestNetwork = TestNetwork {
2137 id: DELEGATED_ID_1,
2138 name: NAME_1,
2139 network_type: fnp_socketproxy::NetworkType::Ethernet,
2140 };
2141 const FUCHSIA_NET_1: TestNetwork = TestNetwork {
2142 id: FUCHSIA_ID_1,
2143 name: NAME_1,
2144 network_type: fnp_socketproxy::NetworkType::Ethernet,
2145 };
2146 const FUCHSIA_NET_2: TestNetwork = TestNetwork {
2147 id: FUCHSIA_ID_2,
2148 name: NAME_2,
2149 network_type: fnp_socketproxy::NetworkType::Wifi,
2150 };
2151
2152 fn test_marks() -> fnet::Marks {
2153 fnet::Marks { mark_1: Some(123), ..Default::default() }
2154 }
2155
2156 fn test_marks_updated() -> fnet::Marks {
2157 fnet::Marks { mark_1: Some(456), ..Default::default() }
2158 }
2159
2160 fn test_dns_1() -> Vec<fnet_name::DnsServer_> {
2161 vec![fnet_name::DnsServer_ {
2162 address: Some(net_declare::fidl_socket_addr!("192.0.2.1:53")),
2163 ..Default::default()
2164 }]
2165 }
2166
2167 fn test_dns_2() -> Vec<fnet_name::DnsServer_> {
2168 vec![fnet_name::DnsServer_ {
2169 address: Some(net_declare::fidl_socket_addr!("192.0.2.2:53")),
2170 ..Default::default()
2171 }]
2172 }
2173
2174 fn delegated_properties() -> NetworkProperties {
2175 NetworkProperties { socket_marks: Some(test_marks()), ..Default::default() }
2176 }
2177
2178 fn fuchsia_properties() -> NetworkProperties {
2179 NetworkProperties::default()
2180 }
2181
2182 fn added_properties(name: &str) -> NetworkPropertiesChange {
2183 NetworkPropertiesChange {
2184 added: true,
2185 marks: None,
2186 dns_servers: None,
2187 connectivity_state: None,
2188 name: Some(name.to_string()),
2189 network_type: Some(fnp_socketproxy::NetworkType::Ethernet),
2190 }
2191 }
2192
2193 impl NetpolNetworksService {
2194 pub(crate) fn default_network(&self) -> Option<NetworkId> {
2195 self.network_registry.default_network
2196 }
2197
2198 pub(crate) fn has_network(&self, id: NetworkId) -> bool {
2199 self.network_registry.networks.contains_key(&id)
2200 }
2201
2202 pub(crate) fn has_token(&self, network_id: NetworkId, is_default: bool) -> bool {
2203 self.tokens.get_token(&NetworkTokenContents { network_id, is_default }).is_some()
2204 }
2205
2206 pub(crate) fn ensure_token_for_test(&mut self, network_id: NetworkId, is_default: bool) {
2207 let _token: crate::network::token_registry::TokenEntry<'_, _> =
2208 self.tokens.ensure_token(NetworkTokenContents { network_id, is_default });
2209 }
2210 }
2211
2212 #[test_case(
2213 DELEGATED_NET_1,
2214 Some(test_marks()),
2215 Some(test_marks_updated()); "delegated network"
2216 )]
2217 #[test_case(FUCHSIA_NET_2, None, None; "fuchsia network")]
2218 fn test_handle_changed_network(
2219 net: TestNetwork,
2220 initial_marks: Option<fnet::Marks>,
2221 updated_marks: Option<fnet::Marks>,
2222 ) {
2223 let mut networks = RegisteredNetworks::default();
2224 let dns1 = test_dns_1();
2225 let dns2 = test_dns_2();
2226
2227 let event = net.change_with(
2229 true,
2230 initial_marks.clone(),
2231 Some(dns1.clone()),
2232 Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
2233 );
2234 assert_eq!(
2235 networks.handle_changed_network(net.id, event),
2236 net.applied(AppliedChanges { added: true, changed_marks: true, changed_dns: true }),
2237 );
2238 assert_eq!(
2239 networks.networks.get(&net.id).expect("network should be present"),
2240 &NetworkProperties {
2241 socket_marks: initial_marks.clone(),
2242 dns_servers: dns1,
2243 connectivity_state: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
2244 name: Some(net.name.to_string()),
2245 network_type: Some(net.network_type),
2246 }
2247 );
2248
2249 let event = net.change_with(
2252 false,
2253 initial_marks.clone(),
2254 Some(dns2.clone()),
2255 Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
2256 );
2257 assert_eq!(
2258 networks.handle_changed_network(net.id, event),
2259 net.applied(AppliedChanges { added: false, changed_marks: false, changed_dns: true }),
2260 );
2261 assert_eq!(
2262 networks.networks.get(&net.id).expect("network should be present"),
2263 &NetworkProperties {
2264 socket_marks: initial_marks.clone(),
2265 dns_servers: dns2.clone(),
2266 connectivity_state: Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
2267 name: Some(net.name.to_string()),
2268 network_type: Some(net.network_type),
2269 }
2270 );
2271
2272 let marks_changed = initial_marks != updated_marks;
2274 let event = net.change_with(
2275 false,
2276 updated_marks.clone(),
2277 Some(dns2.clone()),
2278 Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
2279 );
2280 assert_eq!(
2281 networks.handle_changed_network(net.id, event),
2282 net.applied(AppliedChanges {
2283 added: false,
2284 changed_marks: marks_changed,
2285 changed_dns: false,
2286 }),
2287 );
2288 assert_eq!(
2289 networks.networks.get(&net.id).expect("network should be present"),
2290 &NetworkProperties {
2291 socket_marks: updated_marks,
2292 dns_servers: dns2,
2293 connectivity_state: Some(fnp_socketproxy::ConnectivityState::NoConnectivity),
2294 name: Some(net.name.to_string()),
2295 network_type: Some(net.network_type),
2296 }
2297 );
2298 }
2299
2300 #[test]
2301 fn test_handle_changed_network_validation() {
2302 let mut networks = RegisteredNetworks::default();
2303 let marks = test_marks();
2304 let net = DELEGATED_NET_1;
2305
2306 let event = NetworkPropertiesChange { marks: Some(marks.clone()), ..net.added(false) };
2308 assert_eq!(networks.handle_changed_network(net.id, event), UpdateApplied::None);
2309
2310 let event = NetworkPropertiesChange { marks: Some(marks.clone()), ..net.added(true) };
2312
2313 assert_eq!(
2314 networks.handle_changed_network(net.id, event),
2315 net.applied(AppliedChanges { added: true, changed_marks: true, changed_dns: true }),
2316 );
2317
2318 let event = NetworkPropertiesChange { marks: Some(marks.clone()), ..net.added(true) };
2320 assert_eq!(networks.handle_changed_network(net.id, event), UpdateApplied::None);
2321
2322 let fuchsia_net = FUCHSIA_NET_1;
2324 let event =
2325 NetworkPropertiesChange { marks: Some(marks.clone()), ..fuchsia_net.added(true) };
2326 assert_eq!(networks.handle_changed_network(fuchsia_net.id, event), UpdateApplied::None);
2327
2328 let event = net.added(true);
2330 assert_eq!(networks.handle_changed_network(net.id, event), UpdateApplied::None);
2331 }
2332
2333 #[test]
2336 fn fallback_election_and_prioritization() {
2337 let mut networks = RegisteredNetworks::default();
2338
2339 assert_eq!(networks.calculate_active_default(), None);
2341
2342 let _ = networks.networks.insert(DELEGATED_ID_1, delegated_properties());
2344 networks.starnix_default = Some(DELEGATED_ID_1);
2345 assert_eq!(
2346 networks.handle_default_network_update(),
2347 Some(DefaultChangedEvent { previous_default: None })
2348 );
2349 assert_eq!(networks.default_network, Some(DELEGATED_ID_1));
2350
2351 let _ = networks.networks.insert(DELEGATED_ID_2, delegated_properties());
2354 networks.starnix_default = Some(DELEGATED_ID_2);
2355 assert_eq!(
2356 networks.handle_default_network_update(),
2357 Some(DefaultChangedEvent { previous_default: Some(DELEGATED_ID_1) })
2358 );
2359 assert_eq!(networks.default_network, Some(DELEGATED_ID_2));
2360
2361 let _ = networks.networks.insert(FUCHSIA_ID_2, fuchsia_properties());
2364 assert_eq!(
2365 networks.handle_default_network_update(),
2366 Some(DefaultChangedEvent { previous_default: Some(DELEGATED_ID_2) })
2367 );
2368 assert_eq!(networks.default_network, Some(FUCHSIA_ID_2));
2369
2370 let _ = networks.networks.insert(FUCHSIA_ID_1, fuchsia_properties());
2373 assert_eq!(
2374 networks.handle_default_network_update(),
2375 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_2) })
2376 );
2377 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
2378
2379 let _ = networks.networks.remove(&FUCHSIA_ID_1);
2381 assert_eq!(
2382 networks.handle_default_network_update(),
2383 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_1) })
2384 );
2385 assert_eq!(networks.default_network, Some(FUCHSIA_ID_2));
2386
2387 let _ = networks.networks.remove(&FUCHSIA_ID_2);
2390 assert_eq!(
2391 networks.handle_default_network_update(),
2392 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_2) })
2393 );
2394 assert_eq!(networks.default_network, Some(DELEGATED_ID_2));
2395
2396 assert_eq!(
2398 networks.apply(NetworkRegistryUpdate::UnsetDefaultNetwork),
2399 RegistryUpdateResult {
2400 event: UpdateApplied::None,
2401 default_changed: Some(DefaultChangedEvent {
2402 previous_default: Some(DELEGATED_ID_2)
2403 })
2404 }
2405 );
2406 assert_eq!(networks.default_network, None);
2407
2408 assert_eq!(
2410 networks
2411 .apply(NetworkRegistryUpdate::ChangeNetwork(DELEGATED_ID_1, NetworkUpdate::Remove)),
2412 RegistryUpdateResult {
2413 event: UpdateApplied::NetworkRemoved(DELEGATED_ID_1),
2414 default_changed: None
2415 }
2416 );
2417 }
2418
2419 #[test]
2423 fn test_remove_fuchsia_network_fallback() {
2424 let mut networks = RegisteredNetworks::default();
2425 let marks = test_marks();
2426 let fuchsia_added = NetworkPropertiesChange { added: true, ..Default::default() };
2427
2428 let result = networks.apply(NetworkRegistryUpdate::ChangeNetwork(
2430 FUCHSIA_ID_1,
2431 NetworkUpdate::Properties(fuchsia_added.clone()),
2432 ));
2433 assert_matches!(
2434 result.event,
2435 UpdateApplied::NetworkChanged { network_id: id, added: true, .. }
2436 if id == FUCHSIA_ID_1
2437 );
2438 assert_eq!(result.default_changed, Some(DefaultChangedEvent { previous_default: None }));
2439
2440 let result = networks.apply(NetworkRegistryUpdate::ChangeNetwork(
2442 FUCHSIA_ID_2,
2443 NetworkUpdate::Properties(fuchsia_added),
2444 ));
2445 assert_matches!(
2446 result.event,
2447 UpdateApplied::NetworkChanged { network_id: id, added: true, .. }
2448 if id == FUCHSIA_ID_2
2449 );
2450 assert_eq!(result.default_changed, None);
2451
2452 let result = networks.apply(NetworkRegistryUpdate::ChangeNetwork(
2454 DELEGATED_ID_1,
2455 NetworkUpdate::Properties(NetworkPropertiesChange {
2456 added: true,
2457 marks: Some(marks),
2458 ..Default::default()
2459 }),
2460 ));
2461 assert_matches!(
2462 result.event,
2463 UpdateApplied::NetworkChanged { network_id: id, added: true, .. }
2464 if id == DELEGATED_ID_1
2465 );
2466 assert_eq!(result.default_changed, None);
2467
2468 let result = networks.apply(NetworkRegistryUpdate::ChangeNetwork(
2471 DELEGATED_ID_1,
2472 NetworkUpdate::MakeDefault,
2473 ));
2474 assert_eq!(
2475 result,
2476 RegistryUpdateResult { event: UpdateApplied::None, default_changed: None }
2477 );
2478 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
2479
2480 let result = networks
2483 .apply(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_1, NetworkUpdate::Remove));
2484 assert_eq!(result.event, UpdateApplied::NetworkRemoved(FUCHSIA_ID_1));
2485 assert_eq!(
2486 result.default_changed,
2487 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_1) })
2488 );
2489 assert_eq!(networks.default_network, Some(FUCHSIA_ID_2));
2490
2491 let result = networks
2494 .apply(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_2, NetworkUpdate::Remove));
2495 assert_eq!(result.event, UpdateApplied::NetworkRemoved(FUCHSIA_ID_2));
2496 assert_eq!(
2497 result.default_changed,
2498 Some(DefaultChangedEvent { previous_default: Some(FUCHSIA_ID_2) })
2499 );
2500 assert_eq!(networks.default_network, Some(DELEGATED_ID_1));
2501
2502 let result = networks
2504 .apply(NetworkRegistryUpdate::ChangeNetwork(DELEGATED_ID_1, NetworkUpdate::Remove));
2505 assert_eq!(
2506 result,
2507 RegistryUpdateResult { event: UpdateApplied::None, default_changed: None }
2508 );
2509 assert!(networks.networks.contains_key(&DELEGATED_ID_1));
2510 assert_eq!(networks.default_network, Some(DELEGATED_ID_1));
2511 }
2512
2513 #[test]
2514 fn remove_non_default_fuchsia_preserves_default() {
2515 let mut networks = RegisteredNetworks::default();
2516
2517 let _ = networks.networks.insert(FUCHSIA_ID_1, NetworkProperties::default());
2519 let _ = networks.networks.insert(FUCHSIA_ID_2, NetworkProperties::default());
2520
2521 assert_eq!(
2523 networks.handle_default_network_update(),
2524 Some(DefaultChangedEvent { previous_default: None })
2525 );
2526 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
2527
2528 assert_eq!(
2530 networks
2531 .apply(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_2, NetworkUpdate::Remove)),
2532 RegistryUpdateResult {
2533 event: UpdateApplied::NetworkRemoved(FUCHSIA_ID_2),
2534 default_changed: None
2535 }
2536 );
2537
2538 assert_eq!(networks.default_network, Some(FUCHSIA_ID_1));
2540 }
2541
2542 #[fuchsia::test]
2543 async fn remove_default_network_cleans_up_tokens() {
2544 let mut service = NetpolNetworksService::default();
2545
2546 service
2548 .update(NetworkRegistryUpdate::ChangeNetwork(
2549 FUCHSIA_ID_1,
2550 NetworkUpdate::Properties(added_properties(NAME_1)),
2551 ))
2552 .await;
2553
2554 service
2555 .update(NetworkRegistryUpdate::ChangeNetwork(
2556 FUCHSIA_ID_2,
2557 NetworkUpdate::Properties(added_properties(NAME_2)),
2558 ))
2559 .await;
2560
2561 assert_eq!(service.default_network(), Some(FUCHSIA_ID_1));
2563
2564 assert!(service.has_token(FUCHSIA_ID_1, false ));
2566 assert!(service.has_token(FUCHSIA_ID_2, false ));
2567
2568 service.ensure_token_for_test(FUCHSIA_ID_1, true );
2570 assert!(service.has_token(FUCHSIA_ID_1, true ));
2571
2572 service
2575 .update(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_1, NetworkUpdate::Remove))
2576 .await;
2577
2578 assert_eq!(service.default_network(), Some(FUCHSIA_ID_2));
2580
2581 assert!(!service.has_token(FUCHSIA_ID_1, false ));
2583 assert!(!service.has_token(FUCHSIA_ID_1, true ));
2584
2585 assert!(service.has_token(FUCHSIA_ID_2, false ));
2587 }
2588
2589 #[fuchsia::test]
2590 async fn test_property_watcher_generation_increment_on_unpolled_update() {
2591 let mut service = NetpolNetworksService::default();
2592
2593 service
2595 .update(NetworkRegistryUpdate::ChangeNetwork(
2596 DELEGATED_ID_1,
2597 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
2598 true,
2599 Some(test_marks()),
2600 None,
2601 None,
2602 )),
2603 ))
2604 .await;
2605
2606 let token = service
2607 .tokens
2608 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
2609 .get()
2610 .duplicate()
2611 .unwrap();
2612
2613 let (watcher, server_end) =
2614 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
2615 let (networks_proxy, networks_stream) =
2616 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
2617
2618 service.add_stream(networks_stream);
2619
2620 let request = fnp_properties::NetworksWatchPropertiesRequest {
2622 network: Some(token),
2623 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
2624 watcher: Some(server_end),
2625 ..Default::default()
2626 };
2627
2628 let watch_req = networks_proxy.watch_properties(request);
2629 let req_event = service.select_next_some().await;
2630 assert_eq!(
2631 service.handle_event(req_event).await.expect("Failed to handle event"),
2632 DelegatedNetworkUpdateResult::default()
2633 );
2634 assert_matches!(watch_req.await, Ok(Ok(())));
2635
2636 let watch_fut1 = watcher.watch();
2638 let pw_event1 = service.select_next_some().await;
2639 assert_eq!(
2640 service.handle_event(pw_event1).await.expect("Failed to handle event"),
2641 DelegatedNetworkUpdateResult::default()
2642 );
2643 let initial_updates = watch_fut1.await.unwrap().unwrap();
2644 assert_eq!(
2645 initial_updates,
2646 fnp_properties::PropertyUpdate {
2647 socket_marks: Some(test_marks()),
2648 dns_configuration: None,
2649 ..Default::default()
2650 }
2651 );
2652
2653 service
2656 .update(NetworkRegistryUpdate::ChangeNetwork(
2657 DELEGATED_ID_1,
2658 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
2659 false,
2660 Some(test_marks_updated()),
2661 None,
2662 None,
2663 )),
2664 ))
2665 .await;
2666
2667 let watch_fut2 = watcher.watch();
2669 let pw_event2 = service.select_next_some().await;
2670 assert_eq!(
2671 service.handle_event(pw_event2).await.expect("Failed to handle event"),
2672 DelegatedNetworkUpdateResult::default()
2673 );
2674 let updates = watch_fut2.await.unwrap().unwrap();
2675 assert_eq!(
2676 updates,
2677 fnp_properties::PropertyUpdate {
2678 socket_marks: Some(test_marks_updated()),
2679 dns_configuration: None,
2680 ..Default::default()
2681 }
2682 );
2683 }
2684
2685 #[fuchsia::test]
2686 async fn test_watch_should_return_error_on_concurrent_call() {
2687 let mut service = NetpolNetworksService::default();
2688
2689 let token = service
2690 .tokens
2691 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
2692 .get()
2693 .duplicate()
2694 .unwrap();
2695
2696 let (watcher, server_end) =
2697 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
2698 let (networks_proxy, networks_stream) =
2699 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
2700
2701 service.add_stream(networks_stream);
2702
2703 let watch_req =
2704 networks_proxy.watch_properties(fnp_properties::NetworksWatchPropertiesRequest {
2705 network: Some(token),
2706 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
2707 watcher: Some(server_end),
2708 ..Default::default()
2709 });
2710 let req_event = service.select_next_some().await;
2711 assert_eq!(
2712 service.handle_event(req_event).await.expect("Failed to handle event"),
2713 DelegatedNetworkUpdateResult::default()
2714 );
2715 assert_matches!(watch_req.await, Ok(Ok(())));
2716
2717 let watch_fut1 = watcher.watch();
2719 let pw_event1 = service.select_next_some().await;
2720 assert_eq!(
2721 service.handle_event(pw_event1).await.expect("Failed to handle event"),
2722 DelegatedNetworkUpdateResult::default()
2723 );
2724
2725 let watch_fut2 = watcher.watch();
2726 let pw_event2 = service.select_next_some().await;
2727 assert_eq!(
2728 service.handle_event(pw_event2).await.expect("Failed to handle event"),
2729 DelegatedNetworkUpdateResult::default()
2730 );
2731
2732 for res in [watch_fut1.await, watch_fut2.await] {
2733 assert_matches!(
2734 res,
2735 Err(fidl::Error::ClientChannelClosed { epitaph, .. })
2736 if epitaph == zx::Status::ALREADY_EXISTS
2737 );
2738 }
2739 let disconnect_event = service.select_next_some().await;
2741 assert_eq!(
2742 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
2743 DelegatedNetworkUpdateResult::default()
2744 );
2745 assert!(service.property_watchers.is_empty());
2746 }
2747
2748 #[fuchsia::test]
2749 async fn test_watch_default_should_return_error_on_concurrent_call() {
2750 let mut service = NetpolNetworksService::default();
2751
2752 let (networks_proxy, networks_stream) =
2753 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
2754
2755 service.add_stream(networks_stream);
2756
2757 let watch_fut1 = networks_proxy.watch_default();
2759 let req_event1 = service.select_next_some().await;
2760 assert_eq!(
2761 service.handle_event(req_event1).await.expect("Failed to handle event"),
2762 DelegatedNetworkUpdateResult::default()
2763 );
2764
2765 let watch_fut2 = networks_proxy.watch_default();
2766 let req_event2 = service.select_next_some().await;
2767 assert_eq!(
2768 service.handle_event(req_event2).await.expect("Failed to handle event"),
2769 DelegatedNetworkUpdateResult::default()
2770 );
2771
2772 for res in [watch_fut1.await, watch_fut2.await] {
2773 assert_matches!(
2774 res,
2775 Err(fidl::Error::ClientChannelClosed { epitaph, .. })
2776 if epitaph == zx::Status::ALREADY_EXISTS
2777 );
2778 }
2779 let disconnect_event = service.select_next_some().await;
2781 assert_eq!(
2782 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
2783 DelegatedNetworkUpdateResult::default()
2784 );
2785 assert!(service.networks_clients.is_empty());
2786 }
2787
2788 #[fuchsia::test]
2789 async fn test_network_removal_reports_network_gone() {
2790 let mut service = NetpolNetworksService::default();
2791
2792 service
2793 .update(NetworkRegistryUpdate::ChangeNetwork(
2794 DELEGATED_ID_1,
2795 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
2796 true,
2797 Some(test_marks()),
2798 None,
2799 None,
2800 )),
2801 ))
2802 .await;
2803
2804 let token1 = service
2805 .tokens
2806 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
2807 .get()
2808 .duplicate()
2809 .unwrap();
2810 let token2 = service
2811 .tokens
2812 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
2813 .get()
2814 .duplicate()
2815 .unwrap();
2816
2817 let (active_watcher, active_server_end) =
2818 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
2819 let (idle_watcher, idle_server_end) =
2820 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
2821 let (networks_proxy, networks_stream) =
2822 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
2823
2824 service.add_stream(networks_stream);
2825
2826 for (token, server_end) in [(token1, active_server_end), (token2, idle_server_end)] {
2827 let watch_req =
2828 networks_proxy.watch_properties(fnp_properties::NetworksWatchPropertiesRequest {
2829 network: Some(token),
2830 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
2831 watcher: Some(server_end),
2832 ..Default::default()
2833 });
2834 let req_event = service.select_next_some().await;
2835 assert_eq!(
2836 service.handle_event(req_event).await.expect("Failed to handle event"),
2837 DelegatedNetworkUpdateResult::default()
2838 );
2839 assert_matches!(watch_req.await, Ok(Ok(())));
2840 }
2841
2842 let active_watch_fut1 = active_watcher.watch();
2844 let active_pw_event1 = service.select_next_some().await;
2845 assert_eq!(
2846 service.handle_event(active_pw_event1).await.expect("Failed to handle event"),
2847 DelegatedNetworkUpdateResult::default()
2848 );
2849 let initial_updates = active_watch_fut1.await.unwrap().unwrap();
2850 assert_eq!(
2851 initial_updates,
2852 fnp_properties::PropertyUpdate {
2853 socket_marks: Some(test_marks()),
2854 dns_configuration: None,
2855 ..Default::default()
2856 }
2857 );
2858
2859 let mut active_watch_fut2 = active_watcher.watch();
2861 let active_pw_event2 = service.select_next_some().await;
2862 assert_eq!(
2863 service.handle_event(active_pw_event2).await.expect("Failed to handle event"),
2864 DelegatedNetworkUpdateResult::default()
2865 );
2866 assert_matches!((&mut active_watch_fut2).now_or_never(), None);
2867
2868 service
2870 .update(NetworkRegistryUpdate::ChangeNetwork(DELEGATED_ID_1, NetworkUpdate::Remove))
2871 .await;
2872
2873 assert_matches!(
2876 active_watch_fut2.await,
2877 Ok(Err(fnp_properties::PropertyWatcherError::NetworkGone))
2878 );
2879 let active_closed_event = service.select_next_some().await;
2880 assert_eq!(
2881 service.handle_event(active_closed_event).await.expect("Failed to handle event"),
2882 DelegatedNetworkUpdateResult::default()
2883 );
2884
2885 let idle_watch_fut = idle_watcher.watch();
2887 let idle_pw_event = service.select_next_some().await;
2888 assert_eq!(
2889 service.handle_event(idle_pw_event).await.expect("Failed to handle event"),
2890 DelegatedNetworkUpdateResult::default()
2891 );
2892 assert_matches!(
2893 idle_watch_fut.await,
2894 Ok(Err(fnp_properties::PropertyWatcherError::NetworkGone))
2895 );
2896 }
2897
2898 #[fuchsia::test]
2899 async fn test_idle_default_watcher_reports_network_gone_on_default_change() {
2900 let mut service = NetpolNetworksService::default();
2901
2902 service
2904 .update(NetworkRegistryUpdate::ChangeNetwork(
2905 DELEGATED_ID_1,
2906 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
2907 true,
2908 Some(test_marks()),
2909 None,
2910 None,
2911 )),
2912 ))
2913 .await;
2914 service
2915 .update(NetworkRegistryUpdate::ChangeNetwork(
2916 DELEGATED_ID_1,
2917 NetworkUpdate::MakeDefault,
2918 ))
2919 .await;
2920
2921 let (networks_proxy, networks_stream) =
2922 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
2923 service.add_stream(networks_stream);
2924
2925 let default_fut = networks_proxy.watch_default();
2927 let req_event = service.select_next_some().await;
2928 assert_eq!(
2929 service.handle_event(req_event).await.expect("Failed to handle event"),
2930 DelegatedNetworkUpdateResult::default()
2931 );
2932 let default_token = match default_fut.await.unwrap() {
2933 fnp_properties::NetworksWatchDefaultResponse::Network(token) => token,
2934 res => panic!("Expected Network token, got {res:?}"),
2935 };
2936
2937 let (watcher, server_end) =
2939 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
2940 let watch_req =
2941 networks_proxy.watch_properties(fnp_properties::NetworksWatchPropertiesRequest {
2942 network: Some(default_token),
2943 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
2944 watcher: Some(server_end),
2945 ..Default::default()
2946 });
2947 let req_event = service.select_next_some().await;
2948 assert_eq!(
2949 service.handle_event(req_event).await.expect("Failed to handle event"),
2950 DelegatedNetworkUpdateResult::default()
2951 );
2952 assert_matches!(watch_req.await, Ok(Ok(())));
2953
2954 let initial_fut = watcher.watch();
2956 let pw_event = service.select_next_some().await;
2957 assert_eq!(
2958 service.handle_event(pw_event).await.expect("Failed to handle event"),
2959 DelegatedNetworkUpdateResult::default()
2960 );
2961 assert_matches!(initial_fut.await, Ok(Ok(_)));
2962
2963 service.update(NetworkRegistryUpdate::unset_default()).await;
2965
2966 let idle_watch_fut = watcher.watch();
2968 let idle_pw_event = service.select_next_some().await;
2969 assert_eq!(
2970 service.handle_event(idle_pw_event).await.expect("Failed to handle event"),
2971 DelegatedNetworkUpdateResult::default()
2972 );
2973 assert_matches!(
2974 idle_watch_fut.await,
2975 Ok(Err(fnp_properties::PropertyWatcherError::NetworkGone))
2976 );
2977 }
2978
2979 #[test_case(
2980 None,
2981 Some(fnp_socketproxy::NetworkInfo::Starnix(
2982 fnp_socketproxy::StarnixNetworkInfo {
2983 mark: Some(123),
2984 ..Default::default()
2985 }
2986 )),
2987 Err(NetworkValidationError::MissingNetworkId);
2988 "missing network_id"
2989 )]
2990 #[test_case(
2991 Some(0),
2992 Some(fnp_socketproxy::NetworkInfo::Starnix(
2993 fnp_socketproxy::StarnixNetworkInfo {
2994 mark: Some(123),
2995 ..Default::default()
2996 }
2997 )),
2998 Err(NetworkValidationError::MissingNetworkId);
2999 "zero network_id"
3000 )]
3001 #[test_case(
3002 Some(1),
3003 None,
3004 Err(NetworkValidationError::MissingNetworkInfo);
3005 "missing network_info"
3006 )]
3007 #[test_case(
3008 Some(1),
3009 Some(fnp_socketproxy::NetworkInfo::Fuchsia(Default::default())),
3010 Err(NetworkValidationError::MissingNetworkInfo);
3011 "fuchsia network_info"
3012 )]
3013 #[test_case(
3014 Some(1),
3015 Some(fnp_socketproxy::NetworkInfo::Starnix(
3016 fnp_socketproxy::StarnixNetworkInfo {
3017 mark: Some(123),
3018 ..Default::default()
3019 }
3020 )),
3021 Ok(NetworkId::delegated(InterfaceId::new(1).unwrap()));
3022 "valid starnix network"
3023 )]
3024 fn test_validated_network_validation(
3025 network_id: Option<u32>,
3026 info: Option<fnp_socketproxy::NetworkInfo>,
3027 expected: Result<NetworkId, NetworkValidationError>,
3028 ) {
3029 let net = fnp_socketproxy::Network { network_id, info, ..Default::default() };
3030 let result = ValidatedNetwork::try_from(net).map(|v| v.network_id);
3031 assert_eq!(result, expected);
3032 }
3033
3034 fn starnix_network_payload(id: u32, mark: u32) -> fnp_socketproxy::Network {
3035 fnp_socketproxy::Network {
3036 network_id: Some(id),
3037 info: Some(NetworkInfo::Starnix(StarnixNetworkInfo {
3038 mark: Some(mark),
3039 ..Default::default()
3040 })),
3041 ..Default::default()
3042 }
3043 }
3044
3045 async fn process_fidl_request<E>(
3046 service: &mut NetpolNetworksService,
3047 request_future: impl Future<Output = Result<Result<(), E>, fidl::Error>>,
3048 ) -> Result<(), E> {
3049 let event = service.select_next_some().await;
3050 let update_result = service.handle_event(event).await.expect("failed to handle event");
3051 let client_result = request_future.await.expect("FIDL call failed");
3052 assert_eq!(update_result.dns_servers.is_some(), client_result.is_ok());
3053 client_result
3054 }
3055
3056 #[fuchsia::test]
3057 async fn test_delegated_networks_fidl_errors() {
3058 let mut service = NetpolNetworksService::default();
3059 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3060 service.add_stream(stream);
3061
3062 const NETWORK_ID_1: u32 = 1;
3063 const NETWORK_ID_2: u32 = 2;
3064 const SOCKET_MARK: u32 = 100;
3065
3066 assert_eq!(
3068 process_fidl_request(
3069 &mut service,
3070 proxy.update(&starnix_network_payload(NETWORK_ID_1, SOCKET_MARK,)),
3071 )
3072 .await,
3073 Err(NetworkRegistryUpdateError::NotFound)
3074 );
3075
3076 assert_eq!(
3078 process_fidl_request(
3079 &mut service,
3080 proxy.add(&starnix_network_payload(NETWORK_ID_1, SOCKET_MARK)),
3081 )
3082 .await,
3083 Ok(())
3084 );
3085
3086 assert_eq!(
3088 process_fidl_request(
3089 &mut service,
3090 proxy.add(&starnix_network_payload(NETWORK_ID_1, SOCKET_MARK)),
3091 )
3092 .await,
3093 Err(NetworkRegistryAddError::DuplicateNetworkId)
3094 );
3095
3096 assert_eq!(
3098 process_fidl_request(&mut service, proxy.remove(NETWORK_ID_2)).await,
3099 Err(NetworkRegistryRemoveError::NotFound)
3100 );
3101
3102 assert_eq!(
3104 process_fidl_request(
3105 &mut service,
3106 proxy.set_default(&fposix_socket::OptionalUint32::Value(NETWORK_ID_2,)),
3107 )
3108 .await,
3109 Err(NetworkRegistrySetDefaultError::NotFound)
3110 );
3111
3112 assert_eq!(
3114 process_fidl_request(
3115 &mut service,
3116 proxy.set_default(&fposix_socket::OptionalUint32::Value(NETWORK_ID_1,)),
3117 )
3118 .await,
3119 Ok(())
3120 );
3121
3122 assert_eq!(
3125 process_fidl_request(&mut service, proxy.remove(NETWORK_ID_1)).await,
3126 Err(NetworkRegistryRemoveError::CannotRemoveDefaultNetwork)
3127 );
3128
3129 assert_eq!(
3131 process_fidl_request(
3132 &mut service,
3133 proxy.set_default(&fposix_socket::OptionalUint32::Unset(fposix_socket::Empty)),
3134 )
3135 .await,
3136 Ok(())
3137 );
3138
3139 assert_eq!(process_fidl_request(&mut service, proxy.remove(NETWORK_ID_1)).await, Ok(()));
3141 }
3142
3143 #[fuchsia::test]
3144 async fn test_inspect_metrics() {
3145 let inspector = fuchsia_inspect::Inspector::default();
3146 let telemetry_node = inspector.root().create_child("telemetry");
3147 let mut service = NetpolNetworksService::default()
3148 .with_inspect(&telemetry_node, "operations", &telemetry_node, "network_registry")
3149 .expect("failed to initialize inspect");
3150 inspector.root().record(telemetry_node);
3151
3152 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3153 service.add_stream(stream);
3154
3155 let make_network = |id: u32, mark: u32| fnp_socketproxy::Network {
3156 network_id: Some(id),
3157 info: Some(NetworkInfo::Starnix(StarnixNetworkInfo {
3158 mark: Some(mark),
3159 ..Default::default()
3160 })),
3161 name: Some("wlan0".to_string()),
3162 network_type: Some(fnp_socketproxy::NetworkType::Wifi),
3163 connectivity: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
3164 ..Default::default()
3165 };
3166
3167 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3169 assert_data_tree!(
3170 hierarchy,
3171 root: contains {
3172 telemetry: contains {
3173 operations: contains {
3174 delegated: contains {
3175 adds: contains { successes: 0u64, errors: 0u64 },
3176 removes: contains { successes: 0u64, errors: 0u64 },
3177 set_defaults: contains {
3178 successes: 0u64,
3179 errors: 0u64,
3180 },
3181 updates: contains {
3182 successes: 0u64,
3183 errors: 0u64,
3184 },
3185 }
3186 }
3187 }
3188 }
3189 );
3190
3191 assert_eq!(
3193 process_fidl_request(&mut service, proxy.add(&make_network(1, 100))).await,
3194 Ok(())
3195 );
3196
3197 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3198 assert_data_tree!(
3199 hierarchy,
3200 root: contains {
3201 telemetry: contains {
3202 operations: contains {
3203 delegated: contains {
3204 adds: contains { successes: 1u64, errors: 0u64 },
3205 }
3206 }
3207 }
3208 }
3209 );
3210
3211 assert_eq!(
3213 process_fidl_request(&mut service, proxy.add(&make_network(1, 100))).await,
3214 Err(NetworkRegistryAddError::DuplicateNetworkId)
3215 );
3216
3217 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3218 assert_data_tree!(
3219 hierarchy,
3220 root: contains {
3221 telemetry: contains {
3222 operations: contains {
3223 delegated: contains {
3224 adds: contains { successes: 1u64, errors: 1u64 },
3225 }
3226 }
3227 }
3228 }
3229 );
3230
3231 assert_eq!(
3233 process_fidl_request(&mut service, proxy.update(&make_network(1, 150))).await,
3234 Ok(())
3235 );
3236
3237 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3238 assert_data_tree!(
3239 hierarchy,
3240 root: contains {
3241 telemetry: contains {
3242 operations: contains {
3243 delegated: contains {
3244 updates: contains {
3245 successes: 1u64,
3246 errors: 0u64,
3247 },
3248 }
3249 }
3250 }
3251 }
3252 );
3253
3254 assert_eq!(
3256 process_fidl_request(
3257 &mut service,
3258 proxy.set_default(&fposix_socket::OptionalUint32::Value(1)),
3259 )
3260 .await,
3261 Ok(())
3262 );
3263
3264 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3265 assert_data_tree!(
3266 hierarchy,
3267 root: contains {
3268 telemetry: contains {
3269 operations: contains {
3270 delegated: contains {
3271 set_defaults: contains {
3272 successes: 1u64,
3273 errors: 0u64,
3274 },
3275 default_network_id: 1u64,
3276 }
3277 }
3278 }
3279 }
3280 );
3281
3282 assert_eq!(
3284 process_fidl_request(
3285 &mut service,
3286 proxy.set_default(&fposix_socket::OptionalUint32::Value(2)),
3287 )
3288 .await,
3289 Err(NetworkRegistrySetDefaultError::NotFound)
3290 );
3291
3292 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3293 assert_data_tree!(
3294 hierarchy,
3295 root: contains {
3296 telemetry: contains {
3297 operations: contains {
3298 delegated: contains {
3299 set_defaults: contains {
3300 successes: 1u64,
3301 errors: 1u64,
3302 },
3303 }
3304 }
3305 }
3306 }
3307 );
3308
3309 assert_eq!(
3311 process_fidl_request(&mut service, proxy.remove(1)).await,
3312 Err(NetworkRegistryRemoveError::CannotRemoveDefaultNetwork)
3313 );
3314
3315 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3316 assert_data_tree!(
3317 hierarchy,
3318 root: contains {
3319 telemetry: contains {
3320 operations: contains {
3321 delegated: contains {
3322 removes: contains { successes: 0u64, errors: 1u64 },
3323 }
3324 }
3325 }
3326 }
3327 );
3328
3329 assert_eq!(
3331 process_fidl_request(
3332 &mut service,
3333 proxy.set_default(&fposix_socket::OptionalUint32::Unset(fposix_socket::Empty)),
3334 )
3335 .await,
3336 Ok(())
3337 );
3338
3339 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3340 assert_data_tree!(
3341 hierarchy,
3342 root: contains {
3343 telemetry: contains {
3344 operations: contains {
3345 delegated: contains {
3346 set_defaults: contains {
3347 successes: 2u64,
3348 errors: 1u64,
3349 },
3350 }
3351 }
3352 }
3353 }
3354 );
3355
3356 assert_eq!(process_fidl_request(&mut service, proxy.remove(1)).await, Ok(()));
3358
3359 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3360 assert_data_tree!(
3361 hierarchy,
3362 root: contains {
3363 telemetry: contains {
3364 operations: contains {
3365 delegated: contains {
3366 removes: contains { successes: 1u64, errors: 1u64 },
3367 }
3368 }
3369 }
3370 }
3371 );
3372 }
3373
3374 #[fuchsia::test]
3375 async fn test_network_registry_inspect() {
3376 const FUCHSIA_ID_2: NetworkId = NetworkId::Fuchsia(ID_2);
3377 const DELEGATED_ID_100: NetworkId =
3378 NetworkId::Delegated(InterfaceId(NonZeroU64::new(100).unwrap()));
3379
3380 let inspector = fuchsia_inspect::Inspector::default();
3381 let telemetry_node = inspector.root().create_child("telemetry");
3382 let mut service = NetpolNetworksService::default()
3383 .with_inspect(&telemetry_node, "operations", &telemetry_node, "network_registry")
3384 .expect("failed to initialize inspect");
3385 inspector.root().record(telemetry_node);
3386
3387 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3389 assert_data_tree!(
3390 hierarchy,
3391 root: contains {
3392 telemetry: contains {
3393 network_registry: {}
3394 }
3395 }
3396 );
3397
3398 service
3400 .update(NetworkRegistryUpdate::ChangeNetwork(
3401 FUCHSIA_ID_2,
3402 NetworkUpdate::Properties(NetworkPropertiesChange {
3403 added: true,
3404 name: Some("wlan0".to_string()),
3405 network_type: Some(fnp_socketproxy::NetworkType::Wifi),
3406 connectivity_state: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
3407 ..Default::default()
3408 }),
3409 ))
3410 .await;
3411
3412 let mut marks = fnet::Marks::default();
3414 marks.mark_1 = Some(100);
3415 service
3416 .update(NetworkRegistryUpdate::ChangeNetwork(
3417 DELEGATED_ID_100,
3418 NetworkUpdate::Properties(NetworkPropertiesChange {
3419 added: true,
3420 marks: Some(marks.clone()),
3421 name: Some("eth0".to_string()),
3422 network_type: Some(fnp_socketproxy::NetworkType::Ethernet),
3423 connectivity_state: Some(fnp_socketproxy::ConnectivityState::LocalConnectivity),
3424 ..Default::default()
3425 }),
3426 ))
3427 .await;
3428
3429 service
3431 .update(NetworkRegistryUpdate::ChangeNetwork(
3432 DELEGATED_ID_100,
3433 NetworkUpdate::MakeDefault,
3434 ))
3435 .await;
3436
3437 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3438 assert_data_tree!(
3439 hierarchy,
3440 root: contains {
3441 telemetry: contains {
3442 network_registry: {
3443 default_network: "fuchsia:2",
3444 starnix_default: "delegated:100",
3445 fuchsia_2: {
3446 name: "wlan0",
3447 network_type: "Wifi",
3448 connectivity_state: "FullConnectivity",
3449 },
3450 delegated_100: {
3451 name: "eth0",
3452 network_type: "Ethernet",
3453 connectivity_state: "LocalConnectivity",
3454 },
3455 }
3456 }
3457 }
3458 );
3459
3460 service
3462 .update(NetworkRegistryUpdate::ChangeNetwork(
3463 DELEGATED_ID_100,
3464 NetworkUpdate::Properties(NetworkPropertiesChange {
3465 added: false,
3466 marks: Some(marks),
3467 name: Some("eth0_updated".to_string()),
3468 network_type: Some(fnp_socketproxy::NetworkType::Ethernet),
3469 connectivity_state: Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
3470 ..Default::default()
3471 }),
3472 ))
3473 .await;
3474
3475 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3476 assert_data_tree!(
3477 hierarchy,
3478 root: contains {
3479 telemetry: contains {
3480 network_registry: {
3481 default_network: "fuchsia:2",
3482 starnix_default: "delegated:100",
3483 fuchsia_2: {
3484 name: "wlan0",
3485 network_type: "Wifi",
3486 connectivity_state: "FullConnectivity",
3487 },
3488 delegated_100: {
3489 name: "eth0_updated",
3490 network_type: "Ethernet",
3491 connectivity_state: "FullConnectivity",
3492 },
3493 }
3494 }
3495 }
3496 );
3497
3498 service
3501 .update(NetworkRegistryUpdate::ChangeNetwork(FUCHSIA_ID_2, NetworkUpdate::Remove))
3502 .await;
3503
3504 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3505 assert_data_tree!(
3506 hierarchy,
3507 root: contains {
3508 telemetry: contains {
3509 network_registry: {
3510 default_network: "delegated:100",
3511 starnix_default: "delegated:100",
3512 delegated_100: {
3513 name: "eth0_updated",
3514 network_type: "Ethernet",
3515 connectivity_state: "FullConnectivity",
3516 },
3517 }
3518 }
3519 }
3520 );
3521
3522 service.update(NetworkRegistryUpdate::UnsetDefaultNetwork).await;
3525 service
3526 .update(NetworkRegistryUpdate::ChangeNetwork(DELEGATED_ID_100, NetworkUpdate::Remove))
3527 .await;
3528
3529 let hierarchy = fuchsia_inspect::reader::read(&inspector).await.unwrap();
3530 assert_data_tree!(
3531 hierarchy,
3532 root: contains {
3533 telemetry: contains {
3534 network_registry: {}
3535 }
3536 }
3537 );
3538 }
3539
3540 #[fuchsia::test]
3541 async fn test_reachability_service_integration() {
3542 let mut service = NetpolNetworksService::default();
3543
3544 let mut expected_disconnected = freachability::Snapshot::default();
3545 expected_disconnected.gateway_reachable = Some(false);
3546 expected_disconnected.internet_available = Some(false);
3547 expected_disconnected.dns_active = Some(false);
3548 expected_disconnected.http_active = Some(false);
3549
3550 let mut expected_validated = freachability::Snapshot::default();
3551 expected_validated.gateway_reachable = Some(true);
3552 expected_validated.internet_available = Some(true);
3553 expected_validated.dns_active = Some(true);
3554 expected_validated.http_active = Some(true);
3555
3556 let (proxy, stream) =
3557 fidl::endpoints::create_proxy_and_stream::<freachability::MonitorMarker>();
3558 service.add_stream(stream);
3559 assert_eq!(service.reachability_watcher_count(), 1);
3560
3561 let watch_fut = proxy.watch();
3562 let event = service.select_next_some().await;
3563 assert_eq!(
3564 service.handle_event(event).await.expect("handle event"),
3565 DelegatedNetworkUpdateResult::default()
3566 );
3567 let snapshot = watch_fut.await.expect("watch error");
3568 assert_eq!(snapshot, expected_disconnected);
3569
3570 let mut second_watch = proxy.watch();
3571 let event = service.select_next_some().await;
3572 assert_eq!(
3573 service.handle_event(event).await.expect("handle event"),
3574 DelegatedNetworkUpdateResult::default()
3575 );
3576 assert_matches!(futures::poll!(&mut second_watch), std::task::Poll::Pending);
3577
3578 service
3579 .update(NetworkRegistryUpdate::ChangeNetwork(
3580 DELEGATED_ID_1,
3581 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
3582 true,
3583 Some(test_marks()),
3584 None,
3585 Some(fnp_socketproxy::ConnectivityState::FullConnectivity),
3586 )),
3587 ))
3588 .await;
3589 service
3590 .update(NetworkRegistryUpdate::ChangeNetwork(
3591 DELEGATED_ID_1,
3592 NetworkUpdate::MakeDefault,
3593 ))
3594 .await;
3595
3596 let snapshot = second_watch.await.expect("watch should succeed");
3597 assert_eq!(snapshot, expected_validated);
3598 }
3599
3600 #[fuchsia::test]
3601 async fn test_networks_client_disconnect_cleans_up_state() {
3602 let mut service = NetpolNetworksService::default();
3603 let (proxy, stream) =
3604 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
3605 service.add_stream(stream);
3606
3607 let mut watch_default_fut = proxy.watch_default();
3609 let event = service.select_next_some().await;
3610 assert_eq!(
3611 service.handle_event(event).await.expect("Failed to handle event"),
3612 DelegatedNetworkUpdateResult::default()
3613 );
3614 assert_matches!((&mut watch_default_fut).now_or_never(), None);
3615 assert_matches!(
3616 &service.networks_clients.values().collect::<Vec<_>>()[..],
3617 [NetworksClient { responder: Some(_), .. }]
3618 );
3619
3620 drop(watch_default_fut);
3622 drop(proxy);
3623
3624 let event = service.select_next_some().await;
3625 assert_eq!(
3626 service.handle_event(event).await.expect("Failed to handle event"),
3627 DelegatedNetworkUpdateResult::default()
3628 );
3629 assert!(service.networks_clients.is_empty());
3631 assert!(service.generations_by_connection.default_network.is_empty());
3632 }
3633
3634 #[fuchsia::test]
3635 async fn test_property_watcher_client_disconnect_cleans_up_state() {
3636 let mut service = NetpolNetworksService::default();
3637
3638 service
3639 .update(NetworkRegistryUpdate::ChangeNetwork(
3640 DELEGATED_ID_1,
3641 NetworkUpdate::Properties(DELEGATED_NET_1.change_with(
3642 true,
3643 Some(test_marks()),
3644 None,
3645 None,
3646 )),
3647 ))
3648 .await;
3649
3650 let token = service
3651 .tokens
3652 .ensure_token(NetworkTokenContents { network_id: DELEGATED_ID_1, is_default: false })
3653 .get()
3654 .duplicate()
3655 .unwrap();
3656
3657 let (watcher, server_end) =
3658 fidl::endpoints::create_proxy::<fnp_properties::PropertyWatcherMarker>();
3659 let (networks_proxy, networks_stream) =
3660 fidl::endpoints::create_proxy_and_stream::<fnp_properties::NetworksMarker>();
3661 service.add_stream(networks_stream);
3662
3663 let watch_req =
3664 networks_proxy.watch_properties(fnp_properties::NetworksWatchPropertiesRequest {
3665 network: Some(token),
3666 properties: Some(fnp_properties::PropertyInterest::SOCKET_MARKS),
3667 watcher: Some(server_end),
3668 ..Default::default()
3669 });
3670
3671 let req_event = service.select_next_some().await;
3672 assert_eq!(
3673 service.handle_event(req_event).await.expect("Failed to handle event"),
3674 DelegatedNetworkUpdateResult::default()
3675 );
3676 assert_matches!(watch_req.await, Ok(Ok(())));
3677
3678 let watch_fut1 = watcher.watch();
3680 let pw_event1 = service.select_next_some().await;
3681 assert_eq!(
3682 service.handle_event(pw_event1).await.expect("Failed to handle event"),
3683 DelegatedNetworkUpdateResult::default()
3684 );
3685 let _ = watch_fut1.await.unwrap().unwrap();
3686
3687 let mut watch_fut2 = watcher.watch();
3689 let pw_event2 = service.select_next_some().await;
3690 assert_eq!(
3691 service.handle_event(pw_event2).await.expect("Failed to handle event"),
3692 DelegatedNetworkUpdateResult::default()
3693 );
3694 assert_matches!((&mut watch_fut2).now_or_never(), None);
3695 assert_eq!(service.property_watchers.len(), 1);
3696
3697 drop(watch_fut2);
3699 drop(watcher);
3700
3701 let disconnect_event = service.select_next_some().await;
3702 assert_eq!(
3703 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
3704 DelegatedNetworkUpdateResult::default()
3705 );
3706
3707 assert!(service.property_watchers.is_empty());
3709 assert!(service.generations_by_connection.properties.is_empty());
3710 }
3711
3712 #[fuchsia::test]
3713 async fn test_delegated_networks_single_connection() {
3714 let mut service = NetpolNetworksService::default();
3715 let (proxy1, stream1) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3716 service.add_stream(stream1);
3717 assert!(service.delegated_networks_client.is_some());
3718
3719 assert_eq!(
3721 process_fidl_request(&mut service, proxy1.remove(1)).await,
3722 Err(NetworkRegistryRemoveError::NotFound)
3723 );
3724
3725 let (proxy2, stream2) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3727 service.add_stream(stream2);
3728 assert_matches!(
3729 proxy2.remove(1).await,
3730 Err(fidl::Error::ClientChannelClosed { epitaph, .. })
3731 if epitaph == zx::Status::ALREADY_EXISTS
3732 );
3733
3734 assert_eq!(
3736 process_fidl_request(&mut service, proxy1.remove(1)).await,
3737 Err(NetworkRegistryRemoveError::NotFound)
3738 );
3739
3740 drop(proxy1);
3743 let disconnect_event = service.select_next_some().await;
3744 assert_eq!(
3745 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
3746 DelegatedNetworkUpdateResult::default()
3747 );
3748 assert!(service.delegated_networks_client.is_none());
3749
3750 let (proxy3, stream3) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3751 service.add_stream(stream3);
3752 assert_eq!(
3753 process_fidl_request(&mut service, proxy3.remove(1)).await,
3754 Err(NetworkRegistryRemoveError::NotFound)
3755 );
3756 }
3757
3758 #[fuchsia::test]
3759 async fn test_delegated_networks_client_disconnect_cleans_up_state() {
3760 let mut service = NetpolNetworksService::default();
3761 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3762 service.add_stream(stream);
3763
3764 const STARNIX_ID_1: u32 = 1;
3766 const STARNIX_ID_2: u32 = 2;
3767 const SOCKET_MARK_1: u32 = 100;
3768 const SOCKET_MARK_2: u32 = 200;
3769
3770 service
3772 .update(NetworkRegistryUpdate::ChangeNetwork(
3773 FUCHSIA_ID_1,
3774 NetworkUpdate::Properties(NetworkPropertiesChange {
3775 added: true,
3776 ..Default::default()
3777 }),
3778 ))
3779 .await;
3780
3781 assert_eq!(
3782 process_fidl_request(
3783 &mut service,
3784 proxy.add(&starnix_network_payload(STARNIX_ID_1, SOCKET_MARK_1))
3785 )
3786 .await,
3787 Ok(())
3788 );
3789 assert_eq!(
3790 process_fidl_request(
3791 &mut service,
3792 proxy.add(&starnix_network_payload(STARNIX_ID_2, SOCKET_MARK_2))
3793 )
3794 .await,
3795 Ok(())
3796 );
3797 assert_eq!(
3798 process_fidl_request(
3799 &mut service,
3800 proxy.set_default(&fposix_socket::OptionalUint32::Value(STARNIX_ID_1)),
3801 )
3802 .await,
3803 Ok(())
3804 );
3805 assert_eq!(service.network_registry.starnix_default, Some(DELEGATED_ID_1));
3806 assert_eq!(service.network_registry.networks.len(), 3);
3807
3808 drop(proxy);
3811 let disconnect_event = service.select_next_some().await;
3812 assert_eq!(
3813 service.handle_event(disconnect_event).await.expect("Failed to handle event"),
3814 DelegatedNetworkUpdateResult { dns_servers: Some(vec![]) }
3815 );
3816 assert_eq!(service.network_registry.starnix_default, None);
3817 assert_eq!(
3818 service.network_registry.networks.keys().copied().collect::<Vec<_>>(),
3819 vec![FUCHSIA_ID_1]
3820 );
3821
3822 let (proxy2, stream2) = fidl::endpoints::create_proxy_and_stream::<NetworkRegistryMarker>();
3824 service.add_stream(stream2);
3825 assert_eq!(
3826 process_fidl_request(
3827 &mut service,
3828 proxy2.add(&starnix_network_payload(STARNIX_ID_1, SOCKET_MARK_2)),
3829 )
3830 .await,
3831 Ok(())
3832 );
3833 }
3834}