async fn interface_discovery(
    socket_tasks: Arc<Mutex<HashMap<IpAddr, Task<()>>>>,
    e: events::Queue<DaemonEvent>,
    discovery_interval: Duration,
    query_interval: Duration,
    ttl: u32,
) {
    // See fxbug.dev/62617#c10 for details. A macOS system can end up in
    // a situation where the default routes for protocols are on
    // non-functional interfaces, and under such conditions the wildcard
    // listen socket binds will fail. We will repeat attempting to bind
    // them, as newly added interfaces later may unstick the issue, if
    // they introduce new routes. These boolean flags are used to
    // suppress the production of a log output in every interface
    // iteration.
    // In order to manually reproduce these conditions on a macOS
    // system, open Network.prefpane, and for each connection in the
    // list select Advanced... > TCP/IP > Configure IPv6 > Link-local
    // only. Click apply, then restart the ffx daemon.
    let mut should_log_v4_listen_error = true;
    let mut should_log_v6_listen_error = true;

    let mut v4_listen_socket: Weak<UdpSocket> = Weak::new();
    let mut v6_listen_socket: Weak<UdpSocket> = Weak::new();

    loop {
        if v4_listen_socket.upgrade().is_none() {
            match make_listen_socket((MDNS_MCAST_V4, MDNS_PORT).into())
                .context("make_listen_socket for IPv4")
            {
                Ok(sock) => {
                    let sock = Arc::new(sock);
                    v4_listen_socket = Arc::downgrade(&sock);
                    Task::local(recv_loop(sock, e.clone())).detach();
                    should_log_v4_listen_error = true;
                }
                Err(err) => {
                    if should_log_v4_listen_error {
                        log::error!(
                            "unable to bind IPv4 listen socket: {}. Discovery may fail.",
                            err
                        );
                        should_log_v4_listen_error = false;
                    }
                }
            }
        }

        if v6_listen_socket.upgrade().is_none() {
            match make_listen_socket((MDNS_MCAST_V6, MDNS_PORT).into())
                .context("make_listen_socket for IPv6")
            {
                Ok(sock) => {
                    let sock = Arc::new(sock);
                    v6_listen_socket = Arc::downgrade(&sock);
                    Task::local(recv_loop(sock, e.clone())).detach();
                    should_log_v6_listen_error = true;
                }
                Err(err) => {
                    if should_log_v6_listen_error {
                        log::error!(
                            "unable to bind IPv6 listen socket: {}. Discovery may fail.",
                            err
                        );
                        should_log_v6_listen_error = false;
                    }
                }
            }
        }

        // As some operating systems will not error sendmsg/recvmsg for UDP
        // sockets bound to addresses that no longer exist, they must be removed
        // by ensuring that they still exist, otherwise we may be sending out
        // unanswerable queries.
        let mut to_delete = HashSet::<IpAddr>::new();
        for ip in socket_tasks.lock().await.keys() {
            to_delete.insert(ip.clone());
        }

        for iface in get_mcast_interfaces().unwrap_or(Vec::new()) {
            match iface.id() {
                Ok(id) => {
                    if let Some(sock) = v6_listen_socket.upgrade() {
                        let _ = sock.join_multicast_v6(&MDNS_MCAST_V6, id);
                    }
                }
                Err(err) => {
                    log::warn!("{}", err);
                }
            }

            for addr in iface.addrs.iter() {
                to_delete.remove(&addr.ip());

                let mut addr = addr.clone();
                addr.set_port(0);

                // TODO(raggi): remove duplicate joins, log unexpected errors
                if let SocketAddr::V4(addr) = addr {
                    if let Some(sock) = v4_listen_socket.upgrade() {
                        let _ = sock.join_multicast_v4(MDNS_MCAST_V4, *addr.ip());
                    }
                }

                if socket_tasks.lock().await.get(&addr.ip()).is_some() {
                    continue;
                }

                let sock = iface
                    .id()
                    .map(|id| match make_sender_socket(id, addr.clone(), ttl) {
                        Ok(sock) => Some(sock),
                        Err(err) => {
                            log::info!("mdns: failed to bind {}: {}", &addr, err);
                            None
                        }
                    })
                    .ok()
                    .flatten();

                if sock.is_some() {
                    socket_tasks.lock().await.insert(
                        addr.ip().clone(),
                        Task::local(query_recv_loop(
                            Arc::new(sock.unwrap()),
                            e.clone(),
                            query_interval,
                            socket_tasks.clone(),
                        )),
                    );
                }
            }
        }

        // Drop tasks for IP addresses no longer found on the system.
        {
            let mut tasks = socket_tasks.lock().await;
            for ip in to_delete {
                if let Some(handle) = tasks.remove(&ip) {
                    handle.cancel().await;
                }
            }
        }

        Timer::new(discovery_interval).await;
    }
}
// interface_discovery iterates over all multicast interfaces and adds them to
// the socket_tasks if there is not already a task for that interface.
interface_discovery iterates over all multicast interfaces and adds them to
the socket_tasks if there is not already a task for that interface.
interface_discovery iterates over all multicast interfaces and adds them to the socket_tasks if there is not already a task for that interface .
async fn interface_discovery(
    socket_tasks: Arc<Mutex<HashMap<IpAddr, Task<()>>>>,
    e: events::Queue<DaemonEvent>,
    discovery_interval: Duration,
    query_interval: Duration,
    ttl: u32,
) {
    // See fxbug.dev/62617#c10 for details. A macOS system can end up in
    // a situation where the default routes for protocols are on
    // non-functional interfaces, and under such conditions the wildcard
    // listen socket binds will fail. We will repeat attempting to bind
    // them, as newly added interfaces later may unstick the issue, if
    // they introduce new routes. These boolean flags are used to
    // suppress the production of a log output in every interface
    // iteration.
    // In order to manually reproduce these conditions on a macOS
    // system, open Network.prefpane, and for each connection in the
    // list select Advanced... > TCP/IP > Configure IPv6 > Link-local
    // only. Click apply, then restart the ffx daemon.
    let mut should_log_v4_listen_error = true;
    let mut should_log_v6_listen_error = true;
    let mut v4_listen_socket: Weak<UdpSocket> = Weak::new();
    let mut v6_listen_socket: Weak<UdpSocket> = Weak::new();
    loop {
        if v4_listen_socket.upgrade().is_none() {
            match make_listen_socket((MDNS_MCAST_V4, MDNS_PORT).into())
                .context("make_listen_socket for IPv4")
            {
                Ok(sock) => {
                    let sock = Arc::new(sock);
                    v4_listen_socket = Arc::downgrade(&sock);
                    Task::local(recv_loop(sock, e.clone())).detach();
                    should_log_v4_listen_error = true;
                }
                Err(err) => {
                    if should_log_v4_listen_error {
                        log::error!(
                            "unable to bind IPv4 listen socket: {}. Discovery may fail.",
                            err
                        );
                        should_log_v4_listen_error = false;
                    }
                }
            }
        }
        if v6_listen_socket.upgrade().is_none() {
            match make_listen_socket((MDNS_MCAST_V6, MDNS_PORT).into())
                .context("make_listen_socket for IPv6")
            {
                Ok(sock) => {
                    let sock = Arc::new(sock);
                    v6_listen_socket = Arc::downgrade(&sock);
                    Task::local(recv_loop(sock, e.clone())).detach();
                    should_log_v6_listen_error = true;
                }
                Err(err) => {
                    if should_log_v6_listen_error {
                        log::error!(
                            "unable to bind IPv6 listen socket: {}. Discovery may fail.",
                            err
                        );
                        should_log_v6_listen_error = false;
                    }
                }
            }
        }
        // As some operating systems will not error sendmsg/recvmsg for UDP
        // sockets bound to addresses that no longer exist, they must be removed
        // by ensuring that they still exist, otherwise we may be sending out
        // unanswerable queries.
        let mut to_delete = HashSet::<IpAddr>::new();
        for ip in socket_tasks.lock().await.keys() {
            to_delete.insert(ip.clone());
        }
        for iface in get_mcast_interfaces().unwrap_or(Vec::new()) {
            match iface.id() {
                Ok(id) => {
                    if let Some(sock) = v6_listen_socket.upgrade() {
                        let _ = sock.join_multicast_v6(&MDNS_MCAST_V6, id);
                    }
                }
                Err(err) => {
                    log::warn!("{}", err);
                }
            }
            for addr in iface.addrs.iter() {
                to_delete.remove(&addr.ip());
                let mut addr = addr.clone();
                addr.set_port(0);
                // TODO(raggi): remove duplicate joins, log unexpected errors
                if let SocketAddr::V4(addr) = addr {
                    if let Some(sock) = v4_listen_socket.upgrade() {
                        let _ = sock.join_multicast_v4(MDNS_MCAST_V4, *addr.ip());
                    }
                }
                if socket_tasks.lock().await.get(&addr.ip()).is_some() {
                    continue;
                }
                let sock = iface
                    .id()
                    .map(|id| match make_sender_socket(id, addr.clone(), ttl) {
                        Ok(sock) => Some(sock),
                        Err(err) => {
                            log::info!("mdns: failed to bind {}: {}", &addr, err);
                            None
                        }
                    })
                    .ok()
                    .flatten();
                if sock.is_some() {
                    socket_tasks.lock().await.insert(
                        addr.ip().clone(),
                        Task::local(query_recv_loop(
                            Arc::new(sock.unwrap()),
                            e.clone(),
                            query_interval,
                            socket_tasks.clone(),
                        )),
                    );
                }
            }
        }
        // Drop tasks for IP addresses no longer found on the system.
        {
            let mut tasks = socket_tasks.lock().await;
            for ip in to_delete {
                if let Some(handle) = tasks.remove(&ip) {
                    handle.cancel().await;
                }
            }
        }
        Timer::new(discovery_interval).await;
    }
}
async fn interface_discovery ( socket_tasks : Arc < Mutex < HashMap < IpAddr , Task < ( ) > > > > , e : events :: Queue < DaemonEvent > , discovery_interval : Duration , query_interval : Duration , ttl : u32 , ) { // See fxbug.dev/62617#c10 for details. A macOS system can end up in // a situation where the default routes for protocols are on // non-functional interfaces, and under such conditions the wildcard // listen socket binds will fail. We will repeat attempting to bind // them, as newly added interfaces later may unstick the issue, if // they introduce new routes. These boolean flags are used to // suppress the production of a log output in every interface // iteration. // In order to manually reproduce these conditions on a macOS // system, open Network.prefpane, and for each connection in the // list select Advanced... > TCP/IP > Configure IPv6 > Link-local // only. Click apply, then restart the ffx daemon. let mut should_log_v4_listen_error = true ; let mut should_log_v6_listen_error = true ; let mut v4_listen_socket : Weak < UdpSocket > = Weak :: new ( ) ; let mut v6_listen_socket : Weak < UdpSocket > = Weak :: new ( ) ; loop { if v4_listen_socket . upgrade ( ) . is_none ( ) { match make_listen_socket ( ( MDNS_MCAST_V4 , MDNS_PORT ) . into ( ) ) . context ( " " ) { Ok ( sock ) => { let sock = Arc :: new ( sock ) ; v4_listen_socket = Arc :: downgrade ( & sock ) ; Task :: local ( recv_loop ( sock , e . clone ( ) ) ) . detach ( ) ; should_log_v4_listen_error = true ; } Err ( err ) => { if should_log_v4_listen_error { log :: error ! ( " " err ) ; should_log_v4_listen_error = false ; } } } } if v6_listen_socket . upgrade ( ) . is_none ( ) { match make_listen_socket ( ( MDNS_MCAST_V6 , MDNS_PORT ) . into ( ) ) . context ( " " ) { Ok ( sock ) => { let sock = Arc :: new ( sock ) ; v6_listen_socket = Arc :: downgrade ( & sock ) ; Task :: local ( recv_loop ( sock , e . clone ( ) ) ) . detach ( ) ; should_log_v6_listen_error = true ; } Err ( err ) => { if should_log_v6_listen_error { log :: error ! ( " " err ) ; should_log_v6_listen_error = false ; } } } } // As some operating systems will not error sendmsg/recvmsg for UDP // sockets bound to addresses that no longer exist, they must be removed // by ensuring that they still exist, otherwise we may be sending out // unanswerable queries. let mut to_delete = HashSet :: < IpAddr > :: new ( ) ; for ip in socket_tasks . lock ( ) . await . keys ( ) { to_delete . insert ( ip . clone ( ) ) ; } for iface in get_mcast_interfaces ( ) . unwrap_or ( Vec :: new ( ) ) { match iface . id ( ) { Ok ( id ) => { if let Some ( sock ) = v6_listen_socket . upgrade ( ) { let _ = sock . join_multicast_v6 ( & MDNS_MCAST_V6 , id ) ; } } Err ( err ) => { log :: warn ! ( " " err ) ; } } for addr in iface . addrs . iter ( ) { to_delete . remove ( & addr . ip ( ) ) ; let mut addr = addr . clone ( ) ; addr . set_port ( 0 ) ; // TODO(raggi): remove duplicate joins, log unexpected errors if let SocketAddr :: V4 ( addr ) = addr { if let Some ( sock ) = v4_listen_socket . upgrade ( ) { let _ = sock . join_multicast_v4 ( MDNS_MCAST_V4 , * addr . ip ( ) ) ; } } if socket_tasks . lock ( ) . await . get ( & addr . ip ( ) ) . is_some ( ) { continue ; } let sock = iface . id ( ) . map ( | id | match make_sender_socket ( id , addr . clone ( ) , ttl ) { Ok ( sock ) => Some ( sock ) , Err ( err ) => { log :: info ! ( " " addr err ) ; None } } ) . ok ( ) . flatten ( ) ; if sock . is_some ( ) { socket_tasks . lock ( ) . await . insert ( addr . ip ( ) . clone ( ) , Task :: local ( query_recv_loop ( Arc :: new ( sock . unwrap ( ) ) , e . clone ( ) , query_interval , socket_tasks . clone ( ) , ) ) , ) ; } } } // Drop tasks for IP addresses no longer found on the system. { let mut tasks = socket_tasks . lock ( ) . await ; for ip in to_delete { if let Some ( handle ) = tasks . remove ( & ip ) { handle . cancel ( ) . await ; } } } Timer :: new ( discovery_interval ) . await ; } }
interface_discovery iterates over all multicast interfaces and adds them to
the socket_tasks if there is not already a task for that interface.
interface_discovery iterates over all multicast interfaces and adds them to the socket_tasks if there is not already a task for that interface .
socket_tasks
Arc<Mutex<HashMap<IpAddr, Task<()>>>>
e
events::Queue<DaemonEvent>
discovery_interval
Duration
query_interval
Duration
ttl
u32
socket_tasks
Arc<Mutex<HashMap<IpAddr, Task<()>>>>
e
events::Queue<DaemonEvent>
discovery_interval
Duration
query_interval
Duration
ttl
u32