From 3f588e970af0df0e8b14ba64a4cab680913bd853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 26 Aug 2022 23:09:35 +0200 Subject: [PATCH] [core] Rework mDNS responder to fix TXT records --- arduino/libretuya/libraries/mDNS/LwIPmDNS.cpp | 153 +++++++----------- arduino/libretuya/libraries/mDNS/mDNS.cpp | 40 +++++ arduino/libretuya/libraries/mDNS/mDNS.h | 27 ++-- builder/utils/env.py | 1 + platform/beken-72xx/config/lwipopts.h | 5 +- platform/common/config/lwipopts.h | 10 ++ platform/realtek-amb/config/lwipopts.h | 4 - 7 files changed, 127 insertions(+), 113 deletions(-) create mode 100644 arduino/libretuya/libraries/mDNS/mDNS.cpp create mode 100644 platform/common/config/lwipopts.h diff --git a/arduino/libretuya/libraries/mDNS/LwIPmDNS.cpp b/arduino/libretuya/libraries/mDNS/LwIPmDNS.cpp index f4735bc..e5c0098 100644 --- a/arduino/libretuya/libraries/mDNS/LwIPmDNS.cpp +++ b/arduino/libretuya/libraries/mDNS/LwIPmDNS.cpp @@ -3,6 +3,7 @@ #ifdef LT_HAS_LWIP2 #include "mDNS.h" +#include extern "C" { #include @@ -11,59 +12,35 @@ extern "C" { static u8_t mdns_netif_client_id = 0; // TODO fix this -struct mdns_domain { - /* Encoded domain name */ - u8_t name[256]; - /* Total length of domain name, including zero */ - u16_t length; - /* Set if compression of this domain is not allowed */ - u8_t skip_compression; -}; - -/** Description of a service */ -struct mdns_service { - /** TXT record to answer with */ - struct mdns_domain txtdata; - /** Name of service, like 'myweb' */ - char name[MDNS_LABEL_MAXLEN + 1]; - /** Type of service, like '_http' */ - char service[MDNS_LABEL_MAXLEN + 1]; - /** Callback function and userdata - * to update txtdata buffer */ - service_get_txt_fn_t txt_fn; - void *txt_userdata; - /** TTL in seconds of SRV/TXT replies */ - u32_t dns_ttl; - /** Protocol, TCP or UDP */ - u16_t proto; - /** Port of the service */ - u16_t port; -}; - -/** Description of a host/netif */ -struct mdns_host { - /** Hostname */ - char name[MDNS_LABEL_MAXLEN + 1]; - /** Pointer to services */ - struct mdns_service *services[MDNS_MAX_SERVICES]; - /** TTL in seconds of A/AAAA/PTR replies */ - u32_t dns_ttl; -}; - -static String mdnsInstanceName = "default_instance"; +static std::vector services; +static std::vector protos; +static std::vector> records; mDNS::mDNS() {} mDNS::~mDNS() {} +static void mdnsTxtCallback(struct mdns_service *service, void *userdata) { + size_t index = (size_t)userdata; + if (index >= records.size()) + return; + + for (const auto record : records[index]) { + err_t err = mdns_resp_add_service_txtitem(service, record, strlen(record)); + if (err != ERR_OK) + return; + } +} + +static void mdnsStatusCallback(struct netif *netif, uint8_t result) {} + bool mDNS::begin(const char *hostname) { + mdns_resp_register_name_result_cb(mdnsStatusCallback); mdns_resp_init(); struct netif *netif = netif_list; uint8_t enabled = 0; while (netif != NULL) { netif->flags |= NETIF_FLAG_IGMP; - // TODO: detect mdns_netif_client_id by checking netif_get_client_data() - // and finding the requested hostname in struct mdns_host if (netif_is_up(netif) && mdns_resp_add_netif(netif, hostname, 255) == ERR_OK) { enabled++; } @@ -81,72 +58,52 @@ void mDNS::end() { } } -void mDNS::setInstanceName(String name) { - mdnsInstanceName = name; -} - -bool mDNS::addService(char *service, char *proto, uint16_t port) { - char _service[strlen(service) + 2]; - char _proto[strlen(proto) + 2]; - _service[0] = '_'; - _proto[0] = '_'; - // prepend names with _ - strcpy(_service + 1, service + (service[0] == '_')); - strcpy(_proto + 1, proto + (proto[0] == '_')); - - mdns_sd_proto protocol = DNSSD_PROTO_UDP; - if (strncmp(_proto + 1, "tcp", 3) == 0) - protocol = DNSSD_PROTO_TCP; - +bool mDNS::addServiceImpl(const char *name, const char *service, uint8_t proto, uint16_t port) { + bool added = false; struct netif *netif = netif_list; while (netif != NULL) { if (netif_is_up(netif)) { - mdns_resp_add_service(netif, mdnsInstanceName.c_str(), _service, protocol, port, 255, NULL, NULL); + // register TXT callback; + // pass service index as userdata parameter + mdns_resp_add_service( + netif, + name, + service, + (mdns_sd_proto)proto, + port, + 255, + mdnsTxtCallback, + (void *)services.size() // index of newly added service + ); + added = true; } netif = netif->next; } + + if (!added) + return false; + + // add the service to TXT record arrays + services.push_back(strdup(service)); + protos.push_back(proto); + records.emplace_back(); + + return true; } -bool mDNS::addServiceTxt(char *name, char *proto, char *key, char *value) { - char _name[strlen(name) + 2]; - char _proto[strlen(proto) + 2]; - _name[0] = '_'; - _proto[0] = '_'; - // prepend names with _ - strcpy(_name + 1, name + (name[0] == '_')); - strcpy(_proto + 1, proto + (proto[0] == '_')); - - mdns_sd_proto protocol = DNSSD_PROTO_UDP; - if (strncmp(_proto + 1, "tcp", 3) == 0) - protocol = DNSSD_PROTO_TCP; - - struct netif *netif = netif_list; - struct mdns_host *mdns; - struct mdns_service *service; - - uint8_t txt_len = strlen(key) + strlen(value) + 1; - char *txt = (char *)malloc(txt_len + 1); - sprintf(txt, "%s=%s", key, value); - - while (netif != NULL) { - if (netif_is_up(netif)) { - mdns = (struct mdns_host *)netif_get_client_data(netif, mdns_netif_client_id); - - for (uint8_t i = 0; i < MDNS_MAX_SERVICES; i++) { - service = mdns->services[i]; - if (service == NULL) - continue; - if (strcmp(service->service, _name) || service->proto != protocol) - continue; - if (mdns_resp_add_service_txtitem(service, txt, txt_len) != ERR_OK) { - free(txt); - return false; - } - } +bool mDNS::addServiceTxtImpl(const char *service, uint8_t proto, const char *item) { + int8_t index = -1; + for (uint8_t i = 0; i < services.size(); i++) { + // find a matching service + if (strcmp(services[i], service) == 0 && protos[i] == proto) { + index = i; + break; } - netif = netif->next; } - free(txt); + if (index == -1) + return false; + + records[index].push_back(strdup(item)); return true; } diff --git a/arduino/libretuya/libraries/mDNS/mDNS.cpp b/arduino/libretuya/libraries/mDNS/mDNS.cpp new file mode 100644 index 0000000..4de68fd --- /dev/null +++ b/arduino/libretuya/libraries/mDNS/mDNS.cpp @@ -0,0 +1,40 @@ +/* Copyright (c) Kuba SzczodrzyƄski 2022-08-26. */ + +#include "mDNS.h" + +static char *ensureUnderscore(const char *value) { + uint8_t len = strlen(value) + 1; + char *result = (char *)malloc(len); + result[0] = '_'; + strcpy(result + 1, value + (value[0] == '_')); + return result; +} + +void mDNS::setInstanceName(const char *name) { + if (instanceName) + free(instanceName); + instanceName = strdup(name); +} + +bool mDNS::addService(char *service, char *proto, uint16_t port) { + char *_service = ensureUnderscore(service); + uint8_t _proto = strncmp(proto + (proto[0] == '_'), "tcp", 3) == 0 ? MDNS_TCP : MDNS_UDP; + + bool result = addServiceImpl(instanceName ? instanceName : "LT mDNS", _service, _proto, port); + free(_service); + return result; +} + +bool mDNS::addServiceTxt(char *service, char *proto, char *key, char *value) { + char *_service = ensureUnderscore(service); + uint8_t _proto = strncmp(proto + (proto[0] == '_'), "tcp", 3) == 0 ? MDNS_TCP : MDNS_UDP; + + uint8_t txt_len = strlen(key) + strlen(value) + 1; + char *txt = (char *)malloc(txt_len + 1); + sprintf(txt, "%s=%s", key, value); + + bool result = addServiceTxtImpl(_service, _proto, txt); + free(_service); + free(txt); + return result; +} diff --git a/arduino/libretuya/libraries/mDNS/mDNS.h b/arduino/libretuya/libraries/mDNS/mDNS.h index 225b446..6a15cd3 100644 --- a/arduino/libretuya/libraries/mDNS/mDNS.h +++ b/arduino/libretuya/libraries/mDNS/mDNS.h @@ -44,7 +44,16 @@ License (MIT license): #include #include +#define MDNS_UDP 0 +#define MDNS_TCP 1 + class mDNS { + private: + bool addServiceImpl(const char *name, const char *service, uint8_t proto, uint16_t port); + bool addServiceTxtImpl(const char *service, uint8_t proto, const char *item); + + char *instanceName = NULL; + public: mDNS(); ~mDNS(); @@ -52,9 +61,9 @@ class mDNS { bool begin(const char *hostname); void end(); - void setInstanceName(String name); + void setInstanceName(const char *name); bool addService(char *service, char *proto, uint16_t port); - bool addServiceTxt(char *name, char *proto, char *key, char *value); + bool addServiceTxt(char *service, char *proto, char *key, char *value); // void enableArduino(uint16_t port = 3232, bool auth = false); // void disableArduino(); // void enableWorkstation(esp_interface_t interface = ESP_IF_WIFI_STA); @@ -73,12 +82,12 @@ class mDNS { String txt(int idx, int txtIdx); String txtKey(int idx, int txtIdx); - void setInstanceName(const char *name) { - setInstanceName(String(name)); + void setInstanceName(String name) { + setInstanceName(name.c_str()); } void setInstanceName(char *name) { - setInstanceName(String(name)); + setInstanceName((const char *)name); } bool addService(const char *service, const char *proto, uint16_t port) { @@ -89,12 +98,12 @@ class mDNS { return addService(service.c_str(), proto.c_str(), port); } - void addServiceTxt(const char *name, const char *proto, const char *key, const char *value) { - addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value); + void addServiceTxt(const char *service, const char *proto, const char *key, const char *value) { + addServiceTxt((char *)service, (char *)proto, (char *)key, (char *)value); } - void addServiceTxt(String name, String proto, String key, String value) { - addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str()); + void addServiceTxt(String service, String proto, String key, String value) { + addServiceTxt(service.c_str(), proto.c_str(), key.c_str(), value.c_str()); } IPAddress queryHost(const char *host, uint32_t timeout = 2000) { diff --git a/builder/utils/env.py b/builder/utils/env.py index 1cff8cc..ae5a1c1 100644 --- a/builder/utils/env.py +++ b/builder/utils/env.py @@ -47,6 +47,7 @@ def env_add_defaults(env, platform, board): # Default build options env.Prepend( CPPPATH=[ + "$LT_DIR/platform/common/config", "$LT_DIR/platform/common/fixups", "$LT_DIR/platform/common/fixups/lib_inc", "$BOARD_DIR", diff --git a/platform/beken-72xx/config/lwipopts.h b/platform/beken-72xx/config/lwipopts.h index 9504ba1..ed0552d 100644 --- a/platform/beken-72xx/config/lwipopts.h +++ b/platform/beken-72xx/config/lwipopts.h @@ -6,9 +6,10 @@ #include -#define LWIP_MDNS_RESPONDER 1 +// mDNS support +#undef MEMP_NUM_UDP_PCB #define LWIP_NUM_NETIF_CLIENT_DATA 1 -#define LWIP_SO_RCVBUF 1 // for ioctl(FIONREAD) +#define MEMP_NUM_UDP_PCB (MAX_SOCKETS_UDP + 2 + 1) #define ip_addr ip4_addr #define ip_addr_t ip4_addr_t diff --git a/platform/common/config/lwipopts.h b/platform/common/config/lwipopts.h new file mode 100644 index 0000000..76f79b3 --- /dev/null +++ b/platform/common/config/lwipopts.h @@ -0,0 +1,10 @@ +/* Copyright (c) Kuba SzczodrzyƄski 2022-08-26. */ + +#define LWIP_TIMEVAL_PRIVATE 0 +#define LWIP_NETIF_HOSTNAME 1 // to support hostname changing +#define LWIP_SO_RCVBUF 1 // for ioctl(FIONREAD) + +#define LWIP_MDNS_RESPONDER 1 +#define MDNS_MAX_SERVICES 10 + +#include_next "lwipopts.h" diff --git a/platform/realtek-amb/config/lwipopts.h b/platform/realtek-amb/config/lwipopts.h index e16e540..97af786 100644 --- a/platform/realtek-amb/config/lwipopts.h +++ b/platform/realtek-amb/config/lwipopts.h @@ -2,10 +2,6 @@ #pragma once -#define LWIP_TIMEVAL_PRIVATE 0 -#define LWIP_NETIF_HOSTNAME 1 // to support hostname changing -#define LWIP_SO_RCVBUF 1 // for ioctl(FIONREAD) - #include_next "lwipopts.h" #define ip_addr ip4_addr // LwIP 2.0.x compatibility