Skip to main content

mdns_sd/
service_daemon.rs

1//! Service daemon for mDNS Service Discovery.
2
3// How DNS-based Service Discovery works in a nutshell:
4//
5// (excerpt from RFC 6763)
6// .... that a particular service instance can be
7//    described using a DNS SRV [RFC2782] and DNS TXT [RFC1035] record.
8//    The SRV record has a name of the form "<Instance>.<Service>.<Domain>"
9//    and gives the target host and port where the service instance can be
10//    reached.  The DNS TXT record of the same name gives additional
11//    information about this instance, in a structured form using key/value
12//    pairs, described in Section 6.  A client discovers the list of
13//    available instances of a given service type using a query for a DNS
14//    PTR [RFC1035] record with a name of the form "<Service>.<Domain>",
15//    which returns a set of zero or more names, which are the names of the
16//    aforementioned DNS SRV/TXT record pairs.
17//
18// Some naming conventions in this source code:
19//
20// `ty_domain` refers to service type together with domain name, i.e. <service>.<domain>.
21// Every <service> consists of two labels: service itself and "_udp." or "_tcp".
22// See RFC 6763 section 7 Service Names.
23//     for example: `_my-service._udp.local.`
24//
25// `fullname` refers to a full Service Instance Name, i.e. <instance>.<service>.<domain>
26//     for example: `my_home._my-service._udp.local.`
27//
28// In mDNS and DNS, the basic data structure is "Resource Record" (RR), where
29// in Service Discovery, the basic data structure is "Service Info". One Service Info
30// corresponds to a set of DNS Resource Records.
31#[cfg(feature = "logging")]
32use crate::log::{debug, error, trace};
33use crate::{
34    current_time_millis,
35    dns_cache::{DnsCache, IpType},
36    dns_parser::{
37        ip_address_rr_type, max_pkt_absolute, DnsAddress, DnsEntryExt, DnsIncoming, DnsOutgoing,
38        DnsPointer, DnsRecordBox, DnsRecordExt, DnsSrv, DnsTxt, InterfaceId, RRType, ScopedIp,
39        CLASS_CACHE_FLUSH, CLASS_IN, FLAGS_AA, FLAGS_QR_QUERY, FLAGS_QR_RESPONSE,
40        MAX_PKT_ABSOLUTE_IPV6, MAX_PKT_DEFAULT,
41    },
42    error::{e_fmt, Error, Result},
43    service_info::{
44        valid_ip_on_intf, DnsRegistry, MyIntf, Probe, ServiceInfo, ServiceStatus,
45        MULTICAST_RATE_LIMIT_MILLIS,
46    },
47    Receiver, ResolvedService, TxtProperties,
48};
49use flume::{bounded, Sender, TrySendError};
50use if_addrs::{IfAddr, Interface};
51use mio::{event::Source, net::UdpSocket as MioUdpSocket, Interest, Poll, Registry, Token};
52use socket2::Domain;
53use socket_pktinfo::PktInfoUdpSocket;
54use std::{
55    cmp::{self, Reverse},
56    collections::{hash_map::Entry, BinaryHeap, HashMap, HashSet},
57    fmt, io,
58    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, UdpSocket},
59    str, thread,
60    time::Duration,
61    vec,
62};
63
64/// The default max length of the service name without domain, not including the
65/// leading underscore (`_`). It is set to 15 per
66/// [RFC 6763 section 7.2](https://www.rfc-editor.org/rfc/rfc6763#section-7.2).
67pub const SERVICE_NAME_LEN_MAX_DEFAULT: u8 = 15;
68
69/// The default interval for checking IP changes automatically.
70pub const IP_CHECK_INTERVAL_IN_SECS_DEFAULT: u32 = 5;
71
72/// The default time out for [ServiceDaemon::verify] is 10 seconds, per
73/// [RFC 6762 section 10.4](https://datatracker.ietf.org/doc/html/rfc6762#section-10.4)
74pub const VERIFY_TIMEOUT_DEFAULT: Duration = Duration::from_secs(10);
75
76/// The smallest value accepted by [`ServiceDaemon::set_max_packet_size`].
77pub(crate) const MIN_MAX_PACKET_SIZE: usize = 512;
78
79/// The mDNS port number per RFC 6762.
80pub const MDNS_PORT: u16 = 5353;
81
82const GROUP_ADDR_V4: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 251);
83const GROUP_ADDR_V6: Ipv6Addr = Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 0xfb);
84const LOOPBACK_V4: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
85
86const RESOLVE_WAIT_IN_MILLIS: u64 = 500;
87
88/// RFC 6762 §8.3: the two unsolicited announcements are sent "one second apart".
89/// We schedule the second one strictly wider than the §6 multicast rate-limit
90/// window ([`MULTICAST_RATE_LIMIT_MILLIS`]) so that scheduling skew — the few
91/// millis between capturing this base time and actually stamping the records as
92/// multicast — can never make the rate limit throttle the second announcement
93/// away. A small random jitter is added on top (see `ANNOUNCE_SECOND_JITTER_MILLIS`)
94/// to de-synchronize announcements across hosts and services.
95const ANNOUNCE_SECOND_DELAY_MILLIS: u64 = MULTICAST_RATE_LIMIT_MILLIS + 100;
96
97/// Upper bound (exclusive) of the random jitter added to the second announcement
98/// delay. Kept small so the spacing stays close to the RFC's "one second".
99const ANNOUNCE_SECOND_JITTER_MILLIS: u64 = 50;
100
101// The §8.3 announcement spacing MUST stay strictly wider than the §6 rate-limit
102// window, or the rate limit throttles the second announcement away (leaving only
103// one unsolicited response). Enforced at compile time so the two can't drift.
104#[allow(clippy::assertions_on_constants)]
105const _: () = assert!(ANNOUNCE_SECOND_DELAY_MILLIS > MULTICAST_RATE_LIMIT_MILLIS);
106
107/// RFC 6762 §6:
108/// In any case where there may be multiple responses, such as queries
109/// where the answer is a member of a shared resource record set, each
110/// responder SHOULD delay its response by a random amount of time
111/// selected with uniform random distribution in the range 20-120 ms.
112///
113/// 20ms suggested in the RFC is a bit too long for min. Use 10ms instead.
114const SHARED_RESPONSE_DELAY_MIN_MILLIS: u64 = 10;
115
116/// 120ms suggested in the RFC is too long for max, use 50ms instead.
117const SHARED_RESPONSE_DELAY_MAX_MILLIS: u64 = 50;
118
119/// RFC 6762 §5.2: to avoid accidental synchronization when multiple clients
120/// begin querying at exactly the same moment (e.g. because of some common
121/// external trigger event), a querier SHOULD delay the first query of a
122/// continuous-monitoring series by a randomly chosen amount in the range
123/// 20-120 ms.
124///
125/// Like the responder delay above, we use a shorter 10-50 ms window.
126const INITIAL_QUERY_DELAY_MIN_MILLIS: u64 = 10;
127const INITIAL_QUERY_DELAY_MAX_MILLIS: u64 = 50;
128
129/// Response status code for the service `unregister` call.
130#[derive(Debug)]
131pub enum UnregisterStatus {
132    /// Unregister was successful.
133    OK,
134    /// The service was not found in the registration.
135    NotFound,
136}
137
138/// Status code for the service daemon.
139#[derive(Debug, PartialEq, Clone, Eq)]
140#[non_exhaustive]
141pub enum DaemonStatus {
142    /// The daemon is running as normal.
143    Running,
144
145    /// The daemon has been shutdown.
146    Shutdown,
147}
148
149/// Different counters included in the metrics.
150/// Currently all counters are for outgoing packets.
151#[derive(Hash, Eq, PartialEq)]
152enum Counter {
153    Register,
154    RegisterResend,
155    Unregister,
156    UnregisterResend,
157    Browse,
158    ResolveHostname,
159    Respond,
160    CacheRefreshPTR,
161    CacheRefreshSrvTxt,
162    CacheRefreshAddr,
163    KnownAnswerSuppression,
164    CachedPTR,
165    CachedSRV,
166    CachedAddr,
167    CachedTxt,
168    CachedNSec,
169    CachedSubtype,
170    DnsRegistryProbe,
171    DnsRegistryActive,
172    DnsRegistryTimer,
173    DnsRegistryNameChange,
174    Timer,
175}
176
177impl fmt::Display for Counter {
178    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179        match self {
180            Self::Register => write!(f, "register"),
181            Self::RegisterResend => write!(f, "register-resend"),
182            Self::Unregister => write!(f, "unregister"),
183            Self::UnregisterResend => write!(f, "unregister-resend"),
184            Self::Browse => write!(f, "browse"),
185            Self::ResolveHostname => write!(f, "resolve-hostname"),
186            Self::Respond => write!(f, "respond"),
187            Self::CacheRefreshPTR => write!(f, "cache-refresh-ptr"),
188            Self::CacheRefreshSrvTxt => write!(f, "cache-refresh-srv-txt"),
189            Self::CacheRefreshAddr => write!(f, "cache-refresh-addr"),
190            Self::KnownAnswerSuppression => write!(f, "known-answer-suppression"),
191            Self::CachedPTR => write!(f, "cached-ptr"),
192            Self::CachedSRV => write!(f, "cached-srv"),
193            Self::CachedAddr => write!(f, "cached-addr"),
194            Self::CachedTxt => write!(f, "cached-txt"),
195            Self::CachedNSec => write!(f, "cached-nsec"),
196            Self::CachedSubtype => write!(f, "cached-subtype"),
197            Self::DnsRegistryProbe => write!(f, "dns-registry-probe"),
198            Self::DnsRegistryActive => write!(f, "dns-registry-active"),
199            Self::DnsRegistryTimer => write!(f, "dns-registry-timer"),
200            Self::DnsRegistryNameChange => write!(f, "dns-registry-name-change"),
201            Self::Timer => write!(f, "timer"),
202        }
203    }
204}
205
206#[derive(Debug)]
207enum InternalError {
208    IntfAddrInvalid(Interface),
209}
210
211impl fmt::Display for InternalError {
212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213        match self {
214            InternalError::IntfAddrInvalid(iface) => write!(f, "interface addr invalid: {iface:?}"),
215        }
216    }
217}
218
219type MyResult<T> = core::result::Result<T, InternalError>;
220
221/// A wrapper around UDP socket used by the mDNS daemon.
222///
223/// We do this because `mio` does not support PKTINFO and
224/// does not provide a way to implement `Source` trait directly and safely.
225struct MyUdpSocket {
226    /// The underlying socket that supports control messages like
227    /// `IP_PKTINFO` for IPv4 and `IPV6_PKTINFO` for IPv6.
228    pktinfo: PktInfoUdpSocket,
229
230    /// The mio UDP socket that is a clone of `pktinfo` and
231    /// is used for event polling.
232    mio: MioUdpSocket,
233}
234
235impl MyUdpSocket {
236    pub fn new(pktinfo: PktInfoUdpSocket) -> io::Result<Self> {
237        let std_sock = pktinfo.try_clone_std()?;
238        let mio = MioUdpSocket::from_std(std_sock);
239
240        Ok(Self { pktinfo, mio })
241    }
242}
243
244/// Implements the mio `Source` trait so that we can use `MyUdpSocket` with `Poll`.
245impl Source for MyUdpSocket {
246    fn register(
247        &mut self,
248        registry: &Registry,
249        token: Token,
250        interests: Interest,
251    ) -> io::Result<()> {
252        self.mio.register(registry, token, interests)
253    }
254
255    fn reregister(
256        &mut self,
257        registry: &Registry,
258        token: Token,
259        interests: Interest,
260    ) -> io::Result<()> {
261        self.mio.reregister(registry, token, interests)
262    }
263
264    fn deregister(&mut self, registry: &Registry) -> std::io::Result<()> {
265        self.mio.deregister(registry)
266    }
267}
268
269/// The metrics is a HashMap of (name_key, i64_value).
270/// The main purpose is to help monitoring the mDNS packet traffic.
271pub type Metrics = HashMap<String, i64>;
272
273const IPV4_SOCK_EVENT_KEY: usize = 4; // Pick a key just to indicate IPv4.
274const IPV6_SOCK_EVENT_KEY: usize = 6; // Pick a key just to indicate IPv6.
275const SIGNAL_SOCK_EVENT_KEY: usize = usize::MAX - 1; // avoid to overlap with zc.poll_ids
276
277/// A daemon thread for mDNS
278///
279/// This struct provides a handle and an API to the daemon. It is cloneable.
280#[derive(Clone)]
281pub struct ServiceDaemon {
282    /// Sender handle of the channel to the daemon.
283    sender: Sender<Command>,
284
285    /// Send to this addr to signal that a `Command` is coming.
286    ///
287    /// The daemon listens on this addr together with other mDNS sockets,
288    /// to avoid busy polling the flume channel. If there is a way to poll
289    /// the channel and mDNS sockets together, then this can be removed.
290    signal_addr: SocketAddr,
291}
292
293impl ServiceDaemon {
294    /// Creates a new daemon and spawns a thread to run the daemon.
295    ///
296    /// Creates a new mDNS service daemon using the default port (5353).
297    ///
298    /// For development/testing with custom ports, use [`ServiceDaemon::new_with_port`].
299    ///
300    /// # Errors
301    ///
302    /// Returns [`Error::Msg`] if the daemon cannot be initialized. This wraps an
303    /// underlying OS-level failure.
304    ///
305    /// Note that this constructor does not open the mDNS multicast sockets — those
306    /// are opened lazily by the daemon thread once it starts, so platform issues
307    /// such as "multicast not permitted" are surfaced later via [`DaemonEvent`] from
308    /// [`monitor`](Self::monitor) rather than here.
309    pub fn new() -> Result<Self> {
310        Self::new_with_port(MDNS_PORT)
311    }
312
313    /// Creates a new mDNS service daemon using a custom port.
314    ///
315    /// # Arguments
316    ///
317    /// * `port` - The UDP port to bind for mDNS communication.
318    ///   - In production, this should be `MDNS_PORT` (5353) per RFC 6762.
319    ///   - For development/testing, you can use a non-standard port (e.g., 5454)
320    ///     to avoid conflicts with system mDNS services.
321    ///   - Both publisher and browser must use the same port to communicate.
322    ///
323    /// # Example
324    ///
325    /// ```no_run
326    /// use mdns_sd::ServiceDaemon;
327    ///
328    /// // Use standard mDNS port (production)
329    /// let daemon = ServiceDaemon::new_with_port(5353)?;
330    ///
331    /// // Use custom port for development (avoids macOS Bonjour conflict)
332    /// let daemon_dev = ServiceDaemon::new_with_port(5454)?;
333    /// # Ok::<(), mdns_sd::Error>(())
334    /// ```
335    ///
336    /// # Errors
337    ///
338    /// See [`new`](Self::new) for the set of OS-level failures that may surface
339    /// here. Note that `port` is *not* validated against the kernel until the
340    /// daemon thread tries to bind the mDNS sockets, so an unusable `port`
341    /// (e.g., already in use, requires elevated privileges) will not be
342    /// reported by this constructor — listen for such failures via
343    /// [`monitor`](Self::monitor).
344    pub fn new_with_port(port: u16) -> Result<Self> {
345        // Use port 0 to allow the system assign a random available port,
346        // no need for a pre-defined port number.
347        let signal_addr = SocketAddrV4::new(LOOPBACK_V4, 0);
348
349        let signal_sock = UdpSocket::bind(signal_addr)
350            .map_err(|e| e_fmt!("failed to create signal_sock for daemon: {}", e))?;
351
352        // Get the socket with the OS chosen port
353        let signal_addr = signal_sock
354            .local_addr()
355            .map_err(|e| e_fmt!("failed to get signal sock addr: {}", e))?;
356
357        // Must be nonblocking so we can listen to it together with mDNS sockets.
358        signal_sock
359            .set_nonblocking(true)
360            .map_err(|e| e_fmt!("failed to set nonblocking for signal socket: {}", e))?;
361
362        let poller = Poll::new().map_err(|e| e_fmt!("failed to create mio Poll: {e}"))?;
363
364        let (sender, receiver) = bounded(100);
365
366        // Spawn the daemon thread
367        let mio_sock = MioUdpSocket::from_std(signal_sock);
368        let cmd_sender = sender.clone();
369        thread::Builder::new()
370            .name("mDNS_daemon".to_string())
371            .spawn(move || {
372                Self::daemon_thread(mio_sock, poller, receiver, port, cmd_sender, signal_addr)
373            })
374            .map_err(|e| e_fmt!("thread builder failed to spawn: {}", e))?;
375
376        Ok(Self {
377            sender,
378            signal_addr,
379        })
380    }
381
382    /// Sends `cmd` to the daemon via its channel, and sends a signal
383    /// to its sock addr to notify.
384    fn send_cmd(&self, cmd: Command) -> Result<()> {
385        let cmd_name = cmd.to_string();
386
387        // First, send to the flume channel.
388        self.sender.try_send(cmd).map_err(|e| match e {
389            TrySendError::Full(_) => Error::Again,
390            TrySendError::Disconnected(_) => Error::DaemonShutdown,
391        })?;
392
393        // Second, send a signal to notify the daemon.
394        let addr = SocketAddrV4::new(LOOPBACK_V4, 0);
395        let socket = UdpSocket::bind(addr)
396            .map_err(|e| e_fmt!("Failed to create socket to send signal: {}", e))?;
397        socket
398            .send_to(cmd_name.as_bytes(), self.signal_addr)
399            .map_err(|e| {
400                e_fmt!(
401                    "signal socket send_to {} ({}) failed: {}",
402                    self.signal_addr,
403                    cmd_name,
404                    e
405                )
406            })?;
407
408        Ok(())
409    }
410
411    /// Starts browsing for a specific service type.
412    ///
413    /// `service_type` must end with a valid mDNS domain: '._tcp.local.' or '._udp.local.'
414    ///
415    /// Returns a channel `Receiver` to receive events about the service. The caller
416    /// can call `.recv_async().await` on this receiver to handle events in an
417    /// async environment or call `.recv()` in a sync environment.
418    ///
419    /// When a new instance is found, the daemon automatically tries to resolve, i.e.
420    /// finding more details, i.e. SRV records and TXT records.
421    ///
422    /// # Errors
423    ///
424    /// Returns [`Error::Msg`] if `service_type` does not end with
425    /// `._tcp.local.` or `._udp.local.`.
426    ///
427    /// Returns [`Error::Again`] if the daemon's command queue is full.
428    ///
429    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
430    pub fn browse(&self, service_type: &str) -> Result<Receiver<ServiceEvent>> {
431        check_domain_suffix(service_type)?;
432
433        let (resp_s, resp_r) = bounded(10);
434        self.send_cmd(Command::Browse(service_type.to_string(), 1, false, resp_s))?;
435        Ok(resp_r)
436    }
437
438    /// Preforms a "cache-only" browse.
439    ///
440    /// `service_type` must end with a valid mDNS domain: '._tcp.local.' or '._udp.local.'
441    ///
442    /// The functionality is identical to 'browse', but the service events are based solely on the contents
443    /// of the daemon's cache. No actual mDNS query is sent to the network.
444    ///
445    /// See [accept_unsolicited](Self::accept_unsolicited) if you want to do cache-only browsing.
446    ///
447    /// # Errors
448    ///
449    /// Same error conditions as [`browse`](Self::browse).
450    pub fn browse_cache(&self, service_type: &str) -> Result<Receiver<ServiceEvent>> {
451        check_domain_suffix(service_type)?;
452
453        let (resp_s, resp_r) = bounded(10);
454        self.send_cmd(Command::Browse(service_type.to_string(), 1, true, resp_s))?;
455        Ok(resp_r)
456    }
457
458    /// Stops searching for a specific service type.
459    ///
460    /// # Errors
461    ///
462    /// Returns [`Error::Again`] if the daemon's command queue is full.
463    ///
464    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
465    pub fn stop_browse(&self, ty_domain: &str) -> Result<()> {
466        self.send_cmd(Command::StopBrowse(ty_domain.to_string()))
467    }
468
469    /// Starts querying for the ip addresses of a hostname.
470    ///
471    /// Returns a channel `Receiver` to receive events about the hostname.
472    /// The caller can call `.recv_async().await` on this receiver to handle events in an
473    /// async environment or call `.recv()` in a sync environment.
474    ///
475    /// The `timeout` is specified in milliseconds.
476    ///
477    /// # Errors
478    ///
479    /// Returns [`Error::Msg`] if:
480    ///
481    /// - `hostname` does not end with `.local.`;
482    /// - `hostname` is exactly `.local.` (the label before `.local.` is empty);
483    /// - `hostname` is longer than 255 bytes.
484    ///
485    /// Returns [`Error::Again`] if the daemon's command queue is full.
486    ///
487    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
488    pub fn resolve_hostname(
489        &self,
490        hostname: &str,
491        timeout: Option<u64>,
492    ) -> Result<Receiver<HostnameResolutionEvent>> {
493        check_hostname(hostname)?;
494        let (resp_s, resp_r) = bounded(10);
495        self.send_cmd(Command::ResolveHostname(
496            hostname.to_string(),
497            1,
498            resp_s,
499            timeout,
500        ))?;
501        Ok(resp_r)
502    }
503
504    /// Stops querying for the ip addresses of a hostname.
505    ///
506    /// # Errors
507    ///
508    /// Same error conditions as [`stop_browse`](Self::stop_browse).
509    pub fn stop_resolve_hostname(&self, hostname: &str) -> Result<()> {
510        self.send_cmd(Command::StopResolveHostname(hostname.to_string()))
511    }
512
513    /// Registers a service provided by this host.
514    ///
515    /// If `service_info` has no addresses yet and its `addr_auto` is enabled,
516    /// this method will automatically fill in addresses from the host.
517    ///
518    /// To re-announce a service with an updated `service_info`, just call
519    /// this `register` function again. No need to call `unregister` first.
520    ///
521    /// # Errors
522    ///
523    /// Returns [`Error::Msg`] if the [`ServiceInfo`] is malformed, for example:
524    ///
525    /// - the fullname does not end with `._tcp.local.` or `._udp.local.`;
526    /// - the hostname does not end with `.local.`, is exactly `.local.`, or
527    ///   is longer than 255 bytes.
528    ///
529    /// Returns [`Error::Again`] if the daemon's command queue is full.
530    ///
531    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
532    pub fn register(&self, service_info: ServiceInfo) -> Result<()> {
533        check_service_name(service_info.get_fullname())?;
534        check_hostname(service_info.get_hostname())?;
535
536        self.send_cmd(Command::Register(service_info.into()))
537    }
538
539    /// Unregisters a service. This is a graceful shutdown of a service.
540    ///
541    /// Returns a channel receiver that is used to receive the status code
542    /// of the unregister.
543    ///
544    /// # Errors
545    ///
546    /// Returns [`Error::Again`] if the daemon's command queue is full.
547    ///
548    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
549    pub fn unregister(&self, fullname: &str) -> Result<Receiver<UnregisterStatus>> {
550        let (resp_s, resp_r) = bounded(1);
551        self.send_cmd(Command::Unregister(fullname.to_lowercase(), resp_s))?;
552        Ok(resp_r)
553    }
554
555    /// Starts to monitor events from the daemon.
556    ///
557    /// Returns a channel [`Receiver`] of [`DaemonEvent`].
558    ///
559    /// # Errors
560    ///
561    /// Returns [`Error::Again`] if the daemon's command queue is full.
562    ///
563    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
564    pub fn monitor(&self) -> Result<Receiver<DaemonEvent>> {
565        let (resp_s, resp_r) = bounded(100);
566        self.send_cmd(Command::Monitor(resp_s))?;
567        Ok(resp_r)
568    }
569
570    /// Shuts down the daemon thread and returns a channel to receive the status.
571    ///
572    /// # Errors
573    ///
574    /// Returns [`Error::Again`] if the daemon's command queue is full.
575    ///
576    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
577    pub fn shutdown(&self) -> Result<Receiver<DaemonStatus>> {
578        let (resp_s, resp_r) = bounded(1);
579        self.send_cmd(Command::Exit(resp_s))?;
580        Ok(resp_r)
581    }
582
583    /// Returns the status of the daemon.
584    ///
585    /// # Errors
586    ///
587    /// Returns [`Error::Again`] if the daemon's command queue is full.
588    ///
589    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
590    pub fn status(&self) -> Result<Receiver<DaemonStatus>> {
591        let (resp_s, resp_r) = bounded(1);
592
593        if self.sender.is_disconnected() {
594            resp_s
595                .send(DaemonStatus::Shutdown)
596                .map_err(|e| e_fmt!("failed to send daemon status to the client: {}", e))?;
597        } else {
598            self.send_cmd(Command::GetStatus(resp_s))?;
599        }
600
601        Ok(resp_r)
602    }
603
604    /// Returns a channel receiver for the metrics, e.g. input/output counters.
605    ///
606    /// The metrics returned is a snapshot. Hence the caller should call
607    /// this method repeatedly if they want to monitor the metrics continuously.
608    ///
609    /// # Errors
610    ///
611    /// Returns [`Error::Again`] if the daemon's command queue is full.
612    ///
613    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
614    pub fn get_metrics(&self) -> Result<Receiver<Metrics>> {
615        let (resp_s, resp_r) = bounded(1);
616        self.send_cmd(Command::GetMetrics(resp_s))?;
617        Ok(resp_r)
618    }
619
620    /// Change the max length allowed for a service name.
621    ///
622    /// As RFC 6763 defines a length max for a service name, a user should not call
623    /// this method unless they have to. See [`SERVICE_NAME_LEN_MAX_DEFAULT`].
624    ///
625    /// `len_max` is capped at an internal limit, which is currently 30.
626    ///
627    /// # Errors
628    ///
629    /// Returns [`Error::Msg`] if `len_max` exceeds the internal cap (30).
630    ///
631    /// Returns [`Error::Again`] if the daemon's command queue is full.
632    ///
633    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
634    pub fn set_service_name_len_max(&self, len_max: u8) -> Result<()> {
635        const SERVICE_NAME_LEN_MAX_LIMIT: u8 = 30; // Double the default length max.
636
637        if len_max > SERVICE_NAME_LEN_MAX_LIMIT {
638            return Err(Error::Msg(format!(
639                "service name length max {len_max} is too large"
640            )));
641        }
642
643        self.send_cmd(Command::SetOption(DaemonOption::ServiceNameLenMax(len_max)))
644    }
645
646    /// Change the max byte size of a packet this daemon generates on the interfaces
647    /// matching `if_kind`. Use `IfKind::All` to change it on every interface. Messages
648    /// that don't fit are split across multiple packets. A single record that doesn't
649    /// fit in a packet is sent alone in a packet of up to 8952 bytes over IPv6 or 8972
650    /// bytes over IPv4, per RFC 6762 section 17.
651    ///
652    /// The default is `MAX_PKT_DEFAULT` (1452 bytes), small enough to fit in one
653    /// Ethernet frame over either IPv4 or IPv6.
654    ///
655    /// `size` must be in the range `512..=8952`. The minimum of 512 bytes is the classic
656    /// UDP DNS message size of RFC 1035. The maximum of 8952 bytes follows from RFC 6762
657    /// section 17, which caps an mDNS packet at 9000 bytes: we subtract the
658    /// bigger of the two IP headers so that a generated packet is legal over either
659    /// IP version.
660    pub fn set_max_packet_size(&self, if_kind: impl IntoIfKindVec, size: usize) -> Result<()> {
661        if size < MIN_MAX_PACKET_SIZE {
662            return Err(Error::Msg(format!(
663                "max packet size {size} is too small, must be at least {MIN_MAX_PACKET_SIZE}"
664            )));
665        }
666
667        if size > MAX_PKT_ABSOLUTE_IPV6 {
668            return Err(Error::Msg(format!(
669                "max packet size {size} is too big, must be at most {MAX_PKT_ABSOLUTE_IPV6}"
670            )));
671        }
672
673        let if_kind_vec = if_kind.into_vec();
674        self.send_cmd(Command::SetOption(DaemonOption::MaxPacketSize(
675            if_kind_vec.kinds,
676            size,
677        )))
678    }
679
680    /// Change the interval for checking IP changes automatically.
681    ///
682    /// Setting the interval to 0 disables the IP check.
683    ///
684    /// See [`IP_CHECK_INTERVAL_IN_SECS_DEFAULT`] for the default interval.
685    pub fn set_ip_check_interval(&self, interval_in_secs: u32) -> Result<()> {
686        let interval_in_millis = interval_in_secs as u64 * 1000;
687        self.send_cmd(Command::SetOption(DaemonOption::IpCheckInterval(
688            interval_in_millis,
689        )))
690    }
691
692    /// Get the current interval in seconds for checking IP changes automatically.
693    pub fn get_ip_check_interval(&self) -> Result<u32> {
694        let (resp_s, resp_r) = bounded(1);
695        self.send_cmd(Command::GetOption(resp_s))?;
696
697        let option = resp_r
698            .recv_timeout(Duration::from_secs(10))
699            .map_err(|e| e_fmt!("failed to receive ip check interval: {}", e))?;
700        let ip_check_interval_in_secs = option.ip_check_interval / 1000;
701        Ok(ip_check_interval_in_secs as u32)
702    }
703
704    /// Include interfaces that match `if_kind` for this service daemon.
705    ///
706    /// For example:
707    /// ```ignore
708    ///     daemon.enable_interface("en0")?;
709    /// ```
710    pub fn enable_interface(&self, if_kind: impl IntoIfKindVec) -> Result<()> {
711        let if_kind_vec = if_kind.into_vec();
712        self.send_cmd(Command::SetOption(DaemonOption::EnableInterface(
713            if_kind_vec.kinds,
714        )))
715    }
716
717    /// Ignore/exclude interfaces that match `if_kind` for this daemon.
718    ///
719    /// For example:
720    /// ```ignore
721    ///     daemon.disable_interface(IfKind::IPv6)?;
722    /// ```
723    pub fn disable_interface(&self, if_kind: impl IntoIfKindVec) -> Result<()> {
724        let if_kind_vec = if_kind.into_vec();
725        self.send_cmd(Command::SetOption(DaemonOption::DisableInterface(
726            if_kind_vec.kinds,
727        )))
728    }
729
730    /// If `accept` is true, accept and cache all responses, even if there is no active querier
731    /// for a given service type. This is useful / necessary when doing cache-only browsing. See
732    /// [browse_cache](Self::browse_cache).
733    ///
734    /// If `accept` is false (default), accept only responses matching queries that we have initiated.
735    ///
736    /// For example:
737    /// ```ignore
738    ///     daemon.accept_unsolicited(true)?;
739    /// ```
740    pub fn accept_unsolicited(&self, accept: bool) -> Result<()> {
741        self.send_cmd(Command::SetOption(DaemonOption::AcceptUnsolicited(accept)))
742    }
743
744    /// Include or exclude Apple P2P interfaces, e.g. "awdl0", "llw0".
745    /// By default, they are excluded.
746    pub fn include_apple_p2p(&self, include: bool) -> Result<()> {
747        self.send_cmd(Command::SetOption(DaemonOption::IncludeAppleP2P(include)))
748    }
749
750    #[cfg(test)]
751    pub fn test_down_interface(&self, ifname: &str) -> Result<()> {
752        self.send_cmd(Command::SetOption(DaemonOption::TestDownInterface(
753            ifname.to_string(),
754        )))
755    }
756
757    #[cfg(test)]
758    pub fn test_up_interface(&self, ifname: &str) -> Result<()> {
759        self.send_cmd(Command::SetOption(DaemonOption::TestUpInterface(
760            ifname.to_string(),
761        )))
762    }
763
764    /// Enable or disable the loopback for locally sent multicast packets in IPv4.
765    ///
766    /// By default, multicast loop is enabled for IPv4. When disabled, a querier will not
767    /// receive announcements from a responder on the same host.
768    ///
769    /// Reference: <https://learn.microsoft.com/en-us/windows/win32/winsock/ip-multicast-2>
770    ///
771    /// "The Winsock version of the IP_MULTICAST_LOOP option is semantically different than
772    /// the UNIX version of the IP_MULTICAST_LOOP option:
773    ///
774    /// In Winsock, the IP_MULTICAST_LOOP option applies only to the receive path.
775    /// In the UNIX version, the IP_MULTICAST_LOOP option applies to the send path."
776    ///
777    /// Which means, in order NOT to receive localhost announcements, you want to call
778    /// this API on the querier side on Windows, but on the responder side on Unix.
779    pub fn set_multicast_loop_v4(&self, on: bool) -> Result<()> {
780        self.send_cmd(Command::SetOption(DaemonOption::MulticastLoopV4(on)))
781    }
782
783    /// Enable or disable the loopback for locally sent multicast packets in IPv6.
784    ///
785    /// By default, multicast loop is enabled for IPv6. When disabled, a querier will not
786    /// receive announcements from a responder on the same host.
787    ///
788    /// Reference: <https://learn.microsoft.com/en-us/windows/win32/winsock/ip-multicast-2>
789    ///
790    /// "The Winsock version of the IP_MULTICAST_LOOP option is semantically different than
791    /// the UNIX version of the IP_MULTICAST_LOOP option:
792    ///
793    /// In Winsock, the IP_MULTICAST_LOOP option applies only to the receive path.
794    /// In the UNIX version, the IP_MULTICAST_LOOP option applies to the send path."
795    ///
796    /// Which means, in order NOT to receive localhost announcements, you want to call
797    /// this API on the querier side on Windows, but on the responder side on Unix.
798    pub fn set_multicast_loop_v6(&self, on: bool) -> Result<()> {
799        self.send_cmd(Command::SetOption(DaemonOption::MulticastLoopV6(on)))
800    }
801
802    /// Proactively confirms whether a service instance still valid.
803    ///
804    /// This call will issue queries for a service instance's SRV record and Address records.
805    ///
806    /// For `timeout`, most users should use [VERIFY_TIMEOUT_DEFAULT]
807    /// unless there is a reason not to follow RFC.
808    ///
809    /// If no response is received within `timeout`, the current resource
810    /// records will be flushed, and if needed, `ServiceRemoved` event will be
811    /// sent to active queriers.
812    ///
813    /// Reference: [RFC 6762](https://datatracker.ietf.org/doc/html/rfc6762#section-10.4)
814    ///
815    /// # Errors
816    ///
817    /// Returns [`Error::Again`] if the daemon's command queue is full.
818    ///
819    /// Returns [`Error::DaemonShutdown`] if the daemon thread has already exited.
820    pub fn verify(&self, instance_fullname: String, timeout: Duration) -> Result<()> {
821        self.send_cmd(Command::Verify(instance_fullname, timeout))
822    }
823
824    fn daemon_thread(
825        signal_sock: MioUdpSocket,
826        poller: Poll,
827        receiver: Receiver<Command>,
828        port: u16,
829        cmd_sender: Sender<Command>,
830        signal_addr: SocketAddr,
831    ) {
832        let mut zc = Zeroconf::new(signal_sock, poller, port, cmd_sender, signal_addr);
833
834        if let Some(cmd) = zc.run(receiver) {
835            match cmd {
836                Command::Exit(resp_s) => {
837                    // It is guaranteed that the receiver already dropped,
838                    // i.e. the daemon command channel closed.
839                    if let Err(e) = resp_s.send(DaemonStatus::Shutdown) {
840                        debug!("exit: failed to send response of shutdown: {}", e);
841                    }
842                }
843                _ => {
844                    debug!("Unexpected command: {:?}", cmd);
845                }
846            }
847        }
848    }
849}
850
851/// Creates a new UDP socket that uses `intf` to send and recv multicast.
852fn _new_socket_bind(intf: &Interface, should_loop: bool) -> Result<MyUdpSocket> {
853    // Use the same socket for receiving and sending multicast packets.
854    // Such socket has to bind to INADDR_ANY or IN6ADDR_ANY.
855    let intf_ip = &intf.ip();
856    match intf_ip {
857        IpAddr::V4(ip) => {
858            let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), MDNS_PORT);
859            let sock = new_socket(addr.into(), true)?;
860
861            // Join mDNS group to receive packets.
862            sock.join_multicast_v4(&GROUP_ADDR_V4, ip)
863                .map_err(|e| e_fmt!("join multicast group on addr {}: {}", intf_ip, e))?;
864
865            // Set IP_MULTICAST_IF to send packets.
866            sock.set_multicast_if_v4(ip)
867                .map_err(|e| e_fmt!("set multicast_if on addr {}: {}", ip, e))?;
868
869            // Per RFC 6762 section 11:
870            // "All Multicast DNS responses (including responses sent via unicast) SHOULD
871            // be sent with IP TTL set to 255."
872            // Here we set the TTL to 255 for multicast as we don't support unicast yet.
873            sock.set_multicast_ttl_v4(255)
874                .map_err(|e| e_fmt!("set set_multicast_ttl_v4 on addr {}: {}", ip, e))?;
875
876            if !should_loop {
877                sock.set_multicast_loop_v4(false)
878                    .map_err(|e| e_fmt!("failed to set multicast loop v4 for {ip}: {e}"))?;
879            }
880
881            // Test if we can send packets successfully.
882            let multicast_addr = SocketAddrV4::new(GROUP_ADDR_V4, MDNS_PORT).into();
883            let test_packets = DnsOutgoing::new(0).to_data_on_wire(MAX_PKT_DEFAULT, true);
884            for packet in test_packets {
885                sock.send_to(&packet, &multicast_addr)
886                    .map_err(|e| e_fmt!("send multicast packet on addr {}: {}", ip, e))?;
887            }
888            MyUdpSocket::new(sock)
889                .map_err(|e| e_fmt!("failed to create MySocket for interface {}: {e}", intf.name))
890        }
891        IpAddr::V6(ip) => {
892            let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), MDNS_PORT, 0, 0);
893            let sock = new_socket(addr.into(), true)?;
894
895            let if_index = intf.index.unwrap_or(0);
896
897            // Join mDNS group to receive packets.
898            sock.join_multicast_v6(&GROUP_ADDR_V6, if_index)
899                .map_err(|e| e_fmt!("join multicast group on addr {}: {}", ip, e))?;
900
901            // Set IPV6_MULTICAST_IF to send packets.
902            sock.set_multicast_if_v6(if_index)
903                .map_err(|e| e_fmt!("set multicast_if on addr {}: {}", ip, e))?;
904
905            // We are not sending multicast packets to test this socket as there might
906            // be many IPv6 interfaces on a host and could cause such send error:
907            // "No buffer space available (os error 55)".
908
909            MyUdpSocket::new(sock)
910                .map_err(|e| e_fmt!("failed to create MySocket for interface {}: {e}", intf.name))
911        }
912    }
913}
914
915/// Creates a new UDP socket to bind to `port` with REUSEPORT option.
916/// `non_block` indicates whether to set O_NONBLOCK for the socket.
917fn new_socket(addr: SocketAddr, non_block: bool) -> Result<PktInfoUdpSocket> {
918    let domain = match addr {
919        SocketAddr::V4(_) => socket2::Domain::IPV4,
920        SocketAddr::V6(_) => socket2::Domain::IPV6,
921    };
922
923    let fd = PktInfoUdpSocket::new(domain).map_err(|e| e_fmt!("create socket failed: {}", e))?;
924
925    fd.set_reuse_address(true)
926        .map_err(|e| e_fmt!("set ReuseAddr failed: {}", e))?;
927    #[cfg(unix)]
928    if let Err(e) = fd.set_reuse_port(true) {
929        debug!(
930            "SO_REUSEPORT is not supported, continuing without it: {}",
931            e
932        );
933    }
934
935    if non_block {
936        fd.set_nonblocking(true)
937            .map_err(|e| e_fmt!("set O_NONBLOCK: {}", e))?;
938    }
939
940    fd.bind(&addr.into())
941        .map_err(|e| e_fmt!("socket bind to {} failed: {}", &addr, e))?;
942
943    trace!("new socket bind to {}", &addr);
944    Ok(fd)
945}
946
947/// Specify a UNIX timestamp in millis to run `command` for the next time.
948struct ReRun {
949    /// UNIX timestamp in millis.
950    next_time: u64,
951    command: Command,
952}
953
954/// A query response deferred per RFC 6762 §6 (shared response).
955struct DelayedResponse {
956    /// UNIX timestamp in millis at which to send `out`.
957    next_time: u64,
958    out: DnsOutgoing,
959    if_index: u32,
960    is_ipv4: bool,
961}
962
963/// Specify kinds of interfaces. It is used to enable or to disable interfaces in the daemon.
964///
965/// Note that for ergonomic reasons, `From<&str>` and `From<IpAddr>` are implemented.
966#[derive(Debug, Clone)]
967#[non_exhaustive]
968pub enum IfKind {
969    /// All interfaces.
970    All,
971
972    /// All IPv4 interfaces.
973    IPv4,
974
975    /// All IPv6 interfaces.
976    IPv6,
977
978    /// By the interface name, for example "en0"
979    Name(String),
980
981    /// By an IPv4 or IPv6 address.
982    /// This is used to look up the interface. The semantics is to identify an interface of
983    /// IPv4 or IPv6, not a specific address on the interface.
984    Addr(IpAddr),
985
986    /// 127.0.0.1 (or anything in 127.0.0.0/8), enabled by default.
987    ///
988    /// Loopback interfaces are required by some use cases (e.g., OSCQuery) for publishing.
989    LoopbackV4,
990
991    /// ::1/128, enabled by default.
992    LoopbackV6,
993
994    /// By interface index, IPv4 only.
995    IndexV4(u32),
996
997    /// By interface index, IPv6 only.
998    IndexV6(u32),
999
1000    /// By a user-supplied predicate function.
1001    Predicate(IfPredicate),
1002}
1003
1004impl IfKind {
1005    /// Checks if `intf` matches with this interface kind.
1006    pub(crate) fn matches(&self, intf: &Interface) -> bool {
1007        match self {
1008            Self::All => true,
1009            Self::IPv4 => intf.ip().is_ipv4(),
1010            Self::IPv6 => intf.ip().is_ipv6(),
1011            Self::Name(ifname) => ifname == &intf.name,
1012            Self::Addr(addr) => addr == &intf.ip(),
1013            Self::LoopbackV4 => intf.is_loopback() && intf.ip().is_ipv4(),
1014            Self::LoopbackV6 => intf.is_loopback() && intf.ip().is_ipv6(),
1015            Self::IndexV4(idx) => intf.index == Some(*idx) && intf.ip().is_ipv4(),
1016            Self::IndexV6(idx) => intf.index == Some(*idx) && intf.ip().is_ipv6(),
1017            Self::Predicate(p) => p.matches(intf),
1018        }
1019    }
1020}
1021
1022/// The first use case of specifying an interface was to
1023/// use an interface name. Hence adding this for ergonomic reasons.
1024impl From<&str> for IfKind {
1025    fn from(val: &str) -> Self {
1026        Self::Name(val.to_string())
1027    }
1028}
1029
1030impl From<&String> for IfKind {
1031    fn from(val: &String) -> Self {
1032        Self::Name(val.to_string())
1033    }
1034}
1035
1036/// Still for ergonomic reasons.
1037impl From<IpAddr> for IfKind {
1038    fn from(val: IpAddr) -> Self {
1039        Self::Addr(val)
1040    }
1041}
1042
1043/// A list of `IfKind` that can be used to match interfaces.
1044pub struct IfKindVec {
1045    kinds: Vec<IfKind>,
1046}
1047
1048/// A trait that converts a type into a Vec of `IfKind`.
1049pub trait IntoIfKindVec {
1050    fn into_vec(self) -> IfKindVec;
1051}
1052
1053impl<T: Into<IfKind>> IntoIfKindVec for T {
1054    fn into_vec(self) -> IfKindVec {
1055        let if_kind: IfKind = self.into();
1056        IfKindVec {
1057            kinds: vec![if_kind],
1058        }
1059    }
1060}
1061
1062impl<T: Into<IfKind>> IntoIfKindVec for Vec<T> {
1063    fn into_vec(self) -> IfKindVec {
1064        let kinds: Vec<IfKind> = self.into_iter().map(|x| x.into()).collect();
1065        IfKindVec { kinds }
1066    }
1067}
1068
1069/// A predicate function for matching against interfaces.
1070#[derive(Clone)]
1071pub struct IfPredicate(std::sync::Arc<dyn Fn(&Interface) -> bool + Send + Sync>);
1072
1073impl IfPredicate {
1074    /// Creates a predicate from a closure that decides whether an interface
1075    /// matches.
1076    ///
1077    /// # Example
1078    ///
1079    /// ```no_run
1080    /// # use mdns_sd::IfPredicate;
1081    /// // Match any interface that doesn't look like a virtual bridge
1082    /// IfPredicate::new(|intf| !intf.name.starts_with("virbr"));
1083    /// ```
1084    pub fn new(predicate: impl Fn(&Interface) -> bool + Send + Sync + 'static) -> Self {
1085        Self(std::sync::Arc::new(predicate))
1086    }
1087
1088    pub(crate) fn matches(&self, intf: &Interface) -> bool {
1089        self.0(intf)
1090    }
1091}
1092
1093impl std::fmt::Debug for IfPredicate {
1094    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1095        write!(f, "IfPredicate(...)")
1096    }
1097}
1098
1099/// Selection of interfaces.
1100struct IfSelection {
1101    /// The interfaces to be selected.
1102    if_kind: IfKind,
1103
1104    /// Whether the `if_kind` should be enabled or not.
1105    selected: bool,
1106}
1107
1108/// Selection of the max packet size of interfaces.
1109struct MaxPacketSizeSelection {
1110    /// The interfaces to be selected.
1111    if_kind: IfKind,
1112
1113    /// Max byte size of a packet generated for the selected interfaces.
1114    max_packet_size: usize,
1115}
1116
1117/// A struct holding the state. It was inspired by `zeroconf` package in Python.
1118struct Zeroconf {
1119    /// The mDNS port number to use for socket binding.
1120    /// Typically MDNS_PORT (5353), but can be customized for development/testing.
1121    port: u16,
1122
1123    /// Local interfaces keyed by interface index.
1124    my_intfs: HashMap<u32, MyIntf>,
1125
1126    /// A common socket for IPv4 interfaces. It's None if IPv4 is disabled in OS kernel.
1127    ipv4_sock: Option<MyUdpSocket>,
1128
1129    /// A common socket for IPv6 interfaces. It's None if IPv6 is disabled in OS kernel.
1130    ipv6_sock: Option<MyUdpSocket>,
1131
1132    /// Local registered services, keyed by service full names.
1133    my_services: HashMap<String, ServiceInfo>,
1134
1135    /// Received DNS records.
1136    cache: DnsCache,
1137
1138    /// Registered service records, keyed by interface index.
1139    dns_registry_map: HashMap<u32, DnsRegistry>,
1140
1141    /// Active "Browse" commands.
1142    service_queriers: HashMap<String, Sender<ServiceEvent>>, // <ty_domain, channel::sender>
1143
1144    /// Active "ResolveHostname" commands.
1145    ///
1146    /// The timestamps are set at the future timestamp when the command should timeout.
1147    /// `hostname` is case-insensitive and stored in lowercase.
1148    hostname_resolvers: HashMap<String, (Sender<HostnameResolutionEvent>, Option<u64>)>, // <hostname, (channel::sender, UNIX timestamp in millis)>
1149
1150    /// All repeating transmissions.
1151    retransmissions: Vec<ReRun>,
1152
1153    /// Query responses deferred per RFC 6762 §6.
1154    delayed_responses: Vec<DelayedResponse>,
1155
1156    counters: Metrics,
1157
1158    /// Waits for incoming packets.
1159    poller: Poll,
1160
1161    /// Channels to notify events.
1162    monitors: Vec<Sender<DaemonEvent>>,
1163
1164    /// Options
1165    service_name_len_max: u8,
1166
1167    /// Interval in millis to check IP address changes.
1168    ip_check_interval: u64,
1169
1170    /// All max packet size selections called to the daemon, in call order.
1171    /// For an interface matched by more than one, the last one wins.
1172    max_packet_sizes: Vec<MaxPacketSizeSelection>,
1173
1174    /// All interface selections called to the daemon.
1175    if_selections: Vec<IfSelection>,
1176
1177    /// Socket for signaling.
1178    signal_sock: MioUdpSocket,
1179
1180    /// Timestamps marking where we need another iteration of the run loop,
1181    /// to react to events like retransmissions, cache refreshes, interface IP address changes, etc.
1182    ///
1183    /// When the run loop goes through a single iteration, it will
1184    /// set its timeout to the earliest timer in this list.
1185    timers: BinaryHeap<Reverse<u64>>,
1186
1187    status: DaemonStatus,
1188
1189    /// Service instances that are pending for resolving SRV and TXT.
1190    pending_resolves: HashSet<String>,
1191
1192    /// Service instances that are already resolved.
1193    resolved: HashSet<String>,
1194
1195    multicast_loop_v4: bool,
1196
1197    multicast_loop_v6: bool,
1198
1199    accept_unsolicited: bool,
1200
1201    include_apple_p2p: bool,
1202
1203    cmd_sender: Sender<Command>,
1204
1205    signal_addr: SocketAddr,
1206
1207    #[cfg(test)]
1208    test_down_interfaces: HashSet<String>,
1209}
1210
1211/// Join the multicast group for the given interface.
1212fn join_multicast_group(my_sock: &PktInfoUdpSocket, intf: &Interface) -> Result<()> {
1213    let intf_ip = &intf.ip();
1214    match intf_ip {
1215        IpAddr::V4(ip) => {
1216            // Join mDNS group to receive packets.
1217            debug!("join multicast group V4 on {} addr {ip}", intf.name);
1218            my_sock
1219                .join_multicast_v4(&GROUP_ADDR_V4, ip)
1220                .map_err(|e| e_fmt!("PKT join multicast group on addr {}: {}", intf_ip, e))?;
1221        }
1222        IpAddr::V6(ip) => {
1223            let if_index = intf.index.unwrap_or(0);
1224            // Join mDNS group to receive packets.
1225            debug!(
1226                "join multicast group V6 on {} addr {ip} with index {if_index}",
1227                intf.name
1228            );
1229            my_sock
1230                .join_multicast_v6(&GROUP_ADDR_V6, if_index)
1231                .map_err(|e| e_fmt!("PKT join multicast group on addr {}: {}", ip, e))?;
1232        }
1233    }
1234    Ok(())
1235}
1236
1237impl Zeroconf {
1238    fn new(
1239        signal_sock: MioUdpSocket,
1240        poller: Poll,
1241        port: u16,
1242        cmd_sender: Sender<Command>,
1243        signal_addr: SocketAddr,
1244    ) -> Self {
1245        // Get interfaces.
1246        let my_ifaddrs = my_ip_interfaces(true);
1247
1248        // Create a socket for every IP addr.
1249        // Note: it is possible that `my_ifaddrs` contains the same IP addr with different interface names,
1250        // or the same interface name with different IP addrs.
1251        let mut my_intfs = HashMap::new();
1252        let mut dns_registry_map = HashMap::new();
1253
1254        // Use the same socket for receiving and sending multicast packets.
1255        // Such socket has to bind to INADDR_ANY or IN6ADDR_ANY.
1256        let mut ipv4_sock = None;
1257        let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), port);
1258        match new_socket(addr.into(), true) {
1259            Ok(sock) => {
1260                // Per RFC 6762 section 11:
1261                // "All Multicast DNS responses (including responses sent via unicast) SHOULD
1262                // be sent with IP TTL set to 255."
1263                // Here we set the TTL to 255 for multicast as we don't support unicast yet.
1264                sock.set_multicast_ttl_v4(255)
1265                    .map_err(|e| e_fmt!("set set_multicast_ttl_v4 on addr: {}", e))
1266                    .ok();
1267
1268                // This clones a socket.
1269                ipv4_sock = match MyUdpSocket::new(sock) {
1270                    Ok(s) => Some(s),
1271                    Err(e) => {
1272                        debug!("failed to create IPv4 MyUdpSocket: {e}");
1273                        None
1274                    }
1275                };
1276            }
1277            // Per RFC 6762 section 11:}
1278            Err(e) => debug!("failed to create IPv4 socket: {e}"),
1279        }
1280
1281        let mut ipv6_sock = None;
1282        let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), port, 0, 0);
1283        match new_socket(addr.into(), true) {
1284            Ok(sock) => {
1285                // Per RFC 6762 section 11:
1286                // "All Multicast DNS responses (including responses sent via unicast) SHOULD
1287                // be sent with IP TTL set to 255."
1288                sock.set_multicast_hops_v6(255)
1289                    .map_err(|e| e_fmt!("set set_multicast_hops_v6: {}", e))
1290                    .ok();
1291
1292                // This clones the ipv6 socket.
1293                ipv6_sock = match MyUdpSocket::new(sock) {
1294                    Ok(s) => Some(s),
1295                    Err(e) => {
1296                        debug!("failed to create IPv6 MyUdpSocket: {e}");
1297                        None
1298                    }
1299                };
1300            }
1301            Err(e) => debug!("failed to create IPv6 socket: {e}"),
1302        }
1303
1304        // Configure sockets to join multicast groups.
1305        for intf in my_ifaddrs {
1306            let sock_opt = if intf.ip().is_ipv4() {
1307                &ipv4_sock
1308            } else {
1309                &ipv6_sock
1310            };
1311            let Some(sock) = sock_opt else {
1312                debug!(
1313                    "no socket available for interface {} with addr {}. Skipped.",
1314                    intf.name,
1315                    intf.ip()
1316                );
1317                continue;
1318            };
1319
1320            if let Err(e) = join_multicast_group(&sock.pktinfo, &intf) {
1321                debug!("failed to join multicast: {}: {e}. Skipped.", &intf.ip());
1322            }
1323
1324            let if_index = intf.index.unwrap_or(0);
1325
1326            // Add this interface address if not already present.
1327            dns_registry_map
1328                .entry(if_index)
1329                .or_insert_with(DnsRegistry::new);
1330
1331            my_intfs
1332                .entry(if_index)
1333                .and_modify(|v: &mut MyIntf| {
1334                    v.addrs.insert(intf.addr.clone());
1335                })
1336                .or_insert(MyIntf {
1337                    name: intf.name.clone(),
1338                    index: if_index,
1339                    addrs: HashSet::from([intf.addr]),
1340                    max_packet_size_v4: MAX_PKT_DEFAULT,
1341                    max_packet_size_v6: MAX_PKT_DEFAULT,
1342                });
1343        }
1344
1345        let monitors = Vec::new();
1346        let service_name_len_max = SERVICE_NAME_LEN_MAX_DEFAULT;
1347        let ip_check_interval = IP_CHECK_INTERVAL_IN_SECS_DEFAULT as u64 * 1000;
1348
1349        let timers = BinaryHeap::new();
1350
1351        // Enable everything, including loopback interfaces.
1352        let if_selections = vec![];
1353
1354        let status = DaemonStatus::Running;
1355
1356        Self {
1357            port,
1358            my_intfs,
1359            ipv4_sock,
1360            ipv6_sock,
1361            my_services: HashMap::new(),
1362            cache: DnsCache::new(),
1363            dns_registry_map,
1364            hostname_resolvers: HashMap::new(),
1365            service_queriers: HashMap::new(),
1366            retransmissions: Vec::new(),
1367            delayed_responses: Vec::new(),
1368            counters: HashMap::new(),
1369            poller,
1370            monitors,
1371            service_name_len_max,
1372            ip_check_interval,
1373            max_packet_sizes: Vec::new(),
1374            if_selections,
1375            signal_sock,
1376            timers,
1377            status,
1378            pending_resolves: HashSet::new(),
1379            resolved: HashSet::new(),
1380            multicast_loop_v4: true,
1381            multicast_loop_v6: true,
1382            accept_unsolicited: false,
1383            include_apple_p2p: false,
1384            cmd_sender,
1385            signal_addr,
1386
1387            #[cfg(test)]
1388            test_down_interfaces: HashSet::new(),
1389        }
1390    }
1391
1392    /// Send a Command into the daemon channel and poke the signal socket to wake the poll loop.
1393    fn send_cmd_to_self(&self, cmd: Command) -> Result<()> {
1394        let cmd_name = cmd.to_string();
1395
1396        self.cmd_sender.try_send(cmd).map_err(|e| match e {
1397            TrySendError::Full(_) => Error::Again,
1398            TrySendError::Disconnected(_) => Error::DaemonShutdown,
1399        })?;
1400
1401        let addr = SocketAddrV4::new(LOOPBACK_V4, 0);
1402        let socket = UdpSocket::bind(addr)
1403            .map_err(|e| e_fmt!("Failed to create socket to send signal: {}", e))?;
1404        socket
1405            .send_to(cmd_name.as_bytes(), self.signal_addr)
1406            .map_err(|e| {
1407                e_fmt!(
1408                    "signal socket send_to {} ({}) failed: {}",
1409                    self.signal_addr,
1410                    cmd_name,
1411                    e
1412                )
1413            })?;
1414
1415        Ok(())
1416    }
1417
1418    /// Clean up all resources before shutdown.
1419    ///
1420    /// This method:
1421    /// 1. Unregisters all registered services (sends goodbye packets)
1422    /// 2. Stops all active browse operations
1423    /// 3. Stops all active hostname resolution operations
1424    /// 4. Clears all retransmissions
1425    /// 5. Drops all pending delayed responses
1426    fn cleanup(&mut self) {
1427        debug!("Starting cleanup for shutdown");
1428
1429        // 1. Unregister all services - send goodbye packets
1430        let service_names: Vec<String> = self.my_services.keys().cloned().collect();
1431        for fullname in service_names {
1432            if let Some(info) = self.my_services.get(&fullname) {
1433                debug!("Unregistering service during shutdown: {}", &fullname);
1434
1435                for intf in self.my_intfs.values() {
1436                    if let Some(sock) = self.ipv4_sock.as_ref() {
1437                        self.unregister_service(info, intf, &sock.pktinfo);
1438                    }
1439
1440                    if let Some(sock) = self.ipv6_sock.as_ref() {
1441                        self.unregister_service(info, intf, &sock.pktinfo);
1442                    }
1443                }
1444            }
1445        }
1446        self.my_services.clear();
1447
1448        // 2. Stop all browse operations
1449        let browse_types: Vec<String> = self.service_queriers.keys().cloned().collect();
1450        for ty_domain in browse_types {
1451            debug!("Stopping browse during shutdown: {}", &ty_domain);
1452            if let Some(sender) = self.service_queriers.remove(&ty_domain) {
1453                // Notify the client
1454                if let Err(e) = sender.send(ServiceEvent::SearchStopped(ty_domain.clone())) {
1455                    debug!("Failed to send SearchStopped during shutdown: {}", e);
1456                }
1457            }
1458        }
1459
1460        // 3. Stop all hostname resolution operations
1461        let hostnames: Vec<String> = self.hostname_resolvers.keys().cloned().collect();
1462        for hostname in hostnames {
1463            debug!(
1464                "Stopping hostname resolution during shutdown: {}",
1465                &hostname
1466            );
1467            if let Some((sender, _timeout)) = self.hostname_resolvers.remove(&hostname) {
1468                // Notify the client
1469                if let Err(e) =
1470                    sender.send(HostnameResolutionEvent::SearchStopped(hostname.clone()))
1471                {
1472                    debug!(
1473                        "Failed to send HostnameResolutionEvent::SearchStopped during shutdown: {}",
1474                        e
1475                    );
1476                }
1477            }
1478        }
1479
1480        // 4. Clear all retransmissions
1481        self.retransmissions.clear();
1482
1483        // 5. Drop any pending delayed responses
1484        self.delayed_responses.clear();
1485
1486        debug!("Cleanup completed");
1487    }
1488
1489    /// The main event loop of the daemon thread
1490    ///
1491    /// In each round, it will:
1492    /// 1. select the listening sockets with a timeout.
1493    /// 2. process the incoming packets if any.
1494    /// 3. try_recv on its channel and execute commands.
1495    /// 4. announce its registered services.
1496    /// 5. process retransmissions if any.
1497    fn run(&mut self, receiver: Receiver<Command>) -> Option<Command> {
1498        // Add the daemon's signal socket to the poller.
1499        if let Err(e) = self.poller.registry().register(
1500            &mut self.signal_sock,
1501            mio::Token(SIGNAL_SOCK_EVENT_KEY),
1502            mio::Interest::READABLE,
1503        ) {
1504            debug!("failed to add signal socket to the poller: {}", e);
1505            return None;
1506        }
1507
1508        if let Some(sock) = self.ipv4_sock.as_mut() {
1509            if let Err(e) = self.poller.registry().register(
1510                sock,
1511                mio::Token(IPV4_SOCK_EVENT_KEY),
1512                mio::Interest::READABLE,
1513            ) {
1514                debug!("failed to register ipv4 socket: {}", e);
1515                return None;
1516            }
1517        }
1518
1519        if let Some(sock) = self.ipv6_sock.as_mut() {
1520            if let Err(e) = self.poller.registry().register(
1521                sock,
1522                mio::Token(IPV6_SOCK_EVENT_KEY),
1523                mio::Interest::READABLE,
1524            ) {
1525                debug!("failed to register ipv6 socket: {}", e);
1526                return None;
1527            }
1528        }
1529
1530        // Setup timer for IP checks.
1531        let mut next_ip_check = if self.ip_check_interval > 0 {
1532            current_time_millis() + self.ip_check_interval
1533        } else {
1534            0
1535        };
1536
1537        if next_ip_check > 0 {
1538            self.add_timer(next_ip_check);
1539        }
1540
1541        // Start the run loop.
1542
1543        let mut events = mio::Events::with_capacity(1024);
1544        loop {
1545            let now = current_time_millis();
1546
1547            let earliest_timer = self.peek_earliest_timer();
1548            let timeout = earliest_timer.map(|timer| {
1549                // If `timer` already passed, set `timeout` to be 1ms.
1550                let millis = if timer > now { timer - now } else { 1 };
1551                Duration::from_millis(millis)
1552            });
1553
1554            // Process incoming packets, command events and optional timeout.
1555            events.clear();
1556            match self.poller.poll(&mut events, timeout) {
1557                Ok(_) => self.handle_poller_events(&events),
1558                Err(e) => debug!("failed to select from sockets: {}", e),
1559            }
1560
1561            let now = current_time_millis();
1562
1563            // Remove the timers if already passed.
1564            self.pop_timers_till(now);
1565
1566            // Remove hostname resolvers with expired timeouts.
1567            for hostname in self
1568                .hostname_resolvers
1569                .clone()
1570                .into_iter()
1571                .filter(|(_, (_, timeout))| timeout.map(|t| now >= t).unwrap_or(false))
1572                .map(|(hostname, _)| hostname)
1573            {
1574                trace!("hostname resolver timeout for {}", &hostname);
1575                call_hostname_resolution_listener(
1576                    &self.hostname_resolvers,
1577                    &hostname,
1578                    HostnameResolutionEvent::SearchTimeout(hostname.to_owned()),
1579                );
1580                call_hostname_resolution_listener(
1581                    &self.hostname_resolvers,
1582                    &hostname,
1583                    HostnameResolutionEvent::SearchStopped(hostname.to_owned()),
1584                );
1585                self.hostname_resolvers.remove(&hostname);
1586            }
1587
1588            // process commands from the command channel
1589            while let Ok(command) = receiver.try_recv() {
1590                if matches!(command, Command::Exit(_)) {
1591                    debug!("Exit command received, performing cleanup");
1592                    self.cleanup();
1593                    self.status = DaemonStatus::Shutdown;
1594                    return Some(command);
1595                }
1596                self.exec_command(command, false);
1597            }
1598
1599            // check for repeated commands and run them if their time is up.
1600            let mut i = 0;
1601            while i < self.retransmissions.len() {
1602                if now >= self.retransmissions[i].next_time {
1603                    let rerun = self.retransmissions.remove(i);
1604                    self.exec_command(rerun.command, true);
1605                } else {
1606                    i += 1;
1607                }
1608            }
1609
1610            // Send delayed responses whose time is up (RFC 6762 §6).
1611            let mut i = 0;
1612            while i < self.delayed_responses.len() {
1613                if now >= self.delayed_responses[i].next_time {
1614                    let resp = self.delayed_responses.remove(i);
1615                    self.send_delayed_response(resp);
1616                } else {
1617                    i += 1;
1618                }
1619            }
1620
1621            // Refresh cached service records with active queriers
1622            self.refresh_active_services();
1623
1624            // Refresh cached A/AAAA records with active queriers
1625            let mut query_count = 0;
1626            for (hostname, _sender) in self.hostname_resolvers.iter() {
1627                for (hostname, ip_addr) in
1628                    self.cache.refresh_due_hostname_resolutions(hostname).iter()
1629                {
1630                    self.send_query(hostname, ip_address_rr_type(&ip_addr.to_ip_addr()));
1631                    query_count += 1;
1632                }
1633            }
1634
1635            self.increase_counter(Counter::CacheRefreshAddr, query_count);
1636
1637            // check and evict expired records in our cache
1638            let now = current_time_millis();
1639
1640            // Notify service listeners about the expired records.
1641            let expired_services = self.cache.evict_expired_services(now);
1642            if !expired_services.is_empty() {
1643                debug!(
1644                    "run: send {} service removal to listeners",
1645                    expired_services.len()
1646                );
1647                self.notify_service_removal(expired_services);
1648            }
1649
1650            // Notify hostname listeners about the expired records.
1651            let expired_addrs = self.cache.evict_expired_addr(now);
1652            for (hostname, addrs) in expired_addrs {
1653                call_hostname_resolution_listener(
1654                    &self.hostname_resolvers,
1655                    &hostname,
1656                    HostnameResolutionEvent::AddressesRemoved(hostname.clone(), addrs),
1657                );
1658                let instances = self.cache.get_instances_on_host(&hostname);
1659                let instance_set: HashSet<String> = instances.into_iter().collect();
1660                self.resolve_updated_instances(&instance_set);
1661            }
1662
1663            // Send out probing queries.
1664            self.probing_handler();
1665
1666            // check IP changes if next_ip_check is reached.
1667            if now >= next_ip_check && next_ip_check > 0 {
1668                next_ip_check = now + self.ip_check_interval;
1669                self.add_timer(next_ip_check);
1670
1671                self.check_ip_changes();
1672            }
1673        }
1674    }
1675
1676    fn process_set_option(&mut self, daemon_opt: DaemonOption) {
1677        match daemon_opt {
1678            DaemonOption::ServiceNameLenMax(length) => self.service_name_len_max = length,
1679            DaemonOption::IpCheckInterval(interval) => self.ip_check_interval = interval,
1680            DaemonOption::MaxPacketSize(if_kind, size) => self.set_max_packet_size(if_kind, size),
1681            DaemonOption::EnableInterface(if_kind) => self.enable_interface(if_kind),
1682            DaemonOption::DisableInterface(if_kind) => self.disable_interface(if_kind),
1683            DaemonOption::MulticastLoopV4(on) => self.set_multicast_loop_v4(on),
1684            DaemonOption::MulticastLoopV6(on) => self.set_multicast_loop_v6(on),
1685            DaemonOption::AcceptUnsolicited(accept) => self.set_accept_unsolicited(accept),
1686            DaemonOption::IncludeAppleP2P(enable) => self.set_apple_p2p(enable),
1687            #[cfg(test)]
1688            DaemonOption::TestDownInterface(ifname) => {
1689                self.test_down_interfaces.insert(ifname);
1690            }
1691            #[cfg(test)]
1692            DaemonOption::TestUpInterface(ifname) => {
1693                self.test_down_interfaces.remove(&ifname);
1694            }
1695        }
1696    }
1697
1698    fn enable_interface(&mut self, kinds: Vec<IfKind>) {
1699        debug!("enable_interface: {:?}", kinds);
1700        let interfaces = my_ip_interfaces_inner(true, self.include_apple_p2p);
1701
1702        for if_kind in kinds {
1703            self.if_selections.push(IfSelection {
1704                if_kind: resolve_addr_to_index(if_kind, &interfaces),
1705                selected: true,
1706            });
1707        }
1708
1709        self.apply_intf_selections(interfaces);
1710    }
1711
1712    fn disable_interface(&mut self, kinds: Vec<IfKind>) {
1713        debug!("disable_interface: {:?}", kinds);
1714        let interfaces = my_ip_interfaces_inner(true, self.include_apple_p2p);
1715
1716        for if_kind in kinds {
1717            self.if_selections.push(IfSelection {
1718                if_kind: resolve_addr_to_index(if_kind, &interfaces),
1719                selected: false,
1720            });
1721        }
1722
1723        self.apply_intf_selections(interfaces);
1724    }
1725
1726    fn set_max_packet_size(&mut self, kinds: Vec<IfKind>, size: usize) {
1727        debug!("set_max_packet_size: {:?} {}", kinds, size);
1728        let interfaces = my_ip_interfaces_inner(true, self.include_apple_p2p);
1729
1730        for if_kind in kinds {
1731            self.max_packet_sizes.push(MaxPacketSizeSelection {
1732                if_kind: resolve_addr_to_index(if_kind, &interfaces),
1733                max_packet_size: size,
1734            });
1735        }
1736
1737        self.apply_max_packet_sizes(&interfaces);
1738    }
1739
1740    /// Resolve all max packet size selections against `interfaces` and store the
1741    /// outcome in every interface in `my_intfs`.
1742    fn apply_max_packet_sizes(&mut self, interfaces: &[Interface]) {
1743        for (if_index, my_intf) in self.my_intfs.iter_mut() {
1744            let v4 = resolve_max_packet_size(&self.max_packet_sizes, interfaces, *if_index, true);
1745            let v6 = resolve_max_packet_size(&self.max_packet_sizes, interfaces, *if_index, false);
1746
1747            if my_intf.max_packet_size_v4 != v4 || my_intf.max_packet_size_v6 != v6 {
1748                debug!(
1749                    "interface {}: max packet size v4 {} -> {v4}, v6 {} -> {v6}",
1750                    my_intf.name, my_intf.max_packet_size_v4, my_intf.max_packet_size_v6
1751                );
1752                my_intf.max_packet_size_v4 = v4;
1753                my_intf.max_packet_size_v6 = v6;
1754            }
1755        }
1756    }
1757
1758    fn set_multicast_loop_v4(&mut self, on: bool) {
1759        let Some(sock) = self.ipv4_sock.as_mut() else {
1760            return;
1761        };
1762        self.multicast_loop_v4 = on;
1763        sock.pktinfo
1764            .set_multicast_loop_v4(on)
1765            .map_err(|e| e_fmt!("failed to set multicast loop v4: {}", e))
1766            .unwrap();
1767    }
1768
1769    fn set_multicast_loop_v6(&mut self, on: bool) {
1770        let Some(sock) = self.ipv6_sock.as_mut() else {
1771            return;
1772        };
1773        self.multicast_loop_v6 = on;
1774        sock.pktinfo
1775            .set_multicast_loop_v6(on)
1776            .map_err(|e| e_fmt!("failed to set multicast loop v6: {}", e))
1777            .unwrap();
1778    }
1779
1780    fn set_accept_unsolicited(&mut self, accept: bool) {
1781        self.accept_unsolicited = accept;
1782    }
1783
1784    fn set_apple_p2p(&mut self, include: bool) {
1785        if self.include_apple_p2p != include {
1786            self.include_apple_p2p = include;
1787            self.apply_intf_selections(my_ip_interfaces_inner(true, self.include_apple_p2p));
1788        }
1789    }
1790
1791    fn notify_monitors(&mut self, event: DaemonEvent) {
1792        // Only retain the monitors that are still connected.
1793        self.monitors.retain(|sender| {
1794            if let Err(e) = sender.try_send(event.clone()) {
1795                debug!("notify_monitors: try_send: {}", &e);
1796                if matches!(e, TrySendError::Disconnected(_)) {
1797                    return false; // This monitor is dropped.
1798                }
1799            }
1800            true
1801        });
1802    }
1803
1804    /// Remove `addr` in my services that enabled `addr_auto`.
1805    fn del_addr_in_my_services(&mut self, addr: &IpAddr) {
1806        for (_, service_info) in self.my_services.iter_mut() {
1807            if service_info.is_addr_auto() {
1808                service_info.remove_ipaddr(addr);
1809            }
1810        }
1811    }
1812
1813    fn add_timer(&mut self, next_time: u64) {
1814        self.timers.push(Reverse(next_time));
1815    }
1816
1817    fn peek_earliest_timer(&self) -> Option<u64> {
1818        self.timers.peek().map(|Reverse(v)| *v)
1819    }
1820
1821    fn _pop_earliest_timer(&mut self) -> Option<u64> {
1822        self.timers.pop().map(|Reverse(v)| v)
1823    }
1824
1825    /// Pop all timers that are already passed till `now`.
1826    fn pop_timers_till(&mut self, now: u64) {
1827        while let Some(Reverse(v)) = self.timers.peek() {
1828            if *v > now {
1829                break;
1830            }
1831            self.timers.pop();
1832        }
1833    }
1834
1835    /// Apply all selections to `interfaces` and return the selected addresses.
1836    fn selected_intfs(&self, interfaces: Vec<Interface>) -> HashSet<Interface> {
1837        let intf_count = interfaces.len();
1838        let mut intf_selections = vec![true; intf_count];
1839
1840        // apply if_selections
1841        for selection in self.if_selections.iter() {
1842            // Mark the interfaces for this selection.
1843            for i in 0..intf_count {
1844                if selection.if_kind.matches(&interfaces[i]) {
1845                    intf_selections[i] = selection.selected;
1846                }
1847            }
1848        }
1849
1850        let mut selected_addrs = HashSet::new();
1851        for i in 0..intf_count {
1852            if intf_selections[i] {
1853                selected_addrs.insert(interfaces[i].clone());
1854            }
1855        }
1856
1857        selected_addrs
1858    }
1859
1860    /// Apply all selections to `interfaces`.
1861    ///
1862    /// For any interface, add it if selected but not bound yet,
1863    /// delete it if not selected but still bound.
1864    fn apply_intf_selections(&mut self, interfaces: Vec<Interface>) {
1865        // By default, we enable all interfaces.
1866        let intf_count = interfaces.len();
1867        let mut intf_selections = vec![true; intf_count];
1868
1869        // apply if_selections
1870        for selection in self.if_selections.iter() {
1871            // Mark the interfaces for this selection.
1872            for i in 0..intf_count {
1873                if selection.if_kind.matches(&interfaces[i]) {
1874                    intf_selections[i] = selection.selected;
1875                }
1876            }
1877        }
1878
1879        // Update `my_intfs` based on the selections.
1880        for (idx, intf) in interfaces.iter().enumerate() {
1881            if intf_selections[idx] {
1882                // Add the interface
1883                self.add_interface(intf, &interfaces);
1884            } else {
1885                // Remove the interface
1886                self.del_interface_addr(intf);
1887            }
1888        }
1889
1890        // An interface that lost an address may now match a different selection.
1891        // (`add_interface` already resolved the ones that gained one.)
1892        self.apply_max_packet_sizes(&interfaces);
1893    }
1894
1895    fn del_ip(&mut self, ip: IpAddr) {
1896        self.del_addr_in_my_services(&ip);
1897        self.notify_monitors(DaemonEvent::IpDel(ip));
1898    }
1899
1900    /// Check for IP changes and update [my_intfs] as needed.
1901    fn check_ip_changes(&mut self) {
1902        // Get the current interfaces.
1903        let my_ifaddrs = my_ip_interfaces_inner(true, self.include_apple_p2p);
1904
1905        #[cfg(test)]
1906        let my_ifaddrs: Vec<_> = my_ifaddrs
1907            .into_iter()
1908            .filter(|intf| !self.test_down_interfaces.contains(&intf.name))
1909            .collect();
1910
1911        let ifaddrs_map: HashMap<u32, Vec<&IfAddr>> =
1912            my_ifaddrs.iter().fold(HashMap::new(), |mut acc, intf| {
1913                let if_index = intf.index.unwrap_or(0);
1914                acc.entry(if_index).or_default().push(&intf.addr);
1915                acc
1916            });
1917
1918        let mut deleted_intfs = Vec::new();
1919        let mut deleted_ips = Vec::new();
1920
1921        for (if_index, my_intf) in self.my_intfs.iter_mut() {
1922            let mut last_ipv4 = None;
1923            let mut last_ipv6 = None;
1924
1925            if let Some(current_addrs) = ifaddrs_map.get(if_index) {
1926                my_intf.addrs.retain(|addr| {
1927                    if current_addrs.contains(&addr) {
1928                        true
1929                    } else {
1930                        match addr.ip() {
1931                            IpAddr::V4(ipv4) => last_ipv4 = Some(ipv4),
1932                            IpAddr::V6(ipv6) => last_ipv6 = Some(ipv6),
1933                        }
1934                        deleted_ips.push(addr.ip());
1935                        false
1936                    }
1937                });
1938                if my_intf.addrs.is_empty() {
1939                    deleted_intfs.push((*if_index, last_ipv4, last_ipv6))
1940                }
1941            } else {
1942                // If it does not exist, remove the interface.
1943                debug!(
1944                    "check_ip_changes: interface {} ({}) no longer exists, removing",
1945                    my_intf.name, if_index
1946                );
1947                for addr in my_intf.addrs.iter() {
1948                    match addr.ip() {
1949                        IpAddr::V4(ipv4) => last_ipv4 = Some(ipv4),
1950                        IpAddr::V6(ipv6) => last_ipv6 = Some(ipv6),
1951                    }
1952                    deleted_ips.push(addr.ip())
1953                }
1954                deleted_intfs.push((*if_index, last_ipv4, last_ipv6));
1955            }
1956        }
1957
1958        if !deleted_ips.is_empty() || !deleted_intfs.is_empty() {
1959            debug!(
1960                "check_ip_changes: {} deleted ips {} deleted intfs",
1961                deleted_ips.len(),
1962                deleted_intfs.len()
1963            );
1964        }
1965
1966        for ip in deleted_ips {
1967            self.del_ip(ip);
1968        }
1969
1970        for (if_index, last_ipv4, last_ipv6) in deleted_intfs {
1971            let Some(my_intf) = self.my_intfs.remove(&if_index) else {
1972                continue;
1973            };
1974
1975            if let Some(ipv4) = last_ipv4 {
1976                debug!("leave multicast for {ipv4}");
1977                if let Some(sock) = self.ipv4_sock.as_mut() {
1978                    if let Err(e) = sock.pktinfo.leave_multicast_v4(&GROUP_ADDR_V4, &ipv4) {
1979                        debug!("leave multicast group for addr {ipv4}: {e}");
1980                    }
1981                }
1982            }
1983
1984            if let Some(ipv6) = last_ipv6 {
1985                debug!("leave multicast for {ipv6}");
1986                if let Some(sock) = self.ipv6_sock.as_mut() {
1987                    if let Err(e) = sock
1988                        .pktinfo
1989                        .leave_multicast_v6(&GROUP_ADDR_V6, my_intf.index)
1990                    {
1991                        debug!("leave multicast group for IPv6: {ipv6}: {e}");
1992                    }
1993                }
1994            }
1995
1996            // Remove cache records for this interface.
1997            let intf_id = InterfaceId {
1998                name: my_intf.name.to_string(),
1999                index: my_intf.index,
2000            };
2001            let result = self.cache.remove_records_on_intf(intf_id);
2002            self.notify_service_removal(result.removed_instances);
2003            self.resolve_updated_instances(&result.modified_instances);
2004        }
2005
2006        // Add newly found interfaces only if in our selections.
2007        self.apply_intf_selections(my_ifaddrs);
2008    }
2009
2010    /// Remove an interface address when it was down, disabled or removed from the system.
2011    /// If no more addresses on the interface, remove the interface as well.
2012    fn del_interface_addr(&mut self, intf: &Interface) {
2013        let if_index = intf.index.unwrap_or(0);
2014        debug!(
2015            "del_interface_addr: {} ({if_index}) addr {}",
2016            intf.name,
2017            intf.ip()
2018        );
2019
2020        let Some(my_intf) = self.my_intfs.get_mut(&if_index) else {
2021            debug!("del_interface_addr: interface {} not found", intf.name);
2022            return;
2023        };
2024
2025        let mut ip_removed = false;
2026
2027        if my_intf.addrs.remove(&intf.addr) {
2028            ip_removed = true;
2029
2030            match intf.addr.ip() {
2031                IpAddr::V4(ipv4) => {
2032                    if my_intf.next_ifaddr_v4().is_none() {
2033                        if let Some(sock) = self.ipv4_sock.as_mut() {
2034                            if let Err(e) = sock.pktinfo.leave_multicast_v4(&GROUP_ADDR_V4, &ipv4) {
2035                                debug!("leave multicast group for addr {ipv4}: {e}");
2036                            } else {
2037                                debug!("leave multicast for {ipv4}");
2038                            }
2039                        }
2040                    }
2041                }
2042
2043                IpAddr::V6(ipv6) => {
2044                    if my_intf.next_ifaddr_v6().is_none() {
2045                        if let Some(sock) = self.ipv6_sock.as_mut() {
2046                            if let Err(e) =
2047                                sock.pktinfo.leave_multicast_v6(&GROUP_ADDR_V6, if_index)
2048                            {
2049                                debug!("leave multicast group for addr {ipv6}: {e}");
2050                            }
2051                        }
2052                    }
2053                }
2054            }
2055
2056            if my_intf.addrs.is_empty() {
2057                // If no more addresses, remove the interface.
2058                debug!("del_interface_addr: removing interface {}", intf.name);
2059                self.my_intfs.remove(&if_index);
2060                self.dns_registry_map.remove(&if_index);
2061                self.cache
2062                    .remove_addrs_on_disabled_intf(if_index, IpType::BOTH);
2063            } else {
2064                // Interface still has addresses of the other IP version.
2065                // Remove cached address records for the disabled IP version
2066                // only if no more addresses of that version remain.
2067                let is_v4 = intf.addr.ip().is_ipv4();
2068                let version_gone = if is_v4 {
2069                    my_intf.next_ifaddr_v4().is_none()
2070                } else {
2071                    my_intf.next_ifaddr_v6().is_none()
2072                };
2073                if version_gone {
2074                    let ip_type = if is_v4 { IpType::V4 } else { IpType::V6 };
2075                    self.cache.remove_addrs_on_disabled_intf(if_index, ip_type);
2076                }
2077            }
2078        }
2079
2080        if ip_removed {
2081            // Notify the monitors.
2082            self.notify_monitors(DaemonEvent::IpDel(intf.ip()));
2083            // Remove the interface from my services that enabled `addr_auto`.
2084            self.del_addr_in_my_services(&intf.ip());
2085        }
2086    }
2087
2088    /// Add the address of `intf` to `my_intfs`, and announce our services on it.
2089    ///
2090    /// `interfaces` is the full list the caller is applying, needed to resolve the
2091    /// max packet size of the interface before we send anything on it.
2092    fn add_interface(&mut self, intf: &Interface, interfaces: &[Interface]) {
2093        let sock_opt = if intf.ip().is_ipv4() {
2094            &self.ipv4_sock
2095        } else {
2096            &self.ipv6_sock
2097        };
2098
2099        let Some(sock) = sock_opt else {
2100            debug!(
2101                "add_interface: no socket available for interface {} with addr {}. Skipped.",
2102                intf.name,
2103                intf.ip()
2104            );
2105            return;
2106        };
2107
2108        let if_index = intf.index.unwrap_or(0);
2109        let mut new_addr = false;
2110
2111        match self.my_intfs.entry(if_index) {
2112            Entry::Occupied(mut entry) => {
2113                // If intf has a new address, add it to the existing interface.
2114                let my_intf = entry.get_mut();
2115                if !my_intf.addrs.contains(&intf.addr) {
2116                    if let Err(e) = join_multicast_group(&sock.pktinfo, intf) {
2117                        debug!("add_interface: socket_config {}: {e}", &intf.name);
2118                    }
2119                    my_intf.addrs.insert(intf.addr.clone());
2120                    new_addr = true;
2121                }
2122            }
2123            Entry::Vacant(entry) => {
2124                if let Err(e) = join_multicast_group(&sock.pktinfo, intf) {
2125                    debug!("add_interface: socket_config {}: {e}. Skipped.", &intf.name);
2126                    return;
2127                }
2128
2129                new_addr = true;
2130                let new_intf = MyIntf {
2131                    name: intf.name.clone(),
2132                    index: if_index,
2133                    addrs: HashSet::from([intf.addr.clone()]),
2134                    max_packet_size_v4: MAX_PKT_DEFAULT,
2135                    max_packet_size_v6: MAX_PKT_DEFAULT,
2136                };
2137                entry.insert(new_intf);
2138            }
2139        }
2140
2141        if !new_addr {
2142            trace!("add_interface: interface {} already exists", &intf.name);
2143            return;
2144        }
2145
2146        debug!("add new interface {}: {}", intf.name, intf.ip());
2147
2148        // Resolve before announcing, so the first packet out already honors it.
2149        let v4 = resolve_max_packet_size(&self.max_packet_sizes, interfaces, if_index, true);
2150        let v6 = resolve_max_packet_size(&self.max_packet_sizes, interfaces, if_index, false);
2151        if let Some(my_intf) = self.my_intfs.get_mut(&if_index) {
2152            my_intf.max_packet_size_v4 = v4;
2153            my_intf.max_packet_size_v6 = v6;
2154        }
2155
2156        let Some(my_intf) = self.my_intfs.get(&if_index) else {
2157            debug!("add_interface: cannot find if_index {if_index}");
2158            return;
2159        };
2160
2161        let dns_registry = match self.dns_registry_map.get_mut(&if_index) {
2162            Some(registry) => registry,
2163            None => self
2164                .dns_registry_map
2165                .entry(if_index)
2166                .or_insert_with(DnsRegistry::new),
2167        };
2168
2169        for (_, service_info) in self.my_services.iter_mut() {
2170            if service_info.is_addr_auto() {
2171                service_info.insert_ipaddr(intf);
2172
2173                if let Ok(true) = announce_service_on_intf(
2174                    dns_registry,
2175                    service_info,
2176                    my_intf,
2177                    &sock.pktinfo,
2178                    self.port,
2179                ) {
2180                    debug!(
2181                        "Announce service {} on {}",
2182                        service_info.get_fullname(),
2183                        intf.ip()
2184                    );
2185                    service_info.set_status(if_index, ServiceStatus::Announced);
2186                } else {
2187                    for timer in dns_registry.new_timers.drain(..) {
2188                        self.timers.push(Reverse(timer));
2189                    }
2190                    service_info.set_status(if_index, ServiceStatus::Probing);
2191                }
2192            }
2193        }
2194
2195        // Send browse queries on the new interface without known answers.
2196        // This avoids known-answer suppression (RFC 6762 Section 7.1) that
2197        // would cause the responder to suppress its response, preventing
2198        // address records from being attributed to the new interface.
2199        if let Some(my_intf) = self.my_intfs.get(&if_index) {
2200            for ty in self.service_queriers.keys() {
2201                self.send_query_on_intf(ty, RRType::PTR, my_intf);
2202            }
2203        }
2204
2205        // Notify the monitors.
2206        self.notify_monitors(DaemonEvent::IpAdd(intf.ip()));
2207    }
2208
2209    /// Registers a service.
2210    ///
2211    /// RFC 6762 section 8.3.
2212    /// ...the Multicast DNS responder MUST send
2213    ///    an unsolicited Multicast DNS response containing, in the Answer
2214    ///    Section, all of its newly registered resource records
2215    ///
2216    /// Zeroconf will then respond to requests for information about this service.
2217    fn register_service(&mut self, mut info: ServiceInfo) {
2218        // Check the service name length.
2219        if let Err(e) = check_service_name_length(info.get_type(), self.service_name_len_max) {
2220            error!("check_service_name_length: {}", &e);
2221            self.notify_monitors(DaemonEvent::Error(e));
2222            return;
2223        }
2224
2225        if info.is_addr_auto() {
2226            let selected_intfs =
2227                self.selected_intfs(my_ip_interfaces_inner(true, self.include_apple_p2p));
2228            for intf in selected_intfs {
2229                info.insert_ipaddr(&intf);
2230            }
2231        }
2232
2233        debug!("register service {:?}", &info);
2234
2235        let outgoing_addrs = self.send_unsolicited_response(&mut info);
2236        if !outgoing_addrs.is_empty() {
2237            self.notify_monitors(DaemonEvent::Announce(
2238                info.get_fullname().to_string(),
2239                format!("{:?}", &outgoing_addrs),
2240            ));
2241        }
2242
2243        // The key has to be lower case letter as DNS record name is case insensitive.
2244        // The info will have the original name.
2245        let service_fullname = info.get_fullname().to_lowercase();
2246        self.my_services.insert(service_fullname, info);
2247    }
2248
2249    /// Sends out announcement of `info` on every valid interface.
2250    /// Returns the list of interface IPs that sent out the announcement.
2251    fn send_unsolicited_response(&mut self, info: &mut ServiceInfo) -> Vec<IpAddr> {
2252        let mut outgoing_addrs = Vec::new();
2253        let mut outgoing_intfs = HashSet::new();
2254
2255        let mut invalid_intf_addrs = HashSet::new();
2256
2257        for (if_index, intf) in self.my_intfs.iter() {
2258            let dns_registry = match self.dns_registry_map.get_mut(if_index) {
2259                Some(registry) => registry,
2260                None => self
2261                    .dns_registry_map
2262                    .entry(*if_index)
2263                    .or_insert_with(DnsRegistry::new),
2264            };
2265
2266            let mut announced = false;
2267
2268            // IPv4
2269            if let Some(sock) = self.ipv4_sock.as_mut() {
2270                match announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port) {
2271                    Ok(true) => {
2272                        for addr in intf.addrs.iter().filter(|a| a.ip().is_ipv4()) {
2273                            outgoing_addrs.push(addr.ip());
2274                        }
2275                        outgoing_intfs.insert(intf.index);
2276
2277                        debug!(
2278                            "Announce service IPv4 {} on {}",
2279                            info.get_fullname(),
2280                            intf.name
2281                        );
2282                        announced = true;
2283                    }
2284                    Ok(false) => {}
2285                    Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2286                        invalid_intf_addrs.insert(intf_addr);
2287                    }
2288                }
2289            }
2290
2291            if let Some(sock) = self.ipv6_sock.as_mut() {
2292                match announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port) {
2293                    Ok(true) => {
2294                        for addr in intf.addrs.iter().filter(|a| a.ip().is_ipv6()) {
2295                            outgoing_addrs.push(addr.ip());
2296                        }
2297                        outgoing_intfs.insert(intf.index);
2298
2299                        debug!(
2300                            "Announce service IPv6 {} on {}",
2301                            info.get_fullname(),
2302                            intf.name
2303                        );
2304                        announced = true;
2305                    }
2306                    Ok(false) => {}
2307                    Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2308                        invalid_intf_addrs.insert(intf_addr);
2309                    }
2310                }
2311            }
2312
2313            if announced {
2314                info.set_status(intf.index, ServiceStatus::Announced);
2315            } else {
2316                for timer in dns_registry.new_timers.drain(..) {
2317                    self.timers.push(Reverse(timer));
2318                }
2319                info.set_status(*if_index, ServiceStatus::Probing);
2320            }
2321        }
2322
2323        if !invalid_intf_addrs.is_empty() {
2324            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2325        }
2326
2327        // RFC 6762 section 8.3.
2328        // ..The Multicast DNS responder MUST send at least two unsolicited
2329        //    responses, one second apart.
2330        let next_time = current_time_millis()
2331            + ANNOUNCE_SECOND_DELAY_MILLIS
2332            + fastrand::u64(0..ANNOUNCE_SECOND_JITTER_MILLIS);
2333        for if_index in outgoing_intfs {
2334            self.add_retransmission(
2335                next_time,
2336                Command::RegisterResend(info.get_fullname().to_string(), if_index),
2337            );
2338        }
2339
2340        outgoing_addrs
2341    }
2342
2343    /// Send probings or finish them if expired. Notify waiting services.
2344    fn probing_handler(&mut self) {
2345        let now = current_time_millis();
2346        let mut invalid_intf_addrs = HashSet::new();
2347
2348        for (if_index, intf) in self.my_intfs.iter() {
2349            let Some(dns_registry) = self.dns_registry_map.get_mut(if_index) else {
2350                continue;
2351            };
2352
2353            let (out, expired_probes) = check_probing(dns_registry, &mut self.timers, now);
2354
2355            // send probing.
2356            if !out.questions().is_empty() {
2357                trace!("sending out probing of questions: {:?}", out.questions());
2358                if let Some(sock) = self.ipv4_sock.as_mut() {
2359                    if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2360                        send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2361                    {
2362                        invalid_intf_addrs.insert(intf_addr);
2363                    }
2364                }
2365                if let Some(sock) = self.ipv6_sock.as_mut() {
2366                    if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2367                        send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2368                    {
2369                        invalid_intf_addrs.insert(intf_addr);
2370                    }
2371                }
2372            }
2373
2374            // For finished probes, wake up services that are waiting for the probes.
2375            let waiting_services =
2376                handle_expired_probes(expired_probes, &intf.name, dns_registry, &mut self.monitors);
2377
2378            for service_name in waiting_services {
2379                // service names are lowercase
2380                if let Some(info) = self.my_services.get_mut(&service_name.to_lowercase()) {
2381                    if info.get_status(*if_index) == ServiceStatus::Announced {
2382                        debug!("service {} already announced", info.get_fullname());
2383                        continue;
2384                    }
2385
2386                    let announced_v4 = if let Some(sock) = self.ipv4_sock.as_mut() {
2387                        match announce_service_on_intf(
2388                            dns_registry,
2389                            info,
2390                            intf,
2391                            &sock.pktinfo,
2392                            self.port,
2393                        ) {
2394                            Ok(announced) => announced,
2395                            Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2396                                invalid_intf_addrs.insert(intf_addr);
2397                                false
2398                            }
2399                        }
2400                    } else {
2401                        false
2402                    };
2403                    let announced_v6 = if let Some(sock) = self.ipv6_sock.as_mut() {
2404                        match announce_service_on_intf(
2405                            dns_registry,
2406                            info,
2407                            intf,
2408                            &sock.pktinfo,
2409                            self.port,
2410                        ) {
2411                            Ok(announced) => announced,
2412                            Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2413                                invalid_intf_addrs.insert(intf_addr);
2414                                false
2415                            }
2416                        }
2417                    } else {
2418                        false
2419                    };
2420
2421                    if announced_v4 || announced_v6 {
2422                        let next_time = now
2423                            + ANNOUNCE_SECOND_DELAY_MILLIS
2424                            + fastrand::u64(0..ANNOUNCE_SECOND_JITTER_MILLIS);
2425                        let command =
2426                            Command::RegisterResend(info.get_fullname().to_string(), *if_index);
2427                        self.retransmissions.push(ReRun { next_time, command });
2428                        self.timers.push(Reverse(next_time));
2429
2430                        let fullname = dns_registry.resolve_name(&service_name).to_string();
2431
2432                        let hostname = dns_registry.resolve_name(info.get_hostname());
2433
2434                        debug!("wake up: announce service {} on {}", fullname, intf.name);
2435                        notify_monitors(
2436                            &mut self.monitors,
2437                            DaemonEvent::Announce(fullname, format!("{}:{}", hostname, &intf.name)),
2438                        );
2439
2440                        info.set_status(*if_index, ServiceStatus::Announced);
2441                    }
2442                }
2443            }
2444        }
2445
2446        if !invalid_intf_addrs.is_empty() {
2447            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2448        }
2449    }
2450
2451    fn unregister_service(
2452        &self,
2453        info: &ServiceInfo,
2454        intf: &MyIntf,
2455        sock: &PktInfoUdpSocket,
2456    ) -> Vec<u8> {
2457        let is_ipv4 = sock.domain() == Domain::IPV4;
2458
2459        // Goodbye records must carry the names peers actually cached: if
2460        // probing renamed a record on this interface, withdraw the renamed
2461        // name, not the original one from `ServiceInfo`.
2462        let (fullname, hostname) = match self.dns_registry_map.get(&intf.index) {
2463            Some(dns_registry) => (
2464                dns_registry.resolve_name(info.get_fullname()),
2465                dns_registry.resolve_name(info.get_hostname()),
2466            ),
2467            None => (info.get_fullname(), info.get_hostname()),
2468        };
2469
2470        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
2471        out.add_answer_at_time(
2472            DnsPointer::new(
2473                info.get_type(),
2474                RRType::PTR,
2475                CLASS_IN,
2476                0,
2477                fullname.to_string(),
2478            ),
2479            0,
2480        );
2481
2482        if let Some(sub) = info.get_subtype() {
2483            trace!("Adding subdomain {}", sub);
2484            out.add_answer_at_time(
2485                DnsPointer::new(sub, RRType::PTR, CLASS_IN, 0, fullname.to_string()),
2486                0,
2487            );
2488        }
2489
2490        out.add_answer_at_time(
2491            DnsSrv::new(
2492                fullname,
2493                CLASS_IN | CLASS_CACHE_FLUSH,
2494                0,
2495                info.get_priority(),
2496                info.get_weight(),
2497                info.get_port(),
2498                hostname.to_string(),
2499            ),
2500            0,
2501        );
2502        out.add_answer_at_time(
2503            DnsTxt::new(
2504                fullname,
2505                CLASS_IN | CLASS_CACHE_FLUSH,
2506                0,
2507                info.generate_txt(),
2508            ),
2509            0,
2510        );
2511
2512        let if_addrs = if is_ipv4 {
2513            info.get_addrs_on_my_intf_v4(intf)
2514        } else {
2515            info.get_addrs_on_my_intf_v6(intf)
2516        };
2517
2518        if if_addrs.is_empty() {
2519            return vec![];
2520        }
2521
2522        for address in if_addrs {
2523            out.add_answer_at_time(
2524                DnsAddress::new(
2525                    hostname,
2526                    ip_address_rr_type(&address),
2527                    CLASS_IN | CLASS_CACHE_FLUSH,
2528                    0,
2529                    address,
2530                    intf.into(),
2531                ),
2532                0,
2533            );
2534        }
2535
2536        // Only (at most) one packet is expected to be sent out.
2537        let sent_vec = match send_dns_outgoing(&out, intf, sock, self.port, None, None) {
2538            Ok(sent_vec) => sent_vec,
2539            Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2540                let invalid_intf_addrs = HashSet::from([intf_addr]);
2541                let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2542                vec![]
2543            }
2544        };
2545        sent_vec.into_iter().next().unwrap_or_default()
2546    }
2547
2548    /// Binds a channel `listener` to querying mDNS hostnames.
2549    ///
2550    /// If there is already a `listener`, it will be updated, i.e. overwritten.
2551    fn add_hostname_resolver(
2552        &mut self,
2553        hostname: String,
2554        listener: Sender<HostnameResolutionEvent>,
2555        timeout: Option<u64>,
2556    ) {
2557        let real_timeout = timeout.map(|t| current_time_millis() + t);
2558        self.hostname_resolvers
2559            .insert(hostname.to_lowercase(), (listener, real_timeout));
2560        if let Some(t) = real_timeout {
2561            self.add_timer(t);
2562        }
2563    }
2564
2565    /// Sends a multicast query for `name` with `qtype`.
2566    fn send_query(&self, name: &str, qtype: RRType) {
2567        self.send_query_vec(&[(name, qtype)]);
2568    }
2569
2570    /// Sends a query on a specific interface without known answers.
2571    ///
2572    /// Used when a new interface is added so the responder won't suppress
2573    /// its response due to known-answer suppression (RFC 6762 Section 7.1).
2574    fn send_query_on_intf(&self, name: &str, qtype: RRType, intf: &MyIntf) {
2575        let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
2576        out.add_question(name, qtype);
2577
2578        let mut invalid_intf_addrs = HashSet::new();
2579        if let Some(sock) = self.ipv4_sock.as_ref() {
2580            if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2581                send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2582            {
2583                invalid_intf_addrs.insert(intf_addr);
2584            }
2585        }
2586        if let Some(sock) = self.ipv6_sock.as_ref() {
2587            if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2588                send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2589            {
2590                invalid_intf_addrs.insert(intf_addr);
2591            }
2592        }
2593        if !invalid_intf_addrs.is_empty() {
2594            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2595        }
2596    }
2597
2598    /// Sends out a list of `questions` (i.e. DNS questions) via multicast.
2599    fn send_query_vec(&self, questions: &[(&str, RRType)]) {
2600        let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
2601        let now = current_time_millis();
2602
2603        for (name, qtype) in questions {
2604            out.add_question(name, *qtype);
2605
2606            for record in self.cache.get_known_answers(name, *qtype, now) {
2607                /*
2608                RFC 6762 section 7.1: https://datatracker.ietf.org/doc/html/rfc6762#section-7.1
2609                ...
2610                    When a Multicast DNS querier sends a query to which it already knows
2611                    some answers, it populates the Answer Section of the DNS query
2612                    message with those answers.
2613                 */
2614                trace!("add known answer: {:?}", record.record);
2615                let mut new_record = record.record.clone();
2616                new_record.get_record_mut().update_ttl(now);
2617                out.add_answer_box(new_record);
2618            }
2619        }
2620
2621        let mut invalid_intf_addrs = HashSet::new();
2622        for (_, intf) in self.my_intfs.iter() {
2623            if let Some(sock) = self.ipv4_sock.as_ref() {
2624                if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2625                    send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2626                {
2627                    invalid_intf_addrs.insert(intf_addr);
2628                }
2629            }
2630            if let Some(sock) = self.ipv6_sock.as_ref() {
2631                if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2632                    send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2633                {
2634                    invalid_intf_addrs.insert(intf_addr);
2635                }
2636            }
2637        }
2638
2639        if !invalid_intf_addrs.is_empty() {
2640            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2641        }
2642    }
2643
2644    /// Reads one UDP datagram from the socket of `intf`.
2645    ///
2646    /// Returns false if failed to receive a packet,
2647    /// otherwise returns true.
2648    fn handle_read(&mut self, event_key: usize) -> bool {
2649        let is_ipv4 = event_key == IPV4_SOCK_EVENT_KEY;
2650        let sock_opt = match event_key {
2651            IPV4_SOCK_EVENT_KEY => &mut self.ipv4_sock,
2652            IPV6_SOCK_EVENT_KEY => &mut self.ipv6_sock,
2653            _ => {
2654                debug!("handle_read: unknown token {}", event_key);
2655                return false;
2656            }
2657        };
2658        let Some(sock) = sock_opt.as_mut() else {
2659            debug!("handle_read: socket not available for token {}", event_key);
2660            return false;
2661        };
2662        // The buffer is one byte bigger than the biggest legal message, so that an
2663        // over-sized datagram can be told apart from a legal one that happens to be
2664        // exactly at the limit.
2665        let max_size = max_pkt_absolute(is_ipv4);
2666        let mut buf = vec![0u8; max_size + 1];
2667
2668        // Read the next mDNS UDP datagram.
2669        let (sz, pktinfo) = match sock.pktinfo.recv(&mut buf) {
2670            Ok(sz) => sz,
2671            Err(e) => {
2672                if e.kind() != std::io::ErrorKind::WouldBlock {
2673                    debug!("listening socket read failed: {}", e);
2674                }
2675                return false;
2676            }
2677        };
2678
2679        // RFC 6762 section 17 caps an mDNS packet at 9000 bytes including the IP and
2680        // UDP headers. A datagram over that arrives truncated, and decoding a
2681        // truncated message does not fail cleanly: names run into whatever bytes
2682        // follow, yielding bogus records or confusing parse errors. Drop it instead.
2683        //
2684        // On Windows, `recv` fails with WSAEMSGSIZE for such a datagram instead of
2685        // truncating it, so it is dropped by the error branch above. Either way it
2686        // is never decoded.
2687        if sz > max_size {
2688            debug!(
2689                "handle_read: dropping over-sized datagram of at least {} bytes (max {})",
2690                sz, max_size
2691            );
2692            return true; // We still read something.
2693        }
2694
2695        // Find the interface that received the packet.
2696        let pkt_if_index = pktinfo.if_index as u32;
2697        let Some(my_intf) = self.my_intfs.get(&pkt_if_index) else {
2698            debug!(
2699                "handle_read: no interface found for pktinfo if_index: {}",
2700                pktinfo.if_index
2701            );
2702            return true; // We still return true to indicate that we read something.
2703        };
2704
2705        // Drop packets for an IP version that has been disabled on this interface.
2706        // This is needed because some times the socket layer may still receive packets
2707        // for an IP version even after we left the multicast group for that IP version.
2708        // We want to drop such packets to avoid unnecessary processing.
2709        let is_ipv4 = event_key == IPV4_SOCK_EVENT_KEY;
2710        if (is_ipv4 && my_intf.next_ifaddr_v4().is_none())
2711            || (!is_ipv4 && my_intf.next_ifaddr_v6().is_none())
2712        {
2713            debug!(
2714                "handle_read: dropping {} packet on intf {} (disabled)",
2715                if is_ipv4 { "IPv4" } else { "IPv6" },
2716                my_intf.name
2717            );
2718            return true;
2719        }
2720
2721        buf.truncate(sz); // reduce potential processing errors
2722
2723        match DnsIncoming::new(buf, my_intf.into()) {
2724            Ok(msg) => {
2725                if msg.is_query() {
2726                    let querier_addr = pktinfo.addr_src;
2727                    self.handle_query(msg, pkt_if_index, querier_addr);
2728                } else if msg.is_response() {
2729                    self.handle_response(msg, pkt_if_index);
2730                } else {
2731                    debug!("Invalid message: not query and not response");
2732                }
2733            }
2734            Err(e) => debug!("Invalid incoming DNS message: {}", e),
2735        }
2736
2737        true
2738    }
2739
2740    /// Returns true, if sent query. Returns false if SRV already exists.
2741    fn query_unresolved(&mut self, instance: &str) -> bool {
2742        if !valid_instance_name(instance) {
2743            trace!("instance name {} not valid", instance);
2744            return false;
2745        }
2746
2747        if let Some(records) = self.cache.get_srv(instance) {
2748            for record in records {
2749                if let Some(srv) = record.record.any().downcast_ref::<DnsSrv>() {
2750                    if self.cache.get_addr(srv.host()).is_none() {
2751                        self.send_query_vec(&[(srv.host(), RRType::A), (srv.host(), RRType::AAAA)]);
2752                        return true;
2753                    }
2754                }
2755            }
2756        } else {
2757            self.send_query(instance, RRType::ANY);
2758            return true;
2759        }
2760
2761        false
2762    }
2763
2764    /// Checks if `ty_domain` has records in the cache. If yes, sends the
2765    /// cached records via `sender`.
2766    fn query_cache_for_service(
2767        &mut self,
2768        ty_domain: &str,
2769        sender: &Sender<ServiceEvent>,
2770        now: u64,
2771    ) {
2772        let mut resolved: HashSet<String> = HashSet::new();
2773        let mut unresolved: HashSet<String> = HashSet::new();
2774
2775        if let Some(records) = self.cache.get_ptr(ty_domain) {
2776            for record in records.iter().filter(|r| !r.record.expires_soon(now)) {
2777                if let Some(ptr) = record.record.any().downcast_ref::<DnsPointer>() {
2778                    let mut new_event = None;
2779                    match self.resolve_service_from_cache(ty_domain, ptr.alias()) {
2780                        Ok(resolved_service) => {
2781                            if resolved_service.is_valid() {
2782                                debug!("Resolved service from cache: {}", ptr.alias());
2783                                new_event =
2784                                    Some(ServiceEvent::ServiceResolved(Box::new(resolved_service)));
2785                            } else {
2786                                debug!("Resolved service is not valid: {}", ptr.alias());
2787                            }
2788                        }
2789                        Err(err) => {
2790                            debug!("Error while resolving service from cache: {}", err);
2791                            continue;
2792                        }
2793                    }
2794
2795                    match sender.send(ServiceEvent::ServiceFound(
2796                        ty_domain.to_string(),
2797                        ptr.alias().to_string(),
2798                    )) {
2799                        Ok(()) => debug!("sent service found {}", ptr.alias()),
2800                        Err(e) => {
2801                            debug!("failed to send service found: {}", e);
2802                            continue;
2803                        }
2804                    }
2805
2806                    if let Some(event) = new_event {
2807                        resolved.insert(ptr.alias().to_string());
2808                        match sender.send(event) {
2809                            Ok(()) => debug!("sent service resolved: {}", ptr.alias()),
2810                            Err(e) => debug!("failed to send service resolved: {}", e),
2811                        }
2812                    } else {
2813                        unresolved.insert(ptr.alias().to_string());
2814                    }
2815                }
2816            }
2817        }
2818
2819        for instance in resolved.drain() {
2820            self.pending_resolves.remove(&instance);
2821            self.resolved.insert(instance);
2822        }
2823
2824        for instance in unresolved.drain() {
2825            self.add_pending_resolve(instance);
2826        }
2827    }
2828
2829    /// Checks if `hostname` has records in the cache. If yes, sends the
2830    /// cached records via `sender`.
2831    fn query_cache_for_hostname(
2832        &mut self,
2833        hostname: &str,
2834        sender: Sender<HostnameResolutionEvent>,
2835    ) {
2836        let addresses_map = self.cache.get_addresses_for_host(hostname);
2837        for (name, addresses) in addresses_map {
2838            match sender.send(HostnameResolutionEvent::AddressesFound(name, addresses)) {
2839                Ok(()) => trace!("sent hostname addresses found"),
2840                Err(e) => debug!("failed to send hostname addresses found: {}", e),
2841            }
2842        }
2843    }
2844
2845    fn add_pending_resolve(&mut self, instance: String) {
2846        if !self.pending_resolves.contains(&instance) {
2847            let next_time = current_time_millis() + RESOLVE_WAIT_IN_MILLIS;
2848            self.add_retransmission(next_time, Command::Resolve(instance.clone(), 1));
2849            self.pending_resolves.insert(instance);
2850        }
2851    }
2852
2853    /// Creates a `ResolvedService` from the cache.
2854    fn resolve_service_from_cache(
2855        &self,
2856        ty_domain: &str,
2857        fullname: &str,
2858    ) -> Result<ResolvedService> {
2859        let now = current_time_millis();
2860        let mut resolved_service = ResolvedService {
2861            ty_domain: ty_domain.to_string(),
2862            sub_ty_domain: None,
2863            fullname: fullname.to_string(),
2864            host: String::new(),
2865            port: 0,
2866            addresses: HashSet::new(),
2867            txt_properties: TxtProperties::new(),
2868        };
2869
2870        // Be sure setting `subtype` if available even when querying for the parent domain.
2871        if let Some(subtype) = self.cache.get_subtype(fullname) {
2872            trace!(
2873                "ty_domain: {} found subtype {} for instance: {}",
2874                ty_domain,
2875                subtype,
2876                fullname
2877            );
2878            if resolved_service.sub_ty_domain.is_none() {
2879                resolved_service.sub_ty_domain = Some(subtype.to_string());
2880            }
2881        }
2882
2883        // resolve SRV record
2884        if let Some(records) = self.cache.get_srv(fullname) {
2885            if let Some(answer) = records.iter().find(|r| !r.record.expires_soon(now)) {
2886                if let Some(dns_srv) = answer.record.any().downcast_ref::<DnsSrv>() {
2887                    resolved_service.host = dns_srv.host().to_string();
2888                    resolved_service.port = dns_srv.port();
2889                }
2890            }
2891        }
2892
2893        // resolve TXT record
2894        if let Some(records) = self.cache.get_txt(fullname) {
2895            if let Some(record) = records.iter().find(|r| !r.record.expires_soon(now)) {
2896                if let Some(dns_txt) = record.record.any().downcast_ref::<DnsTxt>() {
2897                    resolved_service.txt_properties = dns_txt.text().into();
2898                }
2899            }
2900        }
2901
2902        // resolve A and AAAA records
2903        if let Some(records) = self.cache.get_addr(&resolved_service.host) {
2904            for answer in records.iter() {
2905                if let Some(dns_a) = answer.record.any().downcast_ref::<DnsAddress>() {
2906                    if dns_a.expires_soon(now) {
2907                        trace!(
2908                            "Addr expired or expires soon: {}",
2909                            dns_a.address().to_ip_addr()
2910                        );
2911                    } else {
2912                        let scoped = dns_a.address();
2913                        if let ScopedIp::V4(v4) = &scoped {
2914                            // Merge interface_ids if this V4 addr already exists.
2915                            // Linear scan by IP since Eq/Hash include interface_ids.
2916                            let existing = resolved_service
2917                                .addresses
2918                                .iter()
2919                                .find(|a| a.to_ip_addr() == IpAddr::V4(*v4.addr()))
2920                                .cloned();
2921                            if let Some(mut existing) = existing {
2922                                resolved_service.addresses.remove(&existing);
2923                                if let ScopedIp::V4(existing_v4) = &mut existing {
2924                                    for id in v4.interface_ids() {
2925                                        existing_v4.add_interface_id(id.clone());
2926                                    }
2927                                }
2928                                resolved_service.addresses.insert(existing);
2929                            } else {
2930                                resolved_service.addresses.insert(scoped);
2931                            }
2932                        } else {
2933                            resolved_service.addresses.insert(scoped);
2934                        }
2935                    }
2936                }
2937            }
2938        }
2939
2940        Ok(resolved_service)
2941    }
2942
2943    fn handle_poller_events(&mut self, events: &mio::Events) {
2944        for ev in events.iter() {
2945            trace!("event received with key {:?}", ev.token());
2946            if ev.token().0 == SIGNAL_SOCK_EVENT_KEY {
2947                // Drain signals as we will drain commands as well.
2948                self.signal_sock_drain();
2949
2950                if let Err(e) = self.poller.registry().reregister(
2951                    &mut self.signal_sock,
2952                    ev.token(),
2953                    mio::Interest::READABLE,
2954                ) {
2955                    debug!("failed to modify poller for signal socket: {}", e);
2956                }
2957                continue; // Next event.
2958            }
2959
2960            // Read until no more packets available.
2961            while self.handle_read(ev.token().0) {}
2962
2963            // we continue to monitor this socket.
2964            if ev.token().0 == IPV4_SOCK_EVENT_KEY {
2965                // Re-register the IPv4 socket for reading.
2966                if let Some(sock) = self.ipv4_sock.as_mut() {
2967                    if let Err(e) =
2968                        self.poller
2969                            .registry()
2970                            .reregister(sock, ev.token(), mio::Interest::READABLE)
2971                    {
2972                        debug!("modify poller for IPv4 socket: {}", e);
2973                    }
2974                }
2975            } else if ev.token().0 == IPV6_SOCK_EVENT_KEY {
2976                // Re-register the IPv6 socket for reading.
2977                if let Some(sock) = self.ipv6_sock.as_mut() {
2978                    if let Err(e) =
2979                        self.poller
2980                            .registry()
2981                            .reregister(sock, ev.token(), mio::Interest::READABLE)
2982                    {
2983                        debug!("modify poller for IPv6 socket: {}", e);
2984                    }
2985                }
2986            }
2987        }
2988    }
2989
2990    /// Deal with incoming response packets.  All answers
2991    /// are held in the cache, and listeners are notified.
2992    fn handle_response(&mut self, mut msg: DnsIncoming, if_index: u32) {
2993        let now = current_time_millis();
2994
2995        // remove records that are expired.
2996        let mut record_predicate = |record: &DnsRecordBox| {
2997            if !record.get_record().is_expired(now) {
2998                return true;
2999            }
3000
3001            debug!("record is expired, removing it from cache.");
3002            if self.cache.remove(record) {
3003                // for PTR records, send event to listeners
3004                if let Some(dns_ptr) = record.any().downcast_ref::<DnsPointer>() {
3005                    call_service_listener(
3006                        &self.service_queriers,
3007                        dns_ptr.get_name(),
3008                        ServiceEvent::ServiceRemoved(
3009                            dns_ptr.get_name().to_string(),
3010                            dns_ptr.alias().to_string(),
3011                        ),
3012                    );
3013                }
3014            }
3015            false
3016        };
3017        msg.answers_mut().retain(&mut record_predicate);
3018        msg.authorities_mut().retain(&mut record_predicate);
3019        msg.additionals_mut().retain(&mut record_predicate);
3020
3021        // check possible conflicts and handle them.
3022        self.conflict_handler(&msg, if_index);
3023
3024        // check if the message is for us.
3025        let mut is_for_us = true; // assume it is for us.
3026
3027        // If there are any PTR records in the answers, there should be
3028        // at least one PTR for us. Otherwise, the message is not for us.
3029        // If there are no PTR records at all, assume this message is for us.
3030        for answer in msg.answers() {
3031            if answer.get_type() == RRType::PTR {
3032                if self.service_queriers.contains_key(answer.get_name()) {
3033                    is_for_us = true;
3034                    break; // OK to break: at least one PTR for us.
3035                } else {
3036                    is_for_us = false;
3037                }
3038            } else if answer.get_type() == RRType::A || answer.get_type() == RRType::AAAA {
3039                // If there is a hostname querier for this address, then it is for us.
3040                let answer_lowercase = answer.get_name().to_lowercase();
3041                if self.hostname_resolvers.contains_key(&answer_lowercase) {
3042                    is_for_us = true;
3043                    break; // OK to break: at least one hostname for us.
3044                }
3045            }
3046        }
3047
3048        // if we explicitily want to accept unsolicited responses, we should consider all messages as for us.
3049        if self.accept_unsolicited {
3050            is_for_us = true;
3051        }
3052
3053        /// Represents a DNS record change that involves one service instance.
3054        struct InstanceChange {
3055            ty: RRType,   // The type of DNS record for the instance.
3056            name: String, // The name of the record.
3057        }
3058
3059        // Go through all answers to get the new and updated records.
3060        // For new PTR records, send out ServiceFound immediately. For others,
3061        // collect them into `changes`.
3062        //
3063        // Note: we don't try to identify the update instances based on
3064        // each record immediately as the answers are likely related to each
3065        // other.
3066        let mut changes = Vec::new();
3067        let mut timers = Vec::new();
3068        let Some(my_intf) = self.my_intfs.get(&if_index) else {
3069            return;
3070        };
3071        for record in msg.all_records() {
3072            match self
3073                .cache
3074                .add_or_update(my_intf, record, &mut timers, is_for_us)
3075            {
3076                Some((dns_record, true)) => {
3077                    timers.push(dns_record.record.get_record().get_expire_time());
3078                    timers.push(dns_record.record.get_record().get_refresh_time());
3079
3080                    let ty = dns_record.record.get_type();
3081                    let name = dns_record.record.get_name();
3082
3083                    // Positive dump: a new record was accepted into the cache.
3084                    // Counterpart to the "skipping record" debug line in the parser.
3085                    debug!("cache: new record: {:?}", &dns_record.record);
3086
3087                    // Only process PTR that does not expire soon (i.e. TTL > 1).
3088                    if ty == RRType::PTR && dns_record.record.get_record().get_ttl() > 1 {
3089                        if self.service_queriers.contains_key(name) {
3090                            timers.push(dns_record.record.get_record().get_refresh_time());
3091                        }
3092
3093                        // send ServiceFound
3094                        if let Some(dns_ptr) = dns_record.record.any().downcast_ref::<DnsPointer>()
3095                        {
3096                            debug!("calling listener with service found: {name}");
3097                            call_service_listener(
3098                                &self.service_queriers,
3099                                name,
3100                                ServiceEvent::ServiceFound(
3101                                    name.to_string(),
3102                                    dns_ptr.alias().to_string(),
3103                                ),
3104                            );
3105                            changes.push(InstanceChange {
3106                                ty,
3107                                name: dns_ptr.alias().to_string(),
3108                            });
3109                        }
3110                    } else {
3111                        changes.push(InstanceChange {
3112                            ty,
3113                            name: name.to_string(),
3114                        });
3115                    }
3116                }
3117                Some((dns_record, false)) => {
3118                    timers.push(dns_record.record.get_record().get_expire_time());
3119                    timers.push(dns_record.record.get_record().get_refresh_time());
3120                }
3121                _ => {}
3122            }
3123        }
3124
3125        // Add timers for the new records.
3126        for t in timers {
3127            self.add_timer(t);
3128        }
3129
3130        // Go through remaining changes to see if any hostname resolutions were found or updated.
3131        for change in changes
3132            .iter()
3133            .filter(|change| change.ty == RRType::A || change.ty == RRType::AAAA)
3134        {
3135            let addr_map = self.cache.get_addresses_for_host(&change.name);
3136            for (name, addresses) in addr_map {
3137                call_hostname_resolution_listener(
3138                    &self.hostname_resolvers,
3139                    &change.name,
3140                    HostnameResolutionEvent::AddressesFound(name, addresses),
3141                )
3142            }
3143        }
3144
3145        // Identify the instances that need to be "resolved".
3146        let mut updated_instances = HashSet::new();
3147        for update in changes {
3148            match update.ty {
3149                RRType::PTR | RRType::SRV | RRType::TXT => {
3150                    updated_instances.insert(update.name);
3151                }
3152                RRType::A | RRType::AAAA => {
3153                    let instances = self.cache.get_instances_on_host(&update.name);
3154                    updated_instances.extend(instances);
3155                }
3156                _ => {}
3157            }
3158        }
3159
3160        self.resolve_updated_instances(&updated_instances);
3161    }
3162
3163    fn conflict_handler(&mut self, msg: &DnsIncoming, if_index: u32) {
3164        let Some(my_intf) = self.my_intfs.get(&if_index) else {
3165            debug!("handle_response: no intf found for index {if_index}");
3166            return;
3167        };
3168
3169        let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) else {
3170            return;
3171        };
3172
3173        for answer in msg.answers().iter() {
3174            let mut new_records = Vec::new();
3175
3176            let name = answer.get_name();
3177            let Some(probe) = dns_registry.probing.get_mut(name) else {
3178                continue;
3179            };
3180
3181            // check against possible multicast forwarding
3182            if answer.get_type() == RRType::A || answer.get_type() == RRType::AAAA {
3183                if let Some(answer_addr) = answer.any().downcast_ref::<DnsAddress>() {
3184                    if answer_addr.interface_id.index != if_index {
3185                        debug!(
3186                            "conflict handler: answer addr {:?} not in the subnet of intf {}",
3187                            answer_addr, my_intf.name
3188                        );
3189                        continue;
3190                    }
3191                }
3192
3193                // double check if any other address record matches rrdata,
3194                // as there could be multiple addresses for the same name.
3195                let any_match = probe.records.iter().any(|r| {
3196                    r.get_type() == answer.get_type()
3197                        && r.get_class() == answer.get_class()
3198                        && r.rrdata_match(answer.as_ref())
3199                });
3200                if any_match {
3201                    continue; // no conflict for this answer.
3202                }
3203            }
3204
3205            probe.records.retain(|record| {
3206                if record.get_type() == answer.get_type()
3207                    && record.get_class() == answer.get_class()
3208                    && !record.rrdata_match(answer.as_ref())
3209                {
3210                    debug!(
3211                        "found conflict name: '{name}' record: {}: {} PEER: {}",
3212                        record.get_type(),
3213                        record.rdata_print(),
3214                        answer.rdata_print()
3215                    );
3216
3217                    // create a new name for this record
3218                    // then remove the old record in probing.
3219                    let mut new_record = record.clone();
3220                    let new_name = match record.get_type() {
3221                        RRType::A => hostname_change(name),
3222                        RRType::AAAA => hostname_change(name),
3223                        _ => name_change(name),
3224                    };
3225                    new_record.get_record_mut().set_new_name(new_name);
3226                    new_records.push(new_record);
3227                    return false; // old record is dropped from the probe.
3228                }
3229
3230                true
3231            });
3232
3233            // ?????
3234            // if probe.records.is_empty() {
3235            //     dns_registry.probing.remove(name);
3236            // }
3237
3238            // Probing again with the new names.
3239            let create_time = current_time_millis() + fastrand::u64(0..250);
3240
3241            let waiting_services = probe.waiting_services.clone();
3242
3243            for record in new_records {
3244                if dns_registry.update_hostname(name, record.get_name(), create_time) {
3245                    self.timers.push(Reverse(create_time));
3246                }
3247
3248                // remember the name changes (note: `name` might not be the original, it could be already changed once.)
3249                dns_registry.name_changes.insert(
3250                    record.get_record().get_original_name().to_string(),
3251                    record.get_name().to_string(),
3252                );
3253
3254                let new_probe = match dns_registry.probing.get_mut(record.get_name()) {
3255                    Some(p) => p,
3256                    None => {
3257                        let new_probe = dns_registry
3258                            .probing
3259                            .entry(record.get_name().to_string())
3260                            .or_insert_with(|| {
3261                                debug!("conflict handler: new probe of {}", record.get_name());
3262                                Probe::new(create_time)
3263                            });
3264                        self.timers.push(Reverse(new_probe.next_send));
3265                        new_probe
3266                    }
3267                };
3268
3269                debug!(
3270                    "insert record with new name '{}' {} into probe",
3271                    record.get_name(),
3272                    record.get_type()
3273                );
3274                new_probe.insert_record(record);
3275
3276                new_probe.waiting_services.extend(waiting_services.clone());
3277            }
3278        }
3279    }
3280
3281    /// Resolve the updated (including new) instances.
3282    ///
3283    /// Note: it is possible that more than 1 PTR pointing to the same
3284    /// instance. For example, a regular service type PTR and a sub-type
3285    /// service type PTR can both point to the same service instance.
3286    /// This loop automatically handles the sub-type PTRs.
3287    fn resolve_updated_instances(&mut self, updated_instances: &HashSet<String>) {
3288        if updated_instances.is_empty() {
3289            return;
3290        }
3291
3292        let mut resolved: HashSet<String> = HashSet::new();
3293        let mut unresolved: HashSet<String> = HashSet::new();
3294        let mut removed_instances = HashMap::new();
3295
3296        let now = current_time_millis();
3297
3298        for (ty_domain, records) in self.cache.all_ptr().iter() {
3299            if !self.service_queriers.contains_key(ty_domain) {
3300                // No need to resolve if not in our queries.
3301                continue;
3302            }
3303
3304            for ptr in records.iter().filter(|r| !r.record.expires_soon(now)) {
3305                let Some(dns_ptr) = ptr.record.any().downcast_ref::<DnsPointer>() else {
3306                    continue;
3307                };
3308
3309                let instance = dns_ptr.alias();
3310                if !updated_instances.contains(instance) {
3311                    continue;
3312                }
3313
3314                let Ok(resolved_service) = self.resolve_service_from_cache(ty_domain, instance)
3315                else {
3316                    continue;
3317                };
3318
3319                debug!("resolve_updated_instances: from cache: {instance}");
3320                if resolved_service.is_valid() {
3321                    debug!(
3322                        "resolved '{}' -> host '{}' port {} addrs {:?}",
3323                        instance,
3324                        resolved_service.host,
3325                        resolved_service.port,
3326                        resolved_service.addresses,
3327                    );
3328                    resolved.insert(instance.to_string());
3329                    let event = ServiceEvent::ServiceResolved(Box::new(resolved_service));
3330                    call_service_listener(&self.service_queriers, ty_domain, event);
3331                } else {
3332                    debug!("Resolved service is not valid: {instance}");
3333                    if self.resolved.remove(dns_ptr.alias()) {
3334                        removed_instances
3335                            .entry(ty_domain.to_string())
3336                            .or_insert_with(HashSet::new)
3337                            .insert(instance.to_string());
3338                    }
3339                    unresolved.insert(instance.to_string());
3340                }
3341            }
3342        }
3343
3344        for instance in resolved.drain() {
3345            self.pending_resolves.remove(&instance);
3346            self.resolved.insert(instance);
3347        }
3348
3349        for instance in unresolved.drain() {
3350            self.add_pending_resolve(instance);
3351        }
3352
3353        if !removed_instances.is_empty() {
3354            debug!(
3355                "resolve_updated_instances: removed {}",
3356                &removed_instances.len()
3357            );
3358            self.notify_service_removal(removed_instances);
3359        }
3360    }
3361
3362    /// Handle incoming query packets, figure out whether and what to respond.
3363    fn handle_query(&mut self, msg: DnsIncoming, if_index: u32, querier_addr: SocketAddr) {
3364        let querier_ip = querier_addr.ip();
3365        let is_ipv4 = querier_ip.is_ipv4();
3366        let sock_opt = if is_ipv4 {
3367            &self.ipv4_sock
3368        } else {
3369            &self.ipv6_sock
3370        };
3371        let Some(sock) = sock_opt.as_ref() else {
3372            debug!("handle_query: socket not available for intf {}", if_index);
3373            return;
3374        };
3375
3376        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
3377        let mut delayed = false;
3378
3379        // Special meta-query "_services._dns-sd._udp.<Domain>".
3380        // See https://datatracker.ietf.org/doc/html/rfc6763#section-9
3381        const META_QUERY: &str = "_services._dns-sd._udp.local.";
3382
3383        let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) else {
3384            debug!("missing dns registry for intf {}", if_index);
3385            return;
3386        };
3387
3388        let Some(intf) = self.my_intfs.get(&if_index) else {
3389            debug!("handle_query: no intf found for index {if_index}");
3390            return;
3391        };
3392
3393        for question in msg.questions().iter() {
3394            let qtype = question.entry_type();
3395            let q_name = question.entry_name();
3396
3397            if qtype == RRType::PTR {
3398                // PTR answers are shared records: defer the response unless this
3399                // is a legacy-unicast (source port != 5353) or probe-defense
3400                // (records in the Authority Section) query.
3401                if querier_addr.port() == MDNS_PORT && msg.num_authorities() == 0 {
3402                    delayed = true;
3403                }
3404                for service in self.my_services.values() {
3405                    if service.get_status(if_index) != ServiceStatus::Announced {
3406                        continue;
3407                    }
3408
3409                    if service.matches_type_or_subtype(q_name) {
3410                        out.add_answer_with_additionals(&msg, service, intf, dns_registry, is_ipv4);
3411                    } else if q_name == META_QUERY {
3412                        let ttl = service.get_other_ttl();
3413                        let alias = service.get_type().to_string();
3414                        let ptr = DnsPointer::new(q_name, RRType::PTR, CLASS_IN, ttl, alias);
3415                        if !out.add_answer(&msg, ptr) {
3416                            trace!("answer was not added for meta-query {:?}", &question);
3417                        }
3418                    }
3419                }
3420            } else {
3421                // Simultaneous Probe Tiebreaking (RFC 6762 section 8.2)
3422                if qtype == RRType::ANY && msg.num_authorities() > 0 {
3423                    if let Some(probe) = dns_registry.probing.get_mut(q_name) {
3424                        probe.tiebreaking(&msg, q_name);
3425                    }
3426                }
3427
3428                if qtype == RRType::A || qtype == RRType::AAAA || qtype == RRType::ANY {
3429                    for service in self.my_services.values() {
3430                        if service.get_status(if_index) != ServiceStatus::Announced {
3431                            continue;
3432                        }
3433
3434                        let service_hostname = dns_registry.resolve_name(service.get_hostname());
3435
3436                        if service_hostname.to_lowercase() == question.entry_name().to_lowercase() {
3437                            // Pick addresses based on the question type, not the
3438                            // socket family. RFC 6762 doesn't require A queries
3439                            // to come over IPv4 transport — Android's getaddrinfo
3440                            // routinely sends both A and AAAA queries over its
3441                            // preferred IPv6 mDNS socket and expects A records
3442                            // to be answered with v4 addresses.
3443                            let mut intf_addrs: Vec<IpAddr> = Vec::new();
3444                            if qtype == RRType::A || qtype == RRType::ANY {
3445                                intf_addrs.extend(service.get_addrs_on_my_intf_v4(intf));
3446                            }
3447                            if qtype == RRType::AAAA || qtype == RRType::ANY {
3448                                intf_addrs.extend(service.get_addrs_on_my_intf_v6(intf));
3449                            }
3450                            if intf_addrs.is_empty()
3451                                && (qtype == RRType::A || qtype == RRType::AAAA)
3452                            {
3453                                let t = match qtype {
3454                                    RRType::A => "TYPE_A",
3455                                    RRType::AAAA => "TYPE_AAAA",
3456                                    _ => "invalid_type",
3457                                };
3458                                trace!(
3459                                    "Cannot find valid addrs for {} response on intf {:?}",
3460                                    t,
3461                                    &intf
3462                                );
3463                                continue;
3464                            }
3465                            for address in intf_addrs {
3466                                out.add_answer(
3467                                    &msg,
3468                                    DnsAddress::new(
3469                                        service_hostname,
3470                                        ip_address_rr_type(&address),
3471                                        CLASS_IN | CLASS_CACHE_FLUSH,
3472                                        service.get_host_ttl(),
3473                                        address,
3474                                        intf.into(),
3475                                    ),
3476                                );
3477                            }
3478                        }
3479                    }
3480                }
3481
3482                let query_name = q_name.to_lowercase();
3483                let service_opt = self
3484                    .my_services
3485                    .iter()
3486                    .find(|(k, _v)| dns_registry.resolve_name(k.as_str()) == query_name)
3487                    .map(|(_, v)| v);
3488
3489                let Some(service) = service_opt else {
3490                    continue;
3491                };
3492
3493                if service.get_status(if_index) != ServiceStatus::Announced {
3494                    continue;
3495                }
3496
3497                let intf_addrs = if is_ipv4 {
3498                    service.get_addrs_on_my_intf_v4(intf)
3499                } else {
3500                    service.get_addrs_on_my_intf_v6(intf)
3501                };
3502                if intf_addrs.is_empty() {
3503                    debug!(
3504                        "Cannot find valid addrs for TYPE_SRV response on intf {:?}",
3505                        &intf
3506                    );
3507                    continue;
3508                }
3509
3510                add_answer_of_service(
3511                    &mut out,
3512                    &msg,
3513                    question.entry_name(),
3514                    service,
3515                    qtype,
3516                    intf_addrs,
3517                );
3518            }
3519        }
3520
3521        // Defer PTR responses (RFC 6762 §6).
3522        if delayed && out.answers_count() > 0 {
3523            out.set_id(msg.id());
3524            self.increase_counter(Counter::KnownAnswerSuppression, out.known_answer_count());
3525            let delay =
3526                fastrand::u64(SHARED_RESPONSE_DELAY_MIN_MILLIS..SHARED_RESPONSE_DELAY_MAX_MILLIS);
3527            let next_time = current_time_millis() + delay;
3528            self.delayed_responses.push(DelayedResponse {
3529                next_time,
3530                out,
3531                if_index,
3532                is_ipv4,
3533            });
3534            self.add_timer(next_time);
3535            return;
3536        }
3537
3538        if out.answers_count() > 0 {
3539            out.set_id(msg.id());
3540
3541            // Pick a source IfAddr on `intf` whose subnet contains the querier's IP.
3542            // It's OK if it's None, `send_dns_outgoing` will then pick one address.
3543            let matched_source = intf
3544                .addrs
3545                .iter()
3546                .find(|if_addr| valid_ip_on_intf(&querier_ip, if_addr));
3547
3548            // RFC 6762 §6.7 (Legacy Unicast Responses): if the querier's source
3549            // port is not 5353, it's a one-shot legacy querier (e.g. Android's
3550            // getaddrinfo, iOS resolver fallback). The response MUST be unicast
3551            // back to the querier's source IP and port; multicast replies will
3552            // never reach the querier's ephemeral socket. Legacy unicast
3553            // responses must also echo the question section and clear the
3554            // cache-flush bit, since legacy resolvers don't understand it.
3555            let unicast_dest = if querier_addr.port() != MDNS_PORT {
3556                Some(querier_addr)
3557            } else {
3558                None
3559            };
3560
3561            if unicast_dest.is_some() {
3562                for q in msg.questions() {
3563                    out.add_question(q.entry_name(), q.entry_type());
3564                }
3565                out.clear_cache_flush_bits();
3566            } else if msg.num_authorities() == 0 {
3567                // RFC 6762 §6: a record MUST NOT be multicast on an interface
3568                // more than once per second. Two exceptions skip the limit here:
3569                //   - Unicast responses (handled above).
3570                //   - Answering probe queries: a probe carries the proposed
3571                //     records in its Authority Section, and we MUST defend our
3572                //     records immediately so the prober detects the conflict.
3573                dns_registry.apply_multicast_rate_limit(&mut out, current_time_millis(), is_ipv4);
3574            }
3575
3576            if out.answers_count() > 0 {
3577                debug!("sending response on intf {}", &intf.name);
3578                if let Err(InternalError::IntfAddrInvalid(intf_addr)) = send_dns_outgoing(
3579                    &out,
3580                    intf,
3581                    &sock.pktinfo,
3582                    self.port,
3583                    matched_source,
3584                    unicast_dest,
3585                ) {
3586                    let invalid_intf_addr = HashSet::from([intf_addr]);
3587                    let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addr));
3588                }
3589
3590                let if_name = intf.name.clone();
3591
3592                self.increase_counter(Counter::Respond, 1);
3593                self.notify_monitors(DaemonEvent::Respond(if_name));
3594            }
3595        }
3596
3597        self.increase_counter(Counter::KnownAnswerSuppression, out.known_answer_count());
3598    }
3599
3600    /// Multicasts a PTR query response that was deferred per RFC 6762 §6.
3601    ///
3602    /// Re-resolves the socket and interface from `if_index`, so it is safe to
3603    /// call from the timer loop after the borrows taken while building the
3604    /// response are gone. The original querier is no longer known, so the
3605    /// response is always a plain multicast (no unicast destination, no
3606    /// source-address preference); the §6 once-per-second multicast rate limit
3607    /// still applies.
3608    fn send_delayed_response(&mut self, resp: DelayedResponse) {
3609        let DelayedResponse {
3610            mut out,
3611            if_index,
3612            is_ipv4,
3613            ..
3614        } = resp;
3615
3616        let sock_opt = if is_ipv4 {
3617            &self.ipv4_sock
3618        } else {
3619            &self.ipv6_sock
3620        };
3621        let Some(sock) = sock_opt.as_ref() else {
3622            debug!("send_delayed_response: socket not available for intf {if_index}");
3623            return;
3624        };
3625
3626        if let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) {
3627            dns_registry.apply_multicast_rate_limit(&mut out, current_time_millis(), is_ipv4);
3628        }
3629        if out.answers_count() == 0 {
3630            return;
3631        }
3632
3633        let Some(intf) = self.my_intfs.get(&if_index) else {
3634            debug!("send_delayed_response: no intf found for index {if_index}");
3635            return;
3636        };
3637
3638        let if_name = intf.name.clone();
3639        debug!("sending delayed response on intf {}", &if_name);
3640        let send_result = send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None);
3641
3642        if let Err(InternalError::IntfAddrInvalid(intf_addr)) = send_result {
3643            let invalid_intf_addr = HashSet::from([intf_addr]);
3644            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addr));
3645        }
3646
3647        self.increase_counter(Counter::Respond, 1);
3648        self.notify_monitors(DaemonEvent::Respond(if_name));
3649    }
3650
3651    /// Increases the value of `counter` by `count`.
3652    fn increase_counter(&mut self, counter: Counter, count: i64) {
3653        let key = counter.to_string();
3654        match self.counters.get_mut(&key) {
3655            Some(v) => *v += count,
3656            None => {
3657                self.counters.insert(key, count);
3658            }
3659        }
3660    }
3661
3662    /// Sets the value of `counter` to `count`.
3663    fn set_counter(&mut self, counter: Counter, count: i64) {
3664        let key = counter.to_string();
3665        self.counters.insert(key, count);
3666    }
3667
3668    fn signal_sock_drain(&self) {
3669        let mut signal_buf = [0; 1024];
3670
3671        // This recv is non-blocking as the socket is non-blocking.
3672        while let Ok(sz) = self.signal_sock.recv(&mut signal_buf) {
3673            trace!(
3674                "signal socket recvd: {}",
3675                String::from_utf8_lossy(&signal_buf[0..sz])
3676            );
3677        }
3678    }
3679
3680    fn add_retransmission(&mut self, next_time: u64, command: Command) {
3681        self.retransmissions.push(ReRun { next_time, command });
3682        self.add_timer(next_time);
3683    }
3684
3685    /// Sends service removal event to listeners for expired service records.
3686    /// `expired`: map of service type domain to set of instance names.
3687    fn notify_service_removal(&self, expired: HashMap<String, HashSet<String>>) {
3688        for (ty_domain, sender) in self.service_queriers.iter() {
3689            if let Some(instances) = expired.get(ty_domain) {
3690                for instance_name in instances {
3691                    let event = ServiceEvent::ServiceRemoved(
3692                        ty_domain.to_string(),
3693                        instance_name.to_string(),
3694                    );
3695                    match sender.send(event) {
3696                        Ok(()) => debug!("notify_service_removal: sent ServiceRemoved to listener of {ty_domain}: {instance_name}"),
3697                        Err(e) => debug!("Failed to send event: {}", e),
3698                    }
3699                }
3700            }
3701        }
3702    }
3703
3704    /// The entry point that executes all commands received by the daemon.
3705    ///
3706    /// `repeating`: whether this is a retransmission.
3707    fn exec_command(&mut self, command: Command, repeating: bool) {
3708        trace!("exec_command: {:?} repeating: {}", &command, repeating);
3709        match command {
3710            Command::Browse(ty, next_delay, cache_only, listener) => {
3711                self.exec_command_browse(repeating, ty, next_delay, cache_only, listener);
3712            }
3713
3714            Command::ResolveHostname(hostname, next_delay, listener, timeout) => {
3715                self.exec_command_resolve_hostname(
3716                    repeating, hostname, next_delay, listener, timeout,
3717                );
3718            }
3719
3720            Command::Register(service_info) => {
3721                self.register_service(*service_info);
3722                self.increase_counter(Counter::Register, 1);
3723            }
3724
3725            Command::RegisterResend(fullname, intf) => {
3726                trace!("register-resend service: {fullname} on {}", &intf);
3727                if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
3728                    self.exec_command_register_resend(fullname, intf)
3729                {
3730                    let invalid_intf_addr = HashSet::from([intf_addr]);
3731                    let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addr));
3732                }
3733            }
3734
3735            Command::Unregister(fullname, resp_s) => {
3736                trace!("unregister service {} repeat {}", &fullname, &repeating);
3737                self.exec_command_unregister(repeating, fullname, resp_s);
3738            }
3739
3740            Command::UnregisterResend(packet, if_index, is_ipv4) => {
3741                self.exec_command_unregister_resend(packet, if_index, is_ipv4);
3742            }
3743
3744            Command::StopBrowse(ty_domain) => self.exec_command_stop_browse(ty_domain),
3745
3746            Command::StopResolveHostname(hostname) => {
3747                self.exec_command_stop_resolve_hostname(hostname.to_lowercase())
3748            }
3749
3750            Command::Resolve(instance, try_count) => self.exec_command_resolve(instance, try_count),
3751
3752            Command::GetMetrics(resp_s) => self.exec_command_get_metrics(resp_s),
3753
3754            Command::GetStatus(resp_s) => match resp_s.send(self.status.clone()) {
3755                Ok(()) => trace!("Sent status to the client"),
3756                Err(e) => debug!("Failed to send status: {}", e),
3757            },
3758
3759            Command::Monitor(resp_s) => {
3760                self.monitors.push(resp_s);
3761            }
3762
3763            Command::SetOption(daemon_opt) => {
3764                self.process_set_option(daemon_opt);
3765            }
3766
3767            Command::GetOption(resp_s) => {
3768                let val = DaemonOptionVal {
3769                    _service_name_len_max: self.service_name_len_max,
3770                    ip_check_interval: self.ip_check_interval,
3771                };
3772                if let Err(e) = resp_s.send(val) {
3773                    debug!("Failed to send options: {}", e);
3774                }
3775            }
3776
3777            Command::Verify(instance_fullname, timeout) => {
3778                self.exec_command_verify(instance_fullname, timeout, repeating);
3779            }
3780
3781            Command::InvalidIntfAddrs(invalid_intf_addrs) => {
3782                for intf_addr in invalid_intf_addrs {
3783                    self.del_interface_addr(&intf_addr);
3784                }
3785
3786                self.check_ip_changes();
3787            }
3788
3789            _ => {
3790                debug!("unexpected command: {:?}", &command);
3791            }
3792        }
3793    }
3794
3795    fn exec_command_get_metrics(&mut self, resp_s: Sender<HashMap<String, i64>>) {
3796        self.set_counter(Counter::CachedPTR, self.cache.ptr_count() as i64);
3797        self.set_counter(Counter::CachedSRV, self.cache.srv_count() as i64);
3798        self.set_counter(Counter::CachedAddr, self.cache.addr_count() as i64);
3799        self.set_counter(Counter::CachedTxt, self.cache.txt_count() as i64);
3800        self.set_counter(Counter::CachedNSec, self.cache.nsec_count() as i64);
3801        self.set_counter(Counter::CachedSubtype, self.cache.subtype_count() as i64);
3802        self.set_counter(Counter::Timer, self.timers.len() as i64);
3803
3804        let dns_registry_probe_count: usize = self
3805            .dns_registry_map
3806            .values()
3807            .map(|r| r.probing.len())
3808            .sum();
3809        self.set_counter(Counter::DnsRegistryProbe, dns_registry_probe_count as i64);
3810
3811        let dns_registry_active_count: usize = self
3812            .dns_registry_map
3813            .values()
3814            .map(|r| r.active.values().map(|a| a.len()).sum::<usize>())
3815            .sum();
3816        self.set_counter(Counter::DnsRegistryActive, dns_registry_active_count as i64);
3817
3818        let dns_registry_timer_count: usize = self
3819            .dns_registry_map
3820            .values()
3821            .map(|r| r.new_timers.len())
3822            .sum();
3823        self.set_counter(Counter::DnsRegistryTimer, dns_registry_timer_count as i64);
3824
3825        let dns_registry_name_change_count: usize = self
3826            .dns_registry_map
3827            .values()
3828            .map(|r| r.name_changes.len())
3829            .sum();
3830        self.set_counter(
3831            Counter::DnsRegistryNameChange,
3832            dns_registry_name_change_count as i64,
3833        );
3834
3835        // Send the metrics to the client.
3836        if let Err(e) = resp_s.send(self.counters.clone()) {
3837            debug!("Failed to send metrics: {}", e);
3838        }
3839    }
3840
3841    fn exec_command_browse(
3842        &mut self,
3843        repeating: bool,
3844        ty: String,
3845        next_delay: u32,
3846        cache_only: bool,
3847        listener: Sender<ServiceEvent>,
3848    ) {
3849        let pretty_addrs: Vec<String> = self
3850            .my_intfs
3851            .iter()
3852            .map(|(if_index, itf)| format!("{} ({if_index})", itf.name))
3853            .collect();
3854
3855        if let Err(e) = listener.send(ServiceEvent::SearchStarted(format!(
3856            "{ty} on {} interfaces [{}]",
3857            pretty_addrs.len(),
3858            pretty_addrs.join(", ")
3859        ))) {
3860            debug!(
3861                "Failed to send SearchStarted({})(repeating:{}): {}",
3862                &ty, repeating, e
3863            );
3864            return;
3865        }
3866
3867        let now = current_time_millis();
3868        if !repeating {
3869            // Binds a `listener` to querying mDNS domain type `ty`.
3870            //
3871            // If there is already a `listener`, it will be updated, i.e. overwritten.
3872            self.service_queriers.insert(ty.clone(), listener.clone());
3873
3874            // if we already have the records in our cache, just send them
3875            self.query_cache_for_service(&ty, &listener, now);
3876        }
3877
3878        if cache_only {
3879            // If cache_only is true, we do not send a query.
3880            match listener.send(ServiceEvent::SearchStopped(ty.clone())) {
3881                Ok(()) => debug!("SearchStopped sent for {}", &ty),
3882                Err(e) => debug!("Failed to send SearchStopped: {}", e),
3883            }
3884            return;
3885        }
3886
3887        if !repeating {
3888            // RFC 6762 §5.2: delay the first query by a random jitter.
3889            let jitter =
3890                fastrand::u64(INITIAL_QUERY_DELAY_MIN_MILLIS..INITIAL_QUERY_DELAY_MAX_MILLIS);
3891            self.add_retransmission(now + jitter, Command::Browse(ty, 1, cache_only, listener));
3892            return;
3893        }
3894
3895        self.send_query(&ty, RRType::PTR);
3896        self.increase_counter(Counter::Browse, 1);
3897
3898        let next_time = now + (next_delay * 1000) as u64;
3899        let max_delay = 60 * 60;
3900        let delay = cmp::min(next_delay * 2, max_delay);
3901        self.add_retransmission(next_time, Command::Browse(ty, delay, cache_only, listener));
3902    }
3903
3904    fn exec_command_resolve_hostname(
3905        &mut self,
3906        repeating: bool,
3907        hostname: String,
3908        next_delay: u32,
3909        listener: Sender<HostnameResolutionEvent>,
3910        timeout: Option<u64>,
3911    ) {
3912        let addr_list: Vec<_> = self.my_intfs.iter().collect();
3913        if let Err(e) = listener.send(HostnameResolutionEvent::SearchStarted(format!(
3914            "{} on addrs {:?}",
3915            &hostname, &addr_list
3916        ))) {
3917            debug!(
3918                "Failed to send ResolveStarted({})(repeating:{}): {}",
3919                &hostname, repeating, e
3920            );
3921            return;
3922        }
3923        let now = current_time_millis();
3924        if !repeating {
3925            self.add_hostname_resolver(hostname.to_owned(), listener.clone(), timeout);
3926            // if we already have the records in our cache, just send them
3927            self.query_cache_for_hostname(&hostname, listener.clone());
3928
3929            // RFC 6762 §5.2: delay the first query by a random jitter.
3930            let jitter =
3931                fastrand::u64(INITIAL_QUERY_DELAY_MIN_MILLIS..INITIAL_QUERY_DELAY_MAX_MILLIS);
3932            self.add_retransmission(
3933                now + jitter,
3934                Command::ResolveHostname(hostname, 1, listener, None),
3935            );
3936            return;
3937        }
3938
3939        self.send_query_vec(&[(&hostname, RRType::A), (&hostname, RRType::AAAA)]);
3940        self.increase_counter(Counter::ResolveHostname, 1);
3941
3942        let next_time = now + u64::from(next_delay) * 1000;
3943        let max_delay = 60 * 60;
3944        let delay = cmp::min(next_delay * 2, max_delay);
3945
3946        // Only add retransmission if it does not exceed the hostname resolver timeout, if any.
3947        if self
3948            .hostname_resolvers
3949            .get(&hostname)
3950            .and_then(|(_sender, timeout)| *timeout)
3951            .map(|timeout| next_time < timeout)
3952            .unwrap_or(true)
3953        {
3954            self.add_retransmission(
3955                next_time,
3956                Command::ResolveHostname(hostname, delay, listener, None),
3957            );
3958        }
3959    }
3960
3961    fn exec_command_resolve(&mut self, instance: String, try_count: u16) {
3962        let pending_query = self.query_unresolved(&instance);
3963        let max_try = 3;
3964        if pending_query && try_count < max_try {
3965            // Note that if the current try already succeeds, the next retransmission
3966            // will be no-op as the cache has been updated.
3967            let next_time = current_time_millis() + RESOLVE_WAIT_IN_MILLIS;
3968            self.add_retransmission(next_time, Command::Resolve(instance, try_count + 1));
3969        }
3970    }
3971
3972    fn exec_command_unregister(
3973        &mut self,
3974        repeating: bool,
3975        fullname: String,
3976        resp_s: Sender<UnregisterStatus>,
3977    ) {
3978        let response = match self.my_services.remove_entry(&fullname) {
3979            None => {
3980                debug!("unregister: cannot find such service {}", &fullname);
3981                UnregisterStatus::NotFound
3982            }
3983            Some((_k, info)) => {
3984                let mut timers = Vec::new();
3985
3986                for (if_index, intf) in self.my_intfs.iter() {
3987                    if let Some(sock) = self.ipv4_sock.as_ref() {
3988                        let packet = self.unregister_service(&info, intf, &sock.pktinfo);
3989                        // repeat for one time just in case some peers miss the message
3990                        if !repeating && !packet.is_empty() {
3991                            let next_time = current_time_millis() + 120;
3992                            self.retransmissions.push(ReRun {
3993                                next_time,
3994                                command: Command::UnregisterResend(packet, *if_index, true),
3995                            });
3996                            timers.push(next_time);
3997                        }
3998                    }
3999
4000                    // ipv6
4001                    if let Some(sock) = self.ipv6_sock.as_ref() {
4002                        let packet = self.unregister_service(&info, intf, &sock.pktinfo);
4003                        if !repeating && !packet.is_empty() {
4004                            let next_time = current_time_millis() + 120;
4005                            self.retransmissions.push(ReRun {
4006                                next_time,
4007                                command: Command::UnregisterResend(packet, *if_index, false),
4008                            });
4009                            timers.push(next_time);
4010                        }
4011                    }
4012                }
4013
4014                for t in timers {
4015                    self.add_timer(t);
4016                }
4017
4018                self.increase_counter(Counter::Unregister, 1);
4019                UnregisterStatus::OK
4020            }
4021        };
4022        if let Err(e) = resp_s.send(response) {
4023            debug!("unregister: failed to send response: {}", e);
4024        }
4025    }
4026
4027    fn exec_command_unregister_resend(&mut self, packet: Vec<u8>, if_index: u32, is_ipv4: bool) {
4028        let Some(intf) = self.my_intfs.get(&if_index) else {
4029            return;
4030        };
4031        let sock_opt = if is_ipv4 {
4032            &self.ipv4_sock
4033        } else {
4034            &self.ipv6_sock
4035        };
4036        let Some(sock) = sock_opt else {
4037            return;
4038        };
4039
4040        let if_addr = if is_ipv4 {
4041            match intf.next_ifaddr_v4() {
4042                Some(addr) => addr,
4043                None => return,
4044            }
4045        } else {
4046            match intf.next_ifaddr_v6() {
4047                Some(addr) => addr,
4048                None => return,
4049            }
4050        };
4051
4052        debug!("UnregisterResend from {:?}", if_addr);
4053        multicast_on_intf(
4054            &packet[..],
4055            &intf.name,
4056            intf.index,
4057            if_addr,
4058            &sock.pktinfo,
4059            self.port,
4060        );
4061
4062        self.increase_counter(Counter::UnregisterResend, 1);
4063    }
4064
4065    fn exec_command_stop_browse(&mut self, ty_domain: String) {
4066        match self.service_queriers.remove_entry(&ty_domain) {
4067            None => debug!("StopBrowse: cannot find querier for {}", &ty_domain),
4068            Some((ty, sender)) => {
4069                // Remove pending browse commands in the reruns.
4070                trace!("StopBrowse: removed queryer for {}", &ty);
4071                let mut i = 0;
4072                while i < self.retransmissions.len() {
4073                    if let Command::Browse(t, _, _, _) = &self.retransmissions[i].command {
4074                        if t == &ty {
4075                            self.retransmissions.remove(i);
4076                            trace!("StopBrowse: removed retransmission for {}", &ty);
4077                            continue;
4078                        }
4079                    }
4080                    i += 1;
4081                }
4082
4083                // Remove cache entries.
4084                self.cache.remove_service_type(&ty_domain);
4085
4086                // Notify the client.
4087                match sender.send(ServiceEvent::SearchStopped(ty_domain)) {
4088                    Ok(()) => trace!("Sent SearchStopped to the listener"),
4089                    Err(e) => debug!("Failed to send SearchStopped: {}", e),
4090                }
4091            }
4092        }
4093    }
4094
4095    fn exec_command_stop_resolve_hostname(&mut self, hostname: String) {
4096        if let Some((host, (sender, _timeout))) = self.hostname_resolvers.remove_entry(&hostname) {
4097            // Remove pending resolve commands in the reruns.
4098            trace!("StopResolve: removed queryer for {}", &host);
4099            let mut i = 0;
4100            while i < self.retransmissions.len() {
4101                if let Command::Resolve(t, _) = &self.retransmissions[i].command {
4102                    if t == &host {
4103                        self.retransmissions.remove(i);
4104                        trace!("StopResolve: removed retransmission for {}", &host);
4105                        continue;
4106                    }
4107                }
4108                i += 1;
4109            }
4110
4111            // Notify the client.
4112            match sender.send(HostnameResolutionEvent::SearchStopped(hostname)) {
4113                Ok(()) => trace!("Sent SearchStopped to the listener"),
4114                Err(e) => debug!("Failed to send SearchStopped: {}", e),
4115            }
4116        }
4117    }
4118
4119    fn exec_command_register_resend(&mut self, fullname: String, if_index: u32) -> MyResult<()> {
4120        let Some(info) = self.my_services.get_mut(&fullname) else {
4121            trace!("announce: cannot find such service {}", &fullname);
4122            return Ok(());
4123        };
4124
4125        let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) else {
4126            return Ok(());
4127        };
4128
4129        let Some(intf) = self.my_intfs.get(&if_index) else {
4130            return Ok(());
4131        };
4132
4133        let announced_v4 = if let Some(sock) = self.ipv4_sock.as_ref() {
4134            announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port)?
4135        } else {
4136            false
4137        };
4138        let announced_v6 = if let Some(sock) = self.ipv6_sock.as_ref() {
4139            announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port)?
4140        } else {
4141            false
4142        };
4143
4144        if announced_v4 || announced_v6 {
4145            let hostname = dns_registry.resolve_name(info.get_hostname());
4146            let service_name = dns_registry.resolve_name(&fullname).to_string();
4147
4148            debug!("resend: announce service {service_name} on {}", intf.name);
4149
4150            notify_monitors(
4151                &mut self.monitors,
4152                DaemonEvent::Announce(service_name, format!("{}:{}", hostname, &intf.name)),
4153            );
4154            info.set_status(if_index, ServiceStatus::Announced);
4155        } else {
4156            debug!("register-resend should not fail");
4157        }
4158
4159        self.increase_counter(Counter::RegisterResend, 1);
4160        Ok(())
4161    }
4162
4163    fn exec_command_verify(&mut self, instance: String, timeout: Duration, repeating: bool) {
4164        /*
4165        RFC 6762 section 10.4:
4166        ...
4167        When the cache receives this hint that it should reconfirm some
4168        record, it MUST issue two or more queries for the resource record in
4169        dispute.  If no response is received within ten seconds, then, even
4170        though its TTL may indicate that it is not yet due to expire, that
4171        record SHOULD be promptly flushed from the cache.
4172        */
4173        let now = current_time_millis();
4174        let expire_at = if repeating {
4175            None
4176        } else {
4177            Some(now + timeout.as_millis() as u64)
4178        };
4179
4180        // send query for the resource records.
4181        let record_vec = self.cache.service_verify_queries(&instance, expire_at);
4182
4183        if !record_vec.is_empty() {
4184            let query_vec: Vec<(&str, RRType)> = record_vec
4185                .iter()
4186                .map(|(record, rr_type)| (record.as_str(), *rr_type))
4187                .collect();
4188            self.send_query_vec(&query_vec);
4189
4190            if let Some(new_expire) = expire_at {
4191                self.add_timer(new_expire); // ensure a check for the new expire time.
4192
4193                // schedule a resend 1 second later
4194                self.add_retransmission(now + 1000, Command::Verify(instance, timeout));
4195            }
4196        }
4197    }
4198
4199    /// Refresh cached service records with active queriers
4200    fn refresh_active_services(&mut self) {
4201        let mut query_ptr_count = 0;
4202        let mut query_srv_count = 0;
4203        let mut new_timers = HashSet::new();
4204        let mut query_addr_count = 0;
4205
4206        for (ty_domain, _sender) in self.service_queriers.iter() {
4207            let refreshed_timers = self.cache.refresh_due_ptr(ty_domain);
4208            if !refreshed_timers.is_empty() {
4209                trace!("sending refresh query for PTR: {}", ty_domain);
4210                self.send_query(ty_domain, RRType::PTR);
4211                query_ptr_count += 1;
4212                new_timers.extend(refreshed_timers);
4213            }
4214
4215            let (instances, timers) = self.cache.refresh_due_srv_txt(ty_domain);
4216            for (instance, types) in instances {
4217                trace!("sending refresh query for: {}", &instance);
4218                let query_vec = types
4219                    .into_iter()
4220                    .map(|ty| (instance.as_str(), ty))
4221                    .collect::<Vec<_>>();
4222                self.send_query_vec(&query_vec);
4223                query_srv_count += 1;
4224            }
4225            new_timers.extend(timers);
4226            let (hostnames, timers) = self.cache.refresh_due_hosts(ty_domain);
4227            for hostname in hostnames.iter() {
4228                trace!("sending refresh queries for A and AAAA:  {}", hostname);
4229                self.send_query_vec(&[(hostname, RRType::A), (hostname, RRType::AAAA)]);
4230                query_addr_count += 2;
4231            }
4232            new_timers.extend(timers);
4233        }
4234
4235        for timer in new_timers {
4236            self.add_timer(timer);
4237        }
4238
4239        self.increase_counter(Counter::CacheRefreshPTR, query_ptr_count);
4240        self.increase_counter(Counter::CacheRefreshSrvTxt, query_srv_count);
4241        self.increase_counter(Counter::CacheRefreshAddr, query_addr_count);
4242    }
4243}
4244
4245/// Adds one or more answers of a service for incoming msg and RR entry name.
4246fn add_answer_of_service(
4247    out: &mut DnsOutgoing,
4248    msg: &DnsIncoming,
4249    entry_name: &str,
4250    service: &ServiceInfo,
4251    qtype: RRType,
4252    intf_addrs: Vec<IpAddr>,
4253) {
4254    if qtype == RRType::SRV || qtype == RRType::ANY {
4255        out.add_answer(
4256            msg,
4257            DnsSrv::new(
4258                entry_name,
4259                CLASS_IN | CLASS_CACHE_FLUSH,
4260                service.get_host_ttl(),
4261                service.get_priority(),
4262                service.get_weight(),
4263                service.get_port(),
4264                service.get_hostname().to_string(),
4265            ),
4266        );
4267    }
4268
4269    if qtype == RRType::TXT || qtype == RRType::ANY {
4270        out.add_answer(
4271            msg,
4272            DnsTxt::new(
4273                entry_name,
4274                CLASS_IN | CLASS_CACHE_FLUSH,
4275                service.get_other_ttl(),
4276                service.generate_txt(),
4277            ),
4278        );
4279    }
4280
4281    if qtype == RRType::SRV {
4282        for address in intf_addrs {
4283            out.add_additional_answer(DnsAddress::new(
4284                service.get_hostname(),
4285                ip_address_rr_type(&address),
4286                CLASS_IN | CLASS_CACHE_FLUSH,
4287                service.get_host_ttl(),
4288                address,
4289                InterfaceId::default(),
4290            ));
4291        }
4292    }
4293}
4294
4295/// All possible events sent to the client from the daemon
4296/// regarding service discovery.
4297#[derive(Clone, Debug)]
4298#[non_exhaustive]
4299pub enum ServiceEvent {
4300    /// Started searching for a service type.
4301    SearchStarted(String),
4302
4303    /// Found a specific (service_type, fullname).
4304    ServiceFound(String, String),
4305
4306    /// Resolved a service instance in a ResolvedService struct.
4307    ServiceResolved(Box<ResolvedService>),
4308
4309    /// A service instance (service_type, fullname) was removed.
4310    ServiceRemoved(String, String),
4311
4312    /// Stopped searching for a service type.
4313    SearchStopped(String),
4314}
4315
4316/// All possible events sent to the client from the daemon
4317/// regarding host resolution.
4318#[derive(Clone, Debug)]
4319#[non_exhaustive]
4320pub enum HostnameResolutionEvent {
4321    /// Started searching for the ip address of a hostname.
4322    SearchStarted(String),
4323    /// One or more addresses for a hostname has been found.
4324    AddressesFound(String, HashSet<ScopedIp>),
4325    /// One or more addresses for a hostname has been removed.
4326    AddressesRemoved(String, HashSet<ScopedIp>),
4327    /// The search for the ip address of a hostname has timed out.
4328    SearchTimeout(String),
4329    /// Stopped searching for the ip address of a hostname.
4330    SearchStopped(String),
4331}
4332
4333/// Some notable events from the daemon besides [`ServiceEvent`].
4334/// These events are expected to happen infrequently.
4335#[derive(Clone, Debug)]
4336#[non_exhaustive]
4337pub enum DaemonEvent {
4338    /// Daemon unsolicitly announced a service from an interface.
4339    Announce(String, String),
4340
4341    /// Daemon encountered an error.
4342    Error(Error),
4343
4344    /// Daemon detected a new IP address from the host.
4345    IpAdd(IpAddr),
4346
4347    /// Daemon detected a IP address removed from the host.
4348    IpDel(IpAddr),
4349
4350    /// Daemon resolved a name conflict by changing one of its names.
4351    /// see [DnsNameChange] for more details.
4352    NameChange(DnsNameChange),
4353
4354    /// Send out a multicast response via an interface.
4355    Respond(String),
4356}
4357
4358/// Represents a name change due to a name conflict resolution.
4359/// See [RFC 6762 section 9](https://datatracker.ietf.org/doc/html/rfc6762#section-9)
4360#[derive(Clone, Debug)]
4361pub struct DnsNameChange {
4362    /// The original name set in `ServiceInfo` by the user.
4363    pub original: String,
4364
4365    /// A new name is created by appending a suffix after the original name.
4366    ///
4367    /// - for a service instance name, the suffix is `(N)`, where N starts at 2.
4368    /// - for a host name, the suffix is `-N`, where N starts at 2.
4369    ///
4370    /// For example:
4371    ///
4372    /// - Service name `foo._service-type._udp` becomes `foo (2)._service-type._udp`
4373    /// - Host name `foo.local.` becomes `foo-2.local.`
4374    pub new_name: String,
4375
4376    /// The resource record type
4377    pub rr_type: RRType,
4378
4379    /// The interface where the name conflict and its change happened.
4380    pub intf_name: String,
4381}
4382
4383/// Commands supported by the daemon
4384#[derive(Debug)]
4385enum Command {
4386    /// Browsing for a service type (ty_domain, next_time_delay_in_seconds, channel::sender)
4387    Browse(String, u32, bool, Sender<ServiceEvent>),
4388
4389    /// Resolve a hostname to IP addresses.
4390    ResolveHostname(String, u32, Sender<HostnameResolutionEvent>, Option<u64>), // (hostname, next_time_delay_in_seconds, sender, timeout_in_milliseconds)
4391
4392    /// Register a service
4393    Register(Box<ServiceInfo>),
4394
4395    /// Unregister a service
4396    Unregister(String, Sender<UnregisterStatus>), // (fullname)
4397
4398    /// Announce again a service to local network
4399    RegisterResend(String, u32), // (fullname)
4400
4401    /// Resend unregister packet.
4402    UnregisterResend(Vec<u8>, u32, bool), // (packet content, if_index, is_ipv4)
4403
4404    /// Stop browsing a service type
4405    StopBrowse(String), // (ty_domain)
4406
4407    /// Stop resolving a hostname
4408    StopResolveHostname(String), // (hostname)
4409
4410    /// Send query to resolve a service instance.
4411    /// This is used when a PTR record exists but SRV & TXT records are missing.
4412    Resolve(String, u16), // (service_instance_fullname, try_count)
4413
4414    /// Read the current values of the counters
4415    GetMetrics(Sender<Metrics>),
4416
4417    /// Get the current status of the daemon.
4418    GetStatus(Sender<DaemonStatus>),
4419
4420    /// Monitor noticeable events in the daemon.
4421    Monitor(Sender<DaemonEvent>),
4422
4423    SetOption(DaemonOption),
4424
4425    GetOption(Sender<DaemonOptionVal>),
4426
4427    /// Proactively confirm a DNS resource record.
4428    ///
4429    /// The intention is to check if a service name or IP address still valid
4430    /// before its TTL expires.
4431    Verify(String, Duration),
4432
4433    /// Invalidate some interface addresses.
4434    InvalidIntfAddrs(HashSet<Interface>),
4435
4436    Exit(Sender<DaemonStatus>),
4437}
4438
4439impl fmt::Display for Command {
4440    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4441        match self {
4442            Self::Browse(_, _, _, _) => write!(f, "Command Browse"),
4443            Self::ResolveHostname(_, _, _, _) => write!(f, "Command ResolveHostname"),
4444            Self::Exit(_) => write!(f, "Command Exit"),
4445            Self::GetStatus(_) => write!(f, "Command GetStatus"),
4446            Self::GetMetrics(_) => write!(f, "Command GetMetrics"),
4447            Self::Monitor(_) => write!(f, "Command Monitor"),
4448            Self::Register(_) => write!(f, "Command Register"),
4449            Self::RegisterResend(_, _) => write!(f, "Command RegisterResend"),
4450            Self::SetOption(_) => write!(f, "Command SetOption"),
4451            Self::GetOption(_) => write!(f, "Command GetOption"),
4452            Self::StopBrowse(_) => write!(f, "Command StopBrowse"),
4453            Self::StopResolveHostname(_) => write!(f, "Command StopResolveHostname"),
4454            Self::Unregister(_, _) => write!(f, "Command Unregister"),
4455            Self::UnregisterResend(_, _, _) => write!(f, "Command UnregisterResend"),
4456            Self::Resolve(_, _) => write!(f, "Command Resolve"),
4457            Self::Verify(_, _) => write!(f, "Command VerifyResource"),
4458            Self::InvalidIntfAddrs(_) => write!(f, "Command InvalidIntfAddrs"),
4459        }
4460    }
4461}
4462
4463struct DaemonOptionVal {
4464    _service_name_len_max: u8,
4465    ip_check_interval: u64,
4466}
4467
4468#[derive(Debug)]
4469enum DaemonOption {
4470    ServiceNameLenMax(u8),
4471    IpCheckInterval(u64),
4472    MaxPacketSize(Vec<IfKind>, usize),
4473    EnableInterface(Vec<IfKind>),
4474    DisableInterface(Vec<IfKind>),
4475    MulticastLoopV4(bool),
4476    MulticastLoopV6(bool),
4477    AcceptUnsolicited(bool),
4478    IncludeAppleP2P(bool),
4479    #[cfg(test)]
4480    TestDownInterface(String),
4481    #[cfg(test)]
4482    TestUpInterface(String),
4483}
4484
4485/// The length of Service Domain name supported in this lib.
4486const DOMAIN_LEN: usize = "._tcp.local.".len();
4487
4488/// Validate the length of "service_name" in a "_<service_name>.<domain_name>." string.
4489fn check_service_name_length(ty_domain: &str, limit: u8) -> Result<()> {
4490    if ty_domain.len() <= DOMAIN_LEN + 1 {
4491        // service name cannot be empty or only '_'.
4492        return Err(e_fmt!("Service type name cannot be empty: {}", ty_domain));
4493    }
4494
4495    let service_name_len = ty_domain.len() - DOMAIN_LEN - 1; // exclude the leading `_`
4496    if service_name_len > limit as usize {
4497        return Err(e_fmt!("Service name length must be <= {} bytes", limit));
4498    }
4499    Ok(())
4500}
4501
4502/// Checks if `name` ends with a valid domain: '._tcp.local.' or '._udp.local.'
4503fn check_domain_suffix(name: &str) -> Result<()> {
4504    if !(name.ends_with("._tcp.local.") || name.ends_with("._udp.local.")) {
4505        return Err(e_fmt!(
4506            "mDNS service {} must end with '._tcp.local.' or '._udp.local.'",
4507            name
4508        ));
4509    }
4510
4511    Ok(())
4512}
4513
4514/// Validate the service name in a fully qualified name.
4515///
4516/// A Full Name = <Instance>.<Service>.<Domain>
4517/// The only `<Domain>` supported are "._tcp.local." and "._udp.local.".
4518///
4519/// Note: this function does not check for the length of the service name.
4520/// Instead, `register_service` method will check the length.
4521fn check_service_name(fullname: &str) -> Result<()> {
4522    check_domain_suffix(fullname)?;
4523
4524    let remaining: Vec<&str> = fullname[..fullname.len() - DOMAIN_LEN].split('.').collect();
4525    let name = remaining.last().ok_or_else(|| e_fmt!("No service name"))?;
4526
4527    if &name[0..1] != "_" {
4528        return Err(e_fmt!("Service name must start with '_'"));
4529    }
4530
4531    let name = &name[1..];
4532
4533    if name.contains("--") {
4534        return Err(e_fmt!("Service name must not contain '--'"));
4535    }
4536
4537    if name.starts_with('-') || name.ends_with('-') {
4538        return Err(e_fmt!("Service name (%s) may not start or end with '-'"));
4539    }
4540
4541    let ascii_count = name.chars().filter(|c| c.is_ascii_alphabetic()).count();
4542    if ascii_count < 1 {
4543        return Err(e_fmt!(
4544            "Service name must contain at least one letter (eg: 'A-Za-z')"
4545        ));
4546    }
4547
4548    Ok(())
4549}
4550
4551/// Validate a hostname.
4552fn check_hostname(hostname: &str) -> Result<()> {
4553    if !hostname.ends_with(".local.") {
4554        return Err(e_fmt!("Hostname must end with '.local.': {hostname}"));
4555    }
4556
4557    if hostname == ".local." {
4558        return Err(e_fmt!(
4559            "The part of the hostname before '.local.' cannot be empty"
4560        ));
4561    }
4562
4563    if hostname.len() > 255 {
4564        return Err(e_fmt!("Hostname length must be <= 255 bytes"));
4565    }
4566
4567    Ok(())
4568}
4569
4570fn call_service_listener(
4571    listeners_map: &HashMap<String, Sender<ServiceEvent>>,
4572    ty_domain: &str,
4573    event: ServiceEvent,
4574) {
4575    if let Some(listener) = listeners_map.get(ty_domain) {
4576        match listener.send(event) {
4577            Ok(()) => trace!("Sent event to listener successfully"),
4578            Err(e) => debug!("Failed to send event: {}", e),
4579        }
4580    }
4581}
4582
4583fn call_hostname_resolution_listener(
4584    listeners_map: &HashMap<String, (Sender<HostnameResolutionEvent>, Option<u64>)>,
4585    hostname: &str,
4586    event: HostnameResolutionEvent,
4587) {
4588    let hostname_lower = hostname.to_lowercase();
4589    if let Some(listener) = listeners_map.get(&hostname_lower).map(|(l, _)| l) {
4590        match listener.send(event) {
4591            Ok(()) => trace!("Sent event to listener successfully"),
4592            Err(e) => debug!("Failed to send event: {}", e),
4593        }
4594    }
4595}
4596
4597/// Returns valid network interfaces in the host system.
4598/// Operational down interfaces are excluded.
4599/// Loopback interfaces are excluded if `with_loopback` is false.
4600fn my_ip_interfaces(with_loopback: bool) -> Vec<Interface> {
4601    my_ip_interfaces_inner(with_loopback, false)
4602}
4603
4604fn my_ip_interfaces_inner(with_loopback: bool, with_apple_p2p: bool) -> Vec<Interface> {
4605    if_addrs::get_if_addrs()
4606        .unwrap_or_default()
4607        .into_iter()
4608        .filter(|i| {
4609            i.is_oper_up()
4610                && !i.is_p2p()
4611                && (!i.is_loopback() || with_loopback)
4612                && (with_apple_p2p || !is_apple_p2p_by_name(&i.name))
4613        })
4614        .collect()
4615}
4616
4617/// Checks if the interface name indicates it's an Apple peer-to-peer interface,
4618/// which should be ignored by default.
4619fn is_apple_p2p_by_name(name: &str) -> bool {
4620    let p2p_prefixes = ["awdl", "llw"];
4621    p2p_prefixes.iter().any(|prefix| name.starts_with(prefix))
4622}
4623
4624/// How to encode and where to send outgoing messages on one interface.
4625#[derive(Clone, Copy, Debug)]
4626struct SendConfig {
4627    /// The mDNS port to send to.
4628    port: u16,
4629
4630    /// Max byte size of a generated packet.
4631    /// See [`ServiceDaemon::set_max_packet_size`].
4632    max_packet_size: usize,
4633
4634    /// Whether the packets go out over IPv4, which decides their absolute
4635    /// ceiling: see [`max_pkt_absolute`].
4636    is_ipv4: bool,
4637}
4638
4639/// Send an outgoing mDNS query or response, and returns the packet bytes.
4640/// Returns empty vec if no valid interface address is found.
4641fn send_dns_outgoing(
4642    out: &DnsOutgoing,
4643    my_intf: &MyIntf,
4644    sock: &PktInfoUdpSocket,
4645    port: u16,
4646    source: Option<&IfAddr>,
4647    unicast_dest: Option<SocketAddr>,
4648) -> MyResult<Vec<Vec<u8>>> {
4649    let if_name = &my_intf.name;
4650
4651    let if_addr = match source {
4652        Some(addr) => addr,
4653        None => {
4654            if sock.domain() == Domain::IPV4 {
4655                match my_intf.next_ifaddr_v4() {
4656                    Some(addr) => addr,
4657                    None => return Ok(vec![]),
4658                }
4659            } else {
4660                match my_intf.next_ifaddr_v6() {
4661                    Some(addr) => addr,
4662                    None => return Ok(vec![]),
4663                }
4664            }
4665        }
4666    };
4667
4668    // The limits are per address family, so read them off the address we send from.
4669    let is_ipv4 = if_addr.ip().is_ipv4();
4670    let config = SendConfig {
4671        port,
4672        max_packet_size: my_intf.max_packet_size(is_ipv4),
4673        is_ipv4,
4674    };
4675
4676    send_dns_outgoing_impl(
4677        out,
4678        if_name,
4679        my_intf.index,
4680        if_addr,
4681        sock,
4682        config,
4683        unicast_dest,
4684    )
4685}
4686
4687/// Send an outgoing mDNS query or response, and returns the packet bytes.
4688fn send_dns_outgoing_impl(
4689    out: &DnsOutgoing,
4690    if_name: &str,
4691    if_index: u32,
4692    if_addr: &IfAddr,
4693    sock: &PktInfoUdpSocket,
4694    config: SendConfig,
4695    unicast_dest: Option<SocketAddr>,
4696) -> MyResult<Vec<Vec<u8>>> {
4697    let qtype = if out.is_query() {
4698        "query"
4699    } else {
4700        if out.answers_count() == 0 && out.additionals().is_empty() {
4701            return Ok(vec![]); // no need to send empty response
4702        }
4703        "response"
4704    };
4705    trace!(
4706        "send {}: {} questions {} answers {} authorities {} additional",
4707        qtype,
4708        out.questions().len(),
4709        out.answers_count(),
4710        out.authorities().len(),
4711        out.additionals().len()
4712    );
4713
4714    match if_addr.ip() {
4715        IpAddr::V4(ipv4) => {
4716            if let Err(e) = sock.set_multicast_if_v4(&ipv4) {
4717                debug!(
4718                    "send_dns_outgoing: failed to set multicast interface for IPv4 {}: {}",
4719                    ipv4, e
4720                );
4721                // cannot send without a valid interface
4722                if e.kind() == std::io::ErrorKind::AddrNotAvailable {
4723                    let intf_addr = Interface {
4724                        name: if_name.to_string(),
4725                        addr: if_addr.clone(),
4726                        index: Some(if_index),
4727                        oper_status: if_addrs::IfOperStatus::Down,
4728                        is_p2p: false,
4729                        #[cfg(windows)]
4730                        adapter_name: String::new(),
4731                    };
4732                    return Err(InternalError::IntfAddrInvalid(intf_addr));
4733                }
4734                return Ok(vec![]); // non-fatal other failure
4735            }
4736        }
4737        IpAddr::V6(ipv6) => {
4738            if let Err(e) = sock.set_multicast_if_v6(if_index) {
4739                debug!(
4740                    "send_dns_outgoing: failed to set multicast interface for IPv6 {}: {}",
4741                    ipv6, e
4742                );
4743                // cannot send without a valid interface
4744                if e.kind() == std::io::ErrorKind::AddrNotAvailable {
4745                    let intf_addr = Interface {
4746                        name: if_name.to_string(),
4747                        addr: if_addr.clone(),
4748                        index: Some(if_index),
4749                        oper_status: if_addrs::IfOperStatus::Down,
4750                        is_p2p: false,
4751                        #[cfg(windows)]
4752                        adapter_name: String::new(),
4753                    };
4754                    return Err(InternalError::IntfAddrInvalid(intf_addr));
4755                }
4756                return Ok(vec![]); // non-fatal other failure
4757            }
4758        }
4759    }
4760
4761    let packet_list = out.to_data_on_wire(config.max_packet_size, config.is_ipv4);
4762    for packet in packet_list.iter() {
4763        match unicast_dest {
4764            Some(dest) => unicast_on_intf(packet, if_name, dest, sock),
4765            None => multicast_on_intf(packet, if_name, if_index, if_addr, sock, config.port),
4766        }
4767    }
4768    Ok(packet_list)
4769}
4770
4771/// Sends a unicast packet directly to `dest` (used for RFC 6762 §6.7
4772/// legacy unicast responses).
4773fn unicast_on_intf(packet: &[u8], if_name: &str, dest: SocketAddr, socket: &PktInfoUdpSocket) {
4774    let max_size = max_pkt_absolute(dest.is_ipv4());
4775    if packet.len() > max_size {
4776        debug!("Drop over-sized packet ({} > {max_size})", packet.len());
4777        return;
4778    }
4779
4780    let sock_addr = dest.into();
4781    match socket.send_to(packet, &sock_addr) {
4782        Ok(sz) => trace!(
4783            "sent unicast {} bytes on interface {} to {}",
4784            sz,
4785            if_name,
4786            dest
4787        ),
4788        Err(e) => trace!(
4789            "Failed to send unicast to {} via {:?}: {}",
4790            dest,
4791            &if_name,
4792            e
4793        ),
4794    }
4795}
4796
4797/// Sends a multicast packet, and returns the packet bytes.
4798fn multicast_on_intf(
4799    packet: &[u8],
4800    if_name: &str,
4801    if_index: u32,
4802    if_addr: &IfAddr,
4803    socket: &PktInfoUdpSocket,
4804    port: u16,
4805) {
4806    let max_size = max_pkt_absolute(if_addr.ip().is_ipv4());
4807    if packet.len() > max_size {
4808        debug!("Drop over-sized packet ({} > {max_size})", packet.len());
4809        return;
4810    }
4811
4812    let addr: SocketAddr = match if_addr {
4813        if_addrs::IfAddr::V4(_) => SocketAddrV4::new(GROUP_ADDR_V4, port).into(),
4814        if_addrs::IfAddr::V6(_) => {
4815            let mut sock = SocketAddrV6::new(GROUP_ADDR_V6, port, 0, 0);
4816            sock.set_scope_id(if_index); // Choose iface for multicast
4817            sock.into()
4818        }
4819    };
4820
4821    // Sends out `packet` to `addr` on the socket.
4822    let sock_addr = addr.into();
4823    match socket.send_to(packet, &sock_addr) {
4824        Ok(sz) => trace!(
4825            "sent out {} bytes on interface {} (idx {}) addr {}",
4826            sz,
4827            if_name,
4828            if_index,
4829            if_addr.ip()
4830        ),
4831        Err(e) => trace!("Failed to send to {} via {:?}: {}", addr, &if_name, e),
4832    }
4833}
4834
4835/// Returns true if `name` is a valid instance name of format:
4836/// <instance>.<service_type>.<_udp|_tcp>.local.
4837/// Note: <instance> could contain '.' as well.
4838fn valid_instance_name(name: &str) -> bool {
4839    name.split('.').count() >= 5
4840}
4841
4842fn notify_monitors(monitors: &mut Vec<Sender<DaemonEvent>>, event: DaemonEvent) {
4843    monitors.retain(|sender| {
4844        if let Err(e) = sender.try_send(event.clone()) {
4845            debug!("notify_monitors: try_send: {}", &e);
4846            if matches!(e, TrySendError::Disconnected(_)) {
4847                return false; // This monitor is dropped.
4848            }
4849        }
4850        true
4851    });
4852}
4853
4854/// Check if all unique records passed "probing", and if yes, create a packet
4855/// to announce the service.
4856fn prepare_announce(
4857    info: &ServiceInfo,
4858    intf: &MyIntf,
4859    dns_registry: &mut DnsRegistry,
4860    is_ipv4: bool,
4861) -> Option<DnsOutgoing> {
4862    let intf_addrs = if is_ipv4 {
4863        info.get_addrs_on_my_intf_v4(intf)
4864    } else {
4865        info.get_addrs_on_my_intf_v6(intf)
4866    };
4867
4868    if intf_addrs.is_empty() {
4869        debug!(
4870            "prepare_announce (ipv4: {is_ipv4}): no valid addrs on interface {}",
4871            &intf.name
4872        );
4873        return None;
4874    }
4875
4876    // check if we changed our name due to conflicts.
4877    let service_fullname = dns_registry.resolve_name(info.get_fullname());
4878
4879    debug!(
4880        "prepare to announce service {service_fullname} on {:?}",
4881        &intf_addrs
4882    );
4883
4884    let mut probing_count = 0;
4885    let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
4886    let create_time = current_time_millis() + fastrand::u64(0..250);
4887
4888    out.add_answer_at_time(
4889        DnsPointer::new(
4890            info.get_type(),
4891            RRType::PTR,
4892            CLASS_IN,
4893            info.get_other_ttl(),
4894            service_fullname.to_string(),
4895        ),
4896        0,
4897    );
4898
4899    if let Some(sub) = info.get_subtype() {
4900        trace!("Adding subdomain {}", sub);
4901        out.add_answer_at_time(
4902            DnsPointer::new(
4903                sub,
4904                RRType::PTR,
4905                CLASS_IN,
4906                info.get_other_ttl(),
4907                service_fullname.to_string(),
4908            ),
4909            0,
4910        );
4911    }
4912
4913    // SRV records.
4914    let hostname = dns_registry.resolve_name(info.get_hostname()).to_string();
4915
4916    let mut srv = DnsSrv::new(
4917        info.get_fullname(),
4918        CLASS_IN | CLASS_CACHE_FLUSH,
4919        info.get_host_ttl(),
4920        info.get_priority(),
4921        info.get_weight(),
4922        info.get_port(),
4923        hostname,
4924    );
4925
4926    if let Some(new_name) = dns_registry.name_changes.get(info.get_fullname()) {
4927        srv.get_record_mut().set_new_name(new_name.to_string());
4928    }
4929
4930    if !info.requires_probe()
4931        || dns_registry.is_probing_done(&srv, info.get_fullname(), create_time)
4932    {
4933        out.add_answer_at_time(srv, 0);
4934    } else {
4935        probing_count += 1;
4936    }
4937
4938    // TXT records.
4939
4940    let mut txt = DnsTxt::new(
4941        info.get_fullname(),
4942        CLASS_IN | CLASS_CACHE_FLUSH,
4943        info.get_other_ttl(),
4944        info.generate_txt(),
4945    );
4946
4947    if let Some(new_name) = dns_registry.name_changes.get(info.get_fullname()) {
4948        txt.get_record_mut().set_new_name(new_name.to_string());
4949    }
4950
4951    if !info.requires_probe()
4952        || dns_registry.is_probing_done(&txt, info.get_fullname(), create_time)
4953    {
4954        out.add_answer_at_time(txt, 0);
4955    } else {
4956        probing_count += 1;
4957    }
4958
4959    // Address records. (A and AAAA)
4960
4961    let hostname = info.get_hostname();
4962    for address in intf_addrs {
4963        let mut dns_addr = DnsAddress::new(
4964            hostname,
4965            ip_address_rr_type(&address),
4966            CLASS_IN | CLASS_CACHE_FLUSH,
4967            info.get_host_ttl(),
4968            address,
4969            intf.into(),
4970        );
4971
4972        if let Some(new_name) = dns_registry.name_changes.get(hostname) {
4973            dns_addr.get_record_mut().set_new_name(new_name.to_string());
4974        }
4975
4976        if !info.requires_probe()
4977            || dns_registry.is_probing_done(&dns_addr, info.get_fullname(), create_time)
4978        {
4979            out.add_answer_at_time(dns_addr, 0);
4980        } else {
4981            probing_count += 1;
4982        }
4983    }
4984
4985    if probing_count > 0 {
4986        return None;
4987    }
4988
4989    Some(out)
4990}
4991
4992/// Send an unsolicited response for owned service via `intf` and `sock`.
4993/// Returns true if sent out successfully for IPv4 or IPv6.
4994fn announce_service_on_intf(
4995    dns_registry: &mut DnsRegistry,
4996    info: &ServiceInfo,
4997    intf: &MyIntf,
4998    sock: &PktInfoUdpSocket,
4999    port: u16,
5000) -> MyResult<bool> {
5001    let is_ipv4 = sock.domain() == Domain::IPV4;
5002    if let Some(mut out) = prepare_announce(info, intf, dns_registry, is_ipv4) {
5003        // RFC 6762 §6: a record MUST NOT be multicast on an interface more than
5004        // once per second. Announcements are unsolicited multicast responses.
5005        dns_registry.apply_multicast_rate_limit(&mut out, current_time_millis(), is_ipv4);
5006        if out.answers_count() > 0 {
5007            let _ = send_dns_outgoing(&out, intf, sock, port, None, None)?;
5008        }
5009        return Ok(true);
5010    }
5011
5012    Ok(false)
5013}
5014
5015/// Returns a new name based on the `original` to avoid conflicts.
5016/// If the name already contains a number in parentheses, increments that number.
5017///
5018/// Examples:
5019/// - `foo.local.` becomes `foo (2).local.`
5020/// - `foo (2).local.` becomes `foo (3).local.`
5021/// - `foo (9)` becomes `foo (10)`
5022fn name_change(original: &str) -> String {
5023    let mut parts: Vec<_> = original.split('.').collect();
5024    let Some(first_part) = parts.get_mut(0) else {
5025        return format!("{original} (2)");
5026    };
5027
5028    let mut new_name = format!("{first_part} (2)");
5029
5030    // check if there is already has `(<num>)` suffix.
5031    if let Some(paren_pos) = first_part.rfind(" (") {
5032        // Check if there's a closing parenthesis
5033        if let Some(end_paren) = first_part[paren_pos..].find(')') {
5034            let absolute_end_pos = paren_pos + end_paren;
5035            // Only process if the closing parenthesis is the last character
5036            if absolute_end_pos == first_part.len() - 1 {
5037                let num_start = paren_pos + 2; // Skip " ("
5038                                               // Try to parse the number between parentheses
5039                if let Ok(number) = first_part[num_start..absolute_end_pos].parse::<u32>() {
5040                    let base_name = &first_part[..paren_pos];
5041                    new_name = format!("{} ({})", base_name, number + 1)
5042                }
5043            }
5044        }
5045    }
5046
5047    *first_part = &new_name;
5048    parts.join(".")
5049}
5050
5051/// Returns a new name based on the `original` to avoid conflicts.
5052/// If the name already contains a hyphenated number, increments that number.
5053///
5054/// Examples:
5055/// - `foo.local.` becomes `foo-2.local.`
5056/// - `foo-2.local.` becomes `foo-3.local.`
5057/// - `foo` becomes `foo-2`
5058fn hostname_change(original: &str) -> String {
5059    let mut parts: Vec<_> = original.split('.').collect();
5060    let Some(first_part) = parts.get_mut(0) else {
5061        return format!("{original}-2");
5062    };
5063
5064    let mut new_name = format!("{first_part}-2");
5065
5066    // check if there is already a `-<num>` suffix
5067    if let Some(hyphen_pos) = first_part.rfind('-') {
5068        // Try to parse everything after the hyphen as a number
5069        if let Ok(number) = first_part[hyphen_pos + 1..].parse::<u32>() {
5070            let base_name = &first_part[..hyphen_pos];
5071            new_name = format!("{}-{}", base_name, number + 1);
5072        }
5073    }
5074
5075    *first_part = &new_name;
5076    parts.join(".")
5077}
5078
5079/// Check probes in a registry and returns: a probing packet to send out, and a list of probe names
5080/// that are finished.
5081fn check_probing(
5082    dns_registry: &mut DnsRegistry,
5083    timers: &mut BinaryHeap<Reverse<u64>>,
5084    now: u64,
5085) -> (DnsOutgoing, Vec<String>) {
5086    let mut expired_probes = Vec::new();
5087    let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
5088
5089    for (name, probe) in dns_registry.probing.iter_mut() {
5090        if now >= probe.next_send {
5091            if probe.expired(now) {
5092                // move the record to active
5093                expired_probes.push(name.clone());
5094            } else {
5095                out.add_question(name, RRType::ANY);
5096
5097                /*
5098                RFC 6762 section 8.2: https://datatracker.ietf.org/doc/html/rfc6762#section-8.2
5099                ...
5100                for tiebreaking to work correctly in all
5101                cases, the Authority Section must contain *all* the records and
5102                proposed rdata being probed for uniqueness.
5103                    */
5104                for record in probe.records.iter() {
5105                    out.add_authority(record.clone());
5106                }
5107
5108                probe.update_next_send(now);
5109
5110                // add timer
5111                timers.push(Reverse(probe.next_send));
5112            }
5113        }
5114    }
5115
5116    (out, expired_probes)
5117}
5118
5119/// Process expired probes on an interface and return a list of services
5120/// that are waiting for the probe to finish.
5121///
5122/// `DnsNameChange` events are sent to the monitors.
5123fn handle_expired_probes(
5124    expired_probes: Vec<String>,
5125    intf_name: &str,
5126    dns_registry: &mut DnsRegistry,
5127    monitors: &mut Vec<Sender<DaemonEvent>>,
5128) -> HashSet<String> {
5129    let mut waiting_services = HashSet::new();
5130
5131    for name in expired_probes {
5132        let Some(probe) = dns_registry.probing.remove(&name) else {
5133            continue;
5134        };
5135
5136        // send notifications about name changes
5137        for record in probe.records.iter() {
5138            if let Some(new_name) = record.get_record().get_new_name() {
5139                dns_registry
5140                    .name_changes
5141                    .insert(name.clone(), new_name.to_string());
5142
5143                let event = DnsNameChange {
5144                    original: record.get_record().get_original_name().to_string(),
5145                    new_name: new_name.to_string(),
5146                    rr_type: record.get_type(),
5147                    intf_name: intf_name.to_string(),
5148                };
5149                debug!("Name change event: {:?}", &event);
5150                notify_monitors(monitors, DaemonEvent::NameChange(event));
5151            }
5152        }
5153
5154        // move RR from probe to active.
5155        debug!(
5156            "probe of '{name}' finished: move {} records to active. ({} waiting services)",
5157            probe.records.len(),
5158            probe.waiting_services.len(),
5159        );
5160
5161        // Move records to active and plan to wake up services if records are not empty.
5162        if !probe.records.is_empty() {
5163            match dns_registry.active.get_mut(&name) {
5164                Some(records) => {
5165                    records.extend(probe.records);
5166                }
5167                None => {
5168                    dns_registry.active.insert(name, probe.records);
5169                }
5170            }
5171
5172            waiting_services.extend(probe.waiting_services);
5173        }
5174    }
5175
5176    waiting_services
5177}
5178
5179/// Returns the max packet size to use on the interface `if_index` for the given
5180/// address family, i.e. the size of the last selection matching it, or
5181/// [`MAX_PKT_DEFAULT`] if none does.
5182///
5183/// A selection matches an address, so it applies as soon as any address of the
5184/// interface in that family matches. That keeps the two families independent:
5185/// e.g. [`IfKind::IPv4`] leaves the IPv6 side of the interface alone.
5186fn resolve_max_packet_size(
5187    selections: &[MaxPacketSizeSelection],
5188    interfaces: &[Interface],
5189    if_index: u32,
5190    is_ipv4: bool,
5191) -> usize {
5192    let mut size = MAX_PKT_DEFAULT;
5193
5194    for selection in selections {
5195        let matched = interfaces.iter().any(|intf| {
5196            intf.index.unwrap_or(0) == if_index
5197                && intf.ip().is_ipv4() == is_ipv4
5198                && selection.if_kind.matches(intf)
5199        });
5200        if matched {
5201            size = selection.max_packet_size;
5202        }
5203    }
5204
5205    size
5206}
5207
5208/// Resolves `IfKind::Addr(ip)` to `IndexV4(if_index)` or `IndexV6(if_index)`.
5209fn resolve_addr_to_index(if_kind: IfKind, interfaces: &[Interface]) -> IfKind {
5210    if let IfKind::Addr(addr) = &if_kind {
5211        if let Some(intf) = interfaces.iter().find(|intf| &intf.ip() == addr) {
5212            let if_index = intf.index.unwrap_or(0);
5213            return if addr.is_ipv4() {
5214                IfKind::IndexV4(if_index)
5215            } else {
5216                IfKind::IndexV6(if_index)
5217            };
5218        }
5219    }
5220    if_kind
5221}
5222
5223#[cfg(test)]
5224mod tests {
5225    use super::{
5226        _new_socket_bind, check_domain_suffix, check_service_name_length, hostname_change,
5227        my_ip_interfaces, name_change, resolve_max_packet_size, send_dns_outgoing_impl,
5228        valid_instance_name, valid_ip_on_intf, DaemonEvent, HostnameResolutionEvent, IfKind,
5229        MaxPacketSizeSelection, MyIntf, SendConfig, ServiceDaemon, ServiceEvent, ServiceInfo,
5230        GROUP_ADDR_V4, INITIAL_QUERY_DELAY_MAX_MILLIS, INITIAL_QUERY_DELAY_MIN_MILLIS,
5231        MAX_PKT_ABSOLUTE_IPV6, MAX_PKT_DEFAULT, MDNS_PORT, MIN_MAX_PACKET_SIZE,
5232        SHARED_RESPONSE_DELAY_MAX_MILLIS, SHARED_RESPONSE_DELAY_MIN_MILLIS,
5233    };
5234    use crate::{
5235        dns_parser::{
5236            DnsEntryExt, DnsIncoming, DnsOutgoing, DnsPointer, InterfaceId, RRType, ScopedIp,
5237            CLASS_IN, FLAGS_AA, FLAGS_QR_QUERY, FLAGS_QR_RESPONSE,
5238        },
5239        service_daemon::{add_answer_of_service, check_hostname},
5240    };
5241    use if_addrs::{IfAddr, Ifv4Addr, Ifv6Addr, Interface};
5242    use std::{
5243        collections::HashSet,
5244        net::{IpAddr, Ipv4Addr, Ipv6Addr, UdpSocket},
5245        time::{Duration, Instant, SystemTime},
5246    };
5247    use test_log::test;
5248
5249    /// Builds an interface address for the max packet size tests below.
5250    fn test_interface(name: &str, index: u32, addr: IfAddr) -> Interface {
5251        Interface {
5252            name: name.to_string(),
5253            addr,
5254            index: Some(index),
5255            oper_status: if_addrs::IfOperStatus::Up,
5256            is_p2p: false,
5257            #[cfg(windows)]
5258            adapter_name: String::new(),
5259        }
5260    }
5261
5262    fn test_ifaddr_v4(ip: Ipv4Addr) -> IfAddr {
5263        IfAddr::V4(Ifv4Addr {
5264            ip,
5265            netmask: Ipv4Addr::new(255, 255, 255, 0),
5266            broadcast: None,
5267            prefixlen: 24,
5268        })
5269    }
5270
5271    fn test_ifaddr_v6(ip: Ipv6Addr) -> IfAddr {
5272        IfAddr::V6(Ifv6Addr {
5273            ip,
5274            netmask: Ipv6Addr::from(u128::MAX << 64),
5275            broadcast: None,
5276            prefixlen: 64,
5277        })
5278    }
5279
5280    #[test]
5281    fn test_resolve_max_packet_size() {
5282        // en0 is dual-stack, en1 is IPv4 only.
5283        let interfaces = vec![
5284            test_interface("en0", 1, test_ifaddr_v4(Ipv4Addr::new(192, 168, 1, 2))),
5285            test_interface(
5286                "en0",
5287                1,
5288                test_ifaddr_v6(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 1)),
5289            ),
5290            test_interface("en1", 2, test_ifaddr_v4(Ipv4Addr::new(10, 0, 0, 2))),
5291        ];
5292
5293        let resolve = |selections: &[MaxPacketSizeSelection], if_index, is_ipv4| {
5294            resolve_max_packet_size(selections, &interfaces, if_index, is_ipv4)
5295        };
5296
5297        // No selection: every interface keeps the default.
5298        assert_eq!(resolve(&[], 1, true), MAX_PKT_DEFAULT);
5299        assert_eq!(resolve(&[], 1, false), MAX_PKT_DEFAULT);
5300
5301        // A selection by name applies to the interface it matches, both families.
5302        let by_name = vec![MaxPacketSizeSelection {
5303            if_kind: IfKind::Name("en0".to_string()),
5304            max_packet_size: 8000,
5305        }];
5306        assert_eq!(resolve(&by_name, 1, true), 8000);
5307        assert_eq!(resolve(&by_name, 1, false), 8000);
5308        assert_eq!(resolve(&by_name, 2, true), MAX_PKT_DEFAULT);
5309
5310        // For an interface matched more than once, the last selection wins.
5311        let overlapping = vec![
5312            MaxPacketSizeSelection {
5313                if_kind: IfKind::All,
5314                max_packet_size: 8000,
5315            },
5316            MaxPacketSizeSelection {
5317                if_kind: IfKind::Name("en1".to_string()),
5318                max_packet_size: 4000,
5319            },
5320        ];
5321        assert_eq!(resolve(&overlapping, 1, true), 8000);
5322        assert_eq!(resolve(&overlapping, 1, false), 8000);
5323        assert_eq!(resolve(&overlapping, 2, true), 4000);
5324
5325        // A selection of one address family leaves the other one alone.
5326        let v4_only = vec![MaxPacketSizeSelection {
5327            if_kind: IfKind::IPv4,
5328            max_packet_size: 8000,
5329        }];
5330        assert_eq!(resolve(&v4_only, 1, true), 8000);
5331        assert_eq!(resolve(&v4_only, 1, false), MAX_PKT_DEFAULT);
5332
5333        let v6_only = vec![MaxPacketSizeSelection {
5334            if_kind: IfKind::IPv6,
5335            max_packet_size: 8000,
5336        }];
5337        assert_eq!(resolve(&v6_only, 1, false), 8000);
5338        assert_eq!(resolve(&v6_only, 1, true), MAX_PKT_DEFAULT);
5339        // en1 has no IPv6 address, so the IPv6 selection cannot reach it.
5340        assert_eq!(resolve(&v6_only, 2, true), MAX_PKT_DEFAULT);
5341        assert_eq!(resolve(&v6_only, 2, false), MAX_PKT_DEFAULT);
5342
5343        // Same for an index selection, which names a family too.
5344        let by_index_v4 = vec![MaxPacketSizeSelection {
5345            if_kind: IfKind::IndexV4(1),
5346            max_packet_size: 8000,
5347        }];
5348        assert_eq!(resolve(&by_index_v4, 1, true), 8000);
5349        assert_eq!(resolve(&by_index_v4, 1, false), MAX_PKT_DEFAULT);
5350    }
5351
5352    /// A size outside [`MIN_MAX_PACKET_SIZE`]..=[`MAX_PKT_ABSOLUTE_IPV6`] is rejected
5353    /// rather than clamped, so what reaches the encoder is always legal.
5354    #[test]
5355    fn test_set_max_packet_size_range() {
5356        let daemon = ServiceDaemon::new().unwrap();
5357
5358        assert!(daemon
5359            .set_max_packet_size(IfKind::All, MIN_MAX_PACKET_SIZE - 1)
5360            .is_err());
5361        assert!(daemon
5362            .set_max_packet_size(IfKind::All, MAX_PKT_ABSOLUTE_IPV6 + 1)
5363            .is_err());
5364
5365        // Both ends of the range are accepted.
5366        assert!(daemon
5367            .set_max_packet_size(IfKind::All, MIN_MAX_PACKET_SIZE)
5368            .is_ok());
5369        assert!(daemon
5370            .set_max_packet_size(IfKind::All, MAX_PKT_ABSOLUTE_IPV6)
5371            .is_ok());
5372
5373        daemon.shutdown().unwrap();
5374    }
5375
5376    #[test]
5377    fn test_response_source_ifaddr_match() {
5378        // When an interface has multiple IPs on unrelated subnets,
5379        // handle_query should pick the IfAddr whose subnet contains the querier,
5380        // and fall back to None if none match.
5381        let ifaddr_a = IfAddr::V4(Ifv4Addr {
5382            ip: Ipv4Addr::new(192, 168, 1, 148),
5383            netmask: Ipv4Addr::new(255, 255, 255, 0),
5384            broadcast: None,
5385            prefixlen: 24,
5386        });
5387        let ifaddr_b = IfAddr::V4(Ifv4Addr {
5388            ip: Ipv4Addr::new(10, 238, 0, 51),
5389            netmask: Ipv4Addr::new(255, 255, 255, 0),
5390            broadcast: None,
5391            prefixlen: 24,
5392        });
5393
5394        let intf = MyIntf {
5395            name: "dummy0".to_string(),
5396            index: 1,
5397            addrs: HashSet::from([ifaddr_a.clone(), ifaddr_b.clone()]),
5398            max_packet_size_v4: MAX_PKT_DEFAULT,
5399            max_packet_size_v6: MAX_PKT_DEFAULT,
5400        };
5401
5402        let pick = |querier: IpAddr| -> Option<IfAddr> {
5403            intf.addrs
5404                .iter()
5405                .find(|a| valid_ip_on_intf(&querier, a))
5406                .cloned()
5407        };
5408
5409        assert_eq!(
5410            pick(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2))),
5411            Some(ifaddr_a)
5412        );
5413        assert_eq!(
5414            pick(IpAddr::V4(Ipv4Addr::new(10, 238, 0, 99))),
5415            Some(ifaddr_b)
5416        );
5417        // Querier not on any local subnet: fall back to None.
5418        assert_eq!(pick(IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1))), None);
5419    }
5420
5421    #[test]
5422    fn test_instance_name() {
5423        assert!(valid_instance_name("my-laser._printer._tcp.local."));
5424        assert!(valid_instance_name("my-laser.._printer._tcp.local."));
5425        assert!(!valid_instance_name("_printer._tcp.local."));
5426    }
5427
5428    #[test]
5429    fn test_legacy_unicast_response() {
5430        // RFC 6762 §6.7: a query whose UDP source port is not 5353 (a
5431        // "legacy" / "one-shot" querier, e.g. Android's getaddrinfo) must
5432        // get its response via unicast, sent back to the querier's source
5433        // address, with the question echoed and the cache-flush bit cleared.
5434        //
5435        // This test sends such a query from an ephemeral port and asserts
5436        // the response arrives on that same socket. The socket is not joined
5437        // to the mDNS multicast group, so a multicast-only reply would never
5438        // reach it — simply receiving the response proves it was unicast.
5439
5440        let intf_ip = match my_ip_interfaces(false)
5441            .into_iter()
5442            .find_map(|intf| match intf.ip() {
5443                IpAddr::V4(ip) => Some(ip),
5444                IpAddr::V6(_) => None,
5445            }) {
5446            Some(ip) => ip,
5447            None => {
5448                println!("No IPv4 interface available; skipping test.");
5449                return;
5450            }
5451        };
5452
5453        // Register a service with a unique hostname on this host.
5454        let daemon = ServiceDaemon::new().expect("Failed to create daemon");
5455        let unique = SystemTime::now()
5456            .duration_since(SystemTime::UNIX_EPOCH)
5457            .unwrap()
5458            .as_micros();
5459        let hostname = format!("legacy-unicast-test-{unique}.local.");
5460        let service_info = ServiceInfo::new(
5461            "_legacy-uni._udp.local.",
5462            "test_instance",
5463            &hostname,
5464            &[IpAddr::V4(intf_ip)] as &[IpAddr],
5465            5353, // arbitrary; the test only resolves the hostname
5466            None,
5467        )
5468        .expect("invalid service info");
5469        daemon.register(service_info).expect("register service");
5470
5471        // A one-shot querier: ephemeral source port, not 5353. Binding to
5472        // `intf_ip` directs the multicast query out that interface, which is
5473        // one the daemon is listening on.
5474        let querier = UdpSocket::bind((intf_ip, 0)).expect("bind querier socket");
5475        querier
5476            .set_multicast_loop_v4(true)
5477            .expect("enable multicast loopback");
5478        querier
5479            .set_read_timeout(Some(Duration::from_millis(500)))
5480            .expect("set read timeout");
5481        assert_ne!(
5482            querier.local_addr().unwrap().port(),
5483            MDNS_PORT,
5484            "querier must use an ephemeral (non-5353) source port"
5485        );
5486
5487        // Build a one-question A-record query for our hostname.
5488        let mut query = DnsOutgoing::new(FLAGS_QR_QUERY);
5489        query.add_question(&hostname, RRType::A);
5490        let query_packet = query
5491            .to_data_on_wire(MAX_PKT_DEFAULT, true)
5492            .pop()
5493            .expect("query serialized to one packet");
5494
5495        let if_id = InterfaceId {
5496            name: "test".to_string(),
5497            index: 0,
5498        };
5499
5500        // The service is announced asynchronously after register(), so retry
5501        // the query until our answer comes back or the deadline passes.
5502        let deadline = Instant::now() + Duration::from_secs(8);
5503        let mut response = None;
5504        'outer: while Instant::now() < deadline {
5505            querier
5506                .send_to(&query_packet, (GROUP_ADDR_V4, MDNS_PORT))
5507                .expect("send query");
5508
5509            // Drain whatever has arrived; on read timeout the loop ends and
5510            // we re-send the query.
5511            let mut buf = [0u8; 1500];
5512            while let Ok((len, from)) = querier.recv_from(&mut buf) {
5513                let Ok(msg) = DnsIncoming::new(buf[..len].to_vec(), if_id.clone()) else {
5514                    continue;
5515                };
5516                if msg.is_response()
5517                    && msg
5518                        .answers()
5519                        .iter()
5520                        .any(|a| a.get_name().eq_ignore_ascii_case(&hostname))
5521                {
5522                    response = Some((msg, from));
5523                    break 'outer;
5524                }
5525            }
5526        }
5527
5528        let (msg, from) = response.expect(
5529            "expected a unicast response to the legacy query; \
5530             a multicast-only reply would never reach this un-joined socket",
5531        );
5532
5533        // The reply came back to our ephemeral socket, from the mDNS port.
5534        assert_eq!(
5535            from.port(),
5536            MDNS_PORT,
5537            "response should originate from the mDNS port"
5538        );
5539
5540        // RFC 6762 §6.7: the original question must be echoed.
5541        assert!(
5542            msg.questions()
5543                .iter()
5544                .any(|q| q.entry_name().eq_ignore_ascii_case(&hostname)),
5545            "legacy unicast response must echo the question section"
5546        );
5547
5548        // RFC 6762 §6.7 / §10.2: the answer must be the A record we asked
5549        // for, with the cache-flush bit cleared.
5550        let answer = msg
5551            .answers()
5552            .iter()
5553            .find(|a| a.get_name().eq_ignore_ascii_case(&hostname))
5554            .expect("response contains an answer for our hostname");
5555        assert_eq!(
5556            answer.get_type(),
5557            RRType::A,
5558            "an A query should be answered with an A record"
5559        );
5560        assert!(
5561            !answer.get_cache_flush(),
5562            "legacy unicast responses must clear the cache-flush bit"
5563        );
5564
5565        daemon.shutdown().unwrap();
5566    }
5567
5568    #[test]
5569    fn test_shared_response_delay_bounds() {
5570        // A shared-record (PTR) response is delayed by a uniform-random amount.
5571        // We deviate from the RFC 6762 §6 suggested 20-120 ms window and use a
5572        // shorter 10-50 ms delay (`MAX` is the exclusive upper bound, so the
5573        // actual delay is 10..=49 ms).
5574        assert_eq!(SHARED_RESPONSE_DELAY_MIN_MILLIS, 10);
5575        assert_eq!(SHARED_RESPONSE_DELAY_MAX_MILLIS, 50);
5576        for _ in 0..10_000 {
5577            let d =
5578                fastrand::u64(SHARED_RESPONSE_DELAY_MIN_MILLIS..SHARED_RESPONSE_DELAY_MAX_MILLIS);
5579            assert!(
5580                (SHARED_RESPONSE_DELAY_MIN_MILLIS..SHARED_RESPONSE_DELAY_MAX_MILLIS).contains(&d),
5581                "delay {} ms is outside the configured {}-{} ms range",
5582                d,
5583                SHARED_RESPONSE_DELAY_MIN_MILLIS,
5584                SHARED_RESPONSE_DELAY_MAX_MILLIS
5585            );
5586        }
5587    }
5588
5589    #[test]
5590    fn test_initial_query_delayed() {
5591        // RFC 6762 §5.2: a querier delays the first query of a continuous
5592        // monitoring series by a random amount (we use a 10-50 ms window).
5593        // Start a browse and observe, on a socket joined to the mDNS group, the
5594        // daemon's first PTR query for our (unique) service type. Assert it
5595        // arrives no sooner than ~10 ms after `browse()` — i.e. it is not sent
5596        // immediately.
5597        use socket2::{Domain, Protocol, Socket, Type};
5598
5599        let (intf, intf_ip) = match my_ip_interfaces(false)
5600            .into_iter()
5601            .find_map(|intf| match intf.ip() {
5602                IpAddr::V4(ip) if !ip.is_loopback() => Some((intf, ip)),
5603                _ => None,
5604            }) {
5605            Some(pair) => pair,
5606            None => {
5607                println!("No IPv4 interface available; skipping test.");
5608                return;
5609            }
5610        };
5611        let interface_id = InterfaceId::from(&intf);
5612
5613        // A receiver socket joined to the mDNS group on this interface. The
5614        // daemon loops back its multicast by default, so its outgoing query is
5615        // delivered here on the same host.
5616        let sock = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP)).unwrap();
5617        sock.set_reuse_address(true).unwrap();
5618        #[cfg(unix)]
5619        sock.set_reuse_port(true).unwrap();
5620        sock.bind(&std::net::SocketAddr::from((Ipv4Addr::UNSPECIFIED, MDNS_PORT)).into())
5621            .unwrap();
5622        sock.join_multicast_v4(&GROUP_ADDR_V4, &intf_ip).unwrap();
5623        sock.set_read_timeout(Some(Duration::from_millis(200)))
5624            .unwrap();
5625        let sock: UdpSocket = sock.into();
5626
5627        // Unique service type, kept within the RFC 6763 §7.2 15-byte label limit.
5628        let unique = SystemTime::now()
5629            .duration_since(SystemTime::UNIX_EPOCH)
5630            .unwrap()
5631            .as_micros()
5632            % 1_000_000_000;
5633        let service_type = format!("_qd{unique}._udp.local.");
5634
5635        let daemon = ServiceDaemon::new().expect("Failed to create daemon");
5636
5637        let sent_at = Instant::now();
5638        let _browse = daemon.browse(&service_type).expect("browse");
5639
5640        // Read packets until we see our own PTR query or time out. The 10-50 ms
5641        // jitter plus command/scheduling latency comfortably fits in 2 s.
5642        let deadline = Instant::now() + Duration::from_secs(2);
5643        let mut buf = [0u8; 2048];
5644        let mut measured = None;
5645        while Instant::now() < deadline {
5646            let n = match sock.recv_from(&mut buf) {
5647                Ok((n, _)) => n,
5648                Err(_) => continue, // read timeout; keep polling until the deadline
5649            };
5650            let Ok(msg) = DnsIncoming::new(buf[..n].to_vec(), interface_id.clone()) else {
5651                continue;
5652            };
5653            if msg.is_query()
5654                && msg
5655                    .questions()
5656                    .iter()
5657                    .any(|q| q.entry_name() == service_type)
5658            {
5659                measured = Some(sent_at.elapsed());
5660                break;
5661            }
5662        }
5663
5664        daemon.shutdown().unwrap();
5665
5666        let elapsed = measured.expect("expected the daemon to send a PTR query for our browse");
5667        let tolerance = Duration::from_millis(2);
5668        assert!(
5669            elapsed + tolerance >= Duration::from_millis(INITIAL_QUERY_DELAY_MIN_MILLIS),
5670            "first browse query was sent after only {:?}; the first query of a series must be \
5671             delayed (10-50 ms window), not sent immediately",
5672            elapsed
5673        );
5674
5675        // Upper bound: the query must fall within the jitter window. Allow
5676        // generous slack above INITIAL_QUERY_DELAY_MAX_MILLIS for command
5677        // handoff, event-loop wakeup, and loopback latency, while still catching
5678        // a regression to a much larger delay (e.g. the RFC's 120 ms window).
5679        let scheduling_slack = Duration::from_millis(50);
5680        assert!(
5681            elapsed <= Duration::from_millis(INITIAL_QUERY_DELAY_MAX_MILLIS) + scheduling_slack,
5682            "first browse query was sent after {:?}, beyond the {}-{} ms jitter window (plus slack)",
5683            elapsed,
5684            INITIAL_QUERY_DELAY_MIN_MILLIS,
5685            INITIAL_QUERY_DELAY_MAX_MILLIS
5686        );
5687    }
5688
5689    #[test]
5690    fn test_shared_ptr_response_delayed() {
5691        // RFC 6762 §6: a PTR (shared record set) response sent by multicast is
5692        // delayed by a uniform-random amount (we use a 10-50 ms window). Register
5693        // a service, then as a proper multicast querier (source port 5353) send a
5694        // PTR query and assert the daemon emits its response no sooner than ~10 ms
5695        // after the query. (A legacy unicast querier gets an *immediate* response
5696        // instead; see `test_legacy_unicast_response`.)
5697        use socket2::{Domain, Protocol, Socket, Type};
5698
5699        let intf_ip = match my_ip_interfaces(false)
5700            .into_iter()
5701            .find_map(|intf| match intf.ip() {
5702                IpAddr::V4(ip) if !ip.is_loopback() => Some(ip),
5703                _ => None,
5704            }) {
5705            Some(ip) => ip,
5706            None => {
5707                println!("No IPv4 interface available; skipping test.");
5708                return;
5709            }
5710        };
5711
5712        let daemon = ServiceDaemon::new().expect("Failed to create daemon");
5713        let monitor = daemon.monitor().expect("monitor daemon events");
5714
5715        // Keep the service name (the `_sd…` label) within the 15-byte limit
5716        // that RFC 6763 §7.2 imposes, while staying unique per run.
5717        let unique = SystemTime::now()
5718            .duration_since(SystemTime::UNIX_EPOCH)
5719            .unwrap()
5720            .as_micros()
5721            % 1_000_000_000;
5722        let service_type = format!("_sd{unique}._udp.local.");
5723        let hostname = format!("sd{unique}.local.");
5724        let service_info = ServiceInfo::new(
5725            &service_type,
5726            "test_instance",
5727            &hostname,
5728            &[IpAddr::V4(intf_ip)] as &[IpAddr],
5729            5353,
5730            None,
5731        )
5732        .expect("invalid service info");
5733        daemon.register(service_info).expect("register service");
5734
5735        // A proper multicast querier: source port 5353 so the daemon takes the
5736        // shared-record (delayed) path rather than the legacy-unicast one. We only
5737        // *send* on this socket; the response is observed through the monitor.
5738        let sock = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP)).unwrap();
5739        sock.set_reuse_address(true).unwrap();
5740        #[cfg(unix)]
5741        sock.set_reuse_port(true).unwrap();
5742        sock.bind(&std::net::SocketAddr::from((Ipv4Addr::UNSPECIFIED, MDNS_PORT)).into())
5743            .unwrap();
5744        sock.set_multicast_if_v4(&intf_ip).unwrap();
5745        // Loop the query back to the daemon's socket on this same host.
5746        sock.set_multicast_loop_v4(true).unwrap();
5747        let sock: UdpSocket = sock.into();
5748
5749        // Build the PTR query for our service type.
5750        let mut query = DnsOutgoing::new(FLAGS_QR_QUERY);
5751        query.add_question(&service_type, RRType::PTR);
5752        let query_packet = query
5753            .to_data_on_wire(MAX_PKT_DEFAULT, true)
5754            .pop()
5755            .expect("one packet");
5756
5757        // Wait for the initial announcements and the §6 rate-limit window (1s) to
5758        // pass, so our query elicits a fresh (delayed) response instead of being
5759        // suppressed by the rate limiter.
5760        std::thread::sleep(Duration::from_secs(3));
5761
5762        // Retry until the daemon emits a Respond for our query. A query landing
5763        // inside the 1 s multicast rate-limit window is rate-limited to an empty
5764        // response (no send, no event), so we simply re-query on the next pass.
5765        let deadline = Instant::now() + Duration::from_secs(8);
5766        let mut measured = None;
5767        while Instant::now() < deadline {
5768            // Drop any Respond events queued earlier so we time only the response
5769            // to the query we are about to send.
5770            while monitor.try_recv().is_ok() {}
5771
5772            let sent_at = Instant::now();
5773            sock.send_to(&query_packet, (GROUP_ADDR_V4, MDNS_PORT))
5774                .expect("send query");
5775
5776            // The delay window is 10-50 ms; 700 ms comfortably covers it plus any
5777            // scheduling slack. Ignore unrelated events; on timeout, re-query.
5778            let attempt_deadline = sent_at + Duration::from_millis(700);
5779            loop {
5780                let remaining = attempt_deadline.saturating_duration_since(Instant::now());
5781                if remaining.is_zero() {
5782                    break;
5783                }
5784                match monitor.recv_timeout(remaining) {
5785                    Ok(DaemonEvent::Respond(_)) => {
5786                        measured = Some(sent_at.elapsed());
5787                        break;
5788                    }
5789                    Ok(_) => continue, // some other daemon event; keep waiting
5790                    Err(_) => break,   // timed out; re-query
5791                }
5792            }
5793            if measured.is_some() {
5794                break;
5795            }
5796        }
5797
5798        let elapsed =
5799            measured.expect("expected the daemon to respond to our PTR query within the deadline");
5800        assert!(
5801            elapsed >= Duration::from_millis(8),
5802            "PTR response was sent after only {:?}; a shared-record response must be \
5803             delayed (10-50 ms window), not sent immediately",
5804            elapsed
5805        );
5806        assert!(
5807            elapsed <= Duration::from_millis(600),
5808            "PTR response was sent after {:?}; expected within the 10-50 ms delay window",
5809            elapsed
5810        );
5811
5812        daemon.shutdown().unwrap();
5813    }
5814
5815    #[test]
5816    fn test_check_service_name_length() {
5817        let result = check_service_name_length("_tcp", 100);
5818        assert!(result.is_err());
5819        if let Err(e) = result {
5820            println!("{}", e);
5821        }
5822    }
5823
5824    #[test]
5825    fn test_check_hostname() {
5826        // valid hostnames
5827        for hostname in &[
5828            "my_host.local.",
5829            &("A".repeat(255 - ".local.".len()) + ".local."),
5830        ] {
5831            let result = check_hostname(hostname);
5832            assert!(result.is_ok());
5833        }
5834
5835        // erroneous hostnames
5836        for hostname in &[
5837            "my_host.local",
5838            ".local.",
5839            &("A".repeat(256 - ".local.".len()) + ".local."),
5840        ] {
5841            let result = check_hostname(hostname);
5842            assert!(result.is_err());
5843            if let Err(e) = result {
5844                println!("{}", e);
5845            }
5846        }
5847    }
5848
5849    #[test]
5850    fn test_check_domain_suffix() {
5851        assert!(check_domain_suffix("_missing_dot._tcp.local").is_err());
5852        assert!(check_domain_suffix("_missing_bar.tcp.local.").is_err());
5853        assert!(check_domain_suffix("_mis_spell._tpp.local.").is_err());
5854        assert!(check_domain_suffix("_mis_spell._upp.local.").is_err());
5855        assert!(check_domain_suffix("_has_dot._tcp.local.").is_ok());
5856        assert!(check_domain_suffix("_goodname._udp.local.").is_ok());
5857    }
5858
5859    #[test]
5860    fn test_service_with_temporarily_invalidated_ptr() {
5861        // Create a daemon
5862        let d = ServiceDaemon::new().expect("Failed to create daemon");
5863
5864        let service = "_test_inval_ptr._udp.local.";
5865        let host_name = "my_host_tmp_invalidated_ptr.local.";
5866        let intfs: Vec<_> = my_ip_interfaces(false);
5867        let intf_ips: Vec<_> = intfs.iter().map(|intf| intf.ip()).collect();
5868        let port = 5201;
5869        let my_service =
5870            ServiceInfo::new(service, "my_instance", host_name, &intf_ips[..], port, None)
5871                .expect("invalid service info")
5872                .enable_addr_auto();
5873        let result = d.register(my_service.clone());
5874        assert!(result.is_ok());
5875
5876        // Browse for a service
5877        let browse_chan = d.browse(service).unwrap();
5878        let timeout = Duration::from_secs(2);
5879        let mut resolved = false;
5880
5881        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5882            match event {
5883                ServiceEvent::ServiceResolved(info) => {
5884                    resolved = true;
5885                    println!("Resolved a service of {}", &info.fullname);
5886                    break;
5887                }
5888                e => {
5889                    println!("Received event {:?}", e);
5890                }
5891            }
5892        }
5893
5894        assert!(resolved);
5895
5896        println!("Stopping browse of {}", service);
5897        // Pause browsing so restarting will cause a new immediate query.
5898        // Unregistering will not work here, it will invalidate all the records.
5899        d.stop_browse(service).unwrap();
5900
5901        // Ensure the search is stopped.
5902        // Reduces the chance of receiving an answer adding the ptr back to the
5903        // cache causing the later browse to return directly from the cache.
5904        // (which invalidates what this test is trying to test for.)
5905        let mut stopped = false;
5906        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5907            match event {
5908                ServiceEvent::SearchStopped(_) => {
5909                    stopped = true;
5910                    println!("Stopped browsing service");
5911                    break;
5912                }
5913                // Other `ServiceResolved` messages may be received
5914                // here as they come from different interfaces.
5915                // That's fine for this test.
5916                e => {
5917                    println!("Received event {:?}", e);
5918                }
5919            }
5920        }
5921
5922        assert!(stopped);
5923
5924        // Invalidate the ptr from the service to the host.
5925        let invalidate_ptr_packet = DnsPointer::new(
5926            my_service.get_type(),
5927            RRType::PTR,
5928            CLASS_IN,
5929            0,
5930            my_service.get_fullname().to_string(),
5931        );
5932
5933        let mut packet_buffer = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
5934        packet_buffer.add_additional_answer(invalidate_ptr_packet);
5935
5936        for intf in intfs {
5937            let sock = _new_socket_bind(&intf, true).unwrap();
5938            send_dns_outgoing_impl(
5939                &packet_buffer,
5940                &intf.name,
5941                intf.index.unwrap_or(0),
5942                &intf.addr,
5943                &sock.pktinfo,
5944                SendConfig {
5945                    port: MDNS_PORT,
5946                    max_packet_size: MAX_PKT_DEFAULT,
5947                    is_ipv4: intf.addr.ip().is_ipv4(),
5948                },
5949                None,
5950            )
5951            .unwrap();
5952        }
5953
5954        println!(
5955            "Sent PTR record invalidation. Starting second browse for {}",
5956            service
5957        );
5958
5959        // Restart the browse to force the sender to re-send the announcements.
5960        let browse_chan = d.browse(service).unwrap();
5961
5962        resolved = false;
5963        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5964            match event {
5965                ServiceEvent::ServiceResolved(info) => {
5966                    resolved = true;
5967                    println!("Resolved a service of {}", &info.fullname);
5968                    break;
5969                }
5970                e => {
5971                    println!("Received event {:?}", e);
5972                }
5973            }
5974        }
5975
5976        assert!(resolved);
5977        d.shutdown().unwrap();
5978    }
5979
5980    #[test]
5981    fn test_expired_srv() {
5982        // construct service info
5983        let service_type = "_expired-srv._udp.local.";
5984        let instance = "test_instance";
5985        let host_name = "expired_srv_host.local.";
5986        let mut my_service = ServiceInfo::new(service_type, instance, host_name, "", 5023, None)
5987            .unwrap()
5988            .enable_addr_auto();
5989        // let fullname = my_service.get_fullname().to_string();
5990
5991        // set SRV to expire soon.
5992        let new_ttl = 3; // for testing only.
5993        my_service._set_host_ttl(new_ttl);
5994
5995        // register my service
5996        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
5997        let result = mdns_server.register(my_service);
5998        assert!(result.is_ok());
5999
6000        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6001        let browse_chan = mdns_client.browse(service_type).unwrap();
6002        let timeout = Duration::from_secs(2);
6003        let mut resolved = false;
6004
6005        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6006            if let ServiceEvent::ServiceResolved(info) = event {
6007                resolved = true;
6008                println!("Resolved a service of {}", &info.fullname);
6009                break;
6010            }
6011        }
6012
6013        assert!(resolved);
6014
6015        // Exit the server so that no more responses.
6016        mdns_server.shutdown().unwrap();
6017
6018        // SRV record in the client cache will expire.
6019        let expire_timeout = Duration::from_secs(new_ttl as u64);
6020        while let Ok(event) = browse_chan.recv_timeout(expire_timeout) {
6021            if let ServiceEvent::ServiceRemoved(service_type, full_name) = event {
6022                println!("Service removed: {}: {}", &service_type, &full_name);
6023                break;
6024            }
6025        }
6026    }
6027
6028    #[test]
6029    fn test_hostname_resolution_address_removed() {
6030        // Create a mDNS server
6031        let server = ServiceDaemon::new().expect("Failed to create server");
6032        let hostname = "addr_remove_host._tcp.local.";
6033        let service_ip_addr: ScopedIp = my_ip_interfaces(false)
6034            .iter()
6035            .find(|iface| iface.ip().is_ipv4())
6036            .map(|iface| iface.into())
6037            .unwrap();
6038
6039        let mut my_service = ServiceInfo::new(
6040            "_host_res_test._tcp.local.",
6041            "my_instance",
6042            hostname,
6043            service_ip_addr.to_ip_addr(),
6044            1234,
6045            None,
6046        )
6047        .expect("invalid service info");
6048
6049        // Set a short TTL for addresses for testing.
6050        let addr_ttl = 2;
6051        my_service._set_host_ttl(addr_ttl); // Expire soon
6052
6053        server.register(my_service).unwrap();
6054
6055        // Create a mDNS client for resolving the hostname.
6056        let client = ServiceDaemon::new().expect("Failed to create client");
6057        let event_receiver = client.resolve_hostname(hostname, None).unwrap();
6058        let resolved = loop {
6059            match event_receiver.recv() {
6060                Ok(HostnameResolutionEvent::AddressesFound(found_hostname, addresses)) => {
6061                    assert!(found_hostname == hostname);
6062                    assert!(addresses.contains(&service_ip_addr));
6063                    println!("address found: {:?}", &addresses);
6064                    break true;
6065                }
6066                Ok(HostnameResolutionEvent::SearchStopped(_)) => break false,
6067                Ok(_event) => {}
6068                Err(_) => break false,
6069            }
6070        };
6071
6072        assert!(resolved);
6073
6074        // Shutdown the server so no more responses / refreshes for addresses.
6075        server.shutdown().unwrap();
6076
6077        // Wait till hostname address record expires, with 1 second grace period.
6078        let timeout = Duration::from_secs(addr_ttl as u64 + 1);
6079        let removed = loop {
6080            match event_receiver.recv_timeout(timeout) {
6081                Ok(HostnameResolutionEvent::AddressesRemoved(removed_host, addresses)) => {
6082                    assert!(removed_host == hostname);
6083                    assert!(addresses.contains(&service_ip_addr));
6084
6085                    println!(
6086                        "address removed: hostname: {} addresses: {:?}",
6087                        &hostname, &addresses
6088                    );
6089                    break true;
6090                }
6091                Ok(_event) => {}
6092                Err(_) => {
6093                    break false;
6094                }
6095            }
6096        };
6097
6098        assert!(removed);
6099
6100        client.shutdown().unwrap();
6101    }
6102
6103    #[test]
6104    fn test_refresh_ptr() {
6105        // construct service info
6106        let service_type = "_refresh-ptr._udp.local.";
6107        let instance = "test_instance";
6108        let host_name = "refresh_ptr_host.local.";
6109        let service_ip_addr = my_ip_interfaces(false)
6110            .iter()
6111            .find(|iface| iface.ip().is_ipv4())
6112            .map(|iface| iface.ip())
6113            .unwrap();
6114
6115        let mut my_service = ServiceInfo::new(
6116            service_type,
6117            instance,
6118            host_name,
6119            service_ip_addr,
6120            5023,
6121            None,
6122        )
6123        .unwrap();
6124
6125        let new_ttl = 3; // for testing only.
6126        my_service._set_other_ttl(new_ttl);
6127
6128        // register my service
6129        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6130        let result = mdns_server.register(my_service);
6131        assert!(result.is_ok());
6132
6133        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6134        let browse_chan = mdns_client.browse(service_type).unwrap();
6135        let timeout = Duration::from_millis(1500); // Give at least 1 second for the service probing.
6136        let mut resolved = false;
6137
6138        // resolve the service first.
6139        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6140            if let ServiceEvent::ServiceResolved(info) = event {
6141                resolved = true;
6142                println!("Resolved a service of {}", &info.fullname);
6143                break;
6144            }
6145        }
6146
6147        assert!(resolved);
6148
6149        // wait over 80% of TTL, and refresh PTR should be sent out.
6150        let timeout = Duration::from_millis(new_ttl as u64 * 1000 * 90 / 100);
6151        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6152            println!("event: {:?}", &event);
6153        }
6154
6155        // verify refresh counter.
6156        let metrics_chan = mdns_client.get_metrics().unwrap();
6157        let metrics = metrics_chan.recv_timeout(timeout).unwrap();
6158        let ptr_refresh_counter = metrics["cache-refresh-ptr"];
6159        assert_eq!(ptr_refresh_counter, 1);
6160        let srvtxt_refresh_counter = metrics["cache-refresh-srv-txt"];
6161        assert_eq!(srvtxt_refresh_counter, 1);
6162
6163        // Exit the server so that no more responses.
6164        mdns_server.shutdown().unwrap();
6165        mdns_client.shutdown().unwrap();
6166    }
6167
6168    #[test]
6169    fn test_name_change() {
6170        assert_eq!(name_change("foo.local."), "foo (2).local.");
6171        assert_eq!(name_change("foo (2).local."), "foo (3).local.");
6172        assert_eq!(name_change("foo (9).local."), "foo (10).local.");
6173        assert_eq!(name_change("foo"), "foo (2)");
6174        assert_eq!(name_change("foo (2)"), "foo (3)");
6175        assert_eq!(name_change(""), " (2)");
6176
6177        // Additional edge cases
6178        assert_eq!(name_change("foo (abc)"), "foo (abc) (2)"); // Invalid number
6179        assert_eq!(name_change("foo (2"), "foo (2 (2)"); // Missing closing parenthesis
6180        assert_eq!(name_change("foo (2) extra"), "foo (2) extra (2)"); // Extra text after number
6181    }
6182
6183    #[test]
6184    fn test_hostname_change() {
6185        assert_eq!(hostname_change("foo.local."), "foo-2.local.");
6186        assert_eq!(hostname_change("foo"), "foo-2");
6187        assert_eq!(hostname_change("foo-2.local."), "foo-3.local.");
6188        assert_eq!(hostname_change("foo-9"), "foo-10");
6189        assert_eq!(hostname_change("test-42.domain."), "test-43.domain.");
6190    }
6191
6192    #[test]
6193    fn test_add_answer_txt_ttl() {
6194        // construct a simple service info
6195        let service_type = "_test_add_answer._udp.local.";
6196        let instance = "test_instance";
6197        let host_name = "add_answer_host.local.";
6198        let service_intf = my_ip_interfaces(false)
6199            .into_iter()
6200            .find(|iface| iface.ip().is_ipv4())
6201            .unwrap();
6202        let service_ip_addr = service_intf.ip();
6203        let my_service = ServiceInfo::new(
6204            service_type,
6205            instance,
6206            host_name,
6207            service_ip_addr,
6208            5023,
6209            None,
6210        )
6211        .unwrap();
6212
6213        // construct a DnsOutgoing message
6214        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
6215
6216        // Construct a dummy DnsIncoming message
6217        let mut dummy_data = out.to_data_on_wire(MAX_PKT_DEFAULT, true);
6218        let interface_id = InterfaceId::from(&service_intf);
6219        let incoming = DnsIncoming::new(dummy_data.pop().unwrap(), interface_id).unwrap();
6220
6221        // Add an answer of TXT type for the service.
6222        let if_addrs = vec![service_intf.ip()];
6223        add_answer_of_service(
6224            &mut out,
6225            &incoming,
6226            instance,
6227            &my_service,
6228            RRType::TXT,
6229            if_addrs,
6230        );
6231
6232        // Check if the answer was added correctly
6233        assert!(
6234            out.answers_count() > 0,
6235            "No answers added to the outgoing message"
6236        );
6237
6238        // Check if the first answer is of type TXT
6239        let answer = out._answers().first().unwrap();
6240        assert_eq!(answer.0.get_type(), RRType::TXT);
6241
6242        // Check TTL is set properly for the TXT record
6243        assert_eq!(answer.0.get_record().get_ttl(), my_service.get_other_ttl());
6244    }
6245
6246    #[test]
6247    fn test_interface_flip() {
6248        // start a server
6249        let ty_domain = "_intf-flip._udp.local.";
6250        let host_name = "intf_flip.local.";
6251        let now = SystemTime::now()
6252            .duration_since(SystemTime::UNIX_EPOCH)
6253            .unwrap();
6254        let instance_name = now.as_micros().to_string(); // Create a unique name.
6255        let port = 5200;
6256
6257        // Get a single IPv4 address
6258        let (ip_addr1, intf_name) = my_ip_interfaces(false)
6259            .iter()
6260            .find(|iface| iface.ip().is_ipv4())
6261            .map(|iface| (iface.ip(), iface.name.clone()))
6262            .unwrap();
6263
6264        println!("Using interface {} with IP {}", intf_name, ip_addr1);
6265
6266        // Register the service.
6267        let service1 = ServiceInfo::new(ty_domain, &instance_name, host_name, ip_addr1, port, None)
6268            .expect("valid service info");
6269        let server1 = ServiceDaemon::new().expect("failed to start server");
6270        server1
6271            .register(service1)
6272            .expect("Failed to register service1");
6273
6274        // wait for the service announced.
6275        std::thread::sleep(Duration::from_secs(2));
6276
6277        // start a client
6278        let client = ServiceDaemon::new().expect("failed to start client");
6279
6280        let receiver = client.browse(ty_domain).unwrap();
6281
6282        let timeout = Duration::from_secs(3);
6283        let mut got_data = false;
6284
6285        while let Ok(event) = receiver.recv_timeout(timeout) {
6286            if let ServiceEvent::ServiceResolved(_) = event {
6287                println!("Received ServiceResolved event");
6288                got_data = true;
6289                break;
6290            }
6291        }
6292
6293        assert!(got_data, "Should receive ServiceResolved event");
6294
6295        // Set a short IP check interval to detect interface changes quickly.
6296        client.set_ip_check_interval(1).unwrap();
6297
6298        // Now shutdown the interface and expect the client to lose the service.
6299        println!("Shutting down interface {}", &intf_name);
6300        client.test_down_interface(&intf_name).unwrap();
6301
6302        let mut got_removed = false;
6303
6304        while let Ok(event) = receiver.recv_timeout(timeout) {
6305            if let ServiceEvent::ServiceRemoved(ty_domain, instance) = event {
6306                got_removed = true;
6307                println!("removed: {ty_domain} : {instance}");
6308                break;
6309            }
6310        }
6311        assert!(got_removed, "Should receive ServiceRemoved event");
6312
6313        println!("Bringing up interface {}", &intf_name);
6314        client.test_up_interface(&intf_name).unwrap();
6315        let mut got_data = false;
6316        while let Ok(event) = receiver.recv_timeout(timeout) {
6317            if let ServiceEvent::ServiceResolved(resolved) = event {
6318                got_data = true;
6319                println!("Received ServiceResolved: {:?}", resolved);
6320                break;
6321            }
6322        }
6323        assert!(
6324            got_data,
6325            "Should receive ServiceResolved event after interface is back up"
6326        );
6327
6328        server1.shutdown().unwrap();
6329        client.shutdown().unwrap();
6330    }
6331
6332    #[test]
6333    fn test_cache_only() {
6334        // construct service info
6335        let service_type = "_cache_only._udp.local.";
6336        let instance = "test_instance";
6337        let host_name = "cache_only_host.local.";
6338        let service_ip_addr = my_ip_interfaces(false)
6339            .iter()
6340            .find(|iface| iface.ip().is_ipv4())
6341            .map(|iface| iface.ip())
6342            .unwrap();
6343
6344        let mut my_service = ServiceInfo::new(
6345            service_type,
6346            instance,
6347            host_name,
6348            service_ip_addr,
6349            5023,
6350            None,
6351        )
6352        .unwrap();
6353
6354        let new_ttl = 3; // for testing only.
6355        my_service._set_other_ttl(new_ttl);
6356
6357        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6358
6359        // make a single browse request to record that we are interested in the service.  This ensures that
6360        // subsequent announcements are cached.
6361        let browse_chan = mdns_client.browse_cache(service_type).unwrap();
6362        std::thread::sleep(Duration::from_secs(2));
6363
6364        // register my service
6365        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6366        let result = mdns_server.register(my_service);
6367        assert!(result.is_ok());
6368
6369        let timeout = Duration::from_millis(1500); // Give at least 1 second for the service probing.
6370        let mut resolved = false;
6371
6372        // resolve the service.
6373        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6374            if let ServiceEvent::ServiceResolved(info) = event {
6375                resolved = true;
6376                println!("Resolved a service of {}", &info.get_fullname());
6377                break;
6378            }
6379        }
6380
6381        assert!(resolved);
6382
6383        // Exit the server so that no more responses.
6384        mdns_server.shutdown().unwrap();
6385        mdns_client.shutdown().unwrap();
6386    }
6387
6388    #[test]
6389    fn test_cache_only_unsolicited() {
6390        let service_type = "_c_unsolicit._udp.local.";
6391        let instance = "test_instance";
6392        let host_name = "c_unsolicit_host.local.";
6393        let service_ip_addr = my_ip_interfaces(false)
6394            .iter()
6395            .find(|iface| iface.ip().is_ipv4())
6396            .map(|iface| iface.ip())
6397            .unwrap();
6398
6399        let my_service = ServiceInfo::new(
6400            service_type,
6401            instance,
6402            host_name,
6403            service_ip_addr,
6404            5023,
6405            None,
6406        )
6407        .unwrap();
6408
6409        // register my service
6410        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6411        let result = mdns_server.register(my_service);
6412        assert!(result.is_ok());
6413
6414        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6415        mdns_client.accept_unsolicited(true).unwrap();
6416
6417        // Wait a bit for the service announcements to go out, before calling browse_cache.  This ensures
6418        // that the announcements are treated as unsolicited
6419        std::thread::sleep(Duration::from_secs(2));
6420        let browse_chan = mdns_client.browse_cache(service_type).unwrap();
6421        let timeout = Duration::from_millis(1500); // Give at least 1 second for the service probing.
6422        let mut resolved = false;
6423
6424        // resolve the service.
6425        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6426            if let ServiceEvent::ServiceResolved(info) = event {
6427                resolved = true;
6428                println!("Resolved a service of {}", &info.get_fullname());
6429                break;
6430            }
6431        }
6432
6433        assert!(resolved);
6434
6435        // Exit the server so that no more responses.
6436        mdns_server.shutdown().unwrap();
6437        mdns_client.shutdown().unwrap();
6438    }
6439
6440    #[test]
6441    fn test_custom_port_isolation() {
6442        // This test verifies:
6443        // 1. Daemons on a custom port can communicate with each other
6444        // 2. Daemons on different ports are isolated (no cross-talk)
6445
6446        let service_type = "_custom_port._udp.local.";
6447        let instance_custom = "custom_port_instance";
6448        let instance_default = "default_port_instance";
6449        let host_name = "custom_port_host.local.";
6450
6451        let service_ip_addr = my_ip_interfaces(false)
6452            .iter()
6453            .find(|iface| iface.ip().is_ipv4())
6454            .map(|iface| iface.ip())
6455            .expect("Test requires an IPv4 interface");
6456
6457        // Create service info for custom port (5454)
6458        let service_custom = ServiceInfo::new(
6459            service_type,
6460            instance_custom,
6461            host_name,
6462            service_ip_addr,
6463            8080,
6464            None,
6465        )
6466        .unwrap();
6467
6468        // Create service info for default port (5353)
6469        let service_default = ServiceInfo::new(
6470            service_type,
6471            instance_default,
6472            host_name,
6473            service_ip_addr,
6474            8081,
6475            None,
6476        )
6477        .unwrap();
6478
6479        // Create two daemons on custom port 5454
6480        let custom_port = 5454u16;
6481        let server_custom =
6482            ServiceDaemon::new_with_port(custom_port).expect("Failed to create custom port server");
6483        let client_custom =
6484            ServiceDaemon::new_with_port(custom_port).expect("Failed to create custom port client");
6485
6486        // Create daemon on default port (5353)
6487        let server_default = ServiceDaemon::new().expect("Failed to create default port server");
6488
6489        // Register service on custom port
6490        server_custom
6491            .register(service_custom.clone())
6492            .expect("Failed to register custom port service");
6493
6494        // Register service on default port
6495        server_default
6496            .register(service_default.clone())
6497            .expect("Failed to register default port service");
6498
6499        // Browse from custom port client
6500        let browse_custom = client_custom
6501            .browse(service_type)
6502            .expect("Failed to browse on custom port");
6503
6504        let timeout = Duration::from_secs(3);
6505        let mut found_custom = false;
6506        let mut found_default_on_custom = false;
6507
6508        // Custom port client should find the custom port service
6509        while let Ok(event) = browse_custom.recv_timeout(timeout) {
6510            if let ServiceEvent::ServiceResolved(info) = event {
6511                println!(
6512                    "Custom port client resolved: {} on port {}",
6513                    info.get_fullname(),
6514                    info.get_port()
6515                );
6516                if info.get_fullname().starts_with(instance_custom) {
6517                    found_custom = true;
6518                    assert_eq!(info.get_port(), 8080);
6519                }
6520                if info.get_fullname().starts_with(instance_default) {
6521                    found_default_on_custom = true;
6522                }
6523            }
6524        }
6525
6526        assert!(
6527            found_custom,
6528            "Custom port client should find service on custom port"
6529        );
6530        assert!(
6531            !found_default_on_custom,
6532            "Custom port client should NOT find service on default port"
6533        );
6534
6535        // Now verify the default port daemon can find its own services
6536        // but not the custom port services
6537        let client_default = ServiceDaemon::new().expect("Failed to create default port client");
6538        let browse_default = client_default
6539            .browse(service_type)
6540            .expect("Failed to browse on default port");
6541
6542        let mut found_default = false;
6543        let mut found_custom_on_default = false;
6544
6545        while let Ok(event) = browse_default.recv_timeout(timeout) {
6546            if let ServiceEvent::ServiceResolved(info) = event {
6547                println!(
6548                    "Default port client resolved: {} on port {}",
6549                    info.get_fullname(),
6550                    info.get_port()
6551                );
6552                if info.get_fullname().starts_with(instance_default) {
6553                    found_default = true;
6554                    assert_eq!(info.get_port(), 8081);
6555                }
6556                if info.get_fullname().starts_with(instance_custom) {
6557                    found_custom_on_default = true;
6558                }
6559            }
6560        }
6561
6562        assert!(
6563            found_default,
6564            "Default port client should find service on default port"
6565        );
6566        assert!(
6567            !found_custom_on_default,
6568            "Default port client should NOT find service on custom port"
6569        );
6570
6571        // Cleanup
6572        server_custom.shutdown().unwrap();
6573        client_custom.shutdown().unwrap();
6574        server_default.shutdown().unwrap();
6575        client_default.shutdown().unwrap();
6576    }
6577}