diff --git a/tools/test_apps/protocols/mdns/CMakeLists.txt b/tools/test_apps/protocols/mdns/CMakeLists.txt new file mode 100644 index 000000000..e756f2b40 --- /dev/null +++ b/tools/test_apps/protocols/mdns/CMakeLists.txt @@ -0,0 +1,11 @@ +# The following four lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +# (Not part of the boilerplate) +# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(mdns) diff --git a/tools/test_apps/protocols/mdns/README.md b/tools/test_apps/protocols/mdns/README.md new file mode 100644 index 000000000..40ae127fe --- /dev/null +++ b/tools/test_apps/protocols/mdns/README.md @@ -0,0 +1,48 @@ +| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 | +| ----------------- | ----- | -------- | -------- | + +# mDNS test project + +Main purpose of this application is to test the mDNS library to correctly advertise, lookup services and hosts. +The "app_test.py" logically separated from two sets of test cases 1. "ESP32 board sends queries -> Host sends answers" and 2. "Host sends queries" -> "ESP32 board sends answers". +Two first sets of test cases are starting by 'test_query_' and the second ones by 'start_case'. + +## Runtime settings + +1. For first sets of test cases python creates and sends dns queries using "dpkt" library +2. For the second sets of test cases this app waits for user input to provide test case(e.g. CONFIG_TEST_QUERY_HOST, CONFIG_TEST_QUERY_HOST_ASYNC or CONFIG_TEST_QUERY_SERVICE) +In order to run both of them just needed to set up the project and run by 'python app_test.py' + +## Test app workflow + +- mDNS is initialized with hostname 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 tries to connect to the access point defined through the project configuration + +### Configure the project + +* Open the project configuration menu (`idf.py menuconfig`) + +* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](README.md) for more details. +* Set `mDNS Hostname` as host name prefix for the device and its instance name in `mDNS Instance Name` + +### Build and Flash + +Build the project and flash it to the board, then run the monitor tool to view the serial output: + +``` +idf.py -p PORT flash monitor +``` + +- Wait for WiFi to connect to your access point +- You can now ping the device at `[board-hostname].local`, where `[board-hostname]` is preconfigured hostname, `esp32-mdns` by default. +- You can also browse for `_http._tcp` on the same network to find the advertised service +- Note that for purpose of CI tests, configuration options of `MDNS_RESOLVE_TEST_SERVICES` and `MDNS_ADD_MAC_TO_HOSTNAME` are available, but disabled by default. If enabled, then the hostname suffix of last 3 bytes from device MAC address is added, e.g. `esp32-mdns-80FFFF`, and a query for test service is issued. + + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Hardware Required +This test-app can be executed on any ESP32 board, the only required interface is WiFi and connection to a local network and tls server. diff --git a/tools/test_apps/protocols/mdns/app_test.py b/tools/test_apps/protocols/mdns/app_test.py new file mode 100644 index 000000000..043e4622b --- /dev/null +++ b/tools/test_apps/protocols/mdns/app_test.py @@ -0,0 +1,268 @@ +# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +import re +import select +import socket +import struct +import time +from threading import Event, Thread + +import dpkt +import dpkt.dns +import ttfw_idf +from tiny_test_fw.Utility import console_log + +UDP_PORT = 5353 +MCAST_GRP = '224.0.0.251' + +# This service is created from esp board startup +SERVICE_NAME = u'ESP32-WebServer._http._tcp.local' +SUB_SERVICE_NAME = u'_server._sub._http._tcp.local' + +# This host name answer sent by host, when there is query from board +HOST_NAME = u'tinytester.local' + +# This servce answer sent by host, when there is query from board +MDNS_HOST_SERVICE = u'ESP32._http._tcp.local' + +stop_mdns_listener = Event() +start_mdns_listener = Event() +esp_service_answered = Event() +esp_sub_service_answered = Event() +esp_host_answered = Event() +esp_delegated_host_answered = Event() + + +# Get query of ESP32-WebServer._http._tcp.local service +def get_mdns_service_query(service): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA + dns.rcode = dpkt.dns.DNS_RCODE_NOERR + arr = dpkt.dns.DNS.RR() + arr.cls = dpkt.dns.DNS_IN + arr.type = dpkt.dns.DNS_SRV + arr.name = service + arr.target = socket.inet_aton('127.0.0.1') + arr.srvname = service + dns.qd.append(arr) + console_log('Created mdns service query: {} '.format(dns.__repr__())) + return dns.pack() + + +# Get query of _server_.sub._http._tcp.local sub service +def get_mdns_sub_service_query(sub_service): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA + dns.rcode = dpkt.dns.DNS_RCODE_NOERR + arr = dpkt.dns.DNS.RR() + arr.cls = dpkt.dns.DNS_IN + arr.type = dpkt.dns.DNS_PTR + arr.name = sub_service + arr.target = socket.inet_aton('127.0.0.1') + arr.ptrname = sub_service + dns.qd.append(arr) + console_log('Created mdns subtype service query: {} '.format(dns.__repr__())) + return dns.pack() + + +# Get query for host resolution +def get_dns_query_for_esp(esp_host): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + arr = dpkt.dns.DNS.RR() + arr.cls = dpkt.dns.DNS_IN + arr.name = esp_host + u'.local' + dns.qd.append(arr) + console_log('Created query for esp host: {} '.format(dns.__repr__())) + return dns.pack() + + +# Get mdns answer for host resoloution +def get_dns_answer_to_mdns(tester_host): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA + dns.rcode = dpkt.dns.DNS_RCODE_NOERR + arr = dpkt.dns.DNS.RR() + arr.cls = dpkt.dns.DNS_IN + arr.type = dpkt.dns.DNS_A + arr.name = tester_host + arr.ip = socket.inet_aton('127.0.0.1') + dns. an.append(arr) + console_log('Created answer to mdns query: {} '.format(dns.__repr__())) + return dns.pack() + + +# Get mdns answer for service query +def get_dns_answer_to_service_query(mdns_service): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA + dns.rcode = dpkt.dns.DNS_RCODE_NOERR + arr = dpkt.dns.DNS.RR() + arr.name = mdns_service + arr.cls = dpkt.dns.DNS_IN + arr.type = dpkt.dns.DNS_SRV + arr.priority = 0 + arr.weight = 0 + arr.port = 100 + arr.srvname = mdns_service + arr.ip = socket.inet_aton('127.0.0.1') + dns. an.append(arr) + console_log('Created answer to mdns query: {} '.format(dns.__repr__())) + return dns.pack() + + +def mdns_listener(esp_host): # type:(str) -> None + print('mdns_listener thread started') + + UDP_IP = '0.0.0.0' + 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) + last_query_timepoint = time.time() + QUERY_TIMEOUT = 0.2 + while not stop_mdns_listener.is_set(): + try: + start_mdns_listener.set() + current_time = time.time() + if current_time - last_query_timepoint > QUERY_TIMEOUT: + 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, _ = sock.recvfrom(1024) + dns = dpkt.dns.DNS(data) + if len(dns.qd) > 0: + if dns.qd[0].name == HOST_NAME: + console_log('Received query: {} '.format(dns.__repr__())) + sock.sendto(get_dns_answer_to_mdns(HOST_NAME), (MCAST_GRP,UDP_PORT)) + if dns.qd[0].name == HOST_NAME: + console_log('Received query: {} '.format(dns.__repr__())) + sock.sendto(get_dns_answer_to_mdns(HOST_NAME), (MCAST_GRP,UDP_PORT)) + if dns.qd[0].name == MDNS_HOST_SERVICE: + print(dns.qd[0].name) + console_log('Received query: {} '.format(dns.__repr__())) + sock.sendto(get_dns_answer_to_service_query(MDNS_HOST_SERVICE), (MCAST_GRP,UDP_PORT)) + if len(dns.an) == 1: + if dns.an[0].name == SERVICE_NAME: + console_log('Received answer to service query: {}'.format(dns.__repr__())) + esp_service_answered.set() + if len(dns.an) > 1: + if dns.an[1].name == SUB_SERVICE_NAME: + console_log('Received answer for sub service query: {}'.format(dns.__repr__())) + esp_sub_service_answered.set() + if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A: + if dns.an[0].name == esp_host + u'.local': + console_log('Received answer to esp32-mdns query: {}'.format(dns.__repr__())) + esp_host_answered.set() + if dns.an[0].name == esp_host + u'-delegated.local': + console_log('Received answer to esp32-mdns-delegate query: {}'.format(dns.__repr__())) + esp_delegated_host_answered.set() + except socket.timeout: + break + except dpkt.UnpackError: + continue + + +def create_socket(): # type:() -> socket.socket + UDP_IP = '0.0.0.0' + 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) + return sock + + +def test_query_dns_http_service(service): # type: (str) -> None + print('SRV: Query {}'.format(service)) + sock = create_socket() + sock.sendto(get_mdns_service_query(service), (MCAST_GRP,UDP_PORT)) + if not esp_service_answered.wait(timeout=25): + raise ValueError('Test has failed: did not receive mdns answer within timeout') + + +def test_query_dns_sub_service(sub_service): # type: (str) -> None + print('PTR: Query {}'.format(sub_service)) + sock = create_socket() + sock.sendto(get_mdns_sub_service_query(sub_service), (MCAST_GRP,UDP_PORT)) + if not esp_sub_service_answered.wait(timeout=25): + raise ValueError('Test has failed: did not receive mdns answer within timeout') + + +def test_query_dns_host(esp_host): # type: (str) -> None + print('A: {}'.format(esp_host)) + sock = create_socket() + sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP,UDP_PORT)) + if not esp_host_answered.wait(timeout=25): + raise ValueError('Test has failed: did not receive mdns answer within timeout') + + +def test_query_dns_host_delegated(esp_host): # type: (str) -> None + print('A: {}'.format(esp_host)) + sock = create_socket() + sock.sendto(get_dns_query_for_esp(esp_host + '-delegated'), (MCAST_GRP,UDP_PORT)) + if not esp_delegated_host_answered.wait(timeout=25): + raise ValueError('Test has failed: did not receive mdns answer within timeout') + + +@ttfw_idf.idf_custom_test(env_tag='Example_WIFI', group='test-apps') +def test_app_esp_mdns(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None + dut1 = env.get_dut('mdns', 'tools/test_apps/protocols/mdns', dut_class=ttfw_idf.ESP32DUT) + + # 1. start mdns application + dut1.start_app() + # 2. get the dut host name (and IP address) + specific_host = dut1.expect(re.compile(r'mdns hostname set to: \[([^\]]+)\]'), timeout=30)[0] + + esp_ip = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30) + print('Got IP={}'.format(esp_ip[0])) + + mdns_responder = Thread(target=mdns_listener, args=(str(specific_host),)) + + def start_case(case, desc, result): # type: (str, str, str) -> None + print('Starting {}: {}'.format(case, desc)) + dut1.write(case) + dut1.expect(re.compile(result), timeout=10) + + try: + # start dns listener thread + mdns_responder.start() + + # wait untill mdns listener thred started + if not start_mdns_listener.wait(timeout=5): + raise ValueError('Test has failed: mdns listener thread did not start') + + # query dns service from host, answer should be received from esp board + test_query_dns_http_service(SERVICE_NAME) + + # query dns sub-service from host, answer should be received from esp board + test_query_dns_sub_service(SUB_SERVICE_NAME) + + # query dns host name, answer should be received from esp board + test_query_dns_host(specific_host) + + # query dns host name delegated, answer should be received from esp board + test_query_dns_host_delegated(specific_host) + + # query dns-host from esp board, answer should be received from host + start_case('CONFIG_TEST_QUERY_HOST', 'Query tinytester.local', 'tinytester.local resolved to: 127.0.0.1') + + # query dns-host aynchrounusely from esp board, answer should be received from host + start_case('CONFIG_TEST_QUERY_HOST_ASYNC', 'Query tinytester.local async', 'Async query resolved to A:127.0.0.1') + + # query service from esp board, answer should be received from host + start_case('CONFIG_TEST_QUERY_SERVICE', 'Query SRV ESP32._http._tcp.local', 'SRV:ESP32') + finally: + stop_mdns_listener.set() + mdns_responder.join() + + +if __name__ == '__main__': + test_app_esp_mdns() diff --git a/tools/test_apps/protocols/mdns/main/CMakeLists.txt b/tools/test_apps/protocols/mdns/main/CMakeLists.txt new file mode 100644 index 000000000..b5902d589 --- /dev/null +++ b/tools/test_apps/protocols/mdns/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" "mdns_test.c" + INCLUDE_DIRS ".") diff --git a/tools/test_apps/protocols/mdns/main/Kconfig.projbuild b/tools/test_apps/protocols/mdns/main/Kconfig.projbuild new file mode 100644 index 000000000..d5d791a70 --- /dev/null +++ b/tools/test_apps/protocols/mdns/main/Kconfig.projbuild @@ -0,0 +1,28 @@ +menu "Example Configuration" + + config TEST_MDNS_HOSTNAME + string "mDNS Hostname" + default "esp32-mdns" + help + mDNS Hostname for example to use + + config TEST_MDNS_INSTANCE + string "mDNS Instance Name" + default "ESP32 with mDNS" + help + mDNS Instance Name for example to use + + config TEST_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 TEST_MDNS_ADD_MAC_TO_HOSTNAME + bool "Add mac suffix to hostname" + default n + help + If enabled, a portion of MAC address is added to the hostname, this is used + for evaluation of tests in CI + +endmenu diff --git a/tools/test_apps/protocols/mdns/main/main.c b/tools/test_apps/protocols/mdns/main/main.c new file mode 100644 index 000000000..cb647aa54 --- /dev/null +++ b/tools/test_apps/protocols/mdns/main/main.c @@ -0,0 +1,117 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_log.h" +#include "protocol_examples_common.h" +#include "mdns.h" + +static const char *TAG = "MDNS_TEST"; +void mdns_test(char *line); + +static void get_string(char *line, size_t size) +{ + int count = 0; + while (count < size) { + int c = fgetc(stdin); + if (c == '\n') { + line[count] = '\0'; + break; + } else if (c > 0 && c < 127) { + line[count] = c; + ++count; + } + vTaskDelay(50 / portTICK_PERIOD_MS); + } +} + +/** 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) +{ +#ifndef CONFIG_TEST_MDNS_ADD_MAC_TO_HOSTNAME + return strdup(CONFIG_TEST_MDNS_HOSTNAME); +#else + uint8_t mac[6]; + char *hostname; + esp_read_mac(mac, ESP_MAC_WIFI_STA); + if (-1 == asprintf(&hostname, "%s-%02X%02X%02X", CONFIG_TEST_MDNS_HOSTNAME, mac[3], mac[4], mac[5])) { + abort(); + } + return hostname; +#endif +} + +static void initialise_mdns(void) +{ + char * hostname = generate_hostname(); + + //initialize mDNS + ESP_ERROR_CHECK( mdns_init() ); + + //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 + ESP_ERROR_CHECK( mdns_instance_name_set(CONFIG_TEST_MDNS_INSTANCE) ); + + //initialize service + ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, NULL, 0) ); + +#if CONFIG_TEST_MDNS_PUBLISH_DELEGATE_HOST + char *delegated_hostname; + if (-1 == asprintf(&delegated_hostname, "%s-delegated", hostname)) { + abort(); + } + + mdns_ip_addr_t addr4, addr6; + esp_netif_str_to_ip4("10.0.0.1", &addr4.addr.u_addr.ip4); + addr4.addr.type = ESP_IPADDR_TYPE_V4; + 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, NULL, 0) ); + free(delegated_hostname); +#endif // CONFIG_TEST_MDNS_PUBLISH_DELEGATE_HOST + + ESP_ERROR_CHECK( mdns_service_subtype_add_for_host("ESP32-WebServer", "_http", "_tcp", NULL, "_server") ); + + free(hostname); +} + +void app_main(void) +{ + char line[256]; + + ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); + ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); + + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + initialise_mdns(); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + + while (1) { + get_string(line, sizeof(line)); + mdns_test(line); + continue; + } +} diff --git a/tools/test_apps/protocols/mdns/main/mdns_test.c b/tools/test_apps/protocols/mdns/main/mdns_test.c new file mode 100644 index 000000000..545988516 --- /dev/null +++ b/tools/test_apps/protocols/mdns/main/mdns_test.c @@ -0,0 +1,166 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "mdns.h" +#include "esp_log.h" +#include "esp_netif.h" + +static const char * TAG = "MDNS_TEST_APP"; + +static void mdns_print_results(mdns_result_t *results) +{ + mdns_result_t *r = results; + mdns_ip_addr_t *a = NULL; + int t; + while (r) { + if (r->instance_name) { + printf("PTR:%s.%s.%s\n", r->instance_name, r->service_type, r->proto); + } + if (r->hostname) { + printf("SRV:%s.local:%u\n", r->hostname, r->port); + } + if (r->txt_count) { + printf("TXT:[%zu] ", r->txt_count); + for (t = 0; t < r->txt_count; t++) { + printf("%s=%s(%d); ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL", r->txt_value_len[t]); + } + printf("\n"); + } + a = r->addr; + 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))); + } + a = a->next; + } + r = r->next; + } +} + +static bool check_and_print_result(mdns_search_once_t *search) +{ + // Check if any result is available + mdns_result_t * result = NULL; + if (!mdns_query_async_get_results(search, 0, &result)) { + return false; + } + + if (!result) { // search timeout, but no result + return true; + } + + // If yes, print the result + mdns_ip_addr_t * a = result->addr; + while (a) { + if(a->addr.type == ESP_IPADDR_TYPE_V6){ + printf("Async query resolved to AAAA:" IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); + } else { + printf("Async query resolved to A:" IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); + } + a = a->next; + } + // and free the result + mdns_query_results_free(result); + return true; +} + +static void query_mdns_hosts_async(const char * host_name) +{ + ESP_LOGI(TAG, "Query both A and AAA: %s.local", host_name); + + mdns_search_once_t *s_a = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_A, 1000, 1, NULL); + mdns_query_async_delete(s_a); + mdns_search_once_t *s_aaaa = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_AAAA, 1000, 1, NULL); + while (s_a || s_aaaa) { + if (s_a && check_and_print_result(s_a)) { + ESP_LOGI(TAG, "Query A %s.local finished", host_name); + mdns_query_async_delete(s_a); + s_a = NULL; + } + if (s_aaaa && check_and_print_result(s_aaaa)) { + ESP_LOGI(TAG, "Query AAAA %s.local finished", host_name); + mdns_query_async_delete(s_aaaa); + s_aaaa = NULL; + } + } +} + +static void query_mdns_host(const char * host_name) +{ + ESP_LOGI(TAG, "Query A: %s.local", host_name); + + struct esp_ip4_addr addr; + addr.addr = 0; + + esp_err_t err = mdns_query_a(host_name, 2000, &addr); + if(err){ + if(err == ESP_ERR_NOT_FOUND){ + ESP_LOGW(TAG, "%s: Host was not found!", esp_err_to_name(err)); + return; + } + ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); + return; + } + + ESP_LOGI(TAG, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr)); +} + +static void query_mdns_service(const char * instance, const char * service_name, const char * proto) +{ + ESP_LOGI(TAG, "Query SRV: %s.%s.local", service_name, proto); + + mdns_result_t * results = NULL; + esp_err_t err = mdns_query_srv(instance, service_name, proto, 3000, &results); + if(err){ + ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); + return; + } + if(!results){ + ESP_LOGW(TAG, "No results found!"); + return; + } + + mdns_print_results(results); + mdns_query_results_free(results); +} + +void query_mdns_service_sub_type(const char * subtype, const char * service_name, const char * proto) { + ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto); + + mdns_result_t * results = NULL; + esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results); + if(err){ + ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); + return; + } + if(!results){ + ESP_LOGW(TAG, "No results found!"); + return; + } + + mdns_print_results(results); + mdns_query_results_free(results); +} + +void mdns_test(const char *line) +{ + char test_case[32]; + + sscanf(line, "%s", test_case); + ESP_LOGI(TAG, "test case = %s", test_case); + + if (strcmp(test_case, "CONFIG_TEST_QUERY_HOST") == 0) { + query_mdns_host("tinytester"); + } else if (strcmp(test_case, "CONFIG_TEST_QUERY_HOST_ASYNC") == 0) { + query_mdns_hosts_async("tinytester"); + } else if (strcmp(test_case, "CONFIG_TEST_QUERY_SERVICE") == 0) { + query_mdns_service("ESP32", "_http", "_tcp"); + } else { + ESP_LOGE(TAG, "%s: No such test case", test_case); + } +} diff --git a/tools/test_apps/protocols/mdns/sdkconfig.defaults b/tools/test_apps/protocols/mdns/sdkconfig.defaults new file mode 100644 index 000000000..0c4ffe915 --- /dev/null +++ b/tools/test_apps/protocols/mdns/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_TEST_MDNS_ADD_MAC_TO_HOSTNAME=y +CONFIG_TEST_MDNS_PUBLISH_DELEGATE_HOST=y