resolve: detach DnsServiceBrowser object from Manager when freed or disconnected

When a DnsServiceBrowser object is detached from the manager,
all queries, event sources, and then the reference to Manager should be
dropped. Otherwise, spurious query may be triggered for already
disconnected varlink.

(cherry picked from commit 219abd95ae)
This commit is contained in:
Yu Watanabe
2026-10-16 11:36:32 +01:00
committed by Luca Boccassi
parent 14b91970e6
commit 3e0080355b
4 changed files with 45 additions and 33 deletions
+35 -11
View File
@@ -160,6 +160,7 @@ int dns_add_new_service(DnsServiceBrowser *sb, DnsResourceRecord *rr, int owner_
int r;
assert(sb);
assert(sb->manager);
assert(rr);
s = new(DnssdDiscoveredService, 1);
@@ -725,6 +726,7 @@ static int mdns_next_query_schedule(sd_event_source *s, uint64_t usec, void *use
assert(userdata);
assert_se(sb = dns_service_browser_ref(userdata));
assert(sb->manager);
/* If the varlink connection has a userdata, then that means the previous query has not been finished. */
if (!sd_varlink_get_userdata(sb->link)) {
@@ -804,6 +806,14 @@ void dns_browse_services_restart(Manager *m) {
}
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
dns_service_browser_hash_ops,
void,
trivial_hash_func,
trivial_compare_func,
DnsServiceBrowser,
dns_service_browser_detach);
int dns_subscribe_browse_service(
Manager *m, sd_varlink *link, const char *domain, const char *type, int ifindex, uint64_t flags) {
@@ -855,8 +865,6 @@ int dns_subscribe_browse_service(
*sb = (DnsServiceBrowser) {
.n_ref = 1,
.manager = m,
.link = sd_varlink_ref(link),
.question_utf8 = dns_question_ref(question_utf8),
.question_idna = dns_question_ref(question_idna),
.key = dns_question_first_key(question_utf8),
@@ -880,35 +888,51 @@ int dns_subscribe_browse_service(
if (r < 0)
return r;
r = hashmap_ensure_put(&m->dns_service_browsers, NULL, link, sb);
r = hashmap_ensure_put(&m->dns_service_browsers, &dns_service_browser_hash_ops, link, sb);
if (r < 0)
return log_error_errno(r, "Failed to add service browser to the hashmap: %m");
sb->manager = m;
sb->link = sd_varlink_ref(link);
TAKE_PTR(sb);
return 0;
}
DnsServiceBrowser *dns_service_browser_free(DnsServiceBrowser *sb) {
DnsQuery *q;
if (!sb)
return NULL;
static DnsServiceBrowser* dns_service_browser_detach_impl(DnsServiceBrowser *sb) {
assert(sb);
assert(!sb->manager == !sb->link);
while (sb->dns_services)
dns_remove_service(sb, sb->dns_services);
sb->schedule_event = sd_event_source_disable_unref(sb->schedule_event);
q = sd_varlink_get_userdata(sb->link);
if (!sb->manager)
return NULL; /* already detached */
DnsQuery *q = sd_varlink_get_userdata(sb->link);
if (q && DNS_TRANSACTION_IS_LIVE(q->state))
dns_query_complete(q, DNS_TRANSACTION_ABORTED);
hashmap_remove(sb->manager->dns_service_browsers, sb->link);
sb->link = sd_varlink_unref(sb->link);
sb->manager = NULL;
return sb; /* indicate that the object is detached */
}
void dns_service_browser_detach(DnsServiceBrowser *sb) {
dns_service_browser_unref(dns_service_browser_detach_impl(sb));
}
static DnsServiceBrowser* dns_service_browser_free(DnsServiceBrowser *sb) {
if (!sb)
return NULL;
dns_service_browser_detach_impl(sb);
sb->question_idna = dns_question_unref(sb->question_idna);
sb->question_utf8 = dns_question_unref(sb->question_utf8);
sb->link = sd_varlink_unref(sb->link);
return mfree(sb);
}
+1 -1
View File
@@ -52,10 +52,10 @@ struct DnsServiceBrowser {
LIST_HEAD(DnssdDiscoveredService, dns_services);
};
DnsServiceBrowser *dns_service_browser_free(DnsServiceBrowser *sb);
void dns_remove_service(DnsServiceBrowser *sb, DnssdDiscoveredService *service);
DnssdDiscoveredService *dns_service_free(DnssdDiscoveredService *service);
void dns_service_browser_detach(DnsServiceBrowser *sb);
DECLARE_TRIVIAL_REF_UNREF_FUNC(DnsServiceBrowser, dns_service_browser);
DECLARE_TRIVIAL_REF_UNREF_FUNC(DnssdDiscoveredService, dnssd_discovered_service);
-3
View File
@@ -841,7 +841,6 @@ int manager_start(Manager *m) {
Manager* manager_free(Manager *m) {
Link *l;
DnssdRegisteredService *s;
DnsServiceBrowser *sb;
if (!m)
return NULL;
@@ -923,8 +922,6 @@ Manager* manager_free(Manager *m) {
manager_etc_hosts_flush(m);
manager_static_records_flush(m);
while ((sb = hashmap_first(m->dns_service_browsers)))
dns_service_browser_free(sb);
hashmap_free(m->dns_service_browsers);
hashmap_free(m->hooks);
+9 -18
View File
@@ -157,28 +157,19 @@ static int reply_query_state(DnsQuery *q) {
}
static void vl_on_disconnect(sd_varlink_server *s, sd_varlink *link, void *userdata) {
DnsQuery *q;
Manager *m;
assert(s);
assert(link);
m = sd_varlink_server_get_userdata(s);
if (!m)
return;
DnsQuery *q = sd_varlink_get_userdata(link);
if (q && DNS_TRANSACTION_IS_LIVE(q->state)) {
log_debug("Client of active query vanished, aborting query.");
dns_query_complete(q, DNS_TRANSACTION_ABORTED);
}
DnsServiceBrowser *sb = hashmap_remove(m->dns_service_browsers, link);
dns_service_browser_unref(sb);
q = sd_varlink_get_userdata(link);
if (!q)
return;
if (!DNS_TRANSACTION_IS_LIVE(q->state))
return;
log_debug("Client of active query vanished, aborting query.");
dns_query_complete(q, DNS_TRANSACTION_ABORTED);
Manager *m = ASSERT_PTR(sd_varlink_server_get_userdata(s));
DnsServiceBrowser *sb = hashmap_get(m->dns_service_browsers, link);
if (sb)
dns_service_browser_detach(sb);
}
static void vl_on_notification_disconnect(sd_varlink_server *s, sd_varlink *link, void *userdata) {