From 5f244c86f29da46c17610563a245d1663a46b439 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Fri, 16 Apr 2021 15:19:34 +0800 Subject: [PATCH 1/9] mdns: fix memory free issue when repeating the query in reply The repeated query will be copied in the next event loop while the memory is freed instantly. Delay the free to fix this issue. --- components/mdns/mdns.c | 52 ++++++++++++++++--- .../mdns/private_include/mdns_private.h | 1 + 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index af3ef03d79..11a495195d 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -1057,7 +1057,26 @@ static void _mdns_free_tx_packet(mdns_tx_packet_t * packet) if (!packet) { return; } - queueFree(mdns_out_question_t, packet->questions); + mdns_out_question_t *q = packet->questions; + while (q) { + mdns_out_question_t *next = q->next; + if (q->own_dynamic_memory) { + if (q->host) { + free((char *)q->host); + } + if (q->service) { + free((char *)q->service); + } + if (q->proto) { + free((char *)q->proto); + } + if (q->domain) { + free((char *)q->domain); + } + } + free(q); + q = next; + } queueFree(mdns_out_answer_t, packet->answers); queueFree(mdns_out_answer_t, packet->servers); queueFree(mdns_out_answer_t, packet->additional); @@ -1341,8 +1360,18 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed _mdns_free_tx_packet(packet); return; } - memcpy(out_question, q, sizeof(mdns_out_question_t)); + out_question->type = q->type; + out_question->unicast = q->unicast; + out_question->host = q->host; + q->host = NULL; + out_question->service = q->service; + q->service = NULL; + out_question->proto = q->proto; + q->proto = NULL; + out_question->domain = q->domain; + q->domain = NULL; out_question->next = NULL; + out_question->own_dynamic_memory = true; queueToEnd(mdns_out_question_t, packet->questions, out_question); #endif // MDNS_REPEAT_QUERY_IN_RESPONSE } else if (!_mdns_alloc_answer(&packet->answers, q->type, NULL, send_flush, false)) { @@ -1409,6 +1438,7 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_ q->service = services[i]->service->service; q->proto = services[i]->service->proto; q->domain = MDNS_DEFAULT_DOMAIN; + q->own_dynamic_memory = false; if (!q->host || _mdns_question_exists(q, packet->questions)) { free(q); continue; @@ -1436,6 +1466,7 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_ q->service = NULL; q->proto = NULL; q->domain = MDNS_DEFAULT_DOMAIN; + q->own_dynamic_memory = false; if (_mdns_question_exists(q, packet->questions)) { free(q); } else { @@ -3117,10 +3148,18 @@ clear_rx_packet: while (parsed_packet->questions) { mdns_parsed_question_t * question = parsed_packet->questions; parsed_packet->questions = parsed_packet->questions->next; - free(question->host); - free(question->service); - free(question->proto); - free(question->domain); + if (question->host) { + free(question->host); + } + if (question->service) { + free(question->service); + } + if (question->proto) { + free(question->proto); + } + if (question->domain) { + free(question->domain); + } free(question); } free(parsed_packet); @@ -3650,6 +3689,7 @@ static mdns_tx_packet_t * _mdns_create_search_packet(mdns_search_once_t * search q->service = search->service; q->proto = search->proto; q->domain = MDNS_DEFAULT_DOMAIN; + q->own_dynamic_memory = false; queueToEnd(mdns_out_question_t, packet->questions, q); if (search->type == MDNS_TYPE_PTR) { diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index 9ed0dcfbd1..d8d507413f 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -299,6 +299,7 @@ typedef struct mdns_out_question_s { const char * service; const char * proto; const char * domain; + bool own_dynamic_memory; } mdns_out_question_t; typedef struct mdns_out_answer_s { From 401ff56cc1ad1d11284143a348cc0c0e4a363e98 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Tue, 30 Mar 2021 13:19:01 +0800 Subject: [PATCH 2/9] mdns: add mdns delegation This allows publishing mdns services for other devices. --- components/mdns/include/mdns.h | 28 + components/mdns/mdns.c | 582 ++++++++++++------ .../mdns/private_include/mdns_private.h | 22 +- .../protocols/mdns/main/mdns_example_main.c | 82 ++- 4 files changed, 494 insertions(+), 220 deletions(-) diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index 22da2afabc..dcf8972bdd 100644 --- a/components/mdns/include/mdns.h +++ b/components/mdns/include/mdns.h @@ -114,6 +114,10 @@ void mdns_free(void); */ esp_err_t mdns_hostname_set(const char * hostname); +esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t *address); + +bool mdns_hostname_exists(const char *hostname); + /** * @brief Set the default instance name for mDNS server * @@ -145,6 +149,12 @@ esp_err_t mdns_instance_name_set(const char * instance_name); */ esp_err_t mdns_service_add(const char * instance_name, const char * service_type, const char * proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items); + +esp_err_t mdns_service_add_custom_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, uint16_t port, mdns_txt_item_t txt[], size_t num_items); + +bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname); + /** * @brief Remove service from mDNS server * @@ -159,6 +169,8 @@ esp_err_t mdns_service_add(const char * instance_name, const char * service_type */ esp_err_t mdns_service_remove(const char * service_type, const char * proto); +esp_err_t mdns_service_remove_for_host(const char * service_type, const char * proto, const char *hostname); + /** * @brief Set instance name for service * @@ -174,6 +186,8 @@ esp_err_t mdns_service_remove(const char * service_type, const char * proto); */ esp_err_t mdns_service_instance_name_set(const char * service_type, const char * proto, const char * instance_name); +esp_err_t mdns_service_instance_name_set_for_host(const char * service_type, const char * proto, const char *hostname, const char * instance_name); + /** * @brief Set service port * @@ -189,6 +203,10 @@ esp_err_t mdns_service_instance_name_set(const char * service_type, const char * */ esp_err_t mdns_service_port_set(const char * service_type, const char * proto, uint16_t port); + +esp_err_t mdns_service_port_set_for_host(const char *service_type, const char *proto, const char *hostname, + uint16_t port); + /** * @brief Replace all TXT items for service * @@ -205,6 +223,9 @@ esp_err_t mdns_service_port_set(const char * service_type, const char * proto, u */ esp_err_t mdns_service_txt_set(const char * service_type, const char * proto, mdns_txt_item_t txt[], uint8_t num_items); +esp_err_t mdns_service_txt_set_for_host(const char *service_type, const char *proto, const char *hostname, + mdns_txt_item_t txt[], uint8_t num_items); + /** * @brief Set/Add TXT item for service TXT record * @@ -221,6 +242,10 @@ esp_err_t mdns_service_txt_set(const char * service_type, const char * proto, md */ esp_err_t mdns_service_txt_item_set(const char * service_type, const char * proto, const char * key, const char * value); + +esp_err_t mdns_service_txt_item_set_for_host(const char *service_type, const char *proto, const char *hostname, + const char *key, const char *value); + /** * @brief Remove TXT item for service TXT record * @@ -236,6 +261,9 @@ esp_err_t mdns_service_txt_item_set(const char * service_type, const char * prot */ esp_err_t mdns_service_txt_item_remove(const char * service_type, const char * proto, const char * key); +esp_err_t mdns_service_txt_item_remove_for_host(const char *service_type, const char *proto, const char *hostname, + const char *key); + /** * @brief Remove and free all services from mDNS server * diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 11a495195d..2a715fe304 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -31,6 +31,8 @@ static const char * MDNS_DEFAULT_DOMAIN = "local"; static const char * MDNS_SUB_STR = "_sub"; mdns_server_t * _mdns_server = NULL; +static mdns_host_item_t *_mdns_host_list = NULL; +static mdns_host_item_t _mdns_self_host; static const char *TAG = "MDNS"; @@ -43,6 +45,7 @@ static void _mdns_search_result_add_ip(mdns_search_once_t * search, const char * static void _mdns_search_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); static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_item_t * txt, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static mdns_result_t * _mdns_search_result_add_ptr(mdns_search_once_t * search, const char * instance, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); +static bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye); /* * @brief Internal collection of mdns supported interfaces @@ -143,6 +146,12 @@ static char * _mdns_mangle_name(char* in) { return ret; } +static bool _mdns_service_match(const mdns_service_t *srv, const char *service, const char *proto, const char *hostname) +{ + return !strcasecmp(srv->service, service) && !strcasecmp(srv->proto, proto) && + (_str_null_or_empty(hostname) || !strcasecmp(srv->hostname, hostname)); +} + /** * @brief finds service from given service type * @param server the server @@ -151,11 +160,11 @@ static char * _mdns_mangle_name(char* in) { * * @return the service item if found or NULL on error */ -static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char * proto) +static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char * proto, const char *hostname) { mdns_srv_item_t * s = _mdns_server->services; while (s) { - if (!strcasecmp(s->service->service, service) && !strcasecmp(s->service->proto, proto)) { + if (_mdns_service_match(s->service, service, proto, hostname)) { return s; } s = s->next; @@ -163,6 +172,21 @@ static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char return NULL; } +static mdns_host_item_t *mdns_get_host_item(const char *hostname, uint8_t address_type) +{ + if (hostname == NULL || strcasecmp(hostname, _mdns_server->hostname) == 0) { + return &_mdns_self_host; + } + mdns_host_item_t *host = _mdns_host_list; + while (host != NULL) { + if (strcasecmp(host->hostname, hostname) == 0 && host->address.type == address_type) { + return host; + } + host = host->next; + } + return NULL; +} + static bool _mdns_can_add_more_services(void) { mdns_srv_item_t * s = _mdns_server->services; @@ -704,7 +728,11 @@ static uint16_t _mdns_append_srv_record(uint8_t * packet, uint16_t * index, mdns return 0; } - str[0] = _mdns_server->hostname; + if (service->hostname) { + str[0] = service->hostname; + } else { + str[0] = _mdns_server->hostname; + } str[1] = MDNS_DEFAULT_DOMAIN; if (_str_null_or_empty(str[0])) { @@ -731,20 +759,19 @@ static uint16_t _mdns_append_srv_record(uint8_t * packet, uint16_t * index, mdns * * @return length of added data: 0 on error or length on success */ -static uint16_t _mdns_append_a_record(uint8_t * packet, uint16_t * index, uint32_t ip, bool flush, bool bye) +static uint16_t _mdns_append_a_record(uint8_t * packet, uint16_t * index, const char * hostname, uint32_t ip, bool flush, bool bye) { const char * str[2]; uint16_t record_length = 0; uint8_t part_length; - str[0] = _mdns_server->hostname; + str[0] = hostname; str[1] = MDNS_DEFAULT_DOMAIN; if (_str_null_or_empty(str[0])) { return 0; } - part_length = _mdns_append_fqdn(packet, index, str, 2); if (!part_length) { return 0; @@ -778,17 +805,18 @@ static uint16_t _mdns_append_a_record(uint8_t * packet, uint16_t * index, uint32 * * @param packet MDNS packet * @param index offset in the packet + * @param hostnamek the hostname address to add * @param ipv6 the IPv6 address to add * * @return length of added data: 0 on error or length on success */ -static uint16_t _mdns_append_aaaa_record(uint8_t * packet, uint16_t * index, uint8_t * ipv6, bool flush, bool bye) +static uint16_t _mdns_append_aaaa_record(uint8_t * packet, uint16_t * index, const char * hostname, uint8_t * ipv6, bool flush, bool bye) { const char * str[2]; uint16_t record_length = 0; uint8_t part_length; - str[0] = _mdns_server->hostname; + str[0] = hostname; str[1] = MDNS_DEFAULT_DOMAIN; if (_str_null_or_empty(str[0])) { @@ -908,6 +936,7 @@ static bool _ipv6_address_is_zero(esp_ip6_addr_t ip6) * @brief Append answer to packet * * @return number of answers added to the packet + * XXX: create the answers here */ static uint8_t _mdns_append_answer(uint8_t * packet, uint16_t * index, mdns_out_answer_t * answer, mdns_if_t tcpip_if) { @@ -930,54 +959,71 @@ static uint8_t _mdns_append_answer(uint8_t * packet, uint16_t * index, mdns_out_ } else if (answer->type == MDNS_TYPE_SDPTR) { return _mdns_append_sdptr_record(packet, index, answer->service, answer->flush, answer->bye) > 0; } else if (answer->type == MDNS_TYPE_A) { - esp_netif_ip_info_t if_ip_info; - if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state != PCB_DUP) { - return 0; - } - if (esp_netif_get_ip_info(_mdns_get_esp_netif(tcpip_if), &if_ip_info)) { - return 0; - } - if (_mdns_append_a_record(packet, index, if_ip_info.ip.addr, answer->flush, answer->bye) <= 0) { - return 0; - } - if (!_mdns_if_is_dup(tcpip_if)) { + if (answer->host == &_mdns_self_host) { + esp_netif_ip_info_t if_ip_info; + if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state != PCB_DUP) { + return 0; + } + if (esp_netif_get_ip_info(_mdns_get_esp_netif(tcpip_if), &if_ip_info)) { + return 0; + } + if (_mdns_append_a_record(packet, index, _mdns_server->hostname, if_ip_info.ip.addr, answer->flush, answer->bye) <= 0) { + return 0; + } + if (!_mdns_if_is_dup(tcpip_if)) { + return 1; + } + mdns_if_t other_if = _mdns_get_other_if (tcpip_if); + if (esp_netif_get_ip_info(_mdns_get_esp_netif(other_if), &if_ip_info)) { + return 1; + } + if (_mdns_append_a_record(packet, index, _mdns_server->hostname, if_ip_info.ip.addr, answer->flush, answer->bye) > 0) { + return 2; + } return 1; + } else if (answer->host != NULL) { + if (_mdns_append_a_record(packet, index, answer->host->hostname, answer->host->address.u_addr.ip4.addr, answer->flush, answer->bye) <= 0) { + return 0; + } else { + return 1; + } } - mdns_if_t other_if = _mdns_get_other_if (tcpip_if); - if (esp_netif_get_ip_info(_mdns_get_esp_netif(other_if), &if_ip_info)) { - return 1; - } - if (_mdns_append_a_record(packet, index, if_ip_info.ip.addr, answer->flush, answer->bye) > 0) { - return 2; - } - return 1; } #if CONFIG_LWIP_IPV6 else if (answer->type == MDNS_TYPE_AAAA) { - struct esp_ip6_addr if_ip6; - if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].state != PCB_DUP) { - return 0; - } - if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(tcpip_if), &if_ip6)) { - return 0; - } - if (_ipv6_address_is_zero(if_ip6)) { - return 0; - } - if (_mdns_append_aaaa_record(packet, index, (uint8_t*)if_ip6.addr, answer->flush, answer->bye) <= 0) { - return 0; - } - if (!_mdns_if_is_dup(tcpip_if)) { + if (answer->host == &_mdns_self_host) { + struct esp_ip6_addr if_ip6; + if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].state != PCB_DUP) { + return 0; + } + if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(tcpip_if), &if_ip6)) { + return 0; + } + if (_ipv6_address_is_zero(if_ip6)) { + return 0; + } + if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t*)if_ip6.addr, answer->flush, answer->bye) <= 0) { + return 0; + } + if (!_mdns_if_is_dup(tcpip_if)) { + return 1; + } + mdns_if_t other_if = _mdns_get_other_if (tcpip_if); + if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(other_if), &if_ip6)) { + return 1; + } + if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t*)if_ip6.addr, answer->flush, answer->bye) > 0) { + return 2; + } return 1; + } else if (answer->host != NULL) { + if (_mdns_append_aaaa_record(packet, index, answer->host->hostname, (uint8_t*)answer->host->address.u_addr.ip6.addr, answer->flush, answer->bye) <= 0) { + return 0; + } else { + return 1; + } + } - mdns_if_t other_if = _mdns_get_other_if (tcpip_if); - if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(other_if), &if_ip6)) { - return 1; - } - if (_mdns_append_aaaa_record(packet, index, (uint8_t*)if_ip6.addr, answer->flush, answer->bye) > 0) { - return 2; - } - return 1; } #endif return 0; @@ -1232,11 +1278,11 @@ static void _mdns_dealloc_answer(mdns_out_answer_t ** destination, uint16_t type /** * @brief Allocate new answer and add it to answer list (destination) */ -static bool _mdns_alloc_answer(mdns_out_answer_t ** destination, uint16_t type, mdns_service_t * service, bool flush, bool bye) +static bool _mdns_alloc_answer(mdns_out_answer_t ** destination, uint16_t type, mdns_service_t * service, mdns_host_item_t *host, bool flush, bool bye) { mdns_out_answer_t * d = *destination; while (d) { - if (d->type == type && d->service == service) { + if (d->type == type && d->service == service && d->host == host) { return true; } d = d->next; @@ -1249,6 +1295,7 @@ static bool _mdns_alloc_answer(mdns_out_answer_t ** destination, uint16_t type, } a->type = type; a->service = service; + a->host = host; a->custom_service = NULL; a->bye = bye; a->flush = flush; @@ -1283,10 +1330,58 @@ static mdns_tx_packet_t * _mdns_alloc_packet_default(mdns_if_t tcpip_if, mdns_ip return packet; } +static bool _mdns_create_answer_from_service(mdns_tx_packet_t *packet, mdns_service_t *service, + mdns_parsed_question_t *question, bool shared, bool send_flush) +{ + mdns_host_item_t *host4 = mdns_get_host_item(service->hostname, ESP_IPADDR_TYPE_V4); + mdns_host_item_t *host6 = mdns_get_host_item(service->hostname, ESP_IPADDR_TYPE_V6); + if (question->type == MDNS_TYPE_PTR || question->type == MDNS_TYPE_ANY) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service, NULL, false, false) || + !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) || + !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false) || + !_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_A, service, host4, + send_flush, false) || + !_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_AAAA, service, host6, + send_flush, false)) { + return false; + } + } else if (question->type == MDNS_TYPE_SRV) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) || + !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_A, service, host4, send_flush, false) || + !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_AAAA, service, host6, send_flush, false)) { + return false; + } + } else if (question->type == MDNS_TYPE_TXT) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false)) { + return false; + } + } else if (question->type == MDNS_TYPE_SDPTR) { + shared = true; + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, service, NULL, false, false)) { + return false; + } + } + return true; +} + +static bool _mdns_create_answer_from_hostname(mdns_tx_packet_t *packet, const char *hostname, bool send_flush) +{ + mdns_host_item_t *host4; + mdns_host_item_t *host6; + host4 = mdns_get_host_item(hostname, ESP_IPADDR_TYPE_V4); + host6 = mdns_get_host_item(hostname, ESP_IPADDR_TYPE_V6); + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, host4, send_flush, false) || + !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, host6, send_flush, false)) { + return false; + } + return true; +} + /** * @brief Create answer packet to questions from parsed packet + * XXX: reply from here */ -static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed_packet) +static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_packet) { if (!parsed_packet->questions) { return; @@ -1294,7 +1389,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed bool send_flush = parsed_packet->src_port == MDNS_SERVICE_PORT; bool unicast = false; bool shared = false; - mdns_tx_packet_t * packet = _mdns_alloc_packet_default(parsed_packet->tcpip_if, parsed_packet->ip_protocol); + mdns_tx_packet_t *packet = _mdns_alloc_packet_default(parsed_packet->tcpip_if, parsed_packet->ip_protocol); if (!packet) { return; } @@ -1302,82 +1397,60 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed packet->distributed = parsed_packet->distributed; packet->id = parsed_packet->id; - mdns_parsed_question_t * q = parsed_packet->questions; + mdns_parsed_question_t *q = parsed_packet->questions; while (q) { - mdns_srv_item_t * service = NULL; + shared = q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_SDPTR || !parsed_packet->probe; if (q->service && q->proto) { - service = _mdns_get_service_item(q->service, q->proto); - if (!service) { - continue; + mdns_srv_item_t *service = _mdns_server->services; + while (service) { + if (_mdns_service_match(service->service, q->service, q->proto, q->host)) { + if (!_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) { + _mdns_free_tx_packet(packet); + return; + } + } + service = service->next; } - } - if (q->unicast) { - unicast = true; - } - if (service) { - if (q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_ANY) { - if (q->type == MDNS_TYPE_PTR || !parsed_packet->probe) { - shared = true; - } - if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service->service, false, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service->service, send_flush, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service->service, send_flush, false) - || !_mdns_alloc_answer(shared?&packet->additional:&packet->answers, MDNS_TYPE_A, NULL, send_flush, false) - || !_mdns_alloc_answer(shared?&packet->additional:&packet->answers, MDNS_TYPE_AAAA, NULL, send_flush, false)) { - _mdns_free_tx_packet(packet); - return; - } - } else if (q->type == MDNS_TYPE_SRV) { - if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service->service, send_flush, false) - || !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_A, NULL, send_flush, false) - || !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_AAAA, NULL, send_flush, false)) { - _mdns_free_tx_packet(packet); - return; - } - } else if (q->type == MDNS_TYPE_TXT) { - if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service->service, send_flush, false)) { - _mdns_free_tx_packet(packet); - return; - } - } else if (q->type == MDNS_TYPE_SDPTR) { - shared = true; - if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, service->service, false, false)) { - _mdns_free_tx_packet(packet); - return; - } - } - } else { - if (q->type == MDNS_TYPE_ANY || q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA) { - if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, send_flush, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, send_flush, false)) { - _mdns_free_tx_packet(packet); - return; - } -#ifdef MDNS_REPEAT_QUERY_IN_RESPONSE - mdns_out_question_t * out_question = malloc(sizeof(mdns_out_question_t)); - if (out_question == NULL) { - HOOK_MALLOC_FAILED; - _mdns_free_tx_packet(packet); - return; - } - out_question->type = q->type; - out_question->unicast = q->unicast; - out_question->host = q->host; - q->host = NULL; - out_question->service = q->service; - q->service = NULL; - out_question->proto = q->proto; - q->proto = NULL; - out_question->domain = q->domain; - q->domain = NULL; - out_question->next = NULL; - out_question->own_dynamic_memory = true; - queueToEnd(mdns_out_question_t, packet->questions, out_question); -#endif // MDNS_REPEAT_QUERY_IN_RESPONSE - } else if (!_mdns_alloc_answer(&packet->answers, q->type, NULL, send_flush, false)) { + } else if (q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA) { + if (!_mdns_create_answer_from_hostname(packet, q->host, send_flush)) { _mdns_free_tx_packet(packet); return; } + } else if (q->type == MDNS_TYPE_ANY) { + if (!_mdns_append_host_list(&packet->answers, send_flush, false)) { + _mdns_free_tx_packet(packet); + return; + } + } else if (!_mdns_alloc_answer(&packet->answers, q->type, NULL, NULL, send_flush, false)) { + _mdns_free_tx_packet(packet); + return; + } + +#ifdef MDNS_REPEAT_QUERY_IN_RESPONSE + if (q->type == MDNS_TYPE_ANY || q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA) { + mdns_out_question_t * out_question = malloc(sizeof(mdns_out_question_t)); + if (out_question == NULL) { + HOOK_MALLOC_FAILED; + _mdns_free_tx_packet(packet); + return; + } + out_question->type = q->type; + out_question->unicast = q->unicast; + out_question->host = q->host; + q->host = NULL; + out_question->service = q->service; + q->service = NULL; + out_question->proto = q->proto; + q->proto = NULL; + out_question->domain = q->domain; + q->domain = NULL; + out_question->next = NULL; + out_question->own_dynamic_memory = true; + queueToEnd(mdns_out_question_t, packet->questions, out_question); + } +#endif // MDNS_REPEAT_QUERY_IN_RESPONSE + if (q->unicast) { + unicast = true; } q = q->next; } @@ -1413,6 +1486,32 @@ static bool _mdns_question_exists(mdns_out_question_t * needle, mdns_out_questio return false; } +bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye) { + if (!_str_null_or_empty(_mdns_server->hostname)) { + mdns_host_item_t *self_host = mdns_get_host_item(_mdns_server->hostname, ESP_IPADDR_TYPE_ANY); + if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, self_host, flush, bye)) { + return false; + } + if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, self_host, flush, bye)) { + return false; + } + } + mdns_host_item_t *host = _mdns_host_list; + while(host != NULL) { + if (host->address.type == ESP_IPADDR_TYPE_V4) { + if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, host, flush, bye)) { + return false; + } + } else if (host->address.type == ESP_IPADDR_TYPE_V6) { + if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, host, flush, bye)) { + return false; + } + } + host = host->next; + } + return true; +} + /** * @brief Create probe packet for particular services on particular PCB */ @@ -1446,13 +1545,13 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_ queueToEnd(mdns_out_question_t, packet->questions, q); } - if (!q->host || !_mdns_alloc_answer(&packet->servers, MDNS_TYPE_SRV, services[i]->service, false, false)) { + if (!q->host || !_mdns_alloc_answer(&packet->servers, MDNS_TYPE_SRV, services[i]->service, NULL, false, false)) { _mdns_free_tx_packet(packet); return NULL; } } - if (include_ip && !_str_null_or_empty(_mdns_server->hostname)) { + if (include_ip) { mdns_out_question_t * q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t)); if (!q) { HOOK_MALLOC_FAILED; @@ -1473,18 +1572,9 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_ queueToEnd(mdns_out_question_t, packet->questions, q); } - if (_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb) { - if (!_mdns_alloc_answer(&packet->servers, MDNS_TYPE_A, NULL, false, false)) { - _mdns_free_tx_packet(packet); - return NULL; - } - } - - if (_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb) { - if (!_mdns_alloc_answer(&packet->servers, MDNS_TYPE_AAAA, NULL, false, false)) { - _mdns_free_tx_packet(packet); - return NULL; - } + if (!_mdns_append_host_list(&packet->servers, false, false)) { + _mdns_free_tx_packet(packet); + return NULL; } } @@ -1504,17 +1594,16 @@ static mdns_tx_packet_t * _mdns_create_announce_packet(mdns_if_t tcpip_if, mdns_ uint8_t i; for (i=0; ianswers, MDNS_TYPE_SDPTR, services[i]->service, false, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, false, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, services[i]->service, true, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, services[i]->service, true, false)) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, services[i]->service, NULL, false, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, NULL, false, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, services[i]->service, NULL, true, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, services[i]->service, NULL, true, false)) { _mdns_free_tx_packet(packet); return NULL; } } if (include_ip) { - if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, true, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, true, false)) { + if (!_mdns_append_host_list(&packet->servers, true, false)) { _mdns_free_tx_packet(packet); return NULL; } @@ -1537,16 +1626,16 @@ static mdns_tx_packet_t * _mdns_create_announce_from_probe(mdns_tx_packet_t * pr mdns_out_answer_t * s = probe->servers; while (s) { if (s->type == MDNS_TYPE_SRV) { - if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, s->service, false, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, s->service, false, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, s->service, true, false) - || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, s->service, true, false)) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, s->service, NULL, false, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, s->service, NULL, false, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, s->service, NULL, true, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, s->service, NULL, true, false)) { _mdns_free_tx_packet(packet); return NULL; } } else if (s->type == MDNS_TYPE_A || s->type == MDNS_TYPE_AAAA) { - if (!_mdns_alloc_answer(&packet->answers, s->type, NULL, true, false)) { + if (!_mdns_alloc_answer(&packet->answers, s->type, NULL, s->host, true, false)) { _mdns_free_tx_packet(packet); return NULL; } @@ -1569,14 +1658,13 @@ static void _mdns_pcb_send_bye(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco packet->flags = MDNS_FLAGS_AUTHORITATIVE; size_t i; for (i=0; ianswers, MDNS_TYPE_PTR, services[i]->service, true, true)) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, NULL, true, true)) { _mdns_free_tx_packet(packet); return; } } - if (include_ip && (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, true, true) || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, true, true))) { - _mdns_free_tx_packet(packet); - return; + if (include_ip) { + _mdns_append_host_list(&packet->answers, true, true); } _mdns_dispatch_tx_packet(packet); _mdns_free_tx_packet(packet); @@ -1732,18 +1820,17 @@ static void _mdns_announce_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco mdns_tx_packet_t * p = _mdns_get_next_pcb_packet(tcpip_if, ip_protocol); if (p) { for (i=0; ianswers, MDNS_TYPE_SDPTR, services[i]->service, false, false) - || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_PTR, services[i]->service, false, false) - || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_SRV, services[i]->service, true, false) - || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_TXT, services[i]->service, true, false)) { + if (!_mdns_alloc_answer(&p->answers, MDNS_TYPE_SDPTR, services[i]->service, NULL, false, false) + || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_PTR, services[i]->service, NULL, false, false) + || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_SRV, services[i]->service, NULL, true, false) + || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_TXT, services[i]->service, NULL, true, false)) { break; } } if (include_ip) { _mdns_dealloc_answer(&p->additional, MDNS_TYPE_A, NULL); _mdns_dealloc_answer(&p->additional, MDNS_TYPE_AAAA, NULL); - _mdns_alloc_answer(&p->answers, MDNS_TYPE_A, NULL, true, false); - _mdns_alloc_answer(&p->answers, MDNS_TYPE_AAAA, NULL, true, false); + _mdns_append_host_list(&p->answers, true, false); } _pcb->state = PCB_ANNOUNCE_1; } @@ -1961,7 +2048,7 @@ static void _mdns_free_linked_txt(mdns_txt_linked_item_t *txt) * * @return pointer to the service or NULL on error */ -static mdns_service_t * _mdns_create_service(const char * service, const char * proto, uint16_t port, const char * instance, size_t num_items, mdns_txt_item_t txt[]) +static mdns_service_t * _mdns_create_service(const char * service, const char * proto, const char *hostname, uint16_t port, const char * instance, size_t num_items, mdns_txt_item_t txt[]) { mdns_service_t * s = (mdns_service_t *)malloc(sizeof(mdns_service_t)); if (!s) { @@ -1981,6 +2068,17 @@ static mdns_service_t * _mdns_create_service(const char * service, const char * s->txt = new_txt; s->port = port; + assert(hostname != NULL); + if (hostname) { + s->hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); + if (!s->hostname) { + free(s); + return NULL; + } + } else { + s->hostname = NULL; + } + s->service = strndup(service, MDNS_NAME_BUF_LEN - 1); if (!s->service) { free(s); @@ -2341,6 +2439,39 @@ static int _mdns_check_aaaa_collision(esp_ip6_addr_t * ip, mdns_if_t tcpip_if) } #endif +static bool _hostname_is_ours(const char *hostname) +{ + if (strcasecmp(hostname, _mdns_server->hostname) == 0) { + return true; + } + mdns_host_item_t *host = _mdns_host_list; + while (host != NULL) { + if (strcasecmp(hostname, host->hostname) == 0) { + return true; + } + host = host->next; + } + return false; +} + +static bool _mdns_delegate_hostname_add(const char *hostname, const esp_ip_addr_t *address) +{ + if (_hostname_is_ours(hostname)) { + return true; + } + + mdns_host_item_t *host = (mdns_host_item_t *)malloc(sizeof(mdns_host_item_t)); + + if (host == NULL) { + return false; + } + host->address = *address; + host->hostname = hostname; + host->next = _mdns_host_list; + _mdns_host_list = host; + return true; +} + /** * @brief Check if parsed name is discovery */ @@ -2369,7 +2500,7 @@ static bool _mdns_name_is_ours(mdns_name_t * name) if (_str_null_or_empty(name->service) && _str_null_or_empty(name->proto)) { if (!_str_null_or_empty(name->host) && !_str_null_or_empty(_mdns_server->hostname) - && strcasecmp(name->host, _mdns_server->hostname) == 0) + && _hostname_is_ours(name->host) == 0) { return true; } @@ -2382,7 +2513,7 @@ static bool _mdns_name_is_ours(mdns_name_t * name) } //find the service - mdns_srv_item_t * service = _mdns_get_service_item(name->service, name->proto); + mdns_srv_item_t * service = _mdns_get_service_item(name->service, name->proto, name->host); if (!service) { return false; } @@ -2860,7 +2991,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) } else if (!name->sub && _mdns_name_is_ours(name)) { ours = true; if (name->service && name->service[0] && name->proto && name->proto[0]) { - service = _mdns_get_service_item(name->service, name->proto); + service = _mdns_get_service_item(name->service, name->proto, name->host); } } else { if (!parsed_packet->authoritative || record_type == MDNS_NS) { @@ -2878,7 +3009,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) _mdns_search_result_add_ptr(search_result, name->host, packet->tcpip_if, packet->ip_protocol); } else if ((discovery || ours) && !name->sub && _mdns_name_is_ours(name)) { if (discovery) { - service = _mdns_get_service_item(name->service, name->proto); + service = _mdns_get_service_item(name->service, name->proto, name->host); _mdns_remove_parsed_question(parsed_packet, MDNS_TYPE_SDPTR, service); } else if (parsed_packet->questions && !parsed_packet->probe) { _mdns_remove_parsed_question(parsed_packet, type, service); @@ -3831,7 +3962,7 @@ static void _mdns_free_action(mdns_action_t * action) { switch(action->type) { case ACTION_HOSTNAME_SET: - free(action->data.hostname); + free(action->data.hostname_set.hostname); break; case ACTION_INSTANCE_SET: free(action->data.instance); @@ -3892,9 +4023,10 @@ static void _mdns_execute_action(mdns_action_t * action) case ACTION_HOSTNAME_SET: _mdns_send_bye_all_pcbs_no_instance(true); free((char*)_mdns_server->hostname); - _mdns_server->hostname = action->data.hostname; + _mdns_server->hostname = action->data.hostname_set.hostname; + _mdns_self_host.hostname = action->data.hostname_set.hostname; _mdns_restart_all_pcbs(); - + xTaskNotifyGive(action->data.hostname_set.calling_task); break; case ACTION_INSTANCE_SET: _mdns_send_bye_all_pcbs_no_instance(false); @@ -3907,7 +4039,6 @@ static void _mdns_execute_action(mdns_action_t * action) action->data.srv_add.service->next = _mdns_server->services; _mdns_server->services = action->data.srv_add.service; _mdns_probe_all_pcbs(&action->data.srv_add.service, 1, false, false); - break; case ACTION_SERVICE_INSTANCE_SET: if (action->data.srv_instance.service->service->instance) { @@ -4058,6 +4189,8 @@ static void _mdns_execute_action(mdns_action_t * action) pbuf_free(action->data.rx_handle.packet->pb); free(action->data.rx_handle.packet); break; + case ACTION_DELEGATE_HOSTNAME_ADD: + _mdns_delegate_hostname_add(action->data.delegate_hostname.hostname, &action->data.delegate_hostname.address); default: break; } @@ -4461,7 +4594,40 @@ esp_err_t mdns_hostname_set(const char * hostname) return ESP_ERR_NO_MEM; } action->type = ACTION_HOSTNAME_SET; - action->data.hostname = new_hostname; + action->data.hostname_set.hostname = new_hostname; + action->data.hostname_set.calling_task = xTaskGetCurrentTaskHandle(); + if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) { + assert(false); + free(new_hostname); + free(action); + return ESP_ERR_NO_MEM; + } + xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); + return ERR_OK; +} + +esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t *address) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_ARG; + } + if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) { + return ESP_ERR_INVALID_ARG; + } + char * new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); + if (!new_hostname) { + return ESP_ERR_NO_MEM; + } + + mdns_action_t * action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + free(new_hostname); + return ESP_ERR_NO_MEM; + } + action->type = ACTION_DELEGATE_HOSTNAME_ADD; + action->data.delegate_hostname.hostname = new_hostname; + action->data.delegate_hostname.address = *address; if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) { free(new_hostname); free(action); @@ -4470,6 +4636,10 @@ esp_err_t mdns_hostname_set(const char * hostname) return ERR_OK; } +bool mdns_hostname_exists(const char *hostname) { + return _hostname_is_ours(hostname); +} + esp_err_t mdns_instance_name_set(const char * instance) { if (!_mdns_server) { @@ -4503,7 +4673,9 @@ esp_err_t mdns_instance_name_set(const char * instance) * MDNS SERVICES * */ -esp_err_t mdns_service_add(const char * instance, const char * service, const char * proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items) +esp_err_t mdns_service_add_custom_host(const char *instance, const char *service, const char *proto, + const char *hostname, uint16_t port, + mdns_txt_item_t txt[], size_t num_items) { if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) { return ESP_ERR_INVALID_ARG; @@ -4513,12 +4685,12 @@ esp_err_t mdns_service_add(const char * instance, const char * service, const ch return ESP_ERR_NO_MEM; } - mdns_srv_item_t * item = _mdns_get_service_item(service, proto); + mdns_srv_item_t * item = _mdns_get_service_item(service, proto, hostname); if (item) { return ESP_ERR_INVALID_ARG; } - mdns_service_t * s = _mdns_create_service(service, proto, port, instance, num_items, txt); + mdns_service_t * s = _mdns_create_service(service, proto, hostname, port, instance, num_items, txt); if (!s) { return ESP_ERR_NO_MEM; } @@ -4551,7 +4723,7 @@ esp_err_t mdns_service_add(const char * instance, const char * service, const ch size_t start = xTaskGetTickCount(); size_t timeout_ticks = pdMS_TO_TICKS(MDNS_SERVICE_ADD_TIMEOUT_MS); - while (_mdns_get_service_item(service, proto) == NULL) + while (_mdns_get_service_item(service, proto, hostname) == NULL) { uint32_t expired = xTaskGetTickCount() - start; if (expired >= timeout_ticks) { @@ -4563,12 +4735,24 @@ esp_err_t mdns_service_add(const char * instance, const char * service, const ch return ESP_OK; } -esp_err_t mdns_service_port_set(const char * service, const char * proto, uint16_t port) +esp_err_t mdns_service_add(const char *instance, const char *service, const char *proto, uint16_t port, + mdns_txt_item_t txt[], size_t num_items) +{ + assert(_mdns_server->hostname != NULL); + return mdns_service_add_custom_host(instance, service, proto, _mdns_server->hostname, port, txt, num_items); +} + +bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname) +{ + return _mdns_get_service_item(service_type, proto, hostname) != NULL; +} + +esp_err_t mdns_service_port_set_for_host(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) { return ESP_ERR_INVALID_ARG; } - mdns_srv_item_t * s = _mdns_get_service_item(service, proto); + mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname); if (!s) { return ESP_ERR_NOT_FOUND; } @@ -4588,12 +4772,17 @@ esp_err_t mdns_service_port_set(const char * service, const char * proto, uint16 return ESP_OK; } -esp_err_t mdns_service_txt_set(const char * service, const char * proto, mdns_txt_item_t txt[], uint8_t num_items) +esp_err_t mdns_service_port_set(const char *service, const char *proto, uint16_t port) { + return mdns_service_port_set_for_host(service, proto, _mdns_server->hostname, port); +} + +esp_err_t mdns_service_txt_set_for_host(const char *service, const char *proto, const char *hostname, + mdns_txt_item_t txt[], uint8_t num_items) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || (num_items && txt == NULL)) { return ESP_ERR_INVALID_ARG; } - mdns_srv_item_t * s = _mdns_get_service_item(service, proto); + mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname); if (!s) { return ESP_ERR_NOT_FOUND; } @@ -4624,13 +4813,17 @@ esp_err_t mdns_service_txt_set(const char * service, const char * proto, mdns_tx return ESP_OK; } +esp_err_t mdns_service_txt_set(const char *service, const char *proto, mdns_txt_item_t txt[], uint8_t num_items) +{ + return mdns_service_txt_set_for_host(service, proto, _mdns_server->hostname, txt, num_items); +} -esp_err_t mdns_service_txt_item_set(const char * service, const char * proto, const char * key, const char * value) +esp_err_t mdns_service_txt_item_set_for_host(const char * service, const char * proto, const char *hostname, const char * key, const char * value) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key) || !value) { return ESP_ERR_INVALID_ARG; } - mdns_srv_item_t * s = _mdns_get_service_item(service, proto); + mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname); if (!s) { return ESP_ERR_NOT_FOUND; } @@ -4662,12 +4855,17 @@ esp_err_t mdns_service_txt_item_set(const char * service, const char * proto, co return ESP_OK; } -esp_err_t mdns_service_txt_item_remove(const char * service, const char * proto, const char * key) +esp_err_t mdns_service_txt_item_set(const char *service, const char *proto, const char *key, const char *value) +{ + return mdns_service_txt_item_set_for_host(service, proto, _mdns_server->hostname, key, value); +} + +esp_err_t mdns_service_txt_item_remove_for_host(const char * service, const char * proto, const char *hostname, const char * key) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key)) { return ESP_ERR_INVALID_ARG; } - mdns_srv_item_t * s = _mdns_get_service_item(service, proto); + mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname); if (!s) { return ESP_ERR_NOT_FOUND; } @@ -4692,7 +4890,13 @@ esp_err_t mdns_service_txt_item_remove(const char * service, const char * proto, return ESP_OK; } -esp_err_t mdns_service_instance_name_set(const char * service, const char * proto, const char * instance) +esp_err_t mdns_service_txt_item_remove(const char *service, const char *proto, const char *key) +{ + return mdns_service_txt_item_remove_for_host(service, proto, _mdns_server->hostname, key); +} + +esp_err_t mdns_service_instance_name_set_for_host(const char *service, const char *proto, const char *hostname, + const char *instance) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) { return ESP_ERR_INVALID_ARG; @@ -4700,7 +4904,7 @@ esp_err_t mdns_service_instance_name_set(const char * service, const char * prot if (_str_null_or_empty(instance) || strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) { return ESP_ERR_INVALID_ARG; } - mdns_srv_item_t * s = _mdns_get_service_item(service, proto); + mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname); if (!s) { return ESP_ERR_NOT_FOUND; } @@ -4726,12 +4930,17 @@ esp_err_t mdns_service_instance_name_set(const char * service, const char * prot return ESP_OK; } -esp_err_t mdns_service_remove(const char * service, const char * proto) +esp_err_t mdns_service_instance_name_set(const char *service, const char *proto, const char *instance) +{ + return mdns_service_instance_name_set_for_host(service, proto, _mdns_server->hostname, instance); +} + +esp_err_t mdns_service_remove_for_host(const char * service, const char * proto, const char *hostname) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) { return ESP_ERR_INVALID_ARG; } - mdns_srv_item_t * s = _mdns_get_service_item(service, proto); + mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname); if (!s) { return ESP_ERR_NOT_FOUND; } @@ -4750,6 +4959,11 @@ esp_err_t mdns_service_remove(const char * service, const char * proto) return ESP_OK; } +esp_err_t mdns_service_remove(const char *service_type, const char *proto) +{ + return mdns_service_remove_for_host(service_type, proto, _mdns_server->hostname); +} + esp_err_t mdns_service_remove_all(void) { if (!_mdns_server) { diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index d8d507413f..b813c5b439 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -17,8 +17,10 @@ #include "esp_event_base.h" #include "esp_task.h" #include "esp_timer.h" +#include "esp_netif_ip_addr.h" +#include "freertos/FreeRTOS.h" -//#define MDNS_ENABLE_DEBUG +#define MDNS_ENABLE_DEBUG #ifdef MDNS_ENABLE_DEBUG #define _mdns_dbg_printf(...) printf(__VA_ARGS__) @@ -182,6 +184,7 @@ typedef enum { ACTION_TX_HANDLE, ACTION_RX_HANDLE, ACTION_TASK_STOP, + ACTION_DELEGATE_HOSTNAME_ADD, ACTION_MAX } mdns_action_type_t; @@ -280,6 +283,7 @@ typedef struct { const char * instance; const char * service; const char * proto; + const char * hostname; uint16_t priority; uint16_t weight; uint16_t port; @@ -302,12 +306,19 @@ typedef struct mdns_out_question_s { bool own_dynamic_memory; } mdns_out_question_t; +typedef struct mdns_host_item_t { + const char * hostname; + esp_ip_addr_t address; + struct mdns_host_item_t *next; +} mdns_host_item_t; + typedef struct mdns_out_answer_s { struct mdns_out_answer_s * next; uint16_t type; uint8_t bye; uint8_t flush; mdns_service_t * service; + mdns_host_item_t* host; const char * custom_instance; const char * custom_service; const char * custom_proto; @@ -381,7 +392,10 @@ typedef struct mdns_server_s { typedef struct { mdns_action_type_t type; union { - char * hostname; + struct { + char * hostname; + xTaskHandle calling_task; + } hostname_set; char * instance; struct { esp_event_base_t event_base; @@ -424,6 +438,10 @@ typedef struct { struct { mdns_rx_packet_t * packet; } rx_handle; + struct { + const char * hostname; + esp_ip_addr_t address; + } delegate_hostname; } data; } mdns_action_t; diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index 8f655fdad0..fcad5eaa7d 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -24,34 +24,47 @@ #define EXAMPLE_BUTTON_GPIO 0 static const char *TAG = "mdns-test"; -static char* generate_hostname(void); +static char *generate_hostname(void); #if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1 -static void query_mdns_host_with_gethostbyname(char * host); -static void query_mdns_host_with_getaddrinfo(char * host); +static void query_mdns_host_with_gethostbyname(char *host); +static void query_mdns_host_with_getaddrinfo(char *host); #endif static void initialise_mdns(void) { - char* hostname = generate_hostname(); + printf("generate_hostname\n"); + char *hostname = generate_hostname(); //initialize mDNS + printf("mdns_init\n"); ESP_ERROR_CHECK( mdns_init() ); + printf("mdns_hostname_set\n"); //set mDNS hostname (required if you want to advertise services) ESP_ERROR_CHECK( mdns_hostname_set(hostname) ); ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname); //set default mDNS instance name + printf("mdns_instance_name_set\n"); ESP_ERROR_CHECK( mdns_instance_name_set(EXAMPLE_MDNS_INSTANCE) ); //structure with TXT records mdns_txt_item_t serviceTxtData[3] = { - {"board","esp32"}, - {"u","user"}, - {"p","password"} + {"board", "esp32"}, + {"u", "user"}, + {"p", "password"} }; //initialize service + printf("mdns_service_add\n"); ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3) ); + esp_ip_addr_t addr; + ip6_addr_t ip6_addr; + ip6addr_aton("fe80::849b:bb01:415c:b722", &ip6_addr); + addr.type = ESP_IPADDR_TYPE_V6; + memcpy(addr.u_addr.ip6.addr, ip6_addr.addr, sizeof(ip6_addr.addr)); + ESP_ERROR_CHECK(mdns_delegate_hostname_add("test-device", &addr)); + ESP_ERROR_CHECK( mdns_service_add_custom_host("test0", "_http", "_tcp", "test-device", 1234, serviceTxtData, 3) ); //add another TXT item + printf("mdns_service_txt_item_set\n"); ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "path", "/foobar") ); //change TXT item value ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "u", "admin") ); @@ -59,33 +72,34 @@ static void initialise_mdns(void) } /* these strings match tcpip_adapter_if_t enumeration */ -static const char * if_str[] = {"STA", "AP", "ETH", "MAX"}; +static const char *if_str[] = {"STA", "AP", "ETH", "MAX"}; /* these strings match mdns_ip_protocol_t enumeration */ -static const char * ip_protocol_str[] = {"V4", "V6", "MAX"}; +static const char *ip_protocol_str[] = {"V4", "V6", "MAX"}; -static void mdns_print_results(mdns_result_t * results){ - mdns_result_t * r = results; - mdns_ip_addr_t * a = NULL; +static void mdns_print_results(mdns_result_t *results) +{ + mdns_result_t *r = results; + mdns_ip_addr_t *a = NULL; int i = 1, t; - while(r){ + while (r) { printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]); - if(r->instance_name){ + if (r->instance_name) { printf(" PTR : %s\n", r->instance_name); } - if(r->hostname){ + if (r->hostname) { printf(" SRV : %s.local:%u\n", r->hostname, r->port); } - if(r->txt_count){ + if (r->txt_count) { printf(" TXT : [%u] ", r->txt_count); - for(t=0; ttxt_count; t++){ - printf("%s=%s; ", r->txt[t].key, r->txt[t].value?r->txt[t].value:"NULL"); + for (t = 0; t < r->txt_count; t++) { + printf("%s=%s; ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL"); } printf("\n"); } a = r->addr; - while(a){ - if(a->addr.type == ESP_IPADDR_TYPE_V6){ + while (a) { + if (a->addr.type == ESP_IPADDR_TYPE_V6) { printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); } else { printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); @@ -97,17 +111,17 @@ static void mdns_print_results(mdns_result_t * results){ } -static void query_mdns_service(const char * service_name, const char * proto) +static void query_mdns_service(const char *service_name, const char *proto) { ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto); - mdns_result_t * results = NULL; + mdns_result_t *results = NULL; esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results); - if(err){ + if (err) { ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); return; } - if(!results){ + if (!results) { ESP_LOGW(TAG, "No results found!"); return; } @@ -116,7 +130,7 @@ static void query_mdns_service(const char * service_name, const char * proto) mdns_query_results_free(results); } -static void query_mdns_host(const char * host_name) +static void query_mdns_host(const char *host_name) { ESP_LOGI(TAG, "Query A: %s.local", host_name); @@ -124,8 +138,8 @@ static void query_mdns_host(const char * host_name) addr.addr = 0; esp_err_t err = mdns_query_a(host_name, 2000, &addr); - if(err){ - if(err == ESP_ERR_NOT_FOUND){ + if (err) { + if (err == ESP_ERR_NOT_FOUND) { ESP_LOGW(TAG, "%s: Host was not found!", esp_err_to_name(err)); return; } @@ -174,7 +188,7 @@ static void mdns_example_task(void *pvParameters) query_mdns_host_with_getaddrinfo("tinytester-lwip.local"); #endif - while(1) { + while (1) { check_button(); vTaskDelay(50 / portTICK_PERIOD_MS); } @@ -201,7 +215,7 @@ void app_main(void) /** Generate host name based on sdkconfig, optionally adding a portion of MAC address to it. * @return host name string allocated from the heap */ -static char* generate_hostname(void) +static char *generate_hostname(void) { #ifndef CONFIG_MDNS_ADD_MAC_TO_HOSTNAME return strdup(CONFIG_MDNS_HOSTNAME); @@ -221,7 +235,7 @@ static char* generate_hostname(void) * @brief Executes gethostbyname and displays list of resolved addresses. * Note: This function is used only to test advertised mdns hostnames resolution */ -static void query_mdns_host_with_gethostbyname(char * host) +static void query_mdns_host_with_gethostbyname(char *host) { struct hostent *res = gethostbyname(host); if (res) { @@ -237,10 +251,10 @@ static void query_mdns_host_with_gethostbyname(char * host) * @brief Executes getaddrinfo and displays list of resolved addresses. * Note: This function is used only to test advertised mdns hostnames resolution */ -static void query_mdns_host_with_getaddrinfo(char * host) +static void query_mdns_host_with_getaddrinfo(char *host) { struct addrinfo hints; - struct addrinfo * res; + struct addrinfo *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; @@ -249,8 +263,8 @@ static void query_mdns_host_with_getaddrinfo(char * host) if (!getaddrinfo(host, NULL, &hints, &res)) { while (res) { ESP_LOGI(TAG, "getaddrinfo: %s resolved to: %s", host, - res->ai_family == AF_INET? - inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr): + res->ai_family == AF_INET ? + inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr) : inet_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr)); res = res->ai_next; } From 2174693096b73ce93261611c44ecba647cd01859 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Fri, 2 Apr 2021 18:06:10 +0800 Subject: [PATCH 3/9] mdns: add remove delegate host api --- components/mdns/include/mdns.h | 2 + components/mdns/mdns.c | 76 +++++++++++++++++++ .../mdns/private_include/mdns_private.h | 1 + .../protocols/mdns/main/mdns_example_main.c | 6 ++ 4 files changed, 85 insertions(+) diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index dcf8972bdd..54cd8a3ee1 100644 --- a/components/mdns/include/mdns.h +++ b/components/mdns/include/mdns.h @@ -116,6 +116,8 @@ esp_err_t mdns_hostname_set(const char * hostname); esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t *address); +esp_err_t mdns_delegate_hostname_remove(const char * hostname); + bool mdns_hostname_exists(const char *hostname); /** diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 2a715fe304..35aa4e09c6 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -2472,6 +2472,48 @@ static bool _mdns_delegate_hostname_add(const char *hostname, const esp_ip_addr_ return true; } +static bool _mdns_delegate_hostname_remove(const char *hostname) +{ + mdns_srv_item_t *srv = _mdns_server->services; + mdns_srv_item_t *prev_srv = NULL; + while (srv) { + if (strcasecmp(srv->service->hostname, hostname) == 0) { + mdns_srv_item_t *to_free = srv; + _mdns_send_bye(&srv, 1, false); + _mdns_remove_scheduled_service_packets(srv->service); + if (prev_srv == NULL) { + _mdns_server->services = srv->next; + srv = srv->next; + } else { + prev_srv->next = srv->next; + } + _mdns_free_service(to_free->service); + free(to_free); + } else { + prev_srv = srv; + srv = srv->next; + } + } + mdns_host_item_t *host = _mdns_host_list; + mdns_host_item_t *prev_host = NULL; + while (host != NULL) { + if (strcasecmp(hostname, host->hostname) == 0) { + if (prev_host == NULL) { + _mdns_host_list = host->next; + } else { + prev_host->next = host->next; + } + free((char *)host->hostname); + free(host); + break; + } else { + prev_host = host; + host = host->next; + } + } + return true; +} + /** * @brief Check if parsed name is discovery */ @@ -4191,6 +4233,11 @@ static void _mdns_execute_action(mdns_action_t * action) break; case ACTION_DELEGATE_HOSTNAME_ADD: _mdns_delegate_hostname_add(action->data.delegate_hostname.hostname, &action->data.delegate_hostname.address); + break; + case ACTION_DELEGATE_HOSTNAME_REMOVE: + _mdns_delegate_hostname_remove(action->data.delegate_hostname.hostname); + free((char *)action->data.delegate_hostname.hostname); + break; default: break; } @@ -4636,6 +4683,35 @@ esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t return ERR_OK; } +esp_err_t mdns_delegate_hostname_remove(const char * hostname) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_ARG; + } + if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) { + return ESP_ERR_INVALID_ARG; + } + char * new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); + if (!new_hostname) { + return ESP_ERR_NO_MEM; + } + + mdns_action_t * action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + free(new_hostname); + return ESP_ERR_NO_MEM; + } + action->type = ACTION_DELEGATE_HOSTNAME_REMOVE; + action->data.delegate_hostname.hostname = new_hostname; + if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) { + free(new_hostname); + free(action); + return ESP_ERR_NO_MEM; + } + return ERR_OK; +} + bool mdns_hostname_exists(const char *hostname) { return _hostname_is_ours(hostname); } diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index b813c5b439..6acdf92833 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -185,6 +185,7 @@ typedef enum { ACTION_RX_HANDLE, ACTION_TASK_STOP, ACTION_DELEGATE_HOSTNAME_ADD, + ACTION_DELEGATE_HOSTNAME_REMOVE, ACTION_MAX } mdns_action_type_t; diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index fcad5eaa7d..525193d20d 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -187,10 +187,16 @@ static void mdns_example_task(void *pvParameters) query_mdns_host_with_gethostbyname("tinytester-lwip.local"); query_mdns_host_with_getaddrinfo("tinytester-lwip.local"); #endif + bool removed = false; while (1) { check_button(); vTaskDelay(50 / portTICK_PERIOD_MS); + if (pdTICKS_TO_MS(xTaskGetTickCount()) >= 15 * 1000 && ! removed) { + printf("Remove device\n"); + ESP_ERROR_CHECK(mdns_delegate_hostname_remove("test-device")); + removed = true; + } } } From 2d34352f3db0fa71366a838933a29138a90eb2af Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Wed, 7 Apr 2021 16:21:16 +0800 Subject: [PATCH 4/9] mdns: make delegate host address a list Also adds unit test and doc string for new apis. --- components/mdns/include/mdns.h | 177 +++++++++++- components/mdns/mdns.c | 263 +++++++++++------- .../mdns/private_include/mdns_private.h | 7 +- components/mdns/test/test_mdns.c | 15 + .../mdns/test_afl_fuzz_host/esp32_compat.h | 1 + .../mdns/test_afl_fuzz_host/esp32_mock.c | 15 + .../mdns/test_afl_fuzz_host/esp32_mock.h | 5 + components/mdns/test_afl_fuzz_host/mdns_di.h | 6 +- .../protocols/mdns/main/mdns_example_main.c | 87 +++--- 9 files changed, 419 insertions(+), 157 deletions(-) diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index 54cd8a3ee1..416740d137 100644 --- a/components/mdns/include/mdns.h +++ b/components/mdns/include/mdns.h @@ -114,11 +114,49 @@ void mdns_free(void); */ esp_err_t mdns_hostname_set(const char * hostname); -esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t *address); +/** + * @brief Adds a hostname and address to be delegated + * A/AAAA queries will be replied for the hostname and + * services can be added to this host. + * + * @param hostname Hostname to add + * @param address_list The IP address list of the host + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + * + */ +esp_err_t mdns_delegate_hostname_add(const char * hostname, const mdns_ip_addr_t *address_list); +/** + * @brief Remove a delegated hostname + * All the services added to this host will also be removed. + * + * @param hostname Hostname to remove + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + * + */ esp_err_t mdns_delegate_hostname_remove(const char * hostname); -bool mdns_hostname_exists(const char *hostname); +/** + * @brief Query whether a hostname has been added + * + * @param hostname Hostname to query + * + * @return + * - true The hostname has been added. + * - false The hostname has not been added. + * + */ +bool mdns_hostname_exists(const char * hostname); /** * @brief Set the default instance name for mDNS server @@ -152,10 +190,39 @@ esp_err_t mdns_instance_name_set(const char * instance_name); esp_err_t mdns_service_add(const char * instance_name, const char * service_type, const char * proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items); -esp_err_t mdns_service_add_custom_host(const char *instance_name, const char *service_type, const char *proto, - const char *hostname, uint16_t port, mdns_txt_item_t txt[], size_t num_items); +/** + * @brief Add service to mDNS server with a delegated hostname + * + * @param instance_name instance name to set. If NULL, + * global instance name or hostname will be used + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param port service port + * @param txt string array of TXT data (eg. {{"var","val"},{"other","2"}}) + * @param num_items number of items in TXT data + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + * - ESP_FAIL failed to add service + */ +esp_err_t mdns_service_add_for_host(const char * instance_name, const char * service_type, const char * proto, + const char * hostname, uint16_t port, mdns_txt_item_t txt[], size_t num_items); -bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname); +/** + * @brief Check whether a service has been added. + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, checks for the local hostname. + * + * @return + * - true Correspondding service has been added. + * - false Service not found. + */ +bool mdns_service_exists(const char * service_type, const char * proto, const char * hostname); /** * @brief Remove service from mDNS server @@ -171,6 +238,19 @@ bool mdns_service_exists(const char *service_type, const char *proto, const char */ esp_err_t mdns_service_remove(const char * service_type, const char * proto); +/** + * @brief Remove service from mDNS server with hostname + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ esp_err_t mdns_service_remove_for_host(const char * service_type, const char * proto, const char *hostname); /** @@ -188,7 +268,22 @@ esp_err_t mdns_service_remove_for_host(const char * service_type, const char * p */ esp_err_t mdns_service_instance_name_set(const char * service_type, const char * proto, const char * instance_name); -esp_err_t mdns_service_instance_name_set_for_host(const char * service_type, const char * proto, const char *hostname, const char * instance_name); +/** + * @brief Set instance name for service with hostname + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param instance_name instance name to set + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_instance_name_set_for_host(const char * service_type, const char * proto, const char * hostname, + const char * instance_name); /** * @brief Set service port @@ -206,7 +301,21 @@ esp_err_t mdns_service_instance_name_set_for_host(const char * service_type, con esp_err_t mdns_service_port_set(const char * service_type, const char * proto, uint16_t port); -esp_err_t mdns_service_port_set_for_host(const char *service_type, const char *proto, const char *hostname, +/** + * @brief Set service port with hostname + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param port service port + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_port_set_for_host(const char * service_type, const char * proto, const char * hostname, uint16_t port); /** @@ -225,7 +334,22 @@ esp_err_t mdns_service_port_set_for_host(const char *service_type, const char *p */ esp_err_t mdns_service_txt_set(const char * service_type, const char * proto, mdns_txt_item_t txt[], uint8_t num_items); -esp_err_t mdns_service_txt_set_for_host(const char *service_type, const char *proto, const char *hostname, +/** + * @brief Replace all TXT items for service with hostname + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param txt array of TXT data (eg. {{"var","val"},{"other","2"}}) + * @param num_items number of items in TXT data + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_set_for_host(const char * service_type, const char * proto, const char * hostname, mdns_txt_item_t txt[], uint8_t num_items); /** @@ -245,8 +369,23 @@ esp_err_t mdns_service_txt_set_for_host(const char *service_type, const char *pr esp_err_t mdns_service_txt_item_set(const char * service_type, const char * proto, const char * key, const char * value); -esp_err_t mdns_service_txt_item_set_for_host(const char *service_type, const char *proto, const char *hostname, - const char *key, const char *value); +/** + * @brief Set/Add TXT item for service TXT record with hostname + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param key the key that you want to add/update + * @param value the new value of the key + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_item_set_for_host(const char * service_type, const char * proto, const char * hostname, + const char * key, const char * value); /** * @brief Remove TXT item for service TXT record @@ -263,8 +402,22 @@ esp_err_t mdns_service_txt_item_set_for_host(const char *service_type, const cha */ esp_err_t mdns_service_txt_item_remove(const char * service_type, const char * proto, const char * key); -esp_err_t mdns_service_txt_item_remove_for_host(const char *service_type, const char *proto, const char *hostname, - const char *key); +/** + * @brief Remove TXT item for service TXT record with hostname + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param key the key that you want to remove + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_item_remove_for_host(const char * service_type, const char * proto, const char * hostname, + const char * key); /** * @brief Remove and free all services from mDNS server diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 35aa4e09c6..e72dce5ae8 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -31,7 +31,7 @@ static const char * MDNS_DEFAULT_DOMAIN = "local"; static const char * MDNS_SUB_STR = "_sub"; mdns_server_t * _mdns_server = NULL; -static mdns_host_item_t *_mdns_host_list = NULL; +static mdns_host_item_t * _mdns_host_list = NULL; static mdns_host_item_t _mdns_self_host; static const char *TAG = "MDNS"; @@ -146,7 +146,8 @@ static char * _mdns_mangle_name(char* in) { return ret; } -static bool _mdns_service_match(const mdns_service_t *srv, const char *service, const char *proto, const char *hostname) +static bool _mdns_service_match(const mdns_service_t * srv, const char * service, const char * proto, + const char * hostname) { return !strcasecmp(srv->service, service) && !strcasecmp(srv->proto, proto) && (_str_null_or_empty(hostname) || !strcasecmp(srv->hostname, hostname)); @@ -160,7 +161,7 @@ static bool _mdns_service_match(const mdns_service_t *srv, const char *service, * * @return the service item if found or NULL on error */ -static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char * proto, const char *hostname) +static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char * proto, const char * hostname) { mdns_srv_item_t * s = _mdns_server->services; while (s) { @@ -172,14 +173,14 @@ static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char return NULL; } -static mdns_host_item_t *mdns_get_host_item(const char *hostname, uint8_t address_type) +static mdns_host_item_t * mdns_get_host_item(const char * hostname) { if (hostname == NULL || strcasecmp(hostname, _mdns_server->hostname) == 0) { return &_mdns_self_host; } - mdns_host_item_t *host = _mdns_host_list; + mdns_host_item_t * host = _mdns_host_list; while (host != NULL) { - if (strcasecmp(host->hostname, hostname) == 0 && host->address.type == address_type) { + if (strcasecmp(host->hostname, hostname) == 0) { return host; } host = host->next; @@ -754,7 +755,7 @@ static uint16_t _mdns_append_srv_record(uint8_t * packet, uint16_t * index, mdns * * @param packet MDNS packet * @param index offset in the packet - * @param server the server + * @param hostname the hostname address to add * @param ip the IP address to add * * @return length of added data: 0 on error or length on success @@ -805,7 +806,7 @@ static uint16_t _mdns_append_a_record(uint8_t * packet, uint16_t * index, const * * @param packet MDNS packet * @param index offset in the packet - * @param hostnamek the hostname address to add + * @param hostname the hostname address to add * @param ipv6 the IPv6 address to add * * @return length of added data: 0 on error or length on success @@ -932,11 +933,36 @@ static bool _ipv6_address_is_zero(esp_ip6_addr_t ip6) } #endif +static uint8_t _mdns_append_host_answer(uint8_t * packet, uint16_t * index, mdns_host_item_t * host, + uint8_t address_type, bool flush, bool bye) +{ + mdns_ip_addr_t * addr = host->address_list; + uint8_t num_records = 0; + + while (addr != NULL) { + if (addr->addr.type == address_type) { + if (address_type == ESP_IPADDR_TYPE_V4 && + _mdns_append_a_record(packet, index, host->hostname, addr->addr.u_addr.ip4.addr, flush, bye) <= 0) { + break; + } +#if CONFIG_LWIP_IPV6 + if (address_type == ESP_IPADDR_TYPE_V6 && + _mdns_append_aaaa_record(packet, index, host->hostname, (uint8_t *)addr->addr.u_addr.ip6.addr, flush, + bye) <= 0) { + break; + } +#endif // CONFIG_LWIP_IPV6 + num_records++; + } + addr = addr->next; + } + return num_records; +} + /** * @brief Append answer to packet * * @return number of answers added to the packet - * XXX: create the answers here */ static uint8_t _mdns_append_answer(uint8_t * packet, uint16_t * index, mdns_out_answer_t * answer, mdns_if_t tcpip_if) { @@ -982,11 +1008,7 @@ static uint8_t _mdns_append_answer(uint8_t * packet, uint16_t * index, mdns_out_ } return 1; } else if (answer->host != NULL) { - if (_mdns_append_a_record(packet, index, answer->host->hostname, answer->host->address.u_addr.ip4.addr, answer->flush, answer->bye) <= 0) { - return 0; - } else { - return 1; - } + return _mdns_append_host_answer(packet, index, answer->host, ESP_IPADDR_TYPE_V4, answer->flush, answer->bye); } } #if CONFIG_LWIP_IPV6 @@ -1017,12 +1039,7 @@ static uint8_t _mdns_append_answer(uint8_t * packet, uint16_t * index, mdns_out_ } return 1; } else if (answer->host != NULL) { - if (_mdns_append_aaaa_record(packet, index, answer->host->hostname, (uint8_t*)answer->host->address.u_addr.ip6.addr, answer->flush, answer->bye) <= 0) { - return 0; - } else { - return 1; - } - + return _mdns_append_host_answer(packet, index, answer->host, ESP_IPADDR_TYPE_V6, answer->flush, answer->bye); } } #endif @@ -1278,7 +1295,8 @@ static void _mdns_dealloc_answer(mdns_out_answer_t ** destination, uint16_t type /** * @brief Allocate new answer and add it to answer list (destination) */ -static bool _mdns_alloc_answer(mdns_out_answer_t ** destination, uint16_t type, mdns_service_t * service, mdns_host_item_t *host, bool flush, bool bye) +static bool _mdns_alloc_answer(mdns_out_answer_t ** destination, uint16_t type, mdns_service_t * service, + mdns_host_item_t * host, bool flush, bool bye) { mdns_out_answer_t * d = *destination; while (d) { @@ -1330,25 +1348,24 @@ static mdns_tx_packet_t * _mdns_alloc_packet_default(mdns_if_t tcpip_if, mdns_ip return packet; } -static bool _mdns_create_answer_from_service(mdns_tx_packet_t *packet, mdns_service_t *service, - mdns_parsed_question_t *question, bool shared, bool send_flush) +static bool _mdns_create_answer_from_service(mdns_tx_packet_t * packet, mdns_service_t * service, + mdns_parsed_question_t * question, bool shared, bool send_flush) { - mdns_host_item_t *host4 = mdns_get_host_item(service->hostname, ESP_IPADDR_TYPE_V4); - mdns_host_item_t *host6 = mdns_get_host_item(service->hostname, ESP_IPADDR_TYPE_V6); + mdns_host_item_t * host = mdns_get_host_item(service->hostname); if (question->type == MDNS_TYPE_PTR || question->type == MDNS_TYPE_ANY) { if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service, NULL, false, false) || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false) || - !_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_A, service, host4, - send_flush, false) || - !_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_AAAA, service, host6, + !_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_A, service, host, send_flush, + false) || + !_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_AAAA, service, host, send_flush, false)) { return false; } } else if (question->type == MDNS_TYPE_SRV) { if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) || - !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_A, service, host4, send_flush, false) || - !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_AAAA, service, host6, send_flush, false)) { + !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_A, service, host, send_flush, false) || + !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_AAAA, service, host, send_flush, false)) { return false; } } else if (question->type == MDNS_TYPE_TXT) { @@ -1364,14 +1381,11 @@ static bool _mdns_create_answer_from_service(mdns_tx_packet_t *packet, mdns_serv return true; } -static bool _mdns_create_answer_from_hostname(mdns_tx_packet_t *packet, const char *hostname, bool send_flush) +static bool _mdns_create_answer_from_hostname(mdns_tx_packet_t * packet, const char * hostname, bool send_flush) { - mdns_host_item_t *host4; - mdns_host_item_t *host6; - host4 = mdns_get_host_item(hostname, ESP_IPADDR_TYPE_V4); - host6 = mdns_get_host_item(hostname, ESP_IPADDR_TYPE_V6); - if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, host4, send_flush, false) || - !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, host6, send_flush, false)) { + mdns_host_item_t * host = mdns_get_host_item(hostname); + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, host, send_flush, false) || + !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, host, send_flush, false)) { return false; } return true; @@ -1379,7 +1393,6 @@ static bool _mdns_create_answer_from_hostname(mdns_tx_packet_t *packet, const ch /** * @brief Create answer packet to questions from parsed packet - * XXX: reply from here */ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_packet) { @@ -1486,9 +1499,10 @@ static bool _mdns_question_exists(mdns_out_question_t * needle, mdns_out_questio return false; } -bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye) { +bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye) +{ if (!_str_null_or_empty(_mdns_server->hostname)) { - mdns_host_item_t *self_host = mdns_get_host_item(_mdns_server->hostname, ESP_IPADDR_TYPE_ANY); + mdns_host_item_t * self_host = mdns_get_host_item(_mdns_server->hostname); if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, self_host, flush, bye)) { return false; } @@ -1496,16 +1510,13 @@ bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool b return false; } } - mdns_host_item_t *host = _mdns_host_list; - while(host != NULL) { - if (host->address.type == ESP_IPADDR_TYPE_V4) { - if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, host, flush, bye)) { - return false; - } - } else if (host->address.type == ESP_IPADDR_TYPE_V6) { - if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, host, flush, bye)) { - return false; - } + mdns_host_item_t * host = _mdns_host_list; + while (host != NULL) { + if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, host, flush, bye)) { + return false; + } + if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, host, flush, bye)) { + return false; } host = host->next; } @@ -2048,7 +2059,9 @@ static void _mdns_free_linked_txt(mdns_txt_linked_item_t *txt) * * @return pointer to the service or NULL on error */ -static mdns_service_t * _mdns_create_service(const char * service, const char * proto, const char *hostname, uint16_t port, const char * instance, size_t num_items, mdns_txt_item_t txt[]) +static mdns_service_t * _mdns_create_service(const char * service, const char * proto, const char * hostname, + uint16_t port, const char * instance, size_t num_items, + mdns_txt_item_t txt[]) { mdns_service_t * s = (mdns_service_t *)malloc(sizeof(mdns_service_t)); if (!s) { @@ -2068,7 +2081,6 @@ static mdns_service_t * _mdns_create_service(const char * service, const char * s->txt = new_txt; s->port = port; - assert(hostname != NULL); if (hostname) { s->hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); if (!s->hostname) { @@ -2219,6 +2231,9 @@ static void _mdns_free_service(mdns_service_t * service) free((char *)service->instance); free((char *)service->service); free((char *)service->proto); + if (service->hostname) { + free((char *)service->hostname); + } while (service->txt) { mdns_txt_linked_item_t * s = service->txt; service->txt = service->txt->next; @@ -2439,12 +2454,12 @@ static int _mdns_check_aaaa_collision(esp_ip6_addr_t * ip, mdns_if_t tcpip_if) } #endif -static bool _hostname_is_ours(const char *hostname) +static bool _hostname_is_ours(const char * hostname) { if (strcasecmp(hostname, _mdns_server->hostname) == 0) { return true; } - mdns_host_item_t *host = _mdns_host_list; + mdns_host_item_t * host = _mdns_host_list; while (host != NULL) { if (strcasecmp(hostname, host->hostname) == 0) { return true; @@ -2454,31 +2469,64 @@ static bool _hostname_is_ours(const char *hostname) return false; } -static bool _mdns_delegate_hostname_add(const char *hostname, const esp_ip_addr_t *address) +static bool _mdns_delegate_hostname_add(const char * hostname, mdns_ip_addr_t * address_list) { if (_hostname_is_ours(hostname)) { return true; } - mdns_host_item_t *host = (mdns_host_item_t *)malloc(sizeof(mdns_host_item_t)); + mdns_host_item_t * host = (mdns_host_item_t *)malloc(sizeof(mdns_host_item_t)); if (host == NULL) { return false; } - host->address = *address; + host->address_list = address_list; host->hostname = hostname; host->next = _mdns_host_list; _mdns_host_list = host; return true; } -static bool _mdns_delegate_hostname_remove(const char *hostname) +static void free_address_list(mdns_ip_addr_t * address_list) { - mdns_srv_item_t *srv = _mdns_server->services; - mdns_srv_item_t *prev_srv = NULL; + while (address_list != NULL) { + mdns_ip_addr_t * next = address_list->next; + free(address_list); + address_list = next; + } +} + +static mdns_ip_addr_t * copy_address_list(const mdns_ip_addr_t * address_list) +{ + mdns_ip_addr_t * head = NULL; + mdns_ip_addr_t * tail = NULL; + while (address_list != NULL) { + mdns_ip_addr_t * addr = (mdns_ip_addr_t *)malloc(sizeof(mdns_ip_addr_t)); + if (addr == NULL) { + free_address_list(head); + return NULL; + } + addr->addr = address_list->addr; + addr->next = NULL; + if (head == NULL) { + head = addr; + tail = addr; + } else { + tail->next = addr; + tail = tail->next; + } + address_list = address_list->next; + } + return head; +} + +static bool _mdns_delegate_hostname_remove(const char * hostname) +{ + mdns_srv_item_t * srv = _mdns_server->services; + mdns_srv_item_t * prev_srv = NULL; while (srv) { if (strcasecmp(srv->service->hostname, hostname) == 0) { - mdns_srv_item_t *to_free = srv; + mdns_srv_item_t * to_free = srv; _mdns_send_bye(&srv, 1, false); _mdns_remove_scheduled_service_packets(srv->service); if (prev_srv == NULL) { @@ -2486,6 +2534,7 @@ static bool _mdns_delegate_hostname_remove(const char *hostname) srv = srv->next; } else { prev_srv->next = srv->next; + srv = srv->next; } _mdns_free_service(to_free->service); free(to_free); @@ -2494,8 +2543,8 @@ static bool _mdns_delegate_hostname_remove(const char *hostname) srv = srv->next; } } - mdns_host_item_t *host = _mdns_host_list; - mdns_host_item_t *prev_host = NULL; + mdns_host_item_t * host = _mdns_host_list; + mdns_host_item_t * prev_host = NULL; while (host != NULL) { if (strcasecmp(hostname, host->hostname) == 0) { if (prev_host == NULL) { @@ -2503,6 +2552,8 @@ static bool _mdns_delegate_hostname_remove(const char *hostname) } else { prev_host->next = host->next; } + printf("Free host %p\n", host); + free_address_list(host->address_list); free((char *)host->hostname); free(host); break; @@ -2542,7 +2593,7 @@ static bool _mdns_name_is_ours(mdns_name_t * name) if (_str_null_or_empty(name->service) && _str_null_or_empty(name->proto)) { if (!_str_null_or_empty(name->host) && !_str_null_or_empty(_mdns_server->hostname) - && _hostname_is_ours(name->host) == 0) + && _hostname_is_ours(name->host)) { return true; } @@ -4232,7 +4283,8 @@ static void _mdns_execute_action(mdns_action_t * action) free(action->data.rx_handle.packet); break; case ACTION_DELEGATE_HOSTNAME_ADD: - _mdns_delegate_hostname_add(action->data.delegate_hostname.hostname, &action->data.delegate_hostname.address); + _mdns_delegate_hostname_add(action->data.delegate_hostname.hostname, + action->data.delegate_hostname.address_list); break; case ACTION_DELEGATE_HOSTNAME_REMOVE: _mdns_delegate_hostname_remove(action->data.delegate_hostname.hostname); @@ -4644,7 +4696,6 @@ esp_err_t mdns_hostname_set(const char * hostname) action->data.hostname_set.hostname = new_hostname; action->data.hostname_set.calling_task = xTaskGetCurrentTaskHandle(); if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) { - assert(false); free(new_hostname); free(action); return ESP_ERR_NO_MEM; @@ -4653,12 +4704,12 @@ esp_err_t mdns_hostname_set(const char * hostname) return ERR_OK; } -esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t *address) +esp_err_t mdns_delegate_hostname_add(const char * hostname, const mdns_ip_addr_t * address_list) { if (!_mdns_server) { - return ESP_ERR_INVALID_ARG; + return ESP_ERR_INVALID_STATE; } - if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) { + if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1) || address_list == NULL) { return ESP_ERR_INVALID_ARG; } char * new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); @@ -4674,7 +4725,7 @@ esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t } action->type = ACTION_DELEGATE_HOSTNAME_ADD; action->data.delegate_hostname.hostname = new_hostname; - action->data.delegate_hostname.address = *address; + action->data.delegate_hostname.address_list = copy_address_list(address_list); if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) { free(new_hostname); free(action); @@ -4686,7 +4737,7 @@ esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t esp_err_t mdns_delegate_hostname_remove(const char * hostname) { if (!_mdns_server) { - return ESP_ERR_INVALID_ARG; + return ESP_ERR_INVALID_STATE; } if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) { return ESP_ERR_INVALID_ARG; @@ -4712,14 +4763,15 @@ esp_err_t mdns_delegate_hostname_remove(const char * hostname) return ERR_OK; } -bool mdns_hostname_exists(const char *hostname) { +bool mdns_hostname_exists(const char * hostname) +{ return _hostname_is_ours(hostname); } esp_err_t mdns_instance_name_set(const char * instance) { if (!_mdns_server) { - return ESP_ERR_INVALID_ARG; + return ESP_ERR_INVALID_STATE; } if (_str_null_or_empty(instance) || strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) { return ESP_ERR_INVALID_ARG; @@ -4749,9 +4801,8 @@ esp_err_t mdns_instance_name_set(const char * instance) * MDNS SERVICES * */ -esp_err_t mdns_service_add_custom_host(const char *instance, const char *service, const char *proto, - const char *hostname, uint16_t port, - mdns_txt_item_t txt[], size_t num_items) +esp_err_t mdns_service_add_for_host(const char * instance, const char * service, const char * proto, + const char * hostname, uint16_t port, mdns_txt_item_t txt[], size_t num_items) { if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) { return ESP_ERR_INVALID_ARG; @@ -4799,8 +4850,7 @@ esp_err_t mdns_service_add_custom_host(const char *instance, const char *service size_t start = xTaskGetTickCount(); size_t timeout_ticks = pdMS_TO_TICKS(MDNS_SERVICE_ADD_TIMEOUT_MS); - while (_mdns_get_service_item(service, proto, hostname) == NULL) - { + while (_mdns_get_service_item(service, proto, hostname) == NULL) { uint32_t expired = xTaskGetTickCount() - start; if (expired >= timeout_ticks) { return ESP_FAIL; // Timeout @@ -4811,19 +4861,21 @@ esp_err_t mdns_service_add_custom_host(const char *instance, const char *service return ESP_OK; } -esp_err_t mdns_service_add(const char *instance, const char *service, const char *proto, uint16_t port, +esp_err_t mdns_service_add(const char * instance, const char * service, const char * proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items) { - assert(_mdns_server->hostname != NULL); - return mdns_service_add_custom_host(instance, service, proto, _mdns_server->hostname, port, txt, num_items); + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_add_for_host(instance, service, proto, _mdns_server->hostname, port, txt, num_items); } -bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname) +bool mdns_service_exists(const char * service_type, const char * proto, const char * hostname) { return _mdns_get_service_item(service_type, proto, hostname) != NULL; } -esp_err_t mdns_service_port_set_for_host(const char *service, const char *proto, const char *hostname, uint16_t port) +esp_err_t mdns_service_port_set_for_host(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) { return ESP_ERR_INVALID_ARG; @@ -4848,11 +4900,15 @@ esp_err_t mdns_service_port_set_for_host(const char *service, const char *proto, return ESP_OK; } -esp_err_t mdns_service_port_set(const char *service, const char *proto, uint16_t port) { +esp_err_t mdns_service_port_set(const char * service, const char * proto, uint16_t port) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } return mdns_service_port_set_for_host(service, proto, _mdns_server->hostname, port); } -esp_err_t mdns_service_txt_set_for_host(const char *service, const char *proto, const char *hostname, +esp_err_t mdns_service_txt_set_for_host(const char * service, const char * proto, const char * hostname, mdns_txt_item_t txt[], uint8_t num_items) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || (num_items && txt == NULL)) { @@ -4889,12 +4945,16 @@ esp_err_t mdns_service_txt_set_for_host(const char *service, const char *proto, return ESP_OK; } -esp_err_t mdns_service_txt_set(const char *service, const char *proto, mdns_txt_item_t txt[], uint8_t num_items) +esp_err_t mdns_service_txt_set(const char * service, const char * proto, mdns_txt_item_t txt[], uint8_t num_items) { + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } return mdns_service_txt_set_for_host(service, proto, _mdns_server->hostname, txt, num_items); } -esp_err_t mdns_service_txt_item_set_for_host(const char * service, const char * proto, const char *hostname, const char * key, const char * value) +esp_err_t mdns_service_txt_item_set_for_host(const char * service, const char * proto, const char * hostname, + const char * key, const char * value) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key) || !value) { return ESP_ERR_INVALID_ARG; @@ -4931,12 +4991,16 @@ esp_err_t mdns_service_txt_item_set_for_host(const char * service, const char * return ESP_OK; } -esp_err_t mdns_service_txt_item_set(const char *service, const char *proto, const char *key, const char *value) +esp_err_t mdns_service_txt_item_set(const char * service, const char * proto, const char * key, const char * value) { + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } return mdns_service_txt_item_set_for_host(service, proto, _mdns_server->hostname, key, value); } -esp_err_t mdns_service_txt_item_remove_for_host(const char * service, const char * proto, const char *hostname, const char * key) +esp_err_t mdns_service_txt_item_remove_for_host(const char * service, const char * proto, const char * hostname, + const char * key) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key)) { return ESP_ERR_INVALID_ARG; @@ -4966,13 +5030,16 @@ esp_err_t mdns_service_txt_item_remove_for_host(const char * service, const char return ESP_OK; } -esp_err_t mdns_service_txt_item_remove(const char *service, const char *proto, const char *key) +esp_err_t mdns_service_txt_item_remove(const char * service, const char * proto, const char * key) { + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } return mdns_service_txt_item_remove_for_host(service, proto, _mdns_server->hostname, key); } -esp_err_t mdns_service_instance_name_set_for_host(const char *service, const char *proto, const char *hostname, - const char *instance) +esp_err_t mdns_service_instance_name_set_for_host(const char * service, const char * proto, const char * hostname, + const char * instance) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) { return ESP_ERR_INVALID_ARG; @@ -5006,12 +5073,15 @@ esp_err_t mdns_service_instance_name_set_for_host(const char *service, const cha return ESP_OK; } -esp_err_t mdns_service_instance_name_set(const char *service, const char *proto, const char *instance) +esp_err_t mdns_service_instance_name_set(const char * service, const char * proto, const char * instance) { + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } return mdns_service_instance_name_set_for_host(service, proto, _mdns_server->hostname, instance); } -esp_err_t mdns_service_remove_for_host(const char * service, const char * proto, const char *hostname) +esp_err_t mdns_service_remove_for_host(const char * service, const char * proto, const char * hostname) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) { return ESP_ERR_INVALID_ARG; @@ -5035,8 +5105,11 @@ esp_err_t mdns_service_remove_for_host(const char * service, const char * proto, return ESP_OK; } -esp_err_t mdns_service_remove(const char *service_type, const char *proto) +esp_err_t mdns_service_remove(const char * service_type, const char * proto) { + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } return mdns_service_remove_for_host(service_type, proto, _mdns_server->hostname); } diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index 6acdf92833..4b8f8806c7 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -19,8 +19,9 @@ #include "esp_timer.h" #include "esp_netif_ip_addr.h" #include "freertos/FreeRTOS.h" +#include "mdns.h" -#define MDNS_ENABLE_DEBUG +//#define MDNS_ENABLE_DEBUG #ifdef MDNS_ENABLE_DEBUG #define _mdns_dbg_printf(...) printf(__VA_ARGS__) @@ -309,7 +310,7 @@ typedef struct mdns_out_question_s { typedef struct mdns_host_item_t { const char * hostname; - esp_ip_addr_t address; + mdns_ip_addr_t *address_list; struct mdns_host_item_t *next; } mdns_host_item_t; @@ -441,7 +442,7 @@ typedef struct { } rx_handle; struct { const char * hostname; - esp_ip_addr_t address; + mdns_ip_addr_t *address_list; } delegate_hostname; } data; } mdns_action_t; diff --git a/components/mdns/test/test_mdns.c b/components/mdns/test/test_mdns.c index 9dc9fe090a..abdad0e63e 100644 --- a/components/mdns/test/test_mdns.c +++ b/components/mdns/test/test_mdns.c @@ -4,6 +4,7 @@ #define MDNS_HOSTNAME "test-hostname" +#define MDNS_DELEGATE_HOSTNAME "delegate-hostname" #define MDNS_INSTANCE "test-instance" #define MDNS_SERVICE_NAME "_http" #define MDNS_SERVICE_PROTO "_tcp" @@ -42,6 +43,10 @@ TEST_CASE("mdns api return expected err-code and do not leak memory", "[mdns][le { mdns_txt_item_t serviceTxtData[CONFIG_MDNS_MAX_SERVICES] = { {NULL, NULL}, }; + mdns_ip_addr_t addr; + addr.addr.type = ESP_IPADDR_TYPE_V4; + addr.addr.u_addr.ip4.addr = esp_ip4addr_aton("127.0.0.1"); + addr.next = NULL; for (int i=0; itcpip_if], ip_protocol_str[r->ip_protocol]); - if (r->instance_name) { + if(r->instance_name){ printf(" PTR : %s\n", r->instance_name); } - if (r->hostname) { + if(r->hostname){ printf(" SRV : %s.local:%u\n", r->hostname, r->port); } - if (r->txt_count) { + if(r->txt_count){ printf(" TXT : [%u] ", r->txt_count); - for (t = 0; t < r->txt_count; t++) { - printf("%s=%s; ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL"); + for(t=0; ttxt_count; t++){ + printf("%s=%s; ", r->txt[t].key, r->txt[t].value?r->txt[t].value:"NULL"); } printf("\n"); } a = r->addr; - while (a) { - if (a->addr.type == ESP_IPADDR_TYPE_V6) { + while(a){ + if(a->addr.type == ESP_IPADDR_TYPE_V6){ printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); } else { printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); @@ -111,17 +110,17 @@ static void mdns_print_results(mdns_result_t *results) } -static void query_mdns_service(const char *service_name, const char *proto) +static void query_mdns_service(const char * service_name, const char * proto) { ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto); - mdns_result_t *results = NULL; + mdns_result_t * results = NULL; esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results); - if (err) { + if(err){ ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); return; } - if (!results) { + if(!results){ ESP_LOGW(TAG, "No results found!"); return; } @@ -130,7 +129,7 @@ static void query_mdns_service(const char *service_name, const char *proto) mdns_query_results_free(results); } -static void query_mdns_host(const char *host_name) +static void query_mdns_host(const char * host_name) { ESP_LOGI(TAG, "Query A: %s.local", host_name); @@ -138,8 +137,8 @@ static void query_mdns_host(const char *host_name) addr.addr = 0; esp_err_t err = mdns_query_a(host_name, 2000, &addr); - if (err) { - if (err == ESP_ERR_NOT_FOUND) { + if(err){ + if(err == ESP_ERR_NOT_FOUND){ ESP_LOGW(TAG, "%s: Host was not found!", esp_err_to_name(err)); return; } @@ -193,7 +192,7 @@ static void mdns_example_task(void *pvParameters) check_button(); vTaskDelay(50 / portTICK_PERIOD_MS); if (pdTICKS_TO_MS(xTaskGetTickCount()) >= 15 * 1000 && ! removed) { - printf("Remove device\n"); + ESP_LOGI(TAG, "Remove delegate device\n"); ESP_ERROR_CHECK(mdns_delegate_hostname_remove("test-device")); removed = true; } @@ -221,7 +220,7 @@ void app_main(void) /** Generate host name based on sdkconfig, optionally adding a portion of MAC address to it. * @return host name string allocated from the heap */ -static char *generate_hostname(void) +static char* generate_hostname(void) { #ifndef CONFIG_MDNS_ADD_MAC_TO_HOSTNAME return strdup(CONFIG_MDNS_HOSTNAME); @@ -241,7 +240,7 @@ static char *generate_hostname(void) * @brief Executes gethostbyname and displays list of resolved addresses. * Note: This function is used only to test advertised mdns hostnames resolution */ -static void query_mdns_host_with_gethostbyname(char *host) +static void query_mdns_host_with_gethostbyname(char * host) { struct hostent *res = gethostbyname(host); if (res) { @@ -257,10 +256,10 @@ static void query_mdns_host_with_gethostbyname(char *host) * @brief Executes getaddrinfo and displays list of resolved addresses. * Note: This function is used only to test advertised mdns hostnames resolution */ -static void query_mdns_host_with_getaddrinfo(char *host) +static void query_mdns_host_with_getaddrinfo(char * host) { struct addrinfo hints; - struct addrinfo *res; + struct addrinfo * res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; @@ -269,8 +268,8 @@ static void query_mdns_host_with_getaddrinfo(char *host) if (!getaddrinfo(host, NULL, &hints, &res)) { while (res) { ESP_LOGI(TAG, "getaddrinfo: %s resolved to: %s", host, - res->ai_family == AF_INET ? - inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr) : + res->ai_family == AF_INET? + inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr): inet_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr)); res = res->ai_next; } From d2a5d25984432d149ca31aea4a0d177f3509dd7b Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Thu, 15 Apr 2021 20:03:53 +0800 Subject: [PATCH 5/9] mdns: fix mdns probe/reply behavior * send correct hostnames when probing. * add test for mdns host delegation. --- components/mdns/mdns.c | 91 +++++++++++-------- examples/protocols/mdns/README.md | 1 + .../protocols/mdns/main/Kconfig.projbuild | 6 ++ .../protocols/mdns/main/mdns_example_main.c | 21 +++-- examples/protocols/mdns/mdns_example_test.py | 8 ++ 5 files changed, 80 insertions(+), 47 deletions(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index e72dce5ae8..305ba734f9 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -45,6 +45,7 @@ static void _mdns_search_result_add_ip(mdns_search_once_t * search, const char * static void _mdns_search_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); static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_item_t * txt, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static mdns_result_t * _mdns_search_result_add_ptr(mdns_search_once_t * search, const char * instance, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); +static bool _mdns_append_host_list_in_services(mdns_out_answer_t ** destination, mdns_srv_item_t * services[], size_t services_len, bool flush, bool bye); static bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye); /* @@ -1499,26 +1500,43 @@ static bool _mdns_question_exists(mdns_out_question_t * needle, mdns_out_questio return false; } -bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye) +static bool _mdns_append_host(mdns_out_answer_t ** destination, mdns_host_item_t * host, bool flush, bool bye) +{ + if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, host, flush, bye)) { + return false; + } + if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, host, flush, bye)) { + return false; + } + return true; +} + +static bool _mdns_append_host_list_in_services(mdns_out_answer_t ** destination, mdns_srv_item_t * services[], + size_t services_len, bool flush, bool bye) +{ + for (size_t i = 0; i < services_len; i++) { + mdns_host_item_t *host = mdns_get_host_item(services[i]->service->hostname); + if (!_mdns_append_host(destination, host, flush, bye)) { + return false; + } + } + return true; +} + +static bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye) { if (!_str_null_or_empty(_mdns_server->hostname)) { mdns_host_item_t * self_host = mdns_get_host_item(_mdns_server->hostname); - if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, self_host, flush, bye)) { - return false; - } - if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, self_host, flush, bye)) { + if (!_mdns_append_host(destination, self_host, flush, bye)) { return false; } } mdns_host_item_t * host = _mdns_host_list; while (host != NULL) { - if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, host, flush, bye)) { - return false; - } - if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, host, flush, bye)) { - return false; - } host = host->next; + if (!_mdns_append_host(destination, host, flush, bye)) { + return false; + } } return true; } @@ -1563,27 +1581,29 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_ } if (include_ip) { - mdns_out_question_t * q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t)); - if (!q) { - HOOK_MALLOC_FAILED; - _mdns_free_tx_packet(packet); - return NULL; - } - q->next = NULL; - q->unicast = first; - q->type = MDNS_TYPE_ANY; - q->host = _mdns_server->hostname; - q->service = NULL; - q->proto = NULL; - q->domain = MDNS_DEFAULT_DOMAIN; - q->own_dynamic_memory = false; - if (_mdns_question_exists(q, packet->questions)) { - free(q); - } else { - queueToEnd(mdns_out_question_t, packet->questions, q); + for (i = 0; i < len; i++) { + mdns_out_question_t * q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t)); + if (!q) { + HOOK_MALLOC_FAILED; + _mdns_free_tx_packet(packet); + return NULL; + } + q->next = NULL; + q->unicast = first; + q->type = MDNS_TYPE_ANY; + q->host = services[i]->service->hostname; + q->service = NULL; + q->proto = NULL; + q->domain = MDNS_DEFAULT_DOMAIN; + q->own_dynamic_memory = false; + if (_mdns_question_exists(q, packet->questions)) { + free(q); + } else { + queueToEnd(mdns_out_question_t, packet->questions, q); + } } - if (!_mdns_append_host_list(&packet->servers, false, false)) { + if (!_mdns_append_host_list_in_services(&packet->servers, services, len, false, false)) { _mdns_free_tx_packet(packet); return NULL; } @@ -1614,7 +1634,7 @@ static mdns_tx_packet_t * _mdns_create_announce_packet(mdns_if_t tcpip_if, mdns_ } } if (include_ip) { - if (!_mdns_append_host_list(&packet->servers, true, false)) { + if (!_mdns_append_host_list_in_services(&packet->servers, services, len, true, false)) { _mdns_free_tx_packet(packet); return NULL; } @@ -1675,7 +1695,7 @@ static void _mdns_pcb_send_bye(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco } } if (include_ip) { - _mdns_append_host_list(&packet->answers, true, true); + _mdns_append_host_list_in_services(&packet->answers, services, len, true, true); } _mdns_dispatch_tx_packet(packet); _mdns_free_tx_packet(packet); @@ -1841,7 +1861,7 @@ static void _mdns_announce_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco if (include_ip) { _mdns_dealloc_answer(&p->additional, MDNS_TYPE_A, NULL); _mdns_dealloc_answer(&p->additional, MDNS_TYPE_AAAA, NULL); - _mdns_append_host_list(&p->answers, true, false); + _mdns_append_host_list_in_services(&p->answers, services, len, true, false); } _pcb->state = PCB_ANNOUNCE_1; } @@ -2231,9 +2251,7 @@ static void _mdns_free_service(mdns_service_t * service) free((char *)service->instance); free((char *)service->service); free((char *)service->proto); - if (service->hostname) { - free((char *)service->hostname); - } + free((char *)service->hostname); while (service->txt) { mdns_txt_linked_item_t * s = service->txt; service->txt = service->txt->next; @@ -2552,7 +2570,6 @@ static bool _mdns_delegate_hostname_remove(const char * hostname) } else { prev_host->next = host->next; } - printf("Free host %p\n", host); free_address_list(host->address_list); free((char *)host->hostname); free(host); diff --git a/examples/protocols/mdns/README.md b/examples/protocols/mdns/README.md index 2b99f2d4c2..e6644d5e5e 100644 --- a/examples/protocols/mdns/README.md +++ b/examples/protocols/mdns/README.md @@ -5,6 +5,7 @@ Shows how to use mDNS to advertise lookup services and hosts ## Example workflow - mDNS is initialized with host name and instance name defined through the project configuration and `_http._tcp` service is added to be advertised +- A delegated host `esp32-delegated._local` is added and another `_http._tcp` service is added for this host. - WiFi STA is started and trying to connect to the access point defined through the project configuration - The system event handler is used to pass the network events to mDNS so the service is aware when the interface comes up or down - GPIO0 (BOOT Button) is initialized as pulled-up input that can be monitored for button press diff --git a/examples/protocols/mdns/main/Kconfig.projbuild b/examples/protocols/mdns/main/Kconfig.projbuild index c4ae7e13b4..ca2f2bbf34 100644 --- a/examples/protocols/mdns/main/Kconfig.projbuild +++ b/examples/protocols/mdns/main/Kconfig.projbuild @@ -12,6 +12,12 @@ menu "Example Configuration" help mDNS Instance Name for example to use + config MDNS_PUBLISH_DELEGATE_HOST + bool "Publish a delegated host" + help + Enable publishing a delegated host other than ESP32. + The example will also add a mock service for this host. + config MDNS_RESOLVE_TEST_SERVICES bool "Resolve test services" default n diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index ecdb47e4e9..244ac41567 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -34,6 +34,9 @@ static void query_mdns_host_with_getaddrinfo(char * host); static void initialise_mdns(void) { char *hostname = generate_hostname(); + char delegated_hostname[64]; + + snprintf(delegated_hostname, sizeof(delegated_hostname), "%s-delegated", hostname); //initialize mDNS ESP_ERROR_CHECK( mdns_init() ); //set mDNS hostname (required if you want to advertise services) @@ -51,19 +54,23 @@ static void initialise_mdns(void) //initialize service ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3) ); + +#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST mdns_ip_addr_t addr4, addr6; ip4_addr_t ip4_addr; ip6_addr_t ip6_addr; - ip4addr_aton("10.0.0.1", &ip4_addr); + ip4addr_aton("10.0.0.1", &ip4_addr); // mock address addr4.addr.u_addr.ip4.addr = ip4_addr.addr; addr4.addr.type = ESP_IPADDR_TYPE_V4; addr4.next = &addr6; - ip6addr_aton("fd11:22::1", &ip6_addr); + ip6addr_aton("fd11:22::1", &ip6_addr); // mock address memcpy(addr6.addr.u_addr.ip6.addr, ip6_addr.addr, sizeof(ip6_addr.addr)); addr6.addr.type = ESP_IPADDR_TYPE_V6; addr6.next = NULL; - ESP_ERROR_CHECK( mdns_delegate_hostname_add("test-device", &addr4) ); - ESP_ERROR_CHECK( mdns_service_add_for_host("test0", "_http", "_tcp", "test-device", 1234, serviceTxtData, 3) ); + ESP_ERROR_CHECK( mdns_delegate_hostname_add(delegated_hostname, &addr4) ); + ESP_ERROR_CHECK( mdns_service_add_for_host("test0", "_http", "_tcp", delegated_hostname, 1234, serviceTxtData, 3) ); +#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST + //add another TXT item ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "path", "/foobar") ); //change TXT item value @@ -186,16 +193,10 @@ static void mdns_example_task(void *pvParameters) query_mdns_host_with_gethostbyname("tinytester-lwip.local"); query_mdns_host_with_getaddrinfo("tinytester-lwip.local"); #endif - bool removed = false; while (1) { check_button(); vTaskDelay(50 / portTICK_PERIOD_MS); - if (pdTICKS_TO_MS(xTaskGetTickCount()) >= 15 * 1000 && ! removed) { - ESP_LOGI(TAG, "Remove delegate device\n"); - ESP_ERROR_CHECK(mdns_delegate_hostname_remove("test-device")); - removed = true; - } } } diff --git a/examples/protocols/mdns/mdns_example_test.py b/examples/protocols/mdns/mdns_example_test.py index 201acb569c..26295d6a78 100644 --- a/examples/protocols/mdns/mdns_example_test.py +++ b/examples/protocols/mdns/mdns_example_test.py @@ -13,6 +13,7 @@ from tiny_test_fw import DUT stop_mdns_server = Event() esp_answered = Event() +esp_delegated_answered = Event() def get_dns_query_for_esp(esp_host): @@ -68,6 +69,8 @@ def mdns_server(esp_host): if not esp_answered.is_set(): sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP,UDP_PORT)) time.sleep(0.2) + sock.sendto(get_dns_query_for_esp(esp_host + '-delegated'), (MCAST_GRP,UDP_PORT)) + time.sleep(0.2) data, addr = sock.recvfrom(1024) dns = dpkt.dns.DNS(data) if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A: @@ -81,6 +84,9 @@ def mdns_server(esp_host): if dns.an[0].name == esp_host + u'.local': print('Received answer to esp32-mdns query: {}'.format(dns.__repr__())) esp_answered.set() + if dns.an[0].name == esp_host + u'-delegated.local': + print('Received answer to esp32-mdns-delegate query: {}'.format(dns.__repr__())) + esp_delegated_answered.set() except socket.timeout: break except dpkt.UnpackError: @@ -120,6 +126,8 @@ def test_examples_protocol_mdns(env, extra_data): # 3. check the mdns name is accessible if not esp_answered.wait(timeout=30): raise ValueError('Test has failed: did not receive mdns answer within timeout') + if not esp_delegated_answered.wait(timeout=30): + raise ValueError('Test has failed: did not receive mdns answer for delegated host within timeout') # 4. check DUT output if mdns advertized host is resolved dut1.expect(re.compile(r'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1'), timeout=30) dut1.expect(re.compile(r'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30) From 7bbb72d86540f04d37b0e2c4efb6dc66ee9c9ea0 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Wed, 21 Apr 2021 16:15:51 +0800 Subject: [PATCH 6/9] mdns: fix empty address change announce packets --- components/mdns/mdns.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 305ba734f9..0558e9a0c2 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -1612,6 +1612,23 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_ return packet; } +/** + * @brief Create announce packet for self IP addresses + */ +static mdns_tx_packet_t * _mdns_create_announce_self_ip(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_tx_packet_t * packet = _mdns_alloc_packet_default(tcpip_if, ip_protocol); + if (!packet) { + return NULL; + } + mdns_host_item_t * host = mdns_get_host_item(_mdns_server->hostname); + if (!_mdns_append_host(&packet->servers, host, true, false)) { + _mdns_free_tx_packet(packet); + return NULL; + } + return packet; +} + /** * @brief Create announce packet for particular services on particular PCB */ @@ -1872,7 +1889,12 @@ static void _mdns_announce_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco } _pcb->state = PCB_ANNOUNCE_1; - mdns_tx_packet_t * p = _mdns_create_announce_packet(tcpip_if, ip_protocol, services, len, include_ip); + mdns_tx_packet_t * p = NULL; + if (services != NULL) { + p = _mdns_create_announce_packet(tcpip_if, ip_protocol, services, len, include_ip); + } else { + p = _mdns_create_announce_self_ip(tcpip_if, ip_protocol); + } if (p) { _mdns_schedule_tx_packet(p, 0); } From 439b31d065eddfdfb6eb4cf9c00454edfebc3d9b Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Fri, 30 Apr 2021 17:22:14 +0800 Subject: [PATCH 7/9] mdns: fix wrong service hostname after mangling --- components/mdns/mdns.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 0558e9a0c2..e96d971bd0 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -47,6 +47,7 @@ static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_it static mdns_result_t * _mdns_search_result_add_ptr(mdns_search_once_t * search, const char * instance, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static bool _mdns_append_host_list_in_services(mdns_out_answer_t ** destination, mdns_srv_item_t * services[], size_t services_len, bool flush, bool bye); static bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye); +static void _mdns_remap_self_service_hostname(const char *old_hostname, const char *new_hostname); /* * @brief Internal collection of mdns supported interfaces @@ -3227,8 +3228,10 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) } else { char * new_host = _mdns_mangle_name((char *)_mdns_server->hostname); if (new_host) { + _mdns_remap_self_service_hostname(_mdns_server->hostname, new_host); free((char *)_mdns_server->hostname); _mdns_server->hostname = new_host; + _mdns_self_host.hostname = new_host; } _mdns_restart_all_pcbs(); } @@ -3333,8 +3336,10 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) _mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].failed_probes++; char * new_host = _mdns_mangle_name((char *)_mdns_server->hostname); if (new_host) { + _mdns_remap_self_service_hostname(_mdns_server->hostname, new_host); free((char *)_mdns_server->hostname); _mdns_server->hostname = new_host; + _mdns_self_host.hostname = new_host; } _mdns_restart_all_pcbs(); } @@ -3381,8 +3386,10 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) _mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].failed_probes++; char * new_host = _mdns_mangle_name((char *)_mdns_server->hostname); if (new_host) { + _mdns_remap_self_service_hostname(_mdns_server->hostname, new_host); free((char *)_mdns_server->hostname); _mdns_server->hostname = new_host; + _mdns_self_host.hostname = new_host; } _mdns_restart_all_pcbs(); } @@ -4087,6 +4094,19 @@ static void _mdns_tx_handle_packet(mdns_tx_packet_t * p) } } +static void _mdns_remap_self_service_hostname(const char * old_hostname, const char * new_hostname) +{ + mdns_srv_item_t * service = _mdns_server->services; + + while (service) { + if (strcmp(service->service->hostname, old_hostname) == 0) { + free((char *)service->service->hostname); + service->service->hostname = strdup(new_hostname); + } + service = service->next; + } +} + /** * @brief Free action data */ @@ -4154,6 +4174,7 @@ static void _mdns_execute_action(mdns_action_t * action) break; case ACTION_HOSTNAME_SET: _mdns_send_bye_all_pcbs_no_instance(true); + _mdns_remap_self_service_hostname(_mdns_server->hostname, action->data.hostname_set.hostname); free((char*)_mdns_server->hostname); _mdns_server->hostname = action->data.hostname_set.hostname; _mdns_self_host.hostname = action->data.hostname_set.hostname; From e6135552d26480e39e11632437020535b1667b7a Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Thu, 6 May 2021 16:03:42 +0800 Subject: [PATCH 8/9] mdns: fix wrong SRV/PTR record handling --- components/mdns/mdns.c | 100 ++++++++++-------- .../mdns/private_include/mdns_private.h | 2 +- examples/protocols/mdns/sdkconfig.ci | 1 + 3 files changed, 55 insertions(+), 48 deletions(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index e96d971bd0..0bb56ecd6c 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -1418,7 +1418,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_ if (q->service && q->proto) { mdns_srv_item_t *service = _mdns_server->services; while (service) { - if (_mdns_service_match(service->service, q->service, q->proto, q->host)) { + if (_mdns_service_match(service->service, q->service, q->proto, NULL)) { if (!_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) { _mdns_free_tx_packet(packet); return; @@ -1515,6 +1515,13 @@ static bool _mdns_append_host(mdns_out_answer_t ** destination, mdns_host_item_t static bool _mdns_append_host_list_in_services(mdns_out_answer_t ** destination, mdns_srv_item_t * services[], size_t services_len, bool flush, bool bye) { + if (services == NULL) { + mdns_host_item_t * host = mdns_get_host_item(_mdns_server->hostname); + if (host != NULL) { + return _mdns_append_host(destination, host, flush, bye); + } + return true; + } for (size_t i = 0; i < services_len; i++) { mdns_host_item_t *host = mdns_get_host_item(services[i]->service->hostname); if (!_mdns_append_host(destination, host, flush, bye)) { @@ -1542,6 +1549,44 @@ static bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, return true; } +static bool _mdns_append_host_question(mdns_out_question_t **questions, const char *hostname, bool unicast) +{ + mdns_out_question_t *q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t)); + if (!q) { + HOOK_MALLOC_FAILED; + return false; + } + q->next = NULL; + q->unicast = unicast; + q->type = MDNS_TYPE_ANY; + q->host = hostname; + q->service = NULL; + q->proto = NULL; + q->domain = MDNS_DEFAULT_DOMAIN; + q->own_dynamic_memory = false; + if (_mdns_question_exists(q, *questions)) { + free(q); + } else { + queueToEnd(mdns_out_question_t, *questions, q); + } + return true; +} + +static bool _mdns_append_host_questions_for_services(mdns_out_question_t **questions, mdns_srv_item_t *services[], + size_t len, bool unicast) +{ + if (!_str_null_or_empty(_mdns_server->hostname) && + !_mdns_append_host_question(questions, _mdns_server->hostname, unicast)) { + return false; + } + for (size_t i = 0; i < len; i++) { + if (!_mdns_append_host_question(questions, services[i]->service->hostname, unicast)) { + return false; + } + } + return true; +} + /** * @brief Create probe packet for particular services on particular PCB */ @@ -1582,26 +1627,9 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_ } if (include_ip) { - for (i = 0; i < len; i++) { - mdns_out_question_t * q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t)); - if (!q) { - HOOK_MALLOC_FAILED; - _mdns_free_tx_packet(packet); - return NULL; - } - q->next = NULL; - q->unicast = first; - q->type = MDNS_TYPE_ANY; - q->host = services[i]->service->hostname; - q->service = NULL; - q->proto = NULL; - q->domain = MDNS_DEFAULT_DOMAIN; - q->own_dynamic_memory = false; - if (_mdns_question_exists(q, packet->questions)) { - free(q); - } else { - queueToEnd(mdns_out_question_t, packet->questions, q); - } + if (!_mdns_append_host_questions_for_services(&packet->questions, services, len, first)) { + _mdns_free_tx_packet(packet); + return NULL; } if (!_mdns_append_host_list_in_services(&packet->servers, services, len, false, false)) { @@ -1613,23 +1641,6 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_ return packet; } -/** - * @brief Create announce packet for self IP addresses - */ -static mdns_tx_packet_t * _mdns_create_announce_self_ip(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) -{ - mdns_tx_packet_t * packet = _mdns_alloc_packet_default(tcpip_if, ip_protocol); - if (!packet) { - return NULL; - } - mdns_host_item_t * host = mdns_get_host_item(_mdns_server->hostname); - if (!_mdns_append_host(&packet->servers, host, true, false)) { - _mdns_free_tx_packet(packet); - return NULL; - } - return packet; -} - /** * @brief Create announce packet for particular services on particular PCB */ @@ -1890,12 +1901,7 @@ static void _mdns_announce_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco } _pcb->state = PCB_ANNOUNCE_1; - mdns_tx_packet_t * p = NULL; - if (services != NULL) { - p = _mdns_create_announce_packet(tcpip_if, ip_protocol, services, len, include_ip); - } else { - p = _mdns_create_announce_self_ip(tcpip_if, ip_protocol); - } + mdns_tx_packet_t * p = _mdns_create_announce_packet(tcpip_if, ip_protocol, services, len, include_ip); if (p) { _mdns_schedule_tx_packet(p, 0); } @@ -2646,7 +2652,7 @@ static bool _mdns_name_is_ours(mdns_name_t * name) } //find the service - mdns_srv_item_t * service = _mdns_get_service_item(name->service, name->proto, name->host); + mdns_srv_item_t * service = _mdns_get_service_item(name->service, name->proto, NULL); if (!service) { return false; } @@ -3124,7 +3130,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) } else if (!name->sub && _mdns_name_is_ours(name)) { ours = true; if (name->service && name->service[0] && name->proto && name->proto[0]) { - service = _mdns_get_service_item(name->service, name->proto, name->host); + service = _mdns_get_service_item(name->service, name->proto, NULL); } } else { if (!parsed_packet->authoritative || record_type == MDNS_NS) { @@ -3142,7 +3148,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) _mdns_search_result_add_ptr(search_result, name->host, packet->tcpip_if, packet->ip_protocol); } else if ((discovery || ours) && !name->sub && _mdns_name_is_ours(name)) { if (discovery) { - service = _mdns_get_service_item(name->service, name->proto, name->host); + service = _mdns_get_service_item(name->service, name->proto, NULL); _mdns_remove_parsed_question(parsed_packet, MDNS_TYPE_SDPTR, service); } else if (parsed_packet->questions && !parsed_packet->probe) { _mdns_remove_parsed_question(parsed_packet, type, service); diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index 4b8f8806c7..3851c4694c 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -215,7 +215,7 @@ typedef struct { } mdns_header_t; typedef struct { - char host[MDNS_NAME_BUF_LEN]; + char host[MDNS_NAME_BUF_LEN]; // hostname for A/AAAA records, instance name for SRV records char service[MDNS_NAME_BUF_LEN]; char proto[MDNS_NAME_BUF_LEN]; char domain[MDNS_NAME_BUF_LEN]; diff --git a/examples/protocols/mdns/sdkconfig.ci b/examples/protocols/mdns/sdkconfig.ci index 42c55b8c0a..0587c0624e 100644 --- a/examples/protocols/mdns/sdkconfig.ci +++ b/examples/protocols/mdns/sdkconfig.ci @@ -1,3 +1,4 @@ CONFIG_MDNS_RESOLVE_TEST_SERVICES=y CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y +CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y From a4f263948c35c13340b6f4b59a649c5073787d5e Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Tue, 11 May 2021 13:47:03 +0800 Subject: [PATCH 9/9] mdns: fix test script delayed response --- components/mdns/mdns.c | 40 ++++++++----------- .../protocols/mdns/main/mdns_example_main.c | 21 +++++----- examples/protocols/mdns/mdns_example_test.py | 32 +++++++++------ 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 0bb56ecd6c..fe2c2f85f1 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -160,6 +160,7 @@ static bool _mdns_service_match(const mdns_service_t * srv, const char * service * @param server the server * @param service service type to match * @param proto proto to match + * @param hostname hostname of the service (if non-null) * * @return the service item if found or NULL on error */ @@ -177,7 +178,7 @@ static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char static mdns_host_item_t * mdns_get_host_item(const char * hostname) { - if (hostname == NULL || strcasecmp(hostname, _mdns_server->hostname) == 0) { + if (strcasecmp(hostname, _mdns_server->hostname) == 0) { return &_mdns_self_host; } mdns_host_item_t * host = _mdns_host_list; @@ -1122,22 +1123,14 @@ static void _mdns_free_tx_packet(mdns_tx_packet_t * packet) if (!packet) { return; } - mdns_out_question_t *q = packet->questions; + mdns_out_question_t * q = packet->questions; while (q) { - mdns_out_question_t *next = q->next; + mdns_out_question_t * next = q->next; if (q->own_dynamic_memory) { - if (q->host) { - free((char *)q->host); - } - if (q->service) { - free((char *)q->service); - } - if (q->proto) { - free((char *)q->proto); - } - if (q->domain) { - free((char *)q->domain); - } + free((char *)q->host); + free((char *)q->service); + free((char *)q->proto); + free((char *)q->domain); } free(q); q = next; @@ -4870,7 +4863,8 @@ esp_err_t mdns_instance_name_set(const char * instance) esp_err_t mdns_service_add_for_host(const char * instance, const char * service, const char * proto, const char * hostname, uint16_t port, mdns_txt_item_t txt[], size_t num_items) { - if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) { + if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(hostname) || + !port) { return ESP_ERR_INVALID_ARG; } @@ -4930,7 +4924,7 @@ esp_err_t mdns_service_add_for_host(const char * instance, const char * service, esp_err_t mdns_service_add(const char * instance, const char * service, const char * proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items) { - if (!_mdns_server) { + if (!_mdns_server || _str_null_or_empty(_mdns_server->hostname)) { return ESP_ERR_INVALID_STATE; } return mdns_service_add_for_host(instance, service, proto, _mdns_server->hostname, port, txt, num_items); @@ -5405,7 +5399,7 @@ void mdns_debug_packet(const uint8_t * data, size_t len) header.answers = 0; header.additional = 0; header.servers = 0; - _mdns_dbg_printf("ERROR: %s:%u\n", __FILE__, __LINE__); + _mdns_dbg_printf("ERROR: parse header questions\n"); break; } @@ -5453,7 +5447,7 @@ void mdns_debug_packet(const uint8_t * data, size_t len) content = _mdns_parse_fqdn(data, content, name); if (!content) { - _mdns_dbg_printf("ERROR: %s:%u\n", __FILE__, __LINE__); + _mdns_dbg_printf("ERROR: parse mdns records\n"); break; } @@ -5467,7 +5461,7 @@ void mdns_debug_packet(const uint8_t * data, size_t len) content = data_ptr + data_len; if (content > (data + len)) { - _mdns_dbg_printf("ERROR: %s:%u\n", __FILE__, __LINE__); + _mdns_dbg_printf("ERROR: content length overflow\n"); break; } @@ -5520,13 +5514,13 @@ void mdns_debug_packet(const uint8_t * data, size_t len) _mdns_dbg_printf("[%u] ", data_len); if (type == MDNS_TYPE_PTR) { if (!_mdns_parse_fqdn(data, data_ptr, name)) { - _mdns_dbg_printf("ERROR: %s:%u\n", __FILE__, __LINE__); + _mdns_dbg_printf("ERROR: parse PTR\n"); continue; } _mdns_dbg_printf("%s.%s.%s.%s.\n", name->host, name->service, name->proto, name->domain); } else if (type == MDNS_TYPE_SRV) { if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name)) { - _mdns_dbg_printf("ERROR: %s:%u\n", __FILE__, __LINE__); + _mdns_dbg_printf("ERROR: parse SRV\n"); continue; } uint16_t priority = _mdns_read_u16(data_ptr, MDNS_SRV_PRIORITY_OFFSET); @@ -5538,7 +5532,7 @@ void mdns_debug_packet(const uint8_t * data, size_t len) while (i < data_len) { uint8_t partLen = data_ptr[i++]; if ((i+partLen) > data_len) { - _mdns_dbg_printf("ERROR: %s:%u\n", __FILE__, __LINE__); + _mdns_dbg_printf("ERROR: parse TXT\n"); break; } char txt[partLen+1]; diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index 244ac41567..f8641197b6 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -9,6 +9,7 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_netif_ip_addr.h" #include "esp_system.h" #include "esp_event.h" #include "esp_log.h" @@ -33,10 +34,8 @@ static void query_mdns_host_with_getaddrinfo(char * host); static void initialise_mdns(void) { - char *hostname = generate_hostname(); - char delegated_hostname[64]; + char * hostname = generate_hostname(); - snprintf(delegated_hostname, sizeof(delegated_hostname), "%s-delegated", hostname); //initialize mDNS ESP_ERROR_CHECK( mdns_init() ); //set mDNS hostname (required if you want to advertise services) @@ -56,19 +55,21 @@ static void initialise_mdns(void) ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3) ); #if CONFIG_MDNS_PUBLISH_DELEGATE_HOST + char *delegated_hostname; + if (-1 == asprintf(&delegated_hostname, "%s-delegated", hostname)) { + abort(); + } + mdns_ip_addr_t addr4, addr6; - ip4_addr_t ip4_addr; - ip6_addr_t ip6_addr; - ip4addr_aton("10.0.0.1", &ip4_addr); // mock address - addr4.addr.u_addr.ip4.addr = ip4_addr.addr; + esp_netif_str_to_ip4("10.0.0.1", &addr4.addr.u_addr.ip4); addr4.addr.type = ESP_IPADDR_TYPE_V4; - addr4.next = &addr6; - ip6addr_aton("fd11:22::1", &ip6_addr); // mock address - memcpy(addr6.addr.u_addr.ip6.addr, ip6_addr.addr, sizeof(ip6_addr.addr)); + esp_netif_str_to_ip6("fd11:22::1", &addr6.addr.u_addr.ip6); addr6.addr.type = ESP_IPADDR_TYPE_V6; + addr4.next = &addr6; addr6.next = NULL; ESP_ERROR_CHECK( mdns_delegate_hostname_add(delegated_hostname, &addr4) ); ESP_ERROR_CHECK( mdns_service_add_for_host("test0", "_http", "_tcp", delegated_hostname, 1234, serviceTxtData, 3) ); + free(delegated_hostname); #endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST //add another TXT item diff --git a/examples/protocols/mdns/mdns_example_test.py b/examples/protocols/mdns/mdns_example_test.py index 26295d6a78..5bbae2111d 100644 --- a/examples/protocols/mdns/mdns_example_test.py +++ b/examples/protocols/mdns/mdns_example_test.py @@ -1,5 +1,6 @@ import os import re +import select import socket import struct import subprocess @@ -10,6 +11,7 @@ import dpkt import dpkt.dns import ttfw_idf from tiny_test_fw import DUT +from tiny_test_fw.Utility import console_log stop_mdns_server = Event() esp_answered = Event() @@ -19,7 +21,7 @@ esp_delegated_answered = Event() def get_dns_query_for_esp(esp_host): dns = dpkt.dns.DNS(b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01') dns.qd[0].name = esp_host + u'.local' - print('Created query for esp host: {} '.format(dns.__repr__())) + console_log('Created query for esp host: {} '.format(dns.__repr__())) return dns.pack() @@ -33,7 +35,7 @@ def get_dns_answer_to_mdns(tester_host): arr.name = tester_host arr.ip = socket.inet_aton('127.0.0.1') dns. an.append(arr) - print('Created answer to mdns query: {} '.format(dns.__repr__())) + console_log('Created answer to mdns query: {} '.format(dns.__repr__())) return dns.pack() @@ -57,35 +59,41 @@ def mdns_server(esp_host): MCAST_GRP = '224.0.0.251' TESTER_NAME = u'tinytester.local' TESTER_NAME_LWIP = u'tinytester-lwip.local' + QUERY_TIMEOUT = 0.2 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + sock.setblocking(False) sock.bind((UDP_IP,UDP_PORT)) mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY) sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) - sock.settimeout(30) + last_query_timepoint = time.time() while not stop_mdns_server.is_set(): try: - if not esp_answered.is_set(): + current_time = time.time() + if not esp_answered.is_set() and current_time - last_query_timepoint > QUERY_TIMEOUT: sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP,UDP_PORT)) - time.sleep(0.2) sock.sendto(get_dns_query_for_esp(esp_host + '-delegated'), (MCAST_GRP,UDP_PORT)) - time.sleep(0.2) + last_query_timepoint = current_time + timeout = max(0, QUERY_TIMEOUT - (current_time - last_query_timepoint)) + read_socks, _, _ = select.select([sock], [], [], timeout) + if not read_socks: + continue data, addr = sock.recvfrom(1024) dns = dpkt.dns.DNS(data) if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A: if dns.qd[0].name == TESTER_NAME: - print('Received query: {} '.format(dns.__repr__())) + console_log('Received query: {} '.format(dns.__repr__())) sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), (MCAST_GRP,UDP_PORT)) elif dns.qd[0].name == TESTER_NAME_LWIP: - print('Received query: {} '.format(dns.__repr__())) + console_log('Received query: {} '.format(dns.__repr__())) sock.sendto(get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), addr) if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A: if dns.an[0].name == esp_host + u'.local': - print('Received answer to esp32-mdns query: {}'.format(dns.__repr__())) + console_log('Received answer to esp32-mdns query: {}'.format(dns.__repr__())) esp_answered.set() if dns.an[0].name == esp_host + u'-delegated.local': - print('Received answer to esp32-mdns-delegate query: {}'.format(dns.__repr__())) + console_log('Received answer to esp32-mdns-delegate query: {}'.format(dns.__repr__())) esp_delegated_answered.set() except socket.timeout: break @@ -117,7 +125,7 @@ def test_examples_protocol_mdns(env, extra_data): thread1.start() try: ip_address = dut1.expect(re.compile(r' sta ip: ([^,]+),'), timeout=30)[0] - print('Connected to AP with IP: {}'.format(ip_address)) + console_log('Connected to AP with IP: {}'.format(ip_address)) except DUT.ExpectTimeout: stop_mdns_server.set() thread1.join() @@ -135,7 +143,7 @@ def test_examples_protocol_mdns(env, extra_data): # 5. check the DUT answers to `dig` command dig_output = subprocess.check_output(['dig', '+short', '-p', '5353', '@224.0.0.251', '{}.local'.format(specific_host)]) - print('Resolving {} using "dig" succeeded with:\n{}'.format(specific_host, dig_output)) + console_log('Resolving {} using "dig" succeeded with:\n{}'.format(specific_host, dig_output)) if not ip_address.encode('utf-8') in dig_output: raise ValueError('Test has failed: Incorrectly resolved DUT hostname using dig' "Output should've contained DUT's IP address:{}".format(ip_address))