mirror of
https://github.com/systemd/systemd.git
synced 2024-10-28 11:55:44 +03:00
resolved: support multiple TXT RRs per DNS-SD service
Section 6.8 of RFC 6763 allows having service instances with multiple TXT resource records.
This commit is contained in:
parent
84b0f133e4
commit
400f54fb36
@ -174,6 +174,10 @@
|
||||
e.g. <literal>path=/portal/index.html</literal>. Keys and values can contain C-style escape
|
||||
sequences which get translated upon reading configuration files.
|
||||
</para>
|
||||
<para>This option together with <varname>TxtData=</varname> may be specified more than once, in which
|
||||
case multiple TXT resource records will be created for the service. If the empty string is assigned to
|
||||
this option, the list is reset and all prior assignments will have no effect.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -185,6 +189,10 @@
|
||||
e.g. <literal>data=YW55IGJpbmFyeSBkYXRhCg==</literal>. Keys can contain C-style escape
|
||||
sequences which get translated upon reading configuration files.
|
||||
</para>
|
||||
<para>This option together with <varname>TxtText=</varname> may be specified more than once, in which
|
||||
case multiple TXT resource records will be created for the service. If the empty string is assigned to
|
||||
this option, the list is reset and all prior assignments will have no effect.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
@ -1605,7 +1605,6 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
|
||||
_cleanup_free_ char *instance_name = NULL;
|
||||
Manager *m = userdata;
|
||||
DnssdService *s = NULL;
|
||||
DnsTxtItem *last = NULL;
|
||||
const char *name;
|
||||
const char *name_template;
|
||||
const char *type;
|
||||
@ -1669,46 +1668,82 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "{say}");
|
||||
r = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "a{say}");
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errno(error, r);
|
||||
return r;
|
||||
|
||||
while ((r = sd_bus_message_enter_container(message, SD_BUS_TYPE_DICT_ENTRY, "say")) > 0) {
|
||||
const char *key;
|
||||
const void *value;
|
||||
size_t size;
|
||||
DnsTxtItem *i;
|
||||
while ((r = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "{say}")) > 0) {
|
||||
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
|
||||
DnsTxtItem *last = NULL;
|
||||
|
||||
r = sd_bus_message_read(message, "s", &key);
|
||||
txt_data = new0(DnssdTxtData, 1);
|
||||
if (!txt_data)
|
||||
return log_oom();
|
||||
|
||||
while ((r = sd_bus_message_enter_container(message, SD_BUS_TYPE_DICT_ENTRY, "say")) > 0) {
|
||||
const char *key;
|
||||
const void *value;
|
||||
size_t size;
|
||||
DnsTxtItem *i;
|
||||
|
||||
r = sd_bus_message_read(message, "s", &key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (isempty(key))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Keys in DNS-SD TXT RRs can't be empty");
|
||||
|
||||
if (!ascii_is_valid(key))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TXT key '%s' contains non-ASCII symbols", key);
|
||||
|
||||
r = sd_bus_message_read_array(message, 'y', &value, &size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dnssd_txt_item_new_from_data(key, value, size, &i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_INSERT_AFTER(items, txt_data->txt, last, i);
|
||||
last = i;
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
}
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errno(error, r);
|
||||
return r;
|
||||
|
||||
if (strlen_ptr(key) == 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Keys in DNS-SD TXT RRs can't be empty");
|
||||
|
||||
if (!ascii_is_valid(key))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TXT key '%s' contains non-ASCII symbols", key);
|
||||
|
||||
r = sd_bus_message_read_array(message, 'y', &value, &size);
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errno(error, r);
|
||||
return r;
|
||||
|
||||
r = dnssd_txt_item_new_from_data(key, value, size, &i);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errno(error, r);
|
||||
|
||||
LIST_INSERT_AFTER(items, service->txt, last, i);
|
||||
last = i;
|
||||
if (txt_data->txt) {
|
||||
LIST_PREPEND(items, service->txt_data_items, txt_data);
|
||||
txt_data = NULL;
|
||||
}
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errno(error, r);
|
||||
return r;
|
||||
|
||||
if (!service->txt) {
|
||||
r = dns_txt_item_new_empty(&service->txt);
|
||||
if (!service->txt_data_items) {
|
||||
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
|
||||
|
||||
txt_data = new0(DnssdTxtData, 1);
|
||||
if (!txt_data)
|
||||
return log_oom();
|
||||
|
||||
r = dns_txt_item_new_empty(&txt_data->txt);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errno(error, r);
|
||||
return r;
|
||||
|
||||
LIST_PREPEND(items, service->txt_data_items, txt_data);
|
||||
txt_data = NULL;
|
||||
}
|
||||
|
||||
r = sd_bus_path_encode("/org/freedesktop/resolve1/dnssd", service->name, &path);
|
||||
@ -1804,7 +1839,7 @@ static const sd_bus_vtable resolve_vtable[] = {
|
||||
SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, 0),
|
||||
SD_BUS_METHOD("RevertLink", "i", NULL, bus_method_revert_link, 0),
|
||||
|
||||
SD_BUS_METHOD("RegisterService", "sssqqqa{say}", "o", bus_method_register_service, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("RegisterService", "sssqqqaa{say}", "o", bus_method_register_service, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("UnregisterService", "o", NULL, bus_method_unregister_service, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
@ -297,6 +297,7 @@ int config_parse_dnssd_service_type(const char *unit, const char *filename, unsi
|
||||
}
|
||||
|
||||
int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
|
||||
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
|
||||
DnssdService *s = userdata;
|
||||
DnsTxtItem *last = NULL;
|
||||
|
||||
@ -305,13 +306,15 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
|
||||
assert(rvalue);
|
||||
assert(s);
|
||||
|
||||
/* TODO: Since RFC6763 allows more than one TXT RR per service
|
||||
* this s->txt field should be implemented as a list
|
||||
* of DnsTxtItem lists. */
|
||||
s->txt = dns_txt_item_free_all(s->txt);
|
||||
|
||||
if (isempty(rvalue))
|
||||
if (isempty(rvalue)) {
|
||||
/* Flush out collected items */
|
||||
s->txt_data_items = dnssd_txtdata_free_all(s->txt_data_items);
|
||||
return 0;
|
||||
}
|
||||
|
||||
txt_data = new0(DnssdTxtData, 1);
|
||||
if (!txt_data)
|
||||
return log_oom();
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
@ -371,10 +374,15 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
|
||||
assert_not_reached("Unknown type of Txt config");
|
||||
}
|
||||
|
||||
LIST_INSERT_AFTER(items, s->txt, last, i);
|
||||
LIST_INSERT_AFTER(items, txt_data->txt, last, i);
|
||||
last = i;
|
||||
}
|
||||
|
||||
if (!LIST_IS_EMPTY(txt_data->txt)) {
|
||||
LIST_PREPEND(items, s->txt_data_items, txt_data);
|
||||
txt_data = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1068,7 +1068,7 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
|
||||
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
|
||||
_cleanup_set_free_ Set *types = NULL;
|
||||
DnsTransaction *t;
|
||||
DnsZoneItem *z;
|
||||
DnsZoneItem *z, *i;
|
||||
unsigned size = 0;
|
||||
Iterator iterator;
|
||||
char *service_type;
|
||||
@ -1117,7 +1117,8 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
|
||||
}
|
||||
}
|
||||
|
||||
size++;
|
||||
LIST_FOREACH(by_key, i, z)
|
||||
size++;
|
||||
}
|
||||
|
||||
answer = dns_answer_new(size + set_size(types));
|
||||
@ -1125,21 +1126,22 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
|
||||
return log_oom();
|
||||
|
||||
/* Second iteration, actually add RRs to the answer. */
|
||||
HASHMAP_FOREACH(z, scope->zone.by_key, iterator) {
|
||||
DnsAnswerFlags flags;
|
||||
HASHMAP_FOREACH(z, scope->zone.by_key, iterator)
|
||||
LIST_FOREACH (by_key, i, z) {
|
||||
DnsAnswerFlags flags;
|
||||
|
||||
if (z->state != DNS_ZONE_ITEM_ESTABLISHED)
|
||||
continue;
|
||||
if (i->state != DNS_ZONE_ITEM_ESTABLISHED)
|
||||
continue;
|
||||
|
||||
if (dns_resource_key_is_dnssd_ptr(z->rr->key))
|
||||
flags = goodbye ? DNS_ANSWER_GOODBYE : 0;
|
||||
else
|
||||
flags = goodbye ? (DNS_ANSWER_GOODBYE|DNS_ANSWER_CACHE_FLUSH) : DNS_ANSWER_CACHE_FLUSH;
|
||||
if (dns_resource_key_is_dnssd_ptr(i->rr->key))
|
||||
flags = goodbye ? DNS_ANSWER_GOODBYE : 0;
|
||||
else
|
||||
flags = goodbye ? (DNS_ANSWER_GOODBYE|DNS_ANSWER_CACHE_FLUSH) : DNS_ANSWER_CACHE_FLUSH;
|
||||
|
||||
r = dns_answer_add(answer, z->rr, 0 , flags);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to add RR to announce: %m");
|
||||
}
|
||||
r = dns_answer_add(answer, i->rr, 0 , flags);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to add RR to announce: %m");
|
||||
}
|
||||
|
||||
/* Since all the active services are in the zone make them discoverable now. */
|
||||
SET_FOREACH(service_type, types, iterator) {
|
||||
@ -1199,6 +1201,7 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
|
||||
int dns_scope_add_dnssd_services(DnsScope *scope) {
|
||||
Iterator i;
|
||||
DnssdService *service;
|
||||
DnssdTxtData *txt_data;
|
||||
int r;
|
||||
|
||||
assert(scope);
|
||||
@ -1219,9 +1222,11 @@ int dns_scope_add_dnssd_services(DnsScope *scope) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to add SRV record to MDNS zone: %m");
|
||||
|
||||
r = dns_zone_put(&scope->zone, scope, service->txt_rr, true);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to add TXT record to MDNS zone: %m");
|
||||
LIST_FOREACH(items, txt_data, service->txt_data_items) {
|
||||
r = dns_zone_put(&scope->zone, scope, txt_data->rr, true);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to add TXT record to MDNS zone: %m");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1231,6 +1236,7 @@ int dns_scope_remove_dnssd_services(DnsScope *scope) {
|
||||
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
|
||||
Iterator i;
|
||||
DnssdService *service;
|
||||
DnssdTxtData *txt_data;
|
||||
int r;
|
||||
|
||||
assert(scope);
|
||||
@ -1247,7 +1253,8 @@ int dns_scope_remove_dnssd_services(DnsScope *scope) {
|
||||
HASHMAP_FOREACH(service, scope->manager->dnssd_services, i) {
|
||||
dns_zone_remove_rr(&scope->zone, service->ptr_rr);
|
||||
dns_zone_remove_rr(&scope->zone, service->srv_rr);
|
||||
dns_zone_remove_rr(&scope->zone, service->txt_rr);
|
||||
LIST_FOREACH(items, txt_data, service->txt_data_items)
|
||||
dns_zone_remove_rr(&scope->zone, txt_data->rr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
DnssdService *s = userdata;
|
||||
DnssdTxtData *txt_data;
|
||||
Manager *m;
|
||||
Iterator i;
|
||||
Link *l;
|
||||
@ -54,7 +55,8 @@ int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_
|
||||
|
||||
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, s->ptr_rr);
|
||||
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, s->srv_rr);
|
||||
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, s->txt_rr);
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items)
|
||||
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, txt_data->rr);
|
||||
}
|
||||
|
||||
if (l->mdns_ipv6_scope) {
|
||||
@ -64,7 +66,8 @@ int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_
|
||||
|
||||
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, s->ptr_rr);
|
||||
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, s->srv_rr);
|
||||
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, s->txt_rr);
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items)
|
||||
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, txt_data->rr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,29 @@ const char* const dnssd_service_dirs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
DnssdTxtData *dnssd_txtdata_free(DnssdTxtData *txt_data) {
|
||||
if (!txt_data)
|
||||
return NULL;
|
||||
|
||||
dns_resource_record_unref(txt_data->rr);
|
||||
dns_txt_item_free_all(txt_data->txt);
|
||||
|
||||
return mfree(txt_data);
|
||||
}
|
||||
|
||||
DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data) {
|
||||
DnssdTxtData *next;
|
||||
|
||||
if (!txt_data)
|
||||
return NULL;
|
||||
|
||||
next = txt_data->items_next;
|
||||
|
||||
dnssd_txtdata_free(txt_data);
|
||||
|
||||
return dnssd_txtdata_free_all(next);
|
||||
}
|
||||
|
||||
DnssdService *dnssd_service_free(DnssdService *service) {
|
||||
if (!service)
|
||||
return NULL;
|
||||
@ -44,19 +67,20 @@ DnssdService *dnssd_service_free(DnssdService *service) {
|
||||
|
||||
dns_resource_record_unref(service->ptr_rr);
|
||||
dns_resource_record_unref(service->srv_rr);
|
||||
dns_resource_record_unref(service->txt_rr);
|
||||
|
||||
dnssd_txtdata_free_all(service->txt_data_items);
|
||||
|
||||
free(service->filename);
|
||||
free(service->name);
|
||||
free(service->type);
|
||||
free(service->name_template);
|
||||
dns_txt_item_free_all(service->txt);
|
||||
|
||||
return mfree(service);
|
||||
}
|
||||
|
||||
static int dnssd_service_load(Manager *manager, const char *filename) {
|
||||
_cleanup_(dnssd_service_freep) DnssdService *service = NULL;
|
||||
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
|
||||
char *d;
|
||||
const char *dropin_dirname;
|
||||
int r;
|
||||
@ -103,10 +127,17 @@ static int dnssd_service_load(Manager *manager, const char *filename) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!service->txt) {
|
||||
r = dns_txt_item_new_empty(&service->txt);
|
||||
if (LIST_IS_EMPTY(service->txt_data_items)) {
|
||||
txt_data = new0(DnssdTxtData, 1);
|
||||
if (!txt_data)
|
||||
return log_oom();
|
||||
|
||||
r = dns_txt_item_new_empty(&txt_data->txt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_PREPEND(items, service->txt_data_items, txt_data);
|
||||
txt_data = NULL;
|
||||
}
|
||||
|
||||
r = hashmap_ensure_allocated(&manager->dnssd_services, &string_hash_ops);
|
||||
@ -200,15 +231,17 @@ int dnssd_update_rrs(DnssdService *s) {
|
||||
_cleanup_free_ char *n = NULL;
|
||||
_cleanup_free_ char *service_name = NULL;
|
||||
_cleanup_free_ char *full_name = NULL;
|
||||
DnssdTxtData *txt_data;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(s->txt);
|
||||
assert(s->txt_data_items);
|
||||
assert(s->manager);
|
||||
|
||||
s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
|
||||
s->srv_rr = dns_resource_record_unref(s->srv_rr);
|
||||
s->txt_rr = dns_resource_record_unref(s->txt_rr);
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items)
|
||||
txt_data->rr = dns_resource_record_unref(txt_data->rr);
|
||||
|
||||
r = dnssd_render_instance_name(s, &n);
|
||||
if (r < 0)
|
||||
@ -221,15 +254,17 @@ int dnssd_update_rrs(DnssdService *s) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
s->txt_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_TXT,
|
||||
full_name);
|
||||
if (!s->txt_rr)
|
||||
goto oom;
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items) {
|
||||
txt_data->rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_TXT,
|
||||
full_name);
|
||||
if (!txt_data->rr)
|
||||
goto oom;
|
||||
|
||||
s->txt_rr->ttl = MDNS_DEFAULT_TTL;
|
||||
s->txt_rr->txt.items = dns_txt_item_copy(s->txt);
|
||||
if (!s->txt_rr->txt.items)
|
||||
goto oom;
|
||||
txt_data->rr->ttl = MDNS_DEFAULT_TTL;
|
||||
txt_data->rr->txt.items = dns_txt_item_copy(txt_data->txt);
|
||||
if (!txt_data->rr->txt.items)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
s->ptr_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR,
|
||||
service_name);
|
||||
@ -257,7 +292,8 @@ int dnssd_update_rrs(DnssdService *s) {
|
||||
return 0;
|
||||
|
||||
oom:
|
||||
s->txt_rr = dns_resource_record_unref(s->txt_rr);
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items)
|
||||
txt_data->rr = dns_resource_record_unref(txt_data->rr);
|
||||
s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
|
||||
s->srv_rr = dns_resource_record_unref(s->srv_rr);
|
||||
return -ENOMEM;
|
||||
|
@ -19,7 +19,10 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "list.h"
|
||||
|
||||
typedef struct DnssdService DnssdService;
|
||||
typedef struct DnssdTxtData DnssdTxtData;
|
||||
|
||||
typedef struct Manager Manager;
|
||||
typedef struct DnsResourceRecord DnsResourceRecord;
|
||||
@ -30,6 +33,14 @@ enum {
|
||||
DNS_TXT_ITEM_DATA
|
||||
};
|
||||
|
||||
struct DnssdTxtData {
|
||||
DnsResourceRecord *rr;
|
||||
|
||||
LIST_HEAD(DnsTxtItem, txt);
|
||||
|
||||
LIST_FIELDS(DnssdTxtData, items);
|
||||
};
|
||||
|
||||
struct DnssdService {
|
||||
char *filename;
|
||||
char *name;
|
||||
@ -38,11 +49,13 @@ struct DnssdService {
|
||||
uint16_t port;
|
||||
uint16_t priority;
|
||||
uint16_t weight;
|
||||
DnsTxtItem *txt;
|
||||
|
||||
DnsResourceRecord *ptr_rr;
|
||||
DnsResourceRecord *srv_rr;
|
||||
DnsResourceRecord *txt_rr;
|
||||
|
||||
/* Section 6.8 of RFC 6763 allows having service
|
||||
* instances with multiple TXT resource records. */
|
||||
LIST_HEAD(DnssdTxtData, txt_data_items);
|
||||
|
||||
Manager *manager;
|
||||
|
||||
@ -51,8 +64,11 @@ struct DnssdService {
|
||||
};
|
||||
|
||||
DnssdService *dnssd_service_free(DnssdService *service);
|
||||
DnssdTxtData *dnssd_txtdata_free(DnssdTxtData *txt_data);
|
||||
DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdService*, dnssd_service_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdTxtData*, dnssd_txtdata_free);
|
||||
|
||||
int dnssd_render_instance_name(DnssdService *s, char **ret_name);
|
||||
int dnssd_load(Manager *manager);
|
||||
|
Loading…
Reference in New Issue
Block a user