From dfb592e256b5121ec897e1516ccaf3b87c5d0de5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 21 Oct 2026 18:04:22 -0400 Subject: [PATCH 1/2] Report every browsed instance on macOS The dns_sd backend reported an instance from its address callback only when kDNSServiceFlagsMoreComing was clear. All operations share one connection, and on a shared connection that flag covers the replies of every operation. So when an instance's last address came with the flag set, and another operation's reply ended the batch, the instance was never reported and the server never dialed it. On a network with five `_sendspin._tcp` speakers, the server reported three on every start. The address callback now marks the instance as updated. The run loop reports the updated instances after it handles a reply and no other reply is left to read on the connection. The host tests never use the system's mDNS, so they cannot reach this backend. Checked against the five speakers: all five are reported on each of three starts. Co-Authored-By: Claude Opus 5.5 --- src/discovery/dns_sd_discovery.cpp | 36 +++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/discovery/dns_sd_discovery.cpp b/src/discovery/dns_sd_discovery.cpp index cedd643..0ebf1b5 100644 --- a/src/discovery/dns_sd_discovery.cpp +++ b/src/discovery/dns_sd_discovery.cpp @@ -200,6 +200,7 @@ class DnsSdDiscovery final : public DiscoveryProvider { } } this->instances_.clear(); + this->updated_.clear(); } void run() { @@ -241,12 +242,15 @@ class DnsSdDiscovery final : public DiscoveryProvider { } // The socket is invalid or mDNSResponder went away (kDNSServiceErr_ServiceNotRunning): // connect again - if (count == 2 && fds[1].revents != 0 && - ((fds[1].revents & POLLNVAL) != 0 || - DNSServiceProcessResult(this->connection_) != kDNSServiceErr_NoError)) { - this->disconnect(); - reported_unavailable = true; - this->sink_->on_unavailable(); + if (count == 2 && fds[1].revents != 0) { + if ((fds[1].revents & POLLNVAL) != 0 || + DNSServiceProcessResult(this->connection_) != kDNSServiceErr_NoError) { + this->disconnect(); + reported_unavailable = true; + this->sink_->on_unavailable(); + } else { + this->report_updated(); + } } } } @@ -269,6 +273,7 @@ class DnsSdDiscovery final : public DiscoveryProvider { this->connection_ = nullptr; } this->instances_.clear(); + this->updated_.clear(); for (int& fd : this->wake_) { if (fd >= 0) { close(fd); @@ -336,6 +341,7 @@ class DnsSdDiscovery final : public DiscoveryProvider { } const bool reported = instance.reported; const std::string lost = instance.name; + this->updated_.erase(&instance); stop_operation(instance.resolve); stop_operation(instance.lookup); this->instances_.erase(it); @@ -398,9 +404,21 @@ class DnsSdDiscovery final : public DiscoveryProvider { addresses.erase(it); } } - if ((flags & kDNSServiceFlagsMoreComing) == 0) { - instance->owner->report(*instance); + instance->owner->updated_.insert(instance); + } + + /// Reports the instances whose addresses changed once no reply is left to read. On the + /// shared connection kDNSServiceFlagsMoreComing covers every operation's replies, so an + /// instance's last address can come with it set and another operation's reply end the batch. + void report_updated() { + pollfd fd{DNSServiceRefSockFD(this->connection_), POLLIN, 0}; + if (poll(&fd, 1, 0) != 0) { + return; + } + for (Instance* instance : this->updated_) { + this->report(*instance); } + this->updated_.clear(); } /// Reports instance once it has a path and an address: IPv4 first, then IPv6, link-local @@ -436,6 +454,8 @@ class DnsSdDiscovery final : public DiscoveryProvider { /// Set by stop() before it writes to the wake pipe std::atomic stopping_{false}; std::map> instances_; + /// Instances whose addresses changed since report_updated() last reported + std::set updated_; std::thread thread_; }; From f2b533a69ec8153b29ba76c5ee78e5d7e2b22d0d Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 28 Oct 2026 07:53:58 -0400 Subject: [PATCH 2/2] Report updated instances when the check for pending replies fails --- src/discovery/dns_sd_discovery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/discovery/dns_sd_discovery.cpp b/src/discovery/dns_sd_discovery.cpp index 0ebf1b5..8488269 100644 --- a/src/discovery/dns_sd_discovery.cpp +++ b/src/discovery/dns_sd_discovery.cpp @@ -412,7 +412,7 @@ class DnsSdDiscovery final : public DiscoveryProvider { /// instance's last address can come with it set and another operation's reply end the batch. void report_updated() { pollfd fd{DNSServiceRefSockFD(this->connection_), POLLIN, 0}; - if (poll(&fd, 1, 0) != 0) { + if (poll(&fd, 1, 0) > 0) { return; } for (Instance* instance : this->updated_) {