diff --git a/components/mdns/examples/main/mdns_example_main.c b/components/mdns/examples/main/mdns_example_main.c index 181dfed88..adb09be14 100644 --- a/components/mdns/examples/main/mdns_example_main.c +++ b/components/mdns/examples/main/mdns_example_main.c @@ -93,8 +93,10 @@ static void mdns_print_results(mdns_result_t *results) mdns_ip_addr_t *a = NULL; int i = 1, t; while (r) { - printf("%d: Interface: %s, Type: %s, TTL: %u\n", i++, esp_netif_get_ifkey(r->esp_netif), ip_protocol_str[r->ip_protocol], - r->ttl); + if (r->esp_netif) { + printf("%d: Interface: %s, Type: %s, TTL: %u\n", i++, esp_netif_get_ifkey(r->esp_netif), + ip_protocol_str[r->ip_protocol], r->ttl); + } if (r->instance_name) { printf(" PTR : %s.%s.%s\n", r->instance_name, r->service_type, r->proto); } @@ -140,6 +142,27 @@ static void query_mdns_service(const char *service_name, const char *proto) mdns_query_results_free(results); } +#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST +static void lookup_mdns_delegated_service(const char *service_name, const char *proto) +{ + ESP_LOGI(TAG, "Lookup delegated service: %s.%s.local", service_name, proto); + + mdns_result_t *results = NULL; + esp_err_t err = mdns_lookup_delegated_service(NULL, service_name, proto, 20, &results); + if (err) { + ESP_LOGE(TAG, "Lookup Failed: %s", esp_err_to_name(err)); + return; + } + if (!results) { + ESP_LOGW(TAG, "No results found!"); + return; + } + + mdns_print_results(results); + mdns_query_results_free(results); +} +#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST + static bool check_and_print_result(mdns_search_once_t *search) { // Check if any result is available @@ -234,6 +257,9 @@ static void check_button(void) query_mdns_service("_smb", "_tcp"); query_mdns_service("_ftp", "_tcp"); query_mdns_service("_nfs", "_tcp"); +#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST + lookup_mdns_delegated_service("_http", "_tcp"); +#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST } old_level = new_level; } diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index d6a3f150b..590773ef0 100644 --- a/components/mdns/include/mdns.h +++ b/components/mdns/include/mdns.h @@ -26,7 +26,6 @@ extern "C" { */ typedef struct mdns_search_once_s mdns_search_once_t; - typedef enum { MDNS_EVENT_ENABLE_IP4 = 1 << 1, MDNS_EVENT_ENABLE_IP6 = 1 << 2, @@ -248,7 +247,6 @@ esp_err_t mdns_service_add_for_host(const char *instance_name, const char *servi */ bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname); - /** * @brief Check whether a service has been added. * @@ -687,6 +685,24 @@ esp_err_t mdns_query_srv(const char *instance_name, const char *service_type, co */ esp_err_t mdns_query_txt(const char *instance_name, const char *service_type, const char *proto, uint32_t timeout, mdns_result_t **result); +/** + * @brief Look up delegated services. + * + * @param instance instance name (NULL for uncertain instance) + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param max_results maximum results to be collected + * @param result pointer to the result of the search + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t mdns_lookup_delegated_service(const char *instance, const char *service_type, const char *proto, size_t max_results, + mdns_result_t **result); + /** * @brief Query mDNS for A record * diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 244c6b5a0..02003abde 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -5736,6 +5736,131 @@ bool mdns_service_exists_with_instance(const char *instance, const char *service return _mdns_get_service_item_instance(instance, service_type, proto, hostname) != NULL; } +static mdns_txt_item_t *_copy_mdns_txt_items(mdns_txt_linked_item_t *items, uint8_t **txt_value_len, size_t *txt_count) +{ + mdns_txt_item_t *ret = NULL; + size_t ret_index = 0; + for (mdns_txt_linked_item_t *tmp = items; tmp != NULL; tmp = tmp->next) { + ret_index++; + } + *txt_count = ret_index; + ret = (mdns_txt_item_t *)calloc(ret_index, sizeof(mdns_txt_item_t)); + *txt_value_len = (uint8_t *)calloc(ret_index, sizeof(uint8_t)); + if (!ret || !(*txt_value_len)) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + ret_index = 0; + for (mdns_txt_linked_item_t *tmp = items; tmp != NULL; tmp = tmp->next) { + size_t key_len = strlen(tmp->key); + char *key = (char *)malloc(key_len + 1); + if (!key) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + memcpy(key, tmp->key, key_len); + key[key_len] = 0; + ret[ret_index].key = key; + char *value = (char *)malloc(tmp->value_len + 1); + if (!value) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + memcpy(value, tmp->value, tmp->value_len); + value[tmp->value_len] = 0; + ret[ret_index].value = value; + (*txt_value_len)[ret_index] = tmp->value_len; + ret_index++; + } + return ret; + +handle_error: + for (size_t y = 0; y < ret_index + 1; y++) { + mdns_txt_item_t *t = &ret[y]; + free((char *)t->key); + free((char *)t->value); + } + free(*txt_value_len); + free(ret); + return NULL; +} + +static mdns_ip_addr_t *_copy_delegated_host_address_list(char *hostname) +{ + mdns_host_item_t *host = _mdns_host_list; + while (host) { + if (strcasecmp(host->hostname, hostname) == 0) { + return copy_address_list(host->address_list); + } + } + return NULL; +} + +static mdns_result_t *_mdns_lookup_delegated_service(const char *instance, const char *service, const char *proto, size_t max_results) +{ + if (_str_null_or_empty(service) || _str_null_or_empty(proto)) { + return NULL; + } + mdns_result_t *results = NULL; + size_t num_results = 0; + mdns_srv_item_t *s = _mdns_server->services; + while (s) { + mdns_service_t *srv = s->service; + if (srv && srv->hostname && (_str_null_or_empty(_mdns_server->hostname) || strcmp(_mdns_server->hostname, srv->hostname) != 0)) { + if (!strcasecmp(srv->service, service) && !strcasecmp(srv->proto, proto) && + (_str_null_or_empty(instance) || _mdns_instance_name_match(srv->instance, instance))) { + mdns_result_t *item = (mdns_result_t *)malloc(sizeof(mdns_result_t)); + if (!item) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + item->next = results; + results = item; + item->esp_netif = NULL; + item->ttl = UINT32_MAX; + item->ip_protocol = MDNS_IP_PROTOCOL_MAX; + item->instance_name = strndup(srv->instance, MDNS_NAME_BUF_LEN - 1); + if (!item->instance_name) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + item->service_type = strndup(srv->service, MDNS_NAME_BUF_LEN - 1); + if (!item->service_type) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + item->proto = strndup(srv->proto, MDNS_NAME_BUF_LEN - 1); + if (!item->proto) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + item->hostname = strndup(srv->hostname, MDNS_NAME_BUF_LEN - 1); + if (!item->hostname) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + item->port = srv->port; + item->txt = _copy_mdns_txt_items(srv->txt, &(item->txt_value_len), &(item->txt_count)); + item->addr = _copy_delegated_host_address_list(item->hostname); + if (!item->addr) { + goto handle_error; + } + if (num_results < max_results) { + num_results++; + } + if (num_results >= max_results) { + break; + } + } + } + s = s->next; + } + return results; +handle_error: + mdns_query_results_free(results); + return NULL; +} + esp_err_t mdns_service_port_set_for_host(const char *instance, const char *service, const char *proto, const char *hostname, uint16_t port) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) { @@ -6207,6 +6332,21 @@ esp_err_t mdns_query_txt(const char *instance, const char *service, const char * return mdns_query(instance, service, proto, MDNS_TYPE_TXT, timeout, 1, result); } +esp_err_t mdns_lookup_delegated_service(const char *instance, const char *service, const char *proto, size_t max_results, + mdns_result_t **result) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + if (!result || _str_null_or_empty(service) || _str_null_or_empty(proto)) { + return ESP_ERR_INVALID_ARG; + } + MDNS_SERVICE_LOCK(); + *result = _mdns_lookup_delegated_service(instance, service, proto, max_results); + MDNS_SERVICE_UNLOCK(); + return ESP_OK; +} + esp_err_t mdns_query_a(const char *name, uint32_t timeout, esp_ip4_addr_t *addr) { mdns_result_t *result = NULL;