Initial public release of the 2024A software.
This commit is contained in:
parent
7b9ad3edfd
commit
303e9e1dad
361 changed files with 60083 additions and 2 deletions
|
@ -0,0 +1,7 @@
|
|||
# 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)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
project(mdns_test_app)
|
49
managed_components/espressif__mdns/tests/test_apps/README.md
Normal file
49
managed_components/espressif__mdns/tests/test_apps/README.md
Normal file
|
@ -0,0 +1,49 @@
|
|||
| 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.
|
||||
|
||||
* 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.
|
|
@ -0,0 +1,2 @@
|
|||
idf_component_register(SRCS "main.c" "mdns_test.c"
|
||||
INCLUDE_DIRS ".")
|
|
@ -0,0 +1,40 @@
|
|||
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
|
||||
config 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
|
||||
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.
|
||||
|
||||
|
||||
endmenu
|
|
@ -0,0 +1,8 @@
|
|||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/mdns:
|
||||
version: "^1.0.0"
|
||||
override_path: "../../../"
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
117
managed_components/espressif__mdns/tests/test_apps/main/main.c
Normal file
117
managed_components/espressif__mdns/tests/test_apps/main/main.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_mac.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(20 / 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)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " 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) {
|
||||
char line[256];
|
||||
|
||||
get_string(line, sizeof(line));
|
||||
mdns_test(line);
|
||||
continue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "mdns.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
static const char *TAG = "mdns_test_app";
|
||||
static const int RETRY_COUNT = 10;
|
||||
|
||||
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, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!result) { // search timeout, but no result
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 bool query_mdns_hosts_async(const char *host_name)
|
||||
{
|
||||
ESP_LOGI(TAG, "Query both A and AAA: %s.local", host_name);
|
||||
bool res = false;
|
||||
|
||||
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;
|
||||
res = true;
|
||||
}
|
||||
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;
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static esp_err_t 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));
|
||||
}
|
||||
ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t 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 err;
|
||||
}
|
||||
if (!results) {
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
}
|
||||
|
||||
mdns_print_results(results);
|
||||
mdns_query_results_free(results);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
if (!results) {
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
}
|
||||
|
||||
mdns_print_results(results);
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
|
||||
void mdns_test(const char *line)
|
||||
{
|
||||
char test_case[32];
|
||||
int i = 0;
|
||||
const TickType_t xDelay = 1000 / portTICK_PERIOD_MS;
|
||||
|
||||
sscanf(line, "%s", test_case);
|
||||
ESP_LOGI(TAG, "test case = %s", test_case);
|
||||
|
||||
if (strcmp(test_case, "CONFIG_TEST_QUERY_HOST") == 0) {
|
||||
i = 0;
|
||||
while (query_mdns_host("tinytester") != ESP_OK && i != RETRY_COUNT) {
|
||||
query_mdns_host("tinytester");
|
||||
i++;
|
||||
vTaskDelay(xDelay);
|
||||
}
|
||||
} else if (strcmp(test_case, "CONFIG_TEST_QUERY_HOST_ASYNC") == 0) {
|
||||
i = 0;
|
||||
while (query_mdns_hosts_async("tinytester") == false && i != RETRY_COUNT) {
|
||||
query_mdns_hosts_async("tinytester");
|
||||
i++;
|
||||
vTaskDelay(xDelay);
|
||||
}
|
||||
} else if (strcmp(test_case, "CONFIG_TEST_QUERY_SERVICE") == 0) {
|
||||
i = 0;
|
||||
while (query_mdns_service("ESP32", "_http", "_tcp") != ESP_OK && i != RETRY_COUNT) {
|
||||
query_mdns_service("ESP32", "_http", "_tcp");
|
||||
i++;
|
||||
vTaskDelay(xDelay);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: No such test case", test_case);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,320 @@
|
|||
# SPDX-FileCopyrightText: 2022 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 pytest
|
||||
|
||||
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'
|
||||
|
||||
# Number of retries to receive mdns answear
|
||||
RETRY_COUNT = 10
|
||||
|
||||
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()
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
# 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)
|
||||
print('Created mdns service query: {} '.format(dns.__repr__()))
|
||||
return dns.pack()
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
# 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)
|
||||
print('Created mdns subtype service query: {} '.format(dns.__repr__()))
|
||||
return dns.pack()
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
# 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)
|
||||
print('Created query for esp host: {} '.format(dns.__repr__()))
|
||||
return dns.pack()
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
# 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)
|
||||
print('Created answer to mdns query: {} '.format(dns.__repr__()))
|
||||
return dns.pack()
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
# 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)
|
||||
print('Created answer to mdns query: {} '.format(dns.__repr__()))
|
||||
return dns.pack()
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
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)
|
||||
# Receives queries from esp board and sends answers
|
||||
if len(dns.qd) > 0:
|
||||
if dns.qd[0].name == HOST_NAME:
|
||||
print('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:
|
||||
print('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('Received query: {} '.format(dns.__repr__()))
|
||||
sock.sendto(
|
||||
get_dns_answer_to_service_query(MDNS_HOST_SERVICE),
|
||||
(MCAST_GRP, UDP_PORT))
|
||||
# Receives answers from esp board and sets event flags for python test cases
|
||||
if len(dns.an) == 1:
|
||||
if dns.an[0].name.startswith(SERVICE_NAME):
|
||||
print('Received answer to service query: {}'.format(
|
||||
dns.__repr__()))
|
||||
esp_service_answered.set()
|
||||
if len(dns.an) > 1:
|
||||
if dns.an[1].name.startswith(SUB_SERVICE_NAME):
|
||||
print('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':
|
||||
print('Received answer to esp32-mdns query: {}'.format(
|
||||
dns.__repr__()))
|
||||
esp_host_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_host_answered.set()
|
||||
except socket.timeout:
|
||||
break
|
||||
except dpkt.UnpackError:
|
||||
continue
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_query_dns_http_service(service): # type: (str) -> None
|
||||
print('SRV: Query {}'.format(service))
|
||||
sock = create_socket()
|
||||
packet = get_mdns_service_query(service)
|
||||
for _ in range(RETRY_COUNT):
|
||||
if esp_service_answered.wait(timeout=25):
|
||||
break
|
||||
sock.sendto(packet, (MCAST_GRP, UDP_PORT))
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'Test has failed: did not receive mdns answer within timeout')
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_query_dns_sub_service(sub_service): # type: (str) -> None
|
||||
print('PTR: Query {}'.format(sub_service))
|
||||
sock = create_socket()
|
||||
packet = get_mdns_sub_service_query(sub_service)
|
||||
for _ in range(RETRY_COUNT):
|
||||
if esp_sub_service_answered.wait(timeout=25):
|
||||
break
|
||||
sock.sendto(packet, (MCAST_GRP, UDP_PORT))
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'Test has failed: did not receive mdns answer within timeout')
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_query_dns_host(esp_host): # type: (str) -> None
|
||||
print('A: {}'.format(esp_host))
|
||||
sock = create_socket()
|
||||
packet = get_dns_query_for_esp(esp_host)
|
||||
for _ in range(RETRY_COUNT):
|
||||
if esp_host_answered.wait(timeout=25):
|
||||
break
|
||||
sock.sendto(packet, (MCAST_GRP, UDP_PORT))
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'Test has failed: did not receive mdns answer within timeout')
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
def test_query_dns_host_delegated(esp_host): # type: (str) -> None
|
||||
print('A: {}'.format(esp_host))
|
||||
sock = create_socket()
|
||||
packet = get_dns_query_for_esp(esp_host + '-delegated')
|
||||
for _ in range(RETRY_COUNT):
|
||||
if esp_delegated_host_answered.wait(timeout=25):
|
||||
break
|
||||
sock.sendto(packet, (MCAST_GRP, UDP_PORT))
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'Test has failed: did not receive mdns answer within timeout')
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.generic
|
||||
def test_app_esp_mdns(dut):
|
||||
|
||||
# 1. get the dut host name (and IP address)
|
||||
specific_host = dut.expect(
|
||||
re.compile(b'mdns hostname set to: \[([^\]]+)\]'), # noqa: W605
|
||||
timeout=30).group(1).decode()
|
||||
|
||||
esp_ip = dut.expect(
|
||||
re.compile(
|
||||
b' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), # noqa: W605
|
||||
timeout=30).group(1).decode()
|
||||
print('Got IP={}'.format(esp_ip))
|
||||
|
||||
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))
|
||||
dut.write(case)
|
||||
res = bytes(result, encoding='utf8')
|
||||
dut.expect(re.compile(res), timeout=30)
|
||||
|
||||
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 service from esp board, answer should be received from host
|
||||
start_case('CONFIG_TEST_QUERY_SERVICE',
|
||||
'Query SRV ESP32._http._tcp.local', 'SRV:ESP32')
|
||||
|
||||
# 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')
|
||||
|
||||
finally:
|
||||
stop_mdns_listener.set()
|
||||
mdns_responder.join()
|
|
@ -0,0 +1,13 @@
|
|||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
|
||||
CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
|
||||
CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
|
@ -0,0 +1,2 @@
|
|||
CONFIG_TEST_MDNS_ADD_MAC_TO_HOSTNAME=y
|
||||
CONFIG_TEST_MDNS_PUBLISH_DELEGATE_HOST=y
|
Loading…
Add table
Add a link
Reference in a new issue