From 1eb5df9780ffdcbda9e30a0931c548fe55abc9a2 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Tue, 30 Mar 2021 13:19:01 +0800 Subject: [PATCH] mdns: add mdns delegation This allows publishing mdns services for other devices. * Original commit: espressif/esp-idf@401ff56cc1ad1d11284143a348cc0c0e4a363e98 --- 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 22da2afab..dcf8972bd 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 11a495195..2a715fe30 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 d8d507413..b813c5b43 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 8f655fdad..fcad5eaa7 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; }