diff --git a/components/mdns/CMakeLists.txt b/components/mdns/CMakeLists.txt index a8d2cedb3..cb3ed4996 100644 --- a/components/mdns/CMakeLists.txt +++ b/components/mdns/CMakeLists.txt @@ -1,7 +1,22 @@ -idf_component_register(SRCS "mdns.c" - "mdns_console.c" - "mdns_networking.c" - INCLUDE_DIRS "include" - PRIV_INCLUDE_DIRS "private_include" - REQUIRES lwip console esp_netif - PRIV_REQUIRES esp_timer) +if(CONFIG_MDNS_NETWORKING_SOCKET) + set(MDNS_NETWORKING "mdns_networking_socket.c") +else() + set(MDNS_NETWORKING "mdns_networking_lwip.c") +endif() + +idf_build_get_property(target IDF_TARGET) +if(${target} STREQUAL "linux") + set(dependencies esp_system_protocols_linux) + set(srcs "mdns.c" ${MDNS_NETWORKING}) +else() + set(dependencies lwip console esp_netif) + set(private_dependencies esp_timer) + set(srcs "mdns.c" ${MDNS_NETWORKING} "mdns_console.c") +endif() + +idf_component_register( + SRCS ${srcs} + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "private_include" + REQUIRES ${dependencies} + PRIV_REQUIRES ${private_dependencies}) diff --git a/components/mdns/Kconfig b/components/mdns/Kconfig index 38dec7628..b49ae703c 100644 --- a/components/mdns/Kconfig +++ b/components/mdns/Kconfig @@ -75,4 +75,13 @@ menu "mDNS" Configures period of mDNS timer, which periodically transmits packets and schedules mDNS searches. + config MDNS_NETWORKING_SOCKET + bool "Use BSD sockets for mdns networking" + default n + help + Enables optional mdns networking implementation using BSD sockets + in UDP multicast mode. + This option creates a new thread to serve receiving packets (TODO). + This option uses additional N sockets, where N is number of interfaces. + endmenu diff --git a/components/mdns/component.mk b/components/mdns/component.mk index 064cc0608..f22f83094 100644 --- a/components/mdns/component.mk +++ b/components/mdns/component.mk @@ -1,2 +1,7 @@ +ifdef CONFIG_MDNS_NETWORKING_SOCKET +COMPONENT_OBJEXCLUDE := mdns_networking_lwip.o +else +COMPONENT_OBJEXCLUDE := mdns_networking_socket.o +endif COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_PRIV_INCLUDEDIRS := private_include diff --git a/components/mdns/host_test/CMakeLists.txt b/components/mdns/host_test/CMakeLists.txt new file mode 100644 index 000000000..132e436ea --- /dev/null +++ b/components/mdns/host_test/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(COMPONENTS main) +project(mdns_host) diff --git a/components/mdns/host_test/README.md b/components/mdns/host_test/README.md new file mode 100644 index 000000000..ab916520d --- /dev/null +++ b/components/mdns/host_test/README.md @@ -0,0 +1,25 @@ +# Setup dummy network interfaces +``` +sudo ip link add eth2 type dummy +sudo ip addr add 192.168.1.200/24 dev eth2 +sudo ip link set eth2 up +sudo ifconfig eth2 multicast +``` + +# Dig on a specified interface + +``` +dig +short -b 192.168.1.200 -p 5353 @224.0.0.251 myesp.local +``` + +# Run avahi to browse services + +Avahi needs the netif to have the "multicast" flag set + +```bash +david@david-comp:~/esp/idf (feature/mdns_networking_socket)$ avahi-browse -a -r -p ++;eth2;IPv6;myesp-service2;Web Site;local ++;eth2;IPv4;myesp-service2;Web Site;local +=;eth2;IPv6;myesp-service2;Web Site;local;myesp.local;192.168.1.200;80;"board=esp32" "u=user" "p=password" +=;eth2;IPv4;myesp-service2;Web Site;local;myesp.local;192.168.1.200;80;"board=esp32" "u=user" "p=password" +``` diff --git a/components/mdns/host_test/components/esp_event_mock/CMakeLists.txt b/components/mdns/host_test/components/esp_event_mock/CMakeLists.txt new file mode 100644 index 000000000..606c16f80 --- /dev/null +++ b/components/mdns/host_test/components/esp_event_mock/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS esp_event_mock.c + INCLUDE_DIRS include + REQUIRES esp_system_protocols_linux) diff --git a/components/mdns/host_test/components/esp_event_mock/esp_event_mock.c b/components/mdns/host_test/components/esp_event_mock/esp_event_mock.c new file mode 100644 index 000000000..cd6b079b3 --- /dev/null +++ b/components/mdns/host_test/components/esp_event_mock/esp_event_mock.c @@ -0,0 +1,29 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_err.h" +#include "esp_event.h" + +const char * WIFI_EVENT = "WIFI_EVENT"; +const char * IP_EVENT = "IP_EVENT"; + +esp_err_t esp_event_handler_register(const char * event_base, int32_t event_id, void* event_handler, void* event_handler_arg) +{ + return ESP_OK; +} + +esp_err_t esp_event_handler_unregister(const char * event_base, int32_t event_id, void* event_handler) +{ + return ESP_OK; +} diff --git a/components/mdns/host_test/components/esp_event_mock/include/esp_event.h b/components/mdns/host_test/components/esp_event_mock/include/esp_event.h new file mode 100644 index 000000000..18801e4b9 --- /dev/null +++ b/components/mdns/host_test/components/esp_event_mock/include/esp_event.h @@ -0,0 +1,32 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#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; + +esp_err_t esp_event_handler_register(const char * event_base, int32_t event_id, void* event_handler, void* event_handler_arg); + +esp_err_t esp_event_handler_unregister(const char * event_base, int32_t event_id, void* event_handler); diff --git a/components/mdns/host_test/components/esp_event_mock/include/esp_event_base.h b/components/mdns/host_test/components/esp_event_mock/include/esp_event_base.h new file mode 100644 index 000000000..740b71270 --- /dev/null +++ b/components/mdns/host_test/components/esp_event_mock/include/esp_event_base.h @@ -0,0 +1,21 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +typedef enum { + WIFI_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */ + WIFI_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */ + WIFI_EVENT_AP_START, /**< ESP32 soft-AP start */ + WIFI_EVENT_AP_STOP, /**< ESP32 soft-AP stop */ +} mdns_used_event_t; diff --git a/components/mdns/host_test/components/esp_netif_linux/CMakeLists.txt b/components/mdns/host_test/components/esp_netif_linux/CMakeLists.txt new file mode 100644 index 000000000..086034b08 --- /dev/null +++ b/components/mdns/host_test/components/esp_netif_linux/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS esp_netif_linux.c + INCLUDE_DIRS include + REQUIRES esp_system_protocols_linux) diff --git a/components/mdns/host_test/components/esp_netif_linux/Kconfig b/components/mdns/host_test/components/esp_netif_linux/Kconfig new file mode 100644 index 000000000..c903f7ca5 --- /dev/null +++ b/components/mdns/host_test/components/esp_netif_linux/Kconfig @@ -0,0 +1,9 @@ +menu "LWIP-MOCK-CONFIG" + + config LWIP_IPV6 + bool "Enable IPv6" + default true + help + Enable/disable IPv6 + +endmenu diff --git a/components/mdns/host_test/components/esp_netif_linux/esp_netif_linux.c b/components/mdns/host_test/components/esp_netif_linux/esp_netif_linux.c new file mode 100644 index 000000000..bbde59073 --- /dev/null +++ b/components/mdns/host_test/components/esp_netif_linux/esp_netif_linux.c @@ -0,0 +1,163 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include + +#include "esp_netif.h" +#include "esp_err.h" +#include //strlen +#include +#include //inet_addr +#include +#include +#include +#include "esp_netif_types.h" + +#define MAX_NETIFS 4 + +static esp_netif_t* s_netif_list[MAX_NETIFS] = { 0 }; + +struct esp_netif_obj +{ + const char *if_key; + const char *if_desc; +}; + +esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key) +{ + for (int i=0; iif_key, if_key) == 0) { + return s_netif_list[i]; + } + } + return NULL; +} + +esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info) +{ + if (esp_netif == NULL) { + return ESP_ERR_INVALID_STATE; + } + struct ifaddrs *addrs, *tmp; + getifaddrs(&addrs); + tmp = addrs; + + while (tmp) { + if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) { + char addr[20]; + 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; + } + return ESP_OK; +} + +esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status) +{ + return ESP_OK; +} + + +esp_err_t esp_netif_get_ip6_linklocal(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6) +{ + if (esp_netif == NULL) { + return ESP_ERR_INVALID_STATE; + } + struct ifaddrs *addrs, *tmp; + getifaddrs(&addrs); + tmp = addrs; + + while (tmp) + { + if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET6) { + char addr[64]; + struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)tmp->ifa_addr; + inet_ntop(AF_INET6, &pAddr->sin6_addr, addr, sizeof(addr) ); + if (strcmp(esp_netif->if_desc, tmp->ifa_name) == 0) { + printf("AF_INET6: %s: %s\n", tmp->ifa_name, addr); + memcpy(if_ip6->addr, &pAddr->sin6_addr, 4*4); + break; + } + } + tmp = tmp->ifa_next; + } + + freeifaddrs(addrs); + return ESP_OK; +} + + +int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif) +{ + if (esp_netif == NULL) { + return -1; + } + uint32_t interfaceIndex = if_nametoindex(esp_netif->if_desc); + return interfaceIndex; +} + +esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char* name) +{ + if (esp_netif == NULL) { + return ESP_ERR_INVALID_STATE; + } + strcpy(name, esp_netif->if_desc); + return ESP_OK; +} + +const char *esp_netif_get_desc(esp_netif_t *esp_netif) +{ + if (esp_netif == NULL) { + return NULL; + } + return esp_netif->if_desc; +} + +esp_netif_t *esp_netif_new(const esp_netif_config_t *config) +{ + if (esp_netif_get_handle_from_ifkey(config->base->if_key)) { + return NULL; + } + esp_netif_t* netif = calloc(1, sizeof(struct esp_netif_obj)); + if (netif) { + netif->if_desc = config->base->if_desc; + netif->if_key = config->base->if_key; + } + + for (int i=0; i + +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 + * 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 */ +} diff --git a/components/mdns/host_test/components/esp_timer_linux/CMakeLists.txt b/components/mdns/host_test/components/esp_timer_linux/CMakeLists.txt new file mode 100644 index 000000000..0c598a2e6 --- /dev/null +++ b/components/mdns/host_test/components/esp_timer_linux/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register(SRCS esp_timer_linux.c timer_task.cpp + INCLUDE_DIRS include + REQUIRES esp_system_protocols_linux freertos_linux) + +target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17) diff --git a/components/mdns/host_test/components/esp_timer_linux/esp_timer_linux.c b/components/mdns/host_test/components/esp_timer_linux/esp_timer_linux.c new file mode 100644 index 000000000..bb2326985 --- /dev/null +++ b/components/mdns/host_test/components/esp_timer_linux/esp_timer_linux.c @@ -0,0 +1,47 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "esp_err.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +void * create_tt(esp_timer_cb_t cb); + +void destroy_tt(void* tt); + +void set_tout(void* tt, uint32_t ms); + +esp_err_t esp_timer_create(const esp_timer_create_args_t* create_args, + esp_timer_handle_t* out_handle) +{ + *out_handle = (esp_timer_handle_t)create_tt(create_args->callback); + return ESP_OK; +} + +esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period) +{ + set_tout(timer, period/1000); + return ESP_OK; +} + +esp_err_t esp_timer_stop(esp_timer_handle_t timer) +{ + return ESP_OK; +} + +esp_err_t esp_timer_delete(esp_timer_handle_t timer) +{ + destroy_tt(timer); + return ESP_OK; +} diff --git a/components/mdns/host_test/components/esp_timer_linux/include/esp_timer.h b/components/mdns/host_test/components/esp_timer_linux/include/esp_timer.h new file mode 100644 index 000000000..669163049 --- /dev/null +++ b/components/mdns/host_test/components/esp_timer_linux/include/esp_timer.h @@ -0,0 +1,41 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include + +typedef struct esp_timer* esp_timer_handle_t; + +typedef void (*esp_timer_cb_t)(void* arg); + +typedef enum { + ESP_TIMER_TASK, +} esp_timer_dispatch_t; + +typedef struct { + esp_timer_cb_t callback; //!< Function to call when timer expires + void* arg; //!< Argument to pass to the callback + esp_timer_dispatch_t dispatch_method; //!< Call the callback from task or from ISR + const char* name; //!< Timer name, used in esp_timer_dump function + bool skip_unhandled_events; //!< Skip unhandled events for periodic timers +} esp_timer_create_args_t; + +esp_err_t esp_timer_create(const esp_timer_create_args_t* create_args, + esp_timer_handle_t* out_handle); +esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period); + +esp_err_t esp_timer_stop(esp_timer_handle_t timer); + +esp_err_t esp_timer_delete(esp_timer_handle_t timer); diff --git a/components/mdns/host_test/components/esp_timer_linux/timer_task.cpp b/components/mdns/host_test/components/esp_timer_linux/timer_task.cpp new file mode 100644 index 000000000..bd971b3f0 --- /dev/null +++ b/components/mdns/host_test/components/esp_timer_linux/timer_task.cpp @@ -0,0 +1,38 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "timer_task.hpp" +#include +#include +#include +#include + +extern "C" void * create_tt(cb_t cb) +{ + auto * tt = new TimerTaskMock(cb); + return tt; +} + +extern "C" void destroy_tt(void* tt) +{ + auto * timer_task = static_cast(tt); + delete(timer_task); +} + + +extern "C" void set_tout(void* tt, uint32_t ms) +{ + auto * timer_task = static_cast(tt); + timer_task->SetTimeout(ms); +} diff --git a/components/mdns/host_test/components/esp_timer_linux/timer_task.hpp b/components/mdns/host_test/components/esp_timer_linux/timer_task.hpp new file mode 100644 index 000000000..8d32a6bd0 --- /dev/null +++ b/components/mdns/host_test/components/esp_timer_linux/timer_task.hpp @@ -0,0 +1,61 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include +#include +#include +#include +#include + +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(void) { active = false; t.join(); } + + void SetTimeout(uint32_t m) + { + ms = m; + active = true; + } + +private: + + static void run_static(TimerTaskMock* timer) + { + timer->run(); + } + + void run(void) + { + while (!active.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + while (active.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + cb(nullptr); + } + } + + cb_t cb; + std::thread t; + std::atomic active; + uint32_t ms; + +}; diff --git a/components/mdns/host_test/components/freertos_linux/CMakeLists.txt b/components/mdns/host_test/components/freertos_linux/CMakeLists.txt new file mode 100644 index 000000000..7a84af21a --- /dev/null +++ b/components/mdns/host_test/components/freertos_linux/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register(SRCS freertos_linux.c queue_unique_ptr.cpp + INCLUDE_DIRS include + REQUIRES esp_system_protocols_linux) + +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) +target_link_libraries(${COMPONENT_LIB} PRIVATE Threads::Threads) + +target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17) diff --git a/components/mdns/host_test/components/freertos_linux/Kconfig b/components/mdns/host_test/components/freertos_linux/Kconfig new file mode 100644 index 000000000..fa57dab7e --- /dev/null +++ b/components/mdns/host_test/components/freertos_linux/Kconfig @@ -0,0 +1,7 @@ +menu "FreeRTOS" + + config FREERTOS_NO_AFFINITY + hex + default 0x7FFFFFFF + +endmenu diff --git a/components/mdns/host_test/components/freertos_linux/freertos_linux.c b/components/mdns/host_test/components/freertos_linux/freertos_linux.c new file mode 100644 index 000000000..763364504 --- /dev/null +++ b/components/mdns/host_test/components/freertos_linux/freertos_linux.c @@ -0,0 +1,192 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include +#include +#include + +void * create_q(void); + +void destroy_q(void* q); + +bool send_q(void* q, uint8_t *data, size_t len); + +bool recv_q(void* q, uint8_t *data, size_t len, uint32_t ms); + +static uint64_t s_semaphore_data = 0; + +struct queue_handle { + size_t item_size; + void * q; +}; + +QueueHandle_t xQueueCreate( uint32_t uxQueueLength, uint32_t uxItemSize ) +{ + struct queue_handle * h = calloc(1, sizeof(struct queue_handle)); + h->item_size = uxItemSize; + h->q = create_q(); + return (QueueHandle_t)h; +} + +uint32_t xQueueSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait) +{ + struct queue_handle * h = xQueue; + return send_q(h->q, (uint8_t*)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL; +} + +uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait) +{ + struct queue_handle * h = xQueue; + return recv_q(h->q, (uint8_t*)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL; +} + +BaseType_t xSemaphoreGive( QueueHandle_t xQueue) +{ + return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY); +} + +BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask ) +{ + return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY); +} + +void vQueueDelete( QueueHandle_t xQueue ) +{ + struct queue_handle * h = xQueue; + if (h->q) { + destroy_q(h->q); + } + free(xQueue); +} + +QueueHandle_t xSemaphoreCreateBinary(void) +{ + QueueHandle_t sempaphore = xQueueCreate(1, 1); + return sempaphore; +} + +QueueHandle_t xSemaphoreCreateMutex(void) +{ + QueueHandle_t sempaphore = xQueueCreate(1, 1); + if (sempaphore) { + xSemaphoreGive(sempaphore); + } + return sempaphore; +} + +void vTaskDelete(TaskHandle_t *task) +{ + if (task == NULL) { + pthread_exit(0); + } + void *thread_rval = NULL; + pthread_join((pthread_t)task, &thread_rval); +} + +TickType_t xTaskGetTickCount( void ) +{ + struct timespec spec; + clock_gettime(CLOCK_REALTIME, &spec); + return spec.tv_nsec / 1000000 + spec.tv_sec * 1000; +} + +void vTaskDelay( const TickType_t xTicksToDelay ) +{ + usleep(xTicksToDelay*1000); +} + +void * pthread_task(void * params) +{ + struct { + void * const param; + TaskFunction_t task; + bool started; + } *pthread_params = params; + + void * const param = pthread_params->param; + TaskFunction_t task = pthread_params->task; + pthread_params->started = true; + + task(param); + + return NULL; +} + +BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pvCreatedTask, + const BaseType_t xCoreID) +{ + xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask); + return pdTRUE; +} + + +void xTaskCreate(TaskFunction_t pvTaskCode, const char * const pcName, const uint32_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pvCreatedTask) +{ + pthread_t new_thread = (pthread_t)NULL; + pthread_attr_t attr; + struct { + void * const param; + TaskFunction_t task; + bool started; + } pthread_params = { .param = pvParameters, .task = pvTaskCode}; + int res = pthread_attr_init(&attr); + assert(res == 0); + res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + assert(res == 0); + res = pthread_create(&new_thread, &attr, pthread_task, &pthread_params); + assert(res == 0); + + if (pvCreatedTask) { + *pvCreatedTask = (void*)new_thread; + } + + // just wait till the task started so we can unwind params from the stack + while (pthread_params.started == false) { + usleep(1000); + } +} + +uint32_t esp_get_free_heap_size(void) +{ + return 0; +} + +uint32_t esp_random(void) +{ + return rand(); +} + +void xTaskNotifyGive(TaskHandle_t task) +{ + +} + +BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time ) +{ + return true; +} + +TaskHandle_t xTaskGetCurrentTaskHandle(void) +{ + return NULL; +} diff --git a/components/mdns/host_test/components/freertos_linux/include/esp_task.h b/components/mdns/host_test/components/freertos_linux/include/esp_task.h new file mode 100644 index 000000000..797b416b6 --- /dev/null +++ b/components/mdns/host_test/components/freertos_linux/include/esp_task.h @@ -0,0 +1,20 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#define ESP_TASK_PRIO_MAX 25 +#define ESP_TASKD_EVENT_PRIO 5 diff --git a/components/mdns/host_test/components/freertos_linux/include/freertos/FreeRTOS.h b/components/mdns/host_test/components/freertos_linux/include/freertos/FreeRTOS.h new file mode 100644 index 000000000..ca13d0463 --- /dev/null +++ b/components/mdns/host_test/components/freertos_linux/include/freertos/FreeRTOS.h @@ -0,0 +1,46 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include +#include +#include + +#define portTICK_PERIOD_MS 1 +#define portMAX_DELAY ( TickType_t ) 0xffffffffUL + +typedef void * xSemaphoreHandle; +typedef void * SemaphoreHandle_t; +typedef void * xQueueHandle; +typedef void * QueueHandle_t; +typedef void * TaskHandle_t; +typedef uint32_t TickType_t; +typedef uint32_t portTickType; + +typedef void (*TaskFunction_t)( void * ); +typedef unsigned int UBaseType_t; +typedef int BaseType_t; + +#define pdFALSE ( ( BaseType_t ) 0 ) +#define pdTRUE ( ( BaseType_t ) 1 ) + +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) + +#define portTICK_RATE_MS portTICK_PERIOD_MS +#define pdMS_TO_TICKS(tick) (tick) + +uint32_t esp_get_free_heap_size(void); +uint32_t esp_random(void); diff --git a/components/mdns/host_test/components/freertos_linux/include/freertos/task.h b/components/mdns/host_test/components/freertos_linux/include/freertos/task.h new file mode 100644 index 000000000..f6c213ed4 --- /dev/null +++ b/components/mdns/host_test/components/freertos_linux/include/freertos/task.h @@ -0,0 +1,58 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include "freertos/FreeRTOS.h" + +#define xTaskHandle TaskHandle_t +#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) ) + +void vTaskDelay( const TickType_t xTicksToDelay ); + +void xTaskNotifyGive(TaskHandle_t task); + +TaskHandle_t xTaskGetCurrentTaskHandle(void); + +BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time ); + +BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pvCreatedTask, + const BaseType_t xCoreID); + +void xTaskCreate(TaskFunction_t pvTaskCode, const char * const pcName, const uint32_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pvCreatedTask); + +TickType_t xTaskGetTickCount( void ); + +void vQueueDelete( QueueHandle_t xQueue ); + +QueueHandle_t xSemaphoreCreateBinary(void); + +QueueHandle_t xSemaphoreCreateMutex(void); + +BaseType_t xSemaphoreGive( QueueHandle_t xQueue); + +BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask ); + +void vTaskDelete(TaskHandle_t *task); + +QueueHandle_t xQueueCreate( uint32_t uxQueueLength, + uint32_t uxItemSize ); + +uint32_t xQueueSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait); + +uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait); diff --git a/components/mdns/host_test/components/freertos_linux/queue_unique_ptr.cpp b/components/mdns/host_test/components/freertos_linux/queue_unique_ptr.cpp new file mode 100644 index 000000000..60c4a8a28 --- /dev/null +++ b/components/mdns/host_test/components/freertos_linux/queue_unique_ptr.cpp @@ -0,0 +1,51 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "queue_unique_ptr.hpp" +#include +#include +#include +#include + +extern "C" void * create_q(void) +{ + auto * q = new QueueMock>(); + return q; +} + +extern "C" void destroy_q(void* q) +{ + auto * queue = static_cast> *>(q); + delete(queue); +} + +extern "C" bool send_q(void* q, uint8_t *data, size_t len) +{ + auto v = std::make_unique>(len); + v->assign(data, data+len); + auto queue = static_cast> *>(q); + queue->send(std::move(v)); + return true; +} + +extern "C" bool recv_q(void* q, uint8_t *data, size_t len, uint32_t ms) +{ + auto queue = static_cast> *>(q); + auto v = queue->receive(ms); + if (v == nullptr) { + return false; + } + memcpy(data, (void *)v->data(), len); + return true; +} diff --git a/components/mdns/host_test/components/freertos_linux/queue_unique_ptr.hpp b/components/mdns/host_test/components/freertos_linux/queue_unique_ptr.hpp new file mode 100644 index 000000000..fe722b97f --- /dev/null +++ b/components/mdns/host_test/components/freertos_linux/queue_unique_ptr.hpp @@ -0,0 +1,55 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include +#include + +template +class QueueMock +{ +public: + QueueMock(void): q(), m(), c() {} + ~QueueMock(void) {} + +void send(std::unique_ptr t) +{ + std::lock_guard lock(m); + q.push(std::move(t)); + c.notify_one(); +} + +std::unique_ptr receive(uint32_t ms) +{ + std::unique_lock lock(m); + while(q.empty()) { + if (c.wait_for(lock, std::chrono::milliseconds(ms)) == std::cv_status::timeout) { + return nullptr; + } + } + std::unique_ptr val = std::move(q.front()); + q.pop(); + return val; +} + +private: + std::queue> q; + mutable std::mutex m; + std::condition_variable c; +}; diff --git a/components/mdns/host_test/main/CMakeLists.txt b/components/mdns/host_test/main/CMakeLists.txt new file mode 100644 index 000000000..8d5202d64 --- /dev/null +++ b/components/mdns/host_test/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS + "." + REQUIRES mdns) diff --git a/components/mdns/host_test/main/main.c b/components/mdns/host_test/main/main.c new file mode 100644 index 000000000..f3883b8c3 --- /dev/null +++ b/components/mdns/host_test/main/main.c @@ -0,0 +1,59 @@ +#include +#include "mdns.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "mdns-test"; + +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, "%x: Host was not found!", (err)); + return; + } + ESP_LOGE(TAG, "Query Failed: %x", (err)); + return; + } + + ESP_LOGI(TAG, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr)); +} + +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" }; + esp_netif_config_t cfg = { .base = &base_cg }; + esp_netif_t *sta = esp_netif_new(&cfg); + + mdns_init(); + + mdns_hostname_set("myesp"); + ESP_LOGI(TAG, "mdns hostname set to: [%s]", "myesp"); + //set default mDNS instance name + mdns_instance_name_set("myesp-inst"); + //structure with TXT records + mdns_txt_item_t serviceTxtData[3] = { + {"board","esp32"}, + {"u","user"}, + {"p","password"} + }; + vTaskDelay(1000); + ESP_ERROR_CHECK(mdns_service_add("myesp-service2", "_http", "_tcp", 80, serviceTxtData, 3)); + vTaskDelay(2000); + + query_mdns_host("david-comp"); + vTaskDelay(2000); + esp_netif_destroy(sta); + mdns_free(); + ESP_LOGI(TAG, "Exit"); + return 0; +} diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index 3d181a1b5..5e6deeab5 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -14,8 +14,10 @@ #ifndef MDNS_PRIVATE_H_ #define MDNS_PRIVATE_H_ +#include "sdkconfig.h" #include "mdns.h" #include "esp_task.h" +#include "esp_timer.h" //#define MDNS_ENABLE_DEBUG