net: dns: resolve: Enable discovery of all service instances

The DNS-based Service Discovery has the following abstract:

   This document specifies how DNS resource records are named and
   structured to facilitate service discovery.  Given a type of service
   that a client is looking for, and a domain in which the client is
   looking for that service, this mechanism allows clients to discover
   a list of named instances of that desired service, using standard
   DNS queries.  This mechanism is referred to as DNS-based Service
   Discovery, or DNS-SD.

As is stated here, DNS-based service discovery is designed to find all
instances implementing a service, not just the first one.

Currently, zephyr `dns_resolve_service` will call the callback for only
the first client instance found. It still does receive the responses
from other instances, but those are dropped since the query is already
marked as finished. The seems incorrect behavior.

With that said, the changes in this commit are API breaking, since even
the docs already state that only the first response is currently used.
So I am fine with creating a new function for discovering all instances
if that is more acceptable.

Since DNS-SD queries expect multiple responses, timeout or manual
cancellation are the only methods to stop an in-flight request. When a
timeout happens, the callback is called with one of the following
responses:
- `DNS_EAI_ALLDONE`: If at least one successful response was received.
- `DNS_EAI_CANCELED`: If no successful response was received.

Tested with 3 BeagleConnect Freedoms (2 running mdns_responder and 1
running dns_resolve sample).

Signed-off-by: Ayush Singh <ayush@beagleboard.org>
This commit is contained in:
Ayush Singh
2025-12-17 13:17:50 +05:30
committed by Johan Hedberg
parent 26a08c86f6
commit b0229771d5
2 changed files with 22 additions and 7 deletions

View File

@@ -516,6 +516,9 @@ struct dns_resolve_context {
* cannot be used to find correct pending query.
*/
uint16_t query_hash;
/** Flag to indicate that the callback has been called at least once. */
bool cb_called;
} queries[DNS_NUM_CONCUR_QUERIES];
/** Is this context in use */
@@ -768,9 +771,8 @@ int dns_resolve_name(struct dns_resolve_context *ctx,
* Note that this is an asynchronous call, the function will return immediately
* and the system will call the callback after resolving has finished or a timeout
* has occurred.
* We might send the query to multiple servers (if there are more than one
* server configured), but we only use the result of the first received
* response.
* The callback is called for each response received. The query needs to be either cancelled
* manually, or by the timeout.
*
* @param ctx DNS context
* @param query What the caller wants to resolve.

View File

@@ -1555,10 +1555,18 @@ static int dns_read(struct dns_resolve_context *ctx,
}
#endif /* CONFIG_DNS_RESOLVER_PACKET_FORWARDING */
invoke_query_callback(ret, NULL, &ctx->queries[query_idx]);
/* Mark the query as success. Only used in case of DNS-SD query which need to wait for
* multiple responses.
*/
ctx->queries[query_idx].cb_called = true;
/* Marks the end of the results */
release_query(&ctx->queries[query_idx]);
/* DNS service discovery can have multiple responses. */
if (ctx->queries[query_idx].query_type != DNS_QUERY_TYPE_PTR) {
invoke_query_callback(ret, NULL, &ctx->queries[query_idx]);
/* Marks the end of the results */
release_query(&ctx->queries[query_idx]);
}
return 0;
@@ -1709,7 +1717,11 @@ static int dns_write(struct dns_resolve_context *ctx,
/* Must be invoked with context lock held */
static void dns_resolve_cancel_slot(struct dns_resolve_context *ctx, int slot)
{
invoke_query_callback(DNS_EAI_CANCELED, NULL, &ctx->queries[slot]);
if (ctx->queries[slot].cb_called) {
invoke_query_callback(DNS_EAI_ALLDONE, NULL, &ctx->queries[slot]);
} else {
invoke_query_callback(DNS_EAI_CANCELED, NULL, &ctx->queries[slot]);
}
release_query(&ctx->queries[slot]);
}
@@ -2087,6 +2099,7 @@ try_resolve:
ctx->queries[i].user_data = user_data;
ctx->queries[i].ctx = ctx;
ctx->queries[i].query_hash = 0;
ctx->queries[i].cb_called = false;
k_work_init_delayable(&ctx->queries[i].timer, query_timeout);