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        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
2460        out.add_answer_at_time(
2461            DnsPointer::new(
2462                info.get_type(),
2463                RRType::PTR,
2464                CLASS_IN,
2465                0,
2466                info.get_fullname().to_string(),
2467            ),
2468            0,
2469        );
2470
2471        if let Some(sub) = info.get_subtype() {
2472            trace!("Adding subdomain {}", sub);
2473            out.add_answer_at_time(
2474                DnsPointer::new(
2475                    sub,
2476                    RRType::PTR,
2477                    CLASS_IN,
2478                    0,
2479                    info.get_fullname().to_string(),
2480                ),
2481                0,
2482            );
2483        }
2484
2485        out.add_answer_at_time(
2486            DnsSrv::new(
2487                info.get_fullname(),
2488                CLASS_IN | CLASS_CACHE_FLUSH,
2489                0,
2490                info.get_priority(),
2491                info.get_weight(),
2492                info.get_port(),
2493                info.get_hostname().to_string(),
2494            ),
2495            0,
2496        );
2497        out.add_answer_at_time(
2498            DnsTxt::new(
2499                info.get_fullname(),
2500                CLASS_IN | CLASS_CACHE_FLUSH,
2501                0,
2502                info.generate_txt(),
2503            ),
2504            0,
2505        );
2506
2507        let if_addrs = if is_ipv4 {
2508            info.get_addrs_on_my_intf_v4(intf)
2509        } else {
2510            info.get_addrs_on_my_intf_v6(intf)
2511        };
2512
2513        if if_addrs.is_empty() {
2514            return vec![];
2515        }
2516
2517        for address in if_addrs {
2518            out.add_answer_at_time(
2519                DnsAddress::new(
2520                    info.get_hostname(),
2521                    ip_address_rr_type(&address),
2522                    CLASS_IN | CLASS_CACHE_FLUSH,
2523                    0,
2524                    address,
2525                    intf.into(),
2526                ),
2527                0,
2528            );
2529        }
2530
2531        // Only (at most) one packet is expected to be sent out.
2532        let sent_vec = match send_dns_outgoing(&out, intf, sock, self.port, None, None) {
2533            Ok(sent_vec) => sent_vec,
2534            Err(InternalError::IntfAddrInvalid(intf_addr)) => {
2535                let invalid_intf_addrs = HashSet::from([intf_addr]);
2536                let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2537                vec![]
2538            }
2539        };
2540        sent_vec.into_iter().next().unwrap_or_default()
2541    }
2542
2543    /// Binds a channel `listener` to querying mDNS hostnames.
2544    ///
2545    /// If there is already a `listener`, it will be updated, i.e. overwritten.
2546    fn add_hostname_resolver(
2547        &mut self,
2548        hostname: String,
2549        listener: Sender<HostnameResolutionEvent>,
2550        timeout: Option<u64>,
2551    ) {
2552        let real_timeout = timeout.map(|t| current_time_millis() + t);
2553        self.hostname_resolvers
2554            .insert(hostname.to_lowercase(), (listener, real_timeout));
2555        if let Some(t) = real_timeout {
2556            self.add_timer(t);
2557        }
2558    }
2559
2560    /// Sends a multicast query for `name` with `qtype`.
2561    fn send_query(&self, name: &str, qtype: RRType) {
2562        self.send_query_vec(&[(name, qtype)]);
2563    }
2564
2565    /// Sends a query on a specific interface without known answers.
2566    ///
2567    /// Used when a new interface is added so the responder won't suppress
2568    /// its response due to known-answer suppression (RFC 6762 Section 7.1).
2569    fn send_query_on_intf(&self, name: &str, qtype: RRType, intf: &MyIntf) {
2570        let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
2571        out.add_question(name, qtype);
2572
2573        let mut invalid_intf_addrs = HashSet::new();
2574        if let Some(sock) = self.ipv4_sock.as_ref() {
2575            if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2576                send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2577            {
2578                invalid_intf_addrs.insert(intf_addr);
2579            }
2580        }
2581        if let Some(sock) = self.ipv6_sock.as_ref() {
2582            if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2583                send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2584            {
2585                invalid_intf_addrs.insert(intf_addr);
2586            }
2587        }
2588        if !invalid_intf_addrs.is_empty() {
2589            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2590        }
2591    }
2592
2593    /// Sends out a list of `questions` (i.e. DNS questions) via multicast.
2594    fn send_query_vec(&self, questions: &[(&str, RRType)]) {
2595        let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
2596        let now = current_time_millis();
2597
2598        for (name, qtype) in questions {
2599            out.add_question(name, *qtype);
2600
2601            for record in self.cache.get_known_answers(name, *qtype, now) {
2602                /*
2603                RFC 6762 section 7.1: https://datatracker.ietf.org/doc/html/rfc6762#section-7.1
2604                ...
2605                    When a Multicast DNS querier sends a query to which it already knows
2606                    some answers, it populates the Answer Section of the DNS query
2607                    message with those answers.
2608                 */
2609                trace!("add known answer: {:?}", record.record);
2610                let mut new_record = record.record.clone();
2611                new_record.get_record_mut().update_ttl(now);
2612                out.add_answer_box(new_record);
2613            }
2614        }
2615
2616        let mut invalid_intf_addrs = HashSet::new();
2617        for (_, intf) in self.my_intfs.iter() {
2618            if let Some(sock) = self.ipv4_sock.as_ref() {
2619                if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2620                    send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2621                {
2622                    invalid_intf_addrs.insert(intf_addr);
2623                }
2624            }
2625            if let Some(sock) = self.ipv6_sock.as_ref() {
2626                if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
2627                    send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None)
2628                {
2629                    invalid_intf_addrs.insert(intf_addr);
2630                }
2631            }
2632        }
2633
2634        if !invalid_intf_addrs.is_empty() {
2635            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addrs));
2636        }
2637    }
2638
2639    /// Reads one UDP datagram from the socket of `intf`.
2640    ///
2641    /// Returns false if failed to receive a packet,
2642    /// otherwise returns true.
2643    fn handle_read(&mut self, event_key: usize) -> bool {
2644        let is_ipv4 = event_key == IPV4_SOCK_EVENT_KEY;
2645        let sock_opt = match event_key {
2646            IPV4_SOCK_EVENT_KEY => &mut self.ipv4_sock,
2647            IPV6_SOCK_EVENT_KEY => &mut self.ipv6_sock,
2648            _ => {
2649                debug!("handle_read: unknown token {}", event_key);
2650                return false;
2651            }
2652        };
2653        let Some(sock) = sock_opt.as_mut() else {
2654            debug!("handle_read: socket not available for token {}", event_key);
2655            return false;
2656        };
2657        // The buffer is one byte bigger than the biggest legal message, so that an
2658        // over-sized datagram can be told apart from a legal one that happens to be
2659        // exactly at the limit.
2660        let max_size = max_pkt_absolute(is_ipv4);
2661        let mut buf = vec![0u8; max_size + 1];
2662
2663        // Read the next mDNS UDP datagram.
2664        let (sz, pktinfo) = match sock.pktinfo.recv(&mut buf) {
2665            Ok(sz) => sz,
2666            Err(e) => {
2667                if e.kind() != std::io::ErrorKind::WouldBlock {
2668                    debug!("listening socket read failed: {}", e);
2669                }
2670                return false;
2671            }
2672        };
2673
2674        // RFC 6762 section 17 caps an mDNS packet at 9000 bytes including the IP and
2675        // UDP headers. A datagram over that arrives truncated, and decoding a
2676        // truncated message does not fail cleanly: names run into whatever bytes
2677        // follow, yielding bogus records or confusing parse errors. Drop it instead.
2678        //
2679        // On Windows, `recv` fails with WSAEMSGSIZE for such a datagram instead of
2680        // truncating it, so it is dropped by the error branch above. Either way it
2681        // is never decoded.
2682        if sz > max_size {
2683            debug!(
2684                "handle_read: dropping over-sized datagram of at least {} bytes (max {})",
2685                sz, max_size
2686            );
2687            return true; // We still read something.
2688        }
2689
2690        // Find the interface that received the packet.
2691        let pkt_if_index = pktinfo.if_index as u32;
2692        let Some(my_intf) = self.my_intfs.get(&pkt_if_index) else {
2693            debug!(
2694                "handle_read: no interface found for pktinfo if_index: {}",
2695                pktinfo.if_index
2696            );
2697            return true; // We still return true to indicate that we read something.
2698        };
2699
2700        // Drop packets for an IP version that has been disabled on this interface.
2701        // This is needed because some times the socket layer may still receive packets
2702        // for an IP version even after we left the multicast group for that IP version.
2703        // We want to drop such packets to avoid unnecessary processing.
2704        let is_ipv4 = event_key == IPV4_SOCK_EVENT_KEY;
2705        if (is_ipv4 && my_intf.next_ifaddr_v4().is_none())
2706            || (!is_ipv4 && my_intf.next_ifaddr_v6().is_none())
2707        {
2708            debug!(
2709                "handle_read: dropping {} packet on intf {} (disabled)",
2710                if is_ipv4 { "IPv4" } else { "IPv6" },
2711                my_intf.name
2712            );
2713            return true;
2714        }
2715
2716        buf.truncate(sz); // reduce potential processing errors
2717
2718        match DnsIncoming::new(buf, my_intf.into()) {
2719            Ok(msg) => {
2720                if msg.is_query() {
2721                    let querier_addr = pktinfo.addr_src;
2722                    self.handle_query(msg, pkt_if_index, querier_addr);
2723                } else if msg.is_response() {
2724                    self.handle_response(msg, pkt_if_index);
2725                } else {
2726                    debug!("Invalid message: not query and not response");
2727                }
2728            }
2729            Err(e) => debug!("Invalid incoming DNS message: {}", e),
2730        }
2731
2732        true
2733    }
2734
2735    /// Returns true, if sent query. Returns false if SRV already exists.
2736    fn query_unresolved(&mut self, instance: &str) -> bool {
2737        if !valid_instance_name(instance) {
2738            trace!("instance name {} not valid", instance);
2739            return false;
2740        }
2741
2742        if let Some(records) = self.cache.get_srv(instance) {
2743            for record in records {
2744                if let Some(srv) = record.record.any().downcast_ref::<DnsSrv>() {
2745                    if self.cache.get_addr(srv.host()).is_none() {
2746                        self.send_query_vec(&[(srv.host(), RRType::A), (srv.host(), RRType::AAAA)]);
2747                        return true;
2748                    }
2749                }
2750            }
2751        } else {
2752            self.send_query(instance, RRType::ANY);
2753            return true;
2754        }
2755
2756        false
2757    }
2758
2759    /// Checks if `ty_domain` has records in the cache. If yes, sends the
2760    /// cached records via `sender`.
2761    fn query_cache_for_service(
2762        &mut self,
2763        ty_domain: &str,
2764        sender: &Sender<ServiceEvent>,
2765        now: u64,
2766    ) {
2767        let mut resolved: HashSet<String> = HashSet::new();
2768        let mut unresolved: HashSet<String> = HashSet::new();
2769
2770        if let Some(records) = self.cache.get_ptr(ty_domain) {
2771            for record in records.iter().filter(|r| !r.record.expires_soon(now)) {
2772                if let Some(ptr) = record.record.any().downcast_ref::<DnsPointer>() {
2773                    let mut new_event = None;
2774                    match self.resolve_service_from_cache(ty_domain, ptr.alias()) {
2775                        Ok(resolved_service) => {
2776                            if resolved_service.is_valid() {
2777                                debug!("Resolved service from cache: {}", ptr.alias());
2778                                new_event =
2779                                    Some(ServiceEvent::ServiceResolved(Box::new(resolved_service)));
2780                            } else {
2781                                debug!("Resolved service is not valid: {}", ptr.alias());
2782                            }
2783                        }
2784                        Err(err) => {
2785                            debug!("Error while resolving service from cache: {}", err);
2786                            continue;
2787                        }
2788                    }
2789
2790                    match sender.send(ServiceEvent::ServiceFound(
2791                        ty_domain.to_string(),
2792                        ptr.alias().to_string(),
2793                    )) {
2794                        Ok(()) => debug!("sent service found {}", ptr.alias()),
2795                        Err(e) => {
2796                            debug!("failed to send service found: {}", e);
2797                            continue;
2798                        }
2799                    }
2800
2801                    if let Some(event) = new_event {
2802                        resolved.insert(ptr.alias().to_string());
2803                        match sender.send(event) {
2804                            Ok(()) => debug!("sent service resolved: {}", ptr.alias()),
2805                            Err(e) => debug!("failed to send service resolved: {}", e),
2806                        }
2807                    } else {
2808                        unresolved.insert(ptr.alias().to_string());
2809                    }
2810                }
2811            }
2812        }
2813
2814        for instance in resolved.drain() {
2815            self.pending_resolves.remove(&instance);
2816            self.resolved.insert(instance);
2817        }
2818
2819        for instance in unresolved.drain() {
2820            self.add_pending_resolve(instance);
2821        }
2822    }
2823
2824    /// Checks if `hostname` has records in the cache. If yes, sends the
2825    /// cached records via `sender`.
2826    fn query_cache_for_hostname(
2827        &mut self,
2828        hostname: &str,
2829        sender: Sender<HostnameResolutionEvent>,
2830    ) {
2831        let addresses_map = self.cache.get_addresses_for_host(hostname);
2832        for (name, addresses) in addresses_map {
2833            match sender.send(HostnameResolutionEvent::AddressesFound(name, addresses)) {
2834                Ok(()) => trace!("sent hostname addresses found"),
2835                Err(e) => debug!("failed to send hostname addresses found: {}", e),
2836            }
2837        }
2838    }
2839
2840    fn add_pending_resolve(&mut self, instance: String) {
2841        if !self.pending_resolves.contains(&instance) {
2842            let next_time = current_time_millis() + RESOLVE_WAIT_IN_MILLIS;
2843            self.add_retransmission(next_time, Command::Resolve(instance.clone(), 1));
2844            self.pending_resolves.insert(instance);
2845        }
2846    }
2847
2848    /// Creates a `ResolvedService` from the cache.
2849    fn resolve_service_from_cache(
2850        &self,
2851        ty_domain: &str,
2852        fullname: &str,
2853    ) -> Result<ResolvedService> {
2854        let now = current_time_millis();
2855        let mut resolved_service = ResolvedService {
2856            ty_domain: ty_domain.to_string(),
2857            sub_ty_domain: None,
2858            fullname: fullname.to_string(),
2859            host: String::new(),
2860            port: 0,
2861            addresses: HashSet::new(),
2862            txt_properties: TxtProperties::new(),
2863        };
2864
2865        // Be sure setting `subtype` if available even when querying for the parent domain.
2866        if let Some(subtype) = self.cache.get_subtype(fullname) {
2867            trace!(
2868                "ty_domain: {} found subtype {} for instance: {}",
2869                ty_domain,
2870                subtype,
2871                fullname
2872            );
2873            if resolved_service.sub_ty_domain.is_none() {
2874                resolved_service.sub_ty_domain = Some(subtype.to_string());
2875            }
2876        }
2877
2878        // resolve SRV record
2879        if let Some(records) = self.cache.get_srv(fullname) {
2880            if let Some(answer) = records.iter().find(|r| !r.record.expires_soon(now)) {
2881                if let Some(dns_srv) = answer.record.any().downcast_ref::<DnsSrv>() {
2882                    resolved_service.host = dns_srv.host().to_string();
2883                    resolved_service.port = dns_srv.port();
2884                }
2885            }
2886        }
2887
2888        // resolve TXT record
2889        if let Some(records) = self.cache.get_txt(fullname) {
2890            if let Some(record) = records.iter().find(|r| !r.record.expires_soon(now)) {
2891                if let Some(dns_txt) = record.record.any().downcast_ref::<DnsTxt>() {
2892                    resolved_service.txt_properties = dns_txt.text().into();
2893                }
2894            }
2895        }
2896
2897        // resolve A and AAAA records
2898        if let Some(records) = self.cache.get_addr(&resolved_service.host) {
2899            for answer in records.iter() {
2900                if let Some(dns_a) = answer.record.any().downcast_ref::<DnsAddress>() {
2901                    if dns_a.expires_soon(now) {
2902                        trace!(
2903                            "Addr expired or expires soon: {}",
2904                            dns_a.address().to_ip_addr()
2905                        );
2906                    } else {
2907                        let scoped = dns_a.address();
2908                        if let ScopedIp::V4(v4) = &scoped {
2909                            // Merge interface_ids if this V4 addr already exists.
2910                            // Linear scan by IP since Eq/Hash include interface_ids.
2911                            let existing = resolved_service
2912                                .addresses
2913                                .iter()
2914                                .find(|a| a.to_ip_addr() == IpAddr::V4(*v4.addr()))
2915                                .cloned();
2916                            if let Some(mut existing) = existing {
2917                                resolved_service.addresses.remove(&existing);
2918                                if let ScopedIp::V4(existing_v4) = &mut existing {
2919                                    for id in v4.interface_ids() {
2920                                        existing_v4.add_interface_id(id.clone());
2921                                    }
2922                                }
2923                                resolved_service.addresses.insert(existing);
2924                            } else {
2925                                resolved_service.addresses.insert(scoped);
2926                            }
2927                        } else {
2928                            resolved_service.addresses.insert(scoped);
2929                        }
2930                    }
2931                }
2932            }
2933        }
2934
2935        Ok(resolved_service)
2936    }
2937
2938    fn handle_poller_events(&mut self, events: &mio::Events) {
2939        for ev in events.iter() {
2940            trace!("event received with key {:?}", ev.token());
2941            if ev.token().0 == SIGNAL_SOCK_EVENT_KEY {
2942                // Drain signals as we will drain commands as well.
2943                self.signal_sock_drain();
2944
2945                if let Err(e) = self.poller.registry().reregister(
2946                    &mut self.signal_sock,
2947                    ev.token(),
2948                    mio::Interest::READABLE,
2949                ) {
2950                    debug!("failed to modify poller for signal socket: {}", e);
2951                }
2952                continue; // Next event.
2953            }
2954
2955            // Read until no more packets available.
2956            while self.handle_read(ev.token().0) {}
2957
2958            // we continue to monitor this socket.
2959            if ev.token().0 == IPV4_SOCK_EVENT_KEY {
2960                // Re-register the IPv4 socket for reading.
2961                if let Some(sock) = self.ipv4_sock.as_mut() {
2962                    if let Err(e) =
2963                        self.poller
2964                            .registry()
2965                            .reregister(sock, ev.token(), mio::Interest::READABLE)
2966                    {
2967                        debug!("modify poller for IPv4 socket: {}", e);
2968                    }
2969                }
2970            } else if ev.token().0 == IPV6_SOCK_EVENT_KEY {
2971                // Re-register the IPv6 socket for reading.
2972                if let Some(sock) = self.ipv6_sock.as_mut() {
2973                    if let Err(e) =
2974                        self.poller
2975                            .registry()
2976                            .reregister(sock, ev.token(), mio::Interest::READABLE)
2977                    {
2978                        debug!("modify poller for IPv6 socket: {}", e);
2979                    }
2980                }
2981            }
2982        }
2983    }
2984
2985    /// Deal with incoming response packets.  All answers
2986    /// are held in the cache, and listeners are notified.
2987    fn handle_response(&mut self, mut msg: DnsIncoming, if_index: u32) {
2988        let now = current_time_millis();
2989
2990        // remove records that are expired.
2991        let mut record_predicate = |record: &DnsRecordBox| {
2992            if !record.get_record().is_expired(now) {
2993                return true;
2994            }
2995
2996            debug!("record is expired, removing it from cache.");
2997            if self.cache.remove(record) {
2998                // for PTR records, send event to listeners
2999                if let Some(dns_ptr) = record.any().downcast_ref::<DnsPointer>() {
3000                    call_service_listener(
3001                        &self.service_queriers,
3002                        dns_ptr.get_name(),
3003                        ServiceEvent::ServiceRemoved(
3004                            dns_ptr.get_name().to_string(),
3005                            dns_ptr.alias().to_string(),
3006                        ),
3007                    );
3008                }
3009            }
3010            false
3011        };
3012        msg.answers_mut().retain(&mut record_predicate);
3013        msg.authorities_mut().retain(&mut record_predicate);
3014        msg.additionals_mut().retain(&mut record_predicate);
3015
3016        // check possible conflicts and handle them.
3017        self.conflict_handler(&msg, if_index);
3018
3019        // check if the message is for us.
3020        let mut is_for_us = true; // assume it is for us.
3021
3022        // If there are any PTR records in the answers, there should be
3023        // at least one PTR for us. Otherwise, the message is not for us.
3024        // If there are no PTR records at all, assume this message is for us.
3025        for answer in msg.answers() {
3026            if answer.get_type() == RRType::PTR {
3027                if self.service_queriers.contains_key(answer.get_name()) {
3028                    is_for_us = true;
3029                    break; // OK to break: at least one PTR for us.
3030                } else {
3031                    is_for_us = false;
3032                }
3033            } else if answer.get_type() == RRType::A || answer.get_type() == RRType::AAAA {
3034                // If there is a hostname querier for this address, then it is for us.
3035                let answer_lowercase = answer.get_name().to_lowercase();
3036                if self.hostname_resolvers.contains_key(&answer_lowercase) {
3037                    is_for_us = true;
3038                    break; // OK to break: at least one hostname for us.
3039                }
3040            }
3041        }
3042
3043        // if we explicitily want to accept unsolicited responses, we should consider all messages as for us.
3044        if self.accept_unsolicited {
3045            is_for_us = true;
3046        }
3047
3048        /// Represents a DNS record change that involves one service instance.
3049        struct InstanceChange {
3050            ty: RRType,   // The type of DNS record for the instance.
3051            name: String, // The name of the record.
3052        }
3053
3054        // Go through all answers to get the new and updated records.
3055        // For new PTR records, send out ServiceFound immediately. For others,
3056        // collect them into `changes`.
3057        //
3058        // Note: we don't try to identify the update instances based on
3059        // each record immediately as the answers are likely related to each
3060        // other.
3061        let mut changes = Vec::new();
3062        let mut timers = Vec::new();
3063        let Some(my_intf) = self.my_intfs.get(&if_index) else {
3064            return;
3065        };
3066        for record in msg.all_records() {
3067            match self
3068                .cache
3069                .add_or_update(my_intf, record, &mut timers, is_for_us)
3070            {
3071                Some((dns_record, true)) => {
3072                    timers.push(dns_record.record.get_record().get_expire_time());
3073                    timers.push(dns_record.record.get_record().get_refresh_time());
3074
3075                    let ty = dns_record.record.get_type();
3076                    let name = dns_record.record.get_name();
3077
3078                    // Only process PTR that does not expire soon (i.e. TTL > 1).
3079                    if ty == RRType::PTR && dns_record.record.get_record().get_ttl() > 1 {
3080                        if self.service_queriers.contains_key(name) {
3081                            timers.push(dns_record.record.get_record().get_refresh_time());
3082                        }
3083
3084                        // send ServiceFound
3085                        if let Some(dns_ptr) = dns_record.record.any().downcast_ref::<DnsPointer>()
3086                        {
3087                            debug!("calling listener with service found: {name}");
3088                            call_service_listener(
3089                                &self.service_queriers,
3090                                name,
3091                                ServiceEvent::ServiceFound(
3092                                    name.to_string(),
3093                                    dns_ptr.alias().to_string(),
3094                                ),
3095                            );
3096                            changes.push(InstanceChange {
3097                                ty,
3098                                name: dns_ptr.alias().to_string(),
3099                            });
3100                        }
3101                    } else {
3102                        changes.push(InstanceChange {
3103                            ty,
3104                            name: name.to_string(),
3105                        });
3106                    }
3107                }
3108                Some((dns_record, false)) => {
3109                    timers.push(dns_record.record.get_record().get_expire_time());
3110                    timers.push(dns_record.record.get_record().get_refresh_time());
3111                }
3112                _ => {}
3113            }
3114        }
3115
3116        // Add timers for the new records.
3117        for t in timers {
3118            self.add_timer(t);
3119        }
3120
3121        // Go through remaining changes to see if any hostname resolutions were found or updated.
3122        for change in changes
3123            .iter()
3124            .filter(|change| change.ty == RRType::A || change.ty == RRType::AAAA)
3125        {
3126            let addr_map = self.cache.get_addresses_for_host(&change.name);
3127            for (name, addresses) in addr_map {
3128                call_hostname_resolution_listener(
3129                    &self.hostname_resolvers,
3130                    &change.name,
3131                    HostnameResolutionEvent::AddressesFound(name, addresses),
3132                )
3133            }
3134        }
3135
3136        // Identify the instances that need to be "resolved".
3137        let mut updated_instances = HashSet::new();
3138        for update in changes {
3139            match update.ty {
3140                RRType::PTR | RRType::SRV | RRType::TXT => {
3141                    updated_instances.insert(update.name);
3142                }
3143                RRType::A | RRType::AAAA => {
3144                    let instances = self.cache.get_instances_on_host(&update.name);
3145                    updated_instances.extend(instances);
3146                }
3147                _ => {}
3148            }
3149        }
3150
3151        self.resolve_updated_instances(&updated_instances);
3152    }
3153
3154    fn conflict_handler(&mut self, msg: &DnsIncoming, if_index: u32) {
3155        let Some(my_intf) = self.my_intfs.get(&if_index) else {
3156            debug!("handle_response: no intf found for index {if_index}");
3157            return;
3158        };
3159
3160        let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) else {
3161            return;
3162        };
3163
3164        for answer in msg.answers().iter() {
3165            let mut new_records = Vec::new();
3166
3167            let name = answer.get_name();
3168            let Some(probe) = dns_registry.probing.get_mut(name) else {
3169                continue;
3170            };
3171
3172            // check against possible multicast forwarding
3173            if answer.get_type() == RRType::A || answer.get_type() == RRType::AAAA {
3174                if let Some(answer_addr) = answer.any().downcast_ref::<DnsAddress>() {
3175                    if answer_addr.interface_id.index != if_index {
3176                        debug!(
3177                            "conflict handler: answer addr {:?} not in the subnet of intf {}",
3178                            answer_addr, my_intf.name
3179                        );
3180                        continue;
3181                    }
3182                }
3183
3184                // double check if any other address record matches rrdata,
3185                // as there could be multiple addresses for the same name.
3186                let any_match = probe.records.iter().any(|r| {
3187                    r.get_type() == answer.get_type()
3188                        && r.get_class() == answer.get_class()
3189                        && r.rrdata_match(answer.as_ref())
3190                });
3191                if any_match {
3192                    continue; // no conflict for this answer.
3193                }
3194            }
3195
3196            probe.records.retain(|record| {
3197                if record.get_type() == answer.get_type()
3198                    && record.get_class() == answer.get_class()
3199                    && !record.rrdata_match(answer.as_ref())
3200                {
3201                    debug!(
3202                        "found conflict name: '{name}' record: {}: {} PEER: {}",
3203                        record.get_type(),
3204                        record.rdata_print(),
3205                        answer.rdata_print()
3206                    );
3207
3208                    // create a new name for this record
3209                    // then remove the old record in probing.
3210                    let mut new_record = record.clone();
3211                    let new_name = match record.get_type() {
3212                        RRType::A => hostname_change(name),
3213                        RRType::AAAA => hostname_change(name),
3214                        _ => name_change(name),
3215                    };
3216                    new_record.get_record_mut().set_new_name(new_name);
3217                    new_records.push(new_record);
3218                    return false; // old record is dropped from the probe.
3219                }
3220
3221                true
3222            });
3223
3224            // ?????
3225            // if probe.records.is_empty() {
3226            //     dns_registry.probing.remove(name);
3227            // }
3228
3229            // Probing again with the new names.
3230            let create_time = current_time_millis() + fastrand::u64(0..250);
3231
3232            let waiting_services = probe.waiting_services.clone();
3233
3234            for record in new_records {
3235                if dns_registry.update_hostname(name, record.get_name(), create_time) {
3236                    self.timers.push(Reverse(create_time));
3237                }
3238
3239                // remember the name changes (note: `name` might not be the original, it could be already changed once.)
3240                dns_registry.name_changes.insert(
3241                    record.get_record().get_original_name().to_string(),
3242                    record.get_name().to_string(),
3243                );
3244
3245                let new_probe = match dns_registry.probing.get_mut(record.get_name()) {
3246                    Some(p) => p,
3247                    None => {
3248                        let new_probe = dns_registry
3249                            .probing
3250                            .entry(record.get_name().to_string())
3251                            .or_insert_with(|| {
3252                                debug!("conflict handler: new probe of {}", record.get_name());
3253                                Probe::new(create_time)
3254                            });
3255                        self.timers.push(Reverse(new_probe.next_send));
3256                        new_probe
3257                    }
3258                };
3259
3260                debug!(
3261                    "insert record with new name '{}' {} into probe",
3262                    record.get_name(),
3263                    record.get_type()
3264                );
3265                new_probe.insert_record(record);
3266
3267                new_probe.waiting_services.extend(waiting_services.clone());
3268            }
3269        }
3270    }
3271
3272    /// Resolve the updated (including new) instances.
3273    ///
3274    /// Note: it is possible that more than 1 PTR pointing to the same
3275    /// instance. For example, a regular service type PTR and a sub-type
3276    /// service type PTR can both point to the same service instance.
3277    /// This loop automatically handles the sub-type PTRs.
3278    fn resolve_updated_instances(&mut self, updated_instances: &HashSet<String>) {
3279        if updated_instances.is_empty() {
3280            return;
3281        }
3282
3283        let mut resolved: HashSet<String> = HashSet::new();
3284        let mut unresolved: HashSet<String> = HashSet::new();
3285        let mut removed_instances = HashMap::new();
3286
3287        let now = current_time_millis();
3288
3289        for (ty_domain, records) in self.cache.all_ptr().iter() {
3290            if !self.service_queriers.contains_key(ty_domain) {
3291                // No need to resolve if not in our queries.
3292                continue;
3293            }
3294
3295            for ptr in records.iter().filter(|r| !r.record.expires_soon(now)) {
3296                let Some(dns_ptr) = ptr.record.any().downcast_ref::<DnsPointer>() else {
3297                    continue;
3298                };
3299
3300                let instance = dns_ptr.alias();
3301                if !updated_instances.contains(instance) {
3302                    continue;
3303                }
3304
3305                let Ok(resolved_service) = self.resolve_service_from_cache(ty_domain, instance)
3306                else {
3307                    continue;
3308                };
3309
3310                debug!("resolve_updated_instances: from cache: {instance}");
3311                if resolved_service.is_valid() {
3312                    debug!("call queriers to resolve {instance}");
3313                    resolved.insert(instance.to_string());
3314                    let event = ServiceEvent::ServiceResolved(Box::new(resolved_service));
3315                    call_service_listener(&self.service_queriers, ty_domain, event);
3316                } else {
3317                    debug!("Resolved service is not valid: {instance}");
3318                    if self.resolved.remove(dns_ptr.alias()) {
3319                        removed_instances
3320                            .entry(ty_domain.to_string())
3321                            .or_insert_with(HashSet::new)
3322                            .insert(instance.to_string());
3323                    }
3324                    unresolved.insert(instance.to_string());
3325                }
3326            }
3327        }
3328
3329        for instance in resolved.drain() {
3330            self.pending_resolves.remove(&instance);
3331            self.resolved.insert(instance);
3332        }
3333
3334        for instance in unresolved.drain() {
3335            self.add_pending_resolve(instance);
3336        }
3337
3338        if !removed_instances.is_empty() {
3339            debug!(
3340                "resolve_updated_instances: removed {}",
3341                &removed_instances.len()
3342            );
3343            self.notify_service_removal(removed_instances);
3344        }
3345    }
3346
3347    /// Handle incoming query packets, figure out whether and what to respond.
3348    fn handle_query(&mut self, msg: DnsIncoming, if_index: u32, querier_addr: SocketAddr) {
3349        let querier_ip = querier_addr.ip();
3350        let is_ipv4 = querier_ip.is_ipv4();
3351        let sock_opt = if is_ipv4 {
3352            &self.ipv4_sock
3353        } else {
3354            &self.ipv6_sock
3355        };
3356        let Some(sock) = sock_opt.as_ref() else {
3357            debug!("handle_query: socket not available for intf {}", if_index);
3358            return;
3359        };
3360
3361        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
3362        let mut delayed = false;
3363
3364        // Special meta-query "_services._dns-sd._udp.<Domain>".
3365        // See https://datatracker.ietf.org/doc/html/rfc6763#section-9
3366        const META_QUERY: &str = "_services._dns-sd._udp.local.";
3367
3368        let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) else {
3369            debug!("missing dns registry for intf {}", if_index);
3370            return;
3371        };
3372
3373        let Some(intf) = self.my_intfs.get(&if_index) else {
3374            debug!("handle_query: no intf found for index {if_index}");
3375            return;
3376        };
3377
3378        for question in msg.questions().iter() {
3379            let qtype = question.entry_type();
3380            let q_name = question.entry_name();
3381
3382            if qtype == RRType::PTR {
3383                // PTR answers are shared records: defer the response unless this
3384                // is a legacy-unicast (source port != 5353) or probe-defense
3385                // (records in the Authority Section) query.
3386                if querier_addr.port() == MDNS_PORT && msg.num_authorities() == 0 {
3387                    delayed = true;
3388                }
3389                for service in self.my_services.values() {
3390                    if service.get_status(if_index) != ServiceStatus::Announced {
3391                        continue;
3392                    }
3393
3394                    if service.matches_type_or_subtype(q_name) {
3395                        out.add_answer_with_additionals(&msg, service, intf, dns_registry, is_ipv4);
3396                    } else if q_name == META_QUERY {
3397                        let ttl = service.get_other_ttl();
3398                        let alias = service.get_type().to_string();
3399                        let ptr = DnsPointer::new(q_name, RRType::PTR, CLASS_IN, ttl, alias);
3400                        if !out.add_answer(&msg, ptr) {
3401                            trace!("answer was not added for meta-query {:?}", &question);
3402                        }
3403                    }
3404                }
3405            } else {
3406                // Simultaneous Probe Tiebreaking (RFC 6762 section 8.2)
3407                if qtype == RRType::ANY && msg.num_authorities() > 0 {
3408                    if let Some(probe) = dns_registry.probing.get_mut(q_name) {
3409                        probe.tiebreaking(&msg, q_name);
3410                    }
3411                }
3412
3413                if qtype == RRType::A || qtype == RRType::AAAA || qtype == RRType::ANY {
3414                    for service in self.my_services.values() {
3415                        if service.get_status(if_index) != ServiceStatus::Announced {
3416                            continue;
3417                        }
3418
3419                        let service_hostname = dns_registry.resolve_name(service.get_hostname());
3420
3421                        if service_hostname.to_lowercase() == question.entry_name().to_lowercase() {
3422                            // Pick addresses based on the question type, not the
3423                            // socket family. RFC 6762 doesn't require A queries
3424                            // to come over IPv4 transport — Android's getaddrinfo
3425                            // routinely sends both A and AAAA queries over its
3426                            // preferred IPv6 mDNS socket and expects A records
3427                            // to be answered with v4 addresses.
3428                            let mut intf_addrs: Vec<IpAddr> = Vec::new();
3429                            if qtype == RRType::A || qtype == RRType::ANY {
3430                                intf_addrs.extend(service.get_addrs_on_my_intf_v4(intf));
3431                            }
3432                            if qtype == RRType::AAAA || qtype == RRType::ANY {
3433                                intf_addrs.extend(service.get_addrs_on_my_intf_v6(intf));
3434                            }
3435                            if intf_addrs.is_empty()
3436                                && (qtype == RRType::A || qtype == RRType::AAAA)
3437                            {
3438                                let t = match qtype {
3439                                    RRType::A => "TYPE_A",
3440                                    RRType::AAAA => "TYPE_AAAA",
3441                                    _ => "invalid_type",
3442                                };
3443                                trace!(
3444                                    "Cannot find valid addrs for {} response on intf {:?}",
3445                                    t,
3446                                    &intf
3447                                );
3448                                continue;
3449                            }
3450                            for address in intf_addrs {
3451                                out.add_answer(
3452                                    &msg,
3453                                    DnsAddress::new(
3454                                        service_hostname,
3455                                        ip_address_rr_type(&address),
3456                                        CLASS_IN | CLASS_CACHE_FLUSH,
3457                                        service.get_host_ttl(),
3458                                        address,
3459                                        intf.into(),
3460                                    ),
3461                                );
3462                            }
3463                        }
3464                    }
3465                }
3466
3467                let query_name = q_name.to_lowercase();
3468                let service_opt = self
3469                    .my_services
3470                    .iter()
3471                    .find(|(k, _v)| dns_registry.resolve_name(k.as_str()) == query_name)
3472                    .map(|(_, v)| v);
3473
3474                let Some(service) = service_opt else {
3475                    continue;
3476                };
3477
3478                if service.get_status(if_index) != ServiceStatus::Announced {
3479                    continue;
3480                }
3481
3482                let intf_addrs = if is_ipv4 {
3483                    service.get_addrs_on_my_intf_v4(intf)
3484                } else {
3485                    service.get_addrs_on_my_intf_v6(intf)
3486                };
3487                if intf_addrs.is_empty() {
3488                    debug!(
3489                        "Cannot find valid addrs for TYPE_SRV response on intf {:?}",
3490                        &intf
3491                    );
3492                    continue;
3493                }
3494
3495                add_answer_of_service(
3496                    &mut out,
3497                    &msg,
3498                    question.entry_name(),
3499                    service,
3500                    qtype,
3501                    intf_addrs,
3502                );
3503            }
3504        }
3505
3506        // Defer PTR responses (RFC 6762 §6).
3507        if delayed && out.answers_count() > 0 {
3508            out.set_id(msg.id());
3509            self.increase_counter(Counter::KnownAnswerSuppression, out.known_answer_count());
3510            let delay =
3511                fastrand::u64(SHARED_RESPONSE_DELAY_MIN_MILLIS..SHARED_RESPONSE_DELAY_MAX_MILLIS);
3512            let next_time = current_time_millis() + delay;
3513            self.delayed_responses.push(DelayedResponse {
3514                next_time,
3515                out,
3516                if_index,
3517                is_ipv4,
3518            });
3519            self.add_timer(next_time);
3520            return;
3521        }
3522
3523        if out.answers_count() > 0 {
3524            out.set_id(msg.id());
3525
3526            // Pick a source IfAddr on `intf` whose subnet contains the querier's IP.
3527            // It's OK if it's None, `send_dns_outgoing` will then pick one address.
3528            let matched_source = intf
3529                .addrs
3530                .iter()
3531                .find(|if_addr| valid_ip_on_intf(&querier_ip, if_addr));
3532
3533            // RFC 6762 §6.7 (Legacy Unicast Responses): if the querier's source
3534            // port is not 5353, it's a one-shot legacy querier (e.g. Android's
3535            // getaddrinfo, iOS resolver fallback). The response MUST be unicast
3536            // back to the querier's source IP and port; multicast replies will
3537            // never reach the querier's ephemeral socket. Legacy unicast
3538            // responses must also echo the question section and clear the
3539            // cache-flush bit, since legacy resolvers don't understand it.
3540            let unicast_dest = if querier_addr.port() != MDNS_PORT {
3541                Some(querier_addr)
3542            } else {
3543                None
3544            };
3545
3546            if unicast_dest.is_some() {
3547                for q in msg.questions() {
3548                    out.add_question(q.entry_name(), q.entry_type());
3549                }
3550                out.clear_cache_flush_bits();
3551            } else if msg.num_authorities() == 0 {
3552                // RFC 6762 §6: a record MUST NOT be multicast on an interface
3553                // more than once per second. Two exceptions skip the limit here:
3554                //   - Unicast responses (handled above).
3555                //   - Answering probe queries: a probe carries the proposed
3556                //     records in its Authority Section, and we MUST defend our
3557                //     records immediately so the prober detects the conflict.
3558                dns_registry.apply_multicast_rate_limit(&mut out, current_time_millis(), is_ipv4);
3559            }
3560
3561            if out.answers_count() > 0 {
3562                debug!("sending response on intf {}", &intf.name);
3563                if let Err(InternalError::IntfAddrInvalid(intf_addr)) = send_dns_outgoing(
3564                    &out,
3565                    intf,
3566                    &sock.pktinfo,
3567                    self.port,
3568                    matched_source,
3569                    unicast_dest,
3570                ) {
3571                    let invalid_intf_addr = HashSet::from([intf_addr]);
3572                    let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addr));
3573                }
3574
3575                let if_name = intf.name.clone();
3576
3577                self.increase_counter(Counter::Respond, 1);
3578                self.notify_monitors(DaemonEvent::Respond(if_name));
3579            }
3580        }
3581
3582        self.increase_counter(Counter::KnownAnswerSuppression, out.known_answer_count());
3583    }
3584
3585    /// Multicasts a PTR query response that was deferred per RFC 6762 §6.
3586    ///
3587    /// Re-resolves the socket and interface from `if_index`, so it is safe to
3588    /// call from the timer loop after the borrows taken while building the
3589    /// response are gone. The original querier is no longer known, so the
3590    /// response is always a plain multicast (no unicast destination, no
3591    /// source-address preference); the §6 once-per-second multicast rate limit
3592    /// still applies.
3593    fn send_delayed_response(&mut self, resp: DelayedResponse) {
3594        let DelayedResponse {
3595            mut out,
3596            if_index,
3597            is_ipv4,
3598            ..
3599        } = resp;
3600
3601        let sock_opt = if is_ipv4 {
3602            &self.ipv4_sock
3603        } else {
3604            &self.ipv6_sock
3605        };
3606        let Some(sock) = sock_opt.as_ref() else {
3607            debug!("send_delayed_response: socket not available for intf {if_index}");
3608            return;
3609        };
3610
3611        if let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) {
3612            dns_registry.apply_multicast_rate_limit(&mut out, current_time_millis(), is_ipv4);
3613        }
3614        if out.answers_count() == 0 {
3615            return;
3616        }
3617
3618        let Some(intf) = self.my_intfs.get(&if_index) else {
3619            debug!("send_delayed_response: no intf found for index {if_index}");
3620            return;
3621        };
3622
3623        let if_name = intf.name.clone();
3624        debug!("sending delayed response on intf {}", &if_name);
3625        let send_result = send_dns_outgoing(&out, intf, &sock.pktinfo, self.port, None, None);
3626
3627        if let Err(InternalError::IntfAddrInvalid(intf_addr)) = send_result {
3628            let invalid_intf_addr = HashSet::from([intf_addr]);
3629            let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addr));
3630        }
3631
3632        self.increase_counter(Counter::Respond, 1);
3633        self.notify_monitors(DaemonEvent::Respond(if_name));
3634    }
3635
3636    /// Increases the value of `counter` by `count`.
3637    fn increase_counter(&mut self, counter: Counter, count: i64) {
3638        let key = counter.to_string();
3639        match self.counters.get_mut(&key) {
3640            Some(v) => *v += count,
3641            None => {
3642                self.counters.insert(key, count);
3643            }
3644        }
3645    }
3646
3647    /// Sets the value of `counter` to `count`.
3648    fn set_counter(&mut self, counter: Counter, count: i64) {
3649        let key = counter.to_string();
3650        self.counters.insert(key, count);
3651    }
3652
3653    fn signal_sock_drain(&self) {
3654        let mut signal_buf = [0; 1024];
3655
3656        // This recv is non-blocking as the socket is non-blocking.
3657        while let Ok(sz) = self.signal_sock.recv(&mut signal_buf) {
3658            trace!(
3659                "signal socket recvd: {}",
3660                String::from_utf8_lossy(&signal_buf[0..sz])
3661            );
3662        }
3663    }
3664
3665    fn add_retransmission(&mut self, next_time: u64, command: Command) {
3666        self.retransmissions.push(ReRun { next_time, command });
3667        self.add_timer(next_time);
3668    }
3669
3670    /// Sends service removal event to listeners for expired service records.
3671    /// `expired`: map of service type domain to set of instance names.
3672    fn notify_service_removal(&self, expired: HashMap<String, HashSet<String>>) {
3673        for (ty_domain, sender) in self.service_queriers.iter() {
3674            if let Some(instances) = expired.get(ty_domain) {
3675                for instance_name in instances {
3676                    let event = ServiceEvent::ServiceRemoved(
3677                        ty_domain.to_string(),
3678                        instance_name.to_string(),
3679                    );
3680                    match sender.send(event) {
3681                        Ok(()) => debug!("notify_service_removal: sent ServiceRemoved to listener of {ty_domain}: {instance_name}"),
3682                        Err(e) => debug!("Failed to send event: {}", e),
3683                    }
3684                }
3685            }
3686        }
3687    }
3688
3689    /// The entry point that executes all commands received by the daemon.
3690    ///
3691    /// `repeating`: whether this is a retransmission.
3692    fn exec_command(&mut self, command: Command, repeating: bool) {
3693        trace!("exec_command: {:?} repeating: {}", &command, repeating);
3694        match command {
3695            Command::Browse(ty, next_delay, cache_only, listener) => {
3696                self.exec_command_browse(repeating, ty, next_delay, cache_only, listener);
3697            }
3698
3699            Command::ResolveHostname(hostname, next_delay, listener, timeout) => {
3700                self.exec_command_resolve_hostname(
3701                    repeating, hostname, next_delay, listener, timeout,
3702                );
3703            }
3704
3705            Command::Register(service_info) => {
3706                self.register_service(*service_info);
3707                self.increase_counter(Counter::Register, 1);
3708            }
3709
3710            Command::RegisterResend(fullname, intf) => {
3711                trace!("register-resend service: {fullname} on {}", &intf);
3712                if let Err(InternalError::IntfAddrInvalid(intf_addr)) =
3713                    self.exec_command_register_resend(fullname, intf)
3714                {
3715                    let invalid_intf_addr = HashSet::from([intf_addr]);
3716                    let _ = self.send_cmd_to_self(Command::InvalidIntfAddrs(invalid_intf_addr));
3717                }
3718            }
3719
3720            Command::Unregister(fullname, resp_s) => {
3721                trace!("unregister service {} repeat {}", &fullname, &repeating);
3722                self.exec_command_unregister(repeating, fullname, resp_s);
3723            }
3724
3725            Command::UnregisterResend(packet, if_index, is_ipv4) => {
3726                self.exec_command_unregister_resend(packet, if_index, is_ipv4);
3727            }
3728
3729            Command::StopBrowse(ty_domain) => self.exec_command_stop_browse(ty_domain),
3730
3731            Command::StopResolveHostname(hostname) => {
3732                self.exec_command_stop_resolve_hostname(hostname.to_lowercase())
3733            }
3734
3735            Command::Resolve(instance, try_count) => self.exec_command_resolve(instance, try_count),
3736
3737            Command::GetMetrics(resp_s) => self.exec_command_get_metrics(resp_s),
3738
3739            Command::GetStatus(resp_s) => match resp_s.send(self.status.clone()) {
3740                Ok(()) => trace!("Sent status to the client"),
3741                Err(e) => debug!("Failed to send status: {}", e),
3742            },
3743
3744            Command::Monitor(resp_s) => {
3745                self.monitors.push(resp_s);
3746            }
3747
3748            Command::SetOption(daemon_opt) => {
3749                self.process_set_option(daemon_opt);
3750            }
3751
3752            Command::GetOption(resp_s) => {
3753                let val = DaemonOptionVal {
3754                    _service_name_len_max: self.service_name_len_max,
3755                    ip_check_interval: self.ip_check_interval,
3756                };
3757                if let Err(e) = resp_s.send(val) {
3758                    debug!("Failed to send options: {}", e);
3759                }
3760            }
3761
3762            Command::Verify(instance_fullname, timeout) => {
3763                self.exec_command_verify(instance_fullname, timeout, repeating);
3764            }
3765
3766            Command::InvalidIntfAddrs(invalid_intf_addrs) => {
3767                for intf_addr in invalid_intf_addrs {
3768                    self.del_interface_addr(&intf_addr);
3769                }
3770
3771                self.check_ip_changes();
3772            }
3773
3774            _ => {
3775                debug!("unexpected command: {:?}", &command);
3776            }
3777        }
3778    }
3779
3780    fn exec_command_get_metrics(&mut self, resp_s: Sender<HashMap<String, i64>>) {
3781        self.set_counter(Counter::CachedPTR, self.cache.ptr_count() as i64);
3782        self.set_counter(Counter::CachedSRV, self.cache.srv_count() as i64);
3783        self.set_counter(Counter::CachedAddr, self.cache.addr_count() as i64);
3784        self.set_counter(Counter::CachedTxt, self.cache.txt_count() as i64);
3785        self.set_counter(Counter::CachedNSec, self.cache.nsec_count() as i64);
3786        self.set_counter(Counter::CachedSubtype, self.cache.subtype_count() as i64);
3787        self.set_counter(Counter::Timer, self.timers.len() as i64);
3788
3789        let dns_registry_probe_count: usize = self
3790            .dns_registry_map
3791            .values()
3792            .map(|r| r.probing.len())
3793            .sum();
3794        self.set_counter(Counter::DnsRegistryProbe, dns_registry_probe_count as i64);
3795
3796        let dns_registry_active_count: usize = self
3797            .dns_registry_map
3798            .values()
3799            .map(|r| r.active.values().map(|a| a.len()).sum::<usize>())
3800            .sum();
3801        self.set_counter(Counter::DnsRegistryActive, dns_registry_active_count as i64);
3802
3803        let dns_registry_timer_count: usize = self
3804            .dns_registry_map
3805            .values()
3806            .map(|r| r.new_timers.len())
3807            .sum();
3808        self.set_counter(Counter::DnsRegistryTimer, dns_registry_timer_count as i64);
3809
3810        let dns_registry_name_change_count: usize = self
3811            .dns_registry_map
3812            .values()
3813            .map(|r| r.name_changes.len())
3814            .sum();
3815        self.set_counter(
3816            Counter::DnsRegistryNameChange,
3817            dns_registry_name_change_count as i64,
3818        );
3819
3820        // Send the metrics to the client.
3821        if let Err(e) = resp_s.send(self.counters.clone()) {
3822            debug!("Failed to send metrics: {}", e);
3823        }
3824    }
3825
3826    fn exec_command_browse(
3827        &mut self,
3828        repeating: bool,
3829        ty: String,
3830        next_delay: u32,
3831        cache_only: bool,
3832        listener: Sender<ServiceEvent>,
3833    ) {
3834        let pretty_addrs: Vec<String> = self
3835            .my_intfs
3836            .iter()
3837            .map(|(if_index, itf)| format!("{} ({if_index})", itf.name))
3838            .collect();
3839
3840        if let Err(e) = listener.send(ServiceEvent::SearchStarted(format!(
3841            "{ty} on {} interfaces [{}]",
3842            pretty_addrs.len(),
3843            pretty_addrs.join(", ")
3844        ))) {
3845            debug!(
3846                "Failed to send SearchStarted({})(repeating:{}): {}",
3847                &ty, repeating, e
3848            );
3849            return;
3850        }
3851
3852        let now = current_time_millis();
3853        if !repeating {
3854            // Binds a `listener` to querying mDNS domain type `ty`.
3855            //
3856            // If there is already a `listener`, it will be updated, i.e. overwritten.
3857            self.service_queriers.insert(ty.clone(), listener.clone());
3858
3859            // if we already have the records in our cache, just send them
3860            self.query_cache_for_service(&ty, &listener, now);
3861        }
3862
3863        if cache_only {
3864            // If cache_only is true, we do not send a query.
3865            match listener.send(ServiceEvent::SearchStopped(ty.clone())) {
3866                Ok(()) => debug!("SearchStopped sent for {}", &ty),
3867                Err(e) => debug!("Failed to send SearchStopped: {}", e),
3868            }
3869            return;
3870        }
3871
3872        if !repeating {
3873            // RFC 6762 §5.2: delay the first query by a random jitter.
3874            let jitter =
3875                fastrand::u64(INITIAL_QUERY_DELAY_MIN_MILLIS..INITIAL_QUERY_DELAY_MAX_MILLIS);
3876            self.add_retransmission(now + jitter, Command::Browse(ty, 1, cache_only, listener));
3877            return;
3878        }
3879
3880        self.send_query(&ty, RRType::PTR);
3881        self.increase_counter(Counter::Browse, 1);
3882
3883        let next_time = now + (next_delay * 1000) as u64;
3884        let max_delay = 60 * 60;
3885        let delay = cmp::min(next_delay * 2, max_delay);
3886        self.add_retransmission(next_time, Command::Browse(ty, delay, cache_only, listener));
3887    }
3888
3889    fn exec_command_resolve_hostname(
3890        &mut self,
3891        repeating: bool,
3892        hostname: String,
3893        next_delay: u32,
3894        listener: Sender<HostnameResolutionEvent>,
3895        timeout: Option<u64>,
3896    ) {
3897        let addr_list: Vec<_> = self.my_intfs.iter().collect();
3898        if let Err(e) = listener.send(HostnameResolutionEvent::SearchStarted(format!(
3899            "{} on addrs {:?}",
3900            &hostname, &addr_list
3901        ))) {
3902            debug!(
3903                "Failed to send ResolveStarted({})(repeating:{}): {}",
3904                &hostname, repeating, e
3905            );
3906            return;
3907        }
3908        let now = current_time_millis();
3909        if !repeating {
3910            self.add_hostname_resolver(hostname.to_owned(), listener.clone(), timeout);
3911            // if we already have the records in our cache, just send them
3912            self.query_cache_for_hostname(&hostname, listener.clone());
3913
3914            // RFC 6762 §5.2: delay the first query by a random jitter.
3915            let jitter =
3916                fastrand::u64(INITIAL_QUERY_DELAY_MIN_MILLIS..INITIAL_QUERY_DELAY_MAX_MILLIS);
3917            self.add_retransmission(
3918                now + jitter,
3919                Command::ResolveHostname(hostname, 1, listener, None),
3920            );
3921            return;
3922        }
3923
3924        self.send_query_vec(&[(&hostname, RRType::A), (&hostname, RRType::AAAA)]);
3925        self.increase_counter(Counter::ResolveHostname, 1);
3926
3927        let next_time = now + u64::from(next_delay) * 1000;
3928        let max_delay = 60 * 60;
3929        let delay = cmp::min(next_delay * 2, max_delay);
3930
3931        // Only add retransmission if it does not exceed the hostname resolver timeout, if any.
3932        if self
3933            .hostname_resolvers
3934            .get(&hostname)
3935            .and_then(|(_sender, timeout)| *timeout)
3936            .map(|timeout| next_time < timeout)
3937            .unwrap_or(true)
3938        {
3939            self.add_retransmission(
3940                next_time,
3941                Command::ResolveHostname(hostname, delay, listener, None),
3942            );
3943        }
3944    }
3945
3946    fn exec_command_resolve(&mut self, instance: String, try_count: u16) {
3947        let pending_query = self.query_unresolved(&instance);
3948        let max_try = 3;
3949        if pending_query && try_count < max_try {
3950            // Note that if the current try already succeeds, the next retransmission
3951            // will be no-op as the cache has been updated.
3952            let next_time = current_time_millis() + RESOLVE_WAIT_IN_MILLIS;
3953            self.add_retransmission(next_time, Command::Resolve(instance, try_count + 1));
3954        }
3955    }
3956
3957    fn exec_command_unregister(
3958        &mut self,
3959        repeating: bool,
3960        fullname: String,
3961        resp_s: Sender<UnregisterStatus>,
3962    ) {
3963        let response = match self.my_services.remove_entry(&fullname) {
3964            None => {
3965                debug!("unregister: cannot find such service {}", &fullname);
3966                UnregisterStatus::NotFound
3967            }
3968            Some((_k, info)) => {
3969                let mut timers = Vec::new();
3970
3971                for (if_index, intf) in self.my_intfs.iter() {
3972                    if let Some(sock) = self.ipv4_sock.as_ref() {
3973                        let packet = self.unregister_service(&info, intf, &sock.pktinfo);
3974                        // repeat for one time just in case some peers miss the message
3975                        if !repeating && !packet.is_empty() {
3976                            let next_time = current_time_millis() + 120;
3977                            self.retransmissions.push(ReRun {
3978                                next_time,
3979                                command: Command::UnregisterResend(packet, *if_index, true),
3980                            });
3981                            timers.push(next_time);
3982                        }
3983                    }
3984
3985                    // ipv6
3986                    if let Some(sock) = self.ipv6_sock.as_ref() {
3987                        let packet = self.unregister_service(&info, intf, &sock.pktinfo);
3988                        if !repeating && !packet.is_empty() {
3989                            let next_time = current_time_millis() + 120;
3990                            self.retransmissions.push(ReRun {
3991                                next_time,
3992                                command: Command::UnregisterResend(packet, *if_index, false),
3993                            });
3994                            timers.push(next_time);
3995                        }
3996                    }
3997                }
3998
3999                for t in timers {
4000                    self.add_timer(t);
4001                }
4002
4003                self.increase_counter(Counter::Unregister, 1);
4004                UnregisterStatus::OK
4005            }
4006        };
4007        if let Err(e) = resp_s.send(response) {
4008            debug!("unregister: failed to send response: {}", e);
4009        }
4010    }
4011
4012    fn exec_command_unregister_resend(&mut self, packet: Vec<u8>, if_index: u32, is_ipv4: bool) {
4013        let Some(intf) = self.my_intfs.get(&if_index) else {
4014            return;
4015        };
4016        let sock_opt = if is_ipv4 {
4017            &self.ipv4_sock
4018        } else {
4019            &self.ipv6_sock
4020        };
4021        let Some(sock) = sock_opt else {
4022            return;
4023        };
4024
4025        let if_addr = if is_ipv4 {
4026            match intf.next_ifaddr_v4() {
4027                Some(addr) => addr,
4028                None => return,
4029            }
4030        } else {
4031            match intf.next_ifaddr_v6() {
4032                Some(addr) => addr,
4033                None => return,
4034            }
4035        };
4036
4037        debug!("UnregisterResend from {:?}", if_addr);
4038        multicast_on_intf(
4039            &packet[..],
4040            &intf.name,
4041            intf.index,
4042            if_addr,
4043            &sock.pktinfo,
4044            self.port,
4045        );
4046
4047        self.increase_counter(Counter::UnregisterResend, 1);
4048    }
4049
4050    fn exec_command_stop_browse(&mut self, ty_domain: String) {
4051        match self.service_queriers.remove_entry(&ty_domain) {
4052            None => debug!("StopBrowse: cannot find querier for {}", &ty_domain),
4053            Some((ty, sender)) => {
4054                // Remove pending browse commands in the reruns.
4055                trace!("StopBrowse: removed queryer for {}", &ty);
4056                let mut i = 0;
4057                while i < self.retransmissions.len() {
4058                    if let Command::Browse(t, _, _, _) = &self.retransmissions[i].command {
4059                        if t == &ty {
4060                            self.retransmissions.remove(i);
4061                            trace!("StopBrowse: removed retransmission for {}", &ty);
4062                            continue;
4063                        }
4064                    }
4065                    i += 1;
4066                }
4067
4068                // Remove cache entries.
4069                self.cache.remove_service_type(&ty_domain);
4070
4071                // Notify the client.
4072                match sender.send(ServiceEvent::SearchStopped(ty_domain)) {
4073                    Ok(()) => trace!("Sent SearchStopped to the listener"),
4074                    Err(e) => debug!("Failed to send SearchStopped: {}", e),
4075                }
4076            }
4077        }
4078    }
4079
4080    fn exec_command_stop_resolve_hostname(&mut self, hostname: String) {
4081        if let Some((host, (sender, _timeout))) = self.hostname_resolvers.remove_entry(&hostname) {
4082            // Remove pending resolve commands in the reruns.
4083            trace!("StopResolve: removed queryer for {}", &host);
4084            let mut i = 0;
4085            while i < self.retransmissions.len() {
4086                if let Command::Resolve(t, _) = &self.retransmissions[i].command {
4087                    if t == &host {
4088                        self.retransmissions.remove(i);
4089                        trace!("StopResolve: removed retransmission for {}", &host);
4090                        continue;
4091                    }
4092                }
4093                i += 1;
4094            }
4095
4096            // Notify the client.
4097            match sender.send(HostnameResolutionEvent::SearchStopped(hostname)) {
4098                Ok(()) => trace!("Sent SearchStopped to the listener"),
4099                Err(e) => debug!("Failed to send SearchStopped: {}", e),
4100            }
4101        }
4102    }
4103
4104    fn exec_command_register_resend(&mut self, fullname: String, if_index: u32) -> MyResult<()> {
4105        let Some(info) = self.my_services.get_mut(&fullname) else {
4106            trace!("announce: cannot find such service {}", &fullname);
4107            return Ok(());
4108        };
4109
4110        let Some(dns_registry) = self.dns_registry_map.get_mut(&if_index) else {
4111            return Ok(());
4112        };
4113
4114        let Some(intf) = self.my_intfs.get(&if_index) else {
4115            return Ok(());
4116        };
4117
4118        let announced_v4 = if let Some(sock) = self.ipv4_sock.as_ref() {
4119            announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port)?
4120        } else {
4121            false
4122        };
4123        let announced_v6 = if let Some(sock) = self.ipv6_sock.as_ref() {
4124            announce_service_on_intf(dns_registry, info, intf, &sock.pktinfo, self.port)?
4125        } else {
4126            false
4127        };
4128
4129        if announced_v4 || announced_v6 {
4130            let hostname = dns_registry.resolve_name(info.get_hostname());
4131            let service_name = dns_registry.resolve_name(&fullname).to_string();
4132
4133            debug!("resend: announce service {service_name} on {}", intf.name);
4134
4135            notify_monitors(
4136                &mut self.monitors,
4137                DaemonEvent::Announce(service_name, format!("{}:{}", hostname, &intf.name)),
4138            );
4139            info.set_status(if_index, ServiceStatus::Announced);
4140        } else {
4141            debug!("register-resend should not fail");
4142        }
4143
4144        self.increase_counter(Counter::RegisterResend, 1);
4145        Ok(())
4146    }
4147
4148    fn exec_command_verify(&mut self, instance: String, timeout: Duration, repeating: bool) {
4149        /*
4150        RFC 6762 section 10.4:
4151        ...
4152        When the cache receives this hint that it should reconfirm some
4153        record, it MUST issue two or more queries for the resource record in
4154        dispute.  If no response is received within ten seconds, then, even
4155        though its TTL may indicate that it is not yet due to expire, that
4156        record SHOULD be promptly flushed from the cache.
4157        */
4158        let now = current_time_millis();
4159        let expire_at = if repeating {
4160            None
4161        } else {
4162            Some(now + timeout.as_millis() as u64)
4163        };
4164
4165        // send query for the resource records.
4166        let record_vec = self.cache.service_verify_queries(&instance, expire_at);
4167
4168        if !record_vec.is_empty() {
4169            let query_vec: Vec<(&str, RRType)> = record_vec
4170                .iter()
4171                .map(|(record, rr_type)| (record.as_str(), *rr_type))
4172                .collect();
4173            self.send_query_vec(&query_vec);
4174
4175            if let Some(new_expire) = expire_at {
4176                self.add_timer(new_expire); // ensure a check for the new expire time.
4177
4178                // schedule a resend 1 second later
4179                self.add_retransmission(now + 1000, Command::Verify(instance, timeout));
4180            }
4181        }
4182    }
4183
4184    /// Refresh cached service records with active queriers
4185    fn refresh_active_services(&mut self) {
4186        let mut query_ptr_count = 0;
4187        let mut query_srv_count = 0;
4188        let mut new_timers = HashSet::new();
4189        let mut query_addr_count = 0;
4190
4191        for (ty_domain, _sender) in self.service_queriers.iter() {
4192            let refreshed_timers = self.cache.refresh_due_ptr(ty_domain);
4193            if !refreshed_timers.is_empty() {
4194                trace!("sending refresh query for PTR: {}", ty_domain);
4195                self.send_query(ty_domain, RRType::PTR);
4196                query_ptr_count += 1;
4197                new_timers.extend(refreshed_timers);
4198            }
4199
4200            let (instances, timers) = self.cache.refresh_due_srv_txt(ty_domain);
4201            for (instance, types) in instances {
4202                trace!("sending refresh query for: {}", &instance);
4203                let query_vec = types
4204                    .into_iter()
4205                    .map(|ty| (instance.as_str(), ty))
4206                    .collect::<Vec<_>>();
4207                self.send_query_vec(&query_vec);
4208                query_srv_count += 1;
4209            }
4210            new_timers.extend(timers);
4211            let (hostnames, timers) = self.cache.refresh_due_hosts(ty_domain);
4212            for hostname in hostnames.iter() {
4213                trace!("sending refresh queries for A and AAAA:  {}", hostname);
4214                self.send_query_vec(&[(hostname, RRType::A), (hostname, RRType::AAAA)]);
4215                query_addr_count += 2;
4216            }
4217            new_timers.extend(timers);
4218        }
4219
4220        for timer in new_timers {
4221            self.add_timer(timer);
4222        }
4223
4224        self.increase_counter(Counter::CacheRefreshPTR, query_ptr_count);
4225        self.increase_counter(Counter::CacheRefreshSrvTxt, query_srv_count);
4226        self.increase_counter(Counter::CacheRefreshAddr, query_addr_count);
4227    }
4228}
4229
4230/// Adds one or more answers of a service for incoming msg and RR entry name.
4231fn add_answer_of_service(
4232    out: &mut DnsOutgoing,
4233    msg: &DnsIncoming,
4234    entry_name: &str,
4235    service: &ServiceInfo,
4236    qtype: RRType,
4237    intf_addrs: Vec<IpAddr>,
4238) {
4239    if qtype == RRType::SRV || qtype == RRType::ANY {
4240        out.add_answer(
4241            msg,
4242            DnsSrv::new(
4243                entry_name,
4244                CLASS_IN | CLASS_CACHE_FLUSH,
4245                service.get_host_ttl(),
4246                service.get_priority(),
4247                service.get_weight(),
4248                service.get_port(),
4249                service.get_hostname().to_string(),
4250            ),
4251        );
4252    }
4253
4254    if qtype == RRType::TXT || qtype == RRType::ANY {
4255        out.add_answer(
4256            msg,
4257            DnsTxt::new(
4258                entry_name,
4259                CLASS_IN | CLASS_CACHE_FLUSH,
4260                service.get_other_ttl(),
4261                service.generate_txt(),
4262            ),
4263        );
4264    }
4265
4266    if qtype == RRType::SRV {
4267        for address in intf_addrs {
4268            out.add_additional_answer(DnsAddress::new(
4269                service.get_hostname(),
4270                ip_address_rr_type(&address),
4271                CLASS_IN | CLASS_CACHE_FLUSH,
4272                service.get_host_ttl(),
4273                address,
4274                InterfaceId::default(),
4275            ));
4276        }
4277    }
4278}
4279
4280/// All possible events sent to the client from the daemon
4281/// regarding service discovery.
4282#[derive(Clone, Debug)]
4283#[non_exhaustive]
4284pub enum ServiceEvent {
4285    /// Started searching for a service type.
4286    SearchStarted(String),
4287
4288    /// Found a specific (service_type, fullname).
4289    ServiceFound(String, String),
4290
4291    /// Resolved a service instance in a ResolvedService struct.
4292    ServiceResolved(Box<ResolvedService>),
4293
4294    /// A service instance (service_type, fullname) was removed.
4295    ServiceRemoved(String, String),
4296
4297    /// Stopped searching for a service type.
4298    SearchStopped(String),
4299}
4300
4301/// All possible events sent to the client from the daemon
4302/// regarding host resolution.
4303#[derive(Clone, Debug)]
4304#[non_exhaustive]
4305pub enum HostnameResolutionEvent {
4306    /// Started searching for the ip address of a hostname.
4307    SearchStarted(String),
4308    /// One or more addresses for a hostname has been found.
4309    AddressesFound(String, HashSet<ScopedIp>),
4310    /// One or more addresses for a hostname has been removed.
4311    AddressesRemoved(String, HashSet<ScopedIp>),
4312    /// The search for the ip address of a hostname has timed out.
4313    SearchTimeout(String),
4314    /// Stopped searching for the ip address of a hostname.
4315    SearchStopped(String),
4316}
4317
4318/// Some notable events from the daemon besides [`ServiceEvent`].
4319/// These events are expected to happen infrequently.
4320#[derive(Clone, Debug)]
4321#[non_exhaustive]
4322pub enum DaemonEvent {
4323    /// Daemon unsolicitly announced a service from an interface.
4324    Announce(String, String),
4325
4326    /// Daemon encountered an error.
4327    Error(Error),
4328
4329    /// Daemon detected a new IP address from the host.
4330    IpAdd(IpAddr),
4331
4332    /// Daemon detected a IP address removed from the host.
4333    IpDel(IpAddr),
4334
4335    /// Daemon resolved a name conflict by changing one of its names.
4336    /// see [DnsNameChange] for more details.
4337    NameChange(DnsNameChange),
4338
4339    /// Send out a multicast response via an interface.
4340    Respond(String),
4341}
4342
4343/// Represents a name change due to a name conflict resolution.
4344/// See [RFC 6762 section 9](https://datatracker.ietf.org/doc/html/rfc6762#section-9)
4345#[derive(Clone, Debug)]
4346pub struct DnsNameChange {
4347    /// The original name set in `ServiceInfo` by the user.
4348    pub original: String,
4349
4350    /// A new name is created by appending a suffix after the original name.
4351    ///
4352    /// - for a service instance name, the suffix is `(N)`, where N starts at 2.
4353    /// - for a host name, the suffix is `-N`, where N starts at 2.
4354    ///
4355    /// For example:
4356    ///
4357    /// - Service name `foo._service-type._udp` becomes `foo (2)._service-type._udp`
4358    /// - Host name `foo.local.` becomes `foo-2.local.`
4359    pub new_name: String,
4360
4361    /// The resource record type
4362    pub rr_type: RRType,
4363
4364    /// The interface where the name conflict and its change happened.
4365    pub intf_name: String,
4366}
4367
4368/// Commands supported by the daemon
4369#[derive(Debug)]
4370enum Command {
4371    /// Browsing for a service type (ty_domain, next_time_delay_in_seconds, channel::sender)
4372    Browse(String, u32, bool, Sender<ServiceEvent>),
4373
4374    /// Resolve a hostname to IP addresses.
4375    ResolveHostname(String, u32, Sender<HostnameResolutionEvent>, Option<u64>), // (hostname, next_time_delay_in_seconds, sender, timeout_in_milliseconds)
4376
4377    /// Register a service
4378    Register(Box<ServiceInfo>),
4379
4380    /// Unregister a service
4381    Unregister(String, Sender<UnregisterStatus>), // (fullname)
4382
4383    /// Announce again a service to local network
4384    RegisterResend(String, u32), // (fullname)
4385
4386    /// Resend unregister packet.
4387    UnregisterResend(Vec<u8>, u32, bool), // (packet content, if_index, is_ipv4)
4388
4389    /// Stop browsing a service type
4390    StopBrowse(String), // (ty_domain)
4391
4392    /// Stop resolving a hostname
4393    StopResolveHostname(String), // (hostname)
4394
4395    /// Send query to resolve a service instance.
4396    /// This is used when a PTR record exists but SRV & TXT records are missing.
4397    Resolve(String, u16), // (service_instance_fullname, try_count)
4398
4399    /// Read the current values of the counters
4400    GetMetrics(Sender<Metrics>),
4401
4402    /// Get the current status of the daemon.
4403    GetStatus(Sender<DaemonStatus>),
4404
4405    /// Monitor noticeable events in the daemon.
4406    Monitor(Sender<DaemonEvent>),
4407
4408    SetOption(DaemonOption),
4409
4410    GetOption(Sender<DaemonOptionVal>),
4411
4412    /// Proactively confirm a DNS resource record.
4413    ///
4414    /// The intention is to check if a service name or IP address still valid
4415    /// before its TTL expires.
4416    Verify(String, Duration),
4417
4418    /// Invalidate some interface addresses.
4419    InvalidIntfAddrs(HashSet<Interface>),
4420
4421    Exit(Sender<DaemonStatus>),
4422}
4423
4424impl fmt::Display for Command {
4425    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4426        match self {
4427            Self::Browse(_, _, _, _) => write!(f, "Command Browse"),
4428            Self::ResolveHostname(_, _, _, _) => write!(f, "Command ResolveHostname"),
4429            Self::Exit(_) => write!(f, "Command Exit"),
4430            Self::GetStatus(_) => write!(f, "Command GetStatus"),
4431            Self::GetMetrics(_) => write!(f, "Command GetMetrics"),
4432            Self::Monitor(_) => write!(f, "Command Monitor"),
4433            Self::Register(_) => write!(f, "Command Register"),
4434            Self::RegisterResend(_, _) => write!(f, "Command RegisterResend"),
4435            Self::SetOption(_) => write!(f, "Command SetOption"),
4436            Self::GetOption(_) => write!(f, "Command GetOption"),
4437            Self::StopBrowse(_) => write!(f, "Command StopBrowse"),
4438            Self::StopResolveHostname(_) => write!(f, "Command StopResolveHostname"),
4439            Self::Unregister(_, _) => write!(f, "Command Unregister"),
4440            Self::UnregisterResend(_, _, _) => write!(f, "Command UnregisterResend"),
4441            Self::Resolve(_, _) => write!(f, "Command Resolve"),
4442            Self::Verify(_, _) => write!(f, "Command VerifyResource"),
4443            Self::InvalidIntfAddrs(_) => write!(f, "Command InvalidIntfAddrs"),
4444        }
4445    }
4446}
4447
4448struct DaemonOptionVal {
4449    _service_name_len_max: u8,
4450    ip_check_interval: u64,
4451}
4452
4453#[derive(Debug)]
4454enum DaemonOption {
4455    ServiceNameLenMax(u8),
4456    IpCheckInterval(u64),
4457    MaxPacketSize(Vec<IfKind>, usize),
4458    EnableInterface(Vec<IfKind>),
4459    DisableInterface(Vec<IfKind>),
4460    MulticastLoopV4(bool),
4461    MulticastLoopV6(bool),
4462    AcceptUnsolicited(bool),
4463    IncludeAppleP2P(bool),
4464    #[cfg(test)]
4465    TestDownInterface(String),
4466    #[cfg(test)]
4467    TestUpInterface(String),
4468}
4469
4470/// The length of Service Domain name supported in this lib.
4471const DOMAIN_LEN: usize = "._tcp.local.".len();
4472
4473/// Validate the length of "service_name" in a "_<service_name>.<domain_name>." string.
4474fn check_service_name_length(ty_domain: &str, limit: u8) -> Result<()> {
4475    if ty_domain.len() <= DOMAIN_LEN + 1 {
4476        // service name cannot be empty or only '_'.
4477        return Err(e_fmt!("Service type name cannot be empty: {}", ty_domain));
4478    }
4479
4480    let service_name_len = ty_domain.len() - DOMAIN_LEN - 1; // exclude the leading `_`
4481    if service_name_len > limit as usize {
4482        return Err(e_fmt!("Service name length must be <= {} bytes", limit));
4483    }
4484    Ok(())
4485}
4486
4487/// Checks if `name` ends with a valid domain: '._tcp.local.' or '._udp.local.'
4488fn check_domain_suffix(name: &str) -> Result<()> {
4489    if !(name.ends_with("._tcp.local.") || name.ends_with("._udp.local.")) {
4490        return Err(e_fmt!(
4491            "mDNS service {} must end with '._tcp.local.' or '._udp.local.'",
4492            name
4493        ));
4494    }
4495
4496    Ok(())
4497}
4498
4499/// Validate the service name in a fully qualified name.
4500///
4501/// A Full Name = <Instance>.<Service>.<Domain>
4502/// The only `<Domain>` supported are "._tcp.local." and "._udp.local.".
4503///
4504/// Note: this function does not check for the length of the service name.
4505/// Instead, `register_service` method will check the length.
4506fn check_service_name(fullname: &str) -> Result<()> {
4507    check_domain_suffix(fullname)?;
4508
4509    let remaining: Vec<&str> = fullname[..fullname.len() - DOMAIN_LEN].split('.').collect();
4510    let name = remaining.last().ok_or_else(|| e_fmt!("No service name"))?;
4511
4512    if &name[0..1] != "_" {
4513        return Err(e_fmt!("Service name must start with '_'"));
4514    }
4515
4516    let name = &name[1..];
4517
4518    if name.contains("--") {
4519        return Err(e_fmt!("Service name must not contain '--'"));
4520    }
4521
4522    if name.starts_with('-') || name.ends_with('-') {
4523        return Err(e_fmt!("Service name (%s) may not start or end with '-'"));
4524    }
4525
4526    let ascii_count = name.chars().filter(|c| c.is_ascii_alphabetic()).count();
4527    if ascii_count < 1 {
4528        return Err(e_fmt!(
4529            "Service name must contain at least one letter (eg: 'A-Za-z')"
4530        ));
4531    }
4532
4533    Ok(())
4534}
4535
4536/// Validate a hostname.
4537fn check_hostname(hostname: &str) -> Result<()> {
4538    if !hostname.ends_with(".local.") {
4539        return Err(e_fmt!("Hostname must end with '.local.': {hostname}"));
4540    }
4541
4542    if hostname == ".local." {
4543        return Err(e_fmt!(
4544            "The part of the hostname before '.local.' cannot be empty"
4545        ));
4546    }
4547
4548    if hostname.len() > 255 {
4549        return Err(e_fmt!("Hostname length must be <= 255 bytes"));
4550    }
4551
4552    Ok(())
4553}
4554
4555fn call_service_listener(
4556    listeners_map: &HashMap<String, Sender<ServiceEvent>>,
4557    ty_domain: &str,
4558    event: ServiceEvent,
4559) {
4560    if let Some(listener) = listeners_map.get(ty_domain) {
4561        match listener.send(event) {
4562            Ok(()) => trace!("Sent event to listener successfully"),
4563            Err(e) => debug!("Failed to send event: {}", e),
4564        }
4565    }
4566}
4567
4568fn call_hostname_resolution_listener(
4569    listeners_map: &HashMap<String, (Sender<HostnameResolutionEvent>, Option<u64>)>,
4570    hostname: &str,
4571    event: HostnameResolutionEvent,
4572) {
4573    let hostname_lower = hostname.to_lowercase();
4574    if let Some(listener) = listeners_map.get(&hostname_lower).map(|(l, _)| l) {
4575        match listener.send(event) {
4576            Ok(()) => trace!("Sent event to listener successfully"),
4577            Err(e) => debug!("Failed to send event: {}", e),
4578        }
4579    }
4580}
4581
4582/// Returns valid network interfaces in the host system.
4583/// Operational down interfaces are excluded.
4584/// Loopback interfaces are excluded if `with_loopback` is false.
4585fn my_ip_interfaces(with_loopback: bool) -> Vec<Interface> {
4586    my_ip_interfaces_inner(with_loopback, false)
4587}
4588
4589fn my_ip_interfaces_inner(with_loopback: bool, with_apple_p2p: bool) -> Vec<Interface> {
4590    if_addrs::get_if_addrs()
4591        .unwrap_or_default()
4592        .into_iter()
4593        .filter(|i| {
4594            i.is_oper_up()
4595                && !i.is_p2p()
4596                && (!i.is_loopback() || with_loopback)
4597                && (with_apple_p2p || !is_apple_p2p_by_name(&i.name))
4598        })
4599        .collect()
4600}
4601
4602/// Checks if the interface name indicates it's an Apple peer-to-peer interface,
4603/// which should be ignored by default.
4604fn is_apple_p2p_by_name(name: &str) -> bool {
4605    let p2p_prefixes = ["awdl", "llw"];
4606    p2p_prefixes.iter().any(|prefix| name.starts_with(prefix))
4607}
4608
4609/// How to encode and where to send outgoing messages on one interface.
4610#[derive(Clone, Copy, Debug)]
4611struct SendConfig {
4612    /// The mDNS port to send to.
4613    port: u16,
4614
4615    /// Max byte size of a generated packet.
4616    /// See [`ServiceDaemon::set_max_packet_size`].
4617    max_packet_size: usize,
4618
4619    /// Whether the packets go out over IPv4, which decides their absolute
4620    /// ceiling: see [`max_pkt_absolute`].
4621    is_ipv4: bool,
4622}
4623
4624/// Send an outgoing mDNS query or response, and returns the packet bytes.
4625/// Returns empty vec if no valid interface address is found.
4626fn send_dns_outgoing(
4627    out: &DnsOutgoing,
4628    my_intf: &MyIntf,
4629    sock: &PktInfoUdpSocket,
4630    port: u16,
4631    source: Option<&IfAddr>,
4632    unicast_dest: Option<SocketAddr>,
4633) -> MyResult<Vec<Vec<u8>>> {
4634    let if_name = &my_intf.name;
4635
4636    let if_addr = match source {
4637        Some(addr) => addr,
4638        None => {
4639            if sock.domain() == Domain::IPV4 {
4640                match my_intf.next_ifaddr_v4() {
4641                    Some(addr) => addr,
4642                    None => return Ok(vec![]),
4643                }
4644            } else {
4645                match my_intf.next_ifaddr_v6() {
4646                    Some(addr) => addr,
4647                    None => return Ok(vec![]),
4648                }
4649            }
4650        }
4651    };
4652
4653    // The limits are per address family, so read them off the address we send from.
4654    let is_ipv4 = if_addr.ip().is_ipv4();
4655    let config = SendConfig {
4656        port,
4657        max_packet_size: my_intf.max_packet_size(is_ipv4),
4658        is_ipv4,
4659    };
4660
4661    send_dns_outgoing_impl(
4662        out,
4663        if_name,
4664        my_intf.index,
4665        if_addr,
4666        sock,
4667        config,
4668        unicast_dest,
4669    )
4670}
4671
4672/// Send an outgoing mDNS query or response, and returns the packet bytes.
4673fn send_dns_outgoing_impl(
4674    out: &DnsOutgoing,
4675    if_name: &str,
4676    if_index: u32,
4677    if_addr: &IfAddr,
4678    sock: &PktInfoUdpSocket,
4679    config: SendConfig,
4680    unicast_dest: Option<SocketAddr>,
4681) -> MyResult<Vec<Vec<u8>>> {
4682    let qtype = if out.is_query() {
4683        "query"
4684    } else {
4685        if out.answers_count() == 0 && out.additionals().is_empty() {
4686            return Ok(vec![]); // no need to send empty response
4687        }
4688        "response"
4689    };
4690    trace!(
4691        "send {}: {} questions {} answers {} authorities {} additional",
4692        qtype,
4693        out.questions().len(),
4694        out.answers_count(),
4695        out.authorities().len(),
4696        out.additionals().len()
4697    );
4698
4699    match if_addr.ip() {
4700        IpAddr::V4(ipv4) => {
4701            if let Err(e) = sock.set_multicast_if_v4(&ipv4) {
4702                debug!(
4703                    "send_dns_outgoing: failed to set multicast interface for IPv4 {}: {}",
4704                    ipv4, e
4705                );
4706                // cannot send without a valid interface
4707                if e.kind() == std::io::ErrorKind::AddrNotAvailable {
4708                    let intf_addr = Interface {
4709                        name: if_name.to_string(),
4710                        addr: if_addr.clone(),
4711                        index: Some(if_index),
4712                        oper_status: if_addrs::IfOperStatus::Down,
4713                        is_p2p: false,
4714                        #[cfg(windows)]
4715                        adapter_name: String::new(),
4716                    };
4717                    return Err(InternalError::IntfAddrInvalid(intf_addr));
4718                }
4719                return Ok(vec![]); // non-fatal other failure
4720            }
4721        }
4722        IpAddr::V6(ipv6) => {
4723            if let Err(e) = sock.set_multicast_if_v6(if_index) {
4724                debug!(
4725                    "send_dns_outgoing: failed to set multicast interface for IPv6 {}: {}",
4726                    ipv6, e
4727                );
4728                // cannot send without a valid interface
4729                if e.kind() == std::io::ErrorKind::AddrNotAvailable {
4730                    let intf_addr = Interface {
4731                        name: if_name.to_string(),
4732                        addr: if_addr.clone(),
4733                        index: Some(if_index),
4734                        oper_status: if_addrs::IfOperStatus::Down,
4735                        is_p2p: false,
4736                        #[cfg(windows)]
4737                        adapter_name: String::new(),
4738                    };
4739                    return Err(InternalError::IntfAddrInvalid(intf_addr));
4740                }
4741                return Ok(vec![]); // non-fatal other failure
4742            }
4743        }
4744    }
4745
4746    let packet_list = out.to_data_on_wire(config.max_packet_size, config.is_ipv4);
4747    for packet in packet_list.iter() {
4748        match unicast_dest {
4749            Some(dest) => unicast_on_intf(packet, if_name, dest, sock),
4750            None => multicast_on_intf(packet, if_name, if_index, if_addr, sock, config.port),
4751        }
4752    }
4753    Ok(packet_list)
4754}
4755
4756/// Sends a unicast packet directly to `dest` (used for RFC 6762 §6.7
4757/// legacy unicast responses).
4758fn unicast_on_intf(packet: &[u8], if_name: &str, dest: SocketAddr, socket: &PktInfoUdpSocket) {
4759    let max_size = max_pkt_absolute(dest.is_ipv4());
4760    if packet.len() > max_size {
4761        debug!("Drop over-sized packet ({} > {max_size})", packet.len());
4762        return;
4763    }
4764
4765    let sock_addr = dest.into();
4766    match socket.send_to(packet, &sock_addr) {
4767        Ok(sz) => trace!(
4768            "sent unicast {} bytes on interface {} to {}",
4769            sz,
4770            if_name,
4771            dest
4772        ),
4773        Err(e) => trace!(
4774            "Failed to send unicast to {} via {:?}: {}",
4775            dest,
4776            &if_name,
4777            e
4778        ),
4779    }
4780}
4781
4782/// Sends a multicast packet, and returns the packet bytes.
4783fn multicast_on_intf(
4784    packet: &[u8],
4785    if_name: &str,
4786    if_index: u32,
4787    if_addr: &IfAddr,
4788    socket: &PktInfoUdpSocket,
4789    port: u16,
4790) {
4791    let max_size = max_pkt_absolute(if_addr.ip().is_ipv4());
4792    if packet.len() > max_size {
4793        debug!("Drop over-sized packet ({} > {max_size})", packet.len());
4794        return;
4795    }
4796
4797    let addr: SocketAddr = match if_addr {
4798        if_addrs::IfAddr::V4(_) => SocketAddrV4::new(GROUP_ADDR_V4, port).into(),
4799        if_addrs::IfAddr::V6(_) => {
4800            let mut sock = SocketAddrV6::new(GROUP_ADDR_V6, port, 0, 0);
4801            sock.set_scope_id(if_index); // Choose iface for multicast
4802            sock.into()
4803        }
4804    };
4805
4806    // Sends out `packet` to `addr` on the socket.
4807    let sock_addr = addr.into();
4808    match socket.send_to(packet, &sock_addr) {
4809        Ok(sz) => trace!(
4810            "sent out {} bytes on interface {} (idx {}) addr {}",
4811            sz,
4812            if_name,
4813            if_index,
4814            if_addr.ip()
4815        ),
4816        Err(e) => trace!("Failed to send to {} via {:?}: {}", addr, &if_name, e),
4817    }
4818}
4819
4820/// Returns true if `name` is a valid instance name of format:
4821/// <instance>.<service_type>.<_udp|_tcp>.local.
4822/// Note: <instance> could contain '.' as well.
4823fn valid_instance_name(name: &str) -> bool {
4824    name.split('.').count() >= 5
4825}
4826
4827fn notify_monitors(monitors: &mut Vec<Sender<DaemonEvent>>, event: DaemonEvent) {
4828    monitors.retain(|sender| {
4829        if let Err(e) = sender.try_send(event.clone()) {
4830            debug!("notify_monitors: try_send: {}", &e);
4831            if matches!(e, TrySendError::Disconnected(_)) {
4832                return false; // This monitor is dropped.
4833            }
4834        }
4835        true
4836    });
4837}
4838
4839/// Check if all unique records passed "probing", and if yes, create a packet
4840/// to announce the service.
4841fn prepare_announce(
4842    info: &ServiceInfo,
4843    intf: &MyIntf,
4844    dns_registry: &mut DnsRegistry,
4845    is_ipv4: bool,
4846) -> Option<DnsOutgoing> {
4847    let intf_addrs = if is_ipv4 {
4848        info.get_addrs_on_my_intf_v4(intf)
4849    } else {
4850        info.get_addrs_on_my_intf_v6(intf)
4851    };
4852
4853    if intf_addrs.is_empty() {
4854        debug!(
4855            "prepare_announce (ipv4: {is_ipv4}): no valid addrs on interface {}",
4856            &intf.name
4857        );
4858        return None;
4859    }
4860
4861    // check if we changed our name due to conflicts.
4862    let service_fullname = dns_registry.resolve_name(info.get_fullname());
4863
4864    debug!(
4865        "prepare to announce service {service_fullname} on {:?}",
4866        &intf_addrs
4867    );
4868
4869    let mut probing_count = 0;
4870    let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
4871    let create_time = current_time_millis() + fastrand::u64(0..250);
4872
4873    out.add_answer_at_time(
4874        DnsPointer::new(
4875            info.get_type(),
4876            RRType::PTR,
4877            CLASS_IN,
4878            info.get_other_ttl(),
4879            service_fullname.to_string(),
4880        ),
4881        0,
4882    );
4883
4884    if let Some(sub) = info.get_subtype() {
4885        trace!("Adding subdomain {}", sub);
4886        out.add_answer_at_time(
4887            DnsPointer::new(
4888                sub,
4889                RRType::PTR,
4890                CLASS_IN,
4891                info.get_other_ttl(),
4892                service_fullname.to_string(),
4893            ),
4894            0,
4895        );
4896    }
4897
4898    // SRV records.
4899    let hostname = dns_registry.resolve_name(info.get_hostname()).to_string();
4900
4901    let mut srv = DnsSrv::new(
4902        info.get_fullname(),
4903        CLASS_IN | CLASS_CACHE_FLUSH,
4904        info.get_host_ttl(),
4905        info.get_priority(),
4906        info.get_weight(),
4907        info.get_port(),
4908        hostname,
4909    );
4910
4911    if let Some(new_name) = dns_registry.name_changes.get(info.get_fullname()) {
4912        srv.get_record_mut().set_new_name(new_name.to_string());
4913    }
4914
4915    if !info.requires_probe()
4916        || dns_registry.is_probing_done(&srv, info.get_fullname(), create_time)
4917    {
4918        out.add_answer_at_time(srv, 0);
4919    } else {
4920        probing_count += 1;
4921    }
4922
4923    // TXT records.
4924
4925    let mut txt = DnsTxt::new(
4926        info.get_fullname(),
4927        CLASS_IN | CLASS_CACHE_FLUSH,
4928        info.get_other_ttl(),
4929        info.generate_txt(),
4930    );
4931
4932    if let Some(new_name) = dns_registry.name_changes.get(info.get_fullname()) {
4933        txt.get_record_mut().set_new_name(new_name.to_string());
4934    }
4935
4936    if !info.requires_probe()
4937        || dns_registry.is_probing_done(&txt, info.get_fullname(), create_time)
4938    {
4939        out.add_answer_at_time(txt, 0);
4940    } else {
4941        probing_count += 1;
4942    }
4943
4944    // Address records. (A and AAAA)
4945
4946    let hostname = info.get_hostname();
4947    for address in intf_addrs {
4948        let mut dns_addr = DnsAddress::new(
4949            hostname,
4950            ip_address_rr_type(&address),
4951            CLASS_IN | CLASS_CACHE_FLUSH,
4952            info.get_host_ttl(),
4953            address,
4954            intf.into(),
4955        );
4956
4957        if let Some(new_name) = dns_registry.name_changes.get(hostname) {
4958            dns_addr.get_record_mut().set_new_name(new_name.to_string());
4959        }
4960
4961        if !info.requires_probe()
4962            || dns_registry.is_probing_done(&dns_addr, info.get_fullname(), create_time)
4963        {
4964            out.add_answer_at_time(dns_addr, 0);
4965        } else {
4966            probing_count += 1;
4967        }
4968    }
4969
4970    if probing_count > 0 {
4971        return None;
4972    }
4973
4974    Some(out)
4975}
4976
4977/// Send an unsolicited response for owned service via `intf` and `sock`.
4978/// Returns true if sent out successfully for IPv4 or IPv6.
4979fn announce_service_on_intf(
4980    dns_registry: &mut DnsRegistry,
4981    info: &ServiceInfo,
4982    intf: &MyIntf,
4983    sock: &PktInfoUdpSocket,
4984    port: u16,
4985) -> MyResult<bool> {
4986    let is_ipv4 = sock.domain() == Domain::IPV4;
4987    if let Some(mut out) = prepare_announce(info, intf, dns_registry, is_ipv4) {
4988        // RFC 6762 §6: a record MUST NOT be multicast on an interface more than
4989        // once per second. Announcements are unsolicited multicast responses.
4990        dns_registry.apply_multicast_rate_limit(&mut out, current_time_millis(), is_ipv4);
4991        if out.answers_count() > 0 {
4992            let _ = send_dns_outgoing(&out, intf, sock, port, None, None)?;
4993        }
4994        return Ok(true);
4995    }
4996
4997    Ok(false)
4998}
4999
5000/// Returns a new name based on the `original` to avoid conflicts.
5001/// If the name already contains a number in parentheses, increments that number.
5002///
5003/// Examples:
5004/// - `foo.local.` becomes `foo (2).local.`
5005/// - `foo (2).local.` becomes `foo (3).local.`
5006/// - `foo (9)` becomes `foo (10)`
5007fn name_change(original: &str) -> String {
5008    let mut parts: Vec<_> = original.split('.').collect();
5009    let Some(first_part) = parts.get_mut(0) else {
5010        return format!("{original} (2)");
5011    };
5012
5013    let mut new_name = format!("{first_part} (2)");
5014
5015    // check if there is already has `(<num>)` suffix.
5016    if let Some(paren_pos) = first_part.rfind(" (") {
5017        // Check if there's a closing parenthesis
5018        if let Some(end_paren) = first_part[paren_pos..].find(')') {
5019            let absolute_end_pos = paren_pos + end_paren;
5020            // Only process if the closing parenthesis is the last character
5021            if absolute_end_pos == first_part.len() - 1 {
5022                let num_start = paren_pos + 2; // Skip " ("
5023                                               // Try to parse the number between parentheses
5024                if let Ok(number) = first_part[num_start..absolute_end_pos].parse::<u32>() {
5025                    let base_name = &first_part[..paren_pos];
5026                    new_name = format!("{} ({})", base_name, number + 1)
5027                }
5028            }
5029        }
5030    }
5031
5032    *first_part = &new_name;
5033    parts.join(".")
5034}
5035
5036/// Returns a new name based on the `original` to avoid conflicts.
5037/// If the name already contains a hyphenated number, increments that number.
5038///
5039/// Examples:
5040/// - `foo.local.` becomes `foo-2.local.`
5041/// - `foo-2.local.` becomes `foo-3.local.`
5042/// - `foo` becomes `foo-2`
5043fn hostname_change(original: &str) -> String {
5044    let mut parts: Vec<_> = original.split('.').collect();
5045    let Some(first_part) = parts.get_mut(0) else {
5046        return format!("{original}-2");
5047    };
5048
5049    let mut new_name = format!("{first_part}-2");
5050
5051    // check if there is already a `-<num>` suffix
5052    if let Some(hyphen_pos) = first_part.rfind('-') {
5053        // Try to parse everything after the hyphen as a number
5054        if let Ok(number) = first_part[hyphen_pos + 1..].parse::<u32>() {
5055            let base_name = &first_part[..hyphen_pos];
5056            new_name = format!("{}-{}", base_name, number + 1);
5057        }
5058    }
5059
5060    *first_part = &new_name;
5061    parts.join(".")
5062}
5063
5064/// Check probes in a registry and returns: a probing packet to send out, and a list of probe names
5065/// that are finished.
5066fn check_probing(
5067    dns_registry: &mut DnsRegistry,
5068    timers: &mut BinaryHeap<Reverse<u64>>,
5069    now: u64,
5070) -> (DnsOutgoing, Vec<String>) {
5071    let mut expired_probes = Vec::new();
5072    let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
5073
5074    for (name, probe) in dns_registry.probing.iter_mut() {
5075        if now >= probe.next_send {
5076            if probe.expired(now) {
5077                // move the record to active
5078                expired_probes.push(name.clone());
5079            } else {
5080                out.add_question(name, RRType::ANY);
5081
5082                /*
5083                RFC 6762 section 8.2: https://datatracker.ietf.org/doc/html/rfc6762#section-8.2
5084                ...
5085                for tiebreaking to work correctly in all
5086                cases, the Authority Section must contain *all* the records and
5087                proposed rdata being probed for uniqueness.
5088                    */
5089                for record in probe.records.iter() {
5090                    out.add_authority(record.clone());
5091                }
5092
5093                probe.update_next_send(now);
5094
5095                // add timer
5096                timers.push(Reverse(probe.next_send));
5097            }
5098        }
5099    }
5100
5101    (out, expired_probes)
5102}
5103
5104/// Process expired probes on an interface and return a list of services
5105/// that are waiting for the probe to finish.
5106///
5107/// `DnsNameChange` events are sent to the monitors.
5108fn handle_expired_probes(
5109    expired_probes: Vec<String>,
5110    intf_name: &str,
5111    dns_registry: &mut DnsRegistry,
5112    monitors: &mut Vec<Sender<DaemonEvent>>,
5113) -> HashSet<String> {
5114    let mut waiting_services = HashSet::new();
5115
5116    for name in expired_probes {
5117        let Some(probe) = dns_registry.probing.remove(&name) else {
5118            continue;
5119        };
5120
5121        // send notifications about name changes
5122        for record in probe.records.iter() {
5123            if let Some(new_name) = record.get_record().get_new_name() {
5124                dns_registry
5125                    .name_changes
5126                    .insert(name.clone(), new_name.to_string());
5127
5128                let event = DnsNameChange {
5129                    original: record.get_record().get_original_name().to_string(),
5130                    new_name: new_name.to_string(),
5131                    rr_type: record.get_type(),
5132                    intf_name: intf_name.to_string(),
5133                };
5134                debug!("Name change event: {:?}", &event);
5135                notify_monitors(monitors, DaemonEvent::NameChange(event));
5136            }
5137        }
5138
5139        // move RR from probe to active.
5140        debug!(
5141            "probe of '{name}' finished: move {} records to active. ({} waiting services)",
5142            probe.records.len(),
5143            probe.waiting_services.len(),
5144        );
5145
5146        // Move records to active and plan to wake up services if records are not empty.
5147        if !probe.records.is_empty() {
5148            match dns_registry.active.get_mut(&name) {
5149                Some(records) => {
5150                    records.extend(probe.records);
5151                }
5152                None => {
5153                    dns_registry.active.insert(name, probe.records);
5154                }
5155            }
5156
5157            waiting_services.extend(probe.waiting_services);
5158        }
5159    }
5160
5161    waiting_services
5162}
5163
5164/// Returns the max packet size to use on the interface `if_index` for the given
5165/// address family, i.e. the size of the last selection matching it, or
5166/// [`MAX_PKT_DEFAULT`] if none does.
5167///
5168/// A selection matches an address, so it applies as soon as any address of the
5169/// interface in that family matches. That keeps the two families independent:
5170/// e.g. [`IfKind::IPv4`] leaves the IPv6 side of the interface alone.
5171fn resolve_max_packet_size(
5172    selections: &[MaxPacketSizeSelection],
5173    interfaces: &[Interface],
5174    if_index: u32,
5175    is_ipv4: bool,
5176) -> usize {
5177    let mut size = MAX_PKT_DEFAULT;
5178
5179    for selection in selections {
5180        let matched = interfaces.iter().any(|intf| {
5181            intf.index.unwrap_or(0) == if_index
5182                && intf.ip().is_ipv4() == is_ipv4
5183                && selection.if_kind.matches(intf)
5184        });
5185        if matched {
5186            size = selection.max_packet_size;
5187        }
5188    }
5189
5190    size
5191}
5192
5193/// Resolves `IfKind::Addr(ip)` to `IndexV4(if_index)` or `IndexV6(if_index)`.
5194fn resolve_addr_to_index(if_kind: IfKind, interfaces: &[Interface]) -> IfKind {
5195    if let IfKind::Addr(addr) = &if_kind {
5196        if let Some(intf) = interfaces.iter().find(|intf| &intf.ip() == addr) {
5197            let if_index = intf.index.unwrap_or(0);
5198            return if addr.is_ipv4() {
5199                IfKind::IndexV4(if_index)
5200            } else {
5201                IfKind::IndexV6(if_index)
5202            };
5203        }
5204    }
5205    if_kind
5206}
5207
5208#[cfg(test)]
5209mod tests {
5210    use super::{
5211        _new_socket_bind, check_domain_suffix, check_service_name_length, hostname_change,
5212        my_ip_interfaces, name_change, resolve_max_packet_size, send_dns_outgoing_impl,
5213        valid_instance_name, valid_ip_on_intf, DaemonEvent, HostnameResolutionEvent, IfKind,
5214        MaxPacketSizeSelection, MyIntf, SendConfig, ServiceDaemon, ServiceEvent, ServiceInfo,
5215        GROUP_ADDR_V4, INITIAL_QUERY_DELAY_MAX_MILLIS, INITIAL_QUERY_DELAY_MIN_MILLIS,
5216        MAX_PKT_ABSOLUTE_IPV6, MAX_PKT_DEFAULT, MDNS_PORT, MIN_MAX_PACKET_SIZE,
5217        SHARED_RESPONSE_DELAY_MAX_MILLIS, SHARED_RESPONSE_DELAY_MIN_MILLIS,
5218    };
5219    use crate::{
5220        dns_parser::{
5221            DnsEntryExt, DnsIncoming, DnsOutgoing, DnsPointer, InterfaceId, RRType, ScopedIp,
5222            CLASS_IN, FLAGS_AA, FLAGS_QR_QUERY, FLAGS_QR_RESPONSE,
5223        },
5224        service_daemon::{add_answer_of_service, check_hostname},
5225    };
5226    use if_addrs::{IfAddr, Ifv4Addr, Ifv6Addr, Interface};
5227    use std::{
5228        collections::HashSet,
5229        net::{IpAddr, Ipv4Addr, Ipv6Addr, UdpSocket},
5230        time::{Duration, Instant, SystemTime},
5231    };
5232    use test_log::test;
5233
5234    /// Builds an interface address for the max packet size tests below.
5235    fn test_interface(name: &str, index: u32, addr: IfAddr) -> Interface {
5236        Interface {
5237            name: name.to_string(),
5238            addr,
5239            index: Some(index),
5240            oper_status: if_addrs::IfOperStatus::Up,
5241            is_p2p: false,
5242            #[cfg(windows)]
5243            adapter_name: String::new(),
5244        }
5245    }
5246
5247    fn test_ifaddr_v4(ip: Ipv4Addr) -> IfAddr {
5248        IfAddr::V4(Ifv4Addr {
5249            ip,
5250            netmask: Ipv4Addr::new(255, 255, 255, 0),
5251            broadcast: None,
5252            prefixlen: 24,
5253        })
5254    }
5255
5256    fn test_ifaddr_v6(ip: Ipv6Addr) -> IfAddr {
5257        IfAddr::V6(Ifv6Addr {
5258            ip,
5259            netmask: Ipv6Addr::from(u128::MAX << 64),
5260            broadcast: None,
5261            prefixlen: 64,
5262        })
5263    }
5264
5265    #[test]
5266    fn test_resolve_max_packet_size() {
5267        // en0 is dual-stack, en1 is IPv4 only.
5268        let interfaces = vec![
5269            test_interface("en0", 1, test_ifaddr_v4(Ipv4Addr::new(192, 168, 1, 2))),
5270            test_interface(
5271                "en0",
5272                1,
5273                test_ifaddr_v6(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 1)),
5274            ),
5275            test_interface("en1", 2, test_ifaddr_v4(Ipv4Addr::new(10, 0, 0, 2))),
5276        ];
5277
5278        let resolve = |selections: &[MaxPacketSizeSelection], if_index, is_ipv4| {
5279            resolve_max_packet_size(selections, &interfaces, if_index, is_ipv4)
5280        };
5281
5282        // No selection: every interface keeps the default.
5283        assert_eq!(resolve(&[], 1, true), MAX_PKT_DEFAULT);
5284        assert_eq!(resolve(&[], 1, false), MAX_PKT_DEFAULT);
5285
5286        // A selection by name applies to the interface it matches, both families.
5287        let by_name = vec![MaxPacketSizeSelection {
5288            if_kind: IfKind::Name("en0".to_string()),
5289            max_packet_size: 8000,
5290        }];
5291        assert_eq!(resolve(&by_name, 1, true), 8000);
5292        assert_eq!(resolve(&by_name, 1, false), 8000);
5293        assert_eq!(resolve(&by_name, 2, true), MAX_PKT_DEFAULT);
5294
5295        // For an interface matched more than once, the last selection wins.
5296        let overlapping = vec![
5297            MaxPacketSizeSelection {
5298                if_kind: IfKind::All,
5299                max_packet_size: 8000,
5300            },
5301            MaxPacketSizeSelection {
5302                if_kind: IfKind::Name("en1".to_string()),
5303                max_packet_size: 4000,
5304            },
5305        ];
5306        assert_eq!(resolve(&overlapping, 1, true), 8000);
5307        assert_eq!(resolve(&overlapping, 1, false), 8000);
5308        assert_eq!(resolve(&overlapping, 2, true), 4000);
5309
5310        // A selection of one address family leaves the other one alone.
5311        let v4_only = vec![MaxPacketSizeSelection {
5312            if_kind: IfKind::IPv4,
5313            max_packet_size: 8000,
5314        }];
5315        assert_eq!(resolve(&v4_only, 1, true), 8000);
5316        assert_eq!(resolve(&v4_only, 1, false), MAX_PKT_DEFAULT);
5317
5318        let v6_only = vec![MaxPacketSizeSelection {
5319            if_kind: IfKind::IPv6,
5320            max_packet_size: 8000,
5321        }];
5322        assert_eq!(resolve(&v6_only, 1, false), 8000);
5323        assert_eq!(resolve(&v6_only, 1, true), MAX_PKT_DEFAULT);
5324        // en1 has no IPv6 address, so the IPv6 selection cannot reach it.
5325        assert_eq!(resolve(&v6_only, 2, true), MAX_PKT_DEFAULT);
5326        assert_eq!(resolve(&v6_only, 2, false), MAX_PKT_DEFAULT);
5327
5328        // Same for an index selection, which names a family too.
5329        let by_index_v4 = vec![MaxPacketSizeSelection {
5330            if_kind: IfKind::IndexV4(1),
5331            max_packet_size: 8000,
5332        }];
5333        assert_eq!(resolve(&by_index_v4, 1, true), 8000);
5334        assert_eq!(resolve(&by_index_v4, 1, false), MAX_PKT_DEFAULT);
5335    }
5336
5337    /// A size outside [`MIN_MAX_PACKET_SIZE`]..=[`MAX_PKT_ABSOLUTE_IPV6`] is rejected
5338    /// rather than clamped, so what reaches the encoder is always legal.
5339    #[test]
5340    fn test_set_max_packet_size_range() {
5341        let daemon = ServiceDaemon::new().unwrap();
5342
5343        assert!(daemon
5344            .set_max_packet_size(IfKind::All, MIN_MAX_PACKET_SIZE - 1)
5345            .is_err());
5346        assert!(daemon
5347            .set_max_packet_size(IfKind::All, MAX_PKT_ABSOLUTE_IPV6 + 1)
5348            .is_err());
5349
5350        // Both ends of the range are accepted.
5351        assert!(daemon
5352            .set_max_packet_size(IfKind::All, MIN_MAX_PACKET_SIZE)
5353            .is_ok());
5354        assert!(daemon
5355            .set_max_packet_size(IfKind::All, MAX_PKT_ABSOLUTE_IPV6)
5356            .is_ok());
5357
5358        daemon.shutdown().unwrap();
5359    }
5360
5361    #[test]
5362    fn test_response_source_ifaddr_match() {
5363        // When an interface has multiple IPs on unrelated subnets,
5364        // handle_query should pick the IfAddr whose subnet contains the querier,
5365        // and fall back to None if none match.
5366        let ifaddr_a = IfAddr::V4(Ifv4Addr {
5367            ip: Ipv4Addr::new(192, 168, 1, 148),
5368            netmask: Ipv4Addr::new(255, 255, 255, 0),
5369            broadcast: None,
5370            prefixlen: 24,
5371        });
5372        let ifaddr_b = IfAddr::V4(Ifv4Addr {
5373            ip: Ipv4Addr::new(10, 238, 0, 51),
5374            netmask: Ipv4Addr::new(255, 255, 255, 0),
5375            broadcast: None,
5376            prefixlen: 24,
5377        });
5378
5379        let intf = MyIntf {
5380            name: "dummy0".to_string(),
5381            index: 1,
5382            addrs: HashSet::from([ifaddr_a.clone(), ifaddr_b.clone()]),
5383            max_packet_size_v4: MAX_PKT_DEFAULT,
5384            max_packet_size_v6: MAX_PKT_DEFAULT,
5385        };
5386
5387        let pick = |querier: IpAddr| -> Option<IfAddr> {
5388            intf.addrs
5389                .iter()
5390                .find(|a| valid_ip_on_intf(&querier, a))
5391                .cloned()
5392        };
5393
5394        assert_eq!(
5395            pick(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2))),
5396            Some(ifaddr_a)
5397        );
5398        assert_eq!(
5399            pick(IpAddr::V4(Ipv4Addr::new(10, 238, 0, 99))),
5400            Some(ifaddr_b)
5401        );
5402        // Querier not on any local subnet: fall back to None.
5403        assert_eq!(pick(IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1))), None);
5404    }
5405
5406    #[test]
5407    fn test_instance_name() {
5408        assert!(valid_instance_name("my-laser._printer._tcp.local."));
5409        assert!(valid_instance_name("my-laser.._printer._tcp.local."));
5410        assert!(!valid_instance_name("_printer._tcp.local."));
5411    }
5412
5413    #[test]
5414    fn test_legacy_unicast_response() {
5415        // RFC 6762 §6.7: a query whose UDP source port is not 5353 (a
5416        // "legacy" / "one-shot" querier, e.g. Android's getaddrinfo) must
5417        // get its response via unicast, sent back to the querier's source
5418        // address, with the question echoed and the cache-flush bit cleared.
5419        //
5420        // This test sends such a query from an ephemeral port and asserts
5421        // the response arrives on that same socket. The socket is not joined
5422        // to the mDNS multicast group, so a multicast-only reply would never
5423        // reach it — simply receiving the response proves it was unicast.
5424
5425        let intf_ip = match my_ip_interfaces(false)
5426            .into_iter()
5427            .find_map(|intf| match intf.ip() {
5428                IpAddr::V4(ip) => Some(ip),
5429                IpAddr::V6(_) => None,
5430            }) {
5431            Some(ip) => ip,
5432            None => {
5433                println!("No IPv4 interface available; skipping test.");
5434                return;
5435            }
5436        };
5437
5438        // Register a service with a unique hostname on this host.
5439        let daemon = ServiceDaemon::new().expect("Failed to create daemon");
5440        let unique = SystemTime::now()
5441            .duration_since(SystemTime::UNIX_EPOCH)
5442            .unwrap()
5443            .as_micros();
5444        let hostname = format!("legacy-unicast-test-{unique}.local.");
5445        let service_info = ServiceInfo::new(
5446            "_legacy-uni._udp.local.",
5447            "test_instance",
5448            &hostname,
5449            &[IpAddr::V4(intf_ip)] as &[IpAddr],
5450            5353, // arbitrary; the test only resolves the hostname
5451            None,
5452        )
5453        .expect("invalid service info");
5454        daemon.register(service_info).expect("register service");
5455
5456        // A one-shot querier: ephemeral source port, not 5353. Binding to
5457        // `intf_ip` directs the multicast query out that interface, which is
5458        // one the daemon is listening on.
5459        let querier = UdpSocket::bind((intf_ip, 0)).expect("bind querier socket");
5460        querier
5461            .set_multicast_loop_v4(true)
5462            .expect("enable multicast loopback");
5463        querier
5464            .set_read_timeout(Some(Duration::from_millis(500)))
5465            .expect("set read timeout");
5466        assert_ne!(
5467            querier.local_addr().unwrap().port(),
5468            MDNS_PORT,
5469            "querier must use an ephemeral (non-5353) source port"
5470        );
5471
5472        // Build a one-question A-record query for our hostname.
5473        let mut query = DnsOutgoing::new(FLAGS_QR_QUERY);
5474        query.add_question(&hostname, RRType::A);
5475        let query_packet = query
5476            .to_data_on_wire(MAX_PKT_DEFAULT, true)
5477            .pop()
5478            .expect("query serialized to one packet");
5479
5480        let if_id = InterfaceId {
5481            name: "test".to_string(),
5482            index: 0,
5483        };
5484
5485        // The service is announced asynchronously after register(), so retry
5486        // the query until our answer comes back or the deadline passes.
5487        let deadline = Instant::now() + Duration::from_secs(8);
5488        let mut response = None;
5489        'outer: while Instant::now() < deadline {
5490            querier
5491                .send_to(&query_packet, (GROUP_ADDR_V4, MDNS_PORT))
5492                .expect("send query");
5493
5494            // Drain whatever has arrived; on read timeout the loop ends and
5495            // we re-send the query.
5496            let mut buf = [0u8; 1500];
5497            while let Ok((len, from)) = querier.recv_from(&mut buf) {
5498                let Ok(msg) = DnsIncoming::new(buf[..len].to_vec(), if_id.clone()) else {
5499                    continue;
5500                };
5501                if msg.is_response()
5502                    && msg
5503                        .answers()
5504                        .iter()
5505                        .any(|a| a.get_name().eq_ignore_ascii_case(&hostname))
5506                {
5507                    response = Some((msg, from));
5508                    break 'outer;
5509                }
5510            }
5511        }
5512
5513        let (msg, from) = response.expect(
5514            "expected a unicast response to the legacy query; \
5515             a multicast-only reply would never reach this un-joined socket",
5516        );
5517
5518        // The reply came back to our ephemeral socket, from the mDNS port.
5519        assert_eq!(
5520            from.port(),
5521            MDNS_PORT,
5522            "response should originate from the mDNS port"
5523        );
5524
5525        // RFC 6762 §6.7: the original question must be echoed.
5526        assert!(
5527            msg.questions()
5528                .iter()
5529                .any(|q| q.entry_name().eq_ignore_ascii_case(&hostname)),
5530            "legacy unicast response must echo the question section"
5531        );
5532
5533        // RFC 6762 §6.7 / §10.2: the answer must be the A record we asked
5534        // for, with the cache-flush bit cleared.
5535        let answer = msg
5536            .answers()
5537            .iter()
5538            .find(|a| a.get_name().eq_ignore_ascii_case(&hostname))
5539            .expect("response contains an answer for our hostname");
5540        assert_eq!(
5541            answer.get_type(),
5542            RRType::A,
5543            "an A query should be answered with an A record"
5544        );
5545        assert!(
5546            !answer.get_cache_flush(),
5547            "legacy unicast responses must clear the cache-flush bit"
5548        );
5549
5550        daemon.shutdown().unwrap();
5551    }
5552
5553    #[test]
5554    fn test_shared_response_delay_bounds() {
5555        // A shared-record (PTR) response is delayed by a uniform-random amount.
5556        // We deviate from the RFC 6762 §6 suggested 20-120 ms window and use a
5557        // shorter 10-50 ms delay (`MAX` is the exclusive upper bound, so the
5558        // actual delay is 10..=49 ms).
5559        assert_eq!(SHARED_RESPONSE_DELAY_MIN_MILLIS, 10);
5560        assert_eq!(SHARED_RESPONSE_DELAY_MAX_MILLIS, 50);
5561        for _ in 0..10_000 {
5562            let d =
5563                fastrand::u64(SHARED_RESPONSE_DELAY_MIN_MILLIS..SHARED_RESPONSE_DELAY_MAX_MILLIS);
5564            assert!(
5565                (SHARED_RESPONSE_DELAY_MIN_MILLIS..SHARED_RESPONSE_DELAY_MAX_MILLIS).contains(&d),
5566                "delay {} ms is outside the configured {}-{} ms range",
5567                d,
5568                SHARED_RESPONSE_DELAY_MIN_MILLIS,
5569                SHARED_RESPONSE_DELAY_MAX_MILLIS
5570            );
5571        }
5572    }
5573
5574    #[test]
5575    fn test_initial_query_delayed() {
5576        // RFC 6762 §5.2: a querier delays the first query of a continuous
5577        // monitoring series by a random amount (we use a 10-50 ms window).
5578        // Start a browse and observe, on a socket joined to the mDNS group, the
5579        // daemon's first PTR query for our (unique) service type. Assert it
5580        // arrives no sooner than ~10 ms after `browse()` — i.e. it is not sent
5581        // immediately.
5582        use socket2::{Domain, Protocol, Socket, Type};
5583
5584        let (intf, intf_ip) = match my_ip_interfaces(false)
5585            .into_iter()
5586            .find_map(|intf| match intf.ip() {
5587                IpAddr::V4(ip) if !ip.is_loopback() => Some((intf, ip)),
5588                _ => None,
5589            }) {
5590            Some(pair) => pair,
5591            None => {
5592                println!("No IPv4 interface available; skipping test.");
5593                return;
5594            }
5595        };
5596        let interface_id = InterfaceId::from(&intf);
5597
5598        // A receiver socket joined to the mDNS group on this interface. The
5599        // daemon loops back its multicast by default, so its outgoing query is
5600        // delivered here on the same host.
5601        let sock = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP)).unwrap();
5602        sock.set_reuse_address(true).unwrap();
5603        #[cfg(unix)]
5604        sock.set_reuse_port(true).unwrap();
5605        sock.bind(&std::net::SocketAddr::from((Ipv4Addr::UNSPECIFIED, MDNS_PORT)).into())
5606            .unwrap();
5607        sock.join_multicast_v4(&GROUP_ADDR_V4, &intf_ip).unwrap();
5608        sock.set_read_timeout(Some(Duration::from_millis(200)))
5609            .unwrap();
5610        let sock: UdpSocket = sock.into();
5611
5612        // Unique service type, kept within the RFC 6763 §7.2 15-byte label limit.
5613        let unique = SystemTime::now()
5614            .duration_since(SystemTime::UNIX_EPOCH)
5615            .unwrap()
5616            .as_micros()
5617            % 1_000_000_000;
5618        let service_type = format!("_qd{unique}._udp.local.");
5619
5620        let daemon = ServiceDaemon::new().expect("Failed to create daemon");
5621
5622        let sent_at = Instant::now();
5623        let _browse = daemon.browse(&service_type).expect("browse");
5624
5625        // Read packets until we see our own PTR query or time out. The 10-50 ms
5626        // jitter plus command/scheduling latency comfortably fits in 2 s.
5627        let deadline = Instant::now() + Duration::from_secs(2);
5628        let mut buf = [0u8; 2048];
5629        let mut measured = None;
5630        while Instant::now() < deadline {
5631            let n = match sock.recv_from(&mut buf) {
5632                Ok((n, _)) => n,
5633                Err(_) => continue, // read timeout; keep polling until the deadline
5634            };
5635            let Ok(msg) = DnsIncoming::new(buf[..n].to_vec(), interface_id.clone()) else {
5636                continue;
5637            };
5638            if msg.is_query()
5639                && msg
5640                    .questions()
5641                    .iter()
5642                    .any(|q| q.entry_name() == service_type)
5643            {
5644                measured = Some(sent_at.elapsed());
5645                break;
5646            }
5647        }
5648
5649        daemon.shutdown().unwrap();
5650
5651        let elapsed = measured.expect("expected the daemon to send a PTR query for our browse");
5652        let tolerance = Duration::from_millis(2);
5653        assert!(
5654            elapsed + tolerance >= Duration::from_millis(INITIAL_QUERY_DELAY_MIN_MILLIS),
5655            "first browse query was sent after only {:?}; the first query of a series must be \
5656             delayed (10-50 ms window), not sent immediately",
5657            elapsed
5658        );
5659
5660        // Upper bound: the query must fall within the jitter window. Allow
5661        // generous slack above INITIAL_QUERY_DELAY_MAX_MILLIS for command
5662        // handoff, event-loop wakeup, and loopback latency, while still catching
5663        // a regression to a much larger delay (e.g. the RFC's 120 ms window).
5664        let scheduling_slack = Duration::from_millis(50);
5665        assert!(
5666            elapsed <= Duration::from_millis(INITIAL_QUERY_DELAY_MAX_MILLIS) + scheduling_slack,
5667            "first browse query was sent after {:?}, beyond the {}-{} ms jitter window (plus slack)",
5668            elapsed,
5669            INITIAL_QUERY_DELAY_MIN_MILLIS,
5670            INITIAL_QUERY_DELAY_MAX_MILLIS
5671        );
5672    }
5673
5674    #[test]
5675    fn test_shared_ptr_response_delayed() {
5676        // RFC 6762 §6: a PTR (shared record set) response sent by multicast is
5677        // delayed by a uniform-random amount (we use a 10-50 ms window). Register
5678        // a service, then as a proper multicast querier (source port 5353) send a
5679        // PTR query and assert the daemon emits its response no sooner than ~10 ms
5680        // after the query. (A legacy unicast querier gets an *immediate* response
5681        // instead; see `test_legacy_unicast_response`.)
5682        use socket2::{Domain, Protocol, Socket, Type};
5683
5684        let intf_ip = match my_ip_interfaces(false)
5685            .into_iter()
5686            .find_map(|intf| match intf.ip() {
5687                IpAddr::V4(ip) if !ip.is_loopback() => Some(ip),
5688                _ => None,
5689            }) {
5690            Some(ip) => ip,
5691            None => {
5692                println!("No IPv4 interface available; skipping test.");
5693                return;
5694            }
5695        };
5696
5697        let daemon = ServiceDaemon::new().expect("Failed to create daemon");
5698        let monitor = daemon.monitor().expect("monitor daemon events");
5699
5700        // Keep the service name (the `_sd…` label) within the 15-byte limit
5701        // that RFC 6763 §7.2 imposes, while staying unique per run.
5702        let unique = SystemTime::now()
5703            .duration_since(SystemTime::UNIX_EPOCH)
5704            .unwrap()
5705            .as_micros()
5706            % 1_000_000_000;
5707        let service_type = format!("_sd{unique}._udp.local.");
5708        let hostname = format!("sd{unique}.local.");
5709        let service_info = ServiceInfo::new(
5710            &service_type,
5711            "test_instance",
5712            &hostname,
5713            &[IpAddr::V4(intf_ip)] as &[IpAddr],
5714            5353,
5715            None,
5716        )
5717        .expect("invalid service info");
5718        daemon.register(service_info).expect("register service");
5719
5720        // A proper multicast querier: source port 5353 so the daemon takes the
5721        // shared-record (delayed) path rather than the legacy-unicast one. We only
5722        // *send* on this socket; the response is observed through the monitor.
5723        let sock = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP)).unwrap();
5724        sock.set_reuse_address(true).unwrap();
5725        #[cfg(unix)]
5726        sock.set_reuse_port(true).unwrap();
5727        sock.bind(&std::net::SocketAddr::from((Ipv4Addr::UNSPECIFIED, MDNS_PORT)).into())
5728            .unwrap();
5729        sock.set_multicast_if_v4(&intf_ip).unwrap();
5730        // Loop the query back to the daemon's socket on this same host.
5731        sock.set_multicast_loop_v4(true).unwrap();
5732        let sock: UdpSocket = sock.into();
5733
5734        // Build the PTR query for our service type.
5735        let mut query = DnsOutgoing::new(FLAGS_QR_QUERY);
5736        query.add_question(&service_type, RRType::PTR);
5737        let query_packet = query
5738            .to_data_on_wire(MAX_PKT_DEFAULT, true)
5739            .pop()
5740            .expect("one packet");
5741
5742        // Wait for the initial announcements and the §6 rate-limit window (1s) to
5743        // pass, so our query elicits a fresh (delayed) response instead of being
5744        // suppressed by the rate limiter.
5745        std::thread::sleep(Duration::from_secs(3));
5746
5747        // Retry until the daemon emits a Respond for our query. A query landing
5748        // inside the 1 s multicast rate-limit window is rate-limited to an empty
5749        // response (no send, no event), so we simply re-query on the next pass.
5750        let deadline = Instant::now() + Duration::from_secs(8);
5751        let mut measured = None;
5752        while Instant::now() < deadline {
5753            // Drop any Respond events queued earlier so we time only the response
5754            // to the query we are about to send.
5755            while monitor.try_recv().is_ok() {}
5756
5757            let sent_at = Instant::now();
5758            sock.send_to(&query_packet, (GROUP_ADDR_V4, MDNS_PORT))
5759                .expect("send query");
5760
5761            // The delay window is 10-50 ms; 700 ms comfortably covers it plus any
5762            // scheduling slack. Ignore unrelated events; on timeout, re-query.
5763            let attempt_deadline = sent_at + Duration::from_millis(700);
5764            loop {
5765                let remaining = attempt_deadline.saturating_duration_since(Instant::now());
5766                if remaining.is_zero() {
5767                    break;
5768                }
5769                match monitor.recv_timeout(remaining) {
5770                    Ok(DaemonEvent::Respond(_)) => {
5771                        measured = Some(sent_at.elapsed());
5772                        break;
5773                    }
5774                    Ok(_) => continue, // some other daemon event; keep waiting
5775                    Err(_) => break,   // timed out; re-query
5776                }
5777            }
5778            if measured.is_some() {
5779                break;
5780            }
5781        }
5782
5783        let elapsed =
5784            measured.expect("expected the daemon to respond to our PTR query within the deadline");
5785        assert!(
5786            elapsed >= Duration::from_millis(8),
5787            "PTR response was sent after only {:?}; a shared-record response must be \
5788             delayed (10-50 ms window), not sent immediately",
5789            elapsed
5790        );
5791        assert!(
5792            elapsed <= Duration::from_millis(600),
5793            "PTR response was sent after {:?}; expected within the 10-50 ms delay window",
5794            elapsed
5795        );
5796
5797        daemon.shutdown().unwrap();
5798    }
5799
5800    #[test]
5801    fn test_check_service_name_length() {
5802        let result = check_service_name_length("_tcp", 100);
5803        assert!(result.is_err());
5804        if let Err(e) = result {
5805            println!("{}", e);
5806        }
5807    }
5808
5809    #[test]
5810    fn test_check_hostname() {
5811        // valid hostnames
5812        for hostname in &[
5813            "my_host.local.",
5814            &("A".repeat(255 - ".local.".len()) + ".local."),
5815        ] {
5816            let result = check_hostname(hostname);
5817            assert!(result.is_ok());
5818        }
5819
5820        // erroneous hostnames
5821        for hostname in &[
5822            "my_host.local",
5823            ".local.",
5824            &("A".repeat(256 - ".local.".len()) + ".local."),
5825        ] {
5826            let result = check_hostname(hostname);
5827            assert!(result.is_err());
5828            if let Err(e) = result {
5829                println!("{}", e);
5830            }
5831        }
5832    }
5833
5834    #[test]
5835    fn test_check_domain_suffix() {
5836        assert!(check_domain_suffix("_missing_dot._tcp.local").is_err());
5837        assert!(check_domain_suffix("_missing_bar.tcp.local.").is_err());
5838        assert!(check_domain_suffix("_mis_spell._tpp.local.").is_err());
5839        assert!(check_domain_suffix("_mis_spell._upp.local.").is_err());
5840        assert!(check_domain_suffix("_has_dot._tcp.local.").is_ok());
5841        assert!(check_domain_suffix("_goodname._udp.local.").is_ok());
5842    }
5843
5844    #[test]
5845    fn test_service_with_temporarily_invalidated_ptr() {
5846        // Create a daemon
5847        let d = ServiceDaemon::new().expect("Failed to create daemon");
5848
5849        let service = "_test_inval_ptr._udp.local.";
5850        let host_name = "my_host_tmp_invalidated_ptr.local.";
5851        let intfs: Vec<_> = my_ip_interfaces(false);
5852        let intf_ips: Vec<_> = intfs.iter().map(|intf| intf.ip()).collect();
5853        let port = 5201;
5854        let my_service =
5855            ServiceInfo::new(service, "my_instance", host_name, &intf_ips[..], port, None)
5856                .expect("invalid service info")
5857                .enable_addr_auto();
5858        let result = d.register(my_service.clone());
5859        assert!(result.is_ok());
5860
5861        // Browse for a service
5862        let browse_chan = d.browse(service).unwrap();
5863        let timeout = Duration::from_secs(2);
5864        let mut resolved = false;
5865
5866        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5867            match event {
5868                ServiceEvent::ServiceResolved(info) => {
5869                    resolved = true;
5870                    println!("Resolved a service of {}", &info.fullname);
5871                    break;
5872                }
5873                e => {
5874                    println!("Received event {:?}", e);
5875                }
5876            }
5877        }
5878
5879        assert!(resolved);
5880
5881        println!("Stopping browse of {}", service);
5882        // Pause browsing so restarting will cause a new immediate query.
5883        // Unregistering will not work here, it will invalidate all the records.
5884        d.stop_browse(service).unwrap();
5885
5886        // Ensure the search is stopped.
5887        // Reduces the chance of receiving an answer adding the ptr back to the
5888        // cache causing the later browse to return directly from the cache.
5889        // (which invalidates what this test is trying to test for.)
5890        let mut stopped = false;
5891        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5892            match event {
5893                ServiceEvent::SearchStopped(_) => {
5894                    stopped = true;
5895                    println!("Stopped browsing service");
5896                    break;
5897                }
5898                // Other `ServiceResolved` messages may be received
5899                // here as they come from different interfaces.
5900                // That's fine for this test.
5901                e => {
5902                    println!("Received event {:?}", e);
5903                }
5904            }
5905        }
5906
5907        assert!(stopped);
5908
5909        // Invalidate the ptr from the service to the host.
5910        let invalidate_ptr_packet = DnsPointer::new(
5911            my_service.get_type(),
5912            RRType::PTR,
5913            CLASS_IN,
5914            0,
5915            my_service.get_fullname().to_string(),
5916        );
5917
5918        let mut packet_buffer = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
5919        packet_buffer.add_additional_answer(invalidate_ptr_packet);
5920
5921        for intf in intfs {
5922            let sock = _new_socket_bind(&intf, true).unwrap();
5923            send_dns_outgoing_impl(
5924                &packet_buffer,
5925                &intf.name,
5926                intf.index.unwrap_or(0),
5927                &intf.addr,
5928                &sock.pktinfo,
5929                SendConfig {
5930                    port: MDNS_PORT,
5931                    max_packet_size: MAX_PKT_DEFAULT,
5932                    is_ipv4: intf.addr.ip().is_ipv4(),
5933                },
5934                None,
5935            )
5936            .unwrap();
5937        }
5938
5939        println!(
5940            "Sent PTR record invalidation. Starting second browse for {}",
5941            service
5942        );
5943
5944        // Restart the browse to force the sender to re-send the announcements.
5945        let browse_chan = d.browse(service).unwrap();
5946
5947        resolved = false;
5948        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5949            match event {
5950                ServiceEvent::ServiceResolved(info) => {
5951                    resolved = true;
5952                    println!("Resolved a service of {}", &info.fullname);
5953                    break;
5954                }
5955                e => {
5956                    println!("Received event {:?}", e);
5957                }
5958            }
5959        }
5960
5961        assert!(resolved);
5962        d.shutdown().unwrap();
5963    }
5964
5965    #[test]
5966    fn test_expired_srv() {
5967        // construct service info
5968        let service_type = "_expired-srv._udp.local.";
5969        let instance = "test_instance";
5970        let host_name = "expired_srv_host.local.";
5971        let mut my_service = ServiceInfo::new(service_type, instance, host_name, "", 5023, None)
5972            .unwrap()
5973            .enable_addr_auto();
5974        // let fullname = my_service.get_fullname().to_string();
5975
5976        // set SRV to expire soon.
5977        let new_ttl = 3; // for testing only.
5978        my_service._set_host_ttl(new_ttl);
5979
5980        // register my service
5981        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
5982        let result = mdns_server.register(my_service);
5983        assert!(result.is_ok());
5984
5985        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
5986        let browse_chan = mdns_client.browse(service_type).unwrap();
5987        let timeout = Duration::from_secs(2);
5988        let mut resolved = false;
5989
5990        while let Ok(event) = browse_chan.recv_timeout(timeout) {
5991            if let ServiceEvent::ServiceResolved(info) = event {
5992                resolved = true;
5993                println!("Resolved a service of {}", &info.fullname);
5994                break;
5995            }
5996        }
5997
5998        assert!(resolved);
5999
6000        // Exit the server so that no more responses.
6001        mdns_server.shutdown().unwrap();
6002
6003        // SRV record in the client cache will expire.
6004        let expire_timeout = Duration::from_secs(new_ttl as u64);
6005        while let Ok(event) = browse_chan.recv_timeout(expire_timeout) {
6006            if let ServiceEvent::ServiceRemoved(service_type, full_name) = event {
6007                println!("Service removed: {}: {}", &service_type, &full_name);
6008                break;
6009            }
6010        }
6011    }
6012
6013    #[test]
6014    fn test_hostname_resolution_address_removed() {
6015        // Create a mDNS server
6016        let server = ServiceDaemon::new().expect("Failed to create server");
6017        let hostname = "addr_remove_host._tcp.local.";
6018        let service_ip_addr: ScopedIp = my_ip_interfaces(false)
6019            .iter()
6020            .find(|iface| iface.ip().is_ipv4())
6021            .map(|iface| iface.into())
6022            .unwrap();
6023
6024        let mut my_service = ServiceInfo::new(
6025            "_host_res_test._tcp.local.",
6026            "my_instance",
6027            hostname,
6028            service_ip_addr.to_ip_addr(),
6029            1234,
6030            None,
6031        )
6032        .expect("invalid service info");
6033
6034        // Set a short TTL for addresses for testing.
6035        let addr_ttl = 2;
6036        my_service._set_host_ttl(addr_ttl); // Expire soon
6037
6038        server.register(my_service).unwrap();
6039
6040        // Create a mDNS client for resolving the hostname.
6041        let client = ServiceDaemon::new().expect("Failed to create client");
6042        let event_receiver = client.resolve_hostname(hostname, None).unwrap();
6043        let resolved = loop {
6044            match event_receiver.recv() {
6045                Ok(HostnameResolutionEvent::AddressesFound(found_hostname, addresses)) => {
6046                    assert!(found_hostname == hostname);
6047                    assert!(addresses.contains(&service_ip_addr));
6048                    println!("address found: {:?}", &addresses);
6049                    break true;
6050                }
6051                Ok(HostnameResolutionEvent::SearchStopped(_)) => break false,
6052                Ok(_event) => {}
6053                Err(_) => break false,
6054            }
6055        };
6056
6057        assert!(resolved);
6058
6059        // Shutdown the server so no more responses / refreshes for addresses.
6060        server.shutdown().unwrap();
6061
6062        // Wait till hostname address record expires, with 1 second grace period.
6063        let timeout = Duration::from_secs(addr_ttl as u64 + 1);
6064        let removed = loop {
6065            match event_receiver.recv_timeout(timeout) {
6066                Ok(HostnameResolutionEvent::AddressesRemoved(removed_host, addresses)) => {
6067                    assert!(removed_host == hostname);
6068                    assert!(addresses.contains(&service_ip_addr));
6069
6070                    println!(
6071                        "address removed: hostname: {} addresses: {:?}",
6072                        &hostname, &addresses
6073                    );
6074                    break true;
6075                }
6076                Ok(_event) => {}
6077                Err(_) => {
6078                    break false;
6079                }
6080            }
6081        };
6082
6083        assert!(removed);
6084
6085        client.shutdown().unwrap();
6086    }
6087
6088    #[test]
6089    fn test_refresh_ptr() {
6090        // construct service info
6091        let service_type = "_refresh-ptr._udp.local.";
6092        let instance = "test_instance";
6093        let host_name = "refresh_ptr_host.local.";
6094        let service_ip_addr = my_ip_interfaces(false)
6095            .iter()
6096            .find(|iface| iface.ip().is_ipv4())
6097            .map(|iface| iface.ip())
6098            .unwrap();
6099
6100        let mut my_service = ServiceInfo::new(
6101            service_type,
6102            instance,
6103            host_name,
6104            service_ip_addr,
6105            5023,
6106            None,
6107        )
6108        .unwrap();
6109
6110        let new_ttl = 3; // for testing only.
6111        my_service._set_other_ttl(new_ttl);
6112
6113        // register my service
6114        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6115        let result = mdns_server.register(my_service);
6116        assert!(result.is_ok());
6117
6118        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6119        let browse_chan = mdns_client.browse(service_type).unwrap();
6120        let timeout = Duration::from_millis(1500); // Give at least 1 second for the service probing.
6121        let mut resolved = false;
6122
6123        // resolve the service first.
6124        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6125            if let ServiceEvent::ServiceResolved(info) = event {
6126                resolved = true;
6127                println!("Resolved a service of {}", &info.fullname);
6128                break;
6129            }
6130        }
6131
6132        assert!(resolved);
6133
6134        // wait over 80% of TTL, and refresh PTR should be sent out.
6135        let timeout = Duration::from_millis(new_ttl as u64 * 1000 * 90 / 100);
6136        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6137            println!("event: {:?}", &event);
6138        }
6139
6140        // verify refresh counter.
6141        let metrics_chan = mdns_client.get_metrics().unwrap();
6142        let metrics = metrics_chan.recv_timeout(timeout).unwrap();
6143        let ptr_refresh_counter = metrics["cache-refresh-ptr"];
6144        assert_eq!(ptr_refresh_counter, 1);
6145        let srvtxt_refresh_counter = metrics["cache-refresh-srv-txt"];
6146        assert_eq!(srvtxt_refresh_counter, 1);
6147
6148        // Exit the server so that no more responses.
6149        mdns_server.shutdown().unwrap();
6150        mdns_client.shutdown().unwrap();
6151    }
6152
6153    #[test]
6154    fn test_name_change() {
6155        assert_eq!(name_change("foo.local."), "foo (2).local.");
6156        assert_eq!(name_change("foo (2).local."), "foo (3).local.");
6157        assert_eq!(name_change("foo (9).local."), "foo (10).local.");
6158        assert_eq!(name_change("foo"), "foo (2)");
6159        assert_eq!(name_change("foo (2)"), "foo (3)");
6160        assert_eq!(name_change(""), " (2)");
6161
6162        // Additional edge cases
6163        assert_eq!(name_change("foo (abc)"), "foo (abc) (2)"); // Invalid number
6164        assert_eq!(name_change("foo (2"), "foo (2 (2)"); // Missing closing parenthesis
6165        assert_eq!(name_change("foo (2) extra"), "foo (2) extra (2)"); // Extra text after number
6166    }
6167
6168    #[test]
6169    fn test_hostname_change() {
6170        assert_eq!(hostname_change("foo.local."), "foo-2.local.");
6171        assert_eq!(hostname_change("foo"), "foo-2");
6172        assert_eq!(hostname_change("foo-2.local."), "foo-3.local.");
6173        assert_eq!(hostname_change("foo-9"), "foo-10");
6174        assert_eq!(hostname_change("test-42.domain."), "test-43.domain.");
6175    }
6176
6177    #[test]
6178    fn test_add_answer_txt_ttl() {
6179        // construct a simple service info
6180        let service_type = "_test_add_answer._udp.local.";
6181        let instance = "test_instance";
6182        let host_name = "add_answer_host.local.";
6183        let service_intf = my_ip_interfaces(false)
6184            .into_iter()
6185            .find(|iface| iface.ip().is_ipv4())
6186            .unwrap();
6187        let service_ip_addr = service_intf.ip();
6188        let my_service = ServiceInfo::new(
6189            service_type,
6190            instance,
6191            host_name,
6192            service_ip_addr,
6193            5023,
6194            None,
6195        )
6196        .unwrap();
6197
6198        // construct a DnsOutgoing message
6199        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE | FLAGS_AA);
6200
6201        // Construct a dummy DnsIncoming message
6202        let mut dummy_data = out.to_data_on_wire(MAX_PKT_DEFAULT, true);
6203        let interface_id = InterfaceId::from(&service_intf);
6204        let incoming = DnsIncoming::new(dummy_data.pop().unwrap(), interface_id).unwrap();
6205
6206        // Add an answer of TXT type for the service.
6207        let if_addrs = vec![service_intf.ip()];
6208        add_answer_of_service(
6209            &mut out,
6210            &incoming,
6211            instance,
6212            &my_service,
6213            RRType::TXT,
6214            if_addrs,
6215        );
6216
6217        // Check if the answer was added correctly
6218        assert!(
6219            out.answers_count() > 0,
6220            "No answers added to the outgoing message"
6221        );
6222
6223        // Check if the first answer is of type TXT
6224        let answer = out._answers().first().unwrap();
6225        assert_eq!(answer.0.get_type(), RRType::TXT);
6226
6227        // Check TTL is set properly for the TXT record
6228        assert_eq!(answer.0.get_record().get_ttl(), my_service.get_other_ttl());
6229    }
6230
6231    #[test]
6232    fn test_interface_flip() {
6233        // start a server
6234        let ty_domain = "_intf-flip._udp.local.";
6235        let host_name = "intf_flip.local.";
6236        let now = SystemTime::now()
6237            .duration_since(SystemTime::UNIX_EPOCH)
6238            .unwrap();
6239        let instance_name = now.as_micros().to_string(); // Create a unique name.
6240        let port = 5200;
6241
6242        // Get a single IPv4 address
6243        let (ip_addr1, intf_name) = my_ip_interfaces(false)
6244            .iter()
6245            .find(|iface| iface.ip().is_ipv4())
6246            .map(|iface| (iface.ip(), iface.name.clone()))
6247            .unwrap();
6248
6249        println!("Using interface {} with IP {}", intf_name, ip_addr1);
6250
6251        // Register the service.
6252        let service1 = ServiceInfo::new(ty_domain, &instance_name, host_name, ip_addr1, port, None)
6253            .expect("valid service info");
6254        let server1 = ServiceDaemon::new().expect("failed to start server");
6255        server1
6256            .register(service1)
6257            .expect("Failed to register service1");
6258
6259        // wait for the service announced.
6260        std::thread::sleep(Duration::from_secs(2));
6261
6262        // start a client
6263        let client = ServiceDaemon::new().expect("failed to start client");
6264
6265        let receiver = client.browse(ty_domain).unwrap();
6266
6267        let timeout = Duration::from_secs(3);
6268        let mut got_data = false;
6269
6270        while let Ok(event) = receiver.recv_timeout(timeout) {
6271            if let ServiceEvent::ServiceResolved(_) = event {
6272                println!("Received ServiceResolved event");
6273                got_data = true;
6274                break;
6275            }
6276        }
6277
6278        assert!(got_data, "Should receive ServiceResolved event");
6279
6280        // Set a short IP check interval to detect interface changes quickly.
6281        client.set_ip_check_interval(1).unwrap();
6282
6283        // Now shutdown the interface and expect the client to lose the service.
6284        println!("Shutting down interface {}", &intf_name);
6285        client.test_down_interface(&intf_name).unwrap();
6286
6287        let mut got_removed = false;
6288
6289        while let Ok(event) = receiver.recv_timeout(timeout) {
6290            if let ServiceEvent::ServiceRemoved(ty_domain, instance) = event {
6291                got_removed = true;
6292                println!("removed: {ty_domain} : {instance}");
6293                break;
6294            }
6295        }
6296        assert!(got_removed, "Should receive ServiceRemoved event");
6297
6298        println!("Bringing up interface {}", &intf_name);
6299        client.test_up_interface(&intf_name).unwrap();
6300        let mut got_data = false;
6301        while let Ok(event) = receiver.recv_timeout(timeout) {
6302            if let ServiceEvent::ServiceResolved(resolved) = event {
6303                got_data = true;
6304                println!("Received ServiceResolved: {:?}", resolved);
6305                break;
6306            }
6307        }
6308        assert!(
6309            got_data,
6310            "Should receive ServiceResolved event after interface is back up"
6311        );
6312
6313        server1.shutdown().unwrap();
6314        client.shutdown().unwrap();
6315    }
6316
6317    #[test]
6318    fn test_cache_only() {
6319        // construct service info
6320        let service_type = "_cache_only._udp.local.";
6321        let instance = "test_instance";
6322        let host_name = "cache_only_host.local.";
6323        let service_ip_addr = my_ip_interfaces(false)
6324            .iter()
6325            .find(|iface| iface.ip().is_ipv4())
6326            .map(|iface| iface.ip())
6327            .unwrap();
6328
6329        let mut my_service = ServiceInfo::new(
6330            service_type,
6331            instance,
6332            host_name,
6333            service_ip_addr,
6334            5023,
6335            None,
6336        )
6337        .unwrap();
6338
6339        let new_ttl = 3; // for testing only.
6340        my_service._set_other_ttl(new_ttl);
6341
6342        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6343
6344        // make a single browse request to record that we are interested in the service.  This ensures that
6345        // subsequent announcements are cached.
6346        let browse_chan = mdns_client.browse_cache(service_type).unwrap();
6347        std::thread::sleep(Duration::from_secs(2));
6348
6349        // register my service
6350        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6351        let result = mdns_server.register(my_service);
6352        assert!(result.is_ok());
6353
6354        let timeout = Duration::from_millis(1500); // Give at least 1 second for the service probing.
6355        let mut resolved = false;
6356
6357        // resolve the service.
6358        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6359            if let ServiceEvent::ServiceResolved(info) = event {
6360                resolved = true;
6361                println!("Resolved a service of {}", &info.get_fullname());
6362                break;
6363            }
6364        }
6365
6366        assert!(resolved);
6367
6368        // Exit the server so that no more responses.
6369        mdns_server.shutdown().unwrap();
6370        mdns_client.shutdown().unwrap();
6371    }
6372
6373    #[test]
6374    fn test_cache_only_unsolicited() {
6375        let service_type = "_c_unsolicit._udp.local.";
6376        let instance = "test_instance";
6377        let host_name = "c_unsolicit_host.local.";
6378        let service_ip_addr = my_ip_interfaces(false)
6379            .iter()
6380            .find(|iface| iface.ip().is_ipv4())
6381            .map(|iface| iface.ip())
6382            .unwrap();
6383
6384        let my_service = ServiceInfo::new(
6385            service_type,
6386            instance,
6387            host_name,
6388            service_ip_addr,
6389            5023,
6390            None,
6391        )
6392        .unwrap();
6393
6394        // register my service
6395        let mdns_server = ServiceDaemon::new().expect("Failed to create mdns server");
6396        let result = mdns_server.register(my_service);
6397        assert!(result.is_ok());
6398
6399        let mdns_client = ServiceDaemon::new().expect("Failed to create mdns client");
6400        mdns_client.accept_unsolicited(true).unwrap();
6401
6402        // Wait a bit for the service announcements to go out, before calling browse_cache.  This ensures
6403        // that the announcements are treated as unsolicited
6404        std::thread::sleep(Duration::from_secs(2));
6405        let browse_chan = mdns_client.browse_cache(service_type).unwrap();
6406        let timeout = Duration::from_millis(1500); // Give at least 1 second for the service probing.
6407        let mut resolved = false;
6408
6409        // resolve the service.
6410        while let Ok(event) = browse_chan.recv_timeout(timeout) {
6411            if let ServiceEvent::ServiceResolved(info) = event {
6412                resolved = true;
6413                println!("Resolved a service of {}", &info.get_fullname());
6414                break;
6415            }
6416        }
6417
6418        assert!(resolved);
6419
6420        // Exit the server so that no more responses.
6421        mdns_server.shutdown().unwrap();
6422        mdns_client.shutdown().unwrap();
6423    }
6424
6425    #[test]
6426    fn test_custom_port_isolation() {
6427        // This test verifies:
6428        // 1. Daemons on a custom port can communicate with each other
6429        // 2. Daemons on different ports are isolated (no cross-talk)
6430
6431        let service_type = "_custom_port._udp.local.";
6432        let instance_custom = "custom_port_instance";
6433        let instance_default = "default_port_instance";
6434        let host_name = "custom_port_host.local.";
6435
6436        let service_ip_addr = my_ip_interfaces(false)
6437            .iter()
6438            .find(|iface| iface.ip().is_ipv4())
6439            .map(|iface| iface.ip())
6440            .expect("Test requires an IPv4 interface");
6441
6442        // Create service info for custom port (5454)
6443        let service_custom = ServiceInfo::new(
6444            service_type,
6445            instance_custom,
6446            host_name,
6447            service_ip_addr,
6448            8080,
6449            None,
6450        )
6451        .unwrap();
6452
6453        // Create service info for default port (5353)
6454        let service_default = ServiceInfo::new(
6455            service_type,
6456            instance_default,
6457            host_name,
6458            service_ip_addr,
6459            8081,
6460            None,
6461        )
6462        .unwrap();
6463
6464        // Create two daemons on custom port 5454
6465        let custom_port = 5454u16;
6466        let server_custom =
6467            ServiceDaemon::new_with_port(custom_port).expect("Failed to create custom port server");
6468        let client_custom =
6469            ServiceDaemon::new_with_port(custom_port).expect("Failed to create custom port client");
6470
6471        // Create daemon on default port (5353)
6472        let server_default = ServiceDaemon::new().expect("Failed to create default port server");
6473
6474        // Register service on custom port
6475        server_custom
6476            .register(service_custom.clone())
6477            .expect("Failed to register custom port service");
6478
6479        // Register service on default port
6480        server_default
6481            .register(service_default.clone())
6482            .expect("Failed to register default port service");
6483
6484        // Browse from custom port client
6485        let browse_custom = client_custom
6486            .browse(service_type)
6487            .expect("Failed to browse on custom port");
6488
6489        let timeout = Duration::from_secs(3);
6490        let mut found_custom = false;
6491        let mut found_default_on_custom = false;
6492
6493        // Custom port client should find the custom port service
6494        while let Ok(event) = browse_custom.recv_timeout(timeout) {
6495            if let ServiceEvent::ServiceResolved(info) = event {
6496                println!(
6497                    "Custom port client resolved: {} on port {}",
6498                    info.get_fullname(),
6499                    info.get_port()
6500                );
6501                if info.get_fullname().starts_with(instance_custom) {
6502                    found_custom = true;
6503                    assert_eq!(info.get_port(), 8080);
6504                }
6505                if info.get_fullname().starts_with(instance_default) {
6506                    found_default_on_custom = true;
6507                }
6508            }
6509        }
6510
6511        assert!(
6512            found_custom,
6513            "Custom port client should find service on custom port"
6514        );
6515        assert!(
6516            !found_default_on_custom,
6517            "Custom port client should NOT find service on default port"
6518        );
6519
6520        // Now verify the default port daemon can find its own services
6521        // but not the custom port services
6522        let client_default = ServiceDaemon::new().expect("Failed to create default port client");
6523        let browse_default = client_default
6524            .browse(service_type)
6525            .expect("Failed to browse on default port");
6526
6527        let mut found_default = false;
6528        let mut found_custom_on_default = false;
6529
6530        while let Ok(event) = browse_default.recv_timeout(timeout) {
6531            if let ServiceEvent::ServiceResolved(info) = event {
6532                println!(
6533                    "Default port client resolved: {} on port {}",
6534                    info.get_fullname(),
6535                    info.get_port()
6536                );
6537                if info.get_fullname().starts_with(instance_default) {
6538                    found_default = true;
6539                    assert_eq!(info.get_port(), 8081);
6540                }
6541                if info.get_fullname().starts_with(instance_custom) {
6542                    found_custom_on_default = true;
6543                }
6544            }
6545        }
6546
6547        assert!(
6548            found_default,
6549            "Default port client should find service on default port"
6550        );
6551        assert!(
6552            !found_custom_on_default,
6553            "Default port client should NOT find service on custom port"
6554        );
6555
6556        // Cleanup
6557        server_custom.shutdown().unwrap();
6558        client_custom.shutdown().unwrap();
6559        server_default.shutdown().unwrap();
6560        client_default.shutdown().unwrap();
6561    }
6562}