Commit 42e6c1fb authored by Konrad Derda's avatar Konrad Derda Committed by Fabio Baltieri
Browse files

net: mdns: add capability of providing records in runtime

Current implementation of mDNS responder does makes it mandatory to have
all the records set at compile time. It is not suited well for applications
that have to publish/unpublish or change records in runtime, e.g. data
received from the network.

Signed-off-by: default avatarKonrad Derda <konrad.derda@nordicsemi.no>
parent 7b2c947a
Loading
Loading
Loading
Loading
+6 −8
Changes for include/zephyr/net/dns_sd.h: 6 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -198,8 +198,6 @@ extern "C" {
/** Empty DNS-SD TXT specifier */
#define DNS_SD_EMPTY_TXT dns_sd_empty_txt

/** @cond INTERNAL_HIDDEN */

/**
 * @brief DNS Service Discovery record
 *
@@ -214,18 +212,16 @@ extern "C" {
 * Thus, it is possible for multiple services to advertise on a
 * particular port if they hard-code the port.
 *
 * @internal
 *
 * @see <a href="https://tools.ietf.org/html/rfc6763">RFC 6763</a>
 */
struct dns_sd_rec {
	/** <Instance> - e.g. "My HTTP Server" */
	/** "<Instance>" - e.g. "My HTTP Server" */
	const char *instance;
	/** Top half of the <Service> such as "_http" */
	/** Top half of the "<Service>" such as "_http" */
	const char *service;
	/** Bottom half of the <Service> "_tcp" or "_udp" */
	/** Bottom half of the "<Service>" "_tcp" or "_udp" */
	const char *proto;
	/** <Domain> such as "local" or "zephyrproject.org" */
	/** "<Domain>" such as "local" or "zephyrproject.org" */
	const char *domain;
	/** DNS TXT record */
	const char *text;
@@ -235,6 +231,8 @@ struct dns_sd_rec {
	const uint16_t *port;
};

/** @cond INTERNAL_HIDDEN */

/**
 * @brief Empty TXT specifier for DNS-SD
 *
+34 −0
Changes for include/zephyr/net/mdns_responder.h: 34 added lines, 0 removed lines.
Original line number Diff line number Diff line
/*
 * Copyright (c) 2023 Nordic Semiconductor ASA.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/** @file
 * @brief mDNS responder API
 *
 * This file contains the mDNS responder API. These APIs are used by the
 * to register mDNS records.
 */

#ifndef ZEPHYR_INCLUDE_NET_MDNS_RESPONDER_H_
#define ZEPHYR_INCLUDE_NET_MDNS_RESPONDER_H_

#include <stddef.h>
#include <zephyr/net/dns_sd.h>

/**
 * @brief Register continuous memory of @ref dns_sd_rec records.
 *
 * mDNS responder will start with iteration over mDNS records registered using
 * @ref DNS_SD_REGISTER_SERVICE (if any) and then go over external records.
 *
 * @param records A pointer to an array of mDNS records. It is stored internally
 *                without copying the content so it must be kept valid. It can
 *                be set to NULL, e.g. before freeing the memory block.
 * @param count The number of elements
 * @return 0 for OK; -EINVAL for invalid parameters.
 */
int mdns_responder_set_ext_records(const struct dns_sd_rec *records, size_t count);

#endif /* ZEPHYR_INCLUDE_NET_MDNS_RESPONDER_H_ */
+1 −0
Changes for subsys/net/lib/dns/dns_sd.c: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -857,6 +857,7 @@ int dns_sd_handle_service_type_enum(const struct dns_sd_rec *inst,

	if (!port_in_use(proto, ntohs(*(inst->port)), addr4, addr6)) {
		/* Service is not yet bound, so do not advertise */
		NET_DBG("service not bound");
		return -EHOSTDOWN;
	}

+6 −0
Changes for subsys/net/lib/dns/dns_sd.h: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -33,6 +33,12 @@ extern "C" {
#define DNS_SD_FOREACH(it) \
	STRUCT_SECTION_FOREACH(dns_sd_rec, it)

#define DNS_SD_COUNT(dst) \
	STRUCT_SECTION_COUNT(dns_sd_rec, dst)

#define DNS_SD_GET(i, dst) \
	STRUCT_SECTION_GET(dns_sd_rec, i, dst)

/**
 * @brief Extract labels from a DNS-SD PTR query
 *
+34 −1
Changes for subsys/net/lib/dns/mdns_responder.c: 34 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ static struct net_context *ipv6[MAX_IPV6_IFACE_COUNT];
#endif

static struct net_mgmt_event_callback mgmt_cb;
static const struct dns_sd_rec *external_records;
static size_t external_records_count;

#define BUF_ALLOC_TIMEOUT K_MSEC(100)

@@ -340,6 +342,7 @@ static void send_sd_response(struct net_context *ctx,
			     struct net_buf *result)
{
	int ret;
	const struct dns_sd_rec *record;
	/* filter must be zero-initialized for "wildcard" port */
	struct dns_sd_rec filter = {0};
	struct sockaddr dst;
@@ -359,6 +362,8 @@ static void send_sd_response(struct net_context *ctx,
		ARRAY_SIZE(domain_buf),
	};
	size_t n = ARRAY_SIZE(label);
	size_t rec_num;
	size_t ext_rec_num = external_records_count;

	BUILD_ASSERT(ARRAY_SIZE(label) == ARRAY_SIZE(size), "");

@@ -423,7 +428,21 @@ static void send_sd_response(struct net_context *ctx,
		service_type_enum = true;
	}

	DNS_SD_FOREACH(record) {
	DNS_SD_COUNT(&rec_num);

	while (rec_num > 0 || ext_rec_num > 0) {
		/*
		 * The loop will always iterate over all entries, it can be done
		 * backwards for simplicity
		 */
		if (rec_num > 0) {
			DNS_SD_GET(rec_num - 1, &record);
			rec_num--;
		} else {
			record = &external_records[ext_rec_num - 1];
			ext_rec_num--;
		}

		/* Checks validity and then compare */
		if (dns_sd_rec_match(record, &filter)) {
			NET_DBG("matched query: %s.%s.%s.%s port: %u",
@@ -760,6 +779,8 @@ ipv4_out:

static int mdns_responder_init(void)
{
	external_records = NULL;
	external_records_count = 0;

	net_mgmt_init_event_callback(&mgmt_cb, mdns_iface_event_handler,
				     NET_EVENT_IF_UP);
@@ -769,4 +790,16 @@ static int mdns_responder_init(void)
	return init_listener();
}

int mdns_responder_set_ext_records(const struct dns_sd_rec *records, size_t count)
{
	if (records == NULL || count == 0) {
		return -EINVAL;
	}

	external_records = records;
	external_records_count = count;

	return 0;
}

SYS_INIT(mdns_responder_init, APPLICATION, CONFIG_MDNS_RESPONDER_INIT_PRIO);