From 418fb60dd926f1c8dd3ea1df9aa7086ff5277130 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Thu, 15 Apr 2021 20:03:53 +0800 Subject: [PATCH] mdns: fix mdns probe/reply behavior * send correct hostnames when probing. * add test for mdns host delegation. * Original commit: espressif/esp-idf@d2a5d25984432d149ca31aea4a0d177f3509dd7b --- 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 e72dce5ae..305ba734f 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 2b99f2d4c..e6644d5e5 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 c4ae7e13b..ca2f2bbf3 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 ecdb47e4e..244ac4156 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 201acb569..26295d6a7 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)