async fn handle_interface_watcher_event(
        &mut self,
        event: fnet_interfaces::Event,
        watchers: &mut DnsServerWatchers<'_>,
    ) -> Result<(), errors::Error> {
        match self
            .interface_properties
            .update(event)
            .context("failed to update interface properties with watcher event")
            .map_err(errors::Error::Fatal)?
        {
            fnet_interfaces_ext::UpdateResult::Added(properties) => {
                match self.interface_states.get_mut(&properties.id) {
                    Some(state) => state
                        .on_discovery(properties, self.dhcpv6_client_provider.as_ref(), watchers)
                        .await
                        .context("failed to handle interface added event"),
                    // An interface netcfg won't be configuring was added, do nothing.
                    None => Ok(()),
                }
            }
            fnet_interfaces_ext::UpdateResult::Existing(properties) => {
                match self.interface_states.get_mut(&properties.id) {
                    Some(state) => state
                        .on_discovery(properties, self.dhcpv6_client_provider.as_ref(), watchers)
                        .await
                        .context("failed to handle existing interface event"),
                    // An interface netcfg won't be configuring was discovered, do nothing.
                    None => Ok(()),
                }
            }
            fnet_interfaces_ext::UpdateResult::Changed {
                previous: fnet_interfaces::Properties { online: previous_online, .. },
                current: current_properties,
            } => {
                let &fnet_interfaces_ext::Properties {
                    id, ref name, online, ref addresses, ..
                } = current_properties;
                match self.interface_states.get_mut(&id) {
                    // An interface netcfg is not configuring was changed, do nothing.
                    None => return Ok(()),
                    Some(InterfaceState::Host(HostInterfaceState { dhcpv6_client_addr })) => {
                        let dhcpv6_client_provider =
                            if let Some(dhcpv6_client_provider) = &self.dhcpv6_client_provider {
                                dhcpv6_client_provider
                            } else {
                                return Ok(());
                            };

                        // Stop DHCPv6 client if interface went down.
                        if !online {
                            let sockaddr = match dhcpv6_client_addr.take() {
                                Some(s) => s,
                                None => return Ok(()),
                            };

                            info!(
                                "host interface {} (id={}) went down \
                                so stopping DHCPv6 client w/ sockaddr = {}",
                                name,
                                id,
                                sockaddr.display_ext(),
                            );

                            return dhcpv6::stop_client(
                                &self.lookup_admin,
                                &mut self.dns_servers,
                                id,
                                watchers,
                            )
                            .await
                            .with_context(|| {
                                format!(
                                    "error stopping DHCPv6 client on down interface {} (id={})",
                                    name, id
                                )
                            });
                        }

                        // Stop the DHCPv6 client if its address can no longer be found on the
                        // interface.
                        if let Some(sockaddr) = dhcpv6_client_addr {
                            let &mut fnet::Ipv6SocketAddress { address, port: _, zone_index: _ } =
                                sockaddr;
                            if !addresses.iter().any(
                                |&fnet_interfaces_ext::Address {
                                     addr: fnet::Subnet { addr, prefix_len: _ },
                                     valid_until: _,
                                 }| {
                                    addr == fnet::IpAddress::Ipv6(address)
                                },
                            ) {
                                let sockaddr = *sockaddr;
                                *dhcpv6_client_addr = None;

                                info!(
                                    "stopping DHCPv6 client on host interface {} (id={}) \
                                    w/ removed sockaddr = {}",
                                    name,
                                    id,
                                    sockaddr.display_ext(),
                                );

                                let () =
                                    dhcpv6::stop_client(
                                        &self.lookup_admin,
                                        &mut self.dns_servers,
                                        id,
                                        watchers,
                                    )
                                    .await
                                    .with_context(|| {
                                        format!(
                                            "error stopping DHCPv6 client on  interface {} (id={}) \
                                            since sockaddr {} was removed",
                                            name, id, sockaddr.display_ext()
                                        )
                                    })?;
                            }
                        }

                        // Start a DHCPv6 client if there isn't one.
                        if dhcpv6_client_addr.is_none() {
                            *dhcpv6_client_addr = start_dhcpv6_client(
                                current_properties,
                                dhcpv6_client_provider,
                                watchers,
                            )?;
                        }
                        Ok(())
                    }
                    Some(InterfaceState::WlanAp(WlanApInterfaceState {})) => {
                        // TODO(fxbug.dev/55879): Stop the DHCP server when the address it is
                        // listening on is removed.
                        let dhcp_server = if let Some(dhcp_server) = &self.dhcp_server {
                            dhcp_server
                        } else {
                            return Ok(());
                        };

                        if previous_online.map_or(true, |previous_online| previous_online == online)
                        {
                            return Ok(());
                        }

                        if online {
                            info!(
                                "WLAN AP interface {} (id={}) came up so starting DHCP server",
                                name, id
                            );
                            dhcpv4::start_server(dhcp_server)
                                .await
                                .context("error starting DHCP server")
                        } else {
                            info!(
                                "WLAN AP interface {} (id={}) went down so stopping DHCP server",
                                name, id
                            );
                            dhcpv4::stop_server(dhcp_server)
                                .await
                                .context("error stopping DHCP server")
                        }
                    }
                }
            }
            fnet_interfaces_ext::UpdateResult::Removed(fnet_interfaces_ext::Properties {
                id,
                name,
                ..
            }) => {
                match self.interface_states.remove(&id) {
                    // An interface netcfg was not responsible for configuring was removed, do
                    // nothing.
                    None => Ok(()),
                    Some(InterfaceState::Host(HostInterfaceState { mut dhcpv6_client_addr })) => {
                        let sockaddr = match dhcpv6_client_addr.take() {
                            Some(s) => s,
                            None => return Ok(()),
                        };

                        info!(
                            "host interface {} (id={}) removed \
                            so stopping DHCPv6 client w/ sockaddr = {}",
                            name,
                            id,
                            sockaddr.display_ext()
                        );

                        dhcpv6::stop_client(&self.lookup_admin, &mut self.dns_servers, id, watchers)
                            .await
                            .with_context(|| {
                                format!(
                                    "error stopping DHCPv6 client on removed interface {} (id={})",
                                    name, id
                                )
                            })
                    }
                    Some(InterfaceState::WlanAp(WlanApInterfaceState {})) => {
                        if let Some(dhcp_server) = &self.dhcp_server {
                            // The DHCP server should only run on the WLAN AP interface, so stop it
                            // since the AP interface is removed.
                            info!(
                                "WLAN AP interface {} (id={}) is removed, stopping DHCP server",
                                name, id
                            );
                            dhcpv4::stop_server(dhcp_server)
                                .await
                                .context("error stopping DHCP server")
                        } else {
                            Ok(())
                        }
                    }
                }
                .context("failed to handle interface removed event")
            }
            fnet_interfaces_ext::UpdateResult::NoChange => Ok(()),
        }
    }
/// Handles an interface watcher event (existing, added, changed, or removed).
Handles an interface watcher event (existing, added, changed, or removed).
Handles an interface watcher event ( existing added changed or removed ) .
async fn handle_interface_watcher_event(
        &mut self,
        event: fnet_interfaces::Event,
        watchers: &mut DnsServerWatchers<'_>,
    ) -> Result<(), errors::Error> {
        match self
            .interface_properties
            .update(event)
            .context("failed to update interface properties with watcher event")
            .map_err(errors::Error::Fatal)?
        {
            fnet_interfaces_ext::UpdateResult::Added(properties) => {
                match self.interface_states.get_mut(&properties.id) {
                    Some(state) => state
                        .on_discovery(properties, self.dhcpv6_client_provider.as_ref(), watchers)
                        .await
                        .context("failed to handle interface added event"),
                    // An interface netcfg won't be configuring was added, do nothing.
                    None => Ok(()),
                }
            }
            fnet_interfaces_ext::UpdateResult::Existing(properties) => {
                match self.interface_states.get_mut(&properties.id) {
                    Some(state) => state
                        .on_discovery(properties, self.dhcpv6_client_provider.as_ref(), watchers)
                        .await
                        .context("failed to handle existing interface event"),
                    // An interface netcfg won't be configuring was discovered, do nothing.
                    None => Ok(()),
                }
            }
            fnet_interfaces_ext::UpdateResult::Changed {
                previous: fnet_interfaces::Properties { online: previous_online, .. },
                current: current_properties,
            } => {
                let &fnet_interfaces_ext::Properties {
                    id, ref name, online, ref addresses, ..
                } = current_properties;
                match self.interface_states.get_mut(&id) {
                    // An interface netcfg is not configuring was changed, do nothing.
                    None => return Ok(()),
                    Some(InterfaceState::Host(HostInterfaceState { dhcpv6_client_addr })) => {
                        let dhcpv6_client_provider =
                            if let Some(dhcpv6_client_provider) = &self.dhcpv6_client_provider {
                                dhcpv6_client_provider
                            } else {
                                return Ok(());
                            };
                        // Stop DHCPv6 client if interface went down.
                        if !online {
                            let sockaddr = match dhcpv6_client_addr.take() {
                                Some(s) => s,
                                None => return Ok(()),
                            };
                            info!(
                                "host interface {} (id={}) went down \
                                so stopping DHCPv6 client w/ sockaddr = {}",
                                name,
                                id,
                                sockaddr.display_ext(),
                            );
                            return dhcpv6::stop_client(
                                &self.lookup_admin,
                                &mut self.dns_servers,
                                id,
                                watchers,
                            )
                            .await
                            .with_context(|| {
                                format!(
                                    "error stopping DHCPv6 client on down interface {} (id={})",
                                    name, id
                                )
                            });
                        }
                        // Stop the DHCPv6 client if its address can no longer be found on the
                        // interface.
                        if let Some(sockaddr) = dhcpv6_client_addr {
                            let &mut fnet::Ipv6SocketAddress { address, port: _, zone_index: _ } =
                                sockaddr;
                            if !addresses.iter().any(
                                |&fnet_interfaces_ext::Address {
                                     addr: fnet::Subnet { addr, prefix_len: _ },
                                     valid_until: _,
                                 }| {
                                    addr == fnet::IpAddress::Ipv6(address)
                                },
                            ) {
                                let sockaddr = *sockaddr;
                                *dhcpv6_client_addr = None;
                                info!(
                                    "stopping DHCPv6 client on host interface {} (id={}) \
                                    w/ removed sockaddr = {}",
                                    name,
                                    id,
                                    sockaddr.display_ext(),
                                );
                                let () =
                                    dhcpv6::stop_client(
                                        &self.lookup_admin,
                                        &mut self.dns_servers,
                                        id,
                                        watchers,
                                    )
                                    .await
                                    .with_context(|| {
                                        format!(
                                            "error stopping DHCPv6 client on  interface {} (id={}) \
                                            since sockaddr {} was removed",
                                            name, id, sockaddr.display_ext()
                                        )
                                    })?;
                            }
                        }
                        // Start a DHCPv6 client if there isn't one.
                        if dhcpv6_client_addr.is_none() {
                            *dhcpv6_client_addr = start_dhcpv6_client(
                                current_properties,
                                dhcpv6_client_provider,
                                watchers,
                            )?;
                        }
                        Ok(())
                    }
                    Some(InterfaceState::WlanAp(WlanApInterfaceState {})) => {
                        // TODO(fxbug.dev/55879): Stop the DHCP server when the address it is
                        // listening on is removed.
                        let dhcp_server = if let Some(dhcp_server) = &self.dhcp_server {
                            dhcp_server
                        } else {
                            return Ok(());
                        };
                        if previous_online.map_or(true, |previous_online| previous_online == online)
                        {
                            return Ok(());
                        }
                        if online {
                            info!(
                                "WLAN AP interface {} (id={}) came up so starting DHCP server",
                                name, id
                            );
                            dhcpv4::start_server(dhcp_server)
                                .await
                                .context("error starting DHCP server")
                        } else {
                            info!(
                                "WLAN AP interface {} (id={}) went down so stopping DHCP server",
                                name, id
                            );
                            dhcpv4::stop_server(dhcp_server)
                                .await
                                .context("error stopping DHCP server")
                        }
                    }
                }
            }
            fnet_interfaces_ext::UpdateResult::Removed(fnet_interfaces_ext::Properties {
                id,
                name,
                ..
            }) => {
                match self.interface_states.remove(&id) {
                    // An interface netcfg was not responsible for configuring was removed, do
                    // nothing.
                    None => Ok(()),
                    Some(InterfaceState::Host(HostInterfaceState { mut dhcpv6_client_addr })) => {
                        let sockaddr = match dhcpv6_client_addr.take() {
                            Some(s) => s,
                            None => return Ok(()),
                        };
                        info!(
                            "host interface {} (id={}) removed \
                            so stopping DHCPv6 client w/ sockaddr = {}",
                            name,
                            id,
                            sockaddr.display_ext()
                        );
                        dhcpv6::stop_client(&self.lookup_admin, &mut self.dns_servers, id, watchers)
                            .await
                            .with_context(|| {
                                format!(
                                    "error stopping DHCPv6 client on removed interface {} (id={})",
                                    name, id
                                )
                            })
                    }
                    Some(InterfaceState::WlanAp(WlanApInterfaceState {})) => {
                        if let Some(dhcp_server) = &self.dhcp_server {
                            // The DHCP server should only run on the WLAN AP interface, so stop it
                            // since the AP interface is removed.
                            info!(
                                "WLAN AP interface {} (id={}) is removed, stopping DHCP server",
                                name, id
                            );
                            dhcpv4::stop_server(dhcp_server)
                                .await
                                .context("error stopping DHCP server")
                        } else {
                            Ok(())
                        }
                    }
                }
                .context("failed to handle interface removed event")
            }
            fnet_interfaces_ext::UpdateResult::NoChange => Ok(()),
        }
    }
async fn handle_interface_watcher_event ( & mut self , event : fnet_interfaces :: Event , watchers : & mut DnsServerWatchers < ' _ > , ) -> Result < ( ) , errors :: Error > { match self . interface_properties . update ( event ) . context ( " " ) . map_err ( errors :: Error :: Fatal ) ? { fnet_interfaces_ext :: UpdateResult :: Added ( properties ) => { match self . interface_states . get_mut ( & properties . id ) { Some ( state ) => state . on_discovery ( properties , self . dhcpv6_client_provider . as_ref ( ) , watchers ) . await . context ( " " ) , // An interface netcfg won't be configuring was added, do nothing. None => Ok ( ( ) ) , } } fnet_interfaces_ext :: UpdateResult :: Existing ( properties ) => { match self . interface_states . get_mut ( & properties . id ) { Some ( state ) => state . on_discovery ( properties , self . dhcpv6_client_provider . as_ref ( ) , watchers ) . await . context ( " " ) , // An interface netcfg won't be configuring was discovered, do nothing. None => Ok ( ( ) ) , } } fnet_interfaces_ext :: UpdateResult :: Changed { previous : fnet_interfaces :: Properties { online : previous_online , .. } , current : current_properties , } => { let & fnet_interfaces_ext :: Properties { id , ref name , online , ref addresses , .. } = current_properties ; match self . interface_states . get_mut ( & id ) { // An interface netcfg is not configuring was changed, do nothing. None => return Ok ( ( ) ) , Some ( InterfaceState :: Host ( HostInterfaceState { dhcpv6_client_addr } ) ) => { let dhcpv6_client_provider = if let Some ( dhcpv6_client_provider ) = & self . dhcpv6_client_provider { dhcpv6_client_provider } else { return Ok ( ( ) ) ; } ; // Stop DHCPv6 client if interface went down. if ! online { let sockaddr = match dhcpv6_client_addr . take ( ) { Some ( s ) => s , None => return Ok ( ( ) ) , } ; info ! ( " \
 " name id sockaddr display_ext ( ) ) ; return dhcpv6 :: stop_client ( & self . lookup_admin , & mut self . dns_servers , id , watchers , ) . await . with_context ( | | { format ! ( " " name id ) } ) ; } // Stop the DHCPv6 client if its address can no longer be found on the // interface. if let Some ( sockaddr ) = dhcpv6_client_addr { let & mut fnet :: Ipv6SocketAddress { address , port : _ , zone_index : _ } = sockaddr ; if ! addresses . iter ( ) . any ( | & fnet_interfaces_ext :: Address { addr : fnet :: Subnet { addr , prefix_len : _ } , valid_until : _ , } | { addr == fnet :: IpAddress :: Ipv6 ( address ) } , ) { let sockaddr = * sockaddr ; * dhcpv6_client_addr = None ; info ! ( " \
 " name id sockaddr display_ext ( ) ) ; let ( ) = dhcpv6 :: stop_client ( & self . lookup_admin , & mut self . dns_servers , id , watchers , ) . await . with_context ( | | { format ! ( " \
 " name id sockaddr display_ext ( ) ) } ) ? ; } } // Start a DHCPv6 client if there isn't one. if dhcpv6_client_addr . is_none ( ) { * dhcpv6_client_addr = start_dhcpv6_client ( current_properties , dhcpv6_client_provider , watchers , ) ? ; } Ok ( ( ) ) } Some ( InterfaceState :: WlanAp ( WlanApInterfaceState { } ) ) => { // TODO(fxbug.dev/55879): Stop the DHCP server when the address it is // listening on is removed. let dhcp_server = if let Some ( dhcp_server ) = & self . dhcp_server { dhcp_server } else { return Ok ( ( ) ) ; } ; if previous_online . map_or ( true , | previous_online | previous_online == online ) { return Ok ( ( ) ) ; } if online { info ! ( " " name id ) ; dhcpv4 :: start_server ( dhcp_server ) . await . context ( " " ) } else { info ! ( " " name id ) ; dhcpv4 :: stop_server ( dhcp_server ) . await . context ( " " ) } } } } fnet_interfaces_ext :: UpdateResult :: Removed ( fnet_interfaces_ext :: Properties { id , name , .. } ) => { match self . interface_states . remove ( & id ) { // An interface netcfg was not responsible for configuring was removed, do // nothing. None => Ok ( ( ) ) , Some ( InterfaceState :: Host ( HostInterfaceState { mut dhcpv6_client_addr } ) ) => { let sockaddr = match dhcpv6_client_addr . take ( ) { Some ( s ) => s , None => return Ok ( ( ) ) , } ; info ! ( " \
 " name id sockaddr display_ext ( ) ) ; dhcpv6 :: stop_client ( & self . lookup_admin , & mut self . dns_servers , id , watchers ) . await . with_context ( | | { format ! ( " " name id ) } ) } Some ( InterfaceState :: WlanAp ( WlanApInterfaceState { } ) ) => { if let Some ( dhcp_server ) = & self . dhcp_server { // The DHCP server should only run on the WLAN AP interface, so stop it // since the AP interface is removed. info ! ( " " name id ) ; dhcpv4 :: stop_server ( dhcp_server ) . await . context ( " " ) } else { Ok ( ( ) ) } } } . context ( " " ) } fnet_interfaces_ext :: UpdateResult :: NoChange => Ok ( ( ) ) , } }
Handles an interface watcher event (existing, added, changed, or removed).
Handles an interface watcher event ( existing added changed or removed ) .
&mut self
event
fnet_interfaces::Event
watchers
&mut DnsServerWatchers<'_>
&mut self
event
fnet_interfaces::Event
watchers
&mut DnsServerWatchers<'_>