From 2ccf030fd1ee7ddf7c015217c7fbc9996c735fd1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Jul 2019 15:38:48 +1000 Subject: [PATCH] esp32: Add support for mDNS queries and responder. They are both enabled by default, but can be disabled by defining MICROPY_HW_ENABLE_MDNS_QUERIES and/or MICROPY_HW_ENABLE_MDNS_RESPONDER to 0. The hostname for the responder is currently taken from tcpip_adapter_get_hostname() but should eventually be configurable. --- ports/esp32/Makefile | 6 ++++ ports/esp32/modnetwork.c | 20 +++++++++++++ ports/esp32/modsocket.c | 57 +++++++++++++++++++++++++++++++++++++- ports/esp32/mpconfigport.h | 8 ++++++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index c6ef04b465..f30a7cfadd 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -74,6 +74,7 @@ INC += -I$(BUILD) INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include_bootloader +INC_ESPCOMP += -I$(ESPCOMP)/console INC_ESPCOMP += -I$(ESPCOMP)/driver/include INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include @@ -103,6 +104,8 @@ INC_ESPCOMP += -I$(ESPCOMP)/lwip/port/esp32/include INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include +INC_ESPCOMP += -I$(ESPCOMP)/mdns/include +INC_ESPCOMP += -I$(ESPCOMP)/mdns/private_include INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include INC_ESPCOMP += -I$(ESPCOMP)/ulp/include INC_ESPCOMP += -I$(ESPCOMP)/vfs/include @@ -346,6 +349,8 @@ ESPIDF_MBEDTLS_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/mbedtls/port/*.c) \ ) +ESPIDF_MDNS_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/mdns/*.c)) + $(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DALLOW_EVEN_MOD -D__ets__ -Wno-strict-aliasing ESPIDF_WPA_SUPPLICANT_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/wpa_supplicant/port/*.c) \ @@ -390,6 +395,7 @@ $(eval $(call gen_espidf_lib_rule,spi_flash,$(ESPIDF_SPI_FLASH_O))) $(eval $(call gen_espidf_lib_rule,ulp,$(ESPIDF_ULP_O))) $(eval $(call gen_espidf_lib_rule,lwip,$(ESPIDF_LWIP_O))) $(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O))) +$(eval $(call gen_espidf_lib_rule,mdns,$(ESPIDF_MDNS_O))) $(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) $(eval $(call gen_espidf_lib_rule,sdmmc,$(ESPIDF_SDMMC_O))) diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 8462576058..3dfe3945bb 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -48,6 +48,7 @@ #include "esp_event_loop.h" #include "lwip/dns.h" #include "tcpip_adapter.h" +#include "mdns.h" #include "modnetwork.h" @@ -128,6 +129,11 @@ static bool wifi_sta_connected = false; // Store the current status. 0 means None here, safe to do so as first enum value is WIFI_REASON_UNSPECIFIED=1. static uint8_t wifi_sta_disconn_reason = 0; +#if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER +// Whether mDNS has been initialised or not +static bool mdns_initialised = false; +#endif + // This function is called by the system-event task and so runs in a different // thread to the main MicroPython task. It must not raise any Python exceptions. static esp_err_t event_handler(void *ctx, system_event_t *event) { @@ -142,6 +148,20 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { ESP_LOGI("network", "GOT_IP"); wifi_sta_connected = true; wifi_sta_disconn_reason = 0; // Success so clear error. (in case of new error will be replaced anyway) + #if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER + if (!mdns_initialised) { + mdns_init(); + #if MICROPY_HW_ENABLE_MDNS_RESPONDER + const char *hostname = NULL; + if (tcpip_adapter_get_hostname(WIFI_IF_STA, &hostname) != ESP_OK || hostname == NULL) { + hostname = "esp32"; + } + mdns_hostname_set(hostname); + mdns_instance_name_set(hostname); + #endif + mdns_initialised = true; + } + #endif break; case SYSTEM_EVENT_STA_DISCONNECTED: { // This is a workaround as ESP32 WiFi libs don't currently diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 8b80e631db..a6f29718d8 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -47,6 +47,7 @@ #include "py/mperrno.h" #include "lib/netutils/netutils.h" #include "tcpip_adapter.h" +#include "mdns.h" #include "modnetwork.h" #include "lwip/sockets.h" @@ -56,6 +57,8 @@ #include "esp_log.h" #define SOCKET_POLL_US (100000) +#define MDNS_QUERY_TIMEOUT_MS (5000) +#define MDNS_LOCAL_SUFFIX ".local" typedef struct _socket_obj_t { mp_obj_base_t base; @@ -150,6 +153,58 @@ static inline void check_for_exceptions(void) { mp_handle_pending(); } +// This function mimics lwip_getaddrinfo, with added support for mDNS queries +static int _socket_getaddrinfo3(const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) { + + #if MICROPY_HW_ENABLE_MDNS_QUERIES + int nodename_len = strlen(nodename); + const int local_len = sizeof(MDNS_LOCAL_SUFFIX) - 1; + if (nodename_len > local_len + && strcasecmp(nodename + nodename_len - local_len, MDNS_LOCAL_SUFFIX) == 0) { + // mDNS query + char nodename_no_local[nodename_len - local_len + 1]; + memcpy(nodename_no_local, nodename, nodename_len - local_len); + nodename_no_local[nodename_len - local_len] = '\0'; + + struct ip4_addr addr = {0}; + esp_err_t err = mdns_query_a(nodename_no_local, MDNS_QUERY_TIMEOUT_MS, &addr); + if (err != ESP_OK) { + if (err == ESP_ERR_NOT_FOUND){ + *res = NULL; + return 0; + } + *res = NULL; + return err; + } + + struct addrinfo *ai = memp_malloc(MEMP_NETDB); + if (ai == NULL) { + *res = NULL; + return EAI_MEMORY; + } + memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); + + struct sockaddr_in *sa = (struct sockaddr_in*)((uint8_t*)ai + sizeof(struct addrinfo)); + inet_addr_from_ip4addr(&sa->sin_addr, &addr); + sa->sin_family = AF_INET; + sa->sin_len = sizeof(struct sockaddr_in); + sa->sin_port = lwip_htons((u16_t)atoi(servname)); + ai->ai_family = AF_INET; + ai->ai_canonname = ((char*)sa + sizeof(struct sockaddr_storage)); + memcpy(ai->ai_canonname, nodename, nodename_len + 1); + ai->ai_addrlen = sizeof(struct sockaddr_storage); + ai->ai_addr = (struct sockaddr*)sa; + + *res = ai; + return 0; + } + #endif + + // Normal query + return lwip_getaddrinfo(nodename, servname, hints, res); +} + static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) { const struct addrinfo hints = { .ai_family = AF_INET, @@ -172,7 +227,7 @@ static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struc } MP_THREAD_GIL_EXIT(); - int res = lwip_getaddrinfo(host_str, port_str, &hints, resp); + int res = _socket_getaddrinfo3(host_str, port_str, &hints, resp); MP_THREAD_GIL_ENTER(); return res; diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 9ffe380fca..b5c7f50792 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -272,3 +272,11 @@ typedef long mp_off_t; #define MICROPY_HW_BOARD_NAME "ESP32 module" #define MICROPY_HW_MCU_NAME "ESP32" #define MICROPY_PY_SYS_PLATFORM "esp32" + +#ifndef MICROPY_HW_ENABLE_MDNS_QUERIES +#define MICROPY_HW_ENABLE_MDNS_QUERIES (1) +#endif + +#ifndef MICROPY_HW_ENABLE_MDNS_RESPONDER +#define MICROPY_HW_ENABLE_MDNS_RESPONDER (1) +#endif