Files
esp-protocols/components/mdns/mdns_querier.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

873 lines
26 KiB
C
Raw Normal View History

/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "sdkconfig.h"
#include "mdns_private.h"
#include "mdns_querier.h"
#include "mdns_mem_caps.h"
#include "mdns_utils.h"
#include "mdns_send.h"
#include "esp_log.h"
#include "mdns_pcb.h"
#include "mdns_netif.h"
#include "mdns_responder.h"
#include "mdns_service.h"
static const char *TAG = "mdns_querier";
static mdns_search_once_t *s_search_once;
static esp_err_t send_search_action(mdns_action_type_t type, mdns_search_once_t *search);
static void search_free(mdns_search_once_t *search);
void mdns_priv_query_results_free(mdns_result_t *results)
{
mdns_result_t *r;
mdns_ip_addr_t *a;
while (results) {
r = results;
mdns_mem_free((char *)(r->hostname));
mdns_mem_free((char *)(r->instance_name));
mdns_mem_free((char *)(r->service_type));
mdns_mem_free((char *)(r->proto));
for (size_t i = 0; i < r->txt_count; i++) {
mdns_mem_free((char *)(r->txt[i].key));
mdns_mem_free((char *)(r->txt[i].value));
}
mdns_mem_free(r->txt);
mdns_mem_free(r->txt_value_len);
while (r->addr) {
a = r->addr;
r->addr = r->addr->next;
mdns_mem_free(a);
}
results = results->next;
mdns_mem_free(r);
}
}
/**
* @brief Mark search as finished and remove it from search chain
*/
static void search_finish(mdns_search_once_t *search)
{
search->state = SEARCH_OFF;
queueDetach(mdns_search_once_t, s_search_once, search);
if (search->notifier) {
search->notifier(search);
}
xSemaphoreGive(search->done_semaphore);
}
/**
* @brief Add new search to the search chain
*/
void search_add(mdns_search_once_t *search)
{
search->next = s_search_once;
s_search_once = search;
}
/**
* @brief Send search packet to all available interfaces
*/
static void search_send(mdns_search_once_t *search)
{
mdns_search_once_t *queue = s_search_once;
bool found = false;
// looking for this search in active searches
while (queue) {
if (queue == search) {
found = true;
break;
}
queue = queue->next;
}
if (!found) {
// no longer active -> skip sending this search
return;
}
uint8_t i, j;
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) {
mdns_priv_query_send(search, (mdns_if_t) i, (mdns_ip_protocol_t) j);
}
}
}
void mdns_priv_query_action(mdns_action_t *action, mdns_action_subtype_t type)
{
if (type == ACTION_RUN) {
switch (action->type) {
case ACTION_SEARCH_ADD:
search_add(action->data.search_add.search);
break;
case ACTION_SEARCH_SEND:
search_send(action->data.search_add.search);
break;
case ACTION_SEARCH_END:
search_finish(action->data.search_add.search);
break;
default:
abort();
}
return;
}
if (type == ACTION_CLEANUP) {
search_free(action->data.search_add.search);
}
}
/**
* @brief Called from timer task to run active searches
*/
void mdns_priv_query_start_stop(void)
{
mdns_priv_service_lock();
mdns_search_once_t *s = s_search_once;
uint32_t now = xTaskGetTickCount() * portTICK_PERIOD_MS;
if (!s) {
mdns_priv_service_unlock();
return;
}
while (s) {
if (s->state != SEARCH_OFF) {
if (now > (s->started_at + s->timeout)) {
s->state = SEARCH_OFF;
if (send_search_action(ACTION_SEARCH_END, s) != ESP_OK) {
s->state = SEARCH_RUNNING;
}
} else if (s->state == SEARCH_INIT || (now - s->sent_at) > 1000) {
s->state = SEARCH_RUNNING;
s->sent_at = now;
if (send_search_action(ACTION_SEARCH_SEND, s) != ESP_OK) {
s->sent_at -= 1000;
}
}
}
s = s->next;
}
mdns_priv_service_unlock();
}
void mdns_priv_query_free(void)
{
while (s_search_once) {
mdns_search_once_t *h = s_search_once;
s_search_once = h->next;
mdns_mem_free(h->instance);
mdns_mem_free(h->service);
mdns_mem_free(h->proto);
vSemaphoreDelete(h->done_semaphore);
if (h->result) {
mdns_priv_query_results_free(h->result);
}
mdns_mem_free(h);
}
}
/**
* @brief Called from parser to finish any searches that have reached maximum results
*/
void mdns_priv_query_done(void)
{
mdns_search_once_t *search = s_search_once;
mdns_search_once_t *s = NULL;
while (search) {
s = search;
search = search->next;
if (s->max_results && s->num_results >= s->max_results) {
search_finish(s);
}
}
}
/**
* @brief Called from packet parser to find matching running search
*/
mdns_search_once_t *mdns_priv_query_find_from(mdns_search_once_t *s, mdns_name_t *name, uint16_t type, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
{
mdns_result_t *r = NULL;
while (s) {
if (s->state == SEARCH_OFF) {
s = s->next;
continue;
}
if (type == MDNS_TYPE_A || type == MDNS_TYPE_AAAA) {
if ((s->type == MDNS_TYPE_ANY && s->service != NULL)
|| (s->type != MDNS_TYPE_ANY && s->type != type && s->type != MDNS_TYPE_PTR && s->type != MDNS_TYPE_SRV)) {
s = s->next;
continue;
}
if (s->type != MDNS_TYPE_PTR && s->type != MDNS_TYPE_SRV) {
if (!strcasecmp(name->host, s->instance)) {
return s;
}
s = s->next;
continue;
}
r = s->result;
while (r) {
if (r->esp_netif == mdns_priv_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !mdns_utils_str_null_or_empty(r->hostname) && !strcasecmp(name->host, r->hostname)) {
return s;
}
r = r->next;
}
s = s->next;
continue;
}
if (type == MDNS_TYPE_SRV || type == MDNS_TYPE_TXT) {
if ((s->type == MDNS_TYPE_ANY && s->service == NULL)
|| (s->type != MDNS_TYPE_ANY && s->type != type && s->type != MDNS_TYPE_PTR)) {
s = s->next;
continue;
}
if (strcasecmp(name->service, s->service)
|| strcasecmp(name->proto, s->proto)) {
s = s->next;
continue;
}
if (s->type != MDNS_TYPE_PTR) {
if (s->instance && strcasecmp(name->host, s->instance) == 0) {
return s;
}
s = s->next;
continue;
}
return s;
}
if (type == MDNS_TYPE_PTR && type == s->type && !strcasecmp(name->service, s->service) && !strcasecmp(name->proto, s->proto)) {
return s;
}
s = s->next;
}
return NULL;
}
mdns_search_once_t *mdns_priv_query_find(mdns_name_t *name, uint16_t type, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
{
return mdns_priv_query_find_from(s_search_once, name, type, tcpip_if, ip_protocol);
}
/**
* @brief Create search packet for particular interface
*/
static mdns_tx_packet_t *create_search_packet(mdns_search_once_t *search, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
{
mdns_result_t *r = NULL;
mdns_tx_packet_t *packet = mdns_priv_alloc_packet(tcpip_if, ip_protocol);
if (!packet) {
return NULL;
}
mdns_out_question_t *q = (mdns_out_question_t *)mdns_mem_malloc(sizeof(mdns_out_question_t));
if (!q) {
HOOK_MALLOC_FAILED;
mdns_priv_free_tx_packet(packet);
return NULL;
}
q->next = NULL;
q->unicast = search->unicast;
q->type = search->type;
q->host = search->instance;
q->service = search->service;
q->proto = search->proto;
q->domain = MDNS_UTILS_DEFAULT_DOMAIN;
q->own_dynamic_memory = false;
queueToEnd(mdns_out_question_t, packet->questions, q);
if (search->type == MDNS_TYPE_PTR) {
r = search->result;
while (r) {
//full record on the same interface is available
if (r->esp_netif != mdns_priv_get_esp_netif(tcpip_if) || r->ip_protocol != ip_protocol || r->instance_name == NULL || r->hostname == NULL || r->addr == NULL) {
r = r->next;
continue;
}
mdns_out_answer_t *a = (mdns_out_answer_t *)mdns_mem_malloc(sizeof(mdns_out_answer_t));
if (!a) {
HOOK_MALLOC_FAILED;
mdns_priv_free_tx_packet(packet);
return NULL;
}
a->type = MDNS_TYPE_PTR;
a->service = NULL;
a->custom_instance = r->instance_name;
a->custom_service = search->service;
a->custom_proto = search->proto;
a->bye = false;
a->flush = false;
a->next = NULL;
queueToEnd(mdns_out_answer_t, packet->answers, a);
r = r->next;
}
}
return packet;
}
/**
* @brief Send search packet to particular interface
*/
void mdns_priv_query_send(mdns_search_once_t *search, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
{
mdns_tx_packet_t *packet = NULL;
if (mdsn_priv_pcb_is_inited(tcpip_if, ip_protocol)) {
packet = create_search_packet(search, tcpip_if, ip_protocol);
if (!packet) {
return;
}
mdns_priv_dispatch_tx_packet(packet);
mdns_priv_free_tx_packet(packet);
}
}
/**
* @brief Free search structure (except the results)
*/
static void search_free(mdns_search_once_t *search)
{
mdns_mem_free(search->instance);
mdns_mem_free(search->service);
mdns_mem_free(search->proto);
vSemaphoreDelete(search->done_semaphore);
mdns_mem_free(search);
}
/**
* @brief Allocate new search structure
*/
static mdns_search_once_t *search_init(const char *name, const char *service, const char *proto, uint16_t type, bool unicast,
uint32_t timeout, uint8_t max_results, mdns_query_notify_t notifier)
{
mdns_search_once_t *search = (mdns_search_once_t *)mdns_mem_malloc(sizeof(mdns_search_once_t));
if (!search) {
HOOK_MALLOC_FAILED;
return NULL;
}
memset(search, 0, sizeof(mdns_search_once_t));
search->done_semaphore = xSemaphoreCreateBinary();
if (!search->done_semaphore) {
mdns_mem_free(search);
return NULL;
}
if (!mdns_utils_str_null_or_empty(name)) {
search->instance = mdns_mem_strndup(name, MDNS_NAME_BUF_LEN - 1);
if (!search->instance) {
search_free(search);
return NULL;
}
}
if (!mdns_utils_str_null_or_empty(service)) {
search->service = mdns_mem_strndup(service, MDNS_NAME_BUF_LEN - 1);
if (!search->service) {
search_free(search);
return NULL;
}
}
if (!mdns_utils_str_null_or_empty(proto)) {
search->proto = mdns_mem_strndup(proto, MDNS_NAME_BUF_LEN - 1);
if (!search->proto) {
search_free(search);
return NULL;
}
}
search->type = type;
search->unicast = unicast;
search->timeout = timeout;
search->num_results = 0;
search->max_results = max_results;
search->result = NULL;
search->state = SEARCH_INIT;
search->sent_at = 0;
search->started_at = xTaskGetTickCount() * portTICK_PERIOD_MS;
search->notifier = notifier;
search->next = NULL;
return search;
}
/**
* @brief Queue search action
*/
static esp_err_t send_search_action(mdns_action_type_t type, mdns_search_once_t *search)
{
mdns_action_t *action = NULL;
action = (mdns_action_t *)mdns_mem_malloc(sizeof(mdns_action_t));
if (!action) {
HOOK_MALLOC_FAILED;
return ESP_ERR_NO_MEM;
}
action->type = type;
action->data.search_add.search = search;
if (!mdns_priv_queue_action(action)) {
mdns_mem_free(action);
return ESP_ERR_NO_MEM;
}
return ESP_OK;
}
/**
* @brief Called from parser to add TXT data to search result
*/
void mdns_priv_query_result_add_txt(mdns_search_once_t *search, mdns_txt_item_t *txt, uint8_t *txt_value_len,
size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol,
uint32_t ttl)
{
mdns_result_t *r = search->result;
while (r) {
if (r->esp_netif == mdns_priv_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol) {
if (r->txt) {
goto free_txt;
}
r->txt = txt;
r->txt_value_len = txt_value_len;
r->txt_count = txt_count;
mdns_priv_query_update_result_ttl(r, ttl);
return;
}
r = r->next;
}
if (!search->max_results || search->num_results < search->max_results) {
r = (mdns_result_t *)mdns_mem_malloc(sizeof(mdns_result_t));
if (!r) {
HOOK_MALLOC_FAILED;
goto free_txt;
}
memset(r, 0, sizeof(mdns_result_t));
r->txt = txt;
r->txt_value_len = txt_value_len;
r->txt_count = txt_count;
r->esp_netif = mdns_priv_get_esp_netif(tcpip_if);
r->ip_protocol = ip_protocol;
r->ttl = ttl;
r->next = search->result;
search->result = r;
search->num_results++;
}
return;
free_txt:
for (size_t i = 0; i < txt_count; i++) {
mdns_mem_free((char *)(txt[i].key));
mdns_mem_free((char *)(txt[i].value));
}
mdns_mem_free(txt);
mdns_mem_free(txt_value_len);
}
/**
* @brief Chain new IP to search result
*/
static void result_add_ip(mdns_result_t *r, esp_ip_addr_t *ip)
{
mdns_ip_addr_t *a = r->addr;
while (a) {
if (a->addr.type == ip->type) {
#ifdef CONFIG_LWIP_IPV4
if (a->addr.type == ESP_IPADDR_TYPE_V4 && a->addr.u_addr.ip4.addr == ip->u_addr.ip4.addr) {
return;
}
#endif
#ifdef CONFIG_LWIP_IPV6
if (a->addr.type == ESP_IPADDR_TYPE_V6 && !memcmp(a->addr.u_addr.ip6.addr, ip->u_addr.ip6.addr, 16)) {
return;
}
#endif
}
a = a->next;
}
a = mdns_priv_result_addr_create_ip(ip);
if (!a) {
return;
}
a->next = r->addr;
r->addr = a;
}
/**
* @brief Called from parser to add A/AAAA data to search result
*/
void mdns_priv_query_result_add_ip(mdns_search_once_t *search, const char *hostname, esp_ip_addr_t *ip,
mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl)
{
mdns_result_t *r = NULL;
mdns_ip_addr_t *a = NULL;
if ((search->type == MDNS_TYPE_A && ip->type == ESP_IPADDR_TYPE_V4)
|| (search->type == MDNS_TYPE_AAAA && ip->type == ESP_IPADDR_TYPE_V6)
|| search->type == MDNS_TYPE_ANY) {
r = search->result;
while (r) {
if (r->esp_netif == mdns_priv_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol) {
result_add_ip(r, ip);
mdns_priv_query_update_result_ttl(r, ttl);
return;
}
r = r->next;
}
if (!search->max_results || search->num_results < search->max_results) {
r = (mdns_result_t *)mdns_mem_malloc(sizeof(mdns_result_t));
if (!r) {
HOOK_MALLOC_FAILED;
return;
}
memset(r, 0, sizeof(mdns_result_t));
a = mdns_priv_result_addr_create_ip(ip);
if (!a) {
mdns_mem_free(r);
return;
}
a->next = r->addr;
r->hostname = mdns_mem_strdup(hostname);
r->addr = a;
r->esp_netif = mdns_priv_get_esp_netif(tcpip_if);
r->ip_protocol = ip_protocol;
r->next = search->result;
r->ttl = ttl;
search->result = r;
search->num_results++;
}
} else if (search->type == MDNS_TYPE_PTR || search->type == MDNS_TYPE_SRV) {
r = search->result;
while (r) {
if (r->esp_netif == mdns_priv_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !mdns_utils_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) {
result_add_ip(r, ip);
mdns_priv_query_update_result_ttl(r, ttl);
break;
}
r = r->next;
}
}
}
/**
* @brief Called from parser to add SRV data to search result
*/
void mdns_priv_query_result_add_srv(mdns_search_once_t *search, const char *hostname, uint16_t port,
mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl)
{
mdns_result_t *r = search->result;
while (r) {
if (r->esp_netif == mdns_priv_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !mdns_utils_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) {
mdns_priv_query_update_result_ttl(r, ttl);
return;
}
r = r->next;
}
if (!search->max_results || search->num_results < search->max_results) {
r = (mdns_result_t *)mdns_mem_malloc(sizeof(mdns_result_t));
if (!r) {
HOOK_MALLOC_FAILED;
return;
}
memset(r, 0, sizeof(mdns_result_t));
r->hostname = mdns_mem_strdup(hostname);
if (!r->hostname) {
mdns_mem_free(r);
return;
}
if (search->instance) {
r->instance_name = mdns_mem_strdup(search->instance);
}
r->service_type = mdns_mem_strdup(search->service);
r->proto = mdns_mem_strdup(search->proto);
r->port = port;
r->esp_netif = mdns_priv_get_esp_netif(tcpip_if);
r->ip_protocol = ip_protocol;
r->ttl = ttl;
r->next = search->result;
search->result = r;
search->num_results++;
}
}
/**
* @brief Called from parser to add PTR data to search result
*/
mdns_result_t *mdns_priv_query_result_add_ptr(mdns_search_once_t *search, const char *instance,
const char *service_type, const char *proto, mdns_if_t tcpip_if,
mdns_ip_protocol_t ip_protocol, uint32_t ttl)
{
mdns_result_t *r = search->result;
while (r) {
if (r->esp_netif == mdns_priv_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !mdns_utils_str_null_or_empty(r->instance_name) && !strcasecmp(instance, r->instance_name)) {
mdns_priv_query_update_result_ttl(r, ttl);
return r;
}
r = r->next;
}
if (!search->max_results || search->num_results < search->max_results) {
r = (mdns_result_t *)mdns_mem_malloc(sizeof(mdns_result_t));
if (!r) {
HOOK_MALLOC_FAILED;
return NULL;
}
memset(r, 0, sizeof(mdns_result_t));
r->instance_name = mdns_mem_strdup(instance);
r->service_type = mdns_mem_strdup(service_type);
r->proto = mdns_mem_strdup(proto);
if (!r->instance_name) {
mdns_mem_free(r);
return NULL;
}
r->esp_netif = mdns_priv_get_esp_netif(tcpip_if);
r->ip_protocol = ip_protocol;
r->ttl = ttl;
r->next = search->result;
search->result = r;
search->num_results++;
return r;
}
return NULL;
}
mdns_ip_addr_t *mdns_priv_result_addr_create_ip(esp_ip_addr_t *ip)
{
mdns_ip_addr_t *a = (mdns_ip_addr_t *)mdns_mem_malloc(sizeof(mdns_ip_addr_t));
if (!a) {
HOOK_MALLOC_FAILED;
return NULL;
}
memset(a, 0, sizeof(mdns_ip_addr_t));
a->addr.type = ip->type;
if (ip->type == ESP_IPADDR_TYPE_V6) {
memcpy(a->addr.u_addr.ip6.addr, ip->u_addr.ip6.addr, 16);
} else {
a->addr.u_addr.ip4.addr = ip->u_addr.ip4.addr;
}
return a;
}
/**
* @brief MDNS_PUBLIC_API
* */
void mdns_query_results_free(mdns_result_t *results)
{
mdns_priv_service_lock();
mdns_priv_query_results_free(results);
mdns_priv_service_unlock();
}
esp_err_t mdns_query_async_delete(mdns_search_once_t *search)
{
if (!search) {
return ESP_ERR_INVALID_ARG;
}
if (search->state != SEARCH_OFF) {
return ESP_ERR_INVALID_STATE;
}
mdns_priv_service_lock();
search_free(search);
mdns_priv_service_unlock();
return ESP_OK;
}
bool mdns_query_async_get_results(mdns_search_once_t *search, uint32_t timeout, mdns_result_t **results, uint8_t *num_results)
{
if (xSemaphoreTake(search->done_semaphore, pdMS_TO_TICKS(timeout)) == pdTRUE) {
if (results) {
*results = search->result;
}
if (num_results) {
*num_results = search->num_results;
}
return true;
}
return false;
}
mdns_search_once_t *mdns_query_async_new(const char *name, const char *service, const char *proto, uint16_t type,
uint32_t timeout, size_t max_results, mdns_query_notify_t notifier)
{
mdns_search_once_t *search = NULL;
if (!mdns_priv_is_server_init() || !timeout || mdns_utils_str_null_or_empty(service) != mdns_utils_str_null_or_empty(proto)) {
return NULL;
}
search = search_init(name, service, proto, type, type != MDNS_TYPE_PTR, timeout, max_results, notifier);
if (!search) {
return NULL;
}
if (send_search_action(ACTION_SEARCH_ADD, search)) {
search_free(search);
return NULL;
}
return search;
}
esp_err_t mdns_query_generic(const char *name, const char *service, const char *proto, uint16_t type, mdns_query_transmission_type_t transmission_type, uint32_t timeout, size_t max_results, mdns_result_t **results)
{
mdns_search_once_t *search = NULL;
*results = NULL;
if (!mdns_priv_is_server_init()) {
return ESP_ERR_INVALID_STATE;
}
if (!timeout || mdns_utils_str_null_or_empty(service) != mdns_utils_str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
search = search_init(name, service, proto, type, transmission_type == MDNS_QUERY_UNICAST, timeout, max_results,
NULL);
if (!search) {
return ESP_ERR_NO_MEM;
}
if (send_search_action(ACTION_SEARCH_ADD, search)) {
search_free(search);
return ESP_ERR_NO_MEM;
}
xSemaphoreTake(search->done_semaphore, portMAX_DELAY);
*results = search->result;
search_free(search);
return ESP_OK;
}
esp_err_t mdns_query(const char *name, const char *service_type, const char *proto, uint16_t type, uint32_t timeout, size_t max_results, mdns_result_t **results)
{
return mdns_query_generic(name, service_type, proto, type, type != MDNS_TYPE_PTR, timeout, max_results, results);
}
esp_err_t mdns_query_ptr(const char *service, const char *proto, uint32_t timeout, size_t max_results, mdns_result_t **results)
{
if (mdns_utils_str_null_or_empty(service) || mdns_utils_str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
return mdns_query(NULL, service, proto, MDNS_TYPE_PTR, timeout, max_results, results);
}
esp_err_t mdns_query_srv(const char *instance, const char *service, const char *proto, uint32_t timeout, mdns_result_t **result)
{
if (mdns_utils_str_null_or_empty(instance) || mdns_utils_str_null_or_empty(service) || mdns_utils_str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
return mdns_query(instance, service, proto, MDNS_TYPE_SRV, timeout, 1, result);
}
esp_err_t mdns_query_txt(const char *instance, const char *service, const char *proto, uint32_t timeout, mdns_result_t **result)
{
if (mdns_utils_str_null_or_empty(instance) || mdns_utils_str_null_or_empty(service) || mdns_utils_str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
return mdns_query(instance, service, proto, MDNS_TYPE_TXT, timeout, 1, result);
}
#ifdef CONFIG_LWIP_IPV4
esp_err_t mdns_query_a(const char *name, uint32_t timeout, esp_ip4_addr_t *addr)
{
mdns_result_t *result = NULL;
esp_err_t err;
if (mdns_utils_str_null_or_empty(name)) {
return ESP_ERR_INVALID_ARG;
}
if (strstr(name, ".local")) {
ESP_LOGW(TAG, "Please note that hostname must not contain domain name, as mDNS uses '.local' domain");
}
err = mdns_query(name, NULL, NULL, MDNS_TYPE_A, timeout, 1, &result);
if (err) {
return err;
}
if (!result) {
return ESP_ERR_NOT_FOUND;
}
mdns_ip_addr_t *a = result->addr;
while (a) {
if (a->addr.type == ESP_IPADDR_TYPE_V4) {
addr->addr = a->addr.u_addr.ip4.addr;
mdns_query_results_free(result);
return ESP_OK;
}
a = a->next;
}
mdns_query_results_free(result);
return ESP_ERR_NOT_FOUND;
}
#endif /* CONFIG_LWIP_IPV4 */
#ifdef CONFIG_LWIP_IPV6
esp_err_t mdns_query_aaaa(const char *name, uint32_t timeout, esp_ip6_addr_t *addr)
{
mdns_result_t *result = NULL;
esp_err_t err;
if (mdns_utils_str_null_or_empty(name)) {
return ESP_ERR_INVALID_ARG;
}
if (strstr(name, ".local")) {
ESP_LOGW(TAG, "Please note that hostname must not contain domain name, as mDNS uses '.local' domain");
}
err = mdns_query(name, NULL, NULL, MDNS_TYPE_AAAA, timeout, 1, &result);
if (err) {
return err;
}
if (!result) {
return ESP_ERR_NOT_FOUND;
}
mdns_ip_addr_t *a = result->addr;
while (a) {
if (a->addr.type == ESP_IPADDR_TYPE_V6) {
memcpy(addr->addr, a->addr.u_addr.ip6.addr, 16);
mdns_query_results_free(result);
return ESP_OK;
}
a = a->next;
}
mdns_query_results_free(result);
return ESP_ERR_NOT_FOUND;
}
#endif /* CONFIG_LWIP_IPV6 */