Compare commits

..

13 Commits

Author SHA1 Message Date
b9b4a75000 mdns: bump the component version to 1.0.8 2023-02-06 15:43:01 +01:00
cc259aa035 Merge pull request #203 from david-cermak/feat/mdns_reverse_query
feat(mdns): Add support for IPv4 reverse query
2023-02-03 15:21:38 +01:00
91134f10ff mdns: Make reverse query conditional per Kconfig
and auto-register reverse logical names
2023-02-02 10:32:01 +01:00
fb8a2f0198 fix(mdns): Host test with IDFv5.1 2023-02-02 10:31:01 +01:00
b87bef52e5 feat(mdns): Add support for IPv4 reverse query
Partially addresses https://github.com/espressif/esp-protocols/issues/101
2023-02-02 10:31:00 +01:00
28813148b2 Merge pull request #211 from gabsuren/websocket/add_new_api_esp_destroy_selected
websocket: Added new API `esp_websocket_client_destroy_on_exit` (IDF-6458)
2023-02-01 18:00:30 +04:00
ae38f27997 Merge pull request #206 from david-cermak/bugfix/mdns_unit_tests
fix(mdns): Make unit test executable with pytest
2023-02-01 12:28:52 +01:00
d0c9070715 fix(mdns): Remove strict mode as it's invalid
Strict mode was introduced to support "one-shot" queries (described in
RFC6762/sec5.1) that are sent by lwip or dig. It was incorrectly assumed
that responding to such queries violates the spec, as we have to repeat
queries in responces, which is forbidden in RFC6762/sec6. It is however
required to repeat query fields according to the Section 6.7. Legacy
Unicast Responses: "it MUST repeat the query ID and the question
given in the query message."
2023-01-31 16:06:52 +01:00
a8339e4618 fix(mdns): Allow setting instance name only after hostname set
Closes https://github.com/espressif/esp-protocols/issues/190
2023-01-31 16:06:52 +01:00
12cfcb5aed fix(mdns): Make unit test executable with pytest 2023-01-31 16:06:52 +01:00
2cfffb056e Merge pull request #214 from david-cermak/bugfix/modem_cxx_broken_components
fix(esp_modem): Fix cmux client compilation issue
2023-01-31 14:42:46 +01:00
0247926219 fix(mdns): AFL port layer per IDF-latest changes 2023-01-31 11:15:06 +01:00
f9b47900f2 websocket: Added new API esp_websocket_client_destroy_on_exit 2023-01-24 22:29:09 +04:00
48 changed files with 467 additions and 302 deletions

View File

@ -3,8 +3,8 @@ name: Host test
on: [push, pull_request]
jobs:
host_test:
name: Build and Test on Host
host_test_esp_modem:
name: esp-modem Build and Test on Host
runs-on: ubuntu-20.04
container: espressif/idf:release-v4.3
env:
@ -38,3 +38,26 @@ jobs:
if: always()
with:
files: esp-protocols/components/esp_modem/test/host_test/junit.xml
host_test_mdns:
name: mdns Build and Test on Host
runs-on: ubuntu-20.04
container: espressif/idf:latest
steps:
- name: Checkout esp-protocols
uses: actions/checkout@master
with:
path: esp-protocols
- name: Build and Test
shell: bash
run: |
apt-get update && apt-get install -y dnsutils gcc g++
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/host_test
idf.py build
./build/mdns_host.elf &
dig +short -p 5353 @224.0.0.251 myesp.local > ip.txt
cat ip.txt | xargs dig +short -p 5353 @224.0.0.251 -x
cat ip.txt

View File

@ -62,48 +62,30 @@ jobs:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2", "esp32c3"]
config: ["eth_custom_netif", "eth_def", "eth_no_ipv6", "eth_socket"]
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: components/mdns/examples
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }} for ${{ matrix.config }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
shell: bash
working-directory: ${{ env.TEST_DIR }}
working-directory: ${{ matrix.test.path }}
run: |
${IDF_PATH}/install.sh --enable-pytest
. ${IDF_PATH}/export.sh
rm -rf sdkconfig sdkconfig.defaults build build_${{ matrix.config }}
cat sdkconfig.ci.${{ matrix.config }} >> sdkconfig.defaults
idf.py set-target ${{ matrix.idf_target }}
idf.py build
mv build build_${{ matrix.config }}
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.config }}
working-directory: ${{ env.TEST_DIR }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd build_${{ matrix.config }}
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
for dir in `ls -d build_*`; do
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
zip -qur artifacts.zip $dir
done
- uses: actions/upload-artifact@v3
if: ${{ matrix.idf_target }} == "esp32"
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
path: |
${{ env.TEST_DIR }}/build_${{ matrix.config }}/bootloader/bootloader.bin
${{ env.TEST_DIR }}/build_${{ matrix.config }}/partition_table/partition-table.bin
${{ env.TEST_DIR }}/build_${{ matrix.config }}/*.bin
${{ env.TEST_DIR }}/build_${{ matrix.config }}/*.elf
${{ env.TEST_DIR }}/build_${{ matrix.config }}/flasher_args.json
${{ env.TEST_DIR }}/build_${{ matrix.config }}/config/sdkconfig.h
${{ env.TEST_DIR }}/build_${{ matrix.config }}/config/sdkconfig.json
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ matrix.test.path }}/artifacts.zip
if-no-files-found: error
build_asio:
@ -240,14 +222,12 @@ jobs:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
config: ["eth_custom_netif", "eth_def", "eth_no_ipv6", "eth_socket"]
name: Run mDNS Example Test on target
test: [ { app: example, path: "components/mdns/examples" }, { app: unit_test, path: "components/mdns/tests/unit_test" } ]
name: Run mDNS target tests
needs: build_mdns
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
env:
TEST_DIR: components/mdns/examples
# Skip running on forks since it won't have access to secrets
if: github.repository == 'espressif/esp-protocols'
steps:
@ -256,28 +236,27 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
path: ${{ env.TEST_DIR }}/build_${{ matrix.config }}
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ matrix.test.path }}/ci/
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
sudo apt-get install -y dnsutils
- name: Download Example Test to target ${{ matrix.config }}
run: |
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/mdns/examples/build_${{ matrix.config }}/flash_image.bin
- name: Run Example Test on target ${{ matrix.config }}
working-directory: components/mdns/examples
- name: Run ${{ matrix.test.app }} application on ${{ matrix.idf_target }}
working-directory: ${{ matrix.test.path }}
run: |
unzip ci/artifacts.zip -d ci
for dir in `ls -d ci/build_*`; do
rm -rf build sdkconfig.defaults
mv build_${{ matrix.config }} build
cat sdkconfig.ci.${{ matrix.config }} >> sdkconfig.defaults
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
mv $dir build
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
done
- uses: actions/upload-artifact@v3
if: always()
with:
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}
path: ${{ env.TEST_DIR }}/*.xml
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
path: ${{ matrix.test.path }}/*.xml
run-target-asio:
strategy:
@ -348,7 +327,6 @@ jobs:
idf.py set-target ${{ matrix.idf_target }}
idf.py build
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh ${GITHUB_WORKSPACE}/${TEST_DIR}/build
ls build
- uses: actions/upload-artifact@v3
with:
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}

View File

@ -4,4 +4,4 @@
# - flasher args
# - sdkconfigs (header and json)
# (Ignoring the command failure as it refuses to delete nonempty dirs)
find $1 ! -regex ".*/build/[^/]+.\(bin\|elf\)" -a ! -regex ".*\(bootloader\|partition-table\).bin" -a ! -name "flasher_args.json" -a ! -regex ".*/build/config/sdkconfig.\(h\|json\)" -delete || true
find $1 ! -regex ".*/build[^/]*/[^/]+.\(bin\|elf\)" -a ! -regex ".*\(bootloader\|partition-table\).bin" -a ! -name "flasher_args.json" -a ! -regex ".*/build[^/]*/config/sdkconfig.\(h\|json\)" -delete || true

View File

@ -115,6 +115,7 @@ struct esp_websocket_client {
int auto_reconnect;
bool run;
bool wait_for_pong_resp;
bool selected_for_destroying;
EventGroupHandle_t status_bits;
SemaphoreHandle_t lock;
char *rx_buffer;
@ -342,6 +343,26 @@ static esp_err_t esp_websocket_client_destroy_config(esp_websocket_client_handle
return ESP_OK;
}
static void destroy_and_free_resources(esp_websocket_client_handle_t client)
{
if (client->event_handle) {
esp_event_loop_delete(client->event_handle);
}
if (client->if_name) {
free(client->if_name);
}
esp_websocket_client_destroy_config(client);
esp_transport_list_destroy(client->transport_list);
vQueueDelete(client->lock);
free(client->tx_buffer);
free(client->rx_buffer);
if (client->status_bits) {
vEventGroupDelete(client->status_bits);
}
free(client);
client = NULL;
}
static esp_err_t set_websocket_transport_optional_settings(esp_websocket_client_handle_t client, const char *scheme)
{
esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, scheme);
@ -527,6 +548,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
client->reconnect_tick_ms = _tick_get_ms();
client->ping_tick_ms = _tick_get_ms();
client->wait_for_pong_resp = false;
client->selected_for_destroying = false;
int buffer_size = config->buffer_size;
if (buffer_size <= 0) {
@ -563,22 +585,16 @@ esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client)
if (client->run) {
esp_websocket_client_stop(client);
}
if (client->event_handle) {
esp_event_loop_delete(client->event_handle);
destroy_and_free_resources(client);
return ESP_OK;
}
esp_err_t esp_websocket_client_destroy_on_exit(esp_websocket_client_handle_t client)
{
if (client == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (client->if_name) {
free(client->if_name);
}
esp_websocket_client_destroy_config(client);
esp_transport_list_destroy(client->transport_list);
vQueueDelete(client->lock);
free(client->tx_buffer);
free(client->rx_buffer);
if (client->status_bits) {
vEventGroupDelete(client->status_bits);
}
free(client);
client = NULL;
client->selected_for_destroying = true;
return ESP_OK;
}
@ -833,6 +849,9 @@ static void esp_websocket_client_task(void *pv)
esp_transport_close(client->transport);
xEventGroupSetBits(client->status_bits, STOPPED_BIT);
client->state = WEBSOCKET_STATE_UNKNOW;
if (client->selected_for_destroying == true) {
destroy_and_free_resources(client);
}
vTaskDelete(NULL);
}

View File

@ -166,6 +166,18 @@ esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client);
*/
esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client);
/**
* @brief If this API called, WebSocket client will destroy and free all resources at the end of event loop.
*
* Notes:
* - After event loop finished, client handle would be dangling and should never be used
*
* @param[in] client The client
*
* @return esp_err_t
*/
esp_err_t esp_websocket_client_destroy_on_exit(esp_websocket_client_handle_t client);
/**
* @brief Write binary data to the WebSocket connection (data send with WS OPCODE=02, i.e. binary)
*

View File

@ -6,7 +6,7 @@ endif()
idf_build_get_property(target IDF_TARGET)
if(${target} STREQUAL "linux")
set(dependencies esp_system_protocols_linux)
set(dependencies esp_event esp_netif_linux esp_timer_linux esp_system)
set(srcs "mdns.c" ${MDNS_NETWORKING})
else()
set(dependencies lwip console esp_netif)
@ -22,6 +22,11 @@ idf_component_register(
PRIV_REQUIRES ${private_dependencies})
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
if(${target} STREQUAL "linux")
target_link_libraries(${COMPONENT_LIB} PRIVATE "-lbsd")
endif()
if(CONFIG_ETH_ENABLED)
idf_component_optional_requires(PRIVATE esp_eth)
endif()

View File

@ -64,17 +64,6 @@ menu "mDNS"
Configures timeout for adding a new mDNS service. Adding a service
fails if could not be completed within this time.
config MDNS_STRICT_MODE
bool "mDNS strict mode"
default "n"
help
Configures strict mode. Set this to 1 for the mDNS library to strictly follow the RFC6762:
Currently the only strict feature: Do not repeat original questions in response packets
(defined in RFC6762 sec. 6).
Default configuration is 0, i.e. non-strict mode, since some implementations,
such as lwIP mDNS resolver (used by standard POSIX API like getaddrinfo, gethostbyname)
could not correctly resolve advertised names.
config MDNS_TIMER_PERIOD_MS
int "mDNS timer period (ms)"
range 10 10000
@ -92,6 +81,27 @@ menu "mDNS"
This option creates a new thread to serve receiving packets (TODO).
This option uses additional N sockets, where N is number of interfaces.
config MDNS_SKIP_SUPPRESSING_OWN_QUERIES
bool "Skip suppressing our own packets"
default n
help
Enable only if the querier and the responder share the same IP address.
This usually happens in test mode, where we may run multiple instances of
responders/queriers on the same interface.
config MDNS_ENABLE_DEBUG_PRINTS
bool "Enable debug prints of mDNS packets"
default n
help
Enable for the library to log received and sent mDNS packets to stdout.
config MDNS_RESPOND_REVERSE_QUERIES
bool "Enable responding to IPv4 reverse queries"
default n
help
Enables support for IPv4 reverse lookup. If enabled, the mDNS library
response to PTR queries of "A.B.C.D.in-addr.arpa" type.
config MDNS_MULTIPLE_INSTANCE
bool "Multiple instances under the same service type"
default y

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -279,6 +279,13 @@ void app_main(void)
ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ENABLE_IP4));
ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ANNOUNCE_IP4));
#endif
#if defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES)
while (mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_IP4_REVERSE_LOOKUP) != ESP_OK) {
vTaskDelay(50 / portTICK_PERIOD_MS);
}
#endif
initialise_button();
xTaskCreate(&mdns_example_task, "mdns_example_task", 2048, NULL, 5, NULL);
}

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import re
import select
@ -8,8 +8,11 @@ import subprocess
import time
from threading import Event, Thread
import dpkt
import dpkt.dns
try:
import dpkt
import dpkt.dns
except ImportError:
pass
def get_dns_query_for_esp(esp_host):

View File

@ -1,4 +1,4 @@
version: "1.0.7"
version: "1.0.8"
description: mDNS
dependencies:
idf:

View File

@ -34,6 +34,8 @@ typedef enum {
MDNS_EVENT_ANNOUNCE_IP6 = 1 << 4,
MDNS_EVENT_DISABLE_IP4 = 1 << 5,
MDNS_EVENT_DISABLE_IP6 = 1 << 6,
MDNS_EVENT_IP4_REVERSE_LOOKUP = 1 << 7,
MDNS_EVENT_IP6_REVERSE_LOOKUP = 1 << 8,
} mdns_event_actions_t;
/**

View File

@ -17,10 +17,13 @@
#include "mdns_networking.h"
#include "esp_log.h"
#include "esp_random.h"
#if CONFIG_ETH_ENABLED
#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH
#include "esp_eth.h"
#endif
#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP
#include "esp_wifi.h"
#endif
#ifdef MDNS_ENABLE_DEBUG
@ -435,7 +438,10 @@ static const uint8_t *_mdns_read_fqdn(const uint8_t *packet, const uint8_t *star
&& (strcasecmp(buf, MDNS_DEFAULT_DOMAIN) != 0)
&& (strcasecmp(buf, "arpa") != 0)
&& (strcasecmp(buf, "ip6") != 0)
&& (strcasecmp(buf, "in-addr") != 0)) {
#ifndef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
&& (strcasecmp(buf, "in-addr") != 0)
#endif
) {
strlcat(name->host, ".", sizeof(name->host));
strlcat(name->host, buf, sizeof(name->host));
} else if (strcasecmp(buf, MDNS_SUB_STR) == 0) {
@ -639,6 +645,60 @@ static inline int append_one_txt_record_entry(uint8_t *packet, uint16_t *index,
return len + 1;
}
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
static inline int append_single_str(uint8_t *packet, uint16_t *index, const char *str, int len)
{
if ((*index + len + 1) >= MDNS_MAX_PACKET_SIZE) {
return 0;
}
if (!_mdns_append_u8(packet, index, len)) {
return 0;
}
memcpy(packet + *index, str, len);
*index += len;
return *index;
}
/**
* @brief appends FQDN to a packet from hostname separated by dots. This API works the same way as
* _mdns_append_fqdn(), but refrains from DNS compression (as it's mainly used for IP addresses (many short items),
* where we gain very little (or compression even gets counter-productive mainly for IPv6 addresses)
*
* @param packet MDNS packet
* @param index offset in the packet
* @param name name representing FQDN in '.' separated parts
* @param last true if appending the last part (domain, typically "arpa")
*
* @return length of added data: 0 on error or length on success
*/
static uint16_t append_fqdn_dots(uint8_t *packet, uint16_t *index, const char *name, bool last)
{
int len = strlen(name);
char *host = (char *)name;
char *end = host;
char *start = host;
do {
end = memchr(start, '.', len);
end = end ? end : host + len;
int part_len = end - start;
if (!append_single_str(packet, index, start, part_len)) {
return 0;
}
start = ++end;
} while (end < name + len);
if (!append_single_str(packet, index, "arpa", sizeof("arpa") - 1)) {
return 0;
}
//empty string so terminate
if (!_mdns_append_u8(packet, index, 0)) {
return 0;
}
return *index;
}
#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */
/**
* @brief appends FQDN to a packet, incrementing the index and
* compressing the output if previous occurrence of the string (or part of it) has been found
@ -680,7 +740,7 @@ search_next:
const uint8_t *content = _mdns_read_fqdn(packet, len_location, &name, buf, packet_len);
if (!content) {
//not a readable fqdn?
return 0;
goto search_next; // could be our unfinished fqdn, continue searching
}
if (name.parts == count) {
uint8_t i;
@ -1100,25 +1160,34 @@ static uint16_t _mdns_append_aaaa_record(uint8_t *packet, uint16_t *index, const
*/
static uint16_t _mdns_append_question(uint8_t *packet, uint16_t *index, mdns_out_question_t *q)
{
const char *str[4];
uint8_t str_index = 0;
uint8_t part_length;
if (q->host) {
str[str_index++] = q->host;
}
if (q->service) {
str[str_index++] = q->service;
}
if (q->proto) {
str[str_index++] = q->proto;
}
if (q->domain) {
str[str_index++] = q->domain;
}
part_length = _mdns_append_fqdn(packet, index, str, str_index, MDNS_MAX_PACKET_SIZE);
if (!part_length) {
return 0;
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
if (q->host && strstr(q->host, "in-addr")) {
part_length = append_fqdn_dots(packet, index, q->host, false);
if (!part_length) {
return 0;
}
} else
#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */
{
const char *str[4];
uint8_t str_index = 0;
if (q->host) {
str[str_index++] = q->host;
}
if (q->service) {
str[str_index++] = q->service;
}
if (q->proto) {
str[str_index++] = q->proto;
}
if (q->domain) {
str[str_index++] = q->domain;
}
part_length = _mdns_append_fqdn(packet, index, str, str_index, MDNS_MAX_PACKET_SIZE);
if (!part_length) {
return 0;
}
}
part_length += _mdns_append_u16(packet, index, q->type);
@ -1200,6 +1269,37 @@ static uint8_t _mdns_append_host_answer(uint8_t *packet, uint16_t *index, mdns_h
return num_records;
}
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
/**
* @brief Appends reverse lookup PTR record
*/
static uint8_t _mdns_append_reverse_ptr_record(uint8_t *packet, uint16_t *index, const char *name)
{
if (strstr(name, "in-addr") == NULL) {
return 0;
}
if (!append_fqdn_dots(packet, index, name, false)) {
return 0;
}
if (!_mdns_append_type(packet, index, MDNS_ANSWER_PTR, false, 10 /* TTL set to 10s*/ )) {
return 0;
}
uint16_t data_len_location = *index - 2; /* store the position of size (2=16bis) of this record */
const char *str[2] = { _mdns_self_host.hostname, MDNS_DEFAULT_DOMAIN };
int part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE);
if (!part_length) {
return 0;
}
_mdns_set_u16(packet, data_len_location, part_length);
return 1; /* appending only 1 record */
}
#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */
/**
* @brief Append PTR answers to packet
*
@ -1238,6 +1338,10 @@ static uint8_t _mdns_append_answer(uint8_t *packet, uint16_t *index, mdns_out_an
if (answer->type == MDNS_TYPE_PTR) {
if (answer->service) {
return _mdns_append_service_ptr_answers(packet, index, answer->service, answer->flush, answer->bye);
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
} else if (answer->host && answer->host->hostname && strstr(answer->host->hostname, "in-addr")) {
return _mdns_append_reverse_ptr_record(packet, index, answer->host->hostname) > 0;
#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */
} else {
return _mdns_append_ptr_record(packet, index,
answer->custom_instance, answer->custom_service, answer->custom_proto,
@ -1723,14 +1827,24 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_
_mdns_free_tx_packet(packet);
return;
}
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
} else if (q->type == MDNS_TYPE_PTR) {
mdns_host_item_t *host = mdns_get_host_item(q->host);
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, NULL, host, send_flush, false)) {
return;
}
#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */
} 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 (parsed_packet->src_port != MDNS_SERVICE_PORT && // Repeat the queries only for "One-Shot mDNS queries"
(q->type == MDNS_TYPE_ANY || q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA)) {
(q->type == MDNS_TYPE_ANY || q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
|| q->type == MDNS_TYPE_PTR
#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */
)) {
mdns_out_question_t *out_question = malloc(sizeof(mdns_out_question_t));
if (out_question == NULL) {
HOOK_MALLOC_FAILED;
@ -1751,7 +1865,6 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_
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;
}
@ -2950,7 +3063,11 @@ static bool _mdns_name_is_discovery(mdns_name_t *name, uint16_t type)
static bool _mdns_name_is_ours(mdns_name_t *name)
{
//domain have to be "local"
if (_str_null_or_empty(name->domain) || strcasecmp(name->domain, MDNS_DEFAULT_DOMAIN)) {
if (_str_null_or_empty(name->domain) || ( strcasecmp(name->domain, MDNS_DEFAULT_DOMAIN)
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
&& strcasecmp(name->domain, "arpa")
#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */
) ) {
return false;
}
@ -3310,6 +3427,7 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
mdns_debug_packet(data, len);
#endif
#ifndef CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES
// Check if the packet wasn't sent by us
if (packet->ip_protocol == MDNS_IP_PROTOCOL_V4) {
esp_netif_ip_info_t if_ip_info;
@ -3326,6 +3444,7 @@ void mdns_parse_packet(mdns_rx_packet_t *packet)
}
#endif
}
#endif
// Check for the minimum size of mdns packet
if (len <= MDNS_HEAD_ADDITIONAL_OFFSET) {
@ -3873,6 +3992,22 @@ static void perform_event_action(mdns_if_t mdns_if, mdns_event_actions_t action)
if (action & MDNS_EVENT_ANNOUNCE_IP6) {
_mdns_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V6, NULL, 0, true);
}
#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES
if (action & MDNS_EVENT_IP4_REVERSE_LOOKUP) {
esp_netif_ip_info_t if_ip_info;
if (esp_netif_get_ip_info(_mdns_get_esp_netif(mdns_if), &if_ip_info) == ESP_OK) {
esp_ip4_addr_t *ip = &if_ip_info.ip;
char *reverse_query_name = NULL;
if (asprintf(&reverse_query_name, "%d.%d.%d.%d.in-addr",
esp_ip4_addr4_16(ip), esp_ip4_addr3_16(ip),
esp_ip4_addr2_16(ip), esp_ip4_addr1_16(ip)) > 0 && reverse_query_name) {
ESP_LOGD(TAG, "Registered reverse query: %s.arpa", reverse_query_name);
_mdns_delegate_hostname_add(reverse_query_name, NULL);
}
}
}
#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */
}
/**
@ -3893,6 +4028,7 @@ static inline void post_mdns_announce_pcb(mdns_predef_if_t preset_if, mdns_ip_pr
mdns_post_custom_action_tcpip_if(mdns_if_from_preset_if(preset_if), protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_ANNOUNCE_IP4 : MDNS_EVENT_ANNOUNCE_IP6);
}
#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH
void mdns_preset_if_handle_system_event(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
@ -3970,6 +4106,7 @@ void mdns_preset_if_handle_system_event(void *arg, esp_event_base_t event_base,
}
}
}
#endif /* CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH */
/*
* MDNS Search
@ -5398,7 +5535,7 @@ esp_err_t mdns_instance_name_set(const char *instance)
if (!_mdns_server) {
return ESP_ERR_INVALID_STATE;
}
if (_str_null_or_empty(instance) || strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) {
if (_str_null_or_empty(instance) || _mdns_server->hostname == NULL || strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) {
return ESP_ERR_INVALID_ARG;
}
char *new_instance = strndup(instance, MDNS_NAME_BUF_LEN - 1);
@ -6067,19 +6204,19 @@ void mdns_debug_packet(const uint8_t *data, size_t len)
_mdns_dbg_printf("Packet[%u]: ", t);
header.id = _mdns_read_u16(data, MDNS_HEAD_ID_OFFSET);
header.flags.value = _mdns_read_u16(data, MDNS_HEAD_FLAGS_OFFSET);
header.flags = _mdns_read_u16(data, MDNS_HEAD_FLAGS_OFFSET);
header.questions = _mdns_read_u16(data, MDNS_HEAD_QUESTIONS_OFFSET);
header.answers = _mdns_read_u16(data, MDNS_HEAD_ANSWERS_OFFSET);
header.servers = _mdns_read_u16(data, MDNS_HEAD_SERVERS_OFFSET);
header.additional = _mdns_read_u16(data, MDNS_HEAD_ADDITIONAL_OFFSET);
_mdns_dbg_printf("%s",
(header.flags.value == MDNS_FLAGS_QR_AUTHORITATIVE) ? "AUTHORITATIVE\n" :
(header.flags.value == MDNS_FLAGS_DISTRIBUTED) ? "DISTRIBUTED\n" :
(header.flags.value == 0) ? "\n" : " "
(header.flags == MDNS_FLAGS_QR_AUTHORITATIVE) ? "AUTHORITATIVE\n" :
(header.flags == MDNS_FLAGS_DISTRIBUTED) ? "DISTRIBUTED\n" :
(header.flags == 0) ? "\n" : " "
);
if (header.flags.value && header.flags.value != MDNS_FLAGS_QR_AUTHORITATIVE) {
_mdns_dbg_printf("0x%04X\n", header.flags.value);
if (header.flags && header.flags != MDNS_FLAGS_QR_AUTHORITATIVE) {
_mdns_dbg_printf("0x%04X\n", header.flags);
}
if (header.questions) {

View File

@ -14,34 +14,13 @@
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_timer.h"
#include "esp_system.h"
//#define MDNS_ENABLE_DEBUG
#ifdef MDNS_ENABLE_DEBUG
#ifdef CONFIG_MDNS_ENABLE_DEBUG_PRINTS
#define MDNS_ENABLE_DEBUG
#define _mdns_dbg_printf(...) printf(__VA_ARGS__)
#endif
/** mDNS strict mode: Set this to 1 for the mDNS library to strictly follow the RFC6762:
* Strict features:
* - to do not set original questions in response packets per RFC6762, sec 6
*
* The actual configuration is 0, i.e. non-strict mode, since some implementations,
* such as lwIP mdns resolver (used by standard POSIX API like getaddrinfo, gethostbyname)
* could not correctly resolve advertised names.
*/
#ifndef CONFIG_MDNS_STRICT_MODE
#define MDNS_STRICT_MODE 0
#else
#define MDNS_STRICT_MODE 1
#endif
#if !MDNS_STRICT_MODE
/* mDNS responders sometimes repeat queries in responses
* but according to RFC6762, sec 6: Responses MUST NOT contain
* any item in question field */
#define MDNS_REPEAT_QUERY_IN_RESPONSE 1
#endif
/** Number of predefined interfaces */
#ifndef CONFIG_MDNS_PREDEF_NETIF_STA
#define CONFIG_MDNS_PREDEF_NETIF_STA 0

View File

@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "../..")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(COMPONENTS main)
set(COMPONENTS main esp_netif_linux)
project(mdns_host)

View File

@ -1,7 +1,10 @@
# Setup dummy network interfaces
Note: Set two addresses so we could use one as source and another as destination
```
sudo ip link add eth2 type dummy
sudo ip addr add 192.168.1.200/24 dev eth2
sudo ip addr add 192.168.1.201/24 dev eth2
sudo ip link set eth2 up
sudo ifconfig eth2 multicast
```
@ -12,6 +15,11 @@ sudo ifconfig eth2 multicast
dig +short -b 192.168.1.200 -p 5353 @224.0.0.251 myesp.local
```
or a reverse query:
```
dig +short -b 192.168.2.200 -p 5353 @224.0.0.251 -x 192.168.1.200
```
# Run avahi to browse services
Avahi needs the netif to have the "multicast" flag set

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS esp_event_mock.c
INCLUDE_DIRS include)

View File

@ -8,16 +8,7 @@
#include "stdbool.h"
#include "esp_err.h"
#include "esp_event_base.h"
#include "bsd_strings.h"
#define ESP_EVENT_DECLARE_BASE(x)
#define ESP_EVENT_ANY_ID (-1)
typedef void *esp_event_base_t;
typedef void *system_event_t;
const char *WIFI_EVENT;
const char *IP_EVENT;
#include "bsd/string.h"
esp_err_t esp_event_handler_register(const char *event_base, int32_t event_id, void *event_handler, void *event_handler_arg);

View File

@ -11,3 +11,9 @@ typedef enum {
WIFI_EVENT_AP_START, /**< ESP32 soft-AP start */
WIFI_EVENT_AP_STOP, /**< ESP32 soft-AP stop */
} mdns_used_event_t;
#define ESP_EVENT_DECLARE_BASE(x)
#define ESP_EVENT_ANY_ID (-1)
typedef void *esp_event_base_t;
typedef void *system_event_t;

View File

@ -1,3 +0,0 @@
idf_component_register(SRCS esp_event_mock.c
INCLUDE_DIRS include
REQUIRES esp_system_protocols_linux)

View File

@ -1,3 +1,3 @@
idf_component_register(SRCS esp_netif_linux.c
INCLUDE_DIRS include
REQUIRES esp_system_protocols_linux)
INCLUDE_DIRS include $ENV{IDF_PATH}/components/esp_netif/include
REQUIRES esp_event)

View File

@ -50,9 +50,7 @@ esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_
struct sockaddr_in *pAddr = (struct sockaddr_in *) tmp->ifa_addr;
inet_ntop(AF_INET, &pAddr->sin_addr, addr, sizeof(addr) );
if (strcmp(esp_netif->if_desc, tmp->ifa_name) == 0) {
printf("AF_INET: %s: %s\n", tmp->ifa_name, addr);
memcpy(&ip_info->ip.addr, &pAddr->sin_addr, 4);
break;
}
}
tmp = tmp->ifa_next;

View File

@ -1,3 +0,0 @@
idf_component_register(SRCS esp_log_impl.c strlcat.c
INCLUDE_DIRS include
REQUIRES esp_netif_linux esp_timer_linux freertos_linux esp_event_mock esp_netif log esp_common)

View File

@ -1,27 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_err.h"
#include "esp_log.h"
#include <stdlib.h>
void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression)
{
ESP_LOGE("ESP_ERROR_CHECK", "Failed with esp_err_t: 0x%x", rc);
ESP_LOGE("ESP_ERROR_CHECK", "Expression: %s", expression);
ESP_LOGE("ESP_ERROR_CHECK", "Functions: %s %s(%d)", function, file, line);
abort();
}
void esp_log_buffer_hexdump_internal(const char *tag, const void *buffer, uint16_t buff_len, esp_log_level_t log_level)
{
if ( LOG_LOCAL_LEVEL >= log_level ) {
ESP_LOG_LEVEL(log_level, tag, "Buffer:%p length:%d", buffer, buff_len);
for (int i = 0; i < buff_len; ++i) {
printf("%02x ", ((uint8_t *)buffer)[i]);
}
printf("\n");
}
}

View File

@ -1,8 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
size_t strlcat(char *dest, const char *src, size_t size);

View File

@ -1,70 +0,0 @@
/* $OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $ */
/*-
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "string.h"
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
strlcat(dst, src, siz)
char *dst;
const char *src;
size_t siz;
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0') {
d++;
}
dlen = d - dst;
n = siz - dlen;
if (n == 0) {
return (dlen + strlen(s));
}
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return (dlen + (s - src)); /* count does not include NUL */
}

View File

@ -1,6 +1,6 @@
idf_component_register(SRCS esp_timer_linux.c timer_task.cpp
INCLUDE_DIRS include
REQUIRES esp_system_protocols_linux freertos_linux)
REQUIRES esp_event)
set_target_properties(${COMPONENT_LIB} PROPERTIES
CXX_STANDARD 17

View File

@ -16,7 +16,7 @@ typedef void (*cb_t)(void *arg);
class TimerTaskMock {
public:
TimerTaskMock(cb_t cb): cb(cb), t(run_static, this), active(false), ms(INT32_MAX) {}
TimerTaskMock(cb_t cb): cb(cb), active(false), ms(INT32_MAX) {}
~TimerTaskMock(void)
{
active = false;
@ -27,6 +27,7 @@ public:
{
ms = m;
active = true;
t = std::thread(run_static, this);
}
private:

View File

@ -1,6 +1,5 @@
idf_component_register(SRCS freertos_linux.c queue_unique_ptr.cpp
INCLUDE_DIRS include
REQUIRES esp_system_protocols_linux)
INCLUDE_DIRS include)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

View File

@ -158,16 +158,6 @@ void xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint
}
}
uint32_t esp_get_free_heap_size(void)
{
return 0;
}
uint32_t esp_random(void)
{
return rand();
}
void xTaskNotifyGive(TaskHandle_t task)
{

View File

@ -32,3 +32,4 @@ typedef int BaseType_t;
uint32_t esp_get_free_heap_size(void);
uint32_t esp_random(void);
void vTaskSuspendAll(void);

View File

@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
//
// Created by david on 1/13/23.
//
#ifndef _QUEUE_H_
#define _QUEUE_H_
#endif //_QUEUE_H_

View File

@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
//
// Created by david on 1/13/23.
//
#ifndef _SEMAPHR_H_
#define _SEMAPHR_H_
#endif //_SEMAPHR_H_

View File

@ -0,0 +1,15 @@
menu "Test Configuration"
config TEST_HOSTNAME
string "mDNS Hostname"
default "esp32-mdns"
help
mDNS Hostname for example to use
config TEST_NETIF_NAME
string "Network interface name"
default "eth2"
help
Name/ID if the network interface on which we run the mDNS host test
endmenu

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -35,14 +35,16 @@ int main(int argc, char *argv[])
{
setvbuf(stdout, NULL, _IONBF, 0);
const esp_netif_inherent_config_t base_cg = { .if_key = "WIFI_STA_DEF", .if_desc = "eth2" };
const esp_netif_inherent_config_t base_cg = { .if_key = "WIFI_STA_DEF", .if_desc = CONFIG_TEST_NETIF_NAME };
esp_netif_config_t cfg = { .base = &base_cg };
esp_netif_t *sta = esp_netif_new(&cfg);
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set(CONFIG_TEST_HOSTNAME));
ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_TEST_HOSTNAME);
ESP_ERROR_CHECK(mdns_register_netif(sta));
ESP_ERROR_CHECK(mdns_netif_action(sta, MDNS_EVENT_ENABLE_IP4 | MDNS_EVENT_IP4_REVERSE_LOOKUP));
mdns_init();
mdns_hostname_set("myesp");
ESP_LOGI(TAG, "mdns hostname set to: [%s]", "myesp");
#ifdef REGISTER_SERVICE
//set default mDNS instance name
mdns_instance_name_set("myesp-inst");
//structure with TXT records
@ -51,12 +53,12 @@ int main(int argc, char *argv[])
{"u", "user"},
{"p", "password"}
};
vTaskDelay(1000);
vTaskDelay(pdMS_TO_TICKS(10000));
ESP_ERROR_CHECK(mdns_service_add("myesp-service2", "_http", "_tcp", 80, serviceTxtData, 3));
vTaskDelay(2000);
query_mdns_host("david-comp");
vTaskDelay(2000);
#endif
vTaskDelay(pdMS_TO_TICKS(10000));
query_mdns_host("david-work");
vTaskDelay(pdMS_TO_TICKS(1000));
esp_netif_destroy(sta);
mdns_free();
ESP_LOGI(TAG, "Exit");

View File

@ -0,0 +1,9 @@
CONFIG_IDF_TARGET="linux"
CONFIG_MDNS_NETWORKING_SOCKET=y
CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES=y
CONFIG_TEST_NETIF_NAME="eth0"
CONFIG_TEST_HOSTNAME="myesp"
CONFIG_MDNS_PREDEF_NETIF_STA=n
CONFIG_MDNS_PREDEF_NETIF_AP=n
CONFIG_MDNS_ENABLE_DEBUG_PRINTS=y
CONFIG_MDNS_RESPOND_REVERSE_QUERIES=y

View File

@ -55,7 +55,6 @@
#define INC_TASK_H
#define pdMS_TO_TICKS(a) a
#define portTICK_PERIOD_MS 10
#define xSemaphoreTake(s,d) true
#define xTaskDelete(a)
#define vTaskDelete(a) free(a)
@ -87,10 +86,6 @@ typedef int BaseType_t;
typedef uint32_t TickType_t;
extern const char *WIFI_EVENT;
extern const char *IP_EVENT;
extern const char *ETH_EVENT;
struct udp_pcb {
uint8_t dummy;
};

View File

@ -1,2 +1,7 @@
idf_component_register(SRC_DIRS "."
PRIV_REQUIRES cmock test_utils mdns)
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS ../.. "$ENV{IDF_PATH}/tools/unit-test-app/components")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mdns_test)

View File

@ -0,0 +1,5 @@
idf_component_register(SRCS "test_mdns.c"
REQUIRES test_utils
INCLUDE_DIRS "."
PRIV_REQUIRES unity mdns)

View File

@ -1,13 +1,16 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "test_utils.h"
#include "mdns.h"
#include "esp_event.h"
#include "unity.h"
#include "test_utils.h"
#include "unity_fixture.h"
#include "memory_checks.h"
#define MDNS_HOSTNAME "test-hostname"
#define MDNS_DELEGATE_HOSTNAME "delegate-hostname"
@ -16,6 +19,18 @@
#define MDNS_SERVICE_PROTO "_tcp"
#define MDNS_SERVICE_PORT 80
TEST_GROUP(mdns);
TEST_SETUP(mdns)
{
test_utils_record_free_mem();
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
}
TEST_TEAR_DOWN(mdns)
{
test_utils_finish_and_evaluate_leaks(32, 64);
}
static void yield_to_all_priorities(void)
{
@ -27,7 +42,7 @@ static void yield_to_all_priorities(void)
}
TEST_CASE("mdns api to fail in invalid state", "[mdns][leaks=64]")
TEST(mdns, api_fails_with_invalid_state)
{
TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_init() );
TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME) );
@ -35,7 +50,7 @@ TEST_CASE("mdns api to fail in invalid state", "[mdns][leaks=64]")
TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0) );
}
TEST_CASE("mdns init and deinit", "[mdns][leaks=64]")
TEST(mdns, init_deinit)
{
test_case_uses_tcpip();
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default());
@ -45,7 +60,7 @@ TEST_CASE("mdns init and deinit", "[mdns][leaks=64]")
esp_event_loop_delete_default();
}
TEST_CASE("mdns api return expected err-code and do not leak memory", "[mdns][leaks=64]")
TEST(mdns, api_fails_with_expected_err)
{
mdns_txt_item_t serviceTxtData[CONFIG_MDNS_MAX_SERVICES] = { {NULL, NULL},
};
@ -91,7 +106,7 @@ TEST_CASE("mdns api return expected err-code and do not leak memory", "[mdns][le
esp_event_loop_delete_default();
}
TEST_CASE("mdns query api return expected err-code and do not leak memory", "[leaks=64]")
TEST(mdns, query_api_fails_with_expected_err)
{
mdns_result_t *results = NULL;
esp_ip6_addr_t addr6;
@ -100,6 +115,14 @@ TEST_CASE("mdns query api return expected err-code and do not leak memory", "[le
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default());
TEST_ASSERT_EQUAL(ESP_OK, mdns_init() );
// check it is not possible to register a service or set an instance without configuring the hostname
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, mdns_instance_name_set(MDNS_INSTANCE));
TEST_ASSERT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME));
// hostname is set, now adding a service and instance should succeed
TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0));
TEST_ASSERT_EQUAL(ESP_OK, mdns_instance_name_set(MDNS_INSTANCE));
TEST_ASSERT_EQUAL(ESP_OK, mdns_query_ptr(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 10, CONFIG_MDNS_MAX_SERVICES, &results) );
mdns_query_results_free(results);
@ -118,3 +141,16 @@ TEST_CASE("mdns query api return expected err-code and do not leak memory", "[le
mdns_free();
esp_event_loop_delete_default();
}
TEST_GROUP_RUNNER(mdns)
{
RUN_TEST_CASE(mdns, api_fails_with_invalid_state)
RUN_TEST_CASE(mdns, api_fails_with_expected_err)
RUN_TEST_CASE(mdns, query_api_fails_with_expected_err)
RUN_TEST_CASE(mdns, init_deinit)
}
void app_main(void)
{
UNITY_MAIN(mdns);
}

View File

@ -0,0 +1,8 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
from pytest_embedded import Dut
def test_lwip(dut: Dut) -> None:
dut.expect_unity_test_output()

View File

@ -0,0 +1,2 @@
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n