diff --git a/src/resolve/resolved-dns-browse-services.c b/src/resolve/resolved-dns-browse-services.c index ca9b54075f..df360fd4d6 100644 --- a/src/resolve/resolved-dns-browse-services.c +++ b/src/resolve/resolved-dns-browse-services.c @@ -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); } diff --git a/src/resolve/resolved-dns-browse-services.h b/src/resolve/resolved-dns-browse-services.h index 84095d5559..8a3afa200e 100644 --- a/src/resolve/resolved-dns-browse-services.h +++ b/src/resolve/resolved-dns-browse-services.h @@ -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); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 10b3b5977f..8997ba0c35 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -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); diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index d29bd92ac5..5d5cdc172b 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -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) {