From 66e79bf81a51d479b8e5ff92a461d4a58dcba5a8 Mon Sep 17 00:00:00 2001 From: LaborEtArs Date: Mon, 2 Dec 2019 19:19:27 +0100 Subject: [PATCH 01/12] LEAmDNS2 (Host Version) --- .../ESP8266WebServer/src/detail/RequestHandler.h | 3 ++- libraries/ESP8266WiFi/src/include/UdpContext.h | 16 ++++++++++++++++ libraries/ESP8266mDNS/src/ESP8266mDNS.h | 2 ++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandler.h b/libraries/ESP8266WebServer/src/detail/RequestHandler.h index db840af2a1..7da7f4be9c 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandler.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandler.h @@ -5,8 +5,9 @@ template class RequestHandler { - using WebServerType = ESP8266WebServerTemplate; public: + using WebServerType = ESP8266WebServerTemplate; + virtual ~RequestHandler() { } virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; } virtual bool canUpload(String uri) { (void) uri; return false; } diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index 8ad074eeec..9ac77ce4da 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -167,6 +167,22 @@ class UdpContext #endif // !LWIP_IPV6 + /* + * Add a netif (by its index) as the multicast interface + */ + void setMulticastInterface(netif* p_pNetIf) + { + udp_set_multicast_netif_index(_pcb, netif_get_index(p_pNetIf)); + } + + /* + * Allow access to pcb to change eg. options + */ + udp_pcb* pcb(void) + { + return _pcb; + } + void setMulticastTTL(int ttl) { #ifdef LWIP_MAYBE_XCC diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS.h b/libraries/ESP8266mDNS/src/ESP8266mDNS.h index 66d40b1b2e..585ddfbbec 100644 --- a/libraries/ESP8266mDNS/src/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/src/ESP8266mDNS.h @@ -44,12 +44,14 @@ #include "ESP8266mDNS_Legacy.h" #include "LEAmDNS.h" +#include "LEAmDNS2.h" #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) // Maps the implementation to use to the global namespace type //using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; //legacy using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new +//using MDNSResponder = esp8266::experimental::MDNSResponder; //new^2 not compatible extern MDNSResponder MDNS; #endif From af3a877e56103cd5fa01543dc971f5b06eb54150 Mon Sep 17 00:00:00 2001 From: LaborEtArs Date: Tue, 3 Dec 2019 18:18:53 +0100 Subject: [PATCH 02/12] Second try :-) --- libraries/ESP8266mDNS/src/LEAmDNS2.h | 1303 ++++++ libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp | 4164 +++++++++++++++++ .../ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp | 354 ++ libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp | 1336 ++++++ libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp | 1177 +++++ .../ESP8266mDNS/src/LEAmDNS2_Host_Control.cpp | 2207 +++++++++ .../ESP8266mDNS/src/LEAmDNS2_Host_Debug.cpp | 327 ++ .../ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp | 2435 ++++++++++ .../src/LEAmDNS2_Host_Transfer.cpp | 2390 ++++++++++ libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h | 169 + libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h | 44 + 11 files changed, 15906 insertions(+) create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2.h create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Host_Control.cpp create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Host_Debug.cpp create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Host_Transfer.cpp create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h create mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2.h b/libraries/ESP8266mDNS/src/LEAmDNS2.h new file mode 100755 index 0000000000..7aa3bb0160 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2.h @@ -0,0 +1,1303 @@ +/* + LEAmDNS2.h + (c) 2018, LaborEtArs + + Version 0.9 beta + + Some notes (from LaborEtArs, 2018): + Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS). + The target of this rewrite was to keep the existing interface as stable as possible while + adding and extending the supported set of mDNS features. + A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code. + + Supported mDNS features (in some cases somewhat limited): + - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service + - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented + - Probing host and service domains for uniqueness in the local network + - Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak) + - Announcing available services after successful probing + - Using fixed service TXT items or + - Using dynamic service TXT items for presented services (via callback) + - Remove services (and un-announcing them to the observers by sending goodbye-messages) + - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) + - Dynamic queries for DNS-SD services with cached and updated answers and user notifications + + + Usage: + In most cases, this implementation should work as a 'drop-in' replacement for the original + ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some + of the new features should be used. + + For presenting services: + In 'setup()': + Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);' + Register DNS-SD services with 'MDNSResponder::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);' + (Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);') + Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback + using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific + 'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);' + Call MDNS.begin("MyHostName"); + + In 'probeResultCallback(MDNSResponder* p_MDNSResponder, const char* p_pcDomain, MDNSResponder:hMDNSService p_hMDNSService, bool p_bProbeResult, void* p_pUserdata)': + Check the probe result and update the host or service domain name if the probe failed + + In 'dynamicServiceTxtCallback(MDNSResponder* p_MDNSResponder, const hMDNSService p_hMDNSService, void* p_pUserdata)': + Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hMDNSService, "c#", "1");' + + In loop(): + Call 'MDNS.update();' + + + For querying services/hosts: + Static: + Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");' or 'MDNS.queryHost("esp8266")'; + Iterate answers by: 'for (uint32_t u=0; u // for UdpContext.h +#include +#include +#include + +#include "lwip/netif.h" +#include "WiFiUdp.h" +#include "lwip/udp.h" +#include "debug.h" +#include "include/UdpContext.h" +#include + +#include "ESP8266WiFi.h" + + +namespace esp8266 +{ + +/** + LEAmDNS +*/ +namespace experimental +{ + +//this should be user-defined at build time +#ifndef ARDUINO_BOARD +#define ARDUINO_BOARD "generic" +#endif + +#define MDNS_IPV4_SUPPORT +#if LWIP_IPV6 +#define MDNS_IPV6_SUPPORT // If we've got IPv6 support, then we need IPv6 support :-) +#endif + + +#ifdef MDNS_IPV4_SUPPORT +#define MDNS_IPV4_SIZE 4 +#endif +#ifdef MDNS_IPV6_SUPPORT +#define MDNS_IPV6_SIZE 16 +#endif +/* + Maximum length for all service txts for one service +*/ +#define MDNS_SERVICE_TXT_MAXLENGTH 1300 +/* + Maximum length for a full domain name eg. MyESP._http._tcp.local +*/ +#define MDNS_DOMAIN_MAXLENGTH 256 +/* + Maximum length of on label in a domain name (length info fits into 6 bits) +*/ +#define MDNS_DOMAIN_LABEL_MAXLENGTH 63 +/* + Maximum length of a service name eg. http +*/ +#define MDNS_SERVICE_NAME_LENGTH 15 +/* + Maximum length of a service protocol name eg. tcp +*/ +#define MDNS_SERVICE_PROTOCOL_LENGTH 3 +/* + Default timeout for static service queries +*/ +#define MDNS_QUERYSERVICES_WAIT_TIME 5000 + +/* + DNS_RRTYPE_NSEC +*/ +#ifndef DNS_RRTYPE_NSEC +#define DNS_RRTYPE_NSEC 0x2F +#endif + + +/** + MDNSResponder +*/ +class MDNSResponder +{ +protected: +#include "LEAmDNS2_Host.hpp" + +public: + // MISC HELPERS + // Domain name helper + static bool indexDomain(char*& p_rpcDomain, + const char* p_pcDivider = "-", + const char* p_pcDefaultDomain = 0); + // Host name helper + static bool setNetIfHostName(netif* p_pNetIf, + const char* p_pcHostName); + + // INTERFACE + MDNSResponder(void); + virtual ~MDNSResponder(void); + + // HANDLEs for opaque access to responder objects + /** + hMDNSHost + */ + using hMDNSHost = const void*; + /** + hMDNSService + */ + using hMDNSService = const void*; + /** + hMDNSTxt + */ + using hMDNSTxt = const void*; + /** + hMDNSQuery + */ + using hMDNSQuery = const void*; + + // CALLBACKS + /** + MDNSHostProbeResultCallbackFn + Callback function for host domain probe results + */ + using MDNSHostProbeResultCallbackFn = std::function; + + // Create a MDNS netif responder netif by setting the default hostname + // Later call 'update()' in every 'loop' to run the process loop + // (probing, announcing, responding, ...) + // If no callback is given, the (maybe) already installed callback stays set + hMDNSHost begin(const char* p_pcHostName, + netif* p_pNetIf, + MDNSHostProbeResultCallbackFn p_fnCallback = 0); + bool begin(const char* p_pcHostName, + WiFiMode_t p_WiFiMode, + MDNSHostProbeResultCallbackFn p_fnCallback = 0); + bool begin(const char* p_pcHostName, + MDNSHostProbeResultCallbackFn p_fnCallback = 0); + + // Finish MDNS processing + bool close(const hMDNSHost p_hMDNSHost); + bool close(void); + + hMDNSHost getMDNSHost(netif* p_pNetIf) const; + hMDNSHost getMDNSHost(WiFiMode_t p_WiFiMode) const; + + // Change hostname (probing is restarted) + // If no callback is given, the (maybe) already installed callback stays set + bool setHostName(const hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + MDNSHostProbeResultCallbackFn p_fnCallback = 0); + + const char* hostName(const hMDNSHost p_hMDNSHost) const; + + // Set a callback function for host probe results + // The callback function is called, when the probeing for the host domain + // succeededs or fails. + // In case of failure, the failed domain name should be changed. + bool setHostProbeResultCallback(const hMDNSHost p_hMDNSHost, + MDNSHostProbeResultCallbackFn p_fnCallback); + + // Returns 'true' is host domain probing is done + bool status(const hMDNSHost p_hMDNSHost) const; + + // Add a 'global' default' instance name for new services + bool setInstanceName(const hMDNSHost p_hMDNSHost, + const char* p_pcInstanceName); + const char* instanceName(const hMDNSHost p_hMDNSHost) const; + + /** + MDNSServiceProbeResultCallbackFn + Callback function for service domain probe results + */ + using MDNSServiceProbeResultCallbackFn = std::function; + // Add a new service to the MDNS responder. If no name (instance name) is given (p_pcName = 0) + // the current hostname is used. If the hostname is changed later, the instance names for + // these 'auto-named' services are changed to the new name also (and probing is restarted). + // The usual '_' before p_pcService (eg. http) and protocol (eg. tcp) may be given.# + // If no callback is given, the (maybe) already installed callback stays set + hMDNSService addService(const hMDNSHost p_hMDNSHost, + const char* p_pcName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port, + MDNSServiceProbeResultCallbackFn p_fnCallback = 0); + // Removes a service from the MDNS responder + bool removeService(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService); + bool removeService(const hMDNSHost p_hMDNSHost, + const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol); + hMDNSService findService(const hMDNSHost p_hMDNSHost, + const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol); + + // Change the services instance name (and restart probing). + // If no callback is given, the (maybe) already installed callback stays set + bool setServiceName(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcInstanceName, + MDNSServiceProbeResultCallbackFn p_fnCallback = 0); + const char* serviceName(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + const char* serviceType(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + const char* serviceProtocol(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + uint16_t servicePort(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + + // Set a service specific probe result callcack + bool setServiceProbeResultCallback(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + MDNSServiceProbeResultCallbackFn p_fnCallback); + + bool serviceStatus(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + + // Add a (static) MDNS TXT item ('key' = 'value') to the service + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value); + + // Remove an existing (static) MDNS TXT item from the service + bool removeServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const hMDNSTxt p_hTxt); + bool removeServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey); + + /** + MDNSDynamicServiceTxtCallbackFn + Callback function for dynamic MDNS TXT items + */ + using MDNSDynamicServiceTxtCallbackFn = std::function; + bool setDynamicServiceTxtCallback(const hMDNSHost p_hMDNSHost, + MDNSDynamicServiceTxtCallbackFn p_fnCallback); + bool setDynamicServiceTxtCallback(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + MDNSDynamicServiceTxtCallbackFn p_fnCallback); + + // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + // Dynamic TXT items are removed right after one-time use. So they need to be added + // every time the value s needed (via callback). + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value); + + // QUERIES & ANSWERS + /** + clsMDNSAnswerAccessor & clsAnswerAccessorVector + */ + struct clsMDNSAnswerAccessor + { + protected: + /** + stcCompareTxtKey + */ + struct stcCompareTxtKey + { + bool operator()(char const* p_pA, char const* p_pB) const; + }; + public: + clsMDNSAnswerAccessor(const clsHost::stcQuery::stcAnswer* p_pAnswer); + ~clsMDNSAnswerAccessor(void); + + /** + clsTxtKeyValueMap + */ + using clsTxtKeyValueMap = std::map; + + bool serviceDomainAvailable(void) const; + const char* serviceDomain(void) const; + bool hostDomainAvailable(void) const; + const char* hostDomain(void) const; + bool hostPortAvailable(void) const; + uint16_t hostPort(void) const; +#ifdef MDNS_IPV4_SUPPORT + bool IPv4AddressAvailable(void) const; + std::vector IPv4Addresses(void) const; +#endif +#ifdef MDNS_IPV6_SUPPORT + bool IPv6AddressAvailable(void) const; + std::vector IPv6Addresses(void) const; +#endif + bool txtsAvailable(void) const; + const char* txts(void) const; + const clsTxtKeyValueMap& txtKeyValues(void) const; + const char* txtValue(const char* p_pcKey) const; + + size_t printTo(Print& p_Print) const; + + protected: + const clsHost::stcQuery::stcAnswer* m_pAnswer; + clsTxtKeyValueMap m_TxtKeyValueMap; + }; + using clsMDNSAnswerAccessorVector = std::vector; + using typeQueryAnswerType = clsHost::typeQueryAnswerType; + using enuQueryAnswerType = clsHost::enuQueryAnswerType; + + // STATIC QUERY + // Perform a (static) service/host query. The function returns after p_u16Timeout milliseconds + // The answers (the number of received answers is returned) can be retrieved by calling + // - answerHostName (or hostname) + // - answerIP (or IP) + // - answerPort (or port) + uint32_t queryService(const hMDNSHost p_hMDNSHost, + const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + uint32_t queryHost(const hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + bool removeQuery(const hMDNSHost p_hMDNSHost); + bool hasQuery(const hMDNSHost p_hMDNSHost); + hMDNSQuery getQuery(const hMDNSHost p_hMDNSHost); + + clsMDNSAnswerAccessorVector answerAccessors(const hMDNSHost p_hMDNSHost); + uint32_t answerCount(const hMDNSHost p_hMDNSHost); + clsMDNSAnswerAccessor answerAccessor(const hMDNSHost p_hMDNSHost, + uint32_t p_u32AnswerIndex); + + // DYNAMIC QUERIES + /** + MDNSQueryCallbackFn + + Callback function for received answers for dynamic queries + */ + using MDNSQueryCallbackFn = std::function; // true: Answer component set, false: component deleted + + // Install a dynamic service/host query. For every received answer (part) the given callback + // function is called. The query will be updated every time, the TTL for an answer + // has timed-out. + // The answers can also be retrieved by calling + // - answerCount service/host (for host queries, this should never be >1) + // - answerServiceDomain service + // - hasAnswerHostDomain/answerHostDomain service/host + // - hasAnswerIPv4Address/answerIPv4Address service/host + // - hasAnswerIPv6Address/answerIPv6Address service/host + // - hasAnswerPort/answerPort service + // - hasAnswerTxts/answerTxts service + hMDNSQuery installServiceQuery(const hMDNSHost p_hMDNSHost, + const char* p_pcServiceType, + const char* p_pcProtocol, + MDNSQueryCallbackFn p_fnCallback); + hMDNSQuery installHostQuery(const hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + MDNSQueryCallbackFn p_fnCallback); + // Remove a dynamic service query + bool removeQuery(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hMDNSQuery); + + + uint32_t answerCount(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hMDNSQuery); + clsMDNSAnswerAccessorVector answerAccessors(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hMDNSQuery); + clsMDNSAnswerAccessor answerAccessor(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hMDNSQuery, + uint32 p_u32AnswerIndex); + + /* bool hasAnswerServiceDomain(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + const char* answerServiceDomain(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerHostDomain(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + const char* answerHostDomain(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + #ifdef MDNS_IPV4_SUPPORT + bool hasAnswerIPv4Address(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIPv4AddressCount(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIPv4Address(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); + #endif + #ifdef MDNS_IPV6_SUPPORT + bool hasAnswerIPv6Address(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIPv6AddressCount(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIPv6Address(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); + #endif + bool hasAnswerPort(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerTxts(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + // Get the TXT items as a ';'-separated string + const char* answerTxts(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex);*/ + + // GENERAL MANAGEMENT + // Application should call this whenever AP is configured/disabled + bool notifyNetIfChange(netif* p_pNetIf); + + // 'update' should be called in every 'loop' to run the MDNS processing + bool update(const hMDNSHost p_hMDNSHost); + bool update(void); // Convenience + + // 'announce' can be called every time, the configuration of some service + // changes. Mainly, this would be changed content of TXT items. + bool announce(const hMDNSHost p_hMDNSHost); + bool announce(void); // Convenience + + // MISC + // Enable OTA update + hMDNSService enableArduino(const hMDNSHost p_hMDNSHost, + uint16_t p_u16Port, + bool p_bAuthUpload = false); + +protected: + /** Internal CLASSES & STRUCTS **/ + + // InstanceData + UdpContext* m_pUDPContext; + clsHostList m_HostList; + + // UDP CONTEXT + bool _allocUDPContext(void); + bool _releaseUDPContext(void); + bool _processUDPInput(void); + + // NETIF + clsHost* _createHost(netif* p_pNetIf); + bool _releaseHost(clsHost* p_pHost); + + const clsHost* _findHost(netif* p_pNetIf) const; + clsHost* _findHost(netif* p_pNetIf); + const clsHost* _findHost(const hMDNSHost p_hMDNSHost) const; + clsHost* _findHost(const hMDNSHost p_hMDNSHost); + + + // HANDLE HELPERS + bool _validateMDNSHostHandle(const hMDNSHost p_hMDNSHost) const; + bool _validateMDNSHostHandle(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + + clsHost* _NRH2Ptr(const hMDNSHost p_hMDNSHost); + const clsHost* _NRH2Ptr(const hMDNSHost p_hMDNSHost) const; + clsHost::stcService* _SH2Ptr(const hMDNSService p_hMDNSService); + const clsHost::stcService* _SH2Ptr(const hMDNSService p_hMDNSService) const; + + // INIT + clsHost* _begin(const char* p_pcHostName, + netif* p_pNetIf, + MDNSHostProbeResultCallbackFn p_fnCallback); + bool _close(clsHost& p_rHost); + + +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + + const char* _DH(hMDNSHost p_hMDNSResponder = 0) const; + +#endif // not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + +}; + +#ifdef __MDNS_USE_LEGACY +/** + MDNSResponder_Legacy +*/ +class MDNSResponder_Legacy //: public MDNSResponder +{ +public: + /* INTERFACE */ + MDNSResponder_Legacy(void); + virtual ~MDNSResponder_Legacy(void); + + /** + hMDNSHost (opaque handle to access a netif binding) + */ + using hMDNSHost = const void*; + /** + hMDNSService (opaque handle to access the service) + */ + using hMDNSService = const void*; + /** + MDNSHostProbeResultCallbackFn + Callback function for host domain probe results + */ + using MDNSHostProbeResultCallbackFn = std::function; + /* LEGACY 2 */ + using MDNSServiceProbeResultCallbackFn1 = std::function; + using MDNSServiceProbeResultCallbackFn2 = std::function; + /** + hMDNSTxt (opaque handle to access the TXT items) + */ + using hMDNSTxt = const void*; + /** + MDNSDynamicServiceTxtCallbackFn + Callback function for dynamic MDNS TXT items + */ + using MDNSDynamicServiceTxtCallbackFn = std::function; + // LEGACY + using MDNSDynamicServiceTxtCallbackFn1 = std::function; + using MDNSDynamicServiceTxtCallbackFn2 = std::function; + + + hMDNSHost getNetIfBinding(netif* p_pNetIf) const; + hMDNSHost getNetIfBinding(WiFiMode_t p_WiFiMode) const; + + // Create a MDNS responder netif binding by setting the default hostname + // Later call 'update()' in every 'loop' to run the process loop + // (probing, announcing, responding, ...) + + hMDNSHost begin(const char* p_pcHostName, + netif* p_pNetIf, + MDNSHostProbeResultCallbackFn p_fnCallback = 0); + bool begin(const char* p_pcHostName, + WiFiMode_t p_WiFiMode, + MDNSHostProbeResultCallbackFn p_fnCallback = 0); + bool begin(const char* p_pcHostName, + MDNSHostProbeResultCallbackFn p_fnCallback = 0); + + /* bool begin(const String& p_strHostName) {return begin(p_strHostName.c_str());} + // for compatibility + bool begin(const char* p_pcHostName, + IPAddress p_IPAddress, // ignored + uint32_t p_u32TTL = 120); // ignored + bool begin(const String& p_strHostName, + IPAddress p_IPAddress, // ignored + uint32_t p_u32TTL = 120) { // ignored + return begin(p_strHostName.c_str(), p_IPAddress, p_u32TTL); + }*/ + // Finish MDNS processing + bool close(const hMDNSHost p_hMDNSHost); + bool close(void); + // for ESP32 compatibility + bool end(void); + + // Change hostname (probing is restarted) + bool setHostName(const hMDNSHost p_hMDNSHost, + const char* p_pcHostName); + // for compatibility... + bool setHostname(const char* p_pcHostName); + bool setHostname(String p_strHostName); + + const char* hostName(const hMDNSHost p_hMDNSHost) const; + const char* hostname(void) const; + + // Returns 'true' is host domain probing is done + bool status(const hMDNSHost p_hMDNSHost) const; + bool status(void) const; + + bool setInstanceName(const hMDNSHost p_hMDNSHost, + const char* p_pcInstanceName); + bool setInstanceName(const char* p_pcInstanceName); + // for ESP32 compatibility + bool setInstanceName(const String& p_strHostName); + + // Add a new service to the MDNS responder. If no name (instance name) is given (p_pcName = 0) + // the current hostname is used. If the hostname is changed later, the instance names for + // these 'auto-named' services are changed to the new name also (and probing is restarted). + // The usual '_' before p_pcService (eg. http) and protocol (eg. tcp) may be given. + hMDNSService addService(const hMDNSHost p_hMDNSHost, + const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port); + hMDNSService addService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port); + // Removes a service from the MDNS responder + bool removeService(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService); + bool removeService(const hMDNSHost p_hMDNSHost, + const char* p_pcInstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol); + bool removeService(const hMDNSService p_hMDNSService); + bool removeService(const char* p_pcInstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol); + // for compatibility... + bool addService(String p_strServiceName, + String p_strProtocol, + uint16_t p_u16Port); + hMDNSService findService(const hMDNSHost p_hMDNSHost, + const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol); + hMDNSService findService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol); + + // Change the services instance name (and restart probing). + bool setServiceName(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcInstanceName); + bool setServiceName(const hMDNSService p_hMDNSService, + const char* p_pcInstanceName); + + const char* serviceName(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + const char* service(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + const char* serviceProtocol(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + /* LEGACY */ + const char* serviceName(const hMDNSService p_hMDNSService) const; + const char* service(const hMDNSService p_hMDNSService) const; + const char* serviceProtocol(const hMDNSService p_hMDNSService) const; + + bool serviceStatus(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const; + bool serviceStatus(const hMDNSService p_hMDNSService) const; + + // Add a (static) MDNS TXT item ('key' = 'value') to the service + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value); + // LEGACY + hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value); + + // Remove an existing (static) MDNS TXT item from the service + bool removeServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const hMDNSTxt p_hTxt); + bool removeServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey); + bool removeServiceTxt(const hMDNSHost p_hMDNSHost, + const char* p_pcinstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol, + const char* p_pcKey); + bool removeServiceTxt(const hMDNSService p_hMDNSService, + const hMDNSTxt p_hTxt); + bool removeServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey); + bool removeServiceTxt(const char* p_pcinstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol, + const char* p_pcKey); + // for compatibility... + bool addServiceTxt(const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey, + const char* p_pcValue); + bool addServiceTxt(String p_strService, + String p_strProtocol, + String p_strKey, + String p_strValue); + + bool setDynamicServiceTxtCallback(const hMDNSHost p_hMDNSHost, + MDNSDynamicServiceTxtCallbackFn p_fnCallback); + bool setDynamicServiceTxtCallback(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + MDNSDynamicServiceTxtCallbackFn p_fnCallback); + + // Set a global callback for dynamic MDNS TXT items. The callback function is called + // every time, a TXT item is needed for one of the installed services. + bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn1 p_fnCallback); + bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn2 p_fnCallback); + + // Set a service specific callback for dynamic MDNS TXT items. The callback function + // is called every time, a TXT item is needed for the given service. + bool setDynamicServiceTxtCallback(const hMDNSService p_hMDNSService, + MDNSDynamicServiceTxtCallbackFn1 p_fnCallback); + bool setDynamicServiceTxtCallback(const hMDNSService p_hMDNSService, + MDNSDynamicServiceTxtCallbackFn2 p_fnCallback); + + // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + // Dynamic TXT items are removed right after one-time use. So they need to be added + // every time the value s needed (via callback). + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value); + /* LEGACY */ + hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value); + + /** + hMDNSQuery (opaque handle to access dynamic service queries) + */ + using hMDNSQuery = const void*; + //using hMDNSServiceQuery = hMDNSQuery; // for compatibility with V1 + + // Perform a (static) service/host query. The function returns after p_u16Timeout milliseconds + // The answers (the number of received answers is returned) can be retrieved by calling + // - answerHostName (or hostname) + // - answerIP (or IP) + // - answerPort (or port) + uint32_t queryService(const hMDNSHost p_hMDNSHost, + const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + uint32_t queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + // for compatibility... + uint32_t queryService(const String& p_strService, + const String& p_strProtocol); + uint32_t queryHost(const hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + uint32_t queryHost(const char* p_pcHostName, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + bool removeQuery(const hMDNSHost p_hMDNSHost); + bool removeQuery(void); + bool hasQuery(const hMDNSHost p_hMDNSHost); + bool hasQuery(void); + hMDNSQuery getQuery(const hMDNSHost p_hMDNSHost); + hMDNSQuery getQuery(void); + + const char* answerHostName(const hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex); + const char* answerHostName(const uint32_t p_u32AnswerIndex); + // for compatibility... + String hostname(const uint32_t p_u32AnswerIndex); +#ifdef MDNS_IPV4_SUPPORT + IPAddress answerIPv4(const hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex); + IPAddress answerIPv4(const uint32_t p_u32AnswerIndex); + // for compatibility + IPAddress answerIP(const uint32_t p_u32AnswerIndex); + IPAddress IP(const uint32_t p_u32AnswerIndex); +#endif +#ifdef MDNS_IPV6_SUPPORT + IPAddress answerIPv6(const hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex); + IPAddress answerIPv6(const uint32_t p_u32AnswerIndex); +#endif + uint16_t answerPort(const hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const uint32_t p_u32AnswerIndex); + // for compatibility + uint16_t port(const uint32_t p_u32AnswerIndex); + + /** + typeQueryAnswerType & enuQueryAnswerType + */ + using typeQueryAnswerType = uint8_t; + enum class enuQueryAnswerType : typeQueryAnswerType + { + Unknown = 0x00, + ServiceDomain = 0x01, // Service domain + HostDomain = 0x02, // Host domain + Port = 0x04, // Port + Txts = 0x08, // TXT items +#ifdef MDNS_IPV4_SUPPORT + IPv4Address = 0x10, // IPv4 address +#endif +#ifdef MDNS_IPV6_SUPPORT + IPv6Address = 0x20, // IPv6 address +#endif + }; + //using AnswerType = enuQueryAnswerType; // for compatibility with V1 + + /** + stcAnswerAccessor + */ + struct stcAnswerAccessor + { + protected: + /** + stcCompareTxtKey + */ + struct stcCompareTxtKey + { + bool operator()(char const* p_pA, char const* p_pB) const; + }; + public: + stcAnswerAccessor(MDNSResponder& p_rMDNSResponder, + hMDNSQuery p_hQuery, + uint32_t p_u32AnswerIndex); + /** + clsTxtKeyValueMap + */ + using clsTxtKeyValueMap = std::map; + + bool serviceDomainAvailable(void) const; + const char* serviceDomain(void) const; + bool hostDomainAvailable(void) const; + const char* hostDomain(void) const; + bool hostPortAvailable(void) const; + uint16_t hostPort(void) const; +#ifdef MDNS_IPV4_SUPPORT + bool IPv4AddressAvailable(void) const; + std::vector IPv4Addresses(void) const; +#endif +#ifdef MDNS_IPV6_SUPPORT + bool IPv6AddressAvailable(void) const; + std::vector IPv6Addresses(void) const; +#endif + bool txtsAvailable(void) const; + const char* txts(void) const; + const clsTxtKeyValueMap& txtKeyValues(void) const; + const char* txtValue(const char* p_pcKey) const; + + size_t printTo(Print& p_Print) const; + + protected: + MDNSResponder& m_rMDNSResponder; + hMDNSQuery m_hQuery; + uint32_t m_u32AnswerIndex; + clsTxtKeyValueMap m_TxtKeyValueMap; + }; + + /** + MDNSQueryCallbackFn + + Callback function for received answers for dynamic queries + */ + using MDNSQueryCallbackFn = std::function; // true: Answer component set, false: component deleted + // LEGACY + using MDNSQueryCallbackFn1 = std::function; // true: Answer component set, false: component deleted + using MDNSQueryCallbackFn2 = std::function; // true: Answer component set, false: component deleted + //using MDNSServiceInfo = stcAnswerAccessor; // for compatibility with V1 + + // Install a dynamic service/host query. For every received answer (part) the given callback + // function is called. The query will be updated every time, the TTL for an answer + // has timed-out. + // The answers can also be retrieved by calling + // - answerCount service/host (for host queries, this should never be >1) + // - answerServiceDomain service + // - hasAnswerHostDomain/answerHostDomain service/host + // - hasAnswerIPv4Address/answerIPv4Address service/host + // - hasAnswerIPv6Address/answerIPv6Address service/host + // - hasAnswerPort/answerPort service + // - hasAnswerTxts/answerTxts service + hMDNSQuery installServiceQuery(const hMDNSHost p_hMDNSHost, + const char* p_pcService, + const char* p_pcProtocol, + MDNSQueryCallbackFn p_fnCallback); + hMDNSQuery installHostQuery(const hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + MDNSQueryCallbackFn p_fnCallback); + + hMDNSQuery installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSQueryCallbackFn1 p_fnCallback); + hMDNSQuery installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSQueryCallbackFn2 p_fnCallback); + + hMDNSQuery installHostQuery(const char* p_pcHostName, + MDNSQueryCallbackFn1 p_fnCallback); + hMDNSQuery installHostQuery(const char* p_pcHostName, + MDNSQueryCallbackFn2 p_fnCallback); + // Remove a dynamic service query + bool removeDynamicQuery(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hMDNSQuery); + bool removeDynamicQuery(const hMDNSQuery p_hQuery); + + /** + clsMDNSAnswerAccessorVector + */ + using clsMDNSAnswerAccessorVector = std::vector; + + clsMDNSAnswerAccessorVector answerAccessors(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hMDNSQuery); + clsMDNSAnswerAccessorVector answerAccessors(const hMDNSQuery p_hQuery); + + uint32_t answerCount(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hMDNSQuery); + uint32_t answerCount(const hMDNSQuery p_hQuery); + + bool hasAnswerServiceDomain(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerServiceDomain(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + const char* answerServiceDomain(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + const char* answerServiceDomain(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerHostDomain(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerHostDomain(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + const char* answerHostDomain(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + const char* answerHostDomain(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); +#ifdef MDNS_IPV4_SUPPORT + bool hasAnswerIPv4Address(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIPv4AddressCount(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIPv4Address(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); + bool hasAnswerIPv4Address(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIPv4AddressCount(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIPv4Address(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif +#ifdef MDNS_IPV6_SUPPORT + bool hasAnswerIPv6Address(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIPv6AddressCount(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIPv6Address(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); + bool hasAnswerIPv6Address(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIPv6AddressCount(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIPv6Address(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif + bool hasAnswerPort(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerPort(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + /* uint16_t answerPort(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex);*/ + bool hasAnswerTxts(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerTxts(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + // Get the TXT items as a ';'-separated string + const char* answerTxts(const hMDNSHost p_hMDNSHost, + const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + const char* answerTxts(const hMDNSQuery p_hQuery, + const uint32_t p_u32AnswerIndex); + + // Set a callback function for host probe results + // The callback function is called, when the probeing for the host domain + // succeededs or fails. + // In case of failure, the failed domain name should be changed. + bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn p_fnCallback); + /* LEGACY 2 */ + using MDNSHostProbeResultCallbackFn1 = std::function; + using MDNSHostProbeResultCallbackFn2 = std::function; + + bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn1 p_fnCallback); + bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn2 p_fnCallback); + + /** + MDNSServiceProbeResultCallbackFn + Callback function for service domain probe results + */ + using MDNSServiceProbeResultCallbackFn = std::function; + // Set a service specific probe result callcack + bool setServiceProbeResultCallback(const hMDNSService p_hMDNSService, + MDNSServiceProbeResultCallbackFn p_fnCallback); + + bool setServiceProbeResultCallback(const hMDNSService p_hMDNSService, + MDNSServiceProbeResultCallbackFn1 p_fnCallback); + bool setServiceProbeResultCallback(const hMDNSService p_hMDNSService, + MDNSServiceProbeResultCallbackFn2 p_fnCallback); + + // Application should call this whenever AP is configured/disabled + bool notifyNetIfChange(netif* p_pNetIf); + + // 'update' should be called in every 'loop' to run the MDNS processing + bool update(const hMDNSHost p_hMDNSHost); + bool update(void); + + // 'announce' can be called every time, the configuration of some service + // changes. Mainly, this would be changed content of TXT items. + bool announce(const hMDNSHost p_hMDNSHost); + bool announce(void); + + // Enable OTA update + hMDNSService enableArduino(const hMDNSHost p_hMDNSHost, + uint16_t p_u16Port, + bool p_bAuthUpload = false); + hMDNSService enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload = false); + + // Domain name helper + static bool indexDomain(char*& p_rpcDomain, + const char* p_pcDivider = "-", + const char* p_pcDefaultDomain = 0); + // Host name helper + static bool setNetIfHostName(netif* p_pNetIf, + const char* p_pcHostName); +}; +#endif + +} // namespace MDNSImplementation + +} // namespace esp8266 + +#endif // LEAMDNS2_H + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp new file mode 100755 index 0000000000..4b3d22902e --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp @@ -0,0 +1,4164 @@ +/* + LEAmDNS2_API.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + + +#include +#include + +#include "LEAmDNS2_Priv.h" + + +namespace +{ + +/* + strrstr (static) + + Backwards search for p_pcPattern in p_pcString + Based on: https://stackoverflow.com/a/1634398/2778898 + +*/ +const char* strrstr(const char*__restrict p_pcString, const char*__restrict p_pcPattern) +{ + const char* pcResult = 0; + + size_t stStringLength = (p_pcString ? strlen(p_pcString) : 0); + size_t stPatternLength = (p_pcPattern ? strlen(p_pcPattern) : 0); + + if ((stStringLength) && + (stPatternLength) && + (stPatternLength <= stStringLength)) + { + // Pattern is shorter or has the same length tham the string + + for (const char* s = (p_pcString + stStringLength - stPatternLength); s >= p_pcString; --s) + { + if (0 == strncmp(s, p_pcPattern, stPatternLength)) + { + pcResult = s; + break; + } + } + } + return pcResult; +} + +} // anonymous + + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace experimental +{ + +/** + STRINGIZE +*/ +#ifndef STRINGIZE +#define STRINGIZE(x) #x +#endif +#ifndef STRINGIZE_VALUE_OF +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) +#endif + +/** + HELPERS +*/ + +/* + MDNSResponder::indexDomain (static) + + Updates the given domain 'p_rpcHostName' by appending a delimiter and an index number. + + If the given domain already hasa numeric index (after the given delimiter), this index + incremented. If not, the delimiter and index '2' is added. + + If 'p_rpcHostName' is empty (==0), the given default name 'p_pcDefaultHostName' is used, + if no default is given, 'esp8266' is used. + +*/ +/*static*/ bool MDNSResponder::indexDomain(char*& p_rpcDomain, + const char* p_pcDivider /*= "-"*/, + const char* p_pcDefaultDomain /*= 0*/) +{ + bool bResult = false; + + // Ensure a divider exists; use '-' as default + const char* pcDivider = (p_pcDivider ? : "-"); + + if (p_rpcDomain) + { + const char* pFoundDivider = strrstr(p_rpcDomain, pcDivider); + if (pFoundDivider) // maybe already extended + { + char* pEnd = 0; + unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10); + if ((ulIndex) && + ((pEnd - p_rpcDomain) == (ptrdiff_t)strlen(p_rpcDomain)) && + (!*pEnd)) // Valid (old) index found + { + + char acIndexBuffer[16]; + sprintf(acIndexBuffer, "%lu", (++ulIndex)); + size_t stLength = ((pFoundDivider - p_rpcDomain + strlen(pcDivider)) + strlen(acIndexBuffer) + 1); + char* pNewHostName = new char[stLength]; + if (pNewHostName) + { + memcpy(pNewHostName, p_rpcDomain, (pFoundDivider - p_rpcDomain + strlen(pcDivider))); + pNewHostName[pFoundDivider - p_rpcDomain + strlen(pcDivider)] = 0; + strcat(pNewHostName, acIndexBuffer); + + delete[] p_rpcDomain; + p_rpcDomain = pNewHostName; + + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: FAILED to alloc new hostname!\n"));); + } + } + else + { + pFoundDivider = 0; // Flag the need to (base) extend the hostname + } + } + + if (!pFoundDivider) // not yet extended (or failed to increment extension) -> start indexing + { + size_t stLength = strlen(p_rpcDomain) + (strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0' + char* pNewHostName = new char[stLength]; + if (pNewHostName) + { + sprintf(pNewHostName, "%s%s2", p_rpcDomain, pcDivider); + + delete[] p_rpcDomain; + p_rpcDomain = pNewHostName; + + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: FAILED to alloc new hostname!\n"));); + } + } + } + else + { + // No given host domain, use base or default + const char* cpcDefaultName = (p_pcDefaultDomain ? : "esp8266"); + + size_t stLength = strlen(cpcDefaultName) + 1; // '\0' + p_rpcDomain = new char[stLength]; + if (p_rpcDomain) + { + strncpy(p_rpcDomain, cpcDefaultName, stLength); + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: FAILED to alloc new hostname!\n"));); + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: %s\n"), p_rpcDomain);); + return bResult; +} + + +/* + MDNSResponder::setStationHostName (static) + + Sets the staion hostname + +*/ +/*static*/ bool MDNSResponder::setNetIfHostName(netif* p_pNetIf, + const char* p_pcHostName) +{ + if ((p_pNetIf) && + (p_pcHostName)) + { + netif_set_hostname(p_pNetIf, p_pcHostName); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setNetIfHostName host name: %s!\n"), p_pcHostName);); + } + return true; +} + + +/** + INTERFACE +*/ + +/** + MDNSResponder::MDNSResponder +*/ +MDNSResponder::MDNSResponder(void) + : m_pUDPContext(0) +{ + _allocUDPContext(); +} + +/* + MDNSResponder::~MDNSResponder +*/ +MDNSResponder::~MDNSResponder(void) +{ + close(); +} + +/* + MDNSResponder::begin (hostname, netif, probe_callback) +*/ +MDNSResponder::hMDNSHost MDNSResponder::begin(const char* p_pcHostName, + netif* p_pNetIf, + MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, netif: %u)\n"), _DH(), (p_pcHostName ? : "-"), (p_pNetIf ? netif_get_index(p_pNetIf) : 0));); + + return (hMDNSHost)_begin(p_pcHostName, p_pNetIf, p_fnCallback); +} + +/* + MDNSResponder::begin (hostname, probe_callback) +*/ +bool MDNSResponder::begin(const char* p_pcHostName, + MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s)\n"), _DH(), (p_pcHostName ? : "_"));); + + return begin(p_pcHostName, (WiFiMode_t)wifi_get_opmode(), p_fnCallback); +} + +/* + MDNSResponder::begin (hostname, WiFiMode, probe_callback) +*/ +bool MDNSResponder::begin(const char* p_pcHostName, + WiFiMode_t p_WiFiMode, + MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, opmode: %u)\n"), _DH(), (p_pcHostName ? : "_"), (uint32_t)p_WiFiMode);); + + bool bResult = true; + + if ((bResult) && + (p_WiFiMode & WIFI_STA)) + { + bResult = (0 != _begin(p_pcHostName, netif_get_by_index(WIFI_STA), p_fnCallback)); + } + if ((bResult) && + (p_WiFiMode & WIFI_AP)) + { + bResult = (0 != _begin(p_pcHostName, netif_get_by_index(WIFI_AP), p_fnCallback)); + } + return bResult; +} + +/* + MDNSResponder::close +*/ +bool MDNSResponder::close(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_close(*(clsHost*)p_hMDNSHost))); +} + +/* + MDNSResponder::close (convenience) +*/ +bool MDNSResponder::close(void) +{ + clsHostList::iterator it(m_HostList.begin()); + while (m_HostList.end() != it) + { + _close(**it++); + } + + return _releaseUDPContext(); +} + + +/* + MDNSResponder::getMDNSHost (netif) +*/ +MDNSResponder::hMDNSHost MDNSResponder::getMDNSHost(netif* p_pNetIf) const +{ + return (hMDNSHost)(p_pNetIf ? _findHost(p_pNetIf) : 0); +} + +/* + MDNSResponder::getMDNSHost (WiFiMode) +*/ +MDNSResponder::hMDNSHost MDNSResponder::getMDNSHost(WiFiMode_t p_WiFiMode) const +{ + hMDNSHost hResult = 0; + + if (WIFI_STA == p_WiFiMode) + { + hResult = getMDNSHost(netif_get_by_index(WIFI_STA)); + } + else if (WIFI_AP == p_WiFiMode) + { + hResult = getMDNSHost(netif_get_by_index(WIFI_AP)); + } + return hResult; +} + +/* + MDNSResponder::setHostName +*/ +bool MDNSResponder::setHostName(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_NRH2Ptr(p_hMDNSHost)->setHostName(p_pcHostName)) && + (p_fnCallback ? setHostProbeResultCallback(p_hMDNSHost, p_fnCallback) : true)); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setHostName: FAILED for '%s'!\n"), _DH(p_hMDNSHost), (p_pcHostName ? : "-"));); + return bResult; +} + +/* + MDNSResponder::hostName +*/ +const char* MDNSResponder::hostName(const MDNSResponder::hMDNSHost p_hMDNSHost) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost) + ? (_NRH2Ptr(p_hMDNSHost)->hostName()) + : 0); +} + +/* + MDNSResponder::setHostProbeResultCallback +*/ +bool MDNSResponder::setHostProbeResultCallback(const hMDNSHost p_hMDNSHost, + MDNSHostProbeResultCallbackFn p_fnCallback) +{ + bool bResult = false; + if ((bResult = _validateMDNSHostHandle(p_hMDNSHost))) + { + if (p_fnCallback) + { + _NRH2Ptr(p_hMDNSHost)->m_HostProbeInformation.m_fnProbeResultCallback = [this, p_fnCallback](clsHost & p_rHost, + const char* p_pcDomainName, + bool p_bProbeResult)->void + { + p_fnCallback(*this, (hMDNSHost)&p_rHost, p_pcDomainName, p_bProbeResult); + }; + } + else + { + _NRH2Ptr(p_hMDNSHost)->m_HostProbeInformation.m_fnProbeResultCallback = 0; + } + } + return bResult; +} + +/* + MDNSResponder::status +*/ +bool MDNSResponder::status(const MDNSResponder::hMDNSHost p_hMDNSHost) const +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_NRH2Ptr(p_hMDNSHost)->probeStatus())); +} + + +/* + SERVICES +*/ + +/* + MDNSResponder::setInstanceName +*/ +bool MDNSResponder::setInstanceName(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcInstanceName) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_NRH2Ptr(p_hMDNSHost)->setInstanceName(p_pcInstanceName))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setInstanceName: FAILED for '%s'!\n"), _DH(p_hMDNSHost), (p_pcInstanceName ? : "-"));); + return bResult; +} + +/* + MDNSResponder::instanceName +*/ +const char* MDNSResponder::instanceName(const MDNSResponder::hMDNSHost p_hMDNSHost) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost) + ? (_NRH2Ptr(p_hMDNSHost)->instanceName()) + : 0); +} + +/* + MDNSResponder::addService + + Add service; using hostname if no name is explicitly provided for the service + The usual '_' underline, which is prepended to service and protocol, eg. _http, + may be given. If not, it is added automatically. + +*/ +MDNSResponder::hMDNSService MDNSResponder::addService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port, + MDNSServiceProbeResultCallbackFn p_fnCallback /*= 0*/) +{ + hMDNSService hService = (_validateMDNSHostHandle(p_hMDNSHost) + ? (hMDNSService)_NRH2Ptr(p_hMDNSHost)->addService(p_pcName, p_pcServiceType, p_pcProtocol, p_u16Port) + : 0); + if ((p_fnCallback) && + (hService)) + { + setServiceProbeResultCallback(p_hMDNSHost, hService, p_fnCallback); + } + DEBUG_EX_ERR(if (!hService) DEBUG_OUTPUT.printf_P(PSTR("%s addService: FAILED for '%s._%s._%s.local'!\n"), _DH(p_hMDNSHost), (p_pcName ? : "-"), (p_pcServiceType ? : "-"), (p_pcProtocol ? : "-"));); + return hService; +} + +/* + MDNSResponder::removeService + + Unanounce a service (by sending a goodbye message) and remove it + from the MDNS responder + +*/ +bool MDNSResponder::removeService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (_NRH2Ptr(p_hMDNSHost)->removeService(_SH2Ptr(p_hMDNSService)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeService: FAILED!\n"), _DH(p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::removeService +*/ +bool MDNSResponder::removeService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol) +{ + clsHost* pMDNSHost; + clsHost::stcService* pMDNSService; + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + (pMDNSHost = (clsHost*)p_hMDNSHost) && + ((pMDNSService = _NRH2Ptr(p_hMDNSHost)->findService(p_pcInstanceName, p_pcServiceType, p_pcProtocol))) && + (_NRH2Ptr(p_hMDNSHost)->removeService(pMDNSService))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeService: FAILED for '%s._%s._%s.local'!\n"), _DH(p_hMDNSHost), (p_pcInstanceName ? : "-"), (p_pcServiceType ? : "-"), (p_pcProtocol ? : "-"));); + return bResult; +} + +/* + MDNSResponder::findService + + Find an existing service. + +*/ +MDNSResponder::hMDNSService MDNSResponder::findService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol) +{ + clsHost* pMDNSHost; + return (((_validateMDNSHostHandle(p_hMDNSHost)) && + (pMDNSHost = (clsHost*)p_hMDNSHost)) + ? _NRH2Ptr(p_hMDNSHost)->findService(p_pcInstanceName, p_pcServiceType, p_pcProtocol) + : 0); +} + +/* + MDNSResponder::setServiceName +*/ +bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcInstanceName, + MDNSServiceProbeResultCallbackFn p_fnCallback /*= 0*/) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (_NRH2Ptr(p_hMDNSHost)->setServiceName(_SH2Ptr(p_hMDNSService), p_pcInstanceName)) && + (p_fnCallback ? setServiceProbeResultCallback(p_hMDNSHost, p_hMDNSService, p_fnCallback) : true)); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setServiceName: FAILED for '%s'!\n"), _DH(p_hMDNSHost), (p_pcInstanceName ? : "-"));); + return bResult; +} + +/* + MDNSResponder::serviceName +*/ +const char* MDNSResponder::serviceName(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? (_SH2Ptr(p_hMDNSService)->m_pcName) + : 0); +} + +/* + MDNSResponder::serviceType +*/ +const char* MDNSResponder::serviceType(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? (_SH2Ptr(p_hMDNSService)->m_pcServiceType) + : 0); +} + +/* + MDNSResponder::serviceProtocol +*/ +const char* MDNSResponder::serviceProtocol(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? (_SH2Ptr(p_hMDNSService)->m_pcProtocol) + : 0); +} + +/* + MDNSResponder::serviceProtocol +*/ +uint16_t MDNSResponder::servicePort(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? (_SH2Ptr(p_hMDNSService)->m_u16Port) + : 0); +} + +/* + MDNSResponder::setServiceProbeResultCallback + + Set a service specific callback for probe results. The callback is called, when probing + for the service domain failes or succeedes. + In the case of failure, the service name should be changed via 'setServiceName'. + When succeeded, the service domain will be announced by the MDNS responder. + +*/ +bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + MDNSResponder::MDNSServiceProbeResultCallbackFn p_fnCallback) +{ + bool bResult = false; + if ((bResult = _validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService))) + { + if (p_fnCallback) + { + _SH2Ptr(p_hMDNSService)->m_ProbeInformation.m_fnProbeResultCallback = [this, p_fnCallback](clsHost & p_rHost, + clsHost::stcService & p_rMDNSService, + const char* p_pcDomainName, + bool p_bProbeResult)->void + { + p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSService)&p_rMDNSService, p_pcDomainName, p_bProbeResult); + }; + } + else + { + _SH2Ptr(p_hMDNSService)->m_ProbeInformation.m_fnProbeResultCallback = 0; + } + } + return bResult; +} + +/* + MDNSResponder::serviceStatus +*/ +bool MDNSResponder::serviceStatus(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (_SH2Ptr(p_hMDNSService)->probeStatus())); +} + + +/* + SERVICE TXT +*/ + +/* + MDNSResponder::addServiceTxt + + Add a static service TXT item ('Key'='Value') to a service. + +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue) +{ + hMDNSTxt hTxt = (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? (hMDNSTxt)_NRH2Ptr(p_hMDNSHost)->addServiceTxt(_SH2Ptr(p_hMDNSService), p_pcKey, p_pcValue) + : 0); + DEBUG_EX_ERR(if (!hTxt) DEBUG_OUTPUT.printf_P(PSTR("%s addServiceTxt: FAILED for '%s=%s'!\n"), _DH(p_hMDNSHost), (p_pcKey ? : "-"), (p_pcValue ? : "-"));); + return hTxt; +} + +/* + MDNSRESPONDER_xxx_TO_CHAR + Formats: http://www.cplusplus.com/reference/cstdio/printf/ +*/ +#define MDNSRESPONDER_U32_TO_CHAR(BUFFERNAME, U32VALUE) \ + char BUFFERNAME[16]; /* 32-bit max 10 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%u", U32VALUE); +#define MDNSRESPONDER_U16_TO_CHAR(BUFFERNAME, U16VALUE) \ + char BUFFERNAME[8]; /* 16-bit max 5 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%hu", U16VALUE); +#define MDNSRESPONDER_U8_TO_CHAR(BUFFERNAME, U8VALUE) \ + char BUFFERNAME[8]; /* 8-bit max 3 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%hhu", U8VALUE); +#define MDNSRESPONDER_I32_TO_CHAR(BUFFERNAME, I32VALUE) \ + char BUFFERNAME[16]; /* 32-bit max 10 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%i", I32VALUE); +#define MDNSRESPONDER_I16_TO_CHAR(BUFFERNAME, I16VALUE) \ + char BUFFERNAME[8]; /* 16-bit max 5 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%hi", I16VALUE); +#define MDNSRESPONDER_I8_TO_CHAR(BUFFERNAME, I8VALUE) \ + char BUFFERNAME[8]; /* 8-bit max 3 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%hhi", I8VALUE); + +/* + MDNSResponder::addServiceTxt (uint32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + MDNSRESPONDER_U32_TO_CHAR(acBuffer, p_u32Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (uint16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + MDNSRESPONDER_U16_TO_CHAR(acBuffer, p_u16Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (uint8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + MDNSRESPONDER_U8_TO_CHAR(acBuffer, p_u8Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (int32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value) +{ + MDNSRESPONDER_I32_TO_CHAR(acBuffer, p_i32Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (int16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value) +{ + MDNSRESPONDER_I16_TO_CHAR(acBuffer, p_i16Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (int8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value) +{ + MDNSRESPONDER_I8_TO_CHAR(acBuffer, p_i8Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::removeServiceTxt + + Remove a static service TXT item from a service. +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const MDNSResponder::hMDNSTxt p_hTxt) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (p_hTxt) && + (_NRH2Ptr(p_hMDNSHost)->removeServiceTxt(_SH2Ptr(p_hMDNSService), (clsHost::stcServiceTxt*)p_hTxt))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH(p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::removeServiceTxt +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (p_pcKey) && + (_NRH2Ptr(p_hMDNSHost)->removeServiceTxt(_SH2Ptr(p_hMDNSService), _NRH2Ptr(p_hMDNSHost)->findServiceTxt(_SH2Ptr(p_hMDNSService), p_pcKey)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH(p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (binding) + + Set a netif binding specific callback for dynamic service TXT items. The callback is called, whenever + service TXT items are needed for any service on the netif binding. + +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, + MDNSResponder::MDNSDynamicServiceTxtCallbackFn p_fnCallback) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + ((!p_fnCallback) || + (_NRH2Ptr(p_hMDNSHost)->setDynamicServiceTxtCallback([this, p_fnCallback](clsHost & p_rHost, + clsHost::stcService & p_rMDNSService)->void + { + if (p_fnCallback) + { + p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSService)&p_rMDNSService); + } + })))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setDynamicServiceTxtCallback: FAILED!\n"), _DH(p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (service) + + Set a service specific callback for dynamic service TXT items. The callback is called, whenever + service TXT items are needed for the given service. +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + MDNSResponder::MDNSDynamicServiceTxtCallbackFn p_fnCallback) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + ((!p_fnCallback) || + (_NRH2Ptr(p_hMDNSHost)->setDynamicServiceTxtCallback(_SH2Ptr(p_hMDNSService), [this, p_fnCallback](clsHost & p_rHost, + clsHost::stcService & p_rMDNSService)->void + { + if (p_fnCallback) + { + p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSService)&p_rMDNSService); + } + })))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setDynamicServiceTxtCallback: FAILED!\n"), _DH(p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::addDynamicServiceTxt +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue) +{ + hMDNSTxt hTxt = (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? (hMDNSTxt)_NRH2Ptr(p_hMDNSHost)->addDynamicServiceTxt(_SH2Ptr(p_hMDNSService), p_pcKey, p_pcValue) + : 0); + DEBUG_EX_ERR(if (!hTxt) DEBUG_OUTPUT.printf_P(PSTR("%s addServiceTxt: FAILED for '%s=%s'!\n"), _DH(p_hMDNSHost), (p_pcKey ? : "-"), (p_pcValue ? : "-"));); + return hTxt; +} + +/* + MDNSResponder::addDynamicServiceTxt (uint32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + MDNSRESPONDER_U32_TO_CHAR(acBuffer, p_u32Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (uint16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + MDNSRESPONDER_U16_TO_CHAR(acBuffer, p_u16Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (uint8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + MDNSRESPONDER_U8_TO_CHAR(acBuffer, p_u8Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (int32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value) +{ + MDNSRESPONDER_I32_TO_CHAR(acBuffer, p_i32Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (int16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value) +{ + MDNSRESPONDER_I16_TO_CHAR(acBuffer, p_i16Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (int8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value) +{ + MDNSRESPONDER_I8_TO_CHAR(acBuffer, p_i8Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); +} + + +/** + QUERIES +*/ + + +/** + MDNSResponder::clsMDNSAnswerAccessor + +*/ + +/* + MDNSResponder::clsMDNSAnswerAccessor::clsMDNSAnswerAccessor constructor +*/ +MDNSResponder::clsMDNSAnswerAccessor::clsMDNSAnswerAccessor(const MDNSResponder::clsHost::stcQuery::stcAnswer* p_pAnswer) + : m_pAnswer(p_pAnswer) +{ + if ((m_pAnswer) && + (txtsAvailable())) + { + // Prepare m_TxtKeyValueMap + for (const clsHost::stcServiceTxt* pTxt = m_pAnswer->m_Txts.m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + m_TxtKeyValueMap.emplace(std::pair(pTxt->m_pcKey, pTxt->m_pcValue)); + } + } +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::~clsMDNSAnswerAccessor destructor +*/ +MDNSResponder::clsMDNSAnswerAccessor::~clsMDNSAnswerAccessor(void) +{ +} + +/** + MDNSResponder::clsMDNSAnswerAccessor::stcCompareTxtKey +*/ + +/* + MDNSResponder::clsMDNSAnswerAccessor::stcCompareTxtKey::operator() +*/ +bool MDNSResponder::clsMDNSAnswerAccessor::stcCompareTxtKey::operator()(char const* p_pA, + char const* p_pB) const +{ + return (0 > strcasecmp(p_pA, p_pB)); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::serviceDomainAvailable +*/ +bool MDNSResponder::clsMDNSAnswerAccessor::serviceDomainAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::ServiceDomain))); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::serviceDomain +*/ +const char* MDNSResponder::clsMDNSAnswerAccessor::serviceDomain(void) const +{ + return ((m_pAnswer) + ? m_pAnswer->m_ServiceDomain.c_str() + : 0); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::hostDomainAvailable +*/ +bool MDNSResponder::clsMDNSAnswerAccessor::hostDomainAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::HostDomain))); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::hostDomain +*/ +const char* MDNSResponder::clsMDNSAnswerAccessor::hostDomain(void) const +{ + return ((m_pAnswer) + ? m_pAnswer->m_HostDomain.c_str() + : 0); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::hostPortAvailable +*/ +bool MDNSResponder::clsMDNSAnswerAccessor::hostPortAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Port))); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::hostPort +*/ +uint16_t MDNSResponder::clsMDNSAnswerAccessor::hostPort(void) const +{ + return ((m_pAnswer) + ? (m_pAnswer->m_u16Port) + : 0); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::clsMDNSAnswerAccessor::IPv4AddressAvailable +*/ +bool MDNSResponder::clsMDNSAnswerAccessor::IPv4AddressAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv4Address))); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::IPv4Addresses +*/ +std::vector MDNSResponder::clsMDNSAnswerAccessor::IPv4Addresses(void) const +{ + std::vector internalIP; + if ((m_pAnswer) && + (IPv4AddressAvailable())) + { + for (uint32_t u = 0; u < m_pAnswer->IPv4AddressCount(); ++u) + { + const clsHost::stcQuery::stcAnswer::stcIPAddress* pIPAddr = m_pAnswer->IPv4AddressAtIndex(u); + if (pIPAddr) + { + internalIP.emplace_back(pIPAddr->m_IPAddress); + } + } + } + return internalIP; +} +#endif + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::clsMDNSAnswerAccessor::IPv6AddressAvailable +*/ +bool MDNSResponder::clsMDNSAnswerAccessor::IPv6AddressAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv6Address))); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::IPv6Addresses +*/ +std::vector MDNSResponder::clsMDNSAnswerAccessor::IPv6Addresses(void) const +{ + std::vector internalIP; + if ((m_pAnswer) && + (IPv6AddressAvailable())) + { + for (uint32_t u = 0; u < m_pAnswer->IPv6AddressCount(); ++u) + { + const clsHost::stcQuery::stcAnswer::stcIPAddress* pIPAddr = m_pAnswer->IPv6AddressAtIndex(u); + if (pIPAddr) + { + internalIP.emplace_back(pIPAddr->m_IPAddress); + } + } + } + return internalIP; +} +#endif + +/* + MDNSResponder::clsMDNSAnswerAccessor::txtsAvailable +*/ +bool MDNSResponder::clsMDNSAnswerAccessor::txtsAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Txts))); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::txts + + Returns all TXT items for the given service as a ';'-separated string. + If not already existing; the string is alloced, filled and attached to the answer. +*/ +const char* MDNSResponder::clsMDNSAnswerAccessor::txts(void) const +{ + return ((m_pAnswer) + ? m_pAnswer->m_Txts.c_str() + : 0); +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::txtKeyValues +*/ +const MDNSResponder::clsMDNSAnswerAccessor::clsTxtKeyValueMap& MDNSResponder::clsMDNSAnswerAccessor::txtKeyValues(void) const +{ + return m_TxtKeyValueMap; +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::txtValue +*/ +const char* MDNSResponder::clsMDNSAnswerAccessor::txtValue(const char* p_pcKey) const +{ + char* pcResult = 0; + + if (m_pAnswer) + { + for (const clsHost::stcServiceTxt* pTxt = m_pAnswer->m_Txts.m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if ((p_pcKey) && + (0 == strcasecmp(pTxt->m_pcKey, p_pcKey))) + { + pcResult = pTxt->m_pcValue; + break; + } + } + } + return pcResult; +} + +/* + MDNSResponder::clsMDNSAnswerAccessor::printTo + **/ +size_t MDNSResponder::clsMDNSAnswerAccessor::printTo(Print& p_Print) const +{ + size_t stLen = 0; + const char* cpcI = " * "; + const char* cpcS = " "; + + stLen += p_Print.println(" * * * * *"); + if (hostDomainAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("Host domain: "); + stLen += p_Print.println(hostDomain()); + } +#ifdef MDNS_IPV4_SUPPORT + if (IPv4AddressAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.println("IPv4 address(es):"); + for (const IPAddress& addr : IPv4Addresses()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print(cpcS); + stLen += p_Print.println(addr); + } + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if (IPv6AddressAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.println("IPv6 address(es):"); + for (const IPAddress& addr : IPv6Addresses()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print(cpcS); + stLen += p_Print.println(addr); + } + } +#endif + if (serviceDomainAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("Service domain: "); + stLen += p_Print.println(serviceDomain()); + } + if (hostPortAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("Host port: "); + stLen += p_Print.println(hostPort()); + } + if (txtsAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("TXTs:"); + for (auto const& x : txtKeyValues()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print(cpcS); + stLen += p_Print.print(x.first); + stLen += p_Print.print("="); + stLen += p_Print.println(x.second); + } + } + stLen += p_Print.println(" * * * * *"); + + return stLen; +} + +/** + STATIC QUERIES +*/ + +/* + MDNSResponder::queryService + + Perform a (blocking) static service query. + The arrived answers can be queried by calling: + - answerHostName (or 'hostname') + - answerIP (or 'IP') + - answerPort (or 'port') + +*/ +uint32_t MDNSResponder::queryService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local'\n"), _DH(p_hMDNSHost), p_pcService, p_pcProtocol);); + + uint32_t u32Result = ((_validateMDNSHostHandle(p_hMDNSHost)) + ? (_NRH2Ptr(p_hMDNSHost)->queryService(p_pcService, p_pcProtocol, p_u16Timeout)) + : 0); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local' returned %u hits!\n"), _DH(p_hMDNSHost), p_pcService, p_pcProtocol, u32Result);); + return u32Result; +} + +/* + MDNSResponder::queryHost + + Perform a (blocking) static host query. + The arrived answers can be queried by calling: + - answerHostName (or 'hostname') + - answerIP (or 'IP') + - answerPort (or 'port') + +*/ +uint32_t MDNSResponder::queryHost(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local'\n"), _DH(p_hMDNSHost), p_pcHostName);); + + uint32_t u32Result = ((_validateMDNSHostHandle(p_hMDNSHost)) + ? (_NRH2Ptr(p_hMDNSHost)->queryHost(p_pcHostName, p_u16Timeout)) + : 0); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local' returned %u hits!\n"), _DH(p_hMDNSHost), p_pcHostName, u32Result);); + return u32Result; +} + +/* + MDNSResponder::removeQuery + + Remove the last static query (and all answers). + +*/ +bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_NRH2Ptr(p_hMDNSHost)->removeQuery())); +} + +/* + MDNSResponder::hasQuery + + Return 'true', if a static query is currently installed + +*/ +bool MDNSResponder::hasQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (0 != _NRH2Ptr(p_hMDNSHost)->hasQuery())); +} + +/* + MDNSResponder::getQuery + + Return handle to the last static query + +*/ +MDNSResponder::hMDNSQuery MDNSResponder::getQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return (_validateMDNSHostHandle(p_hMDNSHost) + ? (hMDNSQuery)_NRH2Ptr(p_hMDNSHost)->getQuery() + : 0); +} + + +/* + MDNSResponder::answerAccessors +*/ +MDNSResponder::clsMDNSAnswerAccessorVector MDNSResponder::answerAccessors(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + hMDNSQuery hLegacyQuery = getQuery(p_hMDNSHost); + return ((hLegacyQuery) + ? answerAccessors(p_hMDNSHost, hLegacyQuery) + : clsMDNSAnswerAccessorVector()); +} + +/* + MDNSResponder::answerCount +*/ +uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + hMDNSQuery hLegacyQuery = getQuery(p_hMDNSHost); + return ((hLegacyQuery) + ? answerCount(p_hMDNSHost, hLegacyQuery) + : 0); +} + +/* + MDNSResponder::answerAccessor +*/ +MDNSResponder::clsMDNSAnswerAccessor MDNSResponder::answerAccessor(const MDNSResponder::hMDNSHost p_hMDNSHost, + uint32_t p_u32AnswerIndex) +{ + hMDNSQuery hLegacyQuery = getQuery(p_hMDNSHost); + return ((hLegacyQuery) + ? answerAccessor(p_hMDNSHost, hLegacyQuery, p_u32AnswerIndex) + : clsMDNSAnswerAccessor(0)); +} + + + +#ifdef NOTUSED + +/* + MDNSResponder::answerHostName +*/ +const char* MDNSResponder::answerHostName(const MDNSResponder::hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex) +{ + const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); + stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); + + if ((pSQAnswer) && + (pSQAnswer->m_HostDomain.m_u16NameLength) && + (!pSQAnswer->m_pcHostDomain)) + { + char* pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); + if (pcHostDomain) + { + pSQAnswer->m_HostDomain.c_str(pcHostDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::answerIPv4 +*/ +IPAddress MDNSResponder::answerIPv4(const MDNSResponder::hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex) +{ + const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); + const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); + const stcQuery::stcAnswer::stcIPv4Address* pIPv4Address = (((pSQAnswer) && (pSQAnswer->m_pIPv4Addresses)) ? pSQAnswer->IPv4AddressAtIndex(0) : 0); + return (pIPv4Address ? pIPv4Address->m_IPAddress : IPAddress()); +} +#endif + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::answerIPv6 +*/ +IPAddress MDNSResponder::answerIPv6(const MDNSResponder::hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex) +{ + const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); + const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); + const stcQuery::stcAnswer::stcIPv6Address* pIPv6Address = (((pSQAnswer) && (pSQAnswer->m_pIPv6Addresses)) ? pSQAnswer->IPv6AddressAtIndex(0) : 0); + return (pIPv6Address ? pIPv6Address->m_IPAddress : IPAddress()); +} +#endif + +/* + MDNSResponder::answerPort +*/ +uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex) +{ + const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); + const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->m_u16Port : 0); +} + +#endif + + +/** + DYNAMIC SERVICE QUERY +*/ + +/* + MDNSResponder::installServiceQuery + + Add a dynamic service query and a corresponding callback to the MDNS responder. + The callback will be called for every answer update. + The answers can also be queried by calling: + - answerServiceDomain + - answerHostDomain + - answerIPv4Address/answerIPv6Address + - answerPort + - answerTxts + +*/ +MDNSResponder::hMDNSQuery MDNSResponder::installServiceQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcService, + const char* p_pcProtocol, + MDNSResponder::MDNSQueryCallbackFn p_fnCallback) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local'\n"), _DH(p_hMDNSHost), p_pcService, p_pcProtocol);); + + hMDNSQuery hResult = ((_validateMDNSHostHandle(p_hMDNSHost)) + ? (_NRH2Ptr(p_hMDNSHost)->installServiceQuery(p_pcService, p_pcProtocol, [this, p_fnCallback](clsHost & p_rHost, + const clsHost::stcQuery & p_Query, + const clsHost::stcQuery::stcAnswer & p_Answer, + clsHost::typeQueryAnswerType p_QueryAnswerTypeFlags, // flags for the updated answer item + bool p_bSetContent)->void + { + if (p_fnCallback) + { + p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSQuery)&p_Query, clsMDNSAnswerAccessor(&p_Answer), p_QueryAnswerTypeFlags, p_bSetContent); + } + })) + : 0); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: %s for '_%s._%s.local'!\n\n"), _DH(p_hMDNSHost), (hResult ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + DEBUG_EX_ERR(if (!hResult) DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: FAILED for '_%s._%s.local'!\n\n"), _DH(p_hMDNSHost), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + return hResult; +} + +/* + MDNSResponder::installHostQuery +*/ +MDNSResponder::hMDNSQuery MDNSResponder::installHostQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + MDNSResponder::MDNSQueryCallbackFn p_fnCallback) +{ + hMDNSQuery hResult = ((_validateMDNSHostHandle(p_hMDNSHost)) + ? (_NRH2Ptr(p_hMDNSHost)->installHostQuery(p_pcHostName, [this, p_fnCallback](clsHost & p_rHost, + const clsHost::stcQuery & p_Query, + const clsHost::stcQuery::stcAnswer & p_Answer, + clsHost::typeQueryAnswerType p_QueryAnswerTypeFlags, // flags for the updated answer item + bool p_bSetContent)->void + { + if (p_fnCallback) + { + p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSQuery)&p_Query, clsMDNSAnswerAccessor(&p_Answer), p_QueryAnswerTypeFlags, p_bSetContent); + } + })) + : 0); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: %s for '%s.local'!\n\n"), _DH(p_hMDNSHost), (hResult ? "Succeeded" : "FAILED"), (p_pcHostName ? : "-"));); + DEBUG_EX_ERR(if (!hResult) DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: FAILED for '%s.local'!\n\n"), _DH(p_hMDNSHost), (p_pcHostName ? : "-"));); + return hResult; +} + +/* + MDNSResponder::removeQuery + + Remove a dynamic query (and all collected answers) from the MDNS responder + +*/ +bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + (p_hMDNSQuery) && + (_NRH2Ptr(p_hMDNSHost)->removeQuery((clsHost::stcQuery*)p_hMDNSQuery))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeQuery: FAILED!\n"), _DH(p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::answerAccessors +*/ +MDNSResponder::clsMDNSAnswerAccessorVector MDNSResponder::answerAccessors(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery) +{ + clsMDNSAnswerAccessorVector tempVector; + for (uint32_t u = 0; u < answerCount(p_hMDNSHost, p_hMDNSQuery); ++u) + { + clsHost::stcQuery::stcAnswer* pAnswer = 0; + if ((_validateMDNSHostHandle(p_hMDNSHost)) && + (p_hMDNSQuery) && + ((pAnswer = ((clsHost::stcQuery*)p_hMDNSQuery)->answerAtIndex(u)))) + { + tempVector.emplace_back(clsMDNSAnswerAccessor(pAnswer)); + //tempVector.emplace_back(*pAnswer); + } + } + return tempVector; +} + +/* + MDNSResponder::answerCount +*/ +uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery) +{ + _validateMDNSHostHandle(p_hMDNSHost); + return ((clsHost::stcQuery*)p_hMDNSQuery)->answerCount(); +} + +/* + MDNSResponder::answerAccessor +*/ +MDNSResponder::clsMDNSAnswerAccessor MDNSResponder::answerAccessor(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + uint32_t p_u32AnswerIndex) +{ + clsHost::stcQuery::stcAnswer* pAnswer = (((_validateMDNSHostHandle(p_hMDNSHost)) && + (p_hMDNSQuery)) + ? ((clsHost::stcQuery*)p_hMDNSQuery)->answerAtIndex(p_u32AnswerIndex) + : 0); + return MDNSResponder::clsMDNSAnswerAccessor(pAnswer); +} + +#ifdef LATER +/* + MDNSResponder::hasAnswerServiceDomain +*/ +bool MDNSResponder::hasAnswerServiceDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::ServiceDomain))); +} + + /* + MDNSResponder::answerServiceDomain + + Returns the domain for the given service. + If not already existing, the string is allocated, filled and attached to the answer. + + */ + const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcServiceDomain (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_ServiceDomain.m_u16NameLength) && + (!pSQAnswer->m_pcServiceDomain)) +{ + + pSQAnswer->m_pcServiceDomain = pSQAnswer->allocServiceDomain(pSQAnswer->m_ServiceDomain.c_strLength()); + if (pSQAnswer->m_pcServiceDomain) + { + pSQAnswer->m_ServiceDomain.c_str(pSQAnswer->m_pcServiceDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcServiceDomain : 0); +} + +/* + MDNSResponder::hasAnswerHostDomain +*/ +bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::HostDomain))); +} + + /* + MDNSResponder::answerHostDomain + + Returns the host domain for the given service. + If not already existing, the string is allocated, filled and attached to the answer. + + */ + const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcHostDomain (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_HostDomain.m_u16NameLength) && + (!pSQAnswer->m_pcHostDomain)) +{ + + pSQAnswer->m_pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); + if (pSQAnswer->m_pcHostDomain) + { + pSQAnswer->m_HostDomain.c_str(pSQAnswer->m_pcHostDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::hasAnswerIPv4Address +*/ +bool MDNSResponder::hasAnswerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv4Address))); +} + + /* + MDNSResponder::answerIPv4AddressCount + */ + uint32_t MDNSResponder::answerIPv4AddressCount(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->IPv4AddressCount() : 0); +} + + /* + MDNSResponder::answerIPv4Address + */ + IPAddress MDNSResponder::answerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + stcQuery::stcAnswer::stcIPv4Address* pIPv4Address = (pSQAnswer ? pSQAnswer->IPv4AddressAtIndex(p_u32AddressIndex) : 0); + return (pIPv4Address ? pIPv4Address->m_IPAddress : IPAddress()); +} +#endif + +#ifdef MDNS_IPV6_SUPPORT + /* + MDNSResponder::hasAnswerIPv6Address + */ + bool MDNSResponder::hasAnswerIPv6Address(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv6Address))); +} + + /* + MDNSResponder::answerIPv6AddressCount + */ + uint32_t MDNSResponder::answerIPv6AddressCount(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->IPv6AddressCount() : 0); +} + + /* + MDNSResponder::answerIPv6Address + */ + IPAddress MDNSResponder::answerIPv6Address(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + stcQuery::stcAnswer::stcIPv6Address* pIPv6Address = (pSQAnswer ? pSQAnswer->IPv6AddressAtIndex(p_u32AddressIndex) : 0); + return (pIPv6Address ? pIPv6Address->m_IPAddress : IPAddress()); +} +#endif + + /* + MDNSResponder::hasAnswerPort + */ + bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Port))); +} + + /* + MDNSResponder::answerPort + */ + uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->m_u16Port : 0); +} + + /* + MDNSResponder::hasAnswerTxts + */ + bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Txts))); +} + + /* + MDNSResponder::answerTxts + + Returns all TXT items for the given service as a ';'-separated string. + If not already existing; the string is alloced, filled and attached to the answer. + + */ + const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcTxts (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_Txts.m_pTxts) && + (!pSQAnswer->m_pcTxts)) +{ + + pSQAnswer->m_pcTxts = pSQAnswer->allocTxts(pSQAnswer->m_Txts.c_strLength()); + if (pSQAnswer->m_pcTxts) + { + pSQAnswer->m_Txts.c_str(pSQAnswer->m_pcTxts); + } + } + return (pSQAnswer ? pSQAnswer->m_pcTxts : 0); +} + + +/* + PROBING +*/ + +/* + MDNSResponder::setHostProbeResultCallback + + Set a callback for probe results. The callback is called, when probing + for the host domain failes or succeedes. + In the case of failure, the domain name should be changed via 'setHostName' + When succeeded, the host domain will be announced by the MDNS responder. + +*/ +bool MDNSResponder::setHostProbeResultCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, + MDNSResponder::MDNSHostProbeResultCallbackFn p_fnCallback) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (((clsHost*)p_hMDNSHost)->m_HostProbeInformation.m_fnProbeResultCallback = p_fnCallback, true)); +} + + +/* + MISC +*/ + +/* + MDNSResponder::notifyNetIfChange + + Should be called, whenever the AP for the MDNS responder changes. + A bit of this is caught by the event callbacks installed in the constructor. + +*/ +bool MDNSResponder::notifyNetIfChange(netif* p_pNetIf) +{ + clsHost* pMDNSHost; + return (((pMDNSHost = _findHost(p_pNetIf))) && + (_restart(*pMDNSHost))); +} + +/* + MDNSResponder::update + + Should be called in every 'loop'. + +*/ +bool MDNSResponder::update(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_process(*(clsHost*)p_hMDNSHost, true))); +} + +/* + MDNSResponder::update (convenience) +*/ +bool MDNSResponder::update(void) +{ + bool bResult = true; + for (clsHost*& pMDNSHost : m_HostList) + { + if (!_process(*it, true)) + { + bResult = false; + } + } + return bResult; +} + +/* + MDNSResponder::announce (convenience) + + Should be called, if the 'configuration' changes. Mainly this will be changes in the TXT items... +*/ +bool MDNSResponder::announce(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_announce(*(clsHost*)p_hMDNSHost, true, true))); +} + +/* + MDNSResponder::announce (convenience) +*/ +bool MDNSResponder::announce(void) +{ + bool bResult = true; + for (clsHost*& pMDNSHost : m_HostList) + { + if (!_announce(*it, true, true)) + { + bResult = false; + } + } + return bResult; +} + +/* + MDNSResponder::enableArduino + + Enable the OTA update service. + +*/ +MDNSResponder::hMDNSService MDNSResponder::enableArduino(const MDNSResponder::hMDNSHost p_hMDNSHost, + uint16_t p_u16Port, + bool p_bAuthUpload /*= false*/) +{ + hMDNSService hService = addService(p_hMDNSHost, 0, "arduino", "tcp", p_u16Port); + if (hService) + { + if ((!addServiceTxt(p_hMDNSHost, hService, "tcp_check", "no")) || + (!addServiceTxt(p_hMDNSHost, hService, "ssh_upload", "no")) || + (!addServiceTxt(p_hMDNSHost, hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) || + (!addServiceTxt(p_hMDNSHost, hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) + { + + removeService(p_hMDNSHost, hService); + hService = 0; + } + } + return hService; +} +#endif // LATER + +#ifdef __MDNS_USE_LEGACY + +/** + INTERFACE +*/ + +/** + MDNSResponder::MDNSResponder +*/ +MDNSResponder::MDNSResponder(void) + : m_pUDPContext(0) +{ +} + +/* + MDNSResponder::~MDNSResponder +*/ +MDNSResponder::~MDNSResponder(void) +{ + close(); +} + + +/* + MDNSResponder::getHost (netif) +*/ +MDNSResponder::hMDNSHost MDNSResponder::getHost(netif* p_pNetIf) const +{ + return (hMDNSHost)(p_pNetIf ? _findHost(p_pNetIf) : 0); +} + +/* + MDNSResponder::getHost (WiFiMode) +*/ +MDNSResponder::hMDNSHost MDNSResponder::getHost(WiFiMode_t p_WiFiMode) const +{ + hMDNSHost hResult = 0; + + if (WIFI_STA == p_WiFiMode) + { + hResult = getHost(netif_get_by_index(WIFI_STA)); + } + else if (WIFI_AP == p_WiFiMode) + { + hResult = getHost(netif_get_by_index(WIFI_AP)); + } + return hResult; +} + +/* + MDNSResponder::begin (hostname, netif, probe_callback) +*/ +MDNSResponder::hMDNSHost MDNSResponder::begin(const char* p_pcHostName, + netif* p_pNetIf, + MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, netif: %u)\n"), _DH(), (p_pcHostName ? : "_"), (p_pNetIf ? netif_get_index(p_pNetIf) : 0));); + + return (hMDNSHost)_begin(p_pcHostName, p_pNetIf, p_fnCallback); +} + +/* + MDNSResponder::begin (hostname, probe_callback) +*/ +bool MDNSResponder::begin(const char* p_pcHostName, + MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s)\n"), _DH(), (p_pcHostName ? : "_"));); + + return begin(p_pcHostName, (WiFiMode_t)wifi_get_opmode(), p_fnCallback); +} + +/* + MDNSResponder::begin (hostname, WiFiMode, probe_callback) +*/ +bool MDNSResponder::begin(const char* p_pcHostName, + WiFiMode_t p_WiFiMode, + MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, opmode: %u)\n"), _DH(), (p_pcHostName ? : "_"), (uint32_t)p_WiFiMode);); + + bool bResult = true; + + if ((bResult) && + (p_WiFiMode & WIFI_STA)) + { + bResult = (0 != _begin(p_pcHostName, netif_get_by_index(WIFI_STA), p_fnCallback)); + } + if ((bResult) && + (p_WiFiMode & WIFI_AP)) + { + bResult = (0 != _begin(p_pcHostName, netif_get_by_index(WIFI_AP), p_fnCallback)); + } + return bResult; +} + +/* + MDNSResponder::close +*/ +bool MDNSResponder::close(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_close(*(clsHost*)p_hMDNSHost))); +} + +/* + MDNSResponder::close (convenience) +*/ +bool MDNSResponder::close(void) +{ + clsHostList::iterator it(m_HostList.begin()); + while (m_HostList.end() != it) + { + _close(**it++); + } + + _releaseUDPContext(); + + return true; +} + +/* + MDNSResponder::end (ESP32) +*/ +bool MDNSResponder::end(void) +{ + return close(); +} + +/* + MDNSResponder::setHostName +*/ +bool MDNSResponder::setHostName(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcHostName) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_setHostName(*(clsHost*)p_hMDNSHost, p_pcHostName))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setHostName: FAILED for '%s'!\n"), _DH(), (p_pcHostName ? : "-"));); + return bResult; +} + +/* + MDNSResponder::setHostname (LEGACY 2) + + Set the host name in all netif bindings + +*/ +bool MDNSResponder::setHostname(const char* p_pcHostName) +{ + bool bResult = true; + for (clsHost*& pMDNSHost : m_HostList) + { + if (!setHostName((hMDNSHost)pMDNSHost, p_pcHostName)) + { + bResult = false; + } + } + return bResult; +} + +/* + MDNSResponder::setHostname (LEGACY) +*/ +bool MDNSResponder::setHostname(String p_strHostName) +{ + return setHostname(p_strHostName.c_str()); +} + +/* + MDNSResponder::hostName +*/ +const char* MDNSResponder::hostName(const MDNSResponder::hMDNSHost p_hMDNSHost) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost) + ? (((clsHost*)p_hMDNSHost)->m_pcHostName) + : 0); +} + +/* + MDNSResponder::hostname (LEGACY 2) +*/ +const char* MDNSResponder::hostname(void) const +{ + return ((!m_HostList.empty()) + ? hostName((hMDNSHost)m_HostList.front()) + : 0); +} + +/* + MDNSResponder::status +*/ +bool MDNSResponder::status(const MDNSResponder::hMDNSHost p_hMDNSHost) const +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (enuProbingStatus::Done == ((clsHost*)p_hMDNSHost)->m_HostProbeInformation.m_ProbingStatus)); +} + +/* + MDNSResponder::status (LEGACY 2) +*/ +bool MDNSResponder::status(void) const +{ + bool bResult = true; + for (clsHost * const& pMDNSHost : m_HostList) + { + if (!((bResult = status((hMDNSHost)pMDNSHost)))) + { + break; + } + } + return bResult; +} + + +/* + SERVICES +*/ + +/* + MDNSResponder::setInstanceName +*/ +bool MDNSResponder::setInstanceName(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcInstanceName) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_setInstanceName(*(clsHost*)p_hMDNSHost, p_pcInstanceName))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setInstanceName: FAILED for '%s'!\n"), _DH(), (p_pcInstanceName ? : "-"));); + return bResult; +} + +/* + MDNSResponder::setInstanceName (LEGACY 2) + + Set the instance name in all netif bindings + +*/ +bool MDNSResponder::setInstanceName(const char* p_pcInstanceName) +{ + bool bResult = true; + for (clsHost*& pMDNSHost : m_HostList) + { + if (!setInstanceName((hMDNSHost)pMDNSHost, p_pcInstanceName)) + { + bResult = false; + } + } + return bResult; +} + +/* + MDNSResponder::setInstanceName (LEGACY 2) +*/ +bool MDNSResponder::setInstanceName(const String& p_strInstanceName) +{ + return setInstanceName(p_strInstanceName.c_str()); +} + +/* + MDNSResponder::addService + + Add service; using hostname if no name is explicitly provided for the service + The usual '_' underline, which is prepended to service and protocol, eg. _http, + may be given. If not, it is added automatically. + +*/ +MDNSResponder::hMDNSService MDNSResponder::addService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + hMDNSService hService = (_validateMDNSHostHandle(p_hMDNSHost) + ? (hMDNSService)_addService(*(clsHost*)p_hMDNSHost, p_pcName, p_pcService, p_pcProtocol, p_u16Port) + : 0); + DEBUG_EX_ERR(if (!hService) DEBUG_OUTPUT.printf_P(PSTR("%s addService: FAILED for '%s._%s._%s.local'!\n"), _DH((clsHost*)p_hMDNSHost), (p_pcName ? : "-"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + return hService; +} + +/* + MDNSResponder::addService (LEGACY 2) + + Add a service to all netif bindings. + (Only) the first service (handle) is returned. + +*/ +MDNSResponder::hMDNSService MDNSResponder::addService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + hMDNSService hResult = 0; + for (clsHost*& pMDNSHost : m_HostList) + { + hMDNSService hNewService = addService((hMDNSHost)pMDNSHost, p_pcName, p_pcService, p_pcProtocol, p_u16Port); + if (!hResult) + { + hResult = hNewService; + } + } + return hResult; +} + +/* + MDNSResponder::removeService + + Unanounce a service (by sending a goodbye message) and remove it + from the MDNS responder + +*/ +bool MDNSResponder::removeService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (_removeService(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeService: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::removeService (LEGACY 2) + + Find and remove the service from one netif binding +*/ +bool MDNSResponder::removeService(const MDNSResponder::hMDNSService p_hMDNSService) +{ + clsHost* pHost = 0; + return ((_validateMDNSHostHandle(p_hMDNSService, &pHost)) && + (removeService((hMDNSHost)pHost, p_hMDNSService))); +} + +/* + MDNSResponder::removeService +*/ +bool MDNSResponder::removeService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol) +{ + clsHost* pMDNSHost; + stcService* pMDNSService; + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + (pMDNSHost = (clsHost*)p_hMDNSHost) && + ((pMDNSService = _findService(*pMDNSHost, (p_pcName ? : (pMDNSHost->m_pcInstanceName ? : pMDNSHost->m_pcHostName)), p_pcService, p_pcProtocol))) && + (_removeService(*(clsHost*)p_hMDNSHost, *pMDNSService))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeService: FAILED for '%s._%s._%s.local'!\n"), _DH((clsHost*)p_hMDNSHost), (p_pcName ? : "-"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + return bResult; +} + +/* + MDNSResponder::removeService (LEGACY 2) +*/ +bool MDNSResponder::removeService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol) +{ + bool bResult = true; + + for (clsHost*& pMDNSHost : m_HostList) + { + if (!removeService((hMDNSHost)pMDNSHost, p_pcName, p_pcService, p_pcProtocol)) + { + bResult = false; + } + } + return bResult; +} + +/* + MDNSResponder::addService (LEGACY) +*/ +bool MDNSResponder::addService(String p_strService, + String p_strProtocol, + uint16_t p_u16Port) +{ + return (0 != addService(0, p_strService.c_str(), p_strProtocol.c_str(), p_u16Port)); +} + +/* + MDNSResponder::findService + + Find an existing service. + +*/ +MDNSResponder::hMDNSService MDNSResponder::findService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol) +{ + clsHost* pMDNSHost; + return (((_validateMDNSHostHandle(p_hMDNSHost)) && + (pMDNSHost = (clsHost*)p_hMDNSHost)) + ? _findService(*pMDNSHost, (p_pcName ? : (pMDNSHost->m_pcInstanceName ? : pMDNSHost->m_pcHostName)), p_pcService, p_pcProtocol) + : 0); +} + +/* + MDNSResponder::findService (LEGACY 2) + + (Only) the first service handle is returned. + +*/ +MDNSResponder::hMDNSService MDNSResponder::findService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol) +{ + hMDNSService hResult = 0; + for (clsHost*& pMDNSHost : m_HostList) + { + if ((hResult = findService((hMDNSHost)pMDNSHost, p_pcName, p_pcService, p_pcProtocol))) + { + break; + } + } + return hResult; +} + +/* + MDNSResponder::setServiceName +*/ +bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcInstanceName) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (_setServiceName(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, p_pcInstanceName))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setServiceName: FAILED for '%s'!\n"), _DH((clsHost*)p_hMDNSHost), (p_pcInstanceName ? : "-"));); + return bResult; +} + +/* + MDNSResponder::setServiceName (LEGACY 2) +*/ +bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcInstanceName) +{ + clsHost* pHost = 0; + return ((_validateMDNSServiceHandle(p_hMDNSService, &pHost)) && + (setServiceName((hMDNSHost)pHost, p_hMDNSService, p_pcInstanceName))); +} + +/* + MDNSResponder::serviceName +*/ +const char* MDNSResponder::serviceName(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? ((stcService*)p_hMDNSService)->m_pcName + : 0); +} + +/* + MDNSResponder::serviceName (LEGACY 2) +*/ +const char* MDNSResponder::serviceName(const hMDNSService p_hMDNSService) const +{ + clsHost* pHost = 0; + return (_validateMDNSServiceHandle(p_hMDNSService, &pHost) + ? serviceName((hMDNSHost)pHost, p_hMDNSService) + : 0); +} + +/* + MDNSResponder::service +*/ +const char* MDNSResponder::service(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? ((stcService*)p_hMDNSService)->m_pcService + : 0); +} + +/* + MDNSResponder::service (LEGACY 2) +*/ +const char* MDNSResponder::service(const hMDNSService p_hMDNSService) const +{ + clsHost* pHost = 0; + return (_validateMDNSServiceHandle(p_hMDNSService, &pHost) + ? service((hMDNSHost)pHost, p_hMDNSService) + : 0); +} + +/* + MDNSResponder::serviceProtocol +*/ +const char* MDNSResponder::serviceProtocol(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? ((stcService*)p_hMDNSService)->m_pcProtocol + : 0); +} + +/* + MDNSResponder::serviceProtocol (LEGACY) +*/ +const char* MDNSResponder::serviceProtocol(const hMDNSService p_hMDNSService) const +{ + clsHost* pHost = 0; + return (_validateMDNSServiceHandle(p_hMDNSService, &pHost) + ? serviceProtocol((hMDNSHost)pHost, p_hMDNSService) + : 0); +} + +/* + MDNSResponder::serviceStatus +*/ +bool MDNSResponder::serviceStatus(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (enuProbingStatus::Done == ((stcService*)p_hMDNSService)->m_ProbeInformation.m_ProbingStatus)); +} + +/* + MDNSResponder::serviceStatus (LEGACY 2) + + Returns 'true' if probing for the service 'hMDNSService' is done + +*/ +bool MDNSResponder::serviceStatus(const hMDNSService p_hMDNSService) const +{ + clsHost* pHost = 0; + return (_validateMDNSServiceHandle(p_hMDNSService, &pHost) + ? serviceStatus((hMDNSHost)pHost, p_hMDNSService) + : false); +} + + +/* + SERVICE TXT +*/ + +/* + MDNSResponder::addServiceTxt + + Add a static service TXT item ('Key'='Value') to a service. + +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue) +{ + hMDNSTxt hTxt = (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? (hMDNSTxt)_addServiceTxt((clsHost*)p_hMDNSHost, (stcService*)p_hMDNSService, p_pcKey, p_pcValue, false) + : 0); + DEBUG_EX_ERR(if (!hTxt) DEBUG_OUTPUT.printf_P(PSTR("%s addServiceTxt: FAILED for '%s=%s'!\n"), _DH(), (p_pcKey ? : "-"), (p_pcValue ? : "-"));); + return hTxt; +} + +/* + MDNSResponder::addServiceTxt (LEGACY 2) + + Add a static service TXT item ('Key'='Value') to a service. + +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_pcValue) + : 0); +} + +/* + MDNSRESPONDER_xxx_TO_CHAR + Formats: http://www.cplusplus.com/reference/cstdio/printf/ +*/ +#define MDNSRESPONDER_U32_TO_CHAR(BUFFERNAME, U32VALUE) \ + char BUFFERNAME[16]; /* 32-bit max 10 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%u", U32VALUE); +#define MDNSRESPONDER_U16_TO_CHAR(BUFFERNAME, U16VALUE) \ + char BUFFERNAME[8]; /* 16-bit max 5 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%hu", U16VALUE); +#define MDNSRESPONDER_U8_TO_CHAR(BUFFERNAME, U8VALUE) \ + char BUFFERNAME[8]; /* 8-bit max 3 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%hhu", U8VALUE); +#define MDNSRESPONDER_I32_TO_CHAR(BUFFERNAME, I32VALUE) \ + char BUFFERNAME[16]; /* 32-bit max 10 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%i", I32VALUE); +#define MDNSRESPONDER_I16_TO_CHAR(BUFFERNAME, I16VALUE) \ + char BUFFERNAME[8]; /* 16-bit max 5 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%hi", I16VALUE); +#define MDNSRESPONDER_I8_TO_CHAR(BUFFERNAME, I8VALUE) \ + char BUFFERNAME[8]; /* 8-bit max 3 digits */ \ + *BUFFERNAME = 0; \ + sprintf(BUFFERNAME, "%hhi", I8VALUE); + + +/* + MDNSResponder::addServiceTxt (uint32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + MDNSRESPONDER_U32_TO_CHAR(acBuffer, p_u32Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addServiceTxt (uint32_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u32Value) + : 0); +} + +/* + MDNSResponder::addServiceTxt (uint16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + MDNSRESPONDER_U16_TO_CHAR(acBuffer, p_u16Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addServiceTxt (uint16_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u16Value) + : 0); +} + +/* + MDNSResponder::addServiceTxt (uint8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + MDNSRESPONDER_U8_TO_CHAR(acBuffer, p_u8Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addServiceTxt (uint8_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u8Value) + : 0); +} + +/* + MDNSResponder::addServiceTxt (int32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value) +{ + MDNSRESPONDER_I32_TO_CHAR(acBuffer, p_i32Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addServiceTxt (int32_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i32Value) + : 0); +} + +/* + MDNSResponder::addServiceTxt (int16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value) +{ + MDNSRESPONDER_I16_TO_CHAR(acBuffer, p_i16Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addServiceTxt (int16_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i16Value) + : 0); +} + +/* + MDNSResponder::addServiceTxt (int8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value) +{ + MDNSRESPONDER_I8_TO_CHAR(acBuffer, p_i8Value); + return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addServiceTxt (int8_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i8Value) + : 0); +} + +/* + MDNSResponder::removeServiceTxt + + Remove a static service TXT item from a service. +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const MDNSResponder::hMDNSTxt p_hTxt) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (p_hTxt) && + (_findServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, p_hTxt)) && + (_releaseServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, (stcServiceTxt*)p_hTxt))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::removeServiceTxt (LEGACY 2) +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const MDNSResponder::hMDNSTxt p_hTxt) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? removeServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_hTxt) + : false); +} + +/* + MDNSResponder::removeServiceTxt +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey) +{ + stcServiceTxt* pTxt; + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (p_pcKey) && + ((pTxt = _findServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, p_pcKey))) && + (_releaseServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, pTxt))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::removeServiceTxt (LEGACY 2) +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? removeServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey) + : false); +} + +/* + MDNSResponder::removeServiceTxt (LEGACY) +*/ +bool MDNSResponder::removeServiceTxt(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey) +{ + hMDNSService hService; + return (((hService = findService(p_pcName, p_pcService, p_pcProtocol))) + ? removeServiceTxt(hService, p_pcKey) + : false); +} + +/* + MDNSResponder::addServiceTxt (LEGACY) +*/ +bool MDNSResponder::addServiceTxt(const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey, + const char* p_pcValue) +{ + hMDNSService hService; + return (((hService = findService(p_pcName, p_pcService, p_pcProtocol))) + ? addServiceTxt(hService, p_pcKey, p_pcValue) + : false); +} + +/* + MDNSResponder::addServiceTxt (LEGACY) +*/ +bool MDNSResponder::addServiceTxt(String p_strService, + String p_strProtocol, + String p_strKey, + String p_strValue) +{ + return addServiceTxt(p_strService.c_str(), p_strProtocol.c_str(), p_strKey.c_str(), p_strValue.c_str()); +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (binding) + + Set a netif binding specific callback for dynamic service TXT items. The callback is called, whenever + service TXT items are needed for any service on the netif binding. + +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, + MDNSResponder::MDNSDynamicServiceTxtCallbackFn p_fnCallback) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + ((!p_fnCallback) || + ((((clsHost*)p_hMDNSHost)->m_fnServiceTxtCallback = p_fnCallback)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setDynamicServiceTxtCallback: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (service) + + Set a service specific callback for dynamic service TXT items. The callback is called, whenever + service TXT items are needed for the given service. +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + MDNSResponder::MDNSDynamicServiceTxtCallbackFn p_fnCallback) +{ + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + ((!p_fnCallback) || + ((((stcService*)p_hMDNSService)->m_fnServiceTxtCallback = p_fnCallback)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setDynamicServiceTxtCallback: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); + return bResult; +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (global) (LEGACY 2) + + Set a global callback for dynamic service TXT items. The callback is called, whenever + service TXT items are needed. + +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::MDNSDynamicServiceTxtCallbackFn1 p_fnCallback) +{ + for (clsHostList : .iterator it : m_HostList) + { + setDynamicServiceTxtCallback((hMDNSHost)it, p_fnCallback); + } + return true; +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (global) (LEGACY 2 (Fn2)) +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::MDNSDynamicServiceTxtCallbackFn2 p_fnCallback) +{ + return setDynamicServiceTxtCallback([p_fnCallback](MDNSResponder*, const hMDNSService p_hMDNSService) + { + if (p_fnCallback) + { + p_fnCallback(p_hMDNSService); + } + }); +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (service) (LEGACY 2) +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::hMDNSService p_hMDNSService, + MDNSResponder::MDNSDynamicServiceTxtCallbackFn1 p_fnCallback) +{ + clsHost* pHost; + return ((_validateMDNSHostHandle(p_hMDNSService, &pHost)) && + (setDynamicServiceTxtCallback((hMDNSHost)pHost, hMDNSService, p_fnCallback))); +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (service) (LEGACY 2 (Fn2)) +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::hMDNSService p_hMDNSService, + MDNSResponder::MDNSDynamicServiceTxtCallbackFn2 p_fnCallback) +{ + return setDynamicServiceTxtCallback(p_hMDNSService, [p_fnCallback](MDNSResponder*, const hMDNSService p_hMDNSService) + { + if (p_fnCallback) + { + p_fnCallback(p_hMDNSService); + } + }); +} + +/* + MDNSResponder::addDynamicServiceTxt +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue) +{ + hMDNSTxt hTxt = (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) + ? _addServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, p_pcKey, p_pcValue, true) + : 0); + DEBUG_EX_ERR(if (!hTxt) DEBUG_OUTPUT.printf_P(PSTR("%s addDynamicServiceTxt: FAILED for '%s=%s'!\n"), _DH(), (p_pcKey ? : "-"), (p_pcValue ? : "-"));); + return hTxt; +} + +/* + MDNSResponder::addDynamicServiceTxt (LEGACY 2) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + const char* p_pcValue) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_pcValue) + : 0); +} + +/* + MDNSResponder::addDynamicServiceTxt (uint32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + MDNSRESPONDER_U32_TO_CHAR(acBuffer, p_u32Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addDynamicServiceTxt (uint32_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u32Value) + : 0); +} + +/* + MDNSResponder::addDynamicServiceTxt (uint16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + MDNSRESPONDER_U16_TO_CHAR(acBuffer, p_u16Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addDynamicServiceTxt (uint16_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u16Value) + : 0); +} + +/* + MDNSResponder::addDynamicServiceTxt (uint8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + MDNSRESPONDER_U8_TO_CHAR(acBuffer, p_u8Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addDynamicServiceTxt (uint8_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u8Value) + : 0); +} + +/* + MDNSResponder::addDynamicServiceTxt (int32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int32_t p_i32Value) +{ + MDNSRESPONDER_I32_TO_CHAR(acBuffer, p_i32Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addDynamicServiceTxt (int32_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint32_t p_i32Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i32Value) + : 0); +} + +/* + MDNSResponder::addDynamicServiceTxt (int16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int16_t p_i16Value) +{ + MDNSRESPONDER_I16_TO_CHAR(acBuffer, p_i16Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addDynamicServiceTxt (int16_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint16_t p_i16Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i16Value) + : 0); +} + +/* + MDNSResponder::addDynamicServiceTxt (int8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + int8_t p_i8Value) +{ + MDNSRESPONDER_I8_TO_CHAR(acBuffer, p_i8Value); + return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): + } + + /* + MDNSResponder::addDynamicServiceTxt (int8_t) (LEGACY 2) + */ + MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, + const char* p_pcKey, + uint8_t p_i8Value) +{ + clsHost* pHost = 0; + return (_validateMDNSHostHandle(p_hMDNSService, &pHost) + ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i8Value) + : 0); +} + + +/** + STATIC QUERIES +*/ + +/* + MDNSResponder::queryService + + Perform a (blocking) static service query. + The arrived answers can be queried by calling: + - answerHostName (or 'hostname') + - answerIP (or 'IP') + - answerPort (or 'port') + +*/ +uint32_t MDNSResponder::queryService(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '%s.%s'\n"), _DH(), p_pcService, p_pcProtocol);); + + uint32_t u32Result = 0; + + stcQuery* pMDNSQuery = 0; + if ((_validateMDNSHostHandle(p_hMDNSHost)) && + (p_pcService) && + (os_strlen(p_pcService)) && + (p_pcProtocol) && + (os_strlen(p_pcProtocol)) && + (p_u16Timeout) && + (_removeLegacyQuery()) && + ((pMDNSQuery = _allocQuery(*(clsHost*)p_hMDNSHost, stcQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) + { + pMDNSQuery->m_bLegacyQuery = true; + + if (_sendMDNSQuery(*(clsHost*)p_hMDNSHost, *pMDNSQuery)) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + pMDNSQuery->m_bAwaitingAnswers = false; + u32Result = pMDNSQuery->answerCount(); + } + else // FAILED to send query + { + _removeQuery(*(clsHost*)p_hMDNSHost, pMDNSQuery); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: INVALID input data!\n"), _DH());); + } + return u32Result; +} + +/* + MDNSResponder::queryService (LEGACY 2) +*/ +uint32_t MDNSResponder::queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + return ((!m_HostList.empty()) + ? queryService((hMDNSHost)m_HostList.front(), p_pcService, p_pcProtocol, p_u16Timeout) + : 0); +} + +/* + MDNSResponder::queryService (LEGACY) +*/ +uint32_t MDNSResponder::queryService(const String& p_strService, + const String& p_strProtocol) +{ + return queryService(p_strService.c_str(), p_strProtocol.c_str()); +} + +/* + MDNSResponder::queryHost + + Perform a (blocking) static host query. + The arrived answers can be queried by calling: + - answerHostName (or 'hostname') + - answerIP (or 'IP') + - answerPort (or 'port') + +*/ +uint32_t MDNSResponder::queryHost(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local'\n"), _DH(), p_pcHostName);); + + uint32_t u32Result = 0; + + stcQuery* pHostQuery = 0; + if ((_validateMDNSHostHandle(p_hMDNSHost)) && + (p_pcHostName) && + (os_strlen(p_pcHostName)) && + (p_u16Timeout) && + (_removeLegacyQuery()) && + ((pHostQuery = _allocQuery(*(clsHost*)p_hMDNSHost, stcQuery::enuQueryType::Host))) && + (_buildDomainForHost(p_pcHostName, pHostQuery->m_Domain))) + { + + pHostQuery->m_bLegacyQuery = true; + + if (_sendMDNSQuery(*(clsHost*)p_hMDNSHost, *pHostQuery)) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + pHostQuery->m_bAwaitingAnswers = false; + u32Result = pHostQuery->answerCount(); + } + else // FAILED to send query + { + _removeQuery(*(clsHost*)p_hMDNSHost, pHostQuery); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: INVALID input data!\n"), _DH());); + } + return u32Result; +} + +/* + queryHost (LEGACY 2) +*/ +uint32_t MDNSResponder::queryHost(const char* p_pcHostName, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + return ((!m_HostList.empty()) + ? queryHost((hMDNSHost)m_HostList.front(), p_pcService, p_pcProtocol, p_u16Timeout) + : 0); +} + +/* + MDNSResponder::removeQuery + + Remove the last static query (and all answers). + +*/ +bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_removeLegacyQuery(*(clsHost*)p_hMDNSHost))); +} + +/* + MDNSResponder::removeQuery (LEGACY 2) +*/ +bool MDNSResponder::removeQuery(void) +{ + return ((!m_HostList.empty()) + ? removeQuery((hMDNSHost)m_HostList.front()) + : false); +} + +/* + MDNSResponder::hasQuery + + Return 'true', if a static query is currently installed + +*/ +bool MDNSResponder::hasQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (0 != _findLegacyQuery(*(clsHost*)p_hMDNSHost))); +} + +/* + MDNSResponder::hasQuery (LEGACY 2) +*/ +bool MDNSResponder::hasQuery(void) +{ + return ((!m_HostList.empty()) + ? hasQuery((hMDNSHost)m_HostList.front()) + : false); +} + +/* + MDNSResponder::getQuery + + Return handle to the last static query + +*/ +MDNSResponder::hMDNSQuery MDNSResponder::getQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return (_validateMDNSHostHandle(p_hMDNSHost) + ? (hMDNSQuery)_findLegacyQuery() + : 0); +} + +/* + MDNSResponder::getQuery (LEGACY 2) +*/ +MDNSResponder::hMDNSQuery MDNSResponder::getQuery(void) +{ + return ((!m_HostList.empty()) + ? getQuery((hMDNSHost)m_HostList.front()) + : false); +} + +/* + MDNSResponder::answerHostName +*/ +const char* MDNSResponder::answerHostName(const MDNSResponder::hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex) +{ + const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); + stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); + + if ((pSQAnswer) && + (pSQAnswer->m_HostDomain.m_u16NameLength) && + (!pSQAnswer->m_pcHostDomain)) + { + char* pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); + if (pcHostDomain) + { + pSQAnswer->m_HostDomain.c_str(pcHostDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); +} + +/* + MDNSResponder::answerHostName (LEGACY 2) +*/ +const char* MDNSResponder::answerHostName(const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerHostName((hMDNSHost)m_HostList.front(), p_u32AnswerIndex) + : 0); +} + +/* + MDNSResponder::hostname (LEGACY) +*/ +String MDNSResponder::hostname(const uint32_t p_u32AnswerIndex) +{ + return String(answerHostName(p_u32AnswerIndex)); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::answerIPv4 +*/ +IPAddress MDNSResponder::answerIPv4(const MDNSResponder::hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex) +{ + const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); + const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); + const stcQuery::stcAnswer::stcIPv4Address* pIPv4Address = (((pSQAnswer) && (pSQAnswer->m_pIPv4Addresses)) ? pSQAnswer->IPv4AddressAtIndex(0) : 0); + return (pIPv4Address ? pIPv4Address->m_IPAddress : IPAddress()); +} + +/* + MDNSResponder::answerIPv4 (LEGACY 2) +*/ +IPAddress MDNSResponder::answerIPv4(const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerIPv4((hMDNSHost)m_HostList.front(), p_u32AnswerIndex) + : IPAddress()); +} + +/* + MDNSResponder::answerIP (LEGACY 2) +*/ +IPAddress MDNSResponder::answerIP(const uint32_t p_u32AnswerIndex) +{ + return answerIPv4(p_u32AnswerIndex); +} + +/* + MDNSResponder::IP (LEGACY) +*/ +IPAddress MDNSResponder::IP(const uint32_t p_u32AnswerIndex) +{ + return answerIPv4(p_u32AnswerIndex); +} +#endif + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::answerIPv6 +*/ +IPAddress MDNSResponder::answerIPv6(const MDNSResponder::hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex) +{ + const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); + const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); + const stcQuery::stcAnswer::stcIPv6Address* pIPv6Address = (((pSQAnswer) && (pSQAnswer->m_pIPv6Addresses)) ? pSQAnswer->IPv6AddressAtIndex(0) : 0); + return (pIPv6Address ? pIPv6Address->m_IPAddress : IPAddress()); +} + +/* + MDNSResponder::answerIPv6 (LEGACY 2) +*/ +IPAddress MDNSResponder::answerIPv6(const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerIPv6((hMDNSHost)m_HostList.front(), p_u32AnswerIndex) + : IPAddress()); +} +#endif + +/* + MDNSResponder::answerPort +*/ +uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, + const uint32_t p_u32AnswerIndex) +{ + const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); + const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->m_u16Port : 0); +} + +/* + MDNSResponder::answerPort (LEGACY 2) +*/ +uint16_t MDNSResponder::answerPort(const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerPort((hMDNSHost)m_HostList.front(), p_u32AnswerIndex) + : 0); +} + +/* + MDNSResponder::port (LEGACY) +*/ +uint16_t MDNSResponder::port(const uint32_t p_u32AnswerIndex) +{ + return answerPort(p_u32AnswerIndex); +} + + +/** + DYNAMIC SERVICE QUERY +*/ + +/* + MDNSResponder::installServiceQuery + + Add a dynamic service query and a corresponding callback to the MDNS responder. + The callback will be called for every answer update. + The answers can also be queried by calling: + - answerServiceDomain + - answerHostDomain + - answerIPv4Address/answerIPv6Address + - answerPort + - answerTxts + +*/ +MDNSResponder::hMDNSQuery MDNSResponder::installServiceQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcService, + const char* p_pcProtocol, + MDNSResponder::MDNSQueryCallbackFn p_fnCallback) +{ + hMDNSQuery hResult = 0; + + stcQuery* pMDNSQuery = 0; + if ((_validateMDNSHostHandle(p_hMDNSHost)) && + (p_pcService) && + (os_strlen(p_pcService)) && + (p_pcProtocol) && + (os_strlen(p_pcProtocol)) && + (p_fnCallback) && + ((pMDNSQuery = _allocQuery(*(clsHost*)p_hMDNSHost, stcQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) + { + + pMDNSQuery->m_fnCallback = p_fnCallback; + pMDNSQuery->m_bLegacyQuery = false; + + if (_sendMDNSQuery(*(clsHost*)p_hMDNSHost, *pMDNSQuery)) + { + pMDNSQuery->m_u8SentCount = 1; + pMDNSQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); + + hResult = (hMDNSQuery)pMDNSQuery; + } + else + { + _removeQuery(*(clsHost*)p_hMDNSHost, pMDNSQuery); + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: %s for '%s.%s'!\n\n"), _DH(), (hResult ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + DEBUG_EX_ERR(if (!hResult) DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: FAILED for '%s.%s'!\n\n"), _DH(), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + return hResult; +} + +/* + MDNSResponder::installServiceQuery (LEGACY 2) +*/ +MDNSResponder::hMDNSQuery MDNSResponder::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSResponder::MDNSQueryCallbackFn1 p_fnCallback) +{ + return ((!m_HostList.empty()) + ? installServiceQuery((hMDNSHost)m_HostList.front(), p_pcService, p_pcProtocol, [p_fnCallback])(MDNSResponder * p_pMDNSResponder, + MDNSResponder::hMDNSHost, + const stcAnswerAccessor & p_MDNSAnswerAccessor, + typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_bSetContent) + { + if (p_fnCallback) + { + p_fnCallback(p_pMDNSResponder, p_MDNSAnswerAccessor, p_QueryAnswerTypeFlags, p_bSetContent); + } + }) + : 0); + } + + /* + MDNSResponder::installServiceQuery (LEGACY 2) + */ + MDNSResponder::hMDNSQuery MDNSResponder::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSResponder::MDNSQueryCallbackFn2 p_fnCallback) +{ + return ((!m_HostList.empty()) + ? installServiceQuery((hMDNSHost)m_HostList.front(), p_pcService, p_pcProtocol, [p_fnCallback])(MDNSResponder*, + MDNSResponder::hMDNSHost, + const stcAnswerAccessor & p_MDNSAnswerAccessor, + typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_bSetContent) + { + if (p_fnCallback) + { + p_fnCallback(p_MDNSAnswerAccessor, p_QueryAnswerTypeFlags, p_bSetContent); + } + }) + : 0); + } + + /* + MDNSResponder::installHostQuery + */ + MDNSResponder::hMDNSQuery MDNSResponder::installHostQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, + const char* p_pcHostName, + MDNSResponder::MDNSQueryCallbackFn p_fnCallback) +{ + hMDNSQuery hResult = 0; + + if ((_validateMDNSHostHandle(p_hMDNSHost)) && + (p_pcHostName) && + (os_strlen(p_pcHostName))) + { + stcRRDomain domain; + hResult = ((_buildDomainForHost(p_pcHostName, domain)) + ? _installDomainQuery(*(clsHost*)p_hMDNSHost, domain, stcQuery::enuQueryType::Host, p_fnCallback) + : 0); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: %s for '%s.local'!\n\n"), _DH(), (hResult ? "Succeeded" : "FAILED"), (p_pcHostName ? : "-"));); + DEBUG_EX_ERR(if (!hResult) DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: FAILED for '%s.local'!\n\n"), _DH(), (p_pcHostName ? : "-"));); + return hResult; +} + +/* + MDNSResponder::installHostQuery (LEGACY 2) +*/ +MDNSResponder::hMDNSQuery MDNSResponder::installHostQuery(const char* p_pcHostName, + MDNSResponder::MDNSQueryCallbackFn1 p_fnCallback) +{ + return installHostQuery(p_pcHostName, [p_fnCallback](MDNSResponder * p_pMDNSResponder, + hMDNSHost, + const stcAnswerAccessor & p_MDNSAnswerAccessor, + typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_bSetContent) + { + if (p_fnCallback) + { + p_fnCallback(p_pMDNSResponder, p_MDNSAnswerAccessor, p_QueryAnswerTypeFlags, p_bSetContent); + } + }); +} + +/* + MDNSResponder::installHostQuery (LEGACY 2) +*/ +MDNSResponder::hMDNSQuery MDNSResponder::installHostQuery(const char* p_pcHostName, + MDNSResponder::MDNSQueryCallbackFn2 p_fnCallback) +{ + return installHostQuery(p_pcHostName, [p_fnCallback](MDNSResponder*, + hMDNSHost, + const stcAnswerAccessor & p_MDNSAnswerAccessor, + typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_bSetContent) + { + if (p_fnCallback) + { + p_fnCallback(p_MDNSAnswerAccessor, p_QueryAnswerTypeFlags, p_bSetContent); + } + }); +} + +/* + MDNSResponder::removeQuery + + Remove a dynamic query (and all collected answers) from the MDNS responder + +*/ +bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery) +{ + stcQuery* pMDNSQuery = 0; + bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && + ((pMDNSQuery = _findQuery(*(clsHost*)p_hMDNSHost, p_hQuery))) && + (_removeQuery(*(clsHost*)p_hMDNSHost, pMDNSQuery))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeQuery: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::removeQuery (LEGACY 2) +*/ +bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSQuery p_hMDNSQuery) +{ + return ((!m_HostList.empty()) + ? removeQuery((hMDNSHost)m_HostList.front(), p_hMDNSQuery) + : false); +} + +/* + MDNSResponder::answerAccessors +*/ +MDNSResponder::clsMDNSAnswerAccessorVector MDNSResponder::answerAccessors(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery) +{ + MDNSResponder::clsMDNSAnswerAccessorVector tempVector; + for (uint32_t u = 0; u < answerCount(p_hMDNSHost, p_hMDNSQuery); ++u) + { + tempVector.emplace_back(*this, p_hMDNSQuery, u); + } + return tempVector; +} + +/* + MDNSResponder::answerAccessors (LEGACY 2) +*/ +MDNSResponder::clsMDNSAnswerAccessorVector MDNSResponder::answerAccessors(const MDNSResponder::hMDNSQuery p_hMDNSQuery) +{ + return ((!m_HostList.empty()) + ? answerAccessors((hMDNSHost)m_HostList.front(), p_hMDNSQuery) + : MDNSResponder::clsMDNSAnswerAccessorVector()); +} + +/* + MDNSResponder::answerCount +*/ +uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery) : 0); + return (pMDNSQuery ? pMDNSQuery->answerCount() : 0); +} + +/* + MDNSResponder::answerCount (LEGACY 2) +*/ +uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSQuery p_hMDNSQuery) +{ + return ((!m_HostList.empty()) + ? answerCount((hMDNSHost)m_HostList.front(), p_hMDNSQuery) + : 0); +} + +/* + MDNSResponder::hasAnswerServiceDomain +*/ +bool MDNSResponder::hasAnswerServiceDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::ServiceDomain))); +} + + /* + MDNSResponder::hasAnswerServiceDomain (LEGACY 2) + */ + bool MDNSResponder::hasAnswerServiceDomain(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? hasAnswerServiceDomain((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : false); +} + +/* + MDNSResponder::answerServiceDomain + + Returns the domain for the given service. + If not already existing, the string is allocated, filled and attached to the answer. + +*/ +const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcServiceDomain (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_ServiceDomain.m_u16NameLength) && + (!pSQAnswer->m_pcServiceDomain)) +{ + + pSQAnswer->m_pcServiceDomain = pSQAnswer->allocServiceDomain(pSQAnswer->m_ServiceDomain.c_strLength()); + if (pSQAnswer->m_pcServiceDomain) + { + pSQAnswer->m_ServiceDomain.c_str(pSQAnswer->m_pcServiceDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcServiceDomain : 0); +} + +/* + MDNSResponder::answerServiceDomain (LEGACY 2) +*/ +const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerServiceDomain((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : 0); +} + +/* + MDNSResponder::hasAnswerHostDomain +*/ +bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::HostDomain))); +} + + /* + MDNSResponder::hasAnswerHostDomain (LEGACY 2) + */ + bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? hasAnswerHostDomain((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : false); +} + +/* + MDNSResponder::answerHostDomain + + Returns the host domain for the given service. + If not already existing, the string is allocated, filled and attached to the answer. + +*/ +const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcHostDomain (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_HostDomain.m_u16NameLength) && + (!pSQAnswer->m_pcHostDomain)) +{ + + pSQAnswer->m_pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); + if (pSQAnswer->m_pcHostDomain) + { + pSQAnswer->m_HostDomain.c_str(pSQAnswer->m_pcHostDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); +} + +/* + MDNSResponder::answerHostDomain (LEGACY 2) +*/ +const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerHostDomain((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : 0); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::hasAnswerIPv4Address +*/ +bool MDNSResponder::hasAnswerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv4Address))); +} + + /* + MDNSResponder::hasAnswerIPv4Address (LEGACY 2) + */ + bool MDNSResponder::hasAnswerIPv4Address(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? hasAnswerIPv4Address((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : false); +} + +/* + MDNSResponder::answerIPv4AddressCount +*/ +uint32_t MDNSResponder::answerIPv4AddressCount(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->IPv4AddressCount() : 0); +} + + /* + MDNSResponder::answerIPv4AddressCount (LEGACY 2) + */ + uint32_t MDNSResponder::answerIPv4AddressCount(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerIPv4AddressCount((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : 0); +} + +/* + MDNSResponder::answerIPv4Address +*/ +IPAddress MDNSResponder::answerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + stcQuery::stcAnswer::stcIPv4Address* pIPv4Address = (pSQAnswer ? pSQAnswer->IPv4AddressAtIndex(p_u32AddressIndex) : 0); + return (pIPv4Address ? pIPv4Address->m_IPAddress : IPAddress()); +} + + /* + MDNSResponder::answerIPv4Address (LEGACY 2) + */ + IPAddress MDNSResponder::answerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + return ((!m_HostList.empty()) + ? answerIPv4Address((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex, p_u32AddressIndex) + : IPAddress()); +} +#endif + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::hasAnswerIPv6Address +*/ +bool MDNSResponder::hasAnswerIPv6Address(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv6Address))); +} + + /* + MDNSResponder::hasAnswerIPv6Address (LEGACY 2) + */ + bool MDNSResponder::hasAnswerIPv6Address(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? hasAnswerIPv6Address((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : false); +} + +/* + MDNSResponder::answerIPv6AddressCount +*/ +uint32_t MDNSResponder::answerIPv6AddressCount(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->IPv6AddressCount() : 0); +} + + /* + MDNSResponder::answerIPv6AddressCount (LEGACY 2) + */ + uint32_t MDNSResponder::answerIPv6AddressCount(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerIPv6AddressCount((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : 0); +} + +/* + MDNSResponder::answerIPv6Address +*/ +IPAddress MDNSResponder::answerIPv6Address(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + stcQuery::stcAnswer::stcIPv6Address* pIPv6Address = (pSQAnswer ? pSQAnswer->IPv6AddressAtIndex(p_u32AddressIndex) : 0); + return (pIPv6Address ? pIPv6Address->m_IPAddress : IPAddress()); +} + + /* + MDNSResponder::answerIPv6Address (LEGACY 2) + */ + IPAddress MDNSResponder::answerIPv6Address(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + return ((!m_HostList.empty()) + ? answerIPv6Address((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : IPAddress()); +} +#endif + +/* + MDNSResponder::hasAnswerPort +*/ +bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Port))); +} + + /* + MDNSResponder::hasAnswerPort (LEGACY 2) + */ + bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? hasAnswerPort((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : false); +} + +/* + MDNSResponder::answerPort +*/ +uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->m_u16Port : 0); +} + + /* + MDNSResponder::answerPort (LEGACY 2) + */ + uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerPort((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : 0); +} + +/* + MDNSResponder::hasAnswerTxts +*/ +bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Txts))); +} + + /* + MDNSResponder::hasAnswerTxts (LEGACY 2) + */ + bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? hasAnswerTxts((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : false); +} + +/* + MDNSResponder::answerTxts + + Returns all TXT items for the given service as a ';'-separated string. + If not already existing; the string is alloced, filled and attached to the answer. + +*/ +const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); + stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcTxts (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_Txts.m_pTxts) && + (!pSQAnswer->m_pcTxts)) +{ + + pSQAnswer->m_pcTxts = pSQAnswer->allocTxts(pSQAnswer->m_Txts.c_strLength()); + if (pSQAnswer->m_pcTxts) + { + pSQAnswer->m_Txts.c_str(pSQAnswer->m_pcTxts); + } + } + return (pSQAnswer ? pSQAnswer->m_pcTxts : 0); +} + +/* + MDNSResponder::answerTxts (LEGACY 2) +*/ +const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSQuery p_hMDNSQuery, + const uint32_t p_u32AnswerIndex) +{ + return ((!m_HostList.empty()) + ? answerTxts((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) + : 0); +} + + +/* + PROBING +*/ + +/* + MDNSResponder::setHostProbeResultCallback + + Set a callback for probe results. The callback is called, when probing + for the host domain failes or succeedes. + In the case of failure, the domain name should be changed via 'setHostName' + When succeeded, the host domain will be announced by the MDNS responder. + +*/ +bool MDNSResponder::setHostProbeResultCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, + MDNSResponder::MDNSHostProbeResultCallbackFn p_fnCallback) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (((clsHost*)p_hMDNSHost)->m_HostProbeInformation.m_fnProbeResultCallback = p_fnCallback, true)); +} + +/* + MDNSResponder::setHostProbeResultCallback (LEGACY 2) +*/ +bool MDNSResponder::setHostProbeResultCallback(MDNSResponder::MDNSHostProbeResultCallbackFn1 p_fnCallback) +{ + return setHostProbeResultCallback([p_fnCallback](MDNSResponder * p_pMDNSResponder, + hMDNSHost, + const char* p_pcDomainName, + bool p_bProbeResult) + { + if (p_fnCallback) + { + p_fnCallback(p_pMDNSResponder, p_pcDomainName, p_bProbeResult); + } + }); +} + +/* + MDNSResponder::setHostProbeResultCallback (LEGACY 2) +*/ +bool MDNSResponder::setHostProbeResultCallback(MDNSResponder::MDNSHostProbeResultCallbackFn2 p_fnCallback) +{ + return setHostProbeResultCallback([p_fnCallback](MDNSResponder*, + hMDNSHost, + const char* p_pcDomainName, + bool p_bProbeResult) + { + if (p_fnCallback) + { + p_fnCallback(p_pcDomainName, p_bProbeResult); + } + }); +} + +/* + MDNSResponder::setServiceProbeResultCallback + + Set a service specific callback for probe results. The callback is called, when probing + for the service domain failes or succeedes. + In the case of failure, the service name should be changed via 'setServiceName'. + When succeeded, the service domain will be announced by the MDNS responder. + +*/ +bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, + const MDNSResponder::hMDNSService p_hMDNSService, + MDNSResponder::MDNSServiceProbeResultCallbackFn p_fnCallback) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && + (((stcService*)p_hMDNSService)->m_ProbeInformation.m_fnProbeResultCallback = p_fnCallback, true)); +} + +/* + MDNSResponder::setServiceProbeResultCallback (LEGACY 2) +*/ +bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hMDNSService, + MDNSResponder::MDNSServiceProbeResultCallbackFn1 p_fnCallback) +{ + return setServiceProbeResultCallback(p_hMDNSService, [p_fnCallback](MDNSResponder * p_pMDNSResponder, + hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcServiceName, + bool p_bProbeResult) + { + if (p_fnCallback) + { + p_fnCallback(p_pMDNSResponder, p_hMDNSService, p_pcServiceName, p_bProbeResult); + } + }); +} + +/* + MDNSResponder::setServiceProbeResultCallback (LEGACY 2) +*/ +bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hMDNSService, + MDNSResponder::MDNSServiceProbeResultCallbackFn2 p_fnCallback) +{ + return setServiceProbeResultCallback(p_hMDNSService, [p_fnCallback](MDNSResponder*, + hMDNSHost, + const hMDNSService p_hMDNSService, + const char* p_pcServiceName, + bool p_bProbeResult) + { + if (p_fnCallback) + { + p_fnCallback(p_hMDNSService, p_pcServiceName, p_bProbeResult); + } + }); +} +#endif + +/* + MISC +*/ + +/* + MDNSResponder::notifyNetIfChange + + Should be called, whenever the AP for the MDNS responder changes. + A bit of this is caught by the event callbacks installed in the constructor. + +*/ +bool MDNSResponder::notifyNetIfChange(netif* p_pNetIf) +{ + clsHost* pMDNSHost; + return (((pMDNSHost = _findHost(p_pNetIf))) && + (pMDNSHost->restart())); +} + +/* + MDNSResponder::update + + Should be called in every 'loop'. + +*/ +bool MDNSResponder::update(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_NRH2Ptr(p_hMDNSHost)->update())); +} + +/* + MDNSResponder::update (convenience) +*/ +bool MDNSResponder::update(void) +{ + bool bResult = true; + for (clsHost* pMDNSHost : m_HostList) + { + if (!pMDNSHost->update()) + { + bResult = false; + } + } + return bResult; +} + +/* + MDNSResponder::announce + + Should be called, if the 'configuration' changes. Mainly this will be changes in the TXT items... +*/ +bool MDNSResponder::announce(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_NRH2Ptr(p_hMDNSHost)->announce(true, true))); +} + +/* + MDNSResponder::announce (convenience) +*/ +bool MDNSResponder::announce(void) +{ + bool bResult = true; + for (clsHost* pMDNSHost : m_HostList) + { + if (!pMDNSHost->announce(true, true)) + { + bResult = false; + } + } + return bResult; +} + +/* + MDNSResponder::enableArduino + + Enable the OTA update service. + +*/ +MDNSResponder::hMDNSService MDNSResponder::enableArduino(const MDNSResponder::hMDNSHost p_hMDNSHost, + uint16_t p_u16Port, + bool p_bAuthUpload /*= false*/) +{ + hMDNSService hService = addService(p_hMDNSHost, 0, "arduino", "tcp", p_u16Port); + if (hService) + { + if ((!addServiceTxt(p_hMDNSHost, hService, "tcp_check", "no")) || + (!addServiceTxt(p_hMDNSHost, hService, "ssh_upload", "no")) || + (!addServiceTxt(p_hMDNSHost, hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) || + (!addServiceTxt(p_hMDNSHost, hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) + { + + removeService(p_hMDNSHost, hService); + hService = 0; + } + } + return hService; +} + +#ifdef LATER + +/* + MDNSResponder::enableArduino (LEGACY 2) +*/ +MDNSResponder::hMDNSService MDNSResponder::enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload /*= false*/) +{ + hMDNSService hMDNSService = 0; + for (clsHost*& pMDNSHost : m_HostList) + { + hMDNSService hLastMDNSService = enableArduino((hMDNSHost)it, p_u16Port, p_bAuthUpload); + if ((hLastMDNSService) && + (!hMDNSService)) + { + hMDNSService = hLastMDNSService; + } + } + return hMDNSService; +} + +#endif + +} //namespace MDNSImplementation + +} //namespace esp8266 + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp new file mode 100755 index 0000000000..7c144499e4 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp @@ -0,0 +1,354 @@ +/* + LEAmDNS2_APIHelpers.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* + ESP8266mDNS Control.cpp +*/ + +extern "C" { +#include "user_interface.h" +} + +#include "LEAmDNS2_lwIPdefs.h" +#include "LEAmDNS2_Priv.h" + +namespace esp8266 +{ +/* + LEAmDNS +*/ +namespace experimental +{ + +/* + MDNSResponder::_allocUDPContext +*/ +bool MDNSResponder::_allocUDPContext(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext\n"), _DH());); + if (_releaseUDPContext()) + { + m_pUDPContext = new UdpContext; + if (m_pUDPContext) + { + m_pUDPContext->ref(); + + ip_set_option(m_pUDPContext->pcb(), SOF_REUSEADDR); + //udp_bind_netif(m_pUDPContext->pcb(), m_pNetIf); + + if (m_pUDPContext->listen(IP_ANY_TYPE, DNS_MQUERY_PORT)) + { + //m_pUDPContext->setMulticastInterface(m_pNetIf); + m_pUDPContext->setMulticastTTL(MDNS_MULTICAST_TTL); + m_pUDPContext->onRx(std::bind(&MDNSResponder::_processUDPInput, this)); + m_pUDPContext->connect(IP_ANY_TYPE, DNS_MQUERY_PORT); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: Succeeded to alloc UDPContext!\n"), _DH());); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to make UDPContext listening!\n"), _DH());); + _releaseUDPContext(); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to alloc UDPContext!\n"), _DH());); + } + } + DEBUG_EX_ERR(if (!m_pUDPContext) DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED!\n"), _DH());); + return (0 != m_pUDPContext); +} + +/* + MDNSResponder::_releaseUDPContext +*/ +bool MDNSResponder::_releaseUDPContext(void) +{ + if (m_pUDPContext) + { + m_pUDPContext->unref(); + m_pUDPContext = 0; + } + return true; +} + +/* + MDNSResponder::_processUDPInput + + Called in SYS context! + +*/ +bool MDNSResponder::_processUDPInput(void) +{ + //DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput\n"), _DH());); + + if (m_pUDPContext->next()) + { + netif* pNetIf = ip_current_input_netif(); + MDNSResponder::clsHost* pHost = 0; + if ((pNetIf) && + ((pHost = _findHost(pNetIf)))) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: netif:%u,src:%s,dest:%s\n"), _DH(), netif_get_index(pNetIf), IPAddress(ip_current_src_addr()).toString().c_str(), IPAddress(ip_current_dest_addr()).toString().c_str());); + pHost->processUDPInput(/*IPAddress(ip_current_src_addr()), IPAddress(ip_current_dest_addr())*/); + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Received UDP datagramm for unused netif at index: %u\n"), _DH(), (pNetIf ? netif_get_index(pNetIf) : (-1)));); + } + m_pUDPContext->flush(); + } + return true; +} + +/* + MDNSResponder::_createHost +*/ +MDNSResponder::clsHost* MDNSResponder::_createHost(netif* p_pNetIf) +{ + clsHost* pHost = 0; + + if ((p_pNetIf) && + (!((pHost = _findHost(p_pNetIf)))) && + (m_pUDPContext) && + ((pHost = new clsHost(*p_pNetIf, *m_pUDPContext)))) + { + if (pHost->init()) + { + //pHost->setHostProbeResultCallback(_defaultHostProbeResultCallback); + m_HostList.push_back(pHost); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: FAILED!\n"), _DH());); + _releaseHost(pHost); + pHost = 0; + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: Attaching to netif %s!\n"), _DH(), (pHost ? "succeeded" : "FAILED"));); + return pHost; +} + +/* + MDNSResponder::_releaseHost +*/ +bool MDNSResponder::_releaseHost(MDNSResponder::clsHost* p_pHost) +{ + bool bResult = false; + + if ((p_pHost) && + (m_HostList.end() != std::find(m_HostList.begin(), m_HostList.end(), p_pHost))) + { + // Delete and remove Responder object + delete p_pHost; + m_HostList.remove(p_pHost); + bResult = true; + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseHost: %s to release netif Responder!\n"), _DH(), (bResult ? "Succeeded" : "FAILED"));); + return bResult; +} + +/* + MDNSResponder::_findHost +*/ +const MDNSResponder::clsHost* MDNSResponder::_findHost(netif* p_pNetIf) const +{ + const clsHost* pResult = 0; + for (const clsHost* pHost : m_HostList) + { + if ((p_pNetIf) && + (&(pHost->m_rNetIf) == p_pNetIf)) + { + pResult = pHost; + break; + } + } + return pResult; +} + +/* + MDNSResponder::_findHost +*/ +MDNSResponder::clsHost* MDNSResponder::_findHost(netif* p_pNetIf) +{ + return (clsHost*)(((const MDNSResponder*)this)->_findHost(p_pNetIf)); +} + +/* + MDNSResponder::_findHost +*/ +const MDNSResponder::clsHost* MDNSResponder::_findHost(const MDNSResponder::hMDNSHost p_hMDNSHost) const +{ + clsHostList::const_iterator it(std::find(m_HostList.begin(), m_HostList.end(), _NRH2Ptr(p_hMDNSHost))); + return ((m_HostList.end() != it) ? *it : 0); +} + +/* + MDNSResponder::_findHost +*/ +MDNSResponder::clsHost* MDNSResponder::_findHost(const MDNSResponder::hMDNSHost p_hMDNSHost) +{ + return (clsHost*)(((const MDNSResponder*)this)->_findHost(p_hMDNSHost)); +} + + +/* + HANDLE HELPERS +*/ + +/* + MDNSResponder::_validateMDNSHostHandle +*/ +bool MDNSResponder::_validateMDNSHostHandle(const hMDNSHost p_hMDNSHost) const +{ + return (0 != _findHost(_NRH2Ptr(p_hMDNSHost))); +} + +/* + MDNSResponder::_validateMDNSHostHandle +*/ +bool MDNSResponder::_validateMDNSHostHandle(const hMDNSHost p_hMDNSHost, + const hMDNSService p_hMDNSService) const +{ + return ((_validateMDNSHostHandle(p_hMDNSHost)) && + (_NRH2Ptr(p_hMDNSHost)->validateService(_SH2Ptr(p_hMDNSService)))); +} + +/* + MDNSResponder::_NRH2Ptr +*/ +MDNSResponder::clsHost* MDNSResponder::_NRH2Ptr(const hMDNSHost p_hMDNSHost) +{ + return (clsHost*)p_hMDNSHost; +} + +/* + MDNSResponder::_NRH2Ptr +*/ +const MDNSResponder::clsHost* MDNSResponder::_NRH2Ptr(const hMDNSHost p_hMDNSHost) const +{ + return (const clsHost*)p_hMDNSHost; +} + +/* + MDNSResponder::_SH2Ptr +*/ +MDNSResponder::clsHost::stcService* MDNSResponder::_SH2Ptr(const hMDNSService p_hMDNSService) +{ + return (clsHost::stcService*)p_hMDNSService; +} + +/* + MDNSResponder::_SH2Ptr +*/ +const MDNSResponder::clsHost::stcService* MDNSResponder::_SH2Ptr(const hMDNSService p_hMDNSService) const +{ + return (const clsHost::stcService*)p_hMDNSService; +} + +/* + MDNSResponder::_begin + + Creates a new netif responder (adding the netif to the multicast groups), + sets up the instance data (hostname, ...) and starts the probing process + +*/ +MDNSResponder::clsHost* MDNSResponder::_begin(const char* p_pcHostName, + netif* p_pNetIf, + MDNSHostProbeResultCallbackFn p_fnCallback) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _begin(%s, netif: %u)\n"), _DH(), (p_pcHostName ?: "_"), (p_pNetIf ? netif_get_index(p_pNetIf) : 0));); + + clsHost* pHost = 0; + if ((!m_pUDPContext) || + (!p_pNetIf) || + (!((pHost = _createHost(p_pNetIf)))) || + (p_fnCallback ? !setHostProbeResultCallback((hMDNSHost)pHost, p_fnCallback) : false) || + (!pHost->setHostName(p_pcHostName)) || + (!pHost->restart())) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _begin: FAILED for '%s'!\n"), _DH(), (p_pcHostName ? : "-"));); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _begin: %s to init netif with hostname %s!\n"), _DH(), (pHost ? "Succeeded" : "FAILED"), (p_pcHostName ? : "-"));); + return pHost; +} + +/* + MDNSResponder::_close + + The announced host and services are unannounced (by multicasting a goodbye message) + All connected objects and finally the netif Responder is removed. + +*/ +bool MDNSResponder::_close(MDNSResponder::clsHost& p_rHost) +{ + _releaseHost(&p_rHost); // Will call 'delete' on the pHost object! + + return true; +} + + +/* + MISC +*/ + +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + +/* + MDNSResponder::_DH +*/ +const char* MDNSResponder::_DH(const hMDNSHost p_hMDNSHost /*= 0*/) const +{ + static char acBuffer[64]; + + *acBuffer = 0; + if (p_hMDNSHost) + { + sprintf_P(acBuffer, PSTR("[MDNSResponder %s]"), ((WIFI_STA == netif_get_index(&((clsHost*)p_hMDNSHost)->m_rNetIf)) + ? "STA" + : ((WIFI_AP == netif_get_index(&((clsHost*)p_hMDNSHost)->m_rNetIf)) + ? "AP" + : "??"))); + } + else + { + sprintf_P(acBuffer, PSTR("[MDNSResponder]")); + } + return acBuffer; +} + +#endif + + +} // namespace MDNSImplementation + +} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp new file mode 100755 index 0000000000..b9df26ce8f --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp @@ -0,0 +1,1336 @@ +/* + LEAmDNS2_Host.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + ESP8266mDNS Control.cpp +*/ + +extern "C" { +#include "user_interface.h" +} + +#include "LEAmDNS2_lwIPdefs.h" +#include "LEAmDNS2_Priv.h" + +#ifdef MDNS_IPV4_SUPPORT +#include +#endif +#ifdef MDNS_IPV6_SUPPORT +#include +#endif + + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace experimental +{ + +/* + MDNSResponder::clsHost::clsHost constructor +*/ +MDNSResponder::clsHost::clsHost(netif& p_rNetIf, + UdpContext& p_rUDPContext) + : m_rNetIf(p_rNetIf), + m_NetIfState(static_cast(enuNetIfState::None)), + m_rUDPContext(p_rUDPContext), + m_pcHostName(0), + m_pcInstanceName(0), + m_pServices(0), + m_pQueries(0), + m_fnServiceTxtCallback(0), + m_HostProbeInformation() +{ +} + +/* + MDNSResponder::clsHost::~clsHost destructor +*/ +MDNSResponder::clsHost::~clsHost(void) +{ + _close(); +} + +/* + MDNSResponder::clsHost::init +*/ +bool MDNSResponder::clsHost::init(void) +{ + bool bResult = true; + + // Join multicast group(s) +#ifdef MDNS_IPV4_SUPPORT + ip_addr_t multicast_addr_V4 = DNS_MQUERY_IPV4_GROUP_INIT; + if (!(m_rNetIf.flags & NETIF_FLAG_IGMP)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: Setting flag: flags & NETIF_FLAG_IGMP\n"), _DH());); + m_rNetIf.flags |= NETIF_FLAG_IGMP; + + if (ERR_OK != igmp_start(&m_rNetIf)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: igmp_start FAILED!\n"), _DH());); + } + } + + bResult = ((bResult) && + (ERR_OK == igmp_joingroup_netif(&m_rNetIf, ip_2_ip4(&multicast_addr_V4)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: igmp_joingroup_netif(%s) FAILED!\n"), _DH(), IPAddress(multicast_addr_V4).toString().c_str());); +#endif + +#ifdef MDNS_IPV6_SUPPORT + ip_addr_t multicast_addr_V6 = DNS_MQUERY_IPV6_GROUP_INIT; + bResult = ((bResult) && + (ERR_OK == mld6_joingroup_netif(&m_rNetIf, ip_2_ip6(&multicast_addr_V6)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: mld6_joingroup_netif FAILED!\n"), _DH());); +#endif + return bResult; +} + +/* + MDNSResponder::clsHost::setHostName +*/ +bool MDNSResponder::clsHost::setHostName(const char* p_pcHostName) +{ + bool bResult; + if ((bResult = _allocHostName(p_pcHostName))) + { + m_HostProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart; + + // Replace 'auto-set' service names + for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if ((pService->m_bAutoName) && + (!m_pcInstanceName)) + { + bResult = pService->setName(p_pcHostName); + pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart; + } + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::setHostName +*/ +const char* MDNSResponder::clsHost::hostName(void) const +{ + return m_pcHostName; +} + +/* + MDNSResponder::clsHost::setHostProbeResultCallback +*/ +bool MDNSResponder::clsHost::setHostProbeResultCallback(HostProbeResultCallbackFn p_fnCallback) +{ + m_HostProbeInformation.m_fnProbeResultCallback = p_fnCallback; + return true; +} + +/* + MDNSResponder::clsHost::probeStatus +*/ +bool MDNSResponder::clsHost::probeStatus(void) const +{ + return (enuProbingStatus::Done == m_HostProbeInformation.m_ProbingStatus); +} + + +/* + SERVICE +*/ + +/* + MDNSResponder::clsHost::setInstanceName +*/ +bool MDNSResponder::clsHost::setInstanceName(const char* p_pcInstanceName) +{ + bool bResult; + if ((bResult = _allocInstanceName(p_pcInstanceName))) + { + // Replace 'auto-set' service names + for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if (pService->m_bAutoName) + { + bResult = pService->setName(p_pcInstanceName); + pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart; + } + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::instanceName +*/ +const char* MDNSResponder::clsHost::instanceName(void) const +{ + return m_pcInstanceName; +} + +/* + MDNSResponder::clsHost::addService +*/ +MDNSResponder::clsHost::stcService* MDNSResponder::clsHost::addService(const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + stcService* pService = 0; + + if (((!p_pcInstanceName) || // NO name OR + (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcInstanceName))) && // Fitting name + (p_pcServiceType) && + (MDNS_SERVICE_NAME_LENGTH >= os_strlen(p_pcServiceType)) && + (p_pcProtocol) && + ((MDNS_SERVICE_PROTOCOL_LENGTH - 1) != os_strlen(p_pcProtocol)) && + (p_u16Port)) + { + if (!((pService = findService((p_pcInstanceName ? : (m_pcInstanceName ? : m_pcHostName)), p_pcServiceType, p_pcProtocol, p_u16Port)))) // Not already used + { + if (0 != (pService = _allocService(p_pcInstanceName, p_pcServiceType, p_pcProtocol, p_u16Port))) + { + // Init probing + pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart; + } + } + } // else: bad arguments + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s addService: %s to add service '%s.%s.%s.local'!\n"), _DH(pService), (pService ? "Succeeded" : "FAILED"), (p_pcInstanceName ? : (m_pcInstanceName ? : (m_pcHostName ? : "-"))), (p_pcServiceType ? : ""), (p_pcProtocol ? : ""));); + DEBUG_EX_ERR(if (!pService) DEBUG_OUTPUT.printf_P(PSTR("%s addService: FAILED to add service '%s.%s.%s.local'!\n"), _DH(pService), (p_pcInstanceName ? : (m_pcInstanceName ? : (m_pcHostName ? : "-"))), (p_pcServiceType ? : ""), (p_pcProtocol ? : ""));); + return pService; +} + +/* + MDNSResponder::clsHost::removeService +*/ +bool MDNSResponder::clsHost::removeService(MDNSResponder::clsHost::stcService* p_pMDNSService) +{ + bool bResult = ((p_pMDNSService) && + (_announceService(*p_pMDNSService, false)) && + (_releaseService(p_pMDNSService))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _removeService: FAILED!\n"), _DH(p_pMDNSService));); + return bResult; +} + +/* + MDNSResponder::clsHost::findService (const) +*/ +const MDNSResponder::clsHost::stcService* MDNSResponder::clsHost::findService(const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port /*= 0*/) const +{ + stcService* pService = m_pServices; + while (pService) + { + if ((0 == strcmp(pService->m_pcName, p_pcInstanceName)) && + (0 == strcmp(pService->m_pcServiceType, p_pcServiceType)) && + (0 == strcmp(pService->m_pcProtocol, p_pcProtocol)) && + ((!p_u16Port) || + (p_u16Port == pService->m_u16Port))) + { + + break; + } + pService = pService->m_pNext; + } + return pService; +} + +/* + MDNSResponder::clsHost::findService +*/ +MDNSResponder::clsHost::stcService* MDNSResponder::clsHost::findService(const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port /*= 0*/) +{ + return (stcService*)((const clsHost*)this)->findService(p_pcInstanceName, p_pcServiceType, p_pcProtocol, p_u16Port); +} + +/* + MDNSResponder::clsHost::validateService +*/ +bool MDNSResponder::clsHost::validateService(const MDNSResponder::clsHost::stcService* p_pService) const +{ + const stcService* pService = m_pServices; + while (pService) + { + if (pService == p_pService) + { + break; + } + pService = pService->m_pNext; + } + return (0 != pService); +} + +/* + MDNSResponder::clsHost::setServiceName +*/ +bool MDNSResponder::clsHost::setServiceName(MDNSResponder::clsHost::stcService* p_pMDNSService, + const char* p_pcInstanceName) +{ + p_pcInstanceName = p_pcInstanceName ? : m_pcInstanceName; + + bool bResult = ((p_pMDNSService) && + ((!p_pcInstanceName) || + (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcInstanceName))) && + (p_pMDNSService->setName(p_pcInstanceName)) && + ((p_pMDNSService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart), true)); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _setServiceName: FAILED for '%s'!\n"), _DH(p_pMDNSService), (p_pcInstanceName ? : "-"));); + return bResult; +} + +/* + MDNSResponder::clsHost::setServiceName +*/ +const char* MDNSResponder::clsHost::serviceName(const stcService* p_pMDNSService) const +{ + return ((p_pMDNSService) + ? (p_pMDNSService->m_pcName) + : 0); +} + +/* + MDNSResponder::clsHost::serviceType +*/ +const char* MDNSResponder::clsHost::serviceType(const stcService* p_pMDNSService) const +{ + return ((p_pMDNSService) + ? (p_pMDNSService->m_pcServiceType) + : 0); +} + +/* + MDNSResponder::clsHost::serviceProtocol +*/ +const char* MDNSResponder::clsHost::serviceProtocol(const stcService* p_pMDNSService) const +{ + return ((p_pMDNSService) + ? (p_pMDNSService->m_pcProtocol) + : 0); +} + +/* + MDNSResponder::clsHost::servicePort +*/ +uint16_t MDNSResponder::clsHost::servicePort(const stcService* p_pMDNSService) const +{ + return ((p_pMDNSService) + ? (p_pMDNSService->m_u16Port) + : 0); +} + + +/* + MDNSResponder::clsHost::setServiceProbeResultCallback +*/ +bool MDNSResponder::clsHost::setServiceProbeResultCallback(stcService* p_pMDNSService, + ServiceProbeResultCallbackFn p_fnCallback) +{ + return ((p_pMDNSService) + ? ((p_pMDNSService->m_ProbeInformation.m_fnProbeResultCallback = p_fnCallback), true) + : false); +} + +/* + MDNSResponder::clsHost::setServiceName +*/ +bool MDNSResponder::clsHost::serviceProbeStatus(const stcService* p_pMDNSService) const +{ + return ((p_pMDNSService) && + (enuProbingStatus::Done == p_pMDNSService->m_ProbeInformation.m_ProbingStatus)); +} + + +/* + SERVICE TXT +*/ + +/* + MDNSResponder::clsHost::addServiceTxt +*/ +MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::addServiceTxt(stcService* p_pMDNSService, + const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_pMDNSService, p_pcKey, p_pcValue, false); +} + +/* + MDNSResponder::clsHost::removeServiceTxt +*/ +bool MDNSResponder::clsHost::removeServiceTxt(stcService* p_pMDNSService, + stcServiceTxt* p_pTxt) +{ + bool bResult = ((p_pMDNSService) && + (p_pTxt) && + (_releaseServiceTxt(p_pMDNSService, p_pTxt))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH(p_pMDNSService));); + return bResult; +} + +/* + MDNSResponder::clsHost::findServiceTxt (const) +*/ +const MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::findServiceTxt(MDNSResponder::clsHost::stcService* p_pMDNSService, + const char* p_pcKey) const +{ + return (const stcServiceTxt*)((const clsHost*)this)->findServiceTxt(p_pMDNSService, p_pcKey); +} + +/* + MDNSResponder::clsHost::findServiceTxt +*/ +MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::findServiceTxt(MDNSResponder::clsHost::stcService* p_pMDNSService, + const char* p_pcKey) +{ + return _findServiceTxt(p_pMDNSService, p_pcKey); +} + +/* + MDNSResponder::clsHost::setDynamicServiceTxtCallback +*/ +bool MDNSResponder::clsHost::setDynamicServiceTxtCallback(DynamicServiceTxtCallbackFn p_fnCallback) +{ + m_fnServiceTxtCallback = p_fnCallback; + return true; +} + +/* + MDNSResponder::clsHost::setDynamicServiceTxtCallback +*/ +bool MDNSResponder::clsHost::setDynamicServiceTxtCallback(stcService* p_pMDNSService, + DynamicServiceTxtCallbackFn p_fnCallback) +{ + return ((p_pMDNSService) + ? ((p_pMDNSService->m_fnTxtCallback = p_fnCallback), true) + : false); +} + +/* + MDNSResponder::clsHost::addDynamicServiceTxt + + Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + Dynamic TXT items are removed right after one-time use. So they need to be added + every time the value s needed (via callback). +*/ +MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::addDynamicServiceTxt(stcService* p_pMDNSService, + const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_pMDNSService, p_pcKey, p_pcValue, true); +} + + +/* + QUERIES +*/ +/* + MDNSResponder::clsHost::queryService +*/ +uint32_t MDNSResponder::clsHost::queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local'\n"), _DH(), p_pcService, p_pcProtocol);); + + stcQuery* pMDNSQuery = 0; + if ((p_pcService) && (*p_pcService) && + (p_pcProtocol) && (*p_pcProtocol) && + (p_u16Timeout) && + ((pMDNSQuery = _allocQuery(stcQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) + { + if ((_removeLegacyQuery()) && + ((pMDNSQuery->m_bLegacyQuery = true)) && + (_sendMDNSQuery(*pMDNSQuery))) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + pMDNSQuery->m_bAwaitingAnswers = false; + } + else // FAILED to send query + { + _removeQuery(pMDNSQuery); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: INVALID input data!\n"), _DH());); + } + return ((pMDNSQuery) + ? pMDNSQuery->answerCount() + : 0); +} + +/* + MDNSResponder::clsHost::queryHost +*/ +uint32_t MDNSResponder::clsHost::queryHost(const char* p_pcHostName, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local'\n"), _DH(), p_pcHostName);); + + stcQuery* pMDNSQuery = 0; + if ((p_pcHostName) && (*p_pcHostName) && + (p_u16Timeout) && + ((pMDNSQuery = _allocQuery(stcQuery::enuQueryType::Host))) && + (_buildDomainForHost(p_pcHostName, pMDNSQuery->m_Domain))) + { + if ((_removeLegacyQuery()) && + ((pMDNSQuery->m_bLegacyQuery = true)) && + (_sendMDNSQuery(*pMDNSQuery))) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + pMDNSQuery->m_bAwaitingAnswers = false; + } + else // FAILED to send query + { + _removeQuery(pMDNSQuery); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: INVALID input data!\n"), _DH());); + } + return ((pMDNSQuery) + ? pMDNSQuery->answerCount() + : 0); +} + +/* + MDNSResponder::clsHost::removeQuery +*/ +bool MDNSResponder::clsHost::removeQuery(void) +{ + return _removeLegacyQuery(); +} + +/* + MDNSResponder::clsHost::hasQuery +*/ +bool MDNSResponder::clsHost::hasQuery(void) +{ + return (0 != _findLegacyQuery()); +} + +/* + MDNSResponder::clsHost::getQuery +*/ +MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::getQuery(void) +{ + return _findLegacyQuery(); +} + +/* + MDNSResponder::clsHost::installServiceQuery +*/ +MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSResponder::clsHost::QueryCallbackFn p_fnCallback) +{ + stcQuery* pMDNSQuery = 0; + if ((p_pcService) && (*p_pcService) && + (p_pcProtocol) && (*p_pcProtocol) && + (p_fnCallback) && + ((pMDNSQuery = _allocQuery(stcQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) + { + + pMDNSQuery->m_fnCallback = p_fnCallback; + pMDNSQuery->m_bLegacyQuery = false; + + if (_sendMDNSQuery(*pMDNSQuery)) + { + pMDNSQuery->m_u8SentCount = 1; + pMDNSQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); + } + else + { + _removeQuery(pMDNSQuery); + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: %s for '_%s._%s.local'!\n\n"), _DH(), (pMDNSQuery ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + DEBUG_EX_ERR(if (!pMDNSQuery) DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: FAILED for '_%s._%s.local'!\n\n"), _DH(), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + return pMDNSQuery; +} + +/* + MDNSResponder::clsHost::installHostQuery +*/ +MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::installHostQuery(const char* p_pcHostName, + MDNSResponder::clsHost::QueryCallbackFn p_fnCallback) +{ + stcQuery* pMDNSQuery = 0; + if ((p_pcHostName) && (*p_pcHostName)) + { + stcRRDomain domain; + pMDNSQuery = ((_buildDomainForHost(p_pcHostName, domain)) + ? _installDomainQuery(domain, stcQuery::enuQueryType::Host, p_fnCallback) + : 0); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: %s for '%s.local'!\n\n"), _DH(), (pMDNSQuery ? "Succeeded" : "FAILED"), (p_pcHostName ? : "-"));); + DEBUG_EX_ERR(if (!pMDNSQuery) DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: FAILED for '%s.local'!\n\n"), _DH(), (p_pcHostName ? : "-"));); + return pMDNSQuery; +} + +/* + MDNSResponder::clsHost::removeQuery +*/ +bool MDNSResponder::clsHost::removeQuery(MDNSResponder::clsHost::stcQuery* p_pMDNSQuery) +{ + bool bResult = ((p_pMDNSQuery) && + (_removeQuery(p_pMDNSQuery))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeQuery: FAILED!\n"), _DH());); + return bResult; +} + + +/* + PROCESSING +*/ + +/* + MDNSResponder::clsHost::processUDPInput +*/ +bool MDNSResponder::clsHost::processUDPInput() +{ + bool bResult = false; + + bResult = ((_checkNetIfState()) && // Any changes in the netif state? + (_parseMessage())); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR(""));); + + return bResult; +} + +/* + MDNSResponder::clsHost::update +*/ +bool MDNSResponder::clsHost::update(void) +{ + return ((_checkNetIfState()) && // Any changes in the netif state? + (_updateProbeStatus()) && // Probing + (_checkQueryCache())); +} + +/* + MDNSResponder::clsHost::restart +*/ +bool MDNSResponder::clsHost::restart(void) +{ + return (_resetProbeStatus(true)); // Stop and restart probing +} + + + + + +/* + P R O T E C T E D +*/ + +/* + MDNSResponder::clsHost::_close +*/ +bool MDNSResponder::clsHost::_close(void) +{ + /* _resetProbeStatus(false); // Stop probing + + _releaseQueries(); + _releaseServices(); + _releaseHostName();*/ + + // Leave multicast group(s) +#ifdef MDNS_IPV4_SUPPORT + ip_addr_t multicast_addr_V4 = DNS_MQUERY_IPV4_GROUP_INIT; + if (ERR_OK != igmp_leavegroup_netif(&m_rNetIf, ip_2_ip4(&multicast_addr_V4)/*(const struct ip4_addr *)&multicast_addr_V4.u_addr.ip4*/)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("\n"));); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + ip_addr_t multicast_addr_V6 = DNS_MQUERY_IPV6_GROUP_INIT; + if (ERR_OK != mld6_leavegroup_netif(&m_rNetIf, ip_2_ip6(&multicast_addr_V6)/*&(multicast_addr_V6.u_addr.ip6)*/)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("\n"));); + } +#endif + return true; +} + + +/* + NETIF +*/ + +/* + MDNSResponder::clsHost::_getNetIfState + + Returns the current netif state. + +*/ +MDNSResponder::clsHost::typeNetIfState MDNSResponder::clsHost::_getNetIfState(void) const +{ + typeNetIfState curNetIfState = static_cast(enuNetIfState::None); + + if (netif_is_up(&m_rNetIf)) + { + curNetIfState |= static_cast(enuNetIfState::IsUp); + + // Check if netif link is up + if ((netif_is_link_up(&m_rNetIf)) && + ((&m_rNetIf != netif_get_by_index(WIFI_STA)) || + (STATION_GOT_IP == wifi_station_get_connect_status()))) + { + curNetIfState |= static_cast(enuNetIfState::LinkIsUp); + } + + // Check for IPv4 address + if (_getResponderIPAddress(enuIPProtocolType::V4).isSet()) + { + curNetIfState |= static_cast(enuNetIfState::IPv4); + } + // Check for IPv6 address + if (_getResponderIPAddress(enuIPProtocolType::V6).isSet()) + { + curNetIfState |= static_cast(enuNetIfState::IPv6); + } + } + return curNetIfState; +} + +/* + MDNSResponder::clsHost::_checkNetIfState + + Checks the netif state. + If eg. a new address appears, the announcing is restarted. + +*/ +bool MDNSResponder::clsHost::_checkNetIfState(void) +{ + typeNetIfState curNetIfState; + if (m_NetIfState != ((curNetIfState = _getNetIfState()))) + { + // Some state change happened + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: DID CHANGE NETIF STATE\n\n"), _DH());); + DEBUG_EX_INFO( + if ((curNetIfState & static_cast(enuNetIfState::IsUp)) != (m_NetIfState & static_cast(enuNetIfState::IsUp))) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Netif is up: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::IsUp)) ? "YES" : "NO")); + } + if ((curNetIfState & static_cast(enuNetIfState::LinkIsUp)) != (m_NetIfState & static_cast(enuNetIfState::LinkIsUp))) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Netif link is up: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::LinkIsUp)) ? "YES" : "NO")); + } + if ((curNetIfState & static_cast(enuNetIfState::IPv4)) != (m_NetIfState & static_cast(enuNetIfState::IPv4))) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv4 address is set: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::IPv4)) ? "YES" : "NO")); + if (curNetIfState & static_cast(enuNetIfState::IPv4)) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv4 address: %s\n"), _DH(), _getResponderIPAddress(enuIPProtocolType::V4).toString().c_str()); + } + } + if ((curNetIfState & static_cast(enuNetIfState::IPv6)) != (m_NetIfState & static_cast(enuNetIfState::IPv6))) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv6 address is set: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::IPv6)) ? "YES" : "NO")); + if (curNetIfState & static_cast(enuNetIfState::IPv6)) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv6 address: %s\n"), _DH(), _getResponderIPAddress(enuIPProtocolType::V6).toString().c_str()); + } + } + ); + + if ((curNetIfState & static_cast(enuNetIfState::LinkMask)) != (m_NetIfState & static_cast(enuNetIfState::LinkMask))) + { + // Link came up (restart() will alloc a m_pUDPContext, ...) or down (_restart() will remove an existing m_pUDPContext, ...) + restart(); + } + else if (curNetIfState & static_cast(enuNetIfState::LinkIsUp)) + { + // Link is up (unchanged) + if ((curNetIfState & static_cast(enuNetIfState::IPMask)) != (m_NetIfState & static_cast(enuNetIfState::IPMask))) + { + // IP state changed + // TODO: If just a new IP address was added, a simple re-announcement should be enough + restart(); + } + } + /* if (enuProbingStatus::Done == m_HostProbeInformation.m_ProbingStatus) { + // Probing is done, prepare to (re)announce host + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Preparing to (re)announce host.\n"));); + //m_HostProbeInformation.m_ProbingStatus = enuProbingStatus::Done; + m_HostProbeInformation.m_u8SentCount = 0; + m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + }*/ + m_NetIfState = curNetIfState; + } + + bool bResult = ((curNetIfState & static_cast(enuNetIfState::LinkMask)) && // Continue if Link is UP + (curNetIfState & static_cast(enuNetIfState::IPMask))); // AND has any IP + //DEBUG_EX_INFO(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Link is DOWN or NO IP address!\n"), _DH());); + return bResult; +} + + +/* + DOMAIN NAMES +*/ + +/* + MDNSResponder::clsHost::_allocDomainName +*/ +bool MDNSResponder::clsHost::_allocDomainName(const char* p_pcNewDomainName, + char*& p_rpcDomainName) +{ + bool bResult = false; + + _releaseDomainName(p_rpcDomainName); + + size_t stLength = 0; + if ((p_pcNewDomainName) && + (MDNS_DOMAIN_LABEL_MAXLENGTH >= (stLength = strlen(p_pcNewDomainName)))) // char max size for a single label + { + // Copy in hostname characters as lowercase + if ((bResult = (0 != (p_rpcDomainName = new char[stLength + 1])))) + { +#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME + size_t i = 0; + for (; i < stLength; ++i) + { + p_rpcDomainName[i] = (isupper(p_pcNewDomainName[i]) ? tolower(p_pcNewDomainName[i]) : p_pcNewDomainName[i]); + } + p_rpcDomainName[i] = 0; +#else + strncpy(p_rpcDomainName, p_pcNewDomainName, (stLength + 1)); +#endif + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::_releaseDomainName +*/ +bool MDNSResponder::clsHost::_releaseDomainName(char*& p_rpcDomainName) +{ + bool bResult; + if ((bResult = (0 != p_rpcDomainName))) + { + delete[] p_rpcDomainName; + p_rpcDomainName = 0; + } + return bResult; +} + +/* + MDNSResponder::clsHost::_allocHostName +*/ +bool MDNSResponder::clsHost::_allocHostName(const char* p_pcHostName) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocHostName (%s)\n"), _DH(), p_pcHostName);); + return _allocDomainName(p_pcHostName, m_pcHostName); +} + +/* + MDNSResponder::clsHost::_releaseHostName +*/ +bool MDNSResponder::clsHost::_releaseHostName(void) +{ + return _releaseDomainName(m_pcHostName); +} + +/* + MDNSResponder::clsHost::_allocInstanceName +*/ +bool MDNSResponder::clsHost::_allocInstanceName(const char* p_pcInstanceName) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocInstanceName (%s)\n"), _DH(), p_pcHostName);); + return _allocDomainName(p_pcInstanceName, m_pcInstanceName); +} + +/* + MDNSResponder::clsHost::_releaseInstanceName +*/ +bool MDNSResponder::clsHost::_releaseInstanceName(void) +{ + return _releaseDomainName(m_pcInstanceName); +} + + +/* + SERVICE +*/ + +/* + MDNSResponder::clsHost::_allocService +*/ +MDNSResponder::clsHost::stcService* MDNSResponder::clsHost::_allocService(const char* p_pcName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + stcService* pService = 0; + if (((!p_pcName) || + (MDNS_DOMAIN_LABEL_MAXLENGTH >= strlen(p_pcName))) && + (p_pcServiceType) && + (MDNS_SERVICE_NAME_LENGTH >= strlen(p_pcServiceType)) && + (p_pcProtocol) && + (MDNS_SERVICE_PROTOCOL_LENGTH >= strlen(p_pcProtocol)) && + (p_u16Port) && + (0 != ((pService = new stcService))) && + (pService->setName(p_pcName ? : (m_pcInstanceName ? : m_pcHostName))) && + (pService->setServiceType(p_pcServiceType)) && + (pService->setProtocol(p_pcProtocol))) + { + pService->m_bAutoName = (0 == p_pcName); + pService->m_u16Port = p_u16Port; + + // Add to list (or start list) + pService->m_pNext = m_pServices; + m_pServices = pService; + } + return pService; +} + +/* + MDNSResponder::clsHost::_releaseService +*/ +bool MDNSResponder::clsHost::_releaseService(MDNSResponder::clsHost::stcService* p_pService) +{ + bool bResult = false; + + if (p_pService) + { + stcService* pPred = m_pServices; + while ((pPred) && + (pPred->m_pNext != p_pService)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pService->m_pNext; + delete p_pService; + bResult = true; + } + else // No predecesor + { + if (m_pServices == p_pService) + { + m_pServices = p_pService->m_pNext; + delete p_pService; + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseService: INVALID service!"), _DH(p_pService));); + } + } + } + return bResult; +} + + +/* + SERVICE TXT +*/ + +/* + MDNSResponder::clsHost::_allocServiceTxt +*/ +MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_allocServiceTxt(MDNSResponder::clsHost::stcService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp) +{ + stcServiceTxt* pTxt = 0; + + if ((p_pService) && + (p_pcKey) && + (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() + + 1 + // Length byte + (p_pcKey ? strlen(p_pcKey) : 0) + + 1 + // '=' + (p_pcValue ? strlen(p_pcValue) : 0)))) + { + + pTxt = new stcServiceTxt; + if (pTxt) + { + size_t stLength = (p_pcKey ? strlen(p_pcKey) : 0); + pTxt->m_pcKey = new char[stLength + 1]; + if (pTxt->m_pcKey) + { + strncpy(pTxt->m_pcKey, p_pcKey, stLength); pTxt->m_pcKey[stLength] = 0; + } + + if (p_pcValue) + { + stLength = (p_pcValue ? strlen(p_pcValue) : 0); + pTxt->m_pcValue = new char[stLength + 1]; + if (pTxt->m_pcValue) + { + strncpy(pTxt->m_pcValue, p_pcValue, stLength); pTxt->m_pcValue[stLength] = 0; + } + } + pTxt->m_bTemp = p_bTemp; + + // Add to list (or start list) + p_pService->m_Txts.add(pTxt); + } + } + return pTxt; +} + +/* + MDNSResponder::clsHost::_releaseServiceTxt +*/ +bool MDNSResponder::clsHost::_releaseServiceTxt(MDNSResponder::clsHost::stcService* p_pService, + MDNSResponder::clsHost::stcServiceTxt* p_pTxt) +{ + return ((p_pService) && + (p_pTxt) && + (p_pService->m_Txts.remove(p_pTxt))); +} + +/* + MDNSResponder::clsHost::_updateServiceTxt +*/ +MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_updateServiceTxt(MDNSResponder::clsHost::stcService* p_pService, + MDNSResponder::clsHost::stcServiceTxt* p_pTxt, + const char* p_pcValue, + bool p_bTemp) +{ + if ((p_pService) && + (p_pTxt) && + (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() - + (p_pTxt->m_pcValue ? strlen(p_pTxt->m_pcValue) : 0) + + (p_pcValue ? strlen(p_pcValue) : 0)))) + { + p_pTxt->update(p_pcValue); + p_pTxt->m_bTemp = p_bTemp; + } + return p_pTxt; +} + +/* + MDNSResponder::clsHost::_findServiceTxt +*/ +MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_findServiceTxt(MDNSResponder::clsHost::stcService* p_pService, + const char* p_pcKey) +{ + return (p_pService ? p_pService->m_Txts.find(p_pcKey) : 0); +} + +/* + MDNSResponder::clsHost::_addServiceTxt +*/ +MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_addServiceTxt(MDNSResponder::clsHost::stcService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp) +{ + stcServiceTxt* pResult = 0; + + if ((p_pService) && + (p_pcKey) && + (strlen(p_pcKey))) + { + + stcServiceTxt* pTxt = p_pService->m_Txts.find(p_pcKey); + if (pTxt) + { + pResult = _updateServiceTxt(p_pService, pTxt, p_pcValue, p_bTemp); + } + else + { + pResult = _allocServiceTxt(p_pService, p_pcKey, p_pcValue, p_bTemp); + } + } + return pResult; +} + +/* + MDNSResponder::clsHost::_answerKeyValue + / + MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_answerKeyValue(const MDNSResponder::clsHost::stcQuery p_pQuery, + const uint32_t p_u32AnswerIndex) + { + stcQuery::stcAnswer* pSQAnswer = (p_pQuery ? p_pQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcTxts (if not already done) + return (pSQAnswer) ? pSQAnswer->m_Txts.m_pTxts : 0; + }*/ + +/* + MDNSResponder::clsHost::_collectServiceTxts +*/ +bool MDNSResponder::clsHost::_collectServiceTxts(MDNSResponder::clsHost::stcService& p_rService) +{ + if (m_fnServiceTxtCallback) + { + //m_fnServiceTxtCallback(*this, p_pService); + } + if (p_rService.m_fnTxtCallback) + { + //p_pService->m_fnTxtCallback(*this, p_pService); + } + return true; +} + +/* + MDNSResponder::clsHost::_releaseTempServiceTxts +*/ +bool MDNSResponder::clsHost::_releaseTempServiceTxts(MDNSResponder::clsHost::stcService& p_rService) +{ + return (p_rService.m_Txts.removeTempTxts()); +} + + +/* + QUERIES +*/ + +/* + MDNSResponder::_allocQuery +*/ +MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::_allocQuery(MDNSResponder::clsHost::stcQuery::enuQueryType p_QueryType) +{ + stcQuery* pQuery = new stcQuery(p_QueryType); + if (pQuery) + { + // Link to query list + pQuery->m_pNext = m_pQueries; + m_pQueries = pQuery; + } + return m_pQueries; +} + +/* + MDNSResponder:clsHost:::_removeQuery +*/ +bool MDNSResponder::clsHost::_removeQuery(MDNSResponder::clsHost::stcQuery* p_pQuery) +{ + bool bResult = false; + + if (p_pQuery) + { + stcQuery* pPred = m_pQueries; + while ((pPred) && + (pPred->m_pNext != p_pQuery)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pQuery->m_pNext; + delete p_pQuery; + bResult = true; + } + else // No predecesor + { + if (m_pQueries == p_pQuery) + { + m_pQueries = p_pQuery->m_pNext; + delete p_pQuery; + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseQuery: INVALID query!"), _DH());); + } + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::_removeLegacyQuery +*/ +bool MDNSResponder::clsHost::_removeLegacyQuery(void) +{ + stcQuery* pLegacyQuery = 0; + return (((pLegacyQuery = _findLegacyQuery())) + ? _removeQuery(pLegacyQuery) + : false); +} + +/* + MDNSResponder::clsHost::_findLegacyQuery +*/ +MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::_findLegacyQuery(void) +{ + stcQuery* pLegacyQuery = m_pQueries; + while (pLegacyQuery) + { + if (pLegacyQuery->m_bLegacyQuery) + { + break; + } + pLegacyQuery = pLegacyQuery->m_pNext; + } + return pLegacyQuery; +} + +/* + MDNSResponder::clsHost::_releaseQueries +*/ +bool MDNSResponder::clsHost::_releaseQueries(void) +{ + while (m_pQueries) + { + stcQuery* pNext = m_pQueries->m_pNext; + delete m_pQueries; + m_pQueries = pNext; + } + return true; +} + +/* + MDNSResponder::clsHost::_findNextQueryByDomain +*/ +MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::_findNextQueryByDomain(const MDNSResponder::clsHost::stcRRDomain& p_Domain, + const MDNSResponder::clsHost::stcQuery::enuQueryType p_QueryType, + const stcQuery* p_pPrevQuery) +{ + stcQuery* pMatchingQuery = 0; + + stcQuery* pQuery = (p_pPrevQuery ? p_pPrevQuery->m_pNext : m_pQueries); + while (pQuery) + { + if (((stcQuery::enuQueryType::None == p_QueryType) || + (pQuery->m_QueryType == p_QueryType)) && + (p_Domain == pQuery->m_Domain)) + { + + pMatchingQuery = pQuery; + break; + } + pQuery = pQuery->m_pNext; + } + return pMatchingQuery; +} + +/* + MDNSResponder::clsHost::_installDomainQuery +*/ +MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::_installDomainQuery(MDNSResponder::clsHost::stcRRDomain& p_Domain, + MDNSResponder::clsHost::stcQuery::enuQueryType p_QueryType, + MDNSResponder::clsHost::QueryCallbackFn p_fnCallback) +{ + stcQuery* pQuery = 0; + + if ((p_fnCallback) && + ((pQuery = _allocQuery(p_QueryType)))) + { + pQuery->m_Domain = p_Domain; + pQuery->m_fnCallback = p_fnCallback; + pQuery->m_bLegacyQuery = false; + + if (_sendMDNSQuery(*pQuery)) + { + pQuery->m_u8SentCount = 1; + pQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); + } + else + { + _removeQuery(pQuery); + } + } + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _installDomainQuery: %s for "), (pQuery ? "Succeeded" : "FAILED"), _DH()); + _printRRDomain(p_Domain); + DEBUG_OUTPUT.println(); + ); + DEBUG_EX_ERR( + if (!pQuery) +{ + DEBUG_OUTPUT.printf_P(PSTR("%s _installDomainQuery: FAILED for "), _DH()); + _printRRDomain(p_Domain); + DEBUG_OUTPUT.println(); + } + ); + return pQuery; +} + +/* + MDNSResponder::clsHost::_hasQueriesWaitingForAnswers +*/ +bool MDNSResponder::clsHost::_hasQueriesWaitingForAnswers(void) const +{ + bool bOpenQueries = false; + + for (stcQuery* pQuery = m_pQueries; pQuery; pQuery = pQuery->m_pNext) + { + if (pQuery->m_bAwaitingAnswers) + { + bOpenQueries = true; + break; + } + } + return bOpenQueries; +} + +/* + MDNSResponder::clsHost::_executeQueryCallback +*/ +bool MDNSResponder::clsHost::_executeQueryCallback(const stcQuery& p_Query, + const stcQuery::stcAnswer& p_Answer, + typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_bSetContent) +{ + if (p_Query.m_fnCallback) + { + p_Query.m_fnCallback(*this, p_Query, p_Answer, p_QueryAnswerTypeFlags, p_bSetContent); + } + return true; +} + + + +} // namespace MDNSImplementation + +} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp new file mode 100755 index 0000000000..4a5ff6f39d --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp @@ -0,0 +1,1177 @@ +/* + LEAmDNS2_Host.hpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +/** + clsHost & clsHostList +*/ +class clsHost +{ +public: + + // File: ..._Host_Structs + /** + typeIPProtocolType & enuIPProtocolType + */ + using typeIPProtocolType = uint8_t; + enum class enuIPProtocolType : typeIPProtocolType + { +#ifdef MDNS_IPV4_SUPPORT + V4 = 0x01, +#endif +#ifdef MDNS_IPV6_SUPPORT + V6 = 0x02, +#endif + }; + + /** + typeNetIfState & enuNetIfState + */ + using typeNetIfState = uint8_t; + enum class enuNetIfState : typeNetIfState + { + None = 0x00, + + IsUp = 0x01, + UpMask = (IsUp), + + LinkIsUp = 0x02, + LinkMask = (LinkIsUp), + + IPv4 = 0x04, + IPv6 = 0x08, + IPMask = (IPv4 | IPv6), + }; + + /** + stcServiceTxt + */ + struct stcServiceTxt + { + stcServiceTxt* m_pNext; + char* m_pcKey; + char* m_pcValue; + bool m_bTemp; + + stcServiceTxt(const char* p_pcKey = 0, + const char* p_pcValue = 0, + bool p_bTemp = false); + stcServiceTxt(const stcServiceTxt& p_Other); + ~stcServiceTxt(void); + + stcServiceTxt& operator=(const stcServiceTxt& p_Other); + bool clear(void); + + char* allocKey(size_t p_stLength); + bool setKey(const char* p_pcKey, + size_t p_stLength); + bool setKey(const char* p_pcKey); + bool releaseKey(void); + + char* allocValue(size_t p_stLength); + bool setValue(const char* p_pcValue, + size_t p_stLength); + bool setValue(const char* p_pcValue); + bool releaseValue(void); + + bool set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp = false); + + bool update(const char* p_pcValue); + + size_t length(void) const; + }; + + /** + stcServiceTxts + */ + struct stcServiceTxts + { + stcServiceTxt* m_pTxts; + char* m_pcCache; + + stcServiceTxts(void); + stcServiceTxts(const stcServiceTxts& p_Other); + ~stcServiceTxts(void); + + stcServiceTxts& operator=(const stcServiceTxts& p_Other); + + bool clear(void); + bool clearCache(void); + + bool add(stcServiceTxt* p_pTxt); + bool remove(stcServiceTxt* p_pTxt); + + bool removeTempTxts(void); + + stcServiceTxt* find(const char* p_pcKey); + const stcServiceTxt* find(const char* p_pcKey) const; + stcServiceTxt* find(const stcServiceTxt* p_pTxt); + + uint16_t length(void) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer); + const char* c_str(void) const; + + size_t bufferLength(void) const; + bool buffer(char* p_pcBuffer); + + bool compare(const stcServiceTxts& p_Other) const; + bool operator==(const stcServiceTxts& p_Other) const; + bool operator!=(const stcServiceTxts& p_Other) const; + }; + + /** + typeProbingStatus & enuProbingStatus + */ + using typeProbingStatus = uint8_t; + enum class enuProbingStatus : typeProbingStatus + { + WaitingForData, + ReadyToStart, + InProgress, + Done + }; + + /** + stcProbeInformation_Base + */ + struct stcProbeInformation_Base + { + enuProbingStatus m_ProbingStatus; + uint8_t m_u8SentCount; // Used for probes and announcements + esp8266::polledTimeout::oneShot m_Timeout; // Used for probes and announcements + bool m_bConflict; + bool m_bTiebreakNeeded; + + stcProbeInformation_Base(void); + + bool clear(void); // No 'virtual' needed, no polymorphic use (save 4 bytes) + }; + + /** + HostProbeResultCallbackFn + Callback function for host domain probe results + */ + using HostProbeResultCallbackFn = std::function; + /** + MDNSServiceProbeResultCallbackFn + Callback function for service domain probe results + */ + struct stcService; + using ServiceProbeResultCallbackFn = std::function; + + /** + stcProbeInformation_Host + */ + struct stcProbeInformation_Host : public stcProbeInformation_Base + { + HostProbeResultCallbackFn m_fnProbeResultCallback; + + stcProbeInformation_Host(void); + + bool clear(bool p_bClearUserdata = false); + }; + + /** + stcProbeInformation_Service + */ + struct stcProbeInformation_Service : public stcProbeInformation_Base + { + ServiceProbeResultCallbackFn m_fnProbeResultCallback; + + stcProbeInformation_Service(void); + + bool clear(bool p_bClearUserdata = false); + }; + + /** + DynamicServiceTxtCallbackFn + Callback function for dynamic MDNS TXT items + */ + struct stcService; + using DynamicServiceTxtCallbackFn = std::function; + + /** + stcService + */ + struct stcService + { + stcService* m_pNext; + char* m_pcName; + bool m_bAutoName; // Name was set automatically to hostname (if no name was supplied) + char* m_pcServiceType; + char* m_pcProtocol; + uint16_t m_u16Port; + uint32_t m_u32ReplyMask; + stcServiceTxts m_Txts; + DynamicServiceTxtCallbackFn m_fnTxtCallback; + stcProbeInformation_Service m_ProbeInformation; + + stcService(const char* p_pcName = 0, + const char* p_pcServiceType = 0, + const char* p_pcProtocol = 0); + ~stcService(void); + + bool setName(const char* p_pcName); + bool releaseName(void); + + bool setServiceType(const char* p_pcService); + bool releaseServiceType(void); + + bool setProtocol(const char* p_pcProtocol); + bool releaseProtocol(void); + + bool probeStatus(void) const; + }; + + /** + typeContentFlag & enuContentFlag + */ + using typeContentFlag = uint16_t; + enum class enuContentFlag : typeContentFlag + { + // Host + A = 0x0001, + PTR_IPv4 = 0x0002, + PTR_IPv6 = 0x0004, + AAAA = 0x0008, + // Service + PTR_TYPE = 0x0010, + PTR_NAME = 0x0020, + TXT = 0x0040, + SRV = 0x0080, + // DNSSEC + NSEC = 0x0100, + + PTR = (PTR_IPv4 | PTR_IPv6 | PTR_TYPE | PTR_NAME) + }; + + /** + stcMsgHeader + */ + struct stcMsgHeader + { + uint16_t m_u16ID; // Identifier + bool m_1bQR : 1; // Query/Response flag + uint8_t m_4bOpcode : 4; // Operation code + bool m_1bAA : 1; // Authoritative Answer flag + bool m_1bTC : 1; // Truncation flag + bool m_1bRD : 1; // Recursion desired + bool m_1bRA : 1; // Recursion available + uint8_t m_3bZ : 3; // Zero + uint8_t m_4bRCode : 4; // Response code + uint16_t m_u16QDCount; // Question count + uint16_t m_u16ANCount; // Answer count + uint16_t m_u16NSCount; // Authority Record count + uint16_t m_u16ARCount; // Additional Record count + + stcMsgHeader(uint16_t p_u16ID = 0, + bool p_bQR = false, + uint8_t p_u8Opcode = 0, + bool p_bAA = false, + bool p_bTC = false, + bool p_bRD = false, + bool p_bRA = false, + uint8_t p_u8RCode = 0, + uint16_t p_u16QDCount = 0, + uint16_t p_u16ANCount = 0, + uint16_t p_u16NSCount = 0, + uint16_t p_u16ARCount = 0); + }; + + /** + stcRRDomain + */ + struct stcRRDomain + { + char m_acName[MDNS_DOMAIN_MAXLENGTH]; // Encoded domain name + uint16_t m_u16NameLength; // Length (incl. '\0') + char* m_pcDecodedName; + + stcRRDomain(void); + stcRRDomain(const stcRRDomain& p_Other); + ~stcRRDomain(void); + + stcRRDomain& operator=(const stcRRDomain& p_Other); + + bool clear(void); + bool clearNameCache(void); + + bool addLabel(const char* p_pcLabel, + bool p_bPrependUnderline = false); + + bool compare(const stcRRDomain& p_Other) const; + bool operator==(const stcRRDomain& p_Other) const; + bool operator!=(const stcRRDomain& p_Other) const; + bool operator>(const stcRRDomain& p_Other) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer) const; + const char* c_str(void) const; + }; + + /** + stcRRAttributes + */ + struct stcRRAttributes + { + uint16_t m_u16Type; // Type + uint16_t m_u16Class; // Class, nearly always 'IN' + + stcRRAttributes(uint16_t p_u16Type = 0, + uint16_t p_u16Class = 1 /*DNS_RRCLASS_IN Internet*/); + stcRRAttributes(const stcRRAttributes& p_Other); + + stcRRAttributes& operator=(const stcRRAttributes& p_Other); + }; + + /** + stcRRHeader + */ + struct stcRRHeader + { + stcRRDomain m_Domain; + stcRRAttributes m_Attributes; + + stcRRHeader(void); + stcRRHeader(const stcRRHeader& p_Other); + + stcRRHeader& operator=(const stcRRHeader& p_Other); + + bool clear(void); + }; + + /** + stcRRQuestion + */ + struct stcRRQuestion + { + stcRRQuestion* m_pNext; + stcRRHeader m_Header; + bool m_bUnicast; // Unicast reply requested + + stcRRQuestion(void); + }; + + /** + stcNSECBitmap + */ + struct stcNSECBitmap + { + uint8_t m_au8BitmapData[6]; // 6 bytes data + + stcNSECBitmap(void); + + bool clear(void); + uint16_t length(void) const; + bool setBit(uint16_t p_u16Bit); + bool getBit(uint16_t p_u16Bit) const; + }; + + /** + typeAnswerType & enuAnswerType + */ + using typeAnswerType = uint8_t; + enum class enuAnswerType : typeAnswerType + { + A, + PTR, + TXT, + AAAA, + SRV, + //NSEC, + Generic + }; + + /** + stcRRAnswer + */ + struct stcRRAnswer + { + stcRRAnswer* m_pNext; + const enuAnswerType m_AnswerType; + stcRRHeader m_Header; + bool m_bCacheFlush; // Cache flush command bit + uint32_t m_u32TTL; // Validity time in seconds + + virtual ~stcRRAnswer(void); + + enuAnswerType answerType(void) const; + + bool clear(void); + + protected: + stcRRAnswer(enuAnswerType p_AnswerType, + const stcRRHeader& p_Header, + uint32_t p_u32TTL); + }; + +#ifdef MDNS_IPV4_SUPPORT + /** + stcRRAnswerA + */ + struct stcRRAnswerA : public stcRRAnswer + { + IPAddress m_IPAddress; + + stcRRAnswerA(const stcRRHeader& p_Header, + uint32_t p_u32TTL); + ~stcRRAnswerA(void); + + bool clear(void); + }; +#endif + + /** + stcRRAnswerPTR + */ + struct stcRRAnswerPTR : public stcRRAnswer + { + stcRRDomain m_PTRDomain; + + stcRRAnswerPTR(const stcRRHeader& p_Header, + uint32_t p_u32TTL); + ~stcRRAnswerPTR(void); + + bool clear(void); + }; + + /** + stcRRAnswerTXT + */ + struct stcRRAnswerTXT : public stcRRAnswer + { + stcServiceTxts m_Txts; + + stcRRAnswerTXT(const stcRRHeader& p_Header, + uint32_t p_u32TTL); + ~stcRRAnswerTXT(void); + + bool clear(void); + }; + +#ifdef MDNS_IPV6_SUPPORT + /** + stcRRAnswerAAAA + */ + struct stcRRAnswerAAAA : public stcRRAnswer + { + IPAddress m_IPAddress; + + stcRRAnswerAAAA(const stcRRHeader& p_Header, + uint32_t p_u32TTL); + ~stcRRAnswerAAAA(void); + + bool clear(void); + }; +#endif + + /** + stcRRAnswerSRV + */ + struct stcRRAnswerSRV : public stcRRAnswer + { + uint16_t m_u16Priority; + uint16_t m_u16Weight; + uint16_t m_u16Port; + stcRRDomain m_SRVDomain; + + stcRRAnswerSRV(const stcRRHeader& p_Header, + uint32_t p_u32TTL); + ~stcRRAnswerSRV(void); + + bool clear(void); + }; + + /** + stcRRAnswerGeneric + */ + struct stcRRAnswerGeneric : public stcRRAnswer + { + uint16_t m_u16RDLength; // Length of variable answer + uint8_t* m_pu8RDData; // Offset of start of variable answer in packet + + stcRRAnswerGeneric(const stcRRHeader& p_Header, + uint32_t p_u32TTL); + ~stcRRAnswerGeneric(void); + + bool clear(void); + }; + + + /** + stcSendParameter + */ + struct stcSendParameter + { + protected: + /** + stcDomainCacheItem + */ + struct stcDomainCacheItem + { + stcDomainCacheItem* m_pNext; + const void* m_pHostNameOrService; // Opaque id for host or service domain (pointer) + bool m_bAdditionalData; // Opaque flag for special info (service domain included) + uint16_t m_u16Offset; // Offset in UDP output buffer + + stcDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset); + }; + + public: + /** + typeResponseType & enuResponseType + */ + using typeResponseType = uint8_t; + enum class enuResponseType : typeResponseType + { + None, + Response, + Unsolicited + }; + + uint16_t m_u16ID; // Query ID (used only in lagacy queries) + stcRRQuestion* m_pQuestions; // A list of queries + uint32_t m_u32HostReplyMask; // Flags for reply components/answers + bool m_bLegacyQuery; // Flag: Legacy query + enuResponseType m_Response; // Enum: Response to a query + bool m_bAuthorative; // Flag: Authorative (owner) response + bool m_bCacheFlush; // Flag: Clients should flush their caches + bool m_bUnicast; // Flag: Unicast response + bool m_bUnannounce; // Flag: Unannounce service + + // Temp content; created while processing _prepareMessage + uint16_t m_u16Offset; // Current offset in UDP write buffer (mainly for domain cache) + stcDomainCacheItem* m_pDomainCacheItems; // Cached host and service domains + + stcSendParameter(void); + ~stcSendParameter(void); + + bool clear(void); + bool flushQuestions(void); + bool flushDomainCache(void); + bool flushTempContent(void); + + bool shiftOffset(uint16_t p_u16Shift); + + bool addDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset); + uint16_t findCachedDomainOffset(const void* p_pHostNameOrService, + bool p_bAdditionalData) const; + }; + + + // QUERIES & ANSWERS + /** + typeQueryAnswerType & enuQueryAnswerType + */ + using typeQueryAnswerType = uint8_t; + enum class enuQueryAnswerType : typeQueryAnswerType + { + Unknown = 0x00, + ServiceDomain = 0x01, // Service domain + HostDomain = 0x02, // Host domain + Port = 0x04, // Port + Txts = 0x08, // TXT items +#ifdef MDNS_IPV4_SUPPORT + IPv4Address = 0x10, // IPv4 address +#endif +#ifdef MDNS_IPV6_SUPPORT + IPv6Address = 0x20, // IPv6 address +#endif + }; + + /** + stcQuery + */ + struct stcQuery + { + /** + stcAnswer + */ + struct stcAnswer + { + /** + stcTTL + */ + struct stcTTL + { + /** + typeTimeoutLevel & enuTimeoutLevel + */ + using typeTimeoutLevel = uint8_t; + enum class enuTimeoutLevel : typeTimeoutLevel + { + None = 0, + Base = 80, + Interval = 5, + Final = 100 + }; + + uint32_t m_u32TTL; + esp8266::polledTimeout::oneShot m_TTLTimeout; + typeTimeoutLevel m_TimeoutLevel; + + stcTTL(void); + bool set(uint32_t p_u32TTL); + + bool flagged(void) const; + bool restart(void); + + bool prepareDeletion(void); + bool finalTimeoutLevel(void) const; + + unsigned long timeout(void) const; + }; + /** + stcIPAddress + */ + struct stcIPAddress + { + stcIPAddress* m_pNext; + IPAddress m_IPAddress; + stcTTL m_TTL; + + stcIPAddress(IPAddress p_IPAddress, + uint32_t p_u32TTL = 0); + }; + + stcAnswer* m_pNext; + // The service domain is the first 'answer' (from PTR answer, using service and protocol) to be set + // Defines the key for additional answer, like host domain, etc. + stcRRDomain m_ServiceDomain; // 1. level answer (PTR), eg. MyESP._http._tcp.local + stcTTL m_TTLServiceDomain; + stcRRDomain m_HostDomain; // 2. level answer (SRV, using service domain), eg. esp8266.local + uint16_t m_u16Port; // 2. level answer (SRV, using service domain), eg. 5000 + stcTTL m_TTLHostDomainAndPort; + stcServiceTxts m_Txts; // 2. level answer (TXT, using service domain), eg. c#=1 + stcTTL m_TTLTxts; +#ifdef MDNS_IPV4_SUPPORT + stcIPAddress* m_pIPv4Addresses; // 3. level answer (A, using host domain), eg. 123.456.789.012 +#endif +#ifdef MDNS_IPV6_SUPPORT + stcIPAddress* m_pIPv6Addresses; // 3. level answer (AAAA, using host domain), eg. 1234::09 +#endif + typeQueryAnswerType m_QueryAnswerFlags; // enuQueryAnswerType + + stcAnswer(void); + ~stcAnswer(void); + + bool clear(void); + +#ifdef MDNS_IPV4_SUPPORT + bool releaseIPv4Addresses(void); + bool addIPv4Address(stcIPAddress* p_pIPAddress); + bool removeIPv4Address(stcIPAddress* p_pIPAddress); + const stcIPAddress* findIPv4Address(const IPAddress& p_IPAddress) const; + stcIPAddress* findIPv4Address(const IPAddress& p_IPAddress); + uint32_t IPv4AddressCount(void) const; + const stcIPAddress* IPv4AddressAtIndex(uint32_t p_u32Index) const; + stcIPAddress* IPv4AddressAtIndex(uint32_t p_u32Index); +#endif +#ifdef MDNS_IPV6_SUPPORT + bool releaseIPv6Addresses(void); + bool addIPv6Address(stcIPAddress* p_pIPAddress); + bool removeIPv6Address(stcIPAddress* p_pIPAddress); + const stcIPAddress* findIPv6Address(const IPAddress& p_IPAddress) const; + stcIPAddress* findIPv6Address(const IPAddress& p_IPAddress); + uint32_t IPv6AddressCount(void) const; + const stcIPAddress* IPv6AddressAtIndex(uint32_t p_u32Index) const; + stcIPAddress* IPv6AddressAtIndex(uint32_t p_u32Index); +#endif + }; //stcAnswer + + /** + typeQueryType & enuQueryType + */ + using typeQueryType = uint8_t; + enum class enuQueryType : typeQueryType + { + None, + Service, + Host + }; + using _QueryCallbackFn = std::function; // true: Answer component set, false: component deleted + + stcQuery* m_pNext; + enuQueryType m_QueryType; + stcRRDomain m_Domain; // Type:Service -> _http._tcp.local; Type:Host -> esp8266.local + _QueryCallbackFn m_fnCallback; + bool m_bLegacyQuery; + uint8_t m_u8SentCount; + esp8266::polledTimeout::oneShot m_ResendTimeout; + bool m_bAwaitingAnswers; + stcAnswer* m_pAnswers; + + stcQuery(const enuQueryType p_QueryType); + ~stcQuery(void); + + bool clear(void); + + uint32_t answerCount(void) const; + const stcAnswer* answerAtIndex(uint32_t p_u32Index) const; + stcAnswer* answerAtIndex(uint32_t p_u32Index); + uint32_t indexOfAnswer(const stcAnswer* p_pAnswer) const; + + bool addAnswer(stcAnswer* p_pAnswer); + bool removeAnswer(stcAnswer* p_pAnswer); + + stcAnswer* findAnswerForServiceDomain(const stcRRDomain& p_ServiceDomain); + stcAnswer* findAnswerForHostDomain(const stcRRDomain& p_HostDomain); + }; + /** + QueryCallbackFn + + Callback function for received answers for dynamic queries + */ + using QueryCallbackFn = stcQuery::_QueryCallbackFn; + +public: + clsHost(netif& p_rNetIf, + UdpContext& p_rUDPContext); + ~clsHost(void); + + bool init(void); + + // HOST + bool setHostName(const char* p_pcHostName); + const char* hostName(void) const; + + bool setHostProbeResultCallback(HostProbeResultCallbackFn p_fnCallback); + + // Returns 'true' is host domain probing is done + bool probeStatus(void) const; + + // SERVICE + bool setInstanceName(const char* p_pcInstanceName); + const char* instanceName(void) const; + + stcService* addService(const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port); + bool removeService(stcService* p_pMDNSService); + + const stcService* findService(const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port = 0) const; + stcService* findService(const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port = 0); + bool validateService(const stcService* p_pService) const; + + bool setServiceName(stcService* p_pMDNSService, + const char* p_pcInstanceName); + const char* serviceName(const stcService* p_pMDNSService) const; + const char* serviceType(const stcService* p_pMDNSService) const; + const char* serviceProtocol(const stcService* p_pMDNSService) const; + uint16_t servicePort(const stcService* p_pMDNSService) const; + + // Set a service specific probe result callcack + bool setServiceProbeResultCallback(stcService* p_pMDNSService, + ServiceProbeResultCallbackFn p_fnCallback); + + bool serviceProbeStatus(const stcService* p_pMDNSService) const; + + // SERVICE TXT + // Add a (static) MDNS TXT item ('key' = 'value') to the service + stcServiceTxt* addServiceTxt(stcService* p_pMDNSService, + const char* p_pcKey, + const char* p_pcValue); + bool removeServiceTxt(stcService* p_pMDNSService, + stcServiceTxt* p_pTxt); + const stcServiceTxt* findServiceTxt(stcService* p_pMDNSService, + const char* p_pcKey) const; + stcServiceTxt* findServiceTxt(stcService* p_pMDNSService, + const char* p_pcKey); + + bool setDynamicServiceTxtCallback(DynamicServiceTxtCallbackFn p_fnCallback); + bool setDynamicServiceTxtCallback(stcService* p_pMDNSService, + DynamicServiceTxtCallbackFn p_fnCallback); + + // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + // Dynamic TXT items are removed right after one-time use. So they need to be added + // every time the value s needed (via callback). + stcServiceTxt* addDynamicServiceTxt(stcService* p_pMDNSService, + const char* p_pcKey, + const char* p_pcValue); + + // QUERIES + + // - STATIC + // Perform a (static) service/host query. The function returns after p_u16Timeout milliseconds + // The answers (the number of received answers is returned) can be retrieved by calling + // - answerHostName (or hostname) + // - answerIP (or IP) + // - answerPort (or port) + uint32_t queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + uint32_t queryHost(const char* p_pcHostName, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + bool removeQuery(void); + bool hasQuery(void); + stcQuery* getQuery(void); + + // - DYNAMIC + // Install a dynamic service/host query. For every received answer (part) the given callback + // function is called. The query will be updated every time, the TTL for an answer + // has timed-out. + // The answers can also be retrieved by calling + // - answerCount service/host (for host queries, this should never be >1) + // - answerServiceDomain service + // - hasAnswerHostDomain/answerHostDomain service/host + // - hasAnswerIPv4Address/answerIPv4Address service/host + // - hasAnswerIPv6Address/answerIPv6Address service/host + // - hasAnswerPort/answerPort service + // - hasAnswerTxts/answerTxts service + stcQuery* installServiceQuery(const char* p_pcServiceType, + const char* p_pcProtocol, + QueryCallbackFn p_fnCallback); + stcQuery* installHostQuery(const char* p_pcHostName, + QueryCallbackFn p_fnCallback); + // Remove a dynamic service query + bool removeQuery(stcQuery* p_pMDNSQuery); + + + + + + // PROCESSING + bool processUDPInput(void); + bool update(void); + + bool announce(bool p_bAnnounce, + bool p_bIncludeServices); + bool announceService(stcService* p_pService, + bool p_bAnnounce = true); + + bool restart(void); + +protected: + // File: ..._Host + bool _close(void); + + // NETIF + typeNetIfState _getNetIfState(void) const; + bool _checkNetIfState(void); + + // DOMAIN NAMES + bool _allocDomainName(const char* p_pcNewDomainName, + char*& p_rpcDomainName); + bool _releaseDomainName(char*& p_rpcDomainName); + bool _allocHostName(const char* p_pcHostName); + bool _releaseHostName(void); + bool _allocInstanceName(const char* p_pcInstanceName); + bool _releaseInstanceName(void); + + // SERVICE + stcService* _allocService(const char* p_pcName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port); + bool _releaseService(stcService* p_pService); + + // SERVICE TXT + stcServiceTxt* _allocServiceTxt(stcService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + bool _releaseServiceTxt(stcService* p_pService, + stcServiceTxt* p_pTxt); + stcServiceTxt* _updateServiceTxt(stcService* p_pService, + stcServiceTxt* p_pTxt, + const char* p_pcValue, + bool p_bTemp); + stcServiceTxt* _findServiceTxt(stcService* p_pService, + const char* p_pcKey); + stcServiceTxt* _addServiceTxt(stcService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + stcServiceTxt* _answerKeyValue(const stcQuery p_pQuery, + const uint32_t p_u32AnswerIndex); + bool _collectServiceTxts(stcService& p_rService); + bool _releaseTempServiceTxts(stcService& p_rService); + + // QUERIES + stcQuery* _allocQuery(stcQuery::enuQueryType p_QueryType); + bool _removeQuery(stcQuery* p_pQuery); + bool _removeLegacyQuery(void); + stcQuery* _findLegacyQuery(void); + bool _releaseQueries(void); + stcQuery* _findNextQueryByDomain(const stcRRDomain& p_Domain, + const stcQuery::enuQueryType p_QueryType, + const stcQuery* p_pPrevQuery); + stcQuery* _installDomainQuery(stcRRDomain& p_Domain, + stcQuery::enuQueryType p_QueryType, + QueryCallbackFn p_fnCallback); + bool _hasQueriesWaitingForAnswers(void) const; + bool _executeQueryCallback(const stcQuery& p_Query, + const stcQuery::stcAnswer& p_Answer, + typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_SetContent); + + + // File: ..._Host_Control + // RECEIVING + bool _parseMessage(void); + bool _parseQuery(const stcMsgHeader& p_Header); + + bool _parseResponse(const stcMsgHeader& p_Header); + bool _processAnswers(const stcRRAnswer* p_pPTRAnswers); + bool _processPTRAnswer(const stcRRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processSRVAnswer(const stcRRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processTXTAnswer(const stcRRAnswerTXT* p_pTXTAnswer); +#ifdef MDNS_IPV4_SUPPORT + bool _processAAnswer(const stcRRAnswerA* p_pAAnswer); +#endif +#ifdef MDNS_IPV6_SUPPORT + bool _processAAAAAnswer(const stcRRAnswerAAAA* p_pAAAAAnswer); +#endif + + // PROBING + bool _updateProbeStatus(void); + bool _resetProbeStatus(bool p_bRestart = true); + bool _hasProbesWaitingForAnswers(void) const; + bool _sendHostProbe(void); + bool _sendServiceProbe(stcService& p_rService); + bool _cancelProbingForHost(void); + bool _cancelProbingForService(stcService& p_rService); + bool _callHostProbeResultCallback(bool p_bResult); + bool _callServiceProbeResultCallback(stcService& p_rService, + bool p_bResult); + + // ANNOUNCE + bool _announce(bool p_bAnnounce, + bool p_bIncludeServices); + bool _announceService(stcService& p_pService, + bool p_bAnnounce = true); + + // QUERY CACHE + bool _checkQueryCache(void); + + uint32_t _replyMaskForHost(const stcRRHeader& p_RRHeader, + bool* p_pbFullNameMatch = 0) const; + uint32_t _replyMaskForService(const stcRRHeader& p_RRHeader, + const stcService& p_Service, + bool* p_pbFullNameMatch = 0) const; + + + // File: ..._Host_Transfer + // SENDING + bool _sendMDNSMessage(stcSendParameter& p_SendParameter); + bool _sendMDNSMessage_Multicast(stcSendParameter& p_rSendParameter, + uint8_t p_IPProtocolTypes); + bool _prepareMDNSMessage(stcSendParameter& p_SendParameter); + bool _addMDNSQueryRecord(stcSendParameter& p_rSendParameter, + const stcRRDomain& p_QueryDomain, + uint16_t p_u16QueryType); + bool _sendMDNSQuery(const stcQuery& p_Query, + stcQuery::stcAnswer* p_pKnownAnswers = 0); + bool _sendMDNSQuery(const stcRRDomain& p_QueryDomain, + uint16_t p_u16RecordType, + stcQuery::stcAnswer* p_pKnownAnswers = 0); + + IPAddress _getResponderIPAddress(enuIPProtocolType p_IPProtocolType) const; + + // RESOURCE RECORD + bool _readRRQuestion(stcRRQuestion& p_rQuestion); + bool _readRRAnswer(stcRRAnswer*& p_rpAnswer); +#ifdef MDNS_IPV4_SUPPORT + bool _readRRAnswerA(stcRRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerPTR(stcRRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength); + bool _readRRAnswerTXT(stcRRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength); +#ifdef MDNS_IPV6_SUPPORT + bool _readRRAnswerAAAA(stcRRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerSRV(stcRRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength); + bool _readRRAnswerGeneric(stcRRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength); + + bool _readRRHeader(stcRRHeader& p_rHeader); + bool _readRRDomain(stcRRDomain& p_rRRDomain); + bool _readRRDomain_Loop(stcRRDomain& p_rRRDomain, + uint8_t p_u8Depth); + bool _readRRAttributes(stcRRAttributes& p_rAttributes); + + // DOMAIN NAMES + bool _buildDomainForHost(const char* p_pcHostName, + stcRRDomain& p_rHostDomain) const; + bool _buildDomainForDNSSD(stcRRDomain& p_rDNSSDDomain) const; + bool _buildDomainForService(const stcService& p_Service, + bool p_bIncludeName, + stcRRDomain& p_rServiceDomain) const; + bool _buildDomainForService(const char* p_pcService, + const char* p_pcProtocol, + stcRRDomain& p_rServiceDomain) const; +#ifdef MDNS_IPV4_SUPPORT + bool _buildDomainForReverseIPv4(IPAddress p_IPv4Address, + stcRRDomain& p_rReverseIPv4Domain) const; +#endif +#ifdef MDNS_IPV6_SUPPORT + bool _buildDomainForReverseIPv6(IPAddress p_IPv4Address, + stcRRDomain& p_rReverseIPv6Domain) const; +#endif + + // UDP + bool _udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength); + bool _udpRead8(uint8_t& p_ru8Value); + bool _udpRead16(uint16_t& p_ru16Value); + bool _udpRead32(uint32_t& p_ru32Value); + + bool _udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength); + bool _udpAppend8(uint8_t p_u8Value); + bool _udpAppend16(uint16_t p_u16Value); + bool _udpAppend32(uint32_t p_u32Value); + +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + bool _udpDump(bool p_bMovePointer = false); + bool _udpDump(unsigned p_uOffset, + unsigned p_uLength); +#endif + + // READ/WRITE MDNS STRUCTS + bool _readMDNSMsgHeader(stcMsgHeader& p_rMsgHeader); + + bool _write8(uint8_t p_u8Value, + stcSendParameter& p_rSendParameter); + bool _write16(uint16_t p_u16Value, + stcSendParameter& p_rSendParameter); + bool _write32(uint32_t p_u32Value, + stcSendParameter& p_rSendParameter); + + bool _writeMDNSMsgHeader(const stcMsgHeader& p_MsgHeader, + stcSendParameter& p_rSendParameter); + bool _writeMDNSRRAttributes(const stcRRAttributes& p_Attributes, + stcSendParameter& p_rSendParameter); + bool _writeMDNSRRDomain(const stcRRDomain& p_Domain, + stcSendParameter& p_rSendParameter); + bool _writeMDNSHostDomain(const char* m_pcHostName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + stcSendParameter& p_rSendParameter); + bool _writeMDNSServiceDomain(const stcService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + stcSendParameter& p_rSendParameter); + + bool _writeMDNSQuestion(stcRRQuestion& p_Question, + stcSendParameter& p_rSendParameter); + +#ifdef MDNS_IPV4_SUPPORT + bool _writeMDNSAnswer_A(IPAddress p_IPAddress, + stcSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, + stcSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_PTR_TYPE(stcService& p_rService, + stcSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_NAME(stcService& p_rService, + stcSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_TXT(stcService& p_rService, + stcSendParameter& p_rSendParameter); +#ifdef MDNS_IPV6_SUPPORT + bool _writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + stcSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, + stcSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_SRV(stcService& p_rService, + stcSendParameter& p_rSendParameter); + stcNSECBitmap* _createNSECBitmap(uint32_t p_u32NSECContent); + bool _writeMDNSNSECBitmap(const stcNSECBitmap& p_NSECBitmap, + stcSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_NSEC(uint32_t p_u32NSECContent, + stcSendParameter& p_rSendParameter); +#ifdef MDNS_IPV4_SUPPORT + bool _writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddress, + stcSendParameter& p_rSendParameter); +#endif +#ifdef MDNS_IPV6_SUPPORT + bool _writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddress, + stcSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_NSEC(stcService& p_rService, + uint32_t p_u32NSECContent, + stcSendParameter& p_rSendParameter); + + + // File: ..._Host_Debug +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + const char* _DH(const stcService* p_pMDNSService = 0) const; + const char* _service2String(const stcService* p_pMDNSService) const; + + bool _printRRDomain(const stcRRDomain& p_rRRDomain) const; + bool _printRRAnswer(const stcRRAnswer& p_RRAnswer) const; + const char* _RRType2Name(uint16_t p_u16RRType) const; + const char* _RRClass2String(uint16_t p_u16RRClass, + bool p_bIsQuery) const; + const char* _replyFlags2String(uint32_t p_u32ReplyFlags) const; + const char* _NSECBitmap2String(const stcNSECBitmap* p_pNSECBitmap) const; +#endif + + +public: + netif& m_rNetIf; + typeNetIfState m_NetIfState; + UdpContext& m_rUDPContext; + + char* m_pcHostName; + char* m_pcInstanceName; + stcService* m_pServices; + stcQuery* m_pQueries; + DynamicServiceTxtCallbackFn m_fnServiceTxtCallback; + stcProbeInformation_Host m_HostProbeInformation; +}; +using clsHostList = std::list; + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Control.cpp new file mode 100755 index 0000000000..7b4402c587 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Control.cpp @@ -0,0 +1,2207 @@ +/* + LEAmDNS2_Host_Control.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* + ESP8266mDNS Control.cpp +*/ + +extern "C" { +#include "user_interface.h" +} + +#include "LEAmDNS2_lwIPdefs.h" +#include "LEAmDNS2_Priv.h" + +namespace esp8266 +{ +/* + LEAmDNS +*/ +namespace experimental +{ + +/** + RECEIVING +*/ + +/* + MDNSResponder::clsHost::_parseMessage +*/ +bool MDNSResponder::clsHost::_parseMessage(void) +{ + DEBUG_EX_INFO( + unsigned long ulStartTime = millis(); + unsigned uStartMemory = ESP.getFreeHeap(); + DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage (Time: %lu ms, heap: %u bytes, from %s, to %s)\n"), _DH(), ulStartTime, uStartMemory, + m_rUDPContext.getRemoteAddress().toString().c_str(), + m_rUDPContext.getDestAddress().toString().c_str()); + ); + //DEBUG_EX_INFO(_udpDump();); + + bool bResult = false; + + stcMsgHeader header; + if (_readMDNSMsgHeader(header)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + _DH(), + (unsigned)header.m_u16ID, + (unsigned)header.m_1bQR, (unsigned)header.m_4bOpcode, (unsigned)header.m_1bAA, (unsigned)header.m_1bTC, (unsigned)header.m_1bRD, + (unsigned)header.m_1bRA, (unsigned)header.m_4bRCode, + (unsigned)header.m_u16QDCount, + (unsigned)header.m_u16ANCount, + (unsigned)header.m_u16NSCount, + (unsigned)header.m_u16ARCount)); + if (0 == header.m_4bOpcode) // A standard query + { + if (header.m_1bQR) // Received a response -> answers to a query + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Reading answers: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), _DH(), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); + bResult = _parseResponse(header); + } + else // Received a query (Questions) + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Reading query: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), _DH(), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); + bResult = _parseQuery(header); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Received UNEXPECTED opcode:%u. Ignoring message!\n"), _DH(), header.m_4bOpcode);); + m_rUDPContext.flush(); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: FAILED to read header\n"), _DH());); + m_rUDPContext.flush(); + } + DEBUG_EX_INFO( + unsigned uFreeHeap = ESP.getFreeHeap(); + DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Done (%s after %lu ms, ate %i bytes, remaining %u)\n\n"), _DH(), (bResult ? "Succeeded" : "FAILED"), (millis() - ulStartTime), (uStartMemory - uFreeHeap), uFreeHeap); + ); + return bResult; +} + +/* + MDNSResponder::clsHost::_parseQuery + + Queries are of interest in two cases: + 1. allow for tiebreaking while probing in the case of a race condition between two instances probing for + the same name at the same time + 2. provide answers to questions for our host domain or any presented service + + When reading the questions, a set of (planned) responses is created, eg. a reverse PTR question for the host domain + gets an A (IP address) response, a PTR question for the _services._dns-sd domain gets a PTR (type) response for any + registered service, ... + + As any mDNS responder should be able to handle 'legacy' queries (from DNS clients), this case is handled here also. + Legacy queries have got only one (unicast) question and are directed to the local DNS port (not the multicast port). + + 1. +*/ +bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHeader& p_MsgHeader) +{ + bool bResult = true; + + stcSendParameter sendParameter; + uint32_t u32HostOrServiceReplies = 0; + for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) + { + stcRRQuestion questionRR; + if ((bResult = _readRRQuestion(questionRR))) + { + // Define host replies, BUT only answer queries after probing is done + u32HostOrServiceReplies = + sendParameter.m_u32HostReplyMask |= ((probeStatus()) + ? _replyMaskForHost(questionRR.m_Header, 0) + : 0); + DEBUG_EX_INFO(if (u32HostOrServiceReplies) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Host reply needed %s\n"), _DH(), _replyFlags2String(u32HostOrServiceReplies));); + + // Check tiebreak need for host domain + if (enuProbingStatus::InProgress == m_HostProbeInformation.m_ProbingStatus) + { + bool bFullNameMatch = false; + if ((_replyMaskForHost(questionRR.m_Header, &bFullNameMatch)) && + (bFullNameMatch)) + { + // We're in 'probing' state and someone is asking for our host domain: this might be + // a race-condition: Two host with the same domain names try simutanously to probe their domains + // See: RFC 6762, 8.2 (Tiebraking) + // However, we're using a max. reduced approach for tiebreaking here: The higher IP-address wins! + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Possible race-condition for host domain detected while probing.\n"), _DH());); + Serial.printf_P(PSTR("%s _parseQuery: Possible race-condition for host domain detected while probing.\n"), _DH()); + + m_HostProbeInformation.m_bTiebreakNeeded = true; + } + } + + // Define service replies + for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + { + // Define service replies, BUT only answer queries after probing is done + uint32_t u32ReplyMaskForQuestion = ((pService->probeStatus()) + ? _replyMaskForService(questionRR.m_Header, *pService, 0) + : 0); + u32HostOrServiceReplies |= (pService->m_u32ReplyMask |= u32ReplyMaskForQuestion); + DEBUG_EX_INFO(if (u32ReplyMaskForQuestion) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service reply needed: %s\n"), _DH(pService), _replyFlags2String(u32ReplyMaskForQuestion));); + + // Check tiebreak need for service domain + if (enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) + { + bool bFullNameMatch = false; + if ((_replyMaskForService(questionRR.m_Header, *pService, &bFullNameMatch)) && + (bFullNameMatch)) + { + // We're in 'probing' state and someone is asking for this service domain: this might be + // a race-condition: Two services with the same domain names try simutanously to probe their domains + // See: RFC 6762, 8.2 (Tiebraking) + // However, we're using a max. reduced approach for tiebreaking here: The 'higher' SRV host wins! + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Possible race-condition for service domain detected while probing.\n"), _DH(pService));); + Serial.printf_P(PSTR("%s _parseQuery: Possible race-condition for service domain detected while probing.\n"), _DH(pService)); + + pService->m_ProbeInformation.m_bTiebreakNeeded = true; + } + } + } + + // Handle unicast and legacy specialities + // If only one question asks for unicast reply, the whole reply packet is send unicast + if (((DNS_MQUERY_PORT != m_rUDPContext.getRemotePort()) || // Unicast (maybe legacy) query OR + (questionRR.m_bUnicast)) && // Expressivly unicast query + (!sendParameter.m_bUnicast)) + { + + sendParameter.m_bUnicast = true; + //sendParameter.m_bCacheFlush = false; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Unicast response asked for %s!\n"), _DH(), m_rUDPContext.getRemoteAddress().toString().c_str());); + //Serial.printf_P(PSTR("%s _parseQuery: Ignored Unicast response asked for by %s!\n"), _DH(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()); + + if ((DNS_MQUERY_PORT != m_rUDPContext.getRemotePort()) && // Unicast (maybe legacy) query AND + (1 == p_MsgHeader.m_u16QDCount) && // Only one question AND + ((sendParameter.m_u32HostReplyMask) || // Host replies OR + (u32HostOrServiceReplies))) // Host or service replies available + { + // Local host check + // We're a match for this legacy query, BUT + // make sure, that the query comes from a local host +#ifdef MDNS_IPV4_SUPPORT + ip_info IPInfo_Local; +#endif + if ( +#ifdef MDNS_IPV4_SUPPORT + (m_rUDPContext.getRemoteAddress().isV4()) && + ((wifi_get_ip_info(netif_get_index(&m_rNetIf), &IPInfo_Local))) && + (ip4_addr_netcmp(ip_2_ip4((const ip_addr_t*)m_rUDPContext.getRemoteAddress()), &IPInfo_Local.ip, &IPInfo_Local.netmask)) +#else + (true) +#endif + && +#ifdef MDNS_IPV6_SUPPORT + (m_rUDPContext.getRemoteAddress().isV6()) && + (ip6_addr_islinklocal(ip_2_ip6((const ip_addr_t*)m_rUDPContext.getRemoteAddress()))) +#else + (true) +#endif + ) + { + /* ip_info IPInfo_Local; + ip_info IPInfo_Remote; + if (((IPInfo_Remote.ip.addr = m_pUDPContext->getRemoteAddress())) && + (((wifi_get_ip_info(SOFTAP_IF, &IPInfo_Local)) && + (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))) || // Remote IP in SOFTAP's subnet OR + ((wifi_get_ip_info(STATION_IF, &IPInfo_Local)) && + (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))))) // Remote IP in STATION's subnet + {*/ + Serial.println("\n\n\nUNICAST QUERY\n\n"); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Legacy query from local host %s!\n"), _DH(), m_rUDPContext.getRemoteAddress().toString().c_str());); + + sendParameter.m_u16ID = p_MsgHeader.m_u16ID; + sendParameter.m_bLegacyQuery = true; + sendParameter.m_bCacheFlush = false; + sendParameter.m_pQuestions = new stcRRQuestion; + if ((bResult = (0 != sendParameter.m_pQuestions))) + { + sendParameter.m_pQuestions->m_Header.m_Domain = questionRR.m_Header.m_Domain; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = questionRR.m_Header.m_Attributes.m_u16Type; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = questionRR.m_Header.m_Attributes.m_u16Class; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED to add legacy question!\n"), _DH());); + } + } + else + { + Serial.println("\n\n\nINVALID UNICAST QUERY\n\n"); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Legacy query from NON-LOCAL host!\n"), _DH());); + bResult = false; + } + } + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED to read question!\n"), _DH());); + } + } // for questions + + //DEBUG_EX_INFO(if (u8HostOrServiceReplies) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Reply needed: %u (%s: %s->%s)\n"), _DH(), u8HostOrServiceReplies, clsTimeSyncer::timestr(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), IPAddress(m_pUDPContext->getDestAddress()).toString().c_str());); + + // Handle known answers + uint32_t u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); + if ((u32HostOrServiceReplies) && + (u32Answers)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Reading known answers(%u):\n"), _DH(), u32Answers);); + + for (uint32_t an = 0; ((bResult) && (an < u32Answers)); ++an) + { + stcRRAnswer* pKnownRRAnswer = 0; + if (((bResult = _readRRAnswer(pKnownRRAnswer))) && + (pKnownRRAnswer)) + { + + if ((DNS_RRTYPE_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Type) && // No ANY type answer + (DNS_RRCLASS_ANY != (pKnownRRAnswer->m_Header.m_Attributes.m_u16Class & (~0x8000)))) // No ANY class answer + { + + // Find match between planned answer (sendParameter.m_u8HostReplyMask) and this 'known answer' + uint32_t u32HostMatchMask = (sendParameter.m_u32HostReplyMask & _replyMaskForHost(pKnownRRAnswer->m_Header)); + if ((u32HostMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND + ((MDNS_HOST_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new host TTL (120s) + { + + // Compare contents + if (enuAnswerType::PTR == pKnownRRAnswer->answerType()) + { + stcRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (((stcRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain == hostDomain)) + { + // Host domain match +#ifdef MDNS_IPV4_SUPPORT + if (u32HostMatchMask & static_cast(enuContentFlag::PTR_IPv4)) + { + // IPv4 PTR was asked for, but is already known -> skipping + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv4 PTR already known... skipping!\n"), _DH());); + sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::PTR_IPv4); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if (u32HostMatchMask & static_cast(enuContentFlag::PTR_IPv6)) + { + // IPv6 PTR was asked for, but is already known -> skipping + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv6 PTR already known... skipping!\n"), _DH());); + sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::PTR_IPv6); + } +#endif + } + } + else if (u32HostMatchMask & static_cast(enuContentFlag::A)) + { + // IPv4 address was asked for +#ifdef MDNS_IPV4_SUPPORT + if ((enuAnswerType::A == pKnownRRAnswer->answerType()) && + (((stcRRAnswerA*)pKnownRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V4))) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv4 address already known... skipping!\n"), _DH());); + sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::A); + } // else: RData NOT IPv4 length !! +#endif + } + else if (u32HostMatchMask & static_cast(enuContentFlag::AAAA)) + { + // IPv6 address was asked for +#ifdef MDNS_IPV6_SUPPORT + if ((enuAnswerType::AAAA == pKnownRRAnswer->answerType()) && + (((stcRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V6))) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv6 address already known... skipping!\n"), _DH());); + sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::AAAA); + } // else: RData NOT IPv6 length !! +#endif + } + } // Host match /*and TTL*/ + + // + // Check host tiebreak possibility + if (m_HostProbeInformation.m_bTiebreakNeeded) + { + stcRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (pKnownRRAnswer->m_Header.m_Domain == hostDomain)) + { + // Host domain match +#ifdef MDNS_IPV4_SUPPORT + if (enuAnswerType::A == pKnownRRAnswer->answerType()) + { + // CHECK + IPAddress localIPAddress(_getResponderIPAddress(enuIPProtocolType::V4)); + if (((stcRRAnswerA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) + { + // SAME IP address -> We've received an old message from ourselfs (same IP) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) WON (was an old message)!\n"), _DH());); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + else + { + if ((uint32_t)(((stcRRAnswerA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) LOST (lower)!\n"), _DH());); + _cancelProbingForHost(); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + else // WON tiebreak + { + //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) WON (higher IP)!\n"), _DH());); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + } + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if (enuAnswerType::AAAA == pKnownRRAnswer->answerType()) + { + // TODO / CHECK + IPAddress localIPAddress(_getResponderIPAddress(enuIPProtocolType::V6)); + if (((stcRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) + { + // SAME IP address -> We've received an old message from ourselfs (same IP) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) WON (was an old message)!\n"), _DH());); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + else + { + if ((uint32_t)(((stcRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) LOST (lower)!\n"), _DH());); + _cancelProbingForHost(); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + else // WON tiebreak + { + //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) WON (higher IP)!\n"), _DH());); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + } + } +#endif + } + } // Host tiebreak possibility + + // Check service answers + for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + { + + uint32_t u32ServiceMatchMask = (pService->m_u32ReplyMask & _replyMaskForService(pKnownRRAnswer->m_Header, *pService)); + + if ((u32ServiceMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND + ((MDNS_SERVICE_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) + { + + if (enuAnswerType::PTR == pKnownRRAnswer->answerType()) + { + stcRRDomain serviceDomain; + if ((u32ServiceMatchMask & static_cast(enuContentFlag::PTR_TYPE)) && + (_buildDomainForService(*pService, false, serviceDomain)) && + (serviceDomain == ((stcRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service type PTR already known... skipping!\n"), _DH());); + pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::PTR_TYPE); + } + if ((u32ServiceMatchMask & static_cast(enuContentFlag::PTR_NAME)) && + (_buildDomainForService(*pService, true, serviceDomain)) && + (serviceDomain == ((stcRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service name PTR already known... skipping!\n"), _DH());); + pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::PTR_NAME); + } + } + else if (u32ServiceMatchMask & static_cast(enuContentFlag::SRV)) + { + DEBUG_EX_ERR(if (enuAnswerType::SRV != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: ERROR! INVALID answer type (SRV)!\n"), _DH());); + stcRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (hostDomain == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + { + + if ((MDNS_SRV_PRIORITY == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Priority) && + (MDNS_SRV_WEIGHT == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Weight) && + (pService->m_u16Port == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Port)) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service SRV answer already known... skipping!\n"), _DH());); + pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::SRV); + } // else: Small differences -> send update message + } + } + else if (u32ServiceMatchMask & static_cast(enuContentFlag::TXT)) + { + DEBUG_EX_ERR(if (enuAnswerType::TXT != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: ERROR! INVALID answer type (TXT)!\n"), _DH());); + _collectServiceTxts(*pService); + if (pService->m_Txts == ((stcRRAnswerTXT*)pKnownRRAnswer)->m_Txts) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service TXT answer already known... skipping!\n"), _DH());); + pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::TXT); + } + _releaseTempServiceTxts(*pService); + } + } // Service match and enough TTL + + // + // Check service tiebreak possibility + if (pService->m_ProbeInformation.m_bTiebreakNeeded) + { + stcRRDomain serviceDomain; + if ((_buildDomainForService(*pService, true, serviceDomain)) && + (pKnownRRAnswer->m_Header.m_Domain == serviceDomain)) + { + // Service domain match + if (enuAnswerType::SRV == pKnownRRAnswer->answerType()) + { + stcRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (hostDomain == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + { + + // We've received an old message from ourselfs (same SRV) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) won (was an old message)!\n"), _DH());); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + else + { + if (((stcRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain > hostDomain) // The OTHER domain is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) LOST (lower)!\n"), _DH());); + _cancelProbingForService(*pService); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + else // WON tiebreak + { + //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) won (higher)!\n"), _DH());); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + } + } + } // service tiebreak possibility + } // for services + } // ANY answers + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED to read known answer!\n"), _DH());); + } + + if (pKnownRRAnswer) + { + delete pKnownRRAnswer; + pKnownRRAnswer = 0; + } + } // for answers + } + else + { + DEBUG_EX_INFO(if (u32Answers) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Skipped %u known answers!\n"), _DH(), u32Answers);); + m_rUDPContext.flush(); + } + + if (bResult) + { + // Check, if a reply is needed + uint32_t u32ReplyNeeded = sendParameter.m_u32HostReplyMask; + for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + { + u32ReplyNeeded |= pService->m_u32ReplyMask; + } + + if (u32ReplyNeeded) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Sending answer(%s)...\n"), _DH(), _replyFlags2String(u32ReplyNeeded));); + + sendParameter.m_Response = stcSendParameter::enuResponseType::Response; + sendParameter.m_bAuthorative = true; + + bResult = _sendMDNSMessage(sendParameter); + } + DEBUG_EX_INFO( + else + { + DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: No reply needed\n"), _DH()); + } + ); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Something FAILED!\n"), _DH());); + m_rUDPContext.flush(); + } + + // + // Check and reset tiebreak-states + if (m_HostProbeInformation.m_bTiebreakNeeded) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: UNSOLVED tiebreak-need for host domain!\n"), _DH());); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + { + if (pService->m_ProbeInformation.m_bTiebreakNeeded) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: UNSOLVED tiebreak-need for service domain '%s')\n"), _DH(), _service2String(pService));); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::clsHost::_parseResponse + + Responses are of interest in two cases: + 1. find domain name conflicts while probing + 2. get answers to service queries + + In both cases any included questions are ignored + + 1. If any answer has a domain name similar to one of the domain names we're planning to use (and are probing for), + then we've got a 'probing conflict'. The conflict has to be solved on our side of the conflict (eg. by + setting a new hostname and restart probing). The callback 'm_fnProbeResultCallback' is called with + 'p_bProbeResult=false' in this case. + + 2. Service queries like '_http._tcp.local' will (if available) produce PTR, SRV, TXT and A/AAAA answers. + All stored answers are pivoted by the service instance name (from the PTR record). Other answer parts, + like host domain or IP address are than attached to this element. + Any answer part carries a TTL, this is also stored (incl. the reception time); if the TTL is '0' the + answer (part) is withdrawn by the sender and should be removed from any cache. RFC 6762, 10.1 proposes to + set the caches TTL-value to 1 second in such a case and to delete the item only, if no update has + has taken place in this second. + Answer parts may arrive in 'unsorted' order, so they are grouped into three levels: + Level 1: PRT - names the service instance (and is used as pivot), voids all other parts if is withdrawn or outdates + Level 2: SRV - links the instance name to a host domain and port, voids A/AAAA parts if is withdrawn or outdates + TXT - links the instance name to services TXTs + Level 3: A/AAAA - links the host domain to an IP address +*/ +bool MDNSResponder::clsHost::_parseResponse(const MDNSResponder::clsHost::stcMsgHeader& p_MsgHeader) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse\n"));); + //DEBUG_EX_INFO(_udpDump();); + + bool bResult = false; + + // A response should be the result of a query or a probe + if ((_hasQueriesWaitingForAnswers()) || // Waiting for query answers OR + (_hasProbesWaitingForAnswers())) // Probe responses + { + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received a response\n"), _DH()); + //_udpDump(); + ); + + bResult = true; + // + // Ignore questions here + stcRRQuestion dummyRRQ; + for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received a response containing a question... ignoring!\n"), _DH());); + bResult = _readRRQuestion(dummyRRQ); + } // for queries + + // + // Read and collect answers + stcRRAnswer* pCollectedRRAnswers = 0; + uint32_t u32NumberOfAnswerRRs = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); + for (uint32_t an = 0; ((bResult) && (an < u32NumberOfAnswerRRs)); ++an) + { + stcRRAnswer* pRRAnswer = 0; + if (((bResult = _readRRAnswer(pRRAnswer))) && + (pRRAnswer)) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: ADDING answer!\n"));); + pRRAnswer->m_pNext = pCollectedRRAnswers; + pCollectedRRAnswers = pRRAnswer; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: FAILED to read answer!\n"), _DH());); + if (pRRAnswer) + { + delete pRRAnswer; + pRRAnswer = 0; + } + bResult = false; + } + } // for answers + + // + // Process answers + if (bResult) + { + bResult = ((!pCollectedRRAnswers) || + (_processAnswers(pCollectedRRAnswers))); + } + else // Some failure while reading answers + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: FAILED to read answers!\n"), _DH());); + m_rUDPContext.flush(); + } + + // Delete collected answers + while (pCollectedRRAnswers) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: DELETING answer!\n"), _DH());); + stcRRAnswer* pNextAnswer = pCollectedRRAnswers->m_pNext; + delete pCollectedRRAnswers; + pCollectedRRAnswers = pNextAnswer; + } + } + else // Received an unexpected response -> ignore + { + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received an unexpected response... ignoring!\n"), _DH()); + /* + DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received an unexpected response... ignoring!\nDUMP:\n"), _DH()); + bool bDumpResult = true; + for (uint16_t qd=0; ((bDumpResult) && (qdanswerType()) + { + // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + bResult = _processPTRAnswer((stcRRAnswerPTR*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new SRV or TXT answers to be linked to queries + } + // 2. level answers + // SRV -> host domain and port + else if (enuAnswerType::SRV == pRRAnswer->answerType()) + { + // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + bResult = _processSRVAnswer((stcRRAnswerSRV*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new A/AAAA answers to be linked to queries + } + // TXT -> Txts + else if (enuAnswerType::TXT == pRRAnswer->answerType()) + { + // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 + bResult = _processTXTAnswer((stcRRAnswerTXT*)pRRAnswer); + } + // 3. level answers +#ifdef MDNS_IPV4_SUPPORT + // A -> IPv4Address + else if (enuAnswerType::A == pRRAnswer->answerType()) + { + // eg. esp8266.local A xxxx xx 192.168.2.120 + bResult = _processAAnswer((stcRRAnswerA*)pRRAnswer); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + // AAAA -> IPv6Address + else if (enuAnswerType::AAAA == pRRAnswer->answerType()) + { + // eg. esp8266.local AAAA xxxx xx 09cf::0c + bResult = _processAAAAAnswer((stcRRAnswerAAAA*)pRRAnswer); + } +#endif + + // Finally check for probing conflicts + // Host domain + if ((enuProbingStatus::InProgress == m_HostProbeInformation.m_ProbingStatus) && + ((enuAnswerType::A == pRRAnswer->answerType()) || + (enuAnswerType::AAAA == pRRAnswer->answerType()))) + { + + stcRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (pRRAnswer->m_Header.m_Domain == hostDomain)) + { + + bool bPossibleEcho = false; +#ifdef MDNS_IPV4_SUPPORT + if ((enuAnswerType::A == pRRAnswer->answerType()) && + (((stcRRAnswerA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V4))) + { + + bPossibleEcho = true; + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if ((enuAnswerType::AAAA == pRRAnswer->answerType()) && + (((stcRRAnswerAAAA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V6))) + { + + bPossibleEcho = true; + } +#endif + if (!bPossibleEcho) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s.local'\n"), _DH(), m_pcHostName);); + _cancelProbingForHost(); + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Ignoring CONFLICT found with '%s.local' as echo!\n"), _DH(), m_pcHostName);); + } + } + } + // Service domains + for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + { + if ((enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && + ((enuAnswerType::TXT == pRRAnswer->answerType()) || + (enuAnswerType::SRV == pRRAnswer->answerType()))) + { + + stcRRDomain serviceDomain; + if ((_buildDomainForService(*pService, true, serviceDomain)) && + (pRRAnswer->m_Header.m_Domain == serviceDomain)) + { + + // TODO: Echo management needed? + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s'\n"), _DH(), _service2String(pService));); + _cancelProbingForService(*pService); + } + } + } + + pRRAnswer = pRRAnswer->m_pNext; // Next collected answer + } // while (answers) + } while ((bFoundNewKeyAnswer) && + (bResult)); + } // else: No answers provided + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::clsHost::_processPTRAnswer (level 1) +*/ +bool MDNSResponder::clsHost::_processPTRAnswer(const MDNSResponder::clsHost::stcRRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pPTRAnswer))) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: Processing PTR answers...\n"), _DH());); + // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + // Check pending service queries for eg. '_http._tcp' + + stcQuery* pQuery = _findNextQueryByDomain(p_pPTRAnswer->m_Header.m_Domain, stcQuery::enuQueryType::Service, 0); + while (pQuery) + { + if (pQuery->m_bAwaitingAnswers) + { + // Find answer for service domain (eg. MyESP._http._tcp.local) + stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pPTRAnswer->m_PTRDomain); + if (pSQAnswer) // existing answer + { + if (p_pPTRAnswer->m_u32TTL) // Received update message + { + pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: Updated TTL(%lu) for "), _DH(), p_pPTRAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + else // received goodbye-message + { + pSQAnswer->m_TTLServiceDomain.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + } + else if ((p_pPTRAnswer->m_u32TTL) && // Not just a goodbye-message + ((pSQAnswer = new stcQuery::stcAnswer))) // Not yet included -> add answer + { + pSQAnswer->m_ServiceDomain = p_pPTRAnswer->m_PTRDomain; + pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::ServiceDomain); + pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); + //pSQAnswer->releaseServiceDomain(); + + bResult = pQuery->addAnswer(pSQAnswer); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: Added service domain to answer: "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.println(); + ); + + p_rbFoundNewKeyAnswer = true; + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::ServiceDomain), true); + } + } + pQuery = _findNextQueryByDomain(p_pPTRAnswer->m_Header.m_Domain, stcQuery::enuQueryType::Service, pQuery); + } + } // else: No p_pPTRAnswer + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::clsHost::_processSRVAnswer (level 2) +*/ +bool MDNSResponder::clsHost::_processSRVAnswer(const MDNSResponder::clsHost::stcRRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pSRVAnswer))) + { + // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + + stcQuery* pQuery = m_pQueries; + while (pQuery) + { + if (pQuery->m_bAwaitingAnswers) + { + stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pSRVAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available + { + if (p_pSRVAnswer->m_u32TTL) // First or update message (TTL != 0) + { + pSQAnswer->m_TTLHostDomainAndPort.set(p_pSRVAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: Updated TTL(%lu) for "), _DH(), p_pSRVAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + ); + // Host domain & Port + if ((pSQAnswer->m_HostDomain != p_pSRVAnswer->m_SRVDomain) || + (pSQAnswer->m_u16Port != p_pSRVAnswer->m_u16Port)) + { + + pSQAnswer->m_HostDomain = p_pSRVAnswer->m_SRVDomain; + //pSQAnswer->releaseHostDomain(); + pSQAnswer->m_u16Port = p_pSRVAnswer->m_u16Port; + pSQAnswer->m_QueryAnswerFlags |= (static_cast(enuQueryAnswerType::HostDomain) | static_cast(enuQueryAnswerType::Port)); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processSVRAnswer: Added host domain and port to "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(": ")); + _printRRDomain(pSQAnswer->m_HostDomain); + DEBUG_OUTPUT.printf_P(PSTR(": %u\n"), pSQAnswer->m_u16Port); + ); + + p_rbFoundNewKeyAnswer = true; + _executeQueryCallback(*pQuery, *pSQAnswer, (static_cast(enuQueryAnswerType::HostDomain) | static_cast(enuQueryAnswerType::Port)), true); + } + } + else // Goodby message + { + pSQAnswer->m_TTLHostDomainAndPort.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + ); + } + } + } // m_bAwaitingAnswers + pQuery = pQuery->m_pNext; + } // while(service query) + } // else: No p_pSRVAnswer + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::clsHost::_processTXTAnswer (level 2) +*/ +bool MDNSResponder::clsHost::_processTXTAnswer(const MDNSResponder::clsHost::stcRRAnswerTXT* p_pTXTAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pTXTAnswer))) + { + // eg. MyESP._http._tcp.local TXT xxxx xx c#=1 + + stcQuery* pQuery = m_pQueries; + while (pQuery) + { + if (pQuery->m_bAwaitingAnswers) + { + stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pTXTAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available + { + if (p_pTXTAnswer->m_u32TTL) // First or update message + { + pSQAnswer->m_TTLTxts.set(p_pTXTAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: Updated TTL(%lu) for "), _DH(), p_pTXTAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + ); + if (!pSQAnswer->m_Txts.compare(p_pTXTAnswer->m_Txts)) + { + pSQAnswer->m_Txts = p_pTXTAnswer->m_Txts; + pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::Txts); + //pSQAnswer->releaseTxts(); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: Added TXT to "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.println(); + ); + + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::Txts), true); + } + } + else // Goodby message + { + pSQAnswer->m_TTLTxts.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + ); + } + } + } // m_bAwaitingAnswers + pQuery = pQuery->m_pNext; + } // while(service query) + } // else: No p_pTXTAnswer + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: FAILED!\n"), _DH());); + return bResult; +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::clsHost::_processAAnswer (level 3) +*/ +bool MDNSResponder::clsHost::_processAAnswer(const MDNSResponder::clsHost::stcRRAnswerA* p_pAAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pAAnswer))) + { + // eg. esp8266.local A xxxx xx 192.168.2.120 + + stcQuery* pQuery = m_pQueries; + while (pQuery) + { + if (pQuery->m_bAwaitingAnswers) + { + // Look for answers to host queries + if ((p_pAAnswer->m_u32TTL) && // NOT just a goodbye message + (stcQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query + (pQuery->m_Domain == p_pAAnswer->m_Header.m_Domain)) // AND a matching host domain + { + + stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); + if ((!pSQAnswer) && + ((pSQAnswer = new stcQuery::stcAnswer))) + { + // Add not yet included answer + pSQAnswer->m_HostDomain = p_pAAnswer->m_Header.m_Domain; + //pSQAnswer->releaseHostDomain(); + + bResult = pQuery->addAnswer(pSQAnswer); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Added host query answer for "), _DH()); + _printRRDomain(pQuery->m_Domain); + DEBUG_OUTPUT.println(); + ); + + pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::HostDomain); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::HostDomain), true); + } + } + + // Look for answers to service queries + stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available + { + stcQuery::stcAnswer::stcIPAddress* pIPAddress = pSQAnswer->findIPv4Address(p_pAAnswer->m_IPAddress); + if (pIPAddress) + { + // Already known IPv4 address + if (p_pAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL + { + pIPAddress->m_TTL.set(p_pAAnswer->m_u32TTL); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Updated TTL(%lu) for "), _DH(), p_pAAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + } + else // 'Goodbye' message for known IPv4 address + { + pIPAddress->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + } + } + else + { + // Until now unknown IPv4 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAnswer->m_u32TTL) // NOT just a 'Goodbye' message + { + pIPAddress = new stcQuery::stcAnswer::stcIPAddress(p_pAAnswer->m_IPAddress, p_pAAnswer->m_u32TTL); + if ((pIPAddress) && + (pSQAnswer->addIPv4Address(pIPAddress))) + { + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Added IPv4 address to "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(": %s\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + + pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::IPv4Address); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::IPv4Address), true); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: FAILED to add IPv4 address (%s)!\n"), _DH(), p_pAAnswer->m_IPAddress.toString().c_str());); + } + } + } + } + } // m_bAwaitingAnswers + pQuery = pQuery->m_pNext; + } // while(service query) + } // else: No p_pAAnswer + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: FAILED!\n"), _DH());); + return bResult; +} +#endif + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::clsHost::_processAAAAAnswer (level 3) +*/ +bool MDNSResponder::clsHost::_processAAAAAnswer(const MDNSResponder::clsHost::stcRRAnswerAAAA* p_pAAAAAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pAAAAAnswer))) + { + // eg. esp8266.local AAAA xxxx xx 0bf3::0c + + stcQuery* pQuery = m_pQueries; + while (pQuery) + { + if (pQuery->m_bAwaitingAnswers) + { + // Look for answers to host queries + if ((p_pAAAAAnswer->m_u32TTL) && // NOT just a goodbye message + (stcQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query + (pQuery->m_Domain == p_pAAAAAnswer->m_Header.m_Domain)) // AND a matching host domain + { + + stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); + if ((!pSQAnswer) && + ((pSQAnswer = new stcQuery::stcAnswer))) + { + // Add not yet included answer + pSQAnswer->m_HostDomain = p_pAAAAAnswer->m_Header.m_Domain; + //pSQAnswer->releaseHostDomain(); + + bResult = pQuery->addAnswer(pSQAnswer); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Added host query answer for "), _DH()); + _printRRDomain(pQuery->m_Domain); + DEBUG_OUTPUT.println(); + ); + + pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::HostDomain); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::HostDomain), true); + } + } + + // Look for answers to service queries + stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available + { + stcQuery::stcAnswer::stcIPAddress* pIPAddress = pSQAnswer->findIPv6Address(p_pAAAAAnswer->m_IPAddress); + if (pIPAddress) + { + // Already known IPv6 address + if (p_pAAAAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL + { + pIPAddress->m_TTL.set(p_pAAAAAnswer->m_u32TTL); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Updated TTL(%lu) for "), _DH(), p_pAAAAAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + } + else // 'Goodbye' message for known IPv6 address + { + pIPAddress->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + } + } + else + { + // Until now unknown IPv6 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAAAAnswer->m_u32TTL) // NOT just a 'Goodbye' message + { + pIPAddress = new stcQuery::stcAnswer::stcIPAddress(p_pAAAAAnswer->m_IPAddress, p_pAAAAAnswer->m_u32TTL); + if ((pIPAddress) && + (pSQAnswer->addIPv6Address(pIPAddress))) + { + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Added IPv6 address to "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(": %s\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + + pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::IPv6Address); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::IPv6Address), true); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: FAILED to add IPv6 address (%s)!\n"), _DH(), p_pAAAAAnswer->m_IPAddress.toString().c_str());); + } + } + } + } + } // m_bAwaitingAnswers + pQuery = pQuery->m_pNext; + } // while(service query) + } // else: No p_pAAAAAnswer + + return bResult; +} +#endif + + +/* + PROBING +*/ + +/* + MDNSResponder::clsHost::_updateProbeStatus + + Manages the (outgoing) probing process. + - If probing has not been started yet (ProbingStatus_NotStarted), the initial delay (see RFC 6762) is determined and + the process is started + - After timeout (of initial or subsequential delay) a probe message is send out for three times. If the message has + already been sent out three times, the probing has been successful and is finished. + + Conflict management is handled in '_parseResponse ff.' + Tiebraking is handled in 'parseQuery ff.' +*/ +bool MDNSResponder::clsHost::_updateProbeStatus(void) +{ + bool bResult = true; + + // + // Probe host domain + if ((enuProbingStatus::ReadyToStart == m_HostProbeInformation.m_ProbingStatus) && // Ready to get started AND + (( +#ifdef MDNS_IPV4_SUPPORT + _getResponderIPAddress(enuIPProtocolType::V4).isSet() // AND has IPv4 address +#else + true +#endif + ) || ( +#ifdef MDNS_IPV6_SUPPORT + _getResponderIPAddress(enuIPProtocolType::V6).isSet() // OR has IPv6 address +#else + true +#endif + ))) // Has IP address + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Starting host probing...\n"), _DH());); + + // First probe delay SHOULD be random 0-250 ms + m_HostProbeInformation.m_Timeout.reset(rand() % MDNS_PROBE_DELAY); + m_HostProbeInformation.m_ProbingStatus = enuProbingStatus::InProgress; + } + else if ((enuProbingStatus::InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing AND + (m_HostProbeInformation.m_Timeout.expired())) // Time for next probe + { + + if (MDNS_PROBE_COUNT > m_HostProbeInformation.m_u8SentCount) // Send next probe + { + if ((bResult = _sendHostProbe())) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Did sent host probe for '%s.local'\n\n"), _DH(), (m_pcHostName ? : ""));); + m_HostProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); + ++m_HostProbeInformation.m_u8SentCount; + } + } + else // Probing finished + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("\n%s _updateProbeStatus: Done host probing for '%s.local'.\n\n\n"), _DH(), (m_pcHostName ? : ""));); + m_HostProbeInformation.m_ProbingStatus = enuProbingStatus::Done; + m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + + _callHostProbeResultCallback(true); + + // Prepare to announce host + m_HostProbeInformation.m_u8SentCount = 0; + m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Prepared host announcing.\n\n"), _DH());); + } + } // else: Probing already finished OR waiting for next time slot + else if ((enuProbingStatus::Done == m_HostProbeInformation.m_ProbingStatus) && + (m_HostProbeInformation.m_Timeout.expired())) + { + + if ((bResult = _announce(true, false))) // Don't announce services here + { + ++m_HostProbeInformation.m_u8SentCount; // 1.. + + if (MDNS_ANNOUNCE_COUNT > m_HostProbeInformation.m_u8SentCount) + { + m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY * pow(2, (m_HostProbeInformation.m_u8SentCount - 1))); // 2^(0..) -> 1, 2, 4, ... + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Announcing host '%s.local' (%lu).\n\n"), _DH(), (m_pcHostName ? : ""), m_HostProbeInformation.m_u8SentCount);); + } + else + { + m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done host announcing for '%s.local'.\n\n"), _DH(), (m_pcHostName ? : ""));); + } + } + } + + // + // Probe services + for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if (enuProbingStatus::ReadyToStart == pService->m_ProbeInformation.m_ProbingStatus) // Ready to get started + { + + pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); // More or equal than first probe for host domain + pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::InProgress; + } + else if ((enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND + (pService->m_ProbeInformation.m_Timeout.expired())) // Time for next probe + { + + if (MDNS_PROBE_COUNT > pService->m_ProbeInformation.m_u8SentCount) // Send next probe + { + if ((bResult = _sendServiceProbe(*pService))) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Did sent service probe for '%s' (%u)\n\n"), _DH(), _service2String(pService), (pService->m_ProbeInformation.m_u8SentCount + 1));); + pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); + ++pService->m_ProbeInformation.m_u8SentCount; + } + } + else // Probing finished + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("\n%s _updateProbeStatus: Done service probing '%s'\n\n\n"), _DH(), _service2String(pService));); + pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::Done; + pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + + _callServiceProbeResultCallback(*pService, true); + + // Prepare to announce service + pService->m_ProbeInformation.m_u8SentCount = 0; + pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Prepared service announcing.\n\n"), _DH());); + } + } // else: Probing already finished OR waiting for next time slot + else if ((enuProbingStatus::Done == pService->m_ProbeInformation.m_ProbingStatus) && + (pService->m_ProbeInformation.m_Timeout.expired())) + { + + if ((bResult = _announceService(*pService))) // Announce service + { + ++pService->m_ProbeInformation.m_u8SentCount; // 1.. + + if (MDNS_ANNOUNCE_COUNT > pService->m_ProbeInformation.m_u8SentCount) + { + pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY * pow(2, (pService->m_ProbeInformation.m_u8SentCount - 1))); // 2^(0..) -> 1, 2, 4, ... + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Announcing service '%s' (%lu)\n\n"), _DH(), _service2String(pService), pService->m_ProbeInformation.m_u8SentCount);); + } + else + { + pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done service announcing for '%s'\n\n"), _DH(), _service2String(pService));); + } + } + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: FAILED!\n\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::clsHost::_resetProbeStatus + + Resets the probe status. + If 'p_bRestart' is set, the status is set to ProbingStatus_NotStarted. Consequently, + when running 'updateProbeStatus' (which is done in every '_update' loop), the probing + process is restarted. +*/ +bool MDNSResponder::clsHost::_resetProbeStatus(bool p_bRestart /*= true*/) +{ + m_HostProbeInformation.clear(false); + m_HostProbeInformation.m_ProbingStatus = (p_bRestart ? enuProbingStatus::ReadyToStart : enuProbingStatus::Done); + + for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + { + pService->m_ProbeInformation.clear(false); + pService->m_ProbeInformation.m_ProbingStatus = (p_bRestart ? enuProbingStatus::ReadyToStart : enuProbingStatus::Done); + } + return true; +} + +/* + MDNSResponder::clsHost::_hasProbesWaitingForAnswers +*/ +bool MDNSResponder::clsHost::_hasProbesWaitingForAnswers(void) const +{ + bool bResult = ((enuProbingStatus::InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing + (0 < m_HostProbeInformation.m_u8SentCount)); // And really probing + + for (stcService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) + { + bResult = ((enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing + (0 < pService->m_ProbeInformation.m_u8SentCount)); // And really probing + } + return bResult; +} + +/* + MDNSResponder::clsHost::_sendHostProbe + + Asks (probes) in the local network for the planned host domain + - (eg. esp8266.local) + + To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in + the 'knwon answers' section of the query. + Host domain: + - A/AAAA (eg. esp8266.esp -> 192.168.2.120) +*/ +bool MDNSResponder::clsHost::_sendHostProbe(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendHostProbe (%s.local, %lu)\n"), _DH(), m_pcHostName, millis());); + + bool bResult = true; + + // Requests for host domain + stcSendParameter sendParameter; + sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 + + sendParameter.m_pQuestions = new stcRRQuestion; + if (((bResult = (0 != sendParameter.m_pQuestions))) && + ((bResult = _buildDomainForHost(m_pcHostName, sendParameter.m_pQuestions->m_Header.m_Domain)))) + { + + //sendParameter.m_pQuestions->m_bUnicast = true; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + + // Add known answers +#ifdef MDNS_IPV4_SUPPORT + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::A); // Add A answer +#endif +#ifdef MDNS_IPV6_SUPPORT + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::AAAA); // Add AAAA answer +#endif + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _sendHostProbe: FAILED to create host question!\n"), _DH());); + if (sendParameter.m_pQuestions) + { + delete sendParameter.m_pQuestions; + sendParameter.m_pQuestions = 0; + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendHostProbe: FAILED!\n"), _DH());); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + +/* + MDNSResponder::clsHost::_sendServiceProbe + + Asks (probes) in the local network for the planned service instance domain + - (eg. MyESP._http._tcp.local). + + To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in + the 'knwon answers' section of the query. + Service domain: + - SRV (eg. MyESP._http._tcp.local -> 5000 esp8266.local) + - PTR NAME (eg. _http._tcp.local -> MyESP._http._tcp.local) (TODO: Check if needed, maybe TXT is better) +*/ +bool MDNSResponder::clsHost::_sendServiceProbe(stcService& p_rService) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendServiceProbe (%s, %lu)\n"), _DH(), _service2String(&p_rService), millis());); + + bool bResult = true; + + // Requests for service instance domain + stcSendParameter sendParameter; + sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 + + sendParameter.m_pQuestions = new stcRRQuestion; + if (((bResult = (0 != sendParameter.m_pQuestions))) && + ((bResult = _buildDomainForService(p_rService, true, sendParameter.m_pQuestions->m_Header.m_Domain)))) + { + + sendParameter.m_pQuestions->m_bUnicast = true; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + + // Add known answers + p_rService.m_u32ReplyMask = (static_cast(enuContentFlag::SRV) | static_cast(enuContentFlag::PTR_NAME)); // Add SRV and PTR NAME answers + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _sendServiceProbe: FAILED to create service question!\n"), _DH());); + if (sendParameter.m_pQuestions) + { + delete sendParameter.m_pQuestions; + sendParameter.m_pQuestions = 0; + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendServiceProbe: FAILED!\n"), _DH());); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + +/* + MDNSResponder::clsHost::_cancelProbingForHost +*/ +bool MDNSResponder::clsHost::_cancelProbingForHost(void) +{ + bool bResult = false; + + m_HostProbeInformation.clear(false); + + // Send host notification + bResult = _callHostProbeResultCallback(false); + + for (stcService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) + { + bResult = _cancelProbingForService(*pService); + } + return bResult; +} + +/* + MDNSResponder::clsHost::_cancelProbingForService +*/ +bool MDNSResponder::clsHost::_cancelProbingForService(stcService& p_rService) +{ + p_rService.m_ProbeInformation.clear(false); + + // Send notification + return _callServiceProbeResultCallback(p_rService, false); +} + +/* + MDNSResponder::clsHost::_callHostProbeResultCallback + +*/ +bool MDNSResponder::clsHost::_callHostProbeResultCallback(bool p_bResult) +{ + if (m_HostProbeInformation.m_fnProbeResultCallback) + { + m_HostProbeInformation.m_fnProbeResultCallback(*this, m_pcHostName, p_bResult); + } + else if (!p_bResult) + { + // Auto-Handle failure by changing the host name, use '-' as divider between base name and index + char* pcHostDomainTemp = strdup(m_pcHostName); + if (pcHostDomainTemp) + { + if (MDNSResponder::indexDomain(pcHostDomainTemp, "-", 0)) + { + setHostName(pcHostDomainTemp); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _callHostProbeResultCallback: FAILED to update host domain '%s'!\n"), _DH(), (m_pcHostName ? : ""));); + } + free(pcHostDomainTemp); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _callHostProbeResultCallback: FAILED to copy host domain '%s'!\n"), _DH(), (m_pcHostName ? : ""));); + } + } + return true; +} + +/* + MDNSResponder::clsHost::_callServiceProbeResultCallback + +*/ +bool MDNSResponder::clsHost::_callServiceProbeResultCallback(MDNSResponder::clsHost::stcService& p_rService, + bool p_bResult) +{ + if (p_rService.m_ProbeInformation.m_fnProbeResultCallback) + { + p_rService.m_ProbeInformation.m_fnProbeResultCallback(*this, p_rService, p_rService.m_pcName, p_bResult); + } + else if (!p_bResult) + { + // Auto-Handle failure by changing the service name, use ' #' as divider between base name and index + char* pcServiceNameTemp = strdup(p_rService.m_pcName); + if (pcServiceNameTemp) + { + if (MDNSResponder::indexDomain(pcServiceNameTemp, " #", 0)) + { + setServiceName(&p_rService, pcServiceNameTemp); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _callServiceProbeResultCallback: FAILED to update service name for '%s'!\n"), _DH(), _service2String(&p_rService));); + } + free(pcServiceNameTemp); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _callServiceProbeResultCallback: FAILED to copy service name for '%s'!\n"), _DH(), _service2String(&p_rService));); + } + } + return true; +} + + +/** + ANNOUNCING +*/ + +/* + MDNSResponder::clsHost::_announce + + Announces the host domain: + - A/AAAA (eg. esp8266.local -> 192.168.2.120) + - PTR (eg. 192.168.2.120.in-addr.arpa -> esp8266.local) + + and all presented services: + - PTR_TYPE (_services._dns-sd._udp.local -> _http._tcp.local) + - PTR_NAME (eg. _http._tcp.local -> MyESP8266._http._tcp.local) + - SRV (eg. MyESP8266._http._tcp.local -> 5000 esp8266.local) + - TXT (eg. MyESP8266._http._tcp.local -> c#=1) + + Goodbye (Un-Announcing) for the host domain and all services is also handled here. + Goodbye messages are created by setting the TTL for the answer to 0, this happens + inside the '_writeXXXAnswer' procs via 'sendParameter.m_bUnannounce = true' +*/ +bool MDNSResponder::clsHost::_announce(bool p_bAnnounce, + bool p_bIncludeServices) +{ + bool bResult = false; + + stcSendParameter sendParameter; + if (enuProbingStatus::Done == m_HostProbeInformation.m_ProbingStatus) + { + bResult = true; + + sendParameter.m_Response = stcSendParameter::enuResponseType::Unsolicited; // Announces are 'Unsolicited authorative responses' + sendParameter.m_bAuthorative = true; + sendParameter.m_bCacheFlush = true; // RFC 6762 8.3 + sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers + + // Announce host + sendParameter.m_u32HostReplyMask = 0; +#ifdef MDNS_IPV4_SUPPORT + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::A); // A answer + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::PTR_IPv4); // PTR_IPv4 answer +#endif +#ifdef MDNS_IPV6_SUPPORT + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::AAAA); // AAAA answer + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::PTR_IPv6); // PTR_IPv6 answer +#endif + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _announce: Announcing host %s (content: %s)\n"), _DH(), m_pcHostName, _replyFlags2String(sendParameter.m_u32HostReplyMask));); + + if (p_bIncludeServices) + { + // Announce services (service type, name, SRV (location) and TXTs) + for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if (enuProbingStatus::Done == pService->m_ProbeInformation.m_ProbingStatus) + { + pService->m_u32ReplyMask = (static_cast(enuContentFlag::PTR_TYPE) | static_cast(enuContentFlag::PTR_NAME) | static_cast(enuContentFlag::SRV) | static_cast(enuContentFlag::TXT)); + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _announce: Announcing service '%s' (content %s)\n"), _DH(), _service2String(pService), _replyFlags2String(pService->m_u32ReplyMask));); + } + } + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _announce: FAILED!\n"), _DH());); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + +/* + MDNSResponder::clsHost::_announceService +*/ +bool MDNSResponder::clsHost::_announceService(MDNSResponder::clsHost::stcService& p_rService, + bool p_bAnnounce /*= true*/) +{ + bool bResult = false; + + stcSendParameter sendParameter; + if (enuProbingStatus::Done == p_rService.m_ProbeInformation.m_ProbingStatus) + { + + sendParameter.m_Response = stcSendParameter::enuResponseType::Unsolicited; // Announces are 'Unsolicited authorative responses' + sendParameter.m_bAuthorative = true; + sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers + + // DON'T announce host + sendParameter.m_u32HostReplyMask = 0; + + // Announce services (service type, name, SRV (location) and TXTs) + p_rService.m_u32ReplyMask = (static_cast(enuContentFlag::PTR_TYPE) | static_cast(enuContentFlag::PTR_NAME) | static_cast(enuContentFlag::SRV) | static_cast(enuContentFlag::TXT)); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _announceService: Announcing service '%s' (content: %s)\n"), _DH(), _service2String(&p_rService), _replyFlags2String(p_rService.m_u32ReplyMask));); + + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _announceService: FAILED!\n"), _DH());); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + + +/** + QUERY CACHE +*/ + +/* + MDNSResponder::clsHost::_checkQueryCache + + For any 'living' query (m_bAwaitingAnswers == true) all available answers (their components) + are checked for topicality based on the stored reception time and the answers TTL. + When the components TTL is outlasted by more than 80%, a new question is generated, to get updated information. + When no update arrived (in time), the component is removed from the answer (cache). + +*/ +bool MDNSResponder::clsHost::_checkQueryCache(void) +{ + bool bResult = true; + + DEBUG_EX_INFO( + bool printedInfo = false; + ); + for (stcQuery* pQuery = m_pQueries; ((bResult) && (pQuery)); pQuery = pQuery->m_pNext) + { + // + // Resend dynamic queries, if not already done often enough + if ((!pQuery->m_bLegacyQuery) && + (pQuery->m_ResendTimeout.expired())) + { + + if ((bResult = _sendMDNSQuery(*pQuery))) + { + // The re-query rate is increased to more than one hour (RFC 6762 5.2) + ++pQuery->m_u8SentCount; + uint32_t u32NewDelay = (MDNS_DYNAMIC_QUERY_RESEND_DELAY * pow(2, std::min((pQuery->m_u8SentCount - 1), 12))); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Next query in %u seconds!\n"), _DH(), (u32NewDelay));); + pQuery->m_ResendTimeout.reset(u32NewDelay); + } + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: %s to resend query!\n"), _DH(), (bResult ? "Succeeded" : "FAILED")); + printedInfo = true; + ); + } + + // + // Schedule updates for cached answers + if (pQuery->m_bAwaitingAnswers) + { + stcQuery::stcAnswer* pSQAnswer = pQuery->m_pAnswers; + while ((bResult) && + (pSQAnswer)) + { + stcQuery::stcAnswer* pNextSQAnswer = pSQAnswer->m_pNext; + + // 1. level answer + if ((bResult) && + (pSQAnswer->m_TTLServiceDomain.flagged())) + { + + if (!pSQAnswer->m_TTLServiceDomain.finalTimeoutLevel()) + { + + bResult = ((_sendMDNSQuery(*pQuery)) && + (pSQAnswer->m_TTLServiceDomain.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: PTR update scheduled for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::ServiceDomain), false); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove PTR answer for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + printedInfo = true; + ); + + bResult = pQuery->removeAnswer(pSQAnswer); + pSQAnswer = 0; + continue; // Don't use this answer anymore + } + } // ServiceDomain flagged + + // 2. level answers + // HostDomain & Port (from SRV) + if ((bResult) && + (pSQAnswer->m_TTLHostDomainAndPort.flagged())) + { + + if (!pSQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) + { + + bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_SRV)) && + (pSQAnswer->m_TTLHostDomainAndPort.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: SRV update scheduled for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove SRV answer for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + printedInfo = true; + ); + // Delete + pSQAnswer->m_HostDomain.clear(); + //pSQAnswer->releaseHostDomain(); + pSQAnswer->m_u16Port = 0; + pSQAnswer->m_TTLHostDomainAndPort.set(0); + typeQueryAnswerType queryAnswerContentFlags = (static_cast(enuQueryAnswerType::HostDomain) | static_cast(enuQueryAnswerType::Port)); + // As the host domain is the base for the IPv4- and IPv6Address, remove these too +#ifdef MDNS_IPV4_SUPPORT + pSQAnswer->releaseIPv4Addresses(); + queryAnswerContentFlags |= static_cast(enuQueryAnswerType::IPv4Address); +#endif +#ifdef MDNS_IPV6_SUPPORT + pSQAnswer->releaseIPv6Addresses(); + queryAnswerContentFlags |= static_cast(enuQueryAnswerType::IPv6Address); +#endif + + // Remove content flags for deleted answer parts + pSQAnswer->m_QueryAnswerFlags &= ~queryAnswerContentFlags; + _executeQueryCallback(*pQuery, *pSQAnswer, queryAnswerContentFlags, false); + } + } // HostDomainAndPort flagged + + // Txts (from TXT) + if ((bResult) && + (pSQAnswer->m_TTLTxts.flagged())) + { + + if (!pSQAnswer->m_TTLTxts.finalTimeoutLevel()) + { + + bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_TXT)) && + (pSQAnswer->m_TTLTxts.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: TXT update scheduled for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove TXT answer for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + printedInfo = true; + ); + // Delete + pSQAnswer->m_Txts.clear(); + pSQAnswer->m_TTLTxts.set(0); + + // Remove content flags for deleted answer parts + pSQAnswer->m_QueryAnswerFlags &= ~static_cast(enuQueryAnswerType::Txts); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::Txts), false); + } + } // TXTs flagged + + // 3. level answers +#ifdef MDNS_IPV4_SUPPORT + // IPv4Address (from A) + stcQuery::stcAnswer::stcIPAddress* pIPv4Address = pSQAnswer->m_pIPv4Addresses; + bool bAUpdateQuerySent = false; + while ((pIPv4Address) && + (bResult)) + { + + stcQuery::stcAnswer::stcIPAddress* pNextIPv4Address = pIPv4Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... + + if (pIPv4Address->m_TTL.flagged()) + { + + if (!pIPv4Address->m_TTL.finalTimeoutLevel()) // Needs update + { + + if ((bAUpdateQuerySent) || + ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_A)))) + { + + pIPv4Address->m_TTL.restart(); + bAUpdateQuerySent = true; + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: IPv4 update scheduled for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address (%s)\n"), (pIPv4Address->m_IPAddress.toString().c_str())); + printedInfo = true; + ); + } + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove IPv4 answer for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address\n")); + printedInfo = true; + ); + pSQAnswer->removeIPv4Address(pIPv4Address); + if (!pSQAnswer->m_pIPv4Addresses) // NO IPv4 address left -> remove content flag + { + pSQAnswer->m_QueryAnswerFlags &= ~static_cast(enuQueryAnswerType::IPv4Address); + } + // Notify client + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::IPv4Address), false); + } + } // IPv4 flagged + + pIPv4Address = pNextIPv4Address; // Next + } // while +#endif +#ifdef MDNS_IPV6_SUPPORT + // IPv6Address (from AAAA) + stcQuery::stcAnswer::stcIPAddress* pIPv6Address = pSQAnswer->m_pIPv6Addresses; + bool bAAAAUpdateQuerySent = false; + while ((pIPv6Address) && + (bResult)) + { + + stcQuery::stcAnswer::stcIPAddress* pNextIPv6Address = pIPv6Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... + + if (pIPv6Address->m_TTL.flagged()) + { + + if (!pIPv6Address->m_TTL.finalTimeoutLevel()) // Needs update + { + + if ((bAAAAUpdateQuerySent) || + ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) + { + + pIPv6Address->m_TTL.restart(); + bAAAAUpdateQuerySent = true; + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: IPv6 update scheduled for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address (%s)\n"), (pIPv6Address->m_IPAddress.toString().c_str())); + printedInfo = true; + ); + } + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove answer for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address\n")); + printedInfo = true; + ); + pSQAnswer->removeIPv6Address(pIPv6Address); + if (!pSQAnswer->m_pIPv6Addresses) // NO IPv6 address left -> remove content flag + { + pSQAnswer->m_QueryAnswerFlags &= ~static_cast(enuQueryAnswerType::IPv6Address); + } + // Notify client + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::IPv6Address), false); + } + } // IPv6 flagged + + pIPv6Address = pNextIPv6Address; // Next + } // while +#endif + pSQAnswer = pNextSQAnswer; + } + } + } + DEBUG_EX_INFO(if (printedInfo) DEBUG_OUTPUT.printf_P(PSTR("\n"));); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: FAILED!\n"), _DH());); + return bResult; +} + + +/* + MDNSResponder::clsHost::_replyMaskForHost + + Determines the relavant host answers for the given question. + - A question for the hostname (eg. esp8266.local) will result in an A/AAAA (eg. 192.168.2.129) reply. + - A question for the reverse IP address (eg. 192-168.2.120.inarpa.arpa) will result in an PTR_IPv4 (eg. esp8266.local) reply. + + In addition, a full name match (question domain == host domain) is marked. +*/ +uint32_t MDNSResponder::clsHost::_replyMaskForHost(const MDNSResponder::clsHost::stcRRHeader& p_RRHeader, + bool* p_pbFullNameMatch /*= 0*/) const +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForHost\n"));); + + uint32_t u32ReplyMask = 0; + (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); + + if ((DNS_RRCLASS_IN == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000))) || + (DNS_RRCLASS_ANY == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000)))) + { + + if ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // PTR request +#ifdef MDNS_IPV4_SUPPORT + stcRRDomain reverseIPv4Domain; + if ((_getResponderIPAddress(enuIPProtocolType::V4).isSet()) && + (_buildDomainForReverseIPv4(_getResponderIPAddress(enuIPProtocolType::V4), reverseIPv4Domain)) && + (p_RRHeader.m_Domain == reverseIPv4Domain)) + { + // Reverse domain match + u32ReplyMask |= static_cast(enuContentFlag::PTR_IPv4); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + stcRRDomain reverseIPv6Domain; + if ((_getResponderIPAddress(enuIPProtocolType::V6).isSet()) && + (_buildDomainForReverseIPv6(_getResponderIPAddress(enuIPProtocolType::V6), reverseIPv6Domain)) && + (p_RRHeader.m_Domain == reverseIPv6Domain)) + { + // Reverse domain match + u32ReplyMask |= static_cast(enuContentFlag::PTR_IPv6); + } +#endif + } // Address qeuest + + stcRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (p_RRHeader.m_Domain == hostDomain)) // Host domain match + { + + (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); + +#ifdef MDNS_IPV4_SUPPORT + if ((DNS_RRTYPE_A == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // IPv4 address request + u32ReplyMask |= static_cast(enuContentFlag::A); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if ((DNS_RRTYPE_AAAA == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // IPv6 address request + u32ReplyMask |= static_cast(enuContentFlag::AAAA); + } +#endif + } + } + else + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForHost: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); + } + DEBUG_EX_INFO(if (u32ReplyMask) DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForHost: %s\n"), _DH(), _replyFlags2String(u32ReplyMask));); + return u32ReplyMask; +} + +/* + MDNSResponder::clsHost::_replyMaskForService + + Determines the relevant service answers for the given question + - A PTR dns-sd service enum question (_services.dns-sd._udp.local) will result into an PTR_TYPE (eg. _http._tcp.local) answer + - A PTR service type question (eg. _http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer + - A PTR service name question (eg. MyESP._http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer + - A SRV service name question (eg. MyESP._http._tcp.local) will result into an SRV (eg. 5000 MyESP.local) answer + - A TXT service name question (eg. MyESP._http._tcp.local) will result into an TXT (eg. c#=1) answer + + In addition, a full name match (question domain == service instance domain) is marked. +*/ +uint32_t MDNSResponder::clsHost::_replyMaskForService(const MDNSResponder::clsHost::stcRRHeader& p_RRHeader, + const MDNSResponder::clsHost::stcService& p_Service, + bool* p_pbFullNameMatch /*= 0*/) const +{ + uint32_t u32ReplyMask = 0; + (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); + + if ((DNS_RRCLASS_IN == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000))) || + (DNS_RRCLASS_ANY == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000)))) + { + + stcRRDomain DNSSDDomain; + if ((_buildDomainForDNSSD(DNSSDDomain)) && // _services._dns-sd._udp.local + (p_RRHeader.m_Domain == DNSSDDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + { + // Common service info requested + u32ReplyMask |= static_cast(enuContentFlag::PTR_TYPE); + } + + stcRRDomain serviceDomain; + if ((_buildDomainForService(p_Service, false, serviceDomain)) && // eg. _http._tcp.local + (p_RRHeader.m_Domain == serviceDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + { + // Special service info requested + u32ReplyMask |= static_cast(enuContentFlag::PTR_NAME); + } + + if ((_buildDomainForService(p_Service, true, serviceDomain)) && // eg. MyESP._http._tcp.local + (p_RRHeader.m_Domain == serviceDomain)) + { + + (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); + + if ((DNS_RRTYPE_SRV == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // Instance info SRV requested + u32ReplyMask |= static_cast(enuContentFlag::SRV); + } + if ((DNS_RRTYPE_TXT == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // Instance info TXT requested + u32ReplyMask |= static_cast(enuContentFlag::TXT); + } + } + } + else + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForService: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); + } + DEBUG_EX_INFO(if (u32ReplyMask) DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForService(%s.%s.%s): %s\n"), _DH(), p_Service.m_pcName, p_Service.m_pcServiceType, p_Service.m_pcProtocol, _replyFlags2String(u32ReplyMask));); + return u32ReplyMask; +} + +} // namespace MDNSImplementation + +} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Debug.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Debug.cpp new file mode 100755 index 0000000000..3f43a54089 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Debug.cpp @@ -0,0 +1,327 @@ +/* + LEAmDNS2_Host_Debug.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +/* + ESP8266mDNS Control.cpp +*/ + +extern "C" { + //#include "user_interface.h" +} + +#include "LEAmDNS2_lwIPdefs.h" +#include "LEAmDNS2_Priv.h" + +#ifdef MDNS_IPV4_SUPPORT +//#include +#endif +#ifdef MDNS_IPV6_SUPPORT +//#include +#endif + + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace experimental +{ + +#ifdef DEBUG_ESP_MDNS_RESPONDER + +/* + MDNSResponder::clsHost::_DH +*/ +const char* MDNSResponder::clsHost::_DH(const MDNSResponder::clsHost::stcService* p_pMDNSService /*= 0*/) const +{ + static char acBuffer[16 + 64]; + + *acBuffer = 0; + if (p_pMDNSService) + { + sprintf_P(acBuffer, PSTR("[MDNSResponder (%c%c%u)->%s]"), m_rNetIf.name[0], m_rNetIf.name[1], m_rNetIf.num, _service2String(p_pMDNSService)); + } + else + { + sprintf_P(acBuffer, PSTR("[MDNSResponder (%c%c%u)]"), m_rNetIf.name[0], m_rNetIf.name[1], m_rNetIf.num); + } + return acBuffer; +} + +/* + MDNSResponder::clsHost::_service2String +*/ +const char* MDNSResponder::clsHost::_service2String(const MDNSResponder::clsHost::stcService* p_pMDNSService) const +{ + static char acBuffer[64]; + + *acBuffer = 0; + if (p_pMDNSService) + { + sprintf_P(acBuffer, PSTR("%s.%s%s.%s%s.local"), + (p_pMDNSService->m_pcName ? : "-"), + (p_pMDNSService->m_pcServiceType ? ('_' == *(p_pMDNSService->m_pcServiceType) ? "" : "_") : "-"), + (p_pMDNSService->m_pcServiceType ? : "-"), + (p_pMDNSService->m_pcProtocol ? ('_' == *(p_pMDNSService->m_pcProtocol) ? "" : "_") : "-"), + (p_pMDNSService->m_pcProtocol ? : "-")); + } + return acBuffer; +} + +/* + MDNSResponder::clsHost::_printRRDomain +*/ +bool MDNSResponder::clsHost::_printRRDomain(const MDNSResponder::clsHost::stcRRDomain& p_RRDomain) const +{ + //DEBUG_OUTPUT.printf_P(PSTR("Domain: ")); + + const char* pCursor = p_RRDomain.m_acName; + uint8_t u8Length = *pCursor++; + if (u8Length) + { + while (u8Length) + { + for (uint8_t u = 0; u < u8Length; ++u) + { + DEBUG_OUTPUT.printf_P(PSTR("%c"), *(pCursor++)); + } + u8Length = *pCursor++; + if (u8Length) + { + DEBUG_OUTPUT.printf_P(PSTR(".")); + } + } + } + else // empty domain + { + DEBUG_OUTPUT.printf_P(PSTR("-empty-")); + } + //DEBUG_OUTPUT.printf_P(PSTR("\n")); + + return true; +} + +/* + MDNSResponder::clsHost::_printRRAnswer +*/ +bool MDNSResponder::clsHost::_printRRAnswer(const MDNSResponder::clsHost::stcRRAnswer& p_RRAnswer) const +{ + DEBUG_OUTPUT.printf_P(PSTR("%s RRAnswer: "), _DH()); + _printRRDomain(p_RRAnswer.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, "), p_RRAnswer.m_Header.m_Attributes.m_u16Type, p_RRAnswer.m_Header.m_Attributes.m_u16Class, p_RRAnswer.m_u32TTL); + switch (p_RRAnswer.m_Header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IPV4_SUPPORT + case DNS_RRTYPE_A: + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((const stcRRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_PTR: + DEBUG_OUTPUT.printf_P(PSTR("PTR ")); + _printRRDomain(((const stcRRAnswerPTR*)&p_RRAnswer)->m_PTRDomain); + break; + case DNS_RRTYPE_TXT: + { + size_t stTxtLength = ((const stcRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength(); + char* pTxts = new char[stTxtLength]; + if (pTxts) + { + ((/*const c_str()!!*/stcRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts); + DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); + delete[] pTxts; + } + break; + } +#ifdef MDNS_IPV6_SUPPORT + case DNS_RRTYPE_AAAA: + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcRRAnswerAAAA*&)p_RRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_SRV: + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((const stcRRAnswerSRV*)&p_RRAnswer)->m_u16Port); + _printRRDomain(((const stcRRAnswerSRV*)&p_RRAnswer)->m_SRVDomain); + break; + default: + DEBUG_OUTPUT.printf_P(PSTR("generic ")); + break; + } + DEBUG_OUTPUT.printf_P(PSTR("\n")); + + return true; +} + +/* + MDNSResponder::clsHost::_RRType2Name +*/ +const char* MDNSResponder::clsHost::_RRType2Name(uint16_t p_u16RRType) const +{ + static char acRRName[16]; + *acRRName = 0; + + switch (p_u16RRType & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { + case DNS_RRTYPE_A: strcpy(acRRName, "A"); break; + case DNS_RRTYPE_PTR: strcpy(acRRName, "PTR"); break; + case DNS_RRTYPE_TXT: strcpy(acRRName, "TXT"); break; + case DNS_RRTYPE_AAAA: strcpy(acRRName, "AAAA"); break; + case DNS_RRTYPE_SRV: strcpy(acRRName, "SRV"); break; + case DNS_RRTYPE_NSEC: strcpy(acRRName, "NSEC"); break; + case DNS_RRTYPE_ANY: strcpy(acRRName, "ANY"); break; + default: + sprintf(acRRName, "Unknown(0x%04X)", p_u16RRType); // MAX 15! + } + return acRRName; +} + +/* + MDNSResponder::clsHost::_RRClass2String +*/ +const char* MDNSResponder::clsHost::_RRClass2String(uint16_t p_u16RRClass, + bool p_bIsQuery) const +{ + static char acClassString[16]; + *acClassString = 0; + + if (p_u16RRClass & 0x0001) + { + strcat(acClassString, "IN "); // 3 + } + if (p_u16RRClass & 0x8000) + { + strcat(acClassString, (p_bIsQuery ? "UNICAST " : "FLUSH ")); // 8/6 + } + + return acClassString; // 11 +} + +/* + MDNSResponder::clsHost::_replyFlags2String +*/ +const char* MDNSResponder::clsHost::_replyFlags2String(uint32_t p_u32ReplyFlags) const +{ + static char acFlagsString[64]; + + *acFlagsString = 0; + if (p_u32ReplyFlags & static_cast(enuContentFlag::A)) + { + strcat(acFlagsString, "A "); // 2 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::PTR_IPv4)) + { + strcat(acFlagsString, "PTR_IPv4 "); // 7 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::PTR_IPv6)) + { + strcat(acFlagsString, "PTR_IPv6 "); // 7 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::AAAA)) + { + strcat(acFlagsString, "AAAA "); // 5 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::PTR_TYPE)) + { + strcat(acFlagsString, "PTR_TYPE "); // 9 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::PTR_NAME)) + { + strcat(acFlagsString, "PTR_NAME "); // 9 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::TXT)) + { + strcat(acFlagsString, "TXT "); // 4 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::SRV)) + { + strcat(acFlagsString, "SRV "); // 4 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::NSEC)) + { + strcat(acFlagsString, "NSEC "); // 5 + } + + if (0 == p_u32ReplyFlags) + { + strcpy(acFlagsString, "none"); + } + + return acFlagsString; // 63 +} + +/* + MDNSResponder::clsHost::_NSECBitmap2String +*/ +const char* MDNSResponder::clsHost::_NSECBitmap2String(const stcNSECBitmap* p_pNSECBitmap) const +{ + static char acFlagsString[32]; + + *acFlagsString = 0; + if (p_pNSECBitmap->getBit(DNS_RRTYPE_A)) + { + strcat(acFlagsString, "A "); // 2 + } + if (p_pNSECBitmap->getBit(DNS_RRTYPE_PTR)) + { + strcat(acFlagsString, "PTR "); // 4 + } + if (p_pNSECBitmap->getBit(DNS_RRTYPE_AAAA)) + { + strcat(acFlagsString, "AAAA "); // 5 + } + if (p_pNSECBitmap->getBit(DNS_RRTYPE_TXT)) + { + strcat(acFlagsString, "TXT "); // 4 + } + if (p_pNSECBitmap->getBit(DNS_RRTYPE_SRV)) + { + strcat(acFlagsString, "SRV "); // 4 + } + if (p_pNSECBitmap->getBit(DNS_RRTYPE_NSEC)) + { + strcat(acFlagsString, "NSEC "); // 5 + } + + if (!*acFlagsString) + { + strcpy(acFlagsString, "none"); + } + + return acFlagsString; // 31 +} + +#endif // DEBUG_ESP_MDNS_RESPONDER + +} // namespace MDNSImplementation + +} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp new file mode 100755 index 0000000000..7121abcfca --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp @@ -0,0 +1,2435 @@ +/* + LEAmDNS2_Host_Structs.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "LEAmDNS2_Priv.h" +#include "LEAmDNS2_lwIPdefs.h" + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace experimental +{ + +/** + Internal CLASSES & STRUCTS +*/ + +/** + MDNSResponder::clsHost::stcServiceTxt + + One MDNS TXT item. + m_pcValue may be '\0'. + Objects can be chained together (list, m_pNext). + A 'm_bTemp' flag differentiates between static and dynamic items. + Output as byte array 'c#=1' is supported. +*/ + +/* + MDNSResponder::clsHost::stcServiceTxt::stcServiceTxt constructor +*/ +MDNSResponder::clsHost::stcServiceTxt::stcServiceTxt(const char* p_pcKey /*= 0*/, + const char* p_pcValue /*= 0*/, + bool p_bTemp /*= false*/) + : m_pNext(0), + m_pcKey(0), + m_pcValue(0), + m_bTemp(p_bTemp) +{ + setKey(p_pcKey); + setValue(p_pcValue); +} + +/* + MDNSResponder::clsHost::stcServiceTxt::stcServiceTxt copy-constructor +*/ +MDNSResponder::clsHost::stcServiceTxt::stcServiceTxt(const MDNSResponder::clsHost::stcServiceTxt& p_Other) + : m_pNext(0), + m_pcKey(0), + m_pcValue(0), + m_bTemp(false) +{ + operator=(p_Other); +} + +/* + MDNSResponder::clsHost::stcServiceTxt::~stcServiceTxt destructor +*/ +MDNSResponder::clsHost::stcServiceTxt::~stcServiceTxt(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcServiceTxt::operator= +*/ +MDNSResponder::clsHost::stcServiceTxt& MDNSResponder::clsHost::stcServiceTxt::operator=(const MDNSResponder::clsHost::stcServiceTxt& p_Other) +{ + if (&p_Other != this) + { + clear(); + set(p_Other.m_pcKey, p_Other.m_pcValue, p_Other.m_bTemp); + } + return *this; +} + +/* + MDNSResponder::clsHost::stcServiceTxt::clear +*/ +bool MDNSResponder::clsHost::stcServiceTxt::clear(void) +{ + releaseKey(); + releaseValue(); + return true; +} + +/* + MDNSResponder::clsHost::stcServiceTxt::allocKey +*/ +char* MDNSResponder::clsHost::stcServiceTxt::allocKey(size_t p_stLength) +{ + releaseKey(); + if (p_stLength) + { + m_pcKey = new char[p_stLength + 1]; + } + return m_pcKey; +} + +/* + MDNSResponder::clsHost::stcServiceTxt::setKey +*/ +bool MDNSResponder::clsHost::stcServiceTxt::setKey(const char* p_pcKey, + size_t p_stLength) +{ + bool bResult = false; + + releaseKey(); + if (p_stLength) + { + if (allocKey(p_stLength)) + { + strncpy(m_pcKey, p_pcKey, p_stLength); + m_pcKey[p_stLength] = 0; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcServiceTxt::setKey +*/ +bool MDNSResponder::clsHost::stcServiceTxt::setKey(const char* p_pcKey) +{ + return setKey(p_pcKey, (p_pcKey ? strlen(p_pcKey) : 0)); +} + +/* + MDNSResponder::clsHost::stcServiceTxt::releaseKey +*/ +bool MDNSResponder::clsHost::stcServiceTxt::releaseKey(void) +{ + if (m_pcKey) + { + delete[] m_pcKey; + m_pcKey = 0; + } + return true; +} + +/* + MDNSResponder::clsHost::stcServiceTxt::allocValue +*/ +char* MDNSResponder::clsHost::stcServiceTxt::allocValue(size_t p_stLength) +{ + releaseValue(); + if (p_stLength) + { + m_pcValue = new char[p_stLength + 1]; + } + return m_pcValue; +} + +/* + MDNSResponder::clsHost::stcServiceTxt::setValue +*/ +bool MDNSResponder::clsHost::stcServiceTxt::setValue(const char* p_pcValue, + size_t p_stLength) +{ + bool bResult = false; + + releaseValue(); + if (p_stLength) + { + if (allocValue(p_stLength)) + { + strncpy(m_pcValue, p_pcValue, p_stLength); + m_pcValue[p_stLength] = 0; + bResult = true; + } + } + else // No value -> also OK + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcServiceTxt::setValue +*/ +bool MDNSResponder::clsHost::stcServiceTxt::setValue(const char* p_pcValue) +{ + return setValue(p_pcValue, (p_pcValue ? strlen(p_pcValue) : 0)); +} + +/* + MDNSResponder::clsHost::stcServiceTxt::releaseValue +*/ +bool MDNSResponder::clsHost::stcServiceTxt::releaseValue(void) +{ + if (m_pcValue) + { + delete[] m_pcValue; + m_pcValue = 0; + } + return true; +} + +/* + MDNSResponder::clsHost::stcServiceTxt::set +*/ +bool MDNSResponder::clsHost::stcServiceTxt::set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp /*= false*/) +{ + m_bTemp = p_bTemp; + return ((setKey(p_pcKey)) && + (setValue(p_pcValue))); +} + +/* + MDNSResponder::clsHost::stcServiceTxt::update +*/ +bool MDNSResponder::clsHost::stcServiceTxt::update(const char* p_pcValue) +{ + return setValue(p_pcValue); +} + +/* + MDNSResponder::clsHost::stcServiceTxt::length + + length of eg. 'c#=1' without any closing '\0' +*/ +size_t MDNSResponder::clsHost::stcServiceTxt::length(void) const +{ + size_t stLength = 0; + if (m_pcKey) + { + stLength += strlen(m_pcKey); // Key + stLength += 1; // '=' + stLength += (m_pcValue ? strlen(m_pcValue) : 0); // Value + } + return stLength; +} + + +/** + MDNSResponder::clsHost::stcServiceTxts + + A list of zero or more MDNS TXT items. + Dynamic TXT items can be removed by 'removeTempTxts'. + A TXT item can be looke up by its 'key' member. + Export as ';'-separated byte array is supported. + Export as 'length byte coded' byte array is supported. + Comparision ((all A TXT items in B and equal) AND (all B TXT items in A and equal)) is supported. + +*/ + +/* + MDNSResponder::clsHost::stcServiceTxts::stcServiceTxts contructor +*/ +MDNSResponder::clsHost::stcServiceTxts::stcServiceTxts(void) + : m_pTxts(0), + m_pcCache(0) +{ +} + +/* + MDNSResponder::clsHost::stcServiceTxts::stcServiceTxts copy-constructor +*/ +MDNSResponder::clsHost::stcServiceTxts::stcServiceTxts(const stcServiceTxts& p_Other) + : m_pTxts(0), + m_pcCache(0) +{ + operator=(p_Other); +} + +/* + MDNSResponder::clsHost::stcServiceTxts::~stcServiceTxts destructor +*/ +MDNSResponder::clsHost::stcServiceTxts::~stcServiceTxts(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcServiceTxts::operator= +*/ +MDNSResponder::clsHost::stcServiceTxts& MDNSResponder::clsHost::stcServiceTxts::operator=(const stcServiceTxts& p_Other) +{ + if (this != &p_Other) + { + clear(); + + for (stcServiceTxt* pOtherTxt = p_Other.m_pTxts; pOtherTxt; pOtherTxt = pOtherTxt->m_pNext) + { + add(new stcServiceTxt(*pOtherTxt)); + } + } + return *this; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::clear +*/ +bool MDNSResponder::clsHost::stcServiceTxts::clear(void) +{ + while (m_pTxts) + { + stcServiceTxt* pNext = m_pTxts->m_pNext; + delete m_pTxts; + m_pTxts = pNext; + } + return clearCache(); +} + +/* + MDNSResponder::clsHost::stcServiceTxts::clearCache +*/ +bool MDNSResponder::clsHost::stcServiceTxts::clearCache(void) +{ + if (m_pcCache) + { + delete[] m_pcCache; + m_pcCache = 0; + } + return true; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::add +*/ +bool MDNSResponder::clsHost::stcServiceTxts::add(MDNSResponder::clsHost::stcServiceTxt* p_pTxt) +{ + bool bResult = false; + + if (p_pTxt) + { + p_pTxt->m_pNext = m_pTxts; + m_pTxts = p_pTxt; + bResult = true; + } + return ((clearCache()) && + (bResult)); +} + +/* + MDNSResponder::clsHost::stcServiceTxts::remove +*/ +bool MDNSResponder::clsHost::stcServiceTxts::remove(stcServiceTxt* p_pTxt) +{ + bool bResult = false; + + if (p_pTxt) + { + stcServiceTxt* pPred = m_pTxts; + while ((pPred) && + (pPred->m_pNext != p_pTxt)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pTxt->m_pNext; + delete p_pTxt; + bResult = true; + } + else if (m_pTxts == p_pTxt) // No predecesor, but first item + { + m_pTxts = p_pTxt->m_pNext; + delete p_pTxt; + bResult = true; + } + } + return ((clearCache()) && + (bResult)); +} + +/* + MDNSResponder::clsHost::stcServiceTxts::removeTempTxts +*/ +bool MDNSResponder::clsHost::stcServiceTxts::removeTempTxts(void) +{ + bool bResult = true; + + stcServiceTxt* pTxt = m_pTxts; + while ((bResult) && + (pTxt)) + { + stcServiceTxt* pNext = pTxt->m_pNext; + if (pTxt->m_bTemp) + { + bResult = remove(pTxt); + } + pTxt = pNext; + } + return ((clearCache()) && + (bResult)); +} + +/* + MDNSResponder::clsHost::stcServiceTxts::find +*/ +MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::stcServiceTxts::find(const char* p_pcKey) +{ + stcServiceTxt* pResult = 0; + + for (stcServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::find +*/ +const MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::stcServiceTxts::find(const char* p_pcKey) const +{ + const stcServiceTxt* pResult = 0; + + for (const stcServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::find +*/ +MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::stcServiceTxts::find(const stcServiceTxt* p_pTxt) +{ + stcServiceTxt* pResult = 0; + + for (stcServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if (p_pTxt == pTxt) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::length +*/ +uint16_t MDNSResponder::clsHost::stcServiceTxts::length(void) const +{ + uint16_t u16Length = 0; + + stcServiceTxt* pTxt = m_pTxts; + while (pTxt) + { + u16Length += 1; // Length byte + u16Length += pTxt->length(); // Text + pTxt = pTxt->m_pNext; + } + return u16Length; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::c_strLength + + (incl. closing '\0'). Length bytes place is used for delimiting ';' and closing '\0' +*/ +size_t MDNSResponder::clsHost::stcServiceTxts::c_strLength(void) const +{ + return length(); +} + +/* + MDNSResponder::clsHost::stcServiceTxts::c_str +*/ +bool MDNSResponder::clsHost::stcServiceTxts::c_str(char* p_pcBuffer) +{ + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + *p_pcBuffer = 0; + for (stcServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + if (pTxt != m_pTxts) + { + *p_pcBuffer++ = ';'; + } + strncpy(p_pcBuffer, pTxt->m_pcKey, stLength); p_pcBuffer[stLength] = 0; + p_pcBuffer += stLength; + *p_pcBuffer++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + strncpy(p_pcBuffer, pTxt->m_pcValue, stLength); p_pcBuffer[stLength] = 0; + p_pcBuffer += stLength; + } + } + } + *p_pcBuffer++ = 0; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::c_str +*/ +const char* MDNSResponder::clsHost::stcServiceTxts::c_str(void) const +{ + + if ((!m_pcCache) && + (m_pTxts) && + ((((stcServiceTxts*)this)->m_pcCache = new char[c_strLength()]))) // TRANSPARENT caching + { + ((stcServiceTxts*)this)->c_str(m_pcCache); + } + return m_pcCache; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::bufferLength + + (incl. closing '\0'). +*/ +size_t MDNSResponder::clsHost::stcServiceTxts::bufferLength(void) const +{ + return (length() + 1); +} + +/* + MDNSResponder::clsHost::stcServiceTxts::toBuffer +*/ +bool MDNSResponder::clsHost::stcServiceTxts::buffer(char* p_pcBuffer) +{ + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + *p_pcBuffer = 0; + for (stcServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + *(unsigned char*)p_pcBuffer++ = pTxt->length(); + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + memcpy(p_pcBuffer, pTxt->m_pcKey, stLength); + p_pcBuffer += stLength; + *p_pcBuffer++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + memcpy(p_pcBuffer, pTxt->m_pcValue, stLength); + p_pcBuffer += stLength; + } + } + } + *p_pcBuffer++ = 0; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::compare +*/ +bool MDNSResponder::clsHost::stcServiceTxts::compare(const MDNSResponder::clsHost::stcServiceTxts& p_Other) const +{ + bool bResult = false; + + if ((bResult = (length() == p_Other.length()))) + { + // Compare A->B + for (const stcServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + const stcServiceTxt* pOtherTxt = p_Other.find(pTxt->m_pcKey); + bResult = ((pOtherTxt) && + (pTxt->m_pcValue) && + (pOtherTxt->m_pcValue) && + (strlen(pTxt->m_pcValue) == strlen(pOtherTxt->m_pcValue)) && + (0 == strcmp(pTxt->m_pcValue, pOtherTxt->m_pcValue))); + } + // Compare B->A + for (const stcServiceTxt* pOtherTxt = p_Other.m_pTxts; ((bResult) && (pOtherTxt)); pOtherTxt = pOtherTxt->m_pNext) + { + const stcServiceTxt* pTxt = find(pOtherTxt->m_pcKey); + bResult = ((pTxt) && + (pOtherTxt->m_pcValue) && + (pTxt->m_pcValue) && + (strlen(pOtherTxt->m_pcValue) == strlen(pTxt->m_pcValue)) && + (0 == strcmp(pOtherTxt->m_pcValue, pTxt->m_pcValue))); + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcServiceTxts::operator== +*/ +bool MDNSResponder::clsHost::stcServiceTxts::operator==(const stcServiceTxts& p_Other) const +{ + return compare(p_Other); +} + +/* + MDNSResponder::clsHost::stcServiceTxts::operator!= +*/ +bool MDNSResponder::clsHost::stcServiceTxts::operator!=(const stcServiceTxts& p_Other) const +{ + return !compare(p_Other); +} + + +/** + MDNSResponder::clsHost::stcProbeInformation_Base + + Probing status information for a host or service domain + +*/ + +/* + MDNSResponder::clsHost::stcProbeInformation_Base::stcProbeInformation_Base constructor +*/ +MDNSResponder::clsHost::stcProbeInformation_Base::stcProbeInformation_Base(void) + : m_ProbingStatus(enuProbingStatus::WaitingForData), + m_u8SentCount(0), + m_Timeout(std::numeric_limits::max()), + m_bConflict(false), + m_bTiebreakNeeded(false) +{ +} + +/* + MDNSResponder::clsHost::stcProbeInformation_Base::clear +*/ +bool MDNSResponder::clsHost::stcProbeInformation_Base::clear(void) +{ + m_ProbingStatus = enuProbingStatus::WaitingForData; + m_u8SentCount = 0; + m_Timeout.reset(std::numeric_limits::max()); + m_bConflict = false; + m_bTiebreakNeeded = false; + + return true; +} + + +/** + MDNSResponder::clsHost::stcProbeInformation_Host + + Probing status information for a host or service domain + +*/ + +/* + MDNSResponder::clsHost::stcProbeInformation_Host::stcProbeInformation_Host constructor +*/ +MDNSResponder::clsHost::stcProbeInformation_Host::stcProbeInformation_Host(void) + : m_fnProbeResultCallback(0) +{ +} + +/* + MDNSResponder::clsHost::stcProbeInformation_Host::clear +*/ +bool MDNSResponder::clsHost::stcProbeInformation_Host::clear(bool p_bClearUserdata /*= false*/) +{ + if (p_bClearUserdata) + { + m_fnProbeResultCallback = 0; + } + return stcProbeInformation_Base::clear(); +} + + +/** + MDNSResponder::clsHost::stcProbeInformation_Service + + Probing status information for a host or service domain + +*/ + +/* + MDNSResponder::clsHost::stcProbeInformation_Service::stcProbeInformation_Service constructor +*/ +MDNSResponder::clsHost::stcProbeInformation_Service::stcProbeInformation_Service(void) + : m_fnProbeResultCallback(0) +{ +} + +/* + MDNSResponder::clsHost::stcProbeInformation_Service::clear +*/ +bool MDNSResponder::clsHost::stcProbeInformation_Service::clear(bool p_bClearUserdata /*= false*/) +{ + if (p_bClearUserdata) + { + m_fnProbeResultCallback = 0; + } + return stcProbeInformation_Base::clear(); +} + + +/** + MDNSResponder::clsHost::stcService + + A MDNS service object (to be announced by the MDNS responder) + The service instance may be '\0'; in this case the hostname is used + and the flag m_bAutoName is set. If the hostname changes, all 'auto- + named' services are renamed also. + m_u8Replymask is used while preparing a response to a MDNS query. It is + resetted in '_sendMDNSMessage' afterwards. +*/ + +/* + MDNSResponder::clsHost::stcService::stcService constructor +*/ +MDNSResponder::clsHost::stcService::stcService(const char* p_pcName /*= 0*/, + const char* p_pcServiceType /*= 0*/, + const char* p_pcProtocol /*= 0*/) + : m_pNext(0), + m_pcName(0), + m_bAutoName(false), + m_pcServiceType(0), + m_pcProtocol(0), + m_u16Port(0), + m_u32ReplyMask(0), + m_fnTxtCallback(0) +{ + setName(p_pcName); + setServiceType(p_pcServiceType); + setProtocol(p_pcProtocol); +} + +/* + MDNSResponder::clsHost::stcService::~stcService destructor +*/ +MDNSResponder::clsHost::stcService::~stcService(void) +{ + releaseName(); + releaseServiceType(); + releaseProtocol(); +} + +/* + MDNSResponder::clsHost::stcService::setName +*/ +bool MDNSResponder::clsHost::stcService::setName(const char* p_pcName) +{ + bool bResult = false; + + releaseName(); + size_t stLength = (p_pcName ? strlen(p_pcName) : 0); + if (stLength) + { + if ((bResult = (0 != (m_pcName = new char[stLength + 1])))) + { + strncpy(m_pcName, p_pcName, stLength); + m_pcName[stLength] = 0; + } + } + else + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcService::releaseName +*/ +bool MDNSResponder::clsHost::stcService::releaseName(void) +{ + if (m_pcName) + { + delete[] m_pcName; + m_pcName = 0; + } + return true; +} + +/* + MDNSResponder::clsHost::stcService::setServiceType +*/ +bool MDNSResponder::clsHost::stcService::setServiceType(const char* p_pcServiceType) +{ + bool bResult = false; + + releaseServiceType(); + size_t stLength = (p_pcServiceType ? strlen(p_pcServiceType) : 0); + if (stLength) + { + if ((bResult = (0 != (m_pcServiceType = new char[stLength + 1])))) + { + strncpy(m_pcServiceType, p_pcServiceType, stLength); + m_pcServiceType[stLength] = 0; + } + } + else + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcService::releaseServiceType +*/ +bool MDNSResponder::clsHost::stcService::releaseServiceType(void) +{ + if (m_pcServiceType) + { + delete[] m_pcServiceType; + m_pcServiceType = 0; + } + return true; +} + +/* + MDNSResponder::clsHost::stcService::setProtocol +*/ +bool MDNSResponder::clsHost::stcService::setProtocol(const char* p_pcProtocol) +{ + bool bResult = false; + + releaseProtocol(); + size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); + if (stLength) + { + if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) + { + strncpy(m_pcProtocol, p_pcProtocol, stLength); + m_pcProtocol[stLength] = 0; + } + } + else + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcService::releaseProtocol +*/ +bool MDNSResponder::clsHost::stcService::releaseProtocol(void) +{ + if (m_pcProtocol) + { + delete[] m_pcProtocol; + m_pcProtocol = 0; + } + return true; +} + +/* + MDNSResponder::clsHost::stcService::probeStatus +*/ +bool MDNSResponder::clsHost::stcService::probeStatus(void) const +{ + return (enuProbingStatus::Done == m_ProbeInformation.m_ProbingStatus); +} + + +/** + MDNSResponder::clsHost::stcMsgHeader + + A MDNS message haeder. + +*/ + +/* + MDNSResponder::clsHost::stcMsgHeader::stcMsgHeader +*/ +MDNSResponder::clsHost::stcMsgHeader::stcMsgHeader(uint16_t p_u16ID /*= 0*/, + bool p_bQR /*= false*/, + uint8_t p_u8Opcode /*= 0*/, + bool p_bAA /*= false*/, + bool p_bTC /*= false*/, + bool p_bRD /*= false*/, + bool p_bRA /*= false*/, + uint8_t p_u8RCode /*= 0*/, + uint16_t p_u16QDCount /*= 0*/, + uint16_t p_u16ANCount /*= 0*/, + uint16_t p_u16NSCount /*= 0*/, + uint16_t p_u16ARCount /*= 0*/) + : m_u16ID(p_u16ID), + m_1bQR(p_bQR), m_4bOpcode(p_u8Opcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), + m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_u8RCode), + m_u16QDCount(p_u16QDCount), + m_u16ANCount(p_u16ANCount), + m_u16NSCount(p_u16NSCount), + m_u16ARCount(p_u16ARCount) +{ +} + + +/** + MDNSResponder::clsHost::stcRRDomain + + A MDNS domain object. + The labels of the domain are stored (DNS-like encoded) in 'm_acName': + [length byte]varlength label[length byte]varlength label[0] + 'm_u16NameLength' stores the used length of 'm_acName'. + Dynamic label addition is supported. + Comparison is supported. + Export as byte array 'esp8266.local' is supported. + +*/ + +/* + MDNSResponder::clsHost::stcRRDomain::stcRRDomain constructor +*/ +MDNSResponder::clsHost::stcRRDomain::stcRRDomain(void) + : m_u16NameLength(0), + m_pcDecodedName(0) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcRRDomain::stcRRDomain copy-constructor +*/ +MDNSResponder::clsHost::stcRRDomain::stcRRDomain(const stcRRDomain& p_Other) + : m_u16NameLength(0), + m_pcDecodedName(0) +{ + operator=(p_Other); +} + +/* + MDNSResponder::clsHost::stcRRDomain::stcRRDomain destructor +*/ +MDNSResponder::clsHost::stcRRDomain::~stcRRDomain(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcRRDomain::operator = +*/ +MDNSResponder::clsHost::stcRRDomain& MDNSResponder::clsHost::stcRRDomain::operator=(const stcRRDomain& p_Other) +{ + if (&p_Other != this) + { + clear(); + memcpy(m_acName, p_Other.m_acName, sizeof(m_acName)); + m_u16NameLength = p_Other.m_u16NameLength; + } + return *this; +} + +/* + MDNSResponder::clsHost::stcRRDomain::clear +*/ +bool MDNSResponder::clsHost::stcRRDomain::clear(void) +{ + memset(m_acName, 0, sizeof(m_acName)); + m_u16NameLength = 0; + return clearNameCache(); +} + +/* + MDNSResponder::clsHost::stcRRDomain::clearNameCache +*/ +bool MDNSResponder::clsHost::stcRRDomain::clearNameCache(void) +{ + if (m_pcDecodedName) + { + delete[] m_pcDecodedName; + m_pcDecodedName = 0; + } + return true; +} + +/* + MDNSResponder::clsHost::stcRRDomain::addLabel +*/ +bool MDNSResponder::clsHost::stcRRDomain::addLabel(const char* p_pcLabel, + bool p_bPrependUnderline /*= false*/) +{ + bool bResult = false; + + size_t stLength = (p_pcLabel + ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) + : 0); + if ((MDNS_DOMAIN_LABEL_MAXLENGTH >= stLength) && + (MDNS_DOMAIN_MAXLENGTH >= (m_u16NameLength + (1 + stLength)))) + { + // Length byte + m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! + ++m_u16NameLength; + // Label + if (stLength) + { + if (p_bPrependUnderline) + { + m_acName[m_u16NameLength++] = '_'; + --stLength; + } + strncpy(&(m_acName[m_u16NameLength]), p_pcLabel, stLength); m_acName[m_u16NameLength + stLength] = 0; + m_u16NameLength += stLength; + } + bResult = clearNameCache(); + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcRRDomain::compare +*/ +bool MDNSResponder::clsHost::stcRRDomain::compare(const stcRRDomain& p_Other) const +{ + bool bResult = false; + + if (m_u16NameLength == p_Other.m_u16NameLength) + { + const char* pT = m_acName; + const char* pO = p_Other.m_acName; + while ((pT) && + (pO) && + (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND + (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content + { + if (*((unsigned char*)pT)) // Not 0 + { + pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and lenght + pO += (1 + * ((unsigned char*)pO)); + } + else // Is 0 -> Successfully reached the end + { + bResult = true; + break; + } + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcRRDomain::operator == +*/ +bool MDNSResponder::clsHost::stcRRDomain::operator==(const stcRRDomain& p_Other) const +{ + return compare(p_Other); +} + +/* + MDNSResponder::clsHost::stcRRDomain::operator != +*/ +bool MDNSResponder::clsHost::stcRRDomain::operator!=(const stcRRDomain& p_Other) const +{ + return !compare(p_Other); +} + +/* + MDNSResponder::clsHost::stcRRDomain::operator > +*/ +bool MDNSResponder::clsHost::stcRRDomain::operator>(const stcRRDomain& p_Other) const +{ + // TODO: Check, if this is a good idea... + return !compare(p_Other); +} + +/* + MDNSResponder::clsHost::stcRRDomain::c_strLength +*/ +size_t MDNSResponder::clsHost::stcRRDomain::c_strLength(void) const +{ + size_t stLength = 0; + + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + stLength += (*pucLabelLength + 1 /* +1 for '.' or '\0'*/); + pucLabelLength += (*pucLabelLength + 1); + } + return stLength; +} + +/* + MDNSResponder::clsHost::stcRRDomain::c_str (const) +*/ +bool MDNSResponder::clsHost::stcRRDomain::c_str(char* p_pcBuffer) const +{ + bool bResult = false; + + if (p_pcBuffer) + { + *p_pcBuffer = 0; + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + memcpy(p_pcBuffer, (const char*)(pucLabelLength + 1), *pucLabelLength); + p_pcBuffer += *pucLabelLength; + pucLabelLength += (*pucLabelLength + 1); + *p_pcBuffer++ = (*pucLabelLength ? '.' : '\0'); + } + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcRRDomain::c_str +*/ +const char* MDNSResponder::clsHost::stcRRDomain::c_str(void) const +{ + if ((!m_pcDecodedName) && + (m_u16NameLength) && + ((((stcRRDomain*)this)->m_pcDecodedName = new char[c_strLength()]))) // TRANSPARENT caching + { + ((stcRRDomain*)this)->c_str(m_pcDecodedName); + } + return m_pcDecodedName; +} + + +/** + MDNSResponder::clsHost::stcRRAttributes + + A MDNS attributes object. + +*/ + +/* + MDNSResponder::clsHost::stcRRAttributes::stcRRAttributes constructor +*/ +MDNSResponder::clsHost::stcRRAttributes::stcRRAttributes(uint16_t p_u16Type /*= 0*/, + uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) + : m_u16Type(p_u16Type), + m_u16Class(p_u16Class) +{ +} + +/* + MDNSResponder::clsHost::stcRRAttributes::stcRRAttributes copy-constructor +*/ +MDNSResponder::clsHost::stcRRAttributes::stcRRAttributes(const MDNSResponder::clsHost::stcRRAttributes& p_Other) +{ + operator=(p_Other); +} + +/* + MDNSResponder::clsHost::stcRRAttributes::operator = +*/ +MDNSResponder::clsHost::stcRRAttributes& MDNSResponder::clsHost::stcRRAttributes::operator=(const MDNSResponder::clsHost::stcRRAttributes& p_Other) +{ + if (&p_Other != this) + { + m_u16Type = p_Other.m_u16Type; + m_u16Class = p_Other.m_u16Class; + } + return *this; +} + + +/** + MDNSResponder::clsHost::stcRRHeader + + A MDNS record header (domain and attributes) object. + +*/ + +/* + MDNSResponder::clsHost::stcRRHeader::stcRRHeader constructor +*/ +MDNSResponder::clsHost::stcRRHeader::stcRRHeader(void) +{ +} + +/* + MDNSResponder::clsHost::stcRRHeader::stcRRHeader copy-constructor +*/ +MDNSResponder::clsHost::stcRRHeader::stcRRHeader(const stcRRHeader& p_Other) +{ + operator=(p_Other); +} + +/* + MDNSResponder::clsHost::stcRRHeader::operator = +*/ +MDNSResponder::clsHost::stcRRHeader& MDNSResponder::clsHost::stcRRHeader::operator=(const MDNSResponder::clsHost::stcRRHeader& p_Other) +{ + if (&p_Other != this) + { + m_Domain = p_Other.m_Domain; + m_Attributes = p_Other.m_Attributes; + } + return *this; +} + +/* + MDNSResponder::clsHost::stcRRHeader::clear +*/ +bool MDNSResponder::clsHost::stcRRHeader::clear(void) +{ + m_Domain.clear(); + return true; +} + + +/** + MDNSResponder::clsHost::stcRRQuestion + + A MDNS question record object (header + question flags) + +*/ + +/* + MDNSResponder::clsHost::stcRRQuestion::stcRRQuestion constructor +*/ +MDNSResponder::clsHost::stcRRQuestion::stcRRQuestion(void) + : m_pNext(0), + m_bUnicast(false) +{ +} + + +/** + MDNSResponder::clsHost::stcNSECBitmap + + A MDNS question record object (header + question flags) + +*/ + +/* + MDNSResponder::clsHost::stcNSECBitmap::stcNSECBitmap constructor +*/ +MDNSResponder::clsHost::stcNSECBitmap::stcNSECBitmap(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcNSECBitmap::stcNSECBitmap destructor +*/ +bool MDNSResponder::clsHost::stcNSECBitmap::clear(void) +{ + memset(m_au8BitmapData, 0, sizeof(m_au8BitmapData)); + return true; +} + +/* + MDNSResponder::clsHost::stcNSECBitmap::length +*/ +uint16_t MDNSResponder::clsHost::stcNSECBitmap::length(void) const +{ + return sizeof(m_au8BitmapData); // 6 +} + +/* + MDNSResponder::clsHost::stcNSECBitmap::setBit +*/ +bool MDNSResponder::clsHost::stcNSECBitmap::setBit(uint16_t p_u16Bit) +{ + bool bResult = false; + + if ((p_u16Bit) && + (length() > (p_u16Bit / 8))) // bit between 0..47(2F) + { + + uint8_t& ru8Byte = m_au8BitmapData[p_u16Bit / 8]; + uint8_t u8Flag = 1 << (7 - (p_u16Bit % 8)); // (7 - (0..7)) = 7..0 + + ru8Byte |= u8Flag; + + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcNSECBitmap::getBit +*/ +bool MDNSResponder::clsHost::stcNSECBitmap::getBit(uint16_t p_u16Bit) const +{ + bool bResult = false; + + if ((p_u16Bit) && + (length() > (p_u16Bit / 8))) // bit between 0..47(2F) + { + + uint8_t u8Byte = m_au8BitmapData[p_u16Bit / 8]; + uint8_t u8Flag = 1 << (7 - (p_u16Bit % 8)); // (7 - (0..7)) = 7..0 + + bResult = (u8Byte & u8Flag); + } + return bResult; +} + + +/** + MDNSResponder::clsHost::stcRRAnswer + + A MDNS answer record object (header + answer content). + This is a 'virtual' base class for all other MDNS answer classes. + +*/ + +/* + MDNSResponder::clsHost::stcRRAnswer::stcRRAnswer constructor +*/ +MDNSResponder::clsHost::stcRRAnswer::stcRRAnswer(enuAnswerType p_AnswerType, + const MDNSResponder::clsHost::stcRRHeader& p_Header, + uint32_t p_u32TTL) + : m_pNext(0), + m_AnswerType(p_AnswerType), + m_Header(p_Header), + m_u32TTL(p_u32TTL) +{ + // Extract 'cache flush'-bit + m_bCacheFlush = (m_Header.m_Attributes.m_u16Class & 0x8000); + m_Header.m_Attributes.m_u16Class &= (~0x8000); +} + +/* + MDNSResponder::clsHost::stcRRAnswer::~stcRRAnswer destructor +*/ +MDNSResponder::clsHost::stcRRAnswer::~stcRRAnswer(void) +{ +} + +/* + MDNSResponder::clsHost::stcRRAnswer::answerType +*/ +MDNSResponder::clsHost::enuAnswerType MDNSResponder::clsHost::stcRRAnswer::answerType(void) const +{ + return m_AnswerType; +} + +/* + MDNSResponder::clsHost::stcRRAnswer::clear +*/ +bool MDNSResponder::clsHost::stcRRAnswer::clear(void) +{ + m_pNext = 0; + m_Header.clear(); + return true; +} + + +/** + MDNSResponder::clsHost::stcRRAnswerA + + A MDNS A answer object. + Extends the base class by an IPv4 address member. + +*/ + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::clsHost::stcRRAnswerA::stcRRAnswerA constructor +*/ +MDNSResponder::clsHost::stcRRAnswerA::stcRRAnswerA(const MDNSResponder::clsHost::stcRRHeader& p_Header, + uint32_t p_u32TTL) + : stcRRAnswer(enuAnswerType::A, p_Header, p_u32TTL), + m_IPAddress() +{ +} + +/* + MDNSResponder::clsHost::stcRRAnswerA::stcRRAnswerA destructor +*/ +MDNSResponder::clsHost::stcRRAnswerA::~stcRRAnswerA(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcRRAnswerA::clear +*/ +bool MDNSResponder::clsHost::stcRRAnswerA::clear(void) +{ + m_IPAddress = IPAddress(); + return true; +} +#endif + + +/** + MDNSResponder::clsHost::stcRRAnswerPTR + + A MDNS PTR answer object. + Extends the base class by a MDNS domain member. + +*/ + +/* + MDNSResponder::clsHost::stcRRAnswerPTR::stcRRAnswerPTR constructor +*/ +MDNSResponder::clsHost::stcRRAnswerPTR::stcRRAnswerPTR(const MDNSResponder::clsHost::stcRRHeader& p_Header, + uint32_t p_u32TTL) + : stcRRAnswer(enuAnswerType::PTR, p_Header, p_u32TTL) +{ +} + +/* + MDNSResponder::clsHost::stcRRAnswerPTR::~stcRRAnswerPTR destructor +*/ +MDNSResponder::clsHost::stcRRAnswerPTR::~stcRRAnswerPTR(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcRRAnswerPTR::clear +*/ +bool MDNSResponder::clsHost::stcRRAnswerPTR::clear(void) +{ + m_PTRDomain.clear(); + return true; +} + + +/** + MDNSResponder::clsHost::stcRRAnswerTXT + + A MDNS TXT answer object. + Extends the base class by a MDNS TXT items list member. + +*/ + +/* + MDNSResponder::clsHost::stcRRAnswerTXT::stcRRAnswerTXT constructor +*/ +MDNSResponder::clsHost::stcRRAnswerTXT::stcRRAnswerTXT(const MDNSResponder::clsHost::stcRRHeader& p_Header, + uint32_t p_u32TTL) + : stcRRAnswer(enuAnswerType::TXT, p_Header, p_u32TTL) +{ +} + +/* + MDNSResponder::clsHost::stcRRAnswerTXT::~stcRRAnswerTXT destructor +*/ +MDNSResponder::clsHost::stcRRAnswerTXT::~stcRRAnswerTXT(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcRRAnswerTXT::clear +*/ +bool MDNSResponder::clsHost::stcRRAnswerTXT::clear(void) +{ + m_Txts.clear(); + return true; +} + + +/** + MDNSResponder::clsHost::stcRRAnswerAAAA + + A MDNS AAAA answer object. + Extends the base class by an IPv6 address member. + +*/ + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::clsHost::stcRRAnswerAAAA::stcRRAnswerAAAA constructor +*/ +MDNSResponder::clsHost::stcRRAnswerAAAA::stcRRAnswerAAAA(const MDNSResponder::clsHost::stcRRHeader& p_Header, + uint32_t p_u32TTL) + : stcRRAnswer(enuAnswerType::AAAA, p_Header, p_u32TTL), + m_IPAddress() +{ +} + +/* + MDNSResponder::clsHost::stcRRAnswerAAAA::~stcRRAnswerAAAA destructor +*/ +MDNSResponder::clsHost::stcRRAnswerAAAA::~stcRRAnswerAAAA(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcRRAnswerAAAA::clear +*/ +bool MDNSResponder::clsHost::stcRRAnswerAAAA::clear(void) +{ + m_IPAddress = IPAddress(); + return true; +} +#endif + + +/** + MDNSResponder::clsHost::stcRRAnswerSRV + + A MDNS SRV answer object. + Extends the base class by a port member. + +*/ + +/* + MDNSResponder::clsHost::stcRRAnswerSRV::stcRRAnswerSRV constructor +*/ +MDNSResponder::clsHost::stcRRAnswerSRV::stcRRAnswerSRV(const MDNSResponder::clsHost::stcRRHeader& p_Header, + uint32_t p_u32TTL) + : stcRRAnswer(enuAnswerType::SRV, p_Header, p_u32TTL), + m_u16Priority(0), + m_u16Weight(0), + m_u16Port(0) +{ +} + +/* + MDNSResponder::clsHost::stcRRAnswerSRV::~stcRRAnswerSRV destructor +*/ +MDNSResponder::clsHost::stcRRAnswerSRV::~stcRRAnswerSRV(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcRRAnswerSRV::clear +*/ +bool MDNSResponder::clsHost::stcRRAnswerSRV::clear(void) +{ + m_u16Priority = 0; + m_u16Weight = 0; + m_u16Port = 0; + m_SRVDomain.clear(); + return true; +} + + +/** + MDNSResponder::clsHost::stcRRAnswerGeneric + + An unknown (generic) MDNS answer object. + Extends the base class by a RDATA buffer member. + +*/ + +/* + MDNSResponder::clsHost::stcRRAnswerGeneric::stcRRAnswerGeneric constructor +*/ +MDNSResponder::clsHost::stcRRAnswerGeneric::stcRRAnswerGeneric(const stcRRHeader& p_Header, + uint32_t p_u32TTL) + : stcRRAnswer(enuAnswerType::Generic, p_Header, p_u32TTL), + m_u16RDLength(0), + m_pu8RDData(0) +{ +} + +/* + MDNSResponder::clsHost::stcRRAnswerGeneric::~stcRRAnswerGeneric destructor +*/ +MDNSResponder::clsHost::stcRRAnswerGeneric::~stcRRAnswerGeneric(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcRRAnswerGeneric::clear +*/ +bool MDNSResponder::clsHost::stcRRAnswerGeneric::clear(void) +{ + if (m_pu8RDData) + { + delete[] m_pu8RDData; + m_pu8RDData = 0; + } + m_u16RDLength = 0; + + return true; +} + + +/** + MDNSResponder::clsHost::stcSendParameter + + A 'collection' of properties and flags for one MDNS query or response. + Mainly managed by the 'Control' functions. + The current offset in the UPD output buffer is tracked to be able to do + a simple host or service domain compression. + +*/ + +/** + MDNSResponder::clsHost::stcSendParameter::stcDomainCacheItem + + A cached host or service domain, incl. the offset in the UDP output buffer. + +*/ + +/* + MDNSResponder::clsHost::stcSendParameter::stcDomainCacheItem::stcDomainCacheItem constructor +*/ +MDNSResponder::clsHost::stcSendParameter::stcDomainCacheItem::stcDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset) + : m_pNext(0), + m_pHostNameOrService(p_pHostNameOrService), + m_bAdditionalData(p_bAdditionalData), + m_u16Offset(p_u16Offset) +{ +} + +/** + MDNSResponder::clsHost::stcSendParameter +*/ + +/* + MDNSResponder::clsHost::stcSendParameter::stcSendParameter constructor +*/ +MDNSResponder::clsHost::stcSendParameter::stcSendParameter(void) + : m_pQuestions(0), + m_Response(enuResponseType::None), + m_pDomainCacheItems(0) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcSendParameter::~stcSendParameter destructor +*/ +MDNSResponder::clsHost::stcSendParameter::~stcSendParameter(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcSendParameter::clear +*/ +bool MDNSResponder::clsHost::stcSendParameter::clear(void) +{ + m_u16ID = 0; + flushQuestions(); + m_u32HostReplyMask = 0; + + m_bLegacyQuery = false; + m_Response = enuResponseType::None; + m_bAuthorative = false; + m_bCacheFlush = true; + m_bUnicast = false; + m_bUnannounce = false; + + m_u16Offset = 0; + flushDomainCache(); + return true; +} + +/* + MDNSResponder::clsHost::stcSendParameter::flushQuestions +*/ +bool MDNSResponder::clsHost::stcSendParameter::flushQuestions(void) +{ + while (m_pQuestions) + { + stcRRQuestion* pNext = m_pQuestions->m_pNext; + delete m_pQuestions; + m_pQuestions = pNext; + } + return true; +} + +/* + MDNSResponder::clsHost::stcSendParameter::flushDomainCache +*/ +bool MDNSResponder::clsHost::stcSendParameter::flushDomainCache(void) +{ + while (m_pDomainCacheItems) + { + stcDomainCacheItem* pNext = m_pDomainCacheItems->m_pNext; + delete m_pDomainCacheItems; + m_pDomainCacheItems = pNext; + } + return true; +} + +/* + MDNSResponder::clsHost::stcSendParameter::flushTempContent +*/ +bool MDNSResponder::clsHost::stcSendParameter::flushTempContent(void) +{ + m_u16Offset = 0; + flushDomainCache(); + return true; +} + +/* + MDNSResponder::clsHost::stcSendParameter::shiftOffset +*/ +bool MDNSResponder::clsHost::stcSendParameter::shiftOffset(uint16_t p_u16Shift) +{ + m_u16Offset += p_u16Shift; + return true; +} + +/* + MDNSResponder::clsHost::stcSendParameter::addDomainCacheItem +*/ +bool MDNSResponder::clsHost::stcSendParameter::addDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset) +{ + bool bResult = false; + + stcDomainCacheItem* pNewItem = 0; + if ((p_pHostNameOrService) && + (p_u16Offset) && + ((pNewItem = new stcDomainCacheItem(p_pHostNameOrService, p_bAdditionalData, p_u16Offset)))) + { + + pNewItem->m_pNext = m_pDomainCacheItems; + bResult = ((m_pDomainCacheItems = pNewItem)); + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcSendParameter::findCachedDomainOffset +*/ +uint16_t MDNSResponder::clsHost::stcSendParameter::findCachedDomainOffset(const void* p_pHostNameOrService, + bool p_bAdditionalData) const +{ + const stcDomainCacheItem* pCacheItem = m_pDomainCacheItems; + + for (; pCacheItem; pCacheItem = pCacheItem->m_pNext) + { + if ((pCacheItem->m_pHostNameOrService == p_pHostNameOrService) && + (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item + { + break; + } + } + return (pCacheItem ? pCacheItem->m_u16Offset : 0); +} + + +/** + MDNSResponder::clsHost::stcQuery + + A MDNS service query object. + Service queries may be static or dynamic. + As the static service query is processed in the blocking function 'queryService', + only one static service service may exist. The processing of the answers is done + on the WiFi-stack side of the ESP stack structure (via 'UDPContext.onRx(_update)'). + +*/ + +/** + MDNSResponder::clsHost::stcQuery::stcAnswer + + One answer for a service query. + Every answer must contain + - a service instance entry (pivot), + and may contain + - a host domain, + - a port + - an IPv4 address + (- an IPv6 address) + - a MDNS TXTs + The existance of a component is flaged in 'm_u32ContentFlags'. + For every answer component a TTL value is maintained. + Answer objects can be connected to a linked list. + + For the host domain, service domain and TXTs components, a char array + representation can be retrieved (which is created on demand). + +*/ + +/** + MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL + + The TTL (Time-To-Live) for an specific answer content. + The 80% and outdated states are calculated based on the current time (millis) + and the 'set' time (also millis). + If the answer is scheduled for an update, the corresponding flag should be set. + +*/ + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::stcTTL constructor +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::stcTTL(void) + : m_u32TTL(0), + m_TTLTimeout(std::numeric_limits::max()), + m_TimeoutLevel(static_cast(enuTimeoutLevel::None)) +{ +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::set +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) +{ + m_u32TTL = p_u32TTL; + if (m_u32TTL) + { + m_TimeoutLevel = static_cast(enuTimeoutLevel::Base); // Set to 80% + m_TTLTimeout.reset(timeout()); + } + else + { + m_TimeoutLevel = static_cast(enuTimeoutLevel::None); // undef + m_TTLTimeout.reset(std::numeric_limits::max()); + } + return true; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::flagged +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::flagged(void) const +{ + return ((m_u32TTL) && + (static_cast(enuTimeoutLevel::None) != m_TimeoutLevel) && + (((esp8266::polledTimeout::timeoutTemplate*)&m_TTLTimeout)->expired())); // Cast-away the const; in case of oneShot-timer OK (but ugly...) +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::restart +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::restart(void) +{ + bool bResult = true; + + if ((static_cast(enuTimeoutLevel::Base) <= m_TimeoutLevel) && // >= 80% AND + (static_cast(enuTimeoutLevel::Final) > m_TimeoutLevel)) // < 100% + { + + m_TimeoutLevel += static_cast(enuTimeoutLevel::Interval); // increment by 5% + m_TTLTimeout.reset(timeout()); + } + else + { + bResult = false; + m_TTLTimeout.reset(std::numeric_limits::max()); + m_TimeoutLevel = static_cast(enuTimeoutLevel::None); + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::prepareDeletion +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::prepareDeletion(void) +{ + m_TimeoutLevel = static_cast(enuTimeoutLevel::Final); + m_TTLTimeout.reset(1 * 1000); // See RFC 6762, 10.1 + + return true; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::finalTimeoutLevel +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::finalTimeoutLevel(void) const +{ + return (static_cast(enuTimeoutLevel::Final) == m_TimeoutLevel); +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::timeout +*/ +unsigned long MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::timeout(void) const +{ + uint32_t u32Timeout = std::numeric_limits::max(); + + if (static_cast(enuTimeoutLevel::Base) == m_TimeoutLevel) // 80% + { + u32Timeout = (m_u32TTL * 800); // to milliseconds + } + else if ((static_cast(enuTimeoutLevel::Base) < m_TimeoutLevel) && // >80% AND + (static_cast(enuTimeoutLevel::Final) >= m_TimeoutLevel)) // <= 100% + { + + u32Timeout = (m_u32TTL * 50); + } // else: invalid + return u32Timeout; +} + + +/** + MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress + +*/ + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress::stcIPAddress constructor +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress::stcIPAddress(IPAddress p_IPAddress, + uint32_t p_u32TTL /*= 0*/) + : m_pNext(0), + m_IPAddress(p_IPAddress) +{ + m_TTL.set(p_u32TTL); +} + + +/** + MDNSResponder::clsHost::stcQuery::stcAnswer +*/ + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::stcAnswer constructor +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer::stcAnswer(void) + : m_pNext(0), + m_u16Port(0), +#ifdef MDNS_IPV4_SUPPORT + m_pIPv4Addresses(0), +#endif +#ifdef MDNS_IPV6_SUPPORT + m_pIPv6Addresses(0), +#endif + m_QueryAnswerFlags(0) +{ +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::~stcAnswer destructor +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer::~stcAnswer(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::clear +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::clear(void) +{ + return ( +#ifdef MDNS_IPV4_SUPPORT + (releaseIPv4Addresses()) && +#endif +#ifdef MDNS_IPV6_SUPPORT + (releaseIPv6Addresses()) +#endif + ); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::releaseIPv4Addresses +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::releaseIPv4Addresses(void) +{ + while (m_pIPv4Addresses) + { + stcIPAddress* pNext = m_pIPv4Addresses->m_pNext; + delete m_pIPv4Addresses; + m_pIPv4Addresses = pNext; + } + return true; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::addIPv4Address +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::addIPv4Address(MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* p_pIPv4Address) +{ + bool bResult = false; + + if (p_pIPv4Address) + { + p_pIPv4Address->m_pNext = m_pIPv4Addresses; + m_pIPv4Addresses = p_pIPv4Address; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::removeIPv4Address +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::removeIPv4Address(MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* p_pIPv4Address) +{ + bool bResult = false; + + if (p_pIPv4Address) + { + stcIPAddress* pPred = m_pIPv4Addresses; + while ((pPred) && + (pPred->m_pNext != p_pIPv4Address)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pIPv4Address->m_pNext; + delete p_pIPv4Address; + bResult = true; + } + else if (m_pIPv4Addresses == p_pIPv4Address) // No predecesor, but first item + { + m_pIPv4Addresses = p_pIPv4Address->m_pNext; + delete p_pIPv4Address; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv4Address (const) +*/ +const MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv4Address(const IPAddress& p_IPAddress) const +{ + return (stcIPAddress*)(((const stcAnswer*)this)->findIPv4Address(p_IPAddress)); +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv4Address +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv4Address(const IPAddress& p_IPAddress) +{ + stcIPAddress* pIPv4Address = m_pIPv4Addresses; + while (pIPv4Address) + { + if (pIPv4Address->m_IPAddress == p_IPAddress) + { + break; + } + pIPv4Address = pIPv4Address->m_pNext; + } + return pIPv4Address; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressCount +*/ +uint32_t MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressCount(void) const +{ + uint32_t u32Count = 0; + + stcIPAddress* pIPv4Address = m_pIPv4Addresses; + while (pIPv4Address) + { + ++u32Count; + pIPv4Address = pIPv4Address->m_pNext; + } + return u32Count; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressAtIndex +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressAtIndex(uint32_t p_u32Index) +{ + return (stcIPAddress*)(((const stcAnswer*)this)->IPv4AddressAtIndex(p_u32Index)); +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressAtIndex (const) +*/ +const MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressAtIndex(uint32_t p_u32Index) const +{ + const stcIPAddress* pIPv4Address = 0; + + if (((uint32_t)(-1) != p_u32Index) && + (m_pIPv4Addresses)) + { + + uint32_t u32Index; + for (pIPv4Address = m_pIPv4Addresses, u32Index = 0; ((pIPv4Address) && (u32Index < p_u32Index)); pIPv4Address = pIPv4Address->m_pNext, ++u32Index); + } + return pIPv4Address; +} +#endif + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::releaseIPv6Addresses +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::releaseIPv6Addresses(void) +{ + while (m_pIPv6Addresses) + { + stcIPAddress* pNext = m_pIPv6Addresses->m_pNext; + delete m_pIPv6Addresses; + m_pIPv6Addresses = pNext; + } + return true; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::addIPv6Address +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::addIPv6Address(MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* p_pIPv6Address) +{ + bool bResult = false; + + if (p_pIPv6Address) + { + p_pIPv6Address->m_pNext = m_pIPv6Addresses; + m_pIPv6Addresses = p_pIPv6Address; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::removeIPv6Address +*/ +bool MDNSResponder::clsHost::stcQuery::stcAnswer::removeIPv6Address(MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* p_pIPv6Address) +{ + bool bResult = false; + + if (p_pIPv6Address) + { + stcIPAddress* pPred = m_pIPv6Addresses; + while ((pPred) && + (pPred->m_pNext != p_pIPv6Address)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pIPv6Address->m_pNext; + delete p_pIPv6Address; + bResult = true; + } + else if (m_pIPv6Addresses == p_pIPv6Address) // No predecesor, but first item + { + m_pIPv6Addresses = p_pIPv6Address->m_pNext; + delete p_pIPv6Address; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv6Address +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv6Address(const IPAddress& p_IPAddress) +{ + return (stcIPAddress*)(((const stcAnswer*)this)->findIPv6Address(p_IPAddress)); +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv6Address (const) +*/ +const MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv6Address(const IPAddress& p_IPAddress) const +{ + const stcIPAddress* pIPv6Address = m_pIPv6Addresses; + while (pIPv6Address) + { + if (pIPv6Address->m_IPAddress == p_IPAddress) + { + break; + } + pIPv6Address = pIPv6Address->m_pNext; + } + return pIPv6Address; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressCount +*/ +uint32_t MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressCount(void) const +{ + uint32_t u32Count = 0; + + stcIPAddress* pIPv6Address = m_pIPv6Addresses; + while (pIPv6Address) + { + ++u32Count; + pIPv6Address = pIPv6Address->m_pNext; + } + return u32Count; +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressAtIndex (const) +*/ +const MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressAtIndex(uint32_t p_u32Index) const +{ + return (stcIPAddress*)(((const stcAnswer*)this)->IPv6AddressAtIndex(p_u32Index)); +} + +/* + MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressAtIndex +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressAtIndex(uint32_t p_u32Index) +{ + stcIPAddress* pIPv6Address = 0; + + if (((uint32_t)(-1) != p_u32Index) && + (m_pIPv6Addresses)) + { + + uint32_t u32Index; + for (pIPv6Address = m_pIPv6Addresses, u32Index = 0; ((pIPv6Address) && (u32Index < p_u32Index)); pIPv6Address = pIPv6Address->m_pNext, ++u32Index); + } + return pIPv6Address; +} +#endif + + +/** + MDNSResponder::clsHost::stcQuery + + A service query object. + A static query is flaged via 'm_bLegacyQuery'; while the function 'queryService' + is waiting for answers, the internal flag 'm_bAwaitingAnswers' is set. When the + timeout is reached, the flag is removed. These two flags are only used for static + service queries. + All answers to the service query are stored in 'm_pAnswers' list. + Individual answers may be addressed by index (in the list of answers). + Every time a answer component is added (or changes) in a dynamic service query, + the callback 'm_fnCallback' is called. + The answer list may be searched by service and host domain. + + Service query object may be connected to a linked list. +*/ + +/* + MDNSResponder::clsHost::stcQuery::stcQuery constructor +*/ +MDNSResponder::clsHost::stcQuery::stcQuery(const enuQueryType p_QueryType) + : m_pNext(0), + m_QueryType(p_QueryType), + m_fnCallback(0), + m_bLegacyQuery(false), + m_u8SentCount(0), + m_ResendTimeout(std::numeric_limits::max()), + m_bAwaitingAnswers(true), + m_pAnswers(0) +{ + clear(); + m_QueryType = p_QueryType; +} + +/* + MDNSResponder::clsHost::stcQuery::~stcQuery destructor +*/ +MDNSResponder::clsHost::stcQuery::~stcQuery(void) +{ + clear(); +} + +/* + MDNSResponder::clsHost::stcQuery::clear +*/ +bool MDNSResponder::clsHost::stcQuery::clear(void) +{ + m_pNext = 0; + m_QueryType = enuQueryType::None; + m_fnCallback = 0; + m_bLegacyQuery = false; + m_u8SentCount = 0; + m_ResendTimeout.reset(std::numeric_limits::max()); + m_bAwaitingAnswers = true; + while (m_pAnswers) + { + stcAnswer* pNext = m_pAnswers->m_pNext; + delete m_pAnswers; + m_pAnswers = pNext; + } + return true; +} + +/* + MDNSResponder::clsHost::stcQuery::answerCount +*/ +uint32_t MDNSResponder::clsHost::stcQuery::answerCount(void) const +{ + uint32_t u32Count = 0; + + stcAnswer* pAnswer = m_pAnswers; + while (pAnswer) + { + ++u32Count; + pAnswer = pAnswer->m_pNext; + } + return u32Count; +} + +/* + MDNSResponder::clsHost::stcQuery::answerAtIndex +*/ +const MDNSResponder::clsHost::stcQuery::stcAnswer* MDNSResponder::clsHost::stcQuery::answerAtIndex(uint32_t p_u32Index) const +{ + const stcAnswer* pAnswer = 0; + + if (((uint32_t)(-1) != p_u32Index) && + (m_pAnswers)) + { + + uint32_t u32Index; + for (pAnswer = m_pAnswers, u32Index = 0; ((pAnswer) && (u32Index < p_u32Index)); pAnswer = pAnswer->m_pNext, ++u32Index); + } + return pAnswer; +} + +/* + MDNSResponder::clsHost::stcQuery::answerAtIndex +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer* MDNSResponder::clsHost::stcQuery::answerAtIndex(uint32_t p_u32Index) +{ + return (stcAnswer*)(((const stcQuery*)this)->answerAtIndex(p_u32Index)); +} + +/* + MDNSResponder::clsHost::stcQuery::indexOfAnswer +*/ +uint32_t MDNSResponder::clsHost::stcQuery::indexOfAnswer(const MDNSResponder::clsHost::stcQuery::stcAnswer* p_pAnswer) const +{ + uint32_t u32Index = 0; + + for (const stcAnswer* pAnswer = m_pAnswers; pAnswer; pAnswer = pAnswer->m_pNext, ++u32Index) + { + if (pAnswer == p_pAnswer) + { + return u32Index; + } + } + return ((uint32_t)(-1)); +} + +/* + MDNSResponder::clsHost::stcQuery::addAnswer +*/ +bool MDNSResponder::clsHost::stcQuery::addAnswer(MDNSResponder::clsHost::stcQuery::stcAnswer* p_pAnswer) +{ + bool bResult = false; + + if (p_pAnswer) + { + p_pAnswer->m_pNext = m_pAnswers; + m_pAnswers = p_pAnswer; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcQuery::removeAnswer +*/ +bool MDNSResponder::clsHost::stcQuery::removeAnswer(MDNSResponder::clsHost::stcQuery::stcAnswer* p_pAnswer) +{ + bool bResult = false; + + if (p_pAnswer) + { + stcAnswer* pPred = m_pAnswers; + while ((pPred) && + (pPred->m_pNext != p_pAnswer)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pAnswer->m_pNext; + delete p_pAnswer; + bResult = true; + } + else if (m_pAnswers == p_pAnswer) // No predecesor, but first item + { + m_pAnswers = p_pAnswer->m_pNext; + delete p_pAnswer; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::clsHost::stcQuery::findAnswerForServiceDomain +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer* MDNSResponder::clsHost::stcQuery::findAnswerForServiceDomain(const MDNSResponder::clsHost::stcRRDomain& p_ServiceDomain) +{ + stcAnswer* pAnswer = m_pAnswers; + while (pAnswer) + { + if (pAnswer->m_ServiceDomain == p_ServiceDomain) + { + break; + } + pAnswer = pAnswer->m_pNext; + } + return pAnswer; +} + +/* + MDNSResponder::clsHost::stcQuery::findAnswerForHostDomain +*/ +MDNSResponder::clsHost::stcQuery::stcAnswer* MDNSResponder::clsHost::stcQuery::findAnswerForHostDomain(const MDNSResponder::clsHost::stcRRDomain& p_HostDomain) +{ + stcAnswer* pAnswer = m_pAnswers; + while (pAnswer) + { + if (pAnswer->m_HostDomain == p_HostDomain) + { + break; + } + pAnswer = pAnswer->m_pNext; + } + return pAnswer; +} + + +} // namespace MDNSImplementation + +} // namespace esp8266 + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Transfer.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Transfer.cpp new file mode 100755 index 0000000000..5da81255ab --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Transfer.cpp @@ -0,0 +1,2390 @@ +/* + LEAmDNS2_Host_Transfer.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +extern "C" { +#include "user_interface.h" +} + +#include "lwip/netif.h" + +#include "LEAmDNS2_lwIPdefs.h" +#include "LEAmDNS2_Priv.h" + + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace experimental +{ + +/** + CONST STRINGS +*/ +static const char* scpcLocal = "local"; +static const char* scpcServices = "services"; +static const char* scpcDNSSD = "dns-sd"; +static const char* scpcUDP = "udp"; +//static const char* scpcTCP = "tcp"; + +#ifdef MDNS_IPV4_SUPPORT +static const char* scpcReverseIPv4Domain = "in-addr"; +#endif +#ifdef MDNS_IPV6_SUPPORT +static const char* scpcReverseIPv6Domain = "ip6"; +#endif +static const char* scpcReverseTopDomain = "arpa"; + +/** + TRANSFER +*/ + + +/** + SENDING +*/ + +/* + MDNSResponder::_sendMDNSMessage + + Unicast responses are prepared and sent directly to the querier. + Multicast responses or queries are transferred to _sendMDNSMessage_Multicast + + Any reply flags in installed services are removed at the end! + +*/ +bool MDNSResponder::clsHost::_sendMDNSMessage(MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + bool bResult = false; + + uint8_t u8AvailableProtocols = 0; +#ifdef MDNS_IPV4_SUPPORT + // Only send out IPv4 messages, if we've got an IPv4 address + if (_getResponderIPAddress(enuIPProtocolType::V4).isSet()) + { + u8AvailableProtocols |= static_cast(enuIPProtocolType::V4); + } + DEBUG_EX_INFO(else + { + DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: No IPv4 address available!\n"), _DH()); + }); +#endif +#ifdef MDNS_IPV6_SUPPORT + // Only send out IPv6 messages, if we've got an IPv6 address + if (_getResponderIPAddress(enuIPProtocolType::V6).isSet()) + { + u8AvailableProtocols |= static_cast(enuIPProtocolType::V6); + } + DEBUG_EX_INFO(else + { + DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: No IPv6 address available!\n"), _DH()); + }); +#endif + + if (stcSendParameter::enuResponseType::None != p_rSendParameter.m_Response) + { + IPAddress ipRemote = ((stcSendParameter::enuResponseType::Response == p_rSendParameter.m_Response) + ? m_rUDPContext.getRemoteAddress() + : IPAddress()); + + if (p_rSendParameter.m_bUnicast) // Unicast response -> Send to querier + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: Will send unicast to '%s'.\n"), _DH(), ipRemote.toString().c_str());); + DEBUG_EX_ERR(if (!ipRemote.isSet()) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: MISSING remote address for unicast response!\n"), _DH());); + + bResult = ((ipRemote.isSet()) && + (_prepareMDNSMessage(p_rSendParameter)) && + (m_rUDPContext.send(ipRemote, m_rUDPContext.getRemotePort()))); + } + else // Multicast response -> Send via the same network interface, that received the query + { +#ifdef MDNS_IPV4_SUPPORT + if (((!ipRemote.isSet()) || // NO remote IP + (ipRemote.isV4())) && // OR IPv4 + (u8AvailableProtocols & static_cast(enuIPProtocolType::V4))) // AND IPv4 protocol available + { + + bResult = _sendMDNSMessage_Multicast(p_rSendParameter, static_cast(enuIPProtocolType::V4)); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if (((!ipRemote.isSet()) || // NO remote IP + (ipRemote.isV6())) && // OR IPv6 + (u8AvailableProtocols & static_cast(enuIPProtocolType::V6))) // AND IPv6 protocol available + { + + bResult = _sendMDNSMessage_Multicast(p_rSendParameter, static_cast(enuIPProtocolType::V6)); + } +#endif + } + } + else // Multicast query -> Send by all available protocols + { + bResult = ((u8AvailableProtocols) && + (_sendMDNSMessage_Multicast(p_rSendParameter, u8AvailableProtocols))); + } + + // Finally clear service reply masks + for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + { + pService->m_u32ReplyMask = 0; + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: FAILED!\n"), _DH());); + return bResult; +} + +#include "cont.h" +/* + MDNSResponder::_sendMDNSMessage_Multicast + + Fills the UDP output buffer (via _prepareMDNSMessage) and sends the buffer + via the selected WiFi protocols +*/ +bool MDNSResponder::clsHost::_sendMDNSMessage_Multicast(MDNSResponder::clsHost::stcSendParameter& p_rSendParameter, + uint8_t p_IPProtocolTypes) +{ + bool bIPv4Result = true; + bool bIPv6Result = true; + +#ifdef MDNS_IPV4_SUPPORT + if (p_IPProtocolTypes & static_cast(enuIPProtocolType::V4)) + { + IPAddress ip4MulticastAddress(DNS_MQUERY_IPV4_GROUP_INIT); + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast v4: Will send to '%s'.\n"), _DH(), ip4MulticastAddress.toString().c_str());); + DEBUG_EX_INFO(if (!_getResponderIPAddress(enuIPProtocolType::V4)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast v4: NO IPv4 address!.\n"), _DH());); + bIPv4Result = ((_prepareMDNSMessage(p_rSendParameter)) && + (m_rUDPContext.setMulticastInterface(&m_rNetIf), true) && + (m_rUDPContext.send(ip4MulticastAddress, DNS_MQUERY_PORT)) && + (m_rUDPContext.setMulticastInterface(0), true)); + DEBUG_EX_ERR(if (!bIPv4Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast (V4): FAILED!\n"), _DH());); + } +#endif + +#ifdef MDNS_IPV6_SUPPORT + if (p_IPProtocolTypes & static_cast(enuIPProtocolType::V6)) + { + IPAddress ip6MulticastAddress(DNS_MQUERY_IPV6_GROUP_INIT); + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast v6: Will send to '%s'.\n"), _DH(), ip6MulticastAddress.toString().c_str());); + DEBUG_EX_INFO(if (!_getResponderIPAddress(enuIPProtocolType::V6)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast v6: NO IPv6 address!.\n"), _DH());); + DEBUG_EX_ERR( + bool bPrepareMessage = false; + bool bUDPContextSend = false; + ); + bIPv6Result = ((DEBUG_EX_ERR(bPrepareMessage =)_prepareMDNSMessage(p_rSendParameter)) && + (m_rUDPContext.setMulticastInterface(&m_rNetIf), true) && + (DEBUG_EX_ERR(bUDPContextSend =)m_rUDPContext.send(ip6MulticastAddress, DNS_MQUERY_PORT)) && + (m_rUDPContext.setMulticastInterface(0), true)); + DEBUG_EX_ERR(if (!bIPv6Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast (V6): FAILED! (%s, %s, %s)\n"), _DH(), (_getResponderIPAddress(enuIPProtocolType::V6).isSet() ? "1" : "0"), (bPrepareMessage ? "1" : "0"), (bUDPContextSend ? "1" : "0"));); + } +#endif + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast: %s!\n\n"), _DH(), ((bIPv4Result && bIPv6Result) ? "Succeeded" : "FAILED"));); + DEBUG_EX_ERR(if (!(bIPv4Result && bIPv6Result)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast: FAILED!\n"), _DH());); + return (bIPv4Result && bIPv6Result); +} + +/* + MDNSResponder::_prepareMDNSMessage + + The MDNS message is composed in a two-step process. + In the first loop 'only' the header informations (mainly number of answers) are collected, + while in the seconds loop, the header and all queries and answers are written to the UDP + output buffer. + +*/ +bool MDNSResponder::clsHost::_prepareMDNSMessage(MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage\n"));); + bool bResult = true; + + // Prepare output buffer for potential reuse + p_rSendParameter.flushTempContent(); + + // Prepare header; count answers + stcMsgHeader msgHeader(p_rSendParameter.m_u16ID, + (static_cast(stcSendParameter::enuResponseType::None) != p_rSendParameter.m_Response), + 0, + p_rSendParameter.m_bAuthorative); + // If this is a response, the answers are anwers, + // else this is a query or probe and the answers go into auth section + uint16_t& ru16Answers = ((stcSendParameter::enuResponseType::None != p_rSendParameter.m_Response) + ? msgHeader.m_u16ANCount // Usual answers + : msgHeader.m_u16NSCount); // Authorative answers + + /** + enuSequence + */ + using typeSequence = uint8_t; + enum class enuSequence : typeSequence + { + Count = 0, + Send = 1 + }; + + // Two step sequence: 'Count' and 'Send' + for (typeSequence sequence = static_cast(enuSequence::Count); ((bResult) && (sequence <= static_cast(enuSequence::Send))); ++sequence) + { + DEBUG_EX_INFO( + if (static_cast(enuSequence::Send) == sequence) + DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + _DH(), + (unsigned)msgHeader.m_u16ID, + (unsigned)msgHeader.m_1bQR, (unsigned)msgHeader.m_4bOpcode, (unsigned)msgHeader.m_1bAA, (unsigned)msgHeader.m_1bTC, (unsigned)msgHeader.m_1bRD, + (unsigned)msgHeader.m_1bRA, (unsigned)msgHeader.m_4bRCode, + (unsigned)msgHeader.m_u16QDCount, + (unsigned)msgHeader.m_u16ANCount, + (unsigned)msgHeader.m_u16NSCount, + (unsigned)msgHeader.m_u16ARCount); + ); + // Count/send + // Header + bResult = ((static_cast(enuSequence::Count) == sequence) + ? true + : _writeMDNSMsgHeader(msgHeader, p_rSendParameter)); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSMsgHeader FAILED!\n"), _DH());); + // Questions + for (stcRRQuestion* pQuestion = p_rSendParameter.m_pQuestions; ((bResult) && (pQuestion)); pQuestion = pQuestion->m_pNext) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++msgHeader.m_u16QDCount + : (bResult = _writeMDNSQuestion(*pQuestion, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSQuestion FAILED!\n"), _DH());); + } + + // Answers and authorative answers + // NSEC host (part 1) + uint32_t u32NSECContent = 0; +#ifdef MDNS_IPV4_SUPPORT + // A + if ((bResult) && + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::A)) && + (_getResponderIPAddress(enuIPProtocolType::V4).isSet())) + { + + u32NSECContent |= static_cast(enuContentFlag::A); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_A(_getResponderIPAddress(enuIPProtocolType::V4), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_A(A) FAILED!\n"), _DH());); + } + // PTR_IPv4 + if ((bResult) && + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::PTR_IPv4)) && + (_getResponderIPAddress(enuIPProtocolType::V4).isSet())) + { + + u32NSECContent |= static_cast(enuContentFlag::PTR_IPv4); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_IPv4(_getResponderIPAddress(enuIPProtocolType::V4), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_PTR_IPv4 FAILED!\n"), _DH());); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + // AAAA + if ((bResult) && + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::AAAA)) && + (_getResponderIPAddress(enuIPProtocolType::V6).isSet())) + { + + u32NSECContent |= static_cast(enuContentFlag::AAAA); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_AAAA(_getResponderIPAddress(enuIPProtocolType::V6), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_AAAA(A) FAILED!\n"), _DH());); + } + // PTR_IPv6 + if ((bResult) && + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::PTR_IPv6)) && + (_getResponderIPAddress(enuIPProtocolType::V6).isSet())) + { + + u32NSECContent |= static_cast(enuContentFlag::PTR_IPv6); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_IPv6(_getResponderIPAddress(enuIPProtocolType::V6), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_PTR_IPv6 FAILED!\n"), _DH());); + } +#endif + + for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + // PTR_TYPE + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_TYPE))) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_TYPE(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_PTR_TYPE FAILED!\n"), _DH());); + } + // PTR_NAME + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_NAME))) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_NAME(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_PTR_NAME FAILED!\n"), _DH());); + } + // SRV + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::SRV))) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_SRV(A) FAILED!\n"), _DH());); + } + // TXT + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::TXT))) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_TXT(A) FAILED!\n"), _DH());); + } + } // for services + + // Additional answers + uint16_t& ru16AdditionalAnswers = msgHeader.m_u16ARCount; + +#ifdef MDNS_IPV4_SUPPORT + bool bNeedsAdditionalAnswerA = false; +#endif +#ifdef MDNS_IPV6_SUPPORT + bool bNeedsAdditionalAnswerAAAA = false; +#endif + for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_NAME)) && // If PTR_NAME is requested, AND + (!(pService->m_u32ReplyMask & static_cast(enuContentFlag::SRV)))) // NOT SRV -> add SRV as additional answer + { + + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_SRV(B) FAILED!\n"), _DH());); + } + /* AppleTV doesn't add TXT + if ((bResult) && + (pService->m_u32ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND + (!(pService->m_u32ReplyMask & ContentFlag_TXT))) { // NOT TXT -> add TXT as additional answer + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_TXT(B) FAILED!\n"));); + } + */ + if ((pService->m_u32ReplyMask & (static_cast(enuContentFlag::PTR_NAME) | static_cast(enuContentFlag::SRV))) || // If service instance name or SRV OR + (p_rSendParameter.m_u32HostReplyMask & (static_cast(enuContentFlag::A) | static_cast(enuContentFlag::AAAA)))) // any host IP address is requested + { +#ifdef MDNS_IPV4_SUPPORT + if ((bResult) && + (!(p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::A)))) // Add IPv4 address + { + bNeedsAdditionalAnswerA = true; + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if ((bResult) && + (!(p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::AAAA)))) // Add IPv6 address + { + bNeedsAdditionalAnswerAAAA = true; + } +#endif + } + // NSEC record for service + if ((bResult) && + (pService->m_u32ReplyMask) && + ((stcSendParameter::enuResponseType::None != p_rSendParameter.m_Response))) + { + + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_NSEC(*pService, (static_cast(enuContentFlag::TXT) | static_cast(enuContentFlag::SRV)), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_NSEC(Service) FAILED!\n"), _DH());); + } + } // for services + +#ifdef MDNS_IPV4_SUPPORT + // Answer A needed? + if ((bResult) && + (bNeedsAdditionalAnswerA) && + (_getResponderIPAddress(enuIPProtocolType::V4).isSet())) + { + // Additional A + u32NSECContent |= static_cast(enuContentFlag::A); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_A(_getResponderIPAddress(enuIPProtocolType::V4), p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_A(B) FAILED!\n"), _DH());); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + // Answer AAAA needed? + if ((bResult) && + (bNeedsAdditionalAnswerAAAA) && + (_getResponderIPAddress(enuIPProtocolType::V6).isSet())) + { + // Additional AAAA + u32NSECContent |= static_cast(enuContentFlag::AAAA); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_AAAA(_getResponderIPAddress(enuIPProtocolType::V6), p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_AAAA(B) FAILED!\n"), _DH());); + } +#endif + + // NSEC host (part 2) + if ((bResult) && + ((stcSendParameter::enuResponseType::None != p_rSendParameter.m_Response)) && + (u32NSECContent)) + { + + // NSEC PTR IPv4/IPv6 are separate answers; make sure, that this is counted for +#ifdef MDNS_IPV4_SUPPORT + uint32_t u32NSECContent_PTR_IPv4 = (u32NSECContent & static_cast(enuContentFlag::PTR_IPv4)); + u32NSECContent &= ~static_cast(enuContentFlag::PTR_IPv4); +#endif +#ifdef MDNS_IPV6_SUPPORT + uint32_t u32NSECContent_PTR_IPv6 = (u32NSECContent & static_cast(enuContentFlag::PTR_IPv6)); + u32NSECContent &= ~static_cast(enuContentFlag::PTR_IPv6); +#endif + + ((static_cast(enuSequence::Count) == sequence) + ? (ru16AdditionalAnswers += ((u32NSECContent ? 1 : 0) +#ifdef MDNS_IPV4_SUPPORT + + (u32NSECContent_PTR_IPv4 ? 1 : 0) +#endif +#ifdef MDNS_IPV6_SUPPORT + + (u32NSECContent_PTR_IPv6 ? 1 : 0) +#endif + )) + : (bResult = (((!u32NSECContent) || + // Write host domain NSEC answer + (_writeMDNSAnswer_NSEC(u32NSECContent, p_rSendParameter))) +#ifdef MDNS_IPV4_SUPPORT + // Write separate answer for host PTR IPv4 + && ((!u32NSECContent_PTR_IPv4) || + ((!_getResponderIPAddress(enuIPProtocolType::V4).isSet()) || + (_writeMDNSAnswer_NSEC_PTR_IPv4(_getResponderIPAddress(enuIPProtocolType::V4), p_rSendParameter)))) +#endif +#ifdef MDNS_IPV6_SUPPORT + // Write separate answer for host PTR IPv6 + && ((!u32NSECContent_PTR_IPv6) || + ((!_getResponderIPAddress(enuIPProtocolType::V6).isSet()) || + (_writeMDNSAnswer_NSEC_PTR_IPv6(_getResponderIPAddress(enuIPProtocolType::V6), p_rSendParameter)))) +#endif + ))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_NSEC(Host) FAILED!\n"), _DH());); + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: Loop %i FAILED!\n"), _DH(), sequence);); + } // for sequence + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_addMDNSQueryRecord + + Adds a query for the given domain and query type. + +*/ +bool MDNSResponder::clsHost::_addMDNSQueryRecord(MDNSResponder::clsHost::stcSendParameter& p_rSendParameter, + const MDNSResponder::clsHost::stcRRDomain& p_QueryDomain, + uint16_t p_u16RecordType) +{ + bool bResult = false; + + stcRRQuestion* pQuestion = new stcRRQuestion; + if ((bResult = (0 != pQuestion))) + { + // Link to list of questions + pQuestion->m_pNext = p_rSendParameter.m_pQuestions; + p_rSendParameter.m_pQuestions = pQuestion; + + pQuestion->m_Header.m_Domain = p_QueryDomain; + + pQuestion->m_Header.m_Attributes.m_u16Type = p_u16RecordType; + // It seems, that some mDNS implementations don't support 'unicast response' questions... + pQuestion->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN); // /*Unicast &*/ INternet + } + return bResult; +} + +/* + MDNSResponder::_sendMDNSQuery + + Creates and sends a query for the given domain and query type. + +*/ +bool MDNSResponder::clsHost::_sendMDNSQuery(const MDNSResponder::clsHost::stcQuery& p_Query, + MDNSResponder::clsHost::stcQuery::stcAnswer* p_pKnownAnswers /*= 0*/) +{ + bool bResult = false; + + stcSendParameter sendParameter; + switch (p_Query.m_QueryType) + { + case stcQuery::enuQueryType::Host: +#ifdef MDNS_IPV4_SUPPORT + bResult = _addMDNSQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_A); +#endif +#ifdef MDNS_IPV6_SUPPORT + bResult = _addMDNSQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_AAAA); +#endif + break; + + case stcQuery::enuQueryType::Service: + bResult = _addMDNSQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_PTR); + break; + + case stcQuery::enuQueryType::None: + default: + break; + } + + // TODO: Add known answers to query + (void)p_pKnownAnswers; + + bResult = ((bResult) && + (_sendMDNSMessage(sendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSQuery: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_sendMDNSQuery + + Creates and sends a query for the given domain and record type. + +*/ +bool MDNSResponder::clsHost::_sendMDNSQuery(const MDNSResponder::clsHost::stcRRDomain& p_QueryDomain, + uint16_t p_u16RecordType, + MDNSResponder::clsHost::stcQuery::stcAnswer* p_pKnownAnswers /*= 0*/) +{ + bool bResult = false; + + stcSendParameter sendParameter; + bResult = ((_addMDNSQueryRecord(sendParameter, p_QueryDomain, p_u16RecordType)) && + (_sendMDNSMessage(sendParameter))); + + // TODO: Add known answer records + (void) p_pKnownAnswers; + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSQuery: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_getResponderIPAddress +*/ +IPAddress MDNSResponder::clsHost::_getResponderIPAddress(enuIPProtocolType p_IPProtocolType) const +{ + IPAddress ipResponder; +#ifdef MDNS_IPV4_SUPPORT + if (enuIPProtocolType::V4 == p_IPProtocolType) + { + ipResponder = netif_ip_addr4(&m_rNetIf); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if (enuIPProtocolType::V6 == p_IPProtocolType) + { + bool bCheckLinkLocal = true; + for (int i = 0; ((!ipResponder.isSet()) && (i < 2)); ++i) // Two loops: First with link-local check, second without + { + for (int idx = 0; idx < LWIP_IPV6_NUM_ADDRESSES; ++idx) + { + //DEBUG_EX_INFO(if ip6_addr_isvalid(netif_ip6_addr_state(&m_rNetIf, idx)) DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Checking IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(&m_rNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); + if ((ip6_addr_isvalid(netif_ip6_addr_state(&m_rNetIf, idx))) && + (((!bCheckLinkLocal) || + (ip6_addr_islinklocal(netif_ip6_addr(&m_rNetIf, idx)))))) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Selected IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(&m_rNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); + ipResponder = netif_ip_addr6(&m_rNetIf, idx); + break; + } + } + bCheckLinkLocal = false; + } + } +#endif + return ipResponder; +} + + +/** + HELPERS +*/ + +/** + RESOURCE RECORDS +*/ + +/* + MDNSResponder::_readRRQuestion + + Reads a question (eg. MyESP._http._tcp.local ANY IN) from the UPD input buffer. + +*/ +bool MDNSResponder::clsHost::_readRRQuestion(MDNSResponder::clsHost::stcRRQuestion& p_rRRQuestion) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRQuestion\n"));); + + bool bResult = false; + + if ((bResult = _readRRHeader(p_rRRQuestion.m_Header))) + { + // Extract unicast flag from class field + p_rRRQuestion.m_bUnicast = (p_rRRQuestion.m_Header.m_Attributes.m_u16Class & 0x8000); + //p_rRRQuestion.m_Header.m_Attributes.m_u16Class &= (~0x8000); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRQuestion "), _DH()); + _printRRDomain(p_rRRQuestion.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:%s\n"), _RRType2Name(p_rRRQuestion.m_Header.m_Attributes.m_u16Type), _RRClass2String(p_rRRQuestion.m_Header.m_Attributes.m_u16Class, true)); + ); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRQuestion: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRAnswer + + Reads an answer (eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local) + from the UDP input buffer. + After reading the domain and type info, the further processing of the answer + is transferred the answer specific reading functions. + Unknown answer types are processed by the generic answer reader (to remove them + from the input buffer). + +*/ +bool MDNSResponder::clsHost::_readRRAnswer(MDNSResponder::clsHost::stcRRAnswer*& p_rpRRAnswer) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer\n"));); + + bool bResult = false; + + stcRRHeader header; + uint32_t u32TTL; + uint16_t u16RDLength; + if ((_readRRHeader(header)) && + (_udpRead32(u32TTL)) && + (_udpRead16(u16RDLength))) + { + + /* DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: Reading 0x%04X answer (class:0x%04X, TTL:%u, RDLength:%u) for "), header.m_Attributes.m_u16Type, header.m_Attributes.m_u16Class, u32TTL, u16RDLength); + _printRRDomain(header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + );*/ + + switch (header.m_Attributes.m_u16Type /*& (~0x8000)*/) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IPV4_SUPPORT + case DNS_RRTYPE_A: + p_rpRRAnswer = new stcRRAnswerA(header, u32TTL); + bResult = _readRRAnswerA(*(stcRRAnswerA*&)p_rpRRAnswer, u16RDLength); + break; +#endif + case DNS_RRTYPE_PTR: + p_rpRRAnswer = new stcRRAnswerPTR(header, u32TTL); + bResult = _readRRAnswerPTR(*(stcRRAnswerPTR*&)p_rpRRAnswer, u16RDLength); + break; + case DNS_RRTYPE_TXT: + p_rpRRAnswer = new stcRRAnswerTXT(header, u32TTL); + bResult = _readRRAnswerTXT(*(stcRRAnswerTXT*&)p_rpRRAnswer, u16RDLength); + break; +#ifdef MDNS_IPV6_SUPPORT + case DNS_RRTYPE_AAAA: + p_rpRRAnswer = new stcRRAnswerAAAA(header, u32TTL); + bResult = _readRRAnswerAAAA(*(stcRRAnswerAAAA*&)p_rpRRAnswer, u16RDLength); + break; +#endif + case DNS_RRTYPE_SRV: + p_rpRRAnswer = new stcRRAnswerSRV(header, u32TTL); + bResult = _readRRAnswerSRV(*(stcRRAnswerSRV*&)p_rpRRAnswer, u16RDLength); + break; + default: + p_rpRRAnswer = new stcRRAnswerGeneric(header, u32TTL); + bResult = _readRRAnswerGeneric(*(stcRRAnswerGeneric*&)p_rpRRAnswer, u16RDLength); + break; + } + DEBUG_EX_INFO( + if ((bResult) && + (p_rpRRAnswer)) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: "), _DH()); + _printRRDomain(p_rpRRAnswer->m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u, RDLength:%u "), + _RRType2Name(p_rpRRAnswer->m_Header.m_Attributes.m_u16Type), + (p_rpRRAnswer->m_Header.m_Attributes.m_u16Class | (p_rpRRAnswer->m_bCacheFlush ? 0x8000 : 0)), + p_rpRRAnswer->m_u32TTL, + u16RDLength); + switch (header.m_Attributes.m_u16Type /*& (~0x8000)*/) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IPV4_SUPPORT + case DNS_RRTYPE_A: + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((stcRRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_PTR: + DEBUG_OUTPUT.printf_P(PSTR("PTR ")); + _printRRDomain(((stcRRAnswerPTR*&)p_rpRRAnswer)->m_PTRDomain); + break; + case DNS_RRTYPE_TXT: + { + size_t stTxtLength = ((stcRRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_strLength(); + char* pTxts = new char[stTxtLength]; + if (pTxts) + { + ((stcRRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_str(pTxts); + DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); + delete[] pTxts; + } + break; + } +#ifdef MDNS_IPV6_SUPPORT + case DNS_RRTYPE_AAAA: + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcRRAnswerAAAA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_SRV: + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((stcRRAnswerSRV*&)p_rpRRAnswer)->m_u16Port); + _printRRDomain(((stcRRAnswerSRV*&)p_rpRRAnswer)->m_SRVDomain); + break; + /* case DNS_RRTYPE_NSEC: + DEBUG_OUTPUT.printf_P(PSTR("NSEC ")); + _printRRDomain(((stcRRAnswerNSEC*&)p_rpRRAnswer)->m_NSECDomain); + for (uint32_t u=0; u<(((stcRRAnswerNSEC*&)p_rpRRAnswer)->m_pNSECBitmap->m_u16BitmapLength * 8); ++u) { + uint8_t byte = ((stcRRAnswerNSEC*&)p_rpRRAnswer)->m_pNSECBitmap->m_pu8BitmapData[u / 8]; + uint8_t flag = 1 << (7 - (u % 8)); // (7 - (0..7)) = 7..0 + if (byte & flag) { + DEBUG_OUTPUT.printf_P(PSTR(" %s"), _RRType2Name(u)); + } + } + break;*/ + default: + DEBUG_OUTPUT.printf_P(PSTR("generic ")); + break; + } + DEBUG_OUTPUT.printf_P(PSTR("\n")); + } + else + { + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: FAILED to read specific answer of type 0x%04X!\n"), _DH(), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type); + } + ); // DEBUG_EX_INFO + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: FAILED!\n"), _DH());); + return bResult; +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::_readRRAnswerA +*/ +bool MDNSResponder::clsHost::_readRRAnswerA(MDNSResponder::clsHost::stcRRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength) +{ + + uint32_t u32IPv4Address; + bool bResult = ((MDNS_IPV4_SIZE == p_u16RDLength) && + (_udpReadBuffer((unsigned char*)&u32IPv4Address, MDNS_IPV4_SIZE)) && + ((p_rRRAnswerA.m_IPAddress = IPAddress(u32IPv4Address)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerA: FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_readRRAnswerPTR +*/ +bool MDNSResponder::clsHost::_readRRAnswerPTR(MDNSResponder::clsHost::stcRRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength) +{ + bool bResult = ((p_u16RDLength) && + (_readRRDomain(p_rRRAnswerPTR.m_PTRDomain))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerPTR: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRAnswerTXT + + Read TXT items from a buffer like 4c#=15ff=20 +*/ +bool MDNSResponder::clsHost::_readRRAnswerTXT(MDNSResponder::clsHost::stcRRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: RDLength:%u\n"), _DH(), p_u16RDLength);); + bool bResult = true; + + p_rRRAnswerTXT.clear(); + if (p_u16RDLength) + { + bResult = false; + + unsigned char* pucBuffer = new unsigned char[p_u16RDLength]; + if (pucBuffer) + { + if (_udpReadBuffer(pucBuffer, p_u16RDLength)) + { + bResult = true; + + const unsigned char* pucCursor = pucBuffer; + while ((pucCursor < (pucBuffer + p_u16RDLength)) && + (bResult)) + { + bResult = false; + + stcServiceTxt* pTxt = 0; + unsigned char ucLength = *pucCursor++; // Length of the next txt item + if (ucLength) + { + DEBUG_EX_INFO( + static char sacBuffer[64]; *sacBuffer = 0; + uint8_t u8MaxLength = ((ucLength > (sizeof(sacBuffer) - 1)) ? (sizeof(sacBuffer) - 1) : ucLength); + os_strncpy(sacBuffer, (const char*)pucCursor, u8MaxLength); sacBuffer[u8MaxLength] = 0; + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: Item(%u): %s\n"), _DH(), ucLength, sacBuffer); + ); + + unsigned char* pucEqualSign = (unsigned char*)os_strchr((const char*)pucCursor, '='); // Position of the '=' sign + unsigned char ucKeyLength; + if ((pucEqualSign) && + ((ucKeyLength = (pucEqualSign - pucCursor)))) + { + unsigned char ucValueLength = (ucLength - (pucEqualSign - pucCursor + 1)); + bResult = (((pTxt = new stcServiceTxt)) && + (pTxt->setKey((const char*)pucCursor, ucKeyLength)) && + (pTxt->setValue((const char*)(pucEqualSign + 1), ucValueLength))); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: INVALID TXT format (No '=')!\n"), _DH());); + } + pucCursor += ucLength; + } + else // no/zero length TXT + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: TXT answer contains no items.\n"), _DH());); + bResult = true; + } + + if ((bResult) && + (pTxt)) // Everythings fine so far + { + // Link TXT item to answer TXTs + pTxt->m_pNext = p_rRRAnswerTXT.m_Txts.m_pTxts; + p_rRRAnswerTXT.m_Txts.m_pTxts = pTxt; + } + else // At least no TXT (migth be OK, if length was 0) OR an error + { + if (!bResult) + { + DEBUG_EX_ERR( + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED to read TXT item!\n"), _DH()); + DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); + _udpDump((m_rUDPContext.tell() - p_u16RDLength), p_u16RDLength); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + if (pTxt) + { + delete pTxt; + pTxt = 0; + } + p_rRRAnswerTXT.clear(); + } + } // while + + DEBUG_EX_ERR( + if (!bResult) // Some failure + { + DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); + _udpDump((m_rUDPContext.tell() - p_u16RDLength), p_u16RDLength); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + } + ); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED to read TXT content!\n"), _DH());); + } + // Clean up + delete[] pucBuffer; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED to alloc buffer for TXT content!\n"), _DH());); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: WARNING! No content!\n"), _DH());); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED!\n"), _DH());); + return bResult; +} + +#ifdef MDNS_IPV6_SUPPORT +bool MDNSResponder::clsHost::_readRRAnswerAAAA(MDNSResponder::clsHost::stcRRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength) +{ + bool bResult = false; + + uint32_t au32IPv6Address[4]; // 16 bytes + if ((bResult = ((MDNS_IPV6_SIZE == p_u16RDLength) && + (_udpReadBuffer((uint8_t*)&au32IPv6Address[0], MDNS_IPV6_SIZE))))) + { + + // ?? IPADDR6_INIT_HOST ?? + ip_addr_t addr = IPADDR6_INIT(au32IPv6Address[0], au32IPv6Address[1], au32IPv6Address[2], au32IPv6Address[3]); + p_rRRAnswerAAAA.m_IPAddress = IPAddress(addr); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerAAAA: FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_readRRAnswerSRV +*/ +bool MDNSResponder::clsHost::_readRRAnswerSRV(MDNSResponder::clsHost::stcRRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength) +{ + bool bResult = (((3 * sizeof(uint16_t)) < p_u16RDLength) && + (_udpRead16(p_rRRAnswerSRV.m_u16Priority)) && + (_udpRead16(p_rRRAnswerSRV.m_u16Weight)) && + (_udpRead16(p_rRRAnswerSRV.m_u16Port)) && + (_readRRDomain(p_rRRAnswerSRV.m_SRVDomain))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerSRV: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRAnswerGeneric +*/ +bool MDNSResponder::clsHost::_readRRAnswerGeneric(MDNSResponder::clsHost::stcRRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength) +{ + bool bResult = (0 == p_u16RDLength); + + p_rRRAnswerGeneric.clear(); + if (((p_rRRAnswerGeneric.m_u16RDLength = p_u16RDLength)) && + ((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength]))) + { + + bResult = _udpReadBuffer(p_rRRAnswerGeneric.m_pu8RDData, p_rRRAnswerGeneric.m_u16RDLength); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerGeneric: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRHeader +*/ +bool MDNSResponder::clsHost::_readRRHeader(MDNSResponder::clsHost::stcRRHeader& p_rRRHeader) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRHeader\n"));); + + bool bResult = ((_readRRDomain(p_rRRHeader.m_Domain)) && + (_readRRAttributes(p_rRRHeader.m_Attributes))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRHeader: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRDomain + + Reads a (maybe multilevel compressed) domain from the UDP input buffer. + +*/ +bool MDNSResponder::clsHost::_readRRDomain(MDNSResponder::clsHost::stcRRDomain& p_rRRDomain) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain\n"));); + + bool bResult = ((p_rRRDomain.clear()) && + (_readRRDomain_Loop(p_rRRDomain, 0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRDomain_Loop + + Reads a domain from the UDP input buffer. For every compression level, the functions + calls itself recursively. To avoid endless recursion because of malformed MDNS records, + the maximum recursion depth is set by MDNS_DOMAIN_MAX_REDIRCTION. + +*/ +bool MDNSResponder::clsHost::_readRRDomain_Loop(MDNSResponder::clsHost::stcRRDomain& p_rRRDomain, + uint8_t p_u8Depth) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u)\n"), _DH(), p_u8Depth);); + + bool bResult = false; + + if (MDNS_DOMAIN_MAX_REDIRCTION >= p_u8Depth) + { + bResult = true; + + uint8_t u8Len = 0; + do + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Offset:%u p0:%02x\n"), _DH(), p_u8Depth, m_rUDPContext.tell(), m_rUDPContext.peek());); + _udpRead8(u8Len); + + if (u8Len & MDNS_DOMAIN_COMPRESS_MARK) + { + // Compressed label(s) + uint16_t u16Offset = ((u8Len & ~MDNS_DOMAIN_COMPRESS_MARK) << 8); // Implicit BE to LE conversion! + _udpRead8(u8Len); + u16Offset |= u8Len; + + if (m_rUDPContext.isValidOffset(u16Offset)) + { + size_t stCurrentPosition = m_rUDPContext.tell(); // Prepare return from recursion + + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Redirecting from %u to %u!\n"), _DH(), p_u8Depth, stCurrentPosition, u16Offset);); + m_rUDPContext.seek(u16Offset); + if (_readRRDomain_Loop(p_rRRDomain, p_u8Depth + 1)) // Do recursion + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Succeeded to read redirected label! Returning to %u\n"), _DH(), p_u8Depth, stCurrentPosition);); + m_rUDPContext.seek(stCurrentPosition); // Restore after recursion + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): FAILED to read redirected label!\n"), _DH(), p_u8Depth);); + bResult = false; + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): INVALID offset in redirection!\n"), _DH(), p_u8Depth);); + bResult = false; + } + break; + } + else + { + // Normal (uncompressed) label (maybe '\0' only) + if (MDNS_DOMAIN_MAXLENGTH > (p_rRRDomain.m_u16NameLength + u8Len)) + { + // Add length byte + p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength] = u8Len; + ++(p_rRRDomain.m_u16NameLength); + if (u8Len) // Add name + { + if ((bResult = _udpReadBuffer((unsigned char*) & (p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength]), u8Len))) + { + /* DEBUG_EX_INFO( + p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength + u8Len] = 0; // Closing '\0' for printing + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Domain label (%u): %s\n"), _DH(), p_u8Depth, (unsigned)(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength - 1]), &(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength])); + );*/ + + p_rRRDomain.m_u16NameLength += u8Len; + } + } + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(2) offset:%u p0:%x\n"), _DH(), m_rUDPContext.tell(), m_rUDPContext.peek());); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): ERROR! Domain name too long (%u + %u)!\n"), _DH(), p_u8Depth, p_rRRDomain.m_u16NameLength, u8Len);); + bResult = false; + break; + } + } + } while ((bResult) && + (0 != u8Len)); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): ERROR! Too many redirections!\n"), _DH(), p_u8Depth);); + } + return bResult; +} + +/* + MDNSResponder::_readRRAttributes +*/ +bool MDNSResponder::clsHost::_readRRAttributes(MDNSResponder::clsHost::stcRRAttributes& p_rRRAttributes) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAttributes\n"));); + + bool bResult = ((_udpRead16(p_rRRAttributes.m_u16Type)) && + (_udpRead16(p_rRRAttributes.m_u16Class))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAttributes: FAILED!\n"), _DH());); + return bResult; +} + + +/* + DOMAIN NAMES +*/ + +/* + MDNSResponder::_buildDomainForHost + + Builds a MDNS host domain (eg. esp8266.local) for the given hostname. + +*/ +bool MDNSResponder::clsHost::_buildDomainForHost(const char* p_pcHostName, + MDNSResponder::clsHost::stcRRDomain& p_rHostDomain) const +{ + + p_rHostDomain.clear(); + bool bResult = ((p_pcHostName) && + (*p_pcHostName) && + (p_rHostDomain.addLabel(p_pcHostName)) && + (p_rHostDomain.addLabel(scpcLocal)) && + (p_rHostDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForHost: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_buildDomainForDNSSD + + Builds the '_services._dns-sd._udp.local' domain. + Used while detecting generic service enum question (DNS-SD) and answering these questions. + +*/ +bool MDNSResponder::clsHost::_buildDomainForDNSSD(MDNSResponder::clsHost::stcRRDomain& p_rDNSSDDomain) const +{ + p_rDNSSDDomain.clear(); + bool bResult = ((p_rDNSSDDomain.addLabel(scpcServices, true)) && + (p_rDNSSDDomain.addLabel(scpcDNSSD, true)) && + (p_rDNSSDDomain.addLabel(scpcUDP, true)) && + (p_rDNSSDDomain.addLabel(scpcLocal)) && + (p_rDNSSDDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForDNSSD: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_buildDomainForService + + Builds the domain for the given service (eg. _http._tcp.local or + MyESP._http._tcp.local (if p_bIncludeName is set)). + +*/ +bool MDNSResponder::clsHost::_buildDomainForService(const MDNSResponder::clsHost::stcService& p_Service, + bool p_bIncludeName, + MDNSResponder::clsHost::stcRRDomain& p_rServiceDomain) const +{ + p_rServiceDomain.clear(); + bool bResult = (((!p_bIncludeName) || + (p_rServiceDomain.addLabel(p_Service.m_pcName))) && + (p_rServiceDomain.addLabel(p_Service.m_pcServiceType, ('_' != *p_Service.m_pcServiceType))) && + (p_rServiceDomain.addLabel(p_Service.m_pcProtocol, ('_' != *p_Service.m_pcProtocol))) && + (p_rServiceDomain.addLabel(scpcLocal)) && + (p_rServiceDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForService: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_buildDomainForService + + Builds the domain for the given service properties (eg. _http._tcp.local). + The usual prepended '_' are added, if missing in the input strings. + +*/ +bool MDNSResponder::clsHost::_buildDomainForService(const char* p_pcServiceType, + const char* p_pcProtocol, + MDNSResponder::clsHost::stcRRDomain& p_rServiceDomain) const +{ + p_rServiceDomain.clear(); + bool bResult = ((p_pcServiceType) && + (p_pcProtocol) && + (p_rServiceDomain.addLabel(p_pcServiceType, ('_' != *p_pcServiceType))) && + (p_rServiceDomain.addLabel(p_pcProtocol, ('_' != *p_pcProtocol))) && + (p_rServiceDomain.addLabel(scpcLocal)) && + (p_rServiceDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForService: FAILED for (%s.%s)!\n"), _DH(), (p_pcServiceType ? : "-"), (p_pcProtocol ? : "-"));); + return bResult; +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::_buildDomainForReverseIPv4 + + The IPv4 address is stringized by printing the four address bytes into a char buffer in reverse order + and adding 'in-addr.arpa' (eg. 012.789.456.123.in-addr.arpa). + Used while detecting reverse IPv4 questions and answering these +*/ +bool MDNSResponder::clsHost::_buildDomainForReverseIPv4(IPAddress p_IPv4Address, + MDNSResponder::clsHost::stcRRDomain& p_rReverseIPv4Domain) const +{ + bool bResult = ((p_IPv4Address.isSet()) && + (p_IPv4Address.isV4())); + + p_rReverseIPv4Domain.clear(); + + char acBuffer[32]; + for (int i = MDNS_IPV4_SIZE; ((bResult) && (i >= 1)); --i) + { + itoa(p_IPv4Address[i - 1], acBuffer, 10); + bResult = p_rReverseIPv4Domain.addLabel(acBuffer); + } + bResult = ((bResult) && + (p_rReverseIPv4Domain.addLabel(scpcReverseIPv4Domain)) && + (p_rReverseIPv4Domain.addLabel(scpcReverseTopDomain)) && + (p_rReverseIPv4Domain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForReverseIPv4: FAILED!\n"), _DH());); + return bResult; +} +#endif + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::_buildDomainForReverseIPv6 + + The IPv6 address is stringized by printing the 16 address bytes (32 nibbles) into a char buffer in reverse order + and adding 'ip6.arpa' (eg. 3.B.6.E.A.1.B.B.A.B.F.7.F.8.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.8.E.F.ip6.arpa). + Used while detecting reverse IPv6 questions and answering these +*/ +bool MDNSResponder::clsHost::_buildDomainForReverseIPv6(IPAddress p_IPv6Address, + MDNSResponder::clsHost::stcRRDomain& p_rReverseIPv6Domain) const +{ + bool bResult = ((p_IPv6Address.isSet()) && + (p_IPv6Address.isV6())); + + p_rReverseIPv6Domain.clear(); + + const uint16_t* pRaw = p_IPv6Address.raw6(); + for (int8_t i8 = (MDNS_IPV6_SIZE / 2); ((bResult) && (i8 > 0)); --i8) // 8..1 + { + uint16_t u16Part = ntohs(pRaw[i8 - 1] & 0xFFFF); + char acBuffer[2]; + for (uint8_t u8 = 0; ((bResult) && (u8 < 4)); ++u8) // 0..3 + { + itoa((u16Part & 0xF), acBuffer, 16); + bResult = p_rReverseIPv6Domain.addLabel(acBuffer); + u16Part >>= 4; + } + } + bResult = ((bResult) && + (p_rReverseIPv6Domain.addLabel(scpcReverseIPv6Domain)) && // .ip6.arpa + (p_rReverseIPv6Domain.addLabel(scpcReverseTopDomain)) && // .local + (p_rReverseIPv6Domain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForReverseIPv6: FAILED!\n"), _DH());); + return bResult; +} +#endif + + +/* + UDP +*/ + +/* + MDNSResponder::_udpReadBuffer +*/ +bool MDNSResponder::clsHost::_udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength) +{ + bool bResult = ((true/*m_rUDPContext.getSize() > p_stLength*/) && + (p_pBuffer) && + (p_stLength) && + ((p_stLength == m_rUDPContext.read((char*)p_pBuffer, p_stLength)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _udpReadBuffer: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_udpRead8 +*/ +bool MDNSResponder::clsHost::_udpRead8(uint8_t& p_ru8Value) +{ + return _udpReadBuffer((unsigned char*)&p_ru8Value, sizeof(p_ru8Value)); +} + +/* + MDNSResponder::_udpRead16 +*/ +bool MDNSResponder::clsHost::_udpRead16(uint16_t& p_ru16Value) +{ + bool bResult = false; + + if (_udpReadBuffer((unsigned char*)&p_ru16Value, sizeof(p_ru16Value))) + { + p_ru16Value = lwip_ntohs(p_ru16Value); + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::_udpRead32 +*/ +bool MDNSResponder::clsHost::_udpRead32(uint32_t& p_ru32Value) +{ + bool bResult = false; + + if (_udpReadBuffer((unsigned char*)&p_ru32Value, sizeof(p_ru32Value))) + { + p_ru32Value = lwip_ntohl(p_ru32Value); + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::_udpAppendBuffer +*/ +bool MDNSResponder::clsHost::_udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength) +{ + bool bResult = ((p_pcBuffer) && + (p_stLength) && + (p_stLength == m_rUDPContext.append((const char*)p_pcBuffer, p_stLength))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _udpAppendBuffer: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_udpAppend8 +*/ +bool MDNSResponder::clsHost::_udpAppend8(uint8_t p_u8Value) +{ + return (_udpAppendBuffer((unsigned char*)&p_u8Value, sizeof(p_u8Value))); +} + +/* + MDNSResponder::_udpAppend16 +*/ +bool MDNSResponder::clsHost::_udpAppend16(uint16_t p_u16Value) +{ + p_u16Value = lwip_htons(p_u16Value); + return (_udpAppendBuffer((unsigned char*)&p_u16Value, sizeof(p_u16Value))); +} + +/* + MDNSResponder::_udpAppend32 +*/ +bool MDNSResponder::clsHost::_udpAppend32(uint32_t p_u32Value) +{ + p_u32Value = lwip_htonl(p_u32Value); + return (_udpAppendBuffer((unsigned char*)&p_u32Value, sizeof(p_u32Value))); +} + +#ifdef DEBUG_ESP_MDNS_RESPONDER +/* + MDNSResponder::_udpDump +*/ +bool MDNSResponder::clsHost::_udpDump(bool p_bMovePointer /*= false*/) +{ + const uint8_t cu8BytesPerLine = 16; + + uint32_t u32StartPosition = m_rUDPContext.tell(); + DEBUG_OUTPUT.println("UDP Context Dump:"); + uint32_t u32Counter = 0; + uint8_t u8Byte = 0; + + while (_udpRead8(u8Byte)) + { + DEBUG_OUTPUT.printf_P(PSTR("%02x %s"), u8Byte, ((++u32Counter % cu8BytesPerLine) ? "" : "\n")); + } + DEBUG_OUTPUT.printf_P(PSTR("%sDone: %u bytes\n"), (((u32Counter) && (u32Counter % cu8BytesPerLine)) ? "\n" : ""), u32Counter); + + if (!p_bMovePointer) // Restore + { + m_rUDPContext.seek(u32StartPosition); + } + return true; +} + +/* + MDNSResponder::_udpDump +*/ +bool MDNSResponder::clsHost::_udpDump(unsigned p_uOffset, + unsigned p_uLength) +{ + if (m_rUDPContext.isValidOffset(p_uOffset)) + { + unsigned uCurrentPosition = m_rUDPContext.tell(); // Remember start position + + m_rUDPContext.seek(p_uOffset); + uint8_t u8Byte; + for (unsigned u = 0; ((u < p_uLength) && (_udpRead8(u8Byte))); ++u) + { + DEBUG_OUTPUT.printf_P(PSTR("%02x "), u8Byte); + } + // Return to start position + m_rUDPContext.seek(uCurrentPosition); + } + return true; +} +#endif + + +/** + READ/WRITE MDNS STRUCTS +*/ + +/* + MDNSResponder::_readMDNSMsgHeader + + Read a MDNS header from the UDP input buffer. + | 8 | 8 | 8 | 8 | + 00| Identifier | Flags & Codes | + 01| Question count | Answer count | + 02| NS answer count | Ad answer count | + + All 16-bit and 32-bit elements need to be translated form network coding to host coding (done in _udpRead16 and _udpRead32) + In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they + need some mapping here +*/ +bool MDNSResponder::clsHost::_readMDNSMsgHeader(MDNSResponder::clsHost::stcMsgHeader& p_rMsgHeader) +{ + bool bResult = false; + + uint8_t u8B1; + uint8_t u8B2; + if ((_udpRead16(p_rMsgHeader.m_u16ID)) && + (_udpRead8(u8B1)) && + (_udpRead8(u8B2)) && + (_udpRead16(p_rMsgHeader.m_u16QDCount)) && + (_udpRead16(p_rMsgHeader.m_u16ANCount)) && + (_udpRead16(p_rMsgHeader.m_u16NSCount)) && + (_udpRead16(p_rMsgHeader.m_u16ARCount))) + { + + p_rMsgHeader.m_1bQR = (u8B1 & 0x80); // Query/Responde flag + p_rMsgHeader.m_4bOpcode = (u8B1 & 0x78); // Operation code (0: Standard query, others ignored) + p_rMsgHeader.m_1bAA = (u8B1 & 0x04); // Authorative answer + p_rMsgHeader.m_1bTC = (u8B1 & 0x02); // Truncation flag + p_rMsgHeader.m_1bRD = (u8B1 & 0x01); // Recursion desired + + p_rMsgHeader.m_1bRA = (u8B2 & 0x80); // Recursion available + p_rMsgHeader.m_3bZ = (u8B2 & 0x70); // Zero + p_rMsgHeader.m_4bRCode = (u8B2 & 0x0F); // Response code + + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + _DH(), + (unsigned)p_rMsgHeader.m_u16ID, + (unsigned)p_rMsgHeader.m_1bQR, (unsigned)p_rMsgHeader.m_4bOpcode, (unsigned)p_rMsgHeader.m_1bAA, (unsigned)p_rMsgHeader.m_1bTC, (unsigned)p_rMsgHeader.m_1bRD, + (unsigned)p_rMsgHeader.m_1bRA, (unsigned)p_rMsgHeader.m_4bRCode, + (unsigned)p_rMsgHeader.m_u16QDCount, + (unsigned)p_rMsgHeader.m_u16ANCount, + (unsigned)p_rMsgHeader.m_u16NSCount, + (unsigned)p_rMsgHeader.m_u16ARCount););*/ + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readMDNSMsgHeader: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_write8 +*/ +bool MDNSResponder::clsHost::_write8(uint8_t p_u8Value, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + return ((_udpAppend8(p_u8Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u8Value)))); +} + +/* + MDNSResponder::_write16 +*/ +bool MDNSResponder::clsHost::_write16(uint16_t p_u16Value, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + return ((_udpAppend16(p_u16Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u16Value)))); +} + +/* + MDNSResponder::_write32 +*/ +bool MDNSResponder::clsHost::_write32(uint32_t p_u32Value, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + return ((_udpAppend32(p_u32Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u32Value)))); +} + +/* + MDNSResponder::_writeMDNSMsgHeader + + Write MDNS header to the UDP output buffer. + + All 16-bit and 32-bit elements need to be translated form host coding to network coding (done in _udpAppend16 and _udpAppend32) + In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they + need some mapping here +*/ +bool MDNSResponder::clsHost::_writeMDNSMsgHeader(const MDNSResponder::clsHost::stcMsgHeader& p_MsgHeader, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + _DH(), + (unsigned)p_MsgHeader.m_u16ID, + (unsigned)p_MsgHeader.m_1bQR, (unsigned)p_MsgHeader.m_4bOpcode, (unsigned)p_MsgHeader.m_1bAA, (unsigned)p_MsgHeader.m_1bTC, (unsigned)p_MsgHeader.m_1bRD, + (unsigned)p_MsgHeader.m_1bRA, (unsigned)p_MsgHeader.m_4bRCode, + (unsigned)p_MsgHeader.m_u16QDCount, + (unsigned)p_MsgHeader.m_u16ANCount, + (unsigned)p_MsgHeader.m_u16NSCount, + (unsigned)p_MsgHeader.m_u16ARCount););*/ + + uint8_t u8B1((p_MsgHeader.m_1bQR << 7) | (p_MsgHeader.m_4bOpcode << 3) | (p_MsgHeader.m_1bAA << 2) | (p_MsgHeader.m_1bTC << 1) | (p_MsgHeader.m_1bRD)); + uint8_t u8B2((p_MsgHeader.m_1bRA << 7) | (p_MsgHeader.m_3bZ << 4) | (p_MsgHeader.m_4bRCode)); + bool bResult = ((_write16(p_MsgHeader.m_u16ID, p_rSendParameter)) && + (_write8(u8B1, p_rSendParameter)) && + (_write8(u8B2, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16QDCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16ANCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16NSCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16ARCount, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSMsgHeader: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeRRAttributes +*/ +bool MDNSResponder::clsHost::_writeMDNSRRAttributes(const MDNSResponder::clsHost::stcRRAttributes& p_Attributes, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + bool bResult = ((_write16(p_Attributes.m_u16Type, p_rSendParameter)) && + (_write16(p_Attributes.m_u16Class, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSRRAttributes: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeMDNSRRDomain +*/ +bool MDNSResponder::clsHost::_writeMDNSRRDomain(const MDNSResponder::clsHost::stcRRDomain& p_Domain, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + bool bResult = ((_udpAppendBuffer((const unsigned char*)p_Domain.m_acName, p_Domain.m_u16NameLength)) && + (p_rSendParameter.shiftOffset(p_Domain.m_u16NameLength))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSRRDomain: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeMDNSHostDomain + + Write a host domain to the UDP output buffer. + If the domain record is part of the answer, the records length is + prepended (p_bPrependRDLength is set). + + A very simple form of name compression is applied here: + If the domain is written to the UDP output buffer, the write offset is stored + together with a domain id (the pointer) in a p_rSendParameter substructure (cache). + If the same domain (pointer) should be written to the UDP output later again, + the old offset is retrieved from the cache, marked as a compressed domain offset + and written to the output buffer. + +*/ +bool MDNSResponder::clsHost::_writeMDNSHostDomain(const char* p_pcHostName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' + uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)p_pcHostName, false); + + stcRRDomain hostDomain; + bool bResult = (u16CachedDomainOffset + // Found cached domain -> mark as compressed domain + ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + ((!p_bPrependRDLength) || + (_write16((2 + p_u16AdditionalLength), p_rSendParameter))) && // Length of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) + // No cached domain -> add this domain to cache and write full domain name + : ((_buildDomainForHost(p_pcHostName, hostDomain)) && // eg. esp8266.local + ((!p_bPrependRDLength) || + (_write16((hostDomain.m_u16NameLength + p_u16AdditionalLength), p_rSendParameter))) && // RDLength (if needed) + (p_rSendParameter.addDomainCacheItem((const void*)p_pcHostName, false, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(hostDomain, p_rSendParameter)))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSHostDomain: FAILED!\n"), _DH());); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSServiceDomain + + Write a service domain to the UDP output buffer. + If the domain record is part of the answer, the records length is + prepended (p_bPrependRDLength is set). + + A very simple form of name compression is applied here: see '_writeMDNSHostDomain' + The cache differentiates of course between service domains which includes + the instance name (p_bIncludeName is set) and thoose who don't. + +*/ +bool MDNSResponder::clsHost::_writeMDNSServiceDomain(const MDNSResponder::clsHost::stcService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' + uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)&p_Service, p_bIncludeName); + + stcRRDomain serviceDomain; + bool bResult = (u16CachedDomainOffset + // Found cached domain -> mark as compressed domain + ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + ((!p_bPrependRDLength) || + (_write16((2 + p_u16AdditionalLength), p_rSendParameter))) && // Lenght of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) + // No cached domain -> add this domain to cache and write full domain name + : ((_buildDomainForService(p_Service, p_bIncludeName, serviceDomain)) && // eg. MyESP._http._tcp.local + ((!p_bPrependRDLength) || + (_write16((serviceDomain.m_u16NameLength + p_u16AdditionalLength), p_rSendParameter))) && // RDLength (if needed) + (p_rSendParameter.addDomainCacheItem((const void*)&p_Service, p_bIncludeName, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(serviceDomain, p_rSendParameter)))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSServiceDomain: FAILED!\n"), _DH());); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSQuestion + + Write a MDNS question to the UDP output buffer + + QNAME (host/service domain, eg. esp8266.local) + QTYPE (16bit, eg. ANY) + QCLASS (16bit, eg. IN) + +*/ +bool MDNSResponder::clsHost::_writeMDNSQuestion(MDNSResponder::clsHost::stcRRQuestion& p_Question, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSQuestion\n"));); + + bool bResult = ((_writeMDNSRRDomain(p_Question.m_Header.m_Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(p_Question.m_Header.m_Attributes, p_rSendParameter))); + + DEBUG_EX_INFO(if (bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSQuestion "), _DH()); + _printRRDomain(p_Question.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X\n"), + _RRType2Name(p_Question.m_Header.m_Attributes.m_u16Type), + p_Question.m_Header.m_Attributes.m_u16Class); + }); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSQuestion: FAILED!\n"), _DH());); + return bResult; + +} + + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_A + + Write a MDNS A answer to the UDP output buffer. + + NAME (var, host/service domain, eg. esp8266.local + TYPE (16bit, eg. A) + CLASS (16bit, eg. IN) + TTL (32bit, eg. 120) + RDLENGTH (16bit, eg 4) + RDATA (var, eg. 123.456.789.012) + + eg. esp8266.local A 0x8001 120 4 123.456.789.012 + Ref: http://www.zytrax.com/books/dns/ch8/a.html +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_A(IPAddress p_IPAddress, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_A (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + stcRRAttributes attributes(DNS_RRTYPE_A, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + const unsigned char aucIPAddress[MDNS_IPV4_SIZE] = { p_IPAddress[0], p_IPAddress[1], p_IPAddress[2], p_IPAddress[3] }; + bool bResult = ((p_IPAddress.isV4()) && + (_writeMDNSHostDomain(m_pcHostName, false, 0, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + (_write16(MDNS_IPV4_SIZE, p_rSendParameter)) && // RDLength + (_udpAppendBuffer(aucIPAddress, MDNS_IPV4_SIZE)) && // RData + (p_rSendParameter.shiftOffset(MDNS_IPV4_SIZE))); + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_A %s.local Type:%s Class:0x%04X TTL:%u %s\n"), + _DH(), + m_pcHostName, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + p_IPAddress.toString().c_str()); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_A: FAILED!\n"), _DH());); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_IPv4 + + Write a MDNS reverse IPv4 PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + eg. 012.789.456.123.in-addr.arpa PTR 0x8001 120 15 esp8266.local + Used while answering reverse IPv4 questions +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv4 (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + stcRRDomain reverseIPv4Domain; + stcRRAttributes attributes(DNS_RRTYPE_PTR, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + stcRRDomain hostDomain; + bool bResult = ((p_IPAddress.isV4()) && + (_buildDomainForReverseIPv4(p_IPAddress, reverseIPv4Domain)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSRRDomain(reverseIPv4Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + (_writeMDNSHostDomain(m_pcHostName, true, 0, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv4 "), _DH()); + _printRRDomain(reverseIPv4Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u %s.local\n"), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + m_pcHostName); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv4: FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_PTR_TYPE + + Write a MDNS PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + PTR all-services -> service type + eg. _services._dns-sd._udp.local PTR 0x8001 5400 xx _http._tcp.local + http://www.zytrax.com/books/dns/ch8/ptr.html +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_TYPE(MDNSResponder::clsHost::stcService& p_rService, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_TYPE\n"));); + + stcRRDomain dnssdDomain; + stcRRDomain serviceDomain; + stcRRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush for shared records! only INternet + bool bResult = ((_buildDomainForDNSSD(dnssdDomain)) && // _services._dns-sd._udp.local + (_writeMDNSRRDomain(dnssdDomain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, false, true, 0, p_rSendParameter))); // RDLength & RData (service domain, eg. _http._tcp.local) + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_TYPE "), _DH()); + _printRRDomain(dnssdDomain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u _%s._%s.local\n"), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), + p_rService.m_pcServiceType, + p_rService.m_pcProtocol); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_TYPE: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_NAME + + Write a MDNS PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + PTR service type -> service name + eg. _http.tcp.local PTR 0x8001 120 xx myESP._http._tcp.local + http://www.zytrax.com/books/dns/ch8/ptr.html +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_NAME(MDNSResponder::clsHost::stcService& p_rService, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME\n"), _DH());); + + stcRRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush for shared records! only INternet + bool bResult = ((_writeMDNSServiceDomain(p_rService, false, false, 0, p_rSendParameter)) && // _http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, true, true, 0, p_rSendParameter))); // RDLength & RData (service domain, eg. MyESP._http._tcp.local) + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME _%s._%s.local Type:%s Class:0x%04X TTL:%u %s._%s._%s.local\n"), + _DH(), + p_rService.m_pcServiceType, + p_rService.m_pcProtocol, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), + p_rService.m_pcName, + p_rService.m_pcServiceType, + p_rService.m_pcProtocol); + ); + DEBUG_EX_ERR(if (!bResult)DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME: FAILED!\n"), _DH());); + return bResult; +} + + +/* + MDNSResponder::_writeMDNSAnswer_TXT + + Write a MDNS TXT answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + The TXT items in the RDATA block are 'length byte encoded': [len]vardata + + eg. myESP._http._tcp.local TXT 0x8001 120 4 c#=1 + http://www.zytrax.com/books/dns/ch8/txt.html +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_TXT(MDNSResponder::clsHost::stcService& p_rService, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"), _DH());); + + bool bResult = false; + + stcRRAttributes attributes(DNS_RRTYPE_TXT, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + + if ((_collectServiceTxts(p_rService)) && + (_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), p_rSendParameter)) && // TTL + (_write16(p_rService.m_Txts.length(), p_rSendParameter))) // RDLength + { + + bResult = true; + // RData Txts + for (stcServiceTxt* pTxt = p_rService.m_Txts.m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + unsigned char ucLengthByte = pTxt->length(); + bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length + (p_rSendParameter.shiftOffset(sizeof(ucLengthByte))) && + ((size_t)os_strlen(pTxt->m_pcKey) == m_rUDPContext.append(pTxt->m_pcKey, os_strlen(pTxt->m_pcKey))) && // Key + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcKey))) && + (1 == m_rUDPContext.append("=", 1)) && // = + (p_rSendParameter.shiftOffset(1)) && + ((!pTxt->m_pcValue) || + (((size_t)os_strlen(pTxt->m_pcValue) == m_rUDPContext.append(pTxt->m_pcValue, os_strlen(pTxt->m_pcValue))) && // Value + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcValue)))))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: FAILED to write %sTxt %s=%s!\n"), _DH(), (pTxt->m_bTemp ? "temp. " : ""), (pTxt->m_pcKey ? : "?"), (pTxt->m_pcValue ? : "?"));); + } + } + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT %s._%s._%s.local Type:%s Class:0x%04X TTL:%u \n"), + _DH(), + p_rService.m_pcName, + p_rService.m_pcServiceType, + p_rService.m_pcProtocol, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), + p_rService.m_pcName, + p_rService.m_pcServiceType, + p_rService.m_pcProtocol); + ); + + _releaseTempServiceTxts(p_rService); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: FAILED!\n"), _DH());); + return bResult; +} + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_AAAA + + Write a MDNS AAAA answer to the UDP output buffer. + See: '_writeMDNSAnswer_AAAA' + + eg. esp8266.local AAAA 0x8001 120 16 xxxx::xx + http://www.zytrax.com/books/dns/ch8/aaaa.html +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + stcRRAttributes attributes(DNS_RRTYPE_AAAA, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + bool bResult = ((p_IPAddress.isV6()) && + (_writeMDNSHostDomain(m_pcHostName, false, 0, p_rSendParameter)) && // esp8266.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + (_write16(MDNS_IPV6_SIZE, p_rSendParameter)) && // RDLength + (_udpAppendBuffer((uint8_t*)p_IPAddress.raw6(), MDNS_IPV6_SIZE)) && // RData + (p_rSendParameter.shiftOffset(MDNS_IPV6_SIZE))); + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA %s.local Type:%s Class:0x%04X TTL:%u %s\n"), + _DH(), + m_pcHostName, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + p_IPAddress.toString().c_str()); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_IPv6 + + Write a MDNS reverse IPv6 PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_AAAA' + + eg. xxxx::xx.ip6.arpa PTR 0x8001 120 15 esp8266.local + Used while answering reverse IPv6 questions +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv6%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + stcRRDomain reverseIPv6Domain; + stcRRAttributes attributes(DNS_RRTYPE_PTR, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + bool bResult = ((p_IPAddress.isV6()) && + (_buildDomainForReverseIPv6(p_IPAddress, reverseIPv6Domain)) && // xxxx::xx.ip6.arpa + (_writeMDNSRRDomain(reverseIPv6Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + (_writeMDNSHostDomain(m_pcHostName, true, 0, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv6 "), _DH()); + _printRRDomain(reverseIPv6Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u %s.local\n"), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + m_pcHostName); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv6: FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_SRV + + eg. MyESP._http.tcp.local SRV 0x8001 120 0 0 60068 esp8266.local + http://www.zytrax.com/books/dns/ch8/srv.html ???? Include instance name ???? +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_SRV(MDNSResponder::clsHost::stcService& p_rService, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_SRV%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyQuery + ? 0 + : p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostName, false)); + + stcRRAttributes attributes(DNS_RRTYPE_SRV, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + stcRRDomain hostDomain; + bool bResult = ((_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL/*MDNS_SERVICE_TTL*/)), p_rSendParameter)) && // TTL + (!u16CachedDomainOffset + // No cache for domain name (or no compression allowed) + ? ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (_write16((sizeof(uint16_t /*Prio*/) + // RDLength + sizeof(uint16_t /*Weight*/) + + sizeof(uint16_t /*Port*/) + + hostDomain.m_u16NameLength), p_rSendParameter)) && // Domain length + (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority + (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight + (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port + (p_rSendParameter.addDomainCacheItem((const void*)m_pcHostName, false, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(hostDomain, p_rSendParameter))) // Host, eg. esp8266.local + // Cache available for domain + : ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + (_write16((sizeof(uint16_t /*Prio*/) + // RDLength + sizeof(uint16_t /*Weight*/) + + sizeof(uint16_t /*Port*/) + + 2), p_rSendParameter)) && // Length of 'C0xx' + (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority + (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight + (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port + (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)u16CachedDomainOffset, p_rSendParameter))))); // Offset + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_SRV %s._%s._%s.local Type:%s Class:0x%04X TTL:%u %u %u %u %s.local\n"), + _DH(), + p_rService.m_pcName, + p_rService.m_pcServiceType, + p_rService.m_pcProtocol, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + MDNS_SRV_PRIORITY, + MDNS_SRV_WEIGHT, + p_rService.m_u16Port, + m_pcHostName); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_SRV: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_createNSECBitmap +*/ +MDNSResponder::clsHost::stcNSECBitmap* MDNSResponder::clsHost::_createNSECBitmap(uint32_t p_u32NSECContent) +{ + // Currently 6 bytes (6*8 -> 0..47) are long enough, and only this is implemented + stcNSECBitmap* pNSECBitmap = new stcNSECBitmap; + if (pNSECBitmap) + { + if (p_u32NSECContent & static_cast(enuContentFlag::A)) + { + pNSECBitmap->setBit(DNS_RRTYPE_A); // 01/0x01 + } + if ((p_u32NSECContent & static_cast(enuContentFlag::PTR_IPv4)) || + (p_u32NSECContent & static_cast(enuContentFlag::PTR_IPv6))) + { + pNSECBitmap->setBit(DNS_RRTYPE_PTR); // 12/0x0C + } + if (p_u32NSECContent & static_cast(enuContentFlag::AAAA)) + { + pNSECBitmap->setBit(DNS_RRTYPE_AAAA); // 28/0x1C + } + if (p_u32NSECContent & static_cast(enuContentFlag::TXT)) + { + pNSECBitmap->setBit(DNS_RRTYPE_TXT); // 16/0x10 + } + if (p_u32NSECContent & static_cast(enuContentFlag::SRV)) + { + pNSECBitmap->setBit(DNS_RRTYPE_SRV); // 33/0x21 + } + if (p_u32NSECContent & static_cast(enuContentFlag::NSEC)) + { + pNSECBitmap->setBit(DNS_RRTYPE_NSEC); // 47/0x2F + } + } + return pNSECBitmap; +} + +/* + MDNSResponder::_writeMDNSNSECBitmap +*/ +bool MDNSResponder::clsHost::_writeMDNSNSECBitmap(const MDNSResponder::clsHost::stcNSECBitmap& p_NSECBitmap, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("_writeMDNSNSECBitmap: ")); + for (uint16_t u=0; ulength()), p_rSendParameter)) && // XX esp8266.local + (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC %s.local Type:%s Class:0x%04X TTL:%u %s %s\n"), + _DH(), + m_pcHostName, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + m_pcHostName, + _NSECBitmap2String(pNSECBitmap)); + ); + + if (pNSECBitmap) + { + delete pNSECBitmap; + pNSECBitmap = 0; + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC (host): FAILED!\n"), _DH());); + return bResult; +} + + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_NSEC_PTR_IPv4(host) + + eg. 012.789.456.123.in-addr.arpa NSEC 0x8001 120 XX 012.789.456.123.in-addr.arpa xxx + http://www.zytrax.com/books/dns/ch8/nsec.html +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddress, + stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv4\n"));); + + stcRRAttributes attributes(DNS_RRTYPE_NSEC, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + stcNSECBitmap* pNSECBitmap = _createNSECBitmap(static_cast(enuContentFlag::PTR_IPv4)); + stcRRDomain reverseIPv4Domain; + bool bResult = ((p_IPAddress.isV4()) && + (pNSECBitmap) && // NSEC bitmap created + (_buildDomainForReverseIPv4(p_IPAddress, reverseIPv4Domain)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSRRDomain(reverseIPv4Domain, p_rSendParameter)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + (_write16((reverseIPv4Domain.m_u16NameLength + (2 + pNSECBitmap->length())), p_rSendParameter)) && + (_writeMDNSRRDomain(reverseIPv4Domain, p_rSendParameter)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap + + DEBUG_EX_INFO(if (bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv4 "), _DH()); + _printRRDomain(reverseIPv4Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u "), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL))); + _printRRDomain(reverseIPv4Domain); + DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), _NSECBitmap2String(pNSECBitmap)); + }); + + if (pNSECBitmap) + { + delete pNSECBitmap; + pNSECBitmap = 0; + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv4 (host): FAILED!\n"), _DH());); + return bResult; +} +#endif + + +#ifdef MDNS_IPV6_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_NSEC_PTR_IPv6(host) + + eg. 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa NSEC 0x8001 120 XX 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa xxx + http://www.zytrax.com/books/dns/ch8/nsec.html +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddress, + stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv6\n"));); + + stcRRAttributes attributes(DNS_RRTYPE_NSEC, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + stcNSECBitmap* pNSECBitmap = _createNSECBitmap(static_cast(enuContentFlag::PTR_IPv6)); + stcRRDomain reverseIPv6Domain; + bool bResult = ((p_IPAddress.isV6()) && + (pNSECBitmap) && // NSEC bitmap created + (_buildDomainForReverseIPv6(p_IPAddress, reverseIPv6Domain)) && // 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa + (_writeMDNSRRDomain(reverseIPv6Domain, p_rSendParameter)) && // 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + (_write16((reverseIPv6Domain.m_u16NameLength + (2 + pNSECBitmap->length())), p_rSendParameter)) && + (_writeMDNSRRDomain(reverseIPv6Domain, p_rSendParameter)) && // 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa + (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap + + DEBUG_EX_INFO(if (bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv6 "), _DH()); + _printRRDomain(reverseIPv6Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u "), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL))); + _printRRDomain(reverseIPv6Domain); + DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), _NSECBitmap2String(pNSECBitmap)); + }); + + if (pNSECBitmap) + { + delete pNSECBitmap; + pNSECBitmap = 0; + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv6 (host): FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_NSEC(service) + + eg. MyESP._http.tcp.local NSEC 0x8001 4500 XX MyESP._http.tcp.local xxx + http://www.zytrax.com/books/dns/ch8/nsec.html +*/ +bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC(MDNSResponder::clsHost::stcService& p_rService, + uint32_t p_u32NSECContent, + MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC (service: %s)\n"), _DH(), _replyFlags2String(p_u32NSECContent));); + + stcRRAttributes attributes(DNS_RRTYPE_NSEC, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + stcNSECBitmap* pNSECBitmap = _createNSECBitmap(p_u32NSECContent); + bool bResult = ((pNSECBitmap) && // NSEC bitmap created + (_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, true, true, (2 + pNSECBitmap->length()), p_rSendParameter)) && // XX MyESP._http._tcp.local + (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC %s._%s._%s.local Type:%s Class:0x%04X TTL:%u %s\n"), + _DH(), + p_rService.m_pcName, + p_rService.m_pcServiceType, + p_rService.m_pcProtocol, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), + _NSECBitmap2String(pNSECBitmap)); + ); + + if (pNSECBitmap) + { + delete pNSECBitmap; + pNSECBitmap = 0; + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC (service): FAILED!\n"), _DH());); + return bResult; +} + +} // namespace MDNSImplementation + +} // namespace esp8266 + + + + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h b/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h new file mode 100755 index 0000000000..240700b7cf --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h @@ -0,0 +1,169 @@ +/* + LEAmDNS2_Priv.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef LEAMDNS2_PRIV_H +#define LEAMDNS2_PRIV_H + +namespace esp8266 +{ + +/* + LEAmDNS +*/ + +namespace experimental +{ + +// Enable class debug functions +#define ESP_8266_MDNS_INCLUDE +#define DEBUG_ESP_MDNS_RESPONDER + + +#ifndef LWIP_OPEN_SRC +#define LWIP_OPEN_SRC +#endif + +// +// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing +// This allows to drive the responder in a environment, where 'update()' isn't called in the loop +//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE + +// Enable/disable debug trace macros +#ifdef DEBUG_ESP_MDNS_RESPONDER +#define DEBUG_ESP_MDNS_INFO +#define DEBUG_ESP_MDNS_ERR +#define DEBUG_ESP_MDNS_TX +#define DEBUG_ESP_MDNS_RX +#endif + +#ifdef DEBUG_ESP_MDNS_RESPONDER +#ifdef DEBUG_ESP_MDNS_INFO +#define DEBUG_EX_INFO(A) A +#else +#define DEBUG_EX_INFO(A) +#endif +#ifdef DEBUG_ESP_MDNS_ERR +#define DEBUG_EX_ERR(A) A +#else +#define DEBUG_EX_ERR(A) +#endif +#ifdef DEBUG_ESP_MDNS_TX +#define DEBUG_EX_TX(A) A +#else +#define DEBUG_EX_TX(A) +#endif +#ifdef DEBUG_ESP_MDNS_RX +#define DEBUG_EX_RX(A) A +#else +#define DEBUG_EX_RX(A) +#endif + +#ifdef DEBUG_ESP_PORT +#define DEBUG_OUTPUT DEBUG_ESP_PORT +#else +#define DEBUG_OUTPUT Serial +#endif +#else +#define DEBUG_EX_INFO(A) +#define DEBUG_EX_ERR(A) +#define DEBUG_EX_TX(A) +#define DEBUG_EX_RX(A) +#endif + +/* + This is NOT the TTL (Time-To-Live) for MDNS records, but the + subnet level distance MDNS records should travel. + 1 sets the subnet distance to 'local', which is default for MDNS. + (Btw.: 255 would set it to 'as far as possible' -> internet) + + However, RFC 3171 seems to force 255 instead +*/ +#define MDNS_MULTICAST_TTL 255 /* some say 1 is right*/ + +/* + This is the MDNS record TTL + Host level records are set to 2min (120s) + service level records are set to 75min (4500s) +*/ +#define MDNS_LEGACY_TTL 10 +#define MDNS_HOST_TTL 120 +#define MDNS_SERVICE_TTL 4500 + +/* + Compressed labels are flaged by the two topmost bits of the length byte being set +*/ +#define MDNS_DOMAIN_COMPRESS_MARK 0xC0 +/* + Avoid endless recursion because of malformed compressed labels +*/ +#define MDNS_DOMAIN_MAX_REDIRCTION 6 + +/* + Default service priority and weight in SRV answers +*/ +#define MDNS_SRV_PRIORITY 0 +#define MDNS_SRV_WEIGHT 0 + +/* + Delay between and number of probes for host and service domains + Delay between and number of announces for host and service domains + Delay between and number of queries; the delay is multiplied by the resent number in '_checkQueryCache' +*/ +#define MDNS_PROBE_DELAY 250 +#define MDNS_PROBE_COUNT 3 +#define MDNS_ANNOUNCE_DELAY 1000 +#define MDNS_ANNOUNCE_COUNT 3 +#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 1000 + + +/* + Force host domain to use only lowercase letters +*/ +//#define MDNS_FORCE_LOWERCASE_HOSTNAME + +/* + Enable/disable the usage of the F() macro in debug trace printf calls. + There needs to be an PGM comptible printf function to use this. + + USE_PGM_PRINTF and F +*/ +#define USE_PGM_PRINTF + +#ifdef USE_PGM_PRINTF +#else +#ifdef F +#undef F +#endif +#define F(A) A +#endif + +} // namespace MDNSImplementation + +} // namespace esp8266 + +// Include the main header, so the submodlues only need to include this header +#include "LEAmDNS2.h" + + +#endif // LEAMDNS2_PRIV_H diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h b/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h new file mode 100755 index 0000000000..b28ea2a26e --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h @@ -0,0 +1,44 @@ +/* + LEAmDNS2_lwIPdefs.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef LEAMDNS2_LWIPDEFS_H +#define LEAMDNS2_LWIPDEFS_H + +#include +#if LWIP_VERSION_MAJOR == 1 + +#include // DNS_RRTYPE_xxx + +// cherry pick from lwip1 dns.c/mdns.c source files: +#define DNS_MQUERY_PORT 5353 +#define DNS_MQUERY_IPV4_GROUP_INIT IPAddress(224,0,0,251) /* resolver1.opendns.com */ +#define DNS_RRCLASS_ANY 255 /* any class */ + +#else // lwIP > 1 + +#include // DNS_RRTYPE_xxx, DNS_MQUERY_PORT + +#endif + +#endif // LEAMDNS2_LWIPDEFS_H From 560c2a5ca1ecdd066940ae292c56f0e29a8c2b14 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 8 May 2020 00:28:47 +0200 Subject: [PATCH 03/12] updated Source files from LEA --- .../LEAmDNS/TwoInterfaces/TwoInterfaces.ino | 165 + libraries/ESP8266mDNS/src/ESP8266mDNS.h | 7 +- libraries/ESP8266mDNS/src/LEAmDNS2.h | 1303 ------ libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp | 1428 ++++++ libraries/ESP8266mDNS/src/LEAmDNS2Host.h | 1658 +++++++ ...t_Control.cpp => LEAmDNS2Host_Control.cpp} | 1134 +++-- ..._Host_Debug.cpp => LEAmDNS2Host_Debug.cpp} | 153 +- .../ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp | 3253 +++++++++++++ ...Transfer.cpp => LEAmDNS2Host_Transfer.cpp} | 932 ++-- libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp | 4164 ----------------- .../ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp | 354 -- .../ESP8266mDNS/src/LEAmDNS2_Backbone.cpp | 339 ++ libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp | 1336 ------ libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp | 1177 ----- .../ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp | 2435 ---------- libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp | 1493 ++++++ libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h | 679 +++ libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h | 169 - libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h | 0 19 files changed, 10156 insertions(+), 12023 deletions(-) create mode 100644 libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino delete mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2.h create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS2Host.h rename libraries/ESP8266mDNS/src/{LEAmDNS2_Host_Control.cpp => LEAmDNS2Host_Control.cpp} (66%) mode change 100755 => 100644 rename libraries/ESP8266mDNS/src/{LEAmDNS2_Host_Debug.cpp => LEAmDNS2Host_Debug.cpp} (65%) mode change 100755 => 100644 create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp rename libraries/ESP8266mDNS/src/{LEAmDNS2_Host_Transfer.cpp => LEAmDNS2Host_Transfer.cpp} (71%) mode change 100755 => 100644 delete mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp delete mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp delete mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp delete mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp delete mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h delete mode 100755 libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h mode change 100755 => 100644 libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h diff --git a/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino b/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino new file mode 100644 index 0000000000..3434454491 --- /dev/null +++ b/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino @@ -0,0 +1,165 @@ + +#include +#include + +#include +#include + + +clsMDNSHost mDNSHost_AP; +clsMDNSHost mDNSHost_STA; +ESP8266WebServer server(80); + +void connectToWiFi(const char* p_pcSSID, + const char* p_pcPWD, + uint32_t p_u32Timeout = 20) +{ + WiFi.begin(p_pcSSID, p_pcPWD); + Serial.println(""); + + // Wait for connection + uint8 u8Tries = p_u32Timeout; + while ((WiFi.status() != WL_CONNECTED) && + (u8Tries--)) { + delay(500); + Serial.print("."); + } + if (WiFi.status() == WL_CONNECTED) + { + Serial.println(""); + Serial.print("Connected to "); + Serial.println(p_pcSSID); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + } + else + { + Serial.printf("FAILED to connect to '%s'!\n", p_pcSSID); + } +} + +void setup(void) +{ + Serial.begin(115200); + Serial.setDebugOutput(false); + delay(2000); + Serial.printf("\nStart\n"); + + // Setup WiFi and AP + WiFi.setAutoConnect(false); + WiFi.mode(WIFI_AP_STA); + WiFi.softAP("ESP8266", "12345678"); + Serial.print("Created AP "); + Serial.println("ESP8266"); + Serial.print("AP-IP address: "); + Serial.println(WiFi.softAPIP()); + + if (mDNSHost_AP.begin("ESP8266", WIFI_AP, [](clsMDNSHost& p_rMDNSHost, + const char* p_pcDomainName, + bool p_bProbeResult)->void + { + Serial.printf("mDNSHost_AP::ProbeResultCallback: '%s' is %s\n", p_pcDomainName, (p_bProbeResult ? "FREE" : "USED!")); + + // Unattended added service + p_rMDNSHost.addService(0, "http", "tcp", 80); + })) + { + Serial.println("mDNS-AP started"); + } + else + { + Serial.println("FAILED to start mDNS-AP"); + } + + // Connect to WiFi network, with WRONG password + connectToWiFi("AP8", "WRONG_PW", 5); + + if (mDNSHost_STA.begin("esp8266", WIFI_STA, [](clsMDNSHost& p_rMDNSHost, + const char* p_pcDomainName, + bool p_bProbeResult)->void + { + Serial.printf("mDNSHost_STA::ProbeResultCallback: '%s' is %s\n", p_pcDomainName, (p_bProbeResult ? "FREE" : "USED!")); + if (p_bProbeResult) + { + p_rMDNSHost.addService("LEA_Weather", "http", "tcp", 80, [](clsMDNSHost::clsService& p_rService, + const char* p_pcInstanceName, + bool p_bProbeResult)->void + { + Serial.printf("mDNSHost_STA::HTTP-Service::ProbeResultCallback: '%s' is %s\n", p_pcInstanceName, (p_bProbeResult ? "FREE" : "USED!")); + if (p_bProbeResult) + { + if (!p_rService.addServiceTxt("path", "/")) + { + Serial.println("FAILED to add service TXT item!"); + } + p_rService.setDynamicServiceTxtCallback([](clsMDNSHost::clsService& p_rService)->void + { + Serial.printf("mDNSHost_STA::HTTP-Service::DynamicTXTCallback\n"); + + p_rService.addDynamicServiceTxt("user", "admin"); + static uint32_t u32Counter = 0; + p_rService.addDynamicServiceTxt("cnt", ++u32Counter); + }); + } + else + { + if (p_rService.indexInstanceName()) + { + Serial.printf("Changed service instance name to '%s'\n", p_rService.instanceName()); + } + else + { + Serial.println("FAILED to index service instance name!"); + } + } + }); + + // Unattended added service + p_rMDNSHost.addService("MQTTInstance", "mqtt", "tcp", 1883); + } + else + { + p_rMDNSHost.indexHostName(); + } + })) + { + Serial.println("mDNS-STA started"); + } + else + { + Serial.println("FAILED to start mDNS-STA"); + } + + // Non-synchronized added service + mDNSHost_STA.addService(0, "test", "tcp", 999); + + // Setup HTTP server + server.on("/", [](void) + { + Serial.println("server.on"); + server.send(200, "text/plain", "test"); + }); + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) +{ + server.handleClient(); + mDNSHost_AP.update(); + mDNSHost_STA.update(); + + static esp8266::polledTimeout::oneShotMs timer2(esp8266::polledTimeout::oneShotMs::alwaysExpired); + if (timer2) + { + Serial.println("FIX PASSWORD"); + connectToWiFi("AP8", "_______"); + + timer2.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + } +} + + + + + diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS.h b/libraries/ESP8266mDNS/src/ESP8266mDNS.h index 585ddfbbec..fdcf489fb0 100644 --- a/libraries/ESP8266mDNS/src/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/src/ESP8266mDNS.h @@ -44,15 +44,16 @@ #include "ESP8266mDNS_Legacy.h" #include "LEAmDNS.h" -#include "LEAmDNS2.h" +#include "LEAmDNS2Host.h" #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) // Maps the implementation to use to the global namespace type //using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; //legacy -using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new +//using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new //using MDNSResponder = esp8266::experimental::MDNSResponder; //new^2 not compatible +using clsMDNSHost = esp8266::experimental::clsLEAMDNSHost; -extern MDNSResponder MDNS; +//extern MDNSResponder MDNS; #endif diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2.h b/libraries/ESP8266mDNS/src/LEAmDNS2.h deleted file mode 100755 index 7aa3bb0160..0000000000 --- a/libraries/ESP8266mDNS/src/LEAmDNS2.h +++ /dev/null @@ -1,1303 +0,0 @@ -/* - LEAmDNS2.h - (c) 2018, LaborEtArs - - Version 0.9 beta - - Some notes (from LaborEtArs, 2018): - Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS). - The target of this rewrite was to keep the existing interface as stable as possible while - adding and extending the supported set of mDNS features. - A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code. - - Supported mDNS features (in some cases somewhat limited): - - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service - - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented - - Probing host and service domains for uniqueness in the local network - - Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak) - - Announcing available services after successful probing - - Using fixed service TXT items or - - Using dynamic service TXT items for presented services (via callback) - - Remove services (and un-announcing them to the observers by sending goodbye-messages) - - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) - - Dynamic queries for DNS-SD services with cached and updated answers and user notifications - - - Usage: - In most cases, this implementation should work as a 'drop-in' replacement for the original - ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some - of the new features should be used. - - For presenting services: - In 'setup()': - Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);' - Register DNS-SD services with 'MDNSResponder::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);' - (Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);') - Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback - using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific - 'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);' - Call MDNS.begin("MyHostName"); - - In 'probeResultCallback(MDNSResponder* p_MDNSResponder, const char* p_pcDomain, MDNSResponder:hMDNSService p_hMDNSService, bool p_bProbeResult, void* p_pUserdata)': - Check the probe result and update the host or service domain name if the probe failed - - In 'dynamicServiceTxtCallback(MDNSResponder* p_MDNSResponder, const hMDNSService p_hMDNSService, void* p_pUserdata)': - Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hMDNSService, "c#", "1");' - - In loop(): - Call 'MDNS.update();' - - - For querying services/hosts: - Static: - Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");' or 'MDNS.queryHost("esp8266")'; - Iterate answers by: 'for (uint32_t u=0; u // for UdpContext.h -#include -#include -#include - -#include "lwip/netif.h" -#include "WiFiUdp.h" -#include "lwip/udp.h" -#include "debug.h" -#include "include/UdpContext.h" -#include - -#include "ESP8266WiFi.h" - - -namespace esp8266 -{ - -/** - LEAmDNS -*/ -namespace experimental -{ - -//this should be user-defined at build time -#ifndef ARDUINO_BOARD -#define ARDUINO_BOARD "generic" -#endif - -#define MDNS_IPV4_SUPPORT -#if LWIP_IPV6 -#define MDNS_IPV6_SUPPORT // If we've got IPv6 support, then we need IPv6 support :-) -#endif - - -#ifdef MDNS_IPV4_SUPPORT -#define MDNS_IPV4_SIZE 4 -#endif -#ifdef MDNS_IPV6_SUPPORT -#define MDNS_IPV6_SIZE 16 -#endif -/* - Maximum length for all service txts for one service -*/ -#define MDNS_SERVICE_TXT_MAXLENGTH 1300 -/* - Maximum length for a full domain name eg. MyESP._http._tcp.local -*/ -#define MDNS_DOMAIN_MAXLENGTH 256 -/* - Maximum length of on label in a domain name (length info fits into 6 bits) -*/ -#define MDNS_DOMAIN_LABEL_MAXLENGTH 63 -/* - Maximum length of a service name eg. http -*/ -#define MDNS_SERVICE_NAME_LENGTH 15 -/* - Maximum length of a service protocol name eg. tcp -*/ -#define MDNS_SERVICE_PROTOCOL_LENGTH 3 -/* - Default timeout for static service queries -*/ -#define MDNS_QUERYSERVICES_WAIT_TIME 5000 - -/* - DNS_RRTYPE_NSEC -*/ -#ifndef DNS_RRTYPE_NSEC -#define DNS_RRTYPE_NSEC 0x2F -#endif - - -/** - MDNSResponder -*/ -class MDNSResponder -{ -protected: -#include "LEAmDNS2_Host.hpp" - -public: - // MISC HELPERS - // Domain name helper - static bool indexDomain(char*& p_rpcDomain, - const char* p_pcDivider = "-", - const char* p_pcDefaultDomain = 0); - // Host name helper - static bool setNetIfHostName(netif* p_pNetIf, - const char* p_pcHostName); - - // INTERFACE - MDNSResponder(void); - virtual ~MDNSResponder(void); - - // HANDLEs for opaque access to responder objects - /** - hMDNSHost - */ - using hMDNSHost = const void*; - /** - hMDNSService - */ - using hMDNSService = const void*; - /** - hMDNSTxt - */ - using hMDNSTxt = const void*; - /** - hMDNSQuery - */ - using hMDNSQuery = const void*; - - // CALLBACKS - /** - MDNSHostProbeResultCallbackFn - Callback function for host domain probe results - */ - using MDNSHostProbeResultCallbackFn = std::function; - - // Create a MDNS netif responder netif by setting the default hostname - // Later call 'update()' in every 'loop' to run the process loop - // (probing, announcing, responding, ...) - // If no callback is given, the (maybe) already installed callback stays set - hMDNSHost begin(const char* p_pcHostName, - netif* p_pNetIf, - MDNSHostProbeResultCallbackFn p_fnCallback = 0); - bool begin(const char* p_pcHostName, - WiFiMode_t p_WiFiMode, - MDNSHostProbeResultCallbackFn p_fnCallback = 0); - bool begin(const char* p_pcHostName, - MDNSHostProbeResultCallbackFn p_fnCallback = 0); - - // Finish MDNS processing - bool close(const hMDNSHost p_hMDNSHost); - bool close(void); - - hMDNSHost getMDNSHost(netif* p_pNetIf) const; - hMDNSHost getMDNSHost(WiFiMode_t p_WiFiMode) const; - - // Change hostname (probing is restarted) - // If no callback is given, the (maybe) already installed callback stays set - bool setHostName(const hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - MDNSHostProbeResultCallbackFn p_fnCallback = 0); - - const char* hostName(const hMDNSHost p_hMDNSHost) const; - - // Set a callback function for host probe results - // The callback function is called, when the probeing for the host domain - // succeededs or fails. - // In case of failure, the failed domain name should be changed. - bool setHostProbeResultCallback(const hMDNSHost p_hMDNSHost, - MDNSHostProbeResultCallbackFn p_fnCallback); - - // Returns 'true' is host domain probing is done - bool status(const hMDNSHost p_hMDNSHost) const; - - // Add a 'global' default' instance name for new services - bool setInstanceName(const hMDNSHost p_hMDNSHost, - const char* p_pcInstanceName); - const char* instanceName(const hMDNSHost p_hMDNSHost) const; - - /** - MDNSServiceProbeResultCallbackFn - Callback function for service domain probe results - */ - using MDNSServiceProbeResultCallbackFn = std::function; - // Add a new service to the MDNS responder. If no name (instance name) is given (p_pcName = 0) - // the current hostname is used. If the hostname is changed later, the instance names for - // these 'auto-named' services are changed to the new name also (and probing is restarted). - // The usual '_' before p_pcService (eg. http) and protocol (eg. tcp) may be given.# - // If no callback is given, the (maybe) already installed callback stays set - hMDNSService addService(const hMDNSHost p_hMDNSHost, - const char* p_pcName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port, - MDNSServiceProbeResultCallbackFn p_fnCallback = 0); - // Removes a service from the MDNS responder - bool removeService(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService); - bool removeService(const hMDNSHost p_hMDNSHost, - const char* p_pcInstanceName, - const char* p_pcServiceType, - const char* p_pcProtocol); - hMDNSService findService(const hMDNSHost p_hMDNSHost, - const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol); - - // Change the services instance name (and restart probing). - // If no callback is given, the (maybe) already installed callback stays set - bool setServiceName(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcInstanceName, - MDNSServiceProbeResultCallbackFn p_fnCallback = 0); - const char* serviceName(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - const char* serviceType(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - const char* serviceProtocol(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - uint16_t servicePort(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - - // Set a service specific probe result callcack - bool setServiceProbeResultCallback(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - MDNSServiceProbeResultCallbackFn p_fnCallback); - - bool serviceStatus(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - - // Add a (static) MDNS TXT item ('key' = 'value') to the service - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value); - - // Remove an existing (static) MDNS TXT item from the service - bool removeServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const hMDNSTxt p_hTxt); - bool removeServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey); - - /** - MDNSDynamicServiceTxtCallbackFn - Callback function for dynamic MDNS TXT items - */ - using MDNSDynamicServiceTxtCallbackFn = std::function; - bool setDynamicServiceTxtCallback(const hMDNSHost p_hMDNSHost, - MDNSDynamicServiceTxtCallbackFn p_fnCallback); - bool setDynamicServiceTxtCallback(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - MDNSDynamicServiceTxtCallbackFn p_fnCallback); - - // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service - // Dynamic TXT items are removed right after one-time use. So they need to be added - // every time the value s needed (via callback). - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value); - - // QUERIES & ANSWERS - /** - clsMDNSAnswerAccessor & clsAnswerAccessorVector - */ - struct clsMDNSAnswerAccessor - { - protected: - /** - stcCompareTxtKey - */ - struct stcCompareTxtKey - { - bool operator()(char const* p_pA, char const* p_pB) const; - }; - public: - clsMDNSAnswerAccessor(const clsHost::stcQuery::stcAnswer* p_pAnswer); - ~clsMDNSAnswerAccessor(void); - - /** - clsTxtKeyValueMap - */ - using clsTxtKeyValueMap = std::map; - - bool serviceDomainAvailable(void) const; - const char* serviceDomain(void) const; - bool hostDomainAvailable(void) const; - const char* hostDomain(void) const; - bool hostPortAvailable(void) const; - uint16_t hostPort(void) const; -#ifdef MDNS_IPV4_SUPPORT - bool IPv4AddressAvailable(void) const; - std::vector IPv4Addresses(void) const; -#endif -#ifdef MDNS_IPV6_SUPPORT - bool IPv6AddressAvailable(void) const; - std::vector IPv6Addresses(void) const; -#endif - bool txtsAvailable(void) const; - const char* txts(void) const; - const clsTxtKeyValueMap& txtKeyValues(void) const; - const char* txtValue(const char* p_pcKey) const; - - size_t printTo(Print& p_Print) const; - - protected: - const clsHost::stcQuery::stcAnswer* m_pAnswer; - clsTxtKeyValueMap m_TxtKeyValueMap; - }; - using clsMDNSAnswerAccessorVector = std::vector; - using typeQueryAnswerType = clsHost::typeQueryAnswerType; - using enuQueryAnswerType = clsHost::enuQueryAnswerType; - - // STATIC QUERY - // Perform a (static) service/host query. The function returns after p_u16Timeout milliseconds - // The answers (the number of received answers is returned) can be retrieved by calling - // - answerHostName (or hostname) - // - answerIP (or IP) - // - answerPort (or port) - uint32_t queryService(const hMDNSHost p_hMDNSHost, - const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - uint32_t queryHost(const hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - bool removeQuery(const hMDNSHost p_hMDNSHost); - bool hasQuery(const hMDNSHost p_hMDNSHost); - hMDNSQuery getQuery(const hMDNSHost p_hMDNSHost); - - clsMDNSAnswerAccessorVector answerAccessors(const hMDNSHost p_hMDNSHost); - uint32_t answerCount(const hMDNSHost p_hMDNSHost); - clsMDNSAnswerAccessor answerAccessor(const hMDNSHost p_hMDNSHost, - uint32_t p_u32AnswerIndex); - - // DYNAMIC QUERIES - /** - MDNSQueryCallbackFn - - Callback function for received answers for dynamic queries - */ - using MDNSQueryCallbackFn = std::function; // true: Answer component set, false: component deleted - - // Install a dynamic service/host query. For every received answer (part) the given callback - // function is called. The query will be updated every time, the TTL for an answer - // has timed-out. - // The answers can also be retrieved by calling - // - answerCount service/host (for host queries, this should never be >1) - // - answerServiceDomain service - // - hasAnswerHostDomain/answerHostDomain service/host - // - hasAnswerIPv4Address/answerIPv4Address service/host - // - hasAnswerIPv6Address/answerIPv6Address service/host - // - hasAnswerPort/answerPort service - // - hasAnswerTxts/answerTxts service - hMDNSQuery installServiceQuery(const hMDNSHost p_hMDNSHost, - const char* p_pcServiceType, - const char* p_pcProtocol, - MDNSQueryCallbackFn p_fnCallback); - hMDNSQuery installHostQuery(const hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - MDNSQueryCallbackFn p_fnCallback); - // Remove a dynamic service query - bool removeQuery(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hMDNSQuery); - - - uint32_t answerCount(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hMDNSQuery); - clsMDNSAnswerAccessorVector answerAccessors(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hMDNSQuery); - clsMDNSAnswerAccessor answerAccessor(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hMDNSQuery, - uint32 p_u32AnswerIndex); - - /* bool hasAnswerServiceDomain(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - const char* answerServiceDomain(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerHostDomain(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - const char* answerHostDomain(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - #ifdef MDNS_IPV4_SUPPORT - bool hasAnswerIPv4Address(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIPv4AddressCount(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIPv4Address(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); - #endif - #ifdef MDNS_IPV6_SUPPORT - bool hasAnswerIPv6Address(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIPv6AddressCount(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIPv6Address(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); - #endif - bool hasAnswerPort(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - uint16_t answerPort(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerTxts(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - // Get the TXT items as a ';'-separated string - const char* answerTxts(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex);*/ - - // GENERAL MANAGEMENT - // Application should call this whenever AP is configured/disabled - bool notifyNetIfChange(netif* p_pNetIf); - - // 'update' should be called in every 'loop' to run the MDNS processing - bool update(const hMDNSHost p_hMDNSHost); - bool update(void); // Convenience - - // 'announce' can be called every time, the configuration of some service - // changes. Mainly, this would be changed content of TXT items. - bool announce(const hMDNSHost p_hMDNSHost); - bool announce(void); // Convenience - - // MISC - // Enable OTA update - hMDNSService enableArduino(const hMDNSHost p_hMDNSHost, - uint16_t p_u16Port, - bool p_bAuthUpload = false); - -protected: - /** Internal CLASSES & STRUCTS **/ - - // InstanceData - UdpContext* m_pUDPContext; - clsHostList m_HostList; - - // UDP CONTEXT - bool _allocUDPContext(void); - bool _releaseUDPContext(void); - bool _processUDPInput(void); - - // NETIF - clsHost* _createHost(netif* p_pNetIf); - bool _releaseHost(clsHost* p_pHost); - - const clsHost* _findHost(netif* p_pNetIf) const; - clsHost* _findHost(netif* p_pNetIf); - const clsHost* _findHost(const hMDNSHost p_hMDNSHost) const; - clsHost* _findHost(const hMDNSHost p_hMDNSHost); - - - // HANDLE HELPERS - bool _validateMDNSHostHandle(const hMDNSHost p_hMDNSHost) const; - bool _validateMDNSHostHandle(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - - clsHost* _NRH2Ptr(const hMDNSHost p_hMDNSHost); - const clsHost* _NRH2Ptr(const hMDNSHost p_hMDNSHost) const; - clsHost::stcService* _SH2Ptr(const hMDNSService p_hMDNSService); - const clsHost::stcService* _SH2Ptr(const hMDNSService p_hMDNSService) const; - - // INIT - clsHost* _begin(const char* p_pcHostName, - netif* p_pNetIf, - MDNSHostProbeResultCallbackFn p_fnCallback); - bool _close(clsHost& p_rHost); - - -#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER - - const char* _DH(hMDNSHost p_hMDNSResponder = 0) const; - -#endif // not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER - -}; - -#ifdef __MDNS_USE_LEGACY -/** - MDNSResponder_Legacy -*/ -class MDNSResponder_Legacy //: public MDNSResponder -{ -public: - /* INTERFACE */ - MDNSResponder_Legacy(void); - virtual ~MDNSResponder_Legacy(void); - - /** - hMDNSHost (opaque handle to access a netif binding) - */ - using hMDNSHost = const void*; - /** - hMDNSService (opaque handle to access the service) - */ - using hMDNSService = const void*; - /** - MDNSHostProbeResultCallbackFn - Callback function for host domain probe results - */ - using MDNSHostProbeResultCallbackFn = std::function; - /* LEGACY 2 */ - using MDNSServiceProbeResultCallbackFn1 = std::function; - using MDNSServiceProbeResultCallbackFn2 = std::function; - /** - hMDNSTxt (opaque handle to access the TXT items) - */ - using hMDNSTxt = const void*; - /** - MDNSDynamicServiceTxtCallbackFn - Callback function for dynamic MDNS TXT items - */ - using MDNSDynamicServiceTxtCallbackFn = std::function; - // LEGACY - using MDNSDynamicServiceTxtCallbackFn1 = std::function; - using MDNSDynamicServiceTxtCallbackFn2 = std::function; - - - hMDNSHost getNetIfBinding(netif* p_pNetIf) const; - hMDNSHost getNetIfBinding(WiFiMode_t p_WiFiMode) const; - - // Create a MDNS responder netif binding by setting the default hostname - // Later call 'update()' in every 'loop' to run the process loop - // (probing, announcing, responding, ...) - - hMDNSHost begin(const char* p_pcHostName, - netif* p_pNetIf, - MDNSHostProbeResultCallbackFn p_fnCallback = 0); - bool begin(const char* p_pcHostName, - WiFiMode_t p_WiFiMode, - MDNSHostProbeResultCallbackFn p_fnCallback = 0); - bool begin(const char* p_pcHostName, - MDNSHostProbeResultCallbackFn p_fnCallback = 0); - - /* bool begin(const String& p_strHostName) {return begin(p_strHostName.c_str());} - // for compatibility - bool begin(const char* p_pcHostName, - IPAddress p_IPAddress, // ignored - uint32_t p_u32TTL = 120); // ignored - bool begin(const String& p_strHostName, - IPAddress p_IPAddress, // ignored - uint32_t p_u32TTL = 120) { // ignored - return begin(p_strHostName.c_str(), p_IPAddress, p_u32TTL); - }*/ - // Finish MDNS processing - bool close(const hMDNSHost p_hMDNSHost); - bool close(void); - // for ESP32 compatibility - bool end(void); - - // Change hostname (probing is restarted) - bool setHostName(const hMDNSHost p_hMDNSHost, - const char* p_pcHostName); - // for compatibility... - bool setHostname(const char* p_pcHostName); - bool setHostname(String p_strHostName); - - const char* hostName(const hMDNSHost p_hMDNSHost) const; - const char* hostname(void) const; - - // Returns 'true' is host domain probing is done - bool status(const hMDNSHost p_hMDNSHost) const; - bool status(void) const; - - bool setInstanceName(const hMDNSHost p_hMDNSHost, - const char* p_pcInstanceName); - bool setInstanceName(const char* p_pcInstanceName); - // for ESP32 compatibility - bool setInstanceName(const String& p_strHostName); - - // Add a new service to the MDNS responder. If no name (instance name) is given (p_pcName = 0) - // the current hostname is used. If the hostname is changed later, the instance names for - // these 'auto-named' services are changed to the new name also (and probing is restarted). - // The usual '_' before p_pcService (eg. http) and protocol (eg. tcp) may be given. - hMDNSService addService(const hMDNSHost p_hMDNSHost, - const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port); - hMDNSService addService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port); - // Removes a service from the MDNS responder - bool removeService(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService); - bool removeService(const hMDNSHost p_hMDNSHost, - const char* p_pcInstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol); - bool removeService(const hMDNSService p_hMDNSService); - bool removeService(const char* p_pcInstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol); - // for compatibility... - bool addService(String p_strServiceName, - String p_strProtocol, - uint16_t p_u16Port); - hMDNSService findService(const hMDNSHost p_hMDNSHost, - const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol); - hMDNSService findService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol); - - // Change the services instance name (and restart probing). - bool setServiceName(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcInstanceName); - bool setServiceName(const hMDNSService p_hMDNSService, - const char* p_pcInstanceName); - - const char* serviceName(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - const char* service(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - const char* serviceProtocol(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - /* LEGACY */ - const char* serviceName(const hMDNSService p_hMDNSService) const; - const char* service(const hMDNSService p_hMDNSService) const; - const char* serviceProtocol(const hMDNSService p_hMDNSService) const; - - bool serviceStatus(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const; - bool serviceStatus(const hMDNSService p_hMDNSService) const; - - // Add a (static) MDNS TXT item ('key' = 'value') to the service - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value); - // LEGACY - hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value); - - // Remove an existing (static) MDNS TXT item from the service - bool removeServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const hMDNSTxt p_hTxt); - bool removeServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey); - bool removeServiceTxt(const hMDNSHost p_hMDNSHost, - const char* p_pcinstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol, - const char* p_pcKey); - bool removeServiceTxt(const hMDNSService p_hMDNSService, - const hMDNSTxt p_hTxt); - bool removeServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey); - bool removeServiceTxt(const char* p_pcinstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol, - const char* p_pcKey); - // for compatibility... - bool addServiceTxt(const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey, - const char* p_pcValue); - bool addServiceTxt(String p_strService, - String p_strProtocol, - String p_strKey, - String p_strValue); - - bool setDynamicServiceTxtCallback(const hMDNSHost p_hMDNSHost, - MDNSDynamicServiceTxtCallbackFn p_fnCallback); - bool setDynamicServiceTxtCallback(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - MDNSDynamicServiceTxtCallbackFn p_fnCallback); - - // Set a global callback for dynamic MDNS TXT items. The callback function is called - // every time, a TXT item is needed for one of the installed services. - bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn1 p_fnCallback); - bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn2 p_fnCallback); - - // Set a service specific callback for dynamic MDNS TXT items. The callback function - // is called every time, a TXT item is needed for the given service. - bool setDynamicServiceTxtCallback(const hMDNSService p_hMDNSService, - MDNSDynamicServiceTxtCallbackFn1 p_fnCallback); - bool setDynamicServiceTxtCallback(const hMDNSService p_hMDNSService, - MDNSDynamicServiceTxtCallbackFn2 p_fnCallback); - - // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service - // Dynamic TXT items are removed right after one-time use. So they need to be added - // every time the value s needed (via callback). - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value); - /* LEGACY */ - hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addDynamicServiceTxt(const hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value); - - /** - hMDNSQuery (opaque handle to access dynamic service queries) - */ - using hMDNSQuery = const void*; - //using hMDNSServiceQuery = hMDNSQuery; // for compatibility with V1 - - // Perform a (static) service/host query. The function returns after p_u16Timeout milliseconds - // The answers (the number of received answers is returned) can be retrieved by calling - // - answerHostName (or hostname) - // - answerIP (or IP) - // - answerPort (or port) - uint32_t queryService(const hMDNSHost p_hMDNSHost, - const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - uint32_t queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - // for compatibility... - uint32_t queryService(const String& p_strService, - const String& p_strProtocol); - uint32_t queryHost(const hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - uint32_t queryHost(const char* p_pcHostName, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - bool removeQuery(const hMDNSHost p_hMDNSHost); - bool removeQuery(void); - bool hasQuery(const hMDNSHost p_hMDNSHost); - bool hasQuery(void); - hMDNSQuery getQuery(const hMDNSHost p_hMDNSHost); - hMDNSQuery getQuery(void); - - const char* answerHostName(const hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex); - const char* answerHostName(const uint32_t p_u32AnswerIndex); - // for compatibility... - String hostname(const uint32_t p_u32AnswerIndex); -#ifdef MDNS_IPV4_SUPPORT - IPAddress answerIPv4(const hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex); - IPAddress answerIPv4(const uint32_t p_u32AnswerIndex); - // for compatibility - IPAddress answerIP(const uint32_t p_u32AnswerIndex); - IPAddress IP(const uint32_t p_u32AnswerIndex); -#endif -#ifdef MDNS_IPV6_SUPPORT - IPAddress answerIPv6(const hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex); - IPAddress answerIPv6(const uint32_t p_u32AnswerIndex); -#endif - uint16_t answerPort(const hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex); - uint16_t answerPort(const uint32_t p_u32AnswerIndex); - // for compatibility - uint16_t port(const uint32_t p_u32AnswerIndex); - - /** - typeQueryAnswerType & enuQueryAnswerType - */ - using typeQueryAnswerType = uint8_t; - enum class enuQueryAnswerType : typeQueryAnswerType - { - Unknown = 0x00, - ServiceDomain = 0x01, // Service domain - HostDomain = 0x02, // Host domain - Port = 0x04, // Port - Txts = 0x08, // TXT items -#ifdef MDNS_IPV4_SUPPORT - IPv4Address = 0x10, // IPv4 address -#endif -#ifdef MDNS_IPV6_SUPPORT - IPv6Address = 0x20, // IPv6 address -#endif - }; - //using AnswerType = enuQueryAnswerType; // for compatibility with V1 - - /** - stcAnswerAccessor - */ - struct stcAnswerAccessor - { - protected: - /** - stcCompareTxtKey - */ - struct stcCompareTxtKey - { - bool operator()(char const* p_pA, char const* p_pB) const; - }; - public: - stcAnswerAccessor(MDNSResponder& p_rMDNSResponder, - hMDNSQuery p_hQuery, - uint32_t p_u32AnswerIndex); - /** - clsTxtKeyValueMap - */ - using clsTxtKeyValueMap = std::map; - - bool serviceDomainAvailable(void) const; - const char* serviceDomain(void) const; - bool hostDomainAvailable(void) const; - const char* hostDomain(void) const; - bool hostPortAvailable(void) const; - uint16_t hostPort(void) const; -#ifdef MDNS_IPV4_SUPPORT - bool IPv4AddressAvailable(void) const; - std::vector IPv4Addresses(void) const; -#endif -#ifdef MDNS_IPV6_SUPPORT - bool IPv6AddressAvailable(void) const; - std::vector IPv6Addresses(void) const; -#endif - bool txtsAvailable(void) const; - const char* txts(void) const; - const clsTxtKeyValueMap& txtKeyValues(void) const; - const char* txtValue(const char* p_pcKey) const; - - size_t printTo(Print& p_Print) const; - - protected: - MDNSResponder& m_rMDNSResponder; - hMDNSQuery m_hQuery; - uint32_t m_u32AnswerIndex; - clsTxtKeyValueMap m_TxtKeyValueMap; - }; - - /** - MDNSQueryCallbackFn - - Callback function for received answers for dynamic queries - */ - using MDNSQueryCallbackFn = std::function; // true: Answer component set, false: component deleted - // LEGACY - using MDNSQueryCallbackFn1 = std::function; // true: Answer component set, false: component deleted - using MDNSQueryCallbackFn2 = std::function; // true: Answer component set, false: component deleted - //using MDNSServiceInfo = stcAnswerAccessor; // for compatibility with V1 - - // Install a dynamic service/host query. For every received answer (part) the given callback - // function is called. The query will be updated every time, the TTL for an answer - // has timed-out. - // The answers can also be retrieved by calling - // - answerCount service/host (for host queries, this should never be >1) - // - answerServiceDomain service - // - hasAnswerHostDomain/answerHostDomain service/host - // - hasAnswerIPv4Address/answerIPv4Address service/host - // - hasAnswerIPv6Address/answerIPv6Address service/host - // - hasAnswerPort/answerPort service - // - hasAnswerTxts/answerTxts service - hMDNSQuery installServiceQuery(const hMDNSHost p_hMDNSHost, - const char* p_pcService, - const char* p_pcProtocol, - MDNSQueryCallbackFn p_fnCallback); - hMDNSQuery installHostQuery(const hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - MDNSQueryCallbackFn p_fnCallback); - - hMDNSQuery installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSQueryCallbackFn1 p_fnCallback); - hMDNSQuery installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSQueryCallbackFn2 p_fnCallback); - - hMDNSQuery installHostQuery(const char* p_pcHostName, - MDNSQueryCallbackFn1 p_fnCallback); - hMDNSQuery installHostQuery(const char* p_pcHostName, - MDNSQueryCallbackFn2 p_fnCallback); - // Remove a dynamic service query - bool removeDynamicQuery(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hMDNSQuery); - bool removeDynamicQuery(const hMDNSQuery p_hQuery); - - /** - clsMDNSAnswerAccessorVector - */ - using clsMDNSAnswerAccessorVector = std::vector; - - clsMDNSAnswerAccessorVector answerAccessors(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hMDNSQuery); - clsMDNSAnswerAccessorVector answerAccessors(const hMDNSQuery p_hQuery); - - uint32_t answerCount(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hMDNSQuery); - uint32_t answerCount(const hMDNSQuery p_hQuery); - - bool hasAnswerServiceDomain(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerServiceDomain(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - const char* answerServiceDomain(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - const char* answerServiceDomain(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerHostDomain(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerHostDomain(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - const char* answerHostDomain(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - const char* answerHostDomain(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); -#ifdef MDNS_IPV4_SUPPORT - bool hasAnswerIPv4Address(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIPv4AddressCount(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIPv4Address(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); - bool hasAnswerIPv4Address(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIPv4AddressCount(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIPv4Address(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); -#endif -#ifdef MDNS_IPV6_SUPPORT - bool hasAnswerIPv6Address(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIPv6AddressCount(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIPv6Address(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); - bool hasAnswerIPv6Address(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIPv6AddressCount(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIPv6Address(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); -#endif - bool hasAnswerPort(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerPort(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - uint16_t answerPort(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - /* uint16_t answerPort(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex);*/ - bool hasAnswerTxts(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerTxts(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - // Get the TXT items as a ';'-separated string - const char* answerTxts(const hMDNSHost p_hMDNSHost, - const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - const char* answerTxts(const hMDNSQuery p_hQuery, - const uint32_t p_u32AnswerIndex); - - // Set a callback function for host probe results - // The callback function is called, when the probeing for the host domain - // succeededs or fails. - // In case of failure, the failed domain name should be changed. - bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn p_fnCallback); - /* LEGACY 2 */ - using MDNSHostProbeResultCallbackFn1 = std::function; - using MDNSHostProbeResultCallbackFn2 = std::function; - - bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn1 p_fnCallback); - bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn2 p_fnCallback); - - /** - MDNSServiceProbeResultCallbackFn - Callback function for service domain probe results - */ - using MDNSServiceProbeResultCallbackFn = std::function; - // Set a service specific probe result callcack - bool setServiceProbeResultCallback(const hMDNSService p_hMDNSService, - MDNSServiceProbeResultCallbackFn p_fnCallback); - - bool setServiceProbeResultCallback(const hMDNSService p_hMDNSService, - MDNSServiceProbeResultCallbackFn1 p_fnCallback); - bool setServiceProbeResultCallback(const hMDNSService p_hMDNSService, - MDNSServiceProbeResultCallbackFn2 p_fnCallback); - - // Application should call this whenever AP is configured/disabled - bool notifyNetIfChange(netif* p_pNetIf); - - // 'update' should be called in every 'loop' to run the MDNS processing - bool update(const hMDNSHost p_hMDNSHost); - bool update(void); - - // 'announce' can be called every time, the configuration of some service - // changes. Mainly, this would be changed content of TXT items. - bool announce(const hMDNSHost p_hMDNSHost); - bool announce(void); - - // Enable OTA update - hMDNSService enableArduino(const hMDNSHost p_hMDNSHost, - uint16_t p_u16Port, - bool p_bAuthUpload = false); - hMDNSService enableArduino(uint16_t p_u16Port, - bool p_bAuthUpload = false); - - // Domain name helper - static bool indexDomain(char*& p_rpcDomain, - const char* p_pcDivider = "-", - const char* p_pcDefaultDomain = 0); - // Host name helper - static bool setNetIfHostName(netif* p_pNetIf, - const char* p_pcHostName); -}; -#endif - -} // namespace MDNSImplementation - -} // namespace esp8266 - -#endif // LEAMDNS2_H - - - diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp new file mode 100644 index 0000000000..dd46d09ad3 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp @@ -0,0 +1,1428 @@ +/* + LEAmDNS2Host.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "LEAmDNS2Host.h" + +#ifdef MDNS_IPV4_SUPPORT +#include +#endif +#ifdef MDNS_IPV6_SUPPORT +#include +#endif + + +namespace // anonymous +{ + +/* + strrstr (static) + + Backwards search for p_pcPattern in p_pcString + Based on: https://stackoverflow.com/a/1634398/2778898 + +*/ +const char* strrstr(const char*__restrict p_pcString, + const char*__restrict p_pcPattern) +{ + const char* pcResult = 0; + + size_t stStringLength = (p_pcString ? strlen(p_pcString) : 0); + size_t stPatternLength = (p_pcPattern ? strlen(p_pcPattern) : 0); + + if ((stStringLength) && + (stPatternLength) && + (stPatternLength <= stStringLength)) + { + // Pattern is shorter or has the same length than the string + for (const char* s = (p_pcString + stStringLength - stPatternLength); s >= p_pcString; --s) + { + if (0 == strncmp(s, p_pcPattern, stPatternLength)) + { + pcResult = s; + break; + } + } + } + return pcResult; +} + + +} // anonymous + + +namespace esp8266 +{ + + +namespace experimental +{ + + +/* + + HELPERS + +*/ + +/* + clsLEAmDNS2_Host::indexDomainName (static) + + Increments the given domain 'p_pcDomainName' by appending a delimiter and an index number. + + If the given domain name already has a numeric index (after the given delimiter), this index + is incremented. If not, the delimiter and index '2' is added. + + If 'p_pcDomainName' is empty (==0), the given default name 'p_pcDefaultDomainName' is used, + if no default is given, 'ESP8266' is used. + +*/ +//static +const char* clsLEAMDNSHost::indexDomainName(const char* p_pcDomainName, + const char* p_pcDivider /*= "-"*/, + const char* p_pcDefaultDomainName /*= 0*/) +{ + static char acResultDomainName[clsConsts::stDomainLabelMaxLength]; + *acResultDomainName = 0; + + // Ensure a divider exists; use '-' as default + const char* pcDivider = (p_pcDivider ? : "-"); + + if (p_pcDomainName) + { + // Given domain + const char* pFoundDivider = strrstr(p_pcDomainName, pcDivider); + if (pFoundDivider) // maybe already extended + { + char* pEnd = 0; + unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10); + if ((ulIndex) && + ((pEnd - p_pcDomainName) == (ptrdiff_t)strlen(p_pcDomainName)) && + (!*pEnd)) + { + // Valid (old) index found + char acIndexBuffer[16]; + sprintf(acIndexBuffer, "%lu", (++ulIndex)); + //size_t stLength = ((pFoundDivider - p_pcDomainName + strlen(pcDivider)) + strlen(acIndexBuffer) + 1); + + memcpy(acResultDomainName, p_pcDomainName, (pFoundDivider - p_pcDomainName + strlen(pcDivider))); + acResultDomainName[pFoundDivider - p_pcDomainName + strlen(pcDivider)] = 0; + strcat(acResultDomainName, acIndexBuffer); + } + else + { + pFoundDivider = 0; // Flag the need to (base) extend the hostname + } + } + + if (!pFoundDivider) + { + // not yet extended (or failed to increment extension) -> start indexing + //size_t stLength = strlen(p_pcDomainName) + (strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0' + sprintf(acResultDomainName, "%s%s2", p_pcDomainName, pcDivider); + } + } + else + { + // No given domain, use base or default + const char* cpcDefaultName = (p_pcDefaultDomainName ? : "ESP8266"); + size_t stLength = strlen(cpcDefaultName) + 1; // '\0' + strncpy(acResultDomainName, cpcDefaultName, stLength); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[mDNS] indexDomainName: From '%s' to '%s'\n"), (p_pcDomainName ? : ""), acResultDomainName);); + return acResultDomainName; +} + + +/* + clsLEAmDNS2_Host::setStationHostName (static) + + Sets the staion hostname + +*/ +// static +bool clsLEAMDNSHost::setNetIfHostName(netif* p_pNetIf, + const char* p_pcHostName) +{ + if ((p_pNetIf) && + (p_pcHostName)) + { + netif_set_hostname(p_pNetIf, (char*)p_pcHostName); // LWIP 1.x forces 'char*' instead of 'const char*' + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[mDNS] setNetIfHostName host name: %s!\n"), p_pcHostName);); + } + return true; +} + + +/** + clsLEAmDNS2_Host::sm_pBackbone + +*/ +clsLEAMDNSHost::clsBackbone* clsLEAMDNSHost::clsBackbone::sm_pBackbone = 0; + +/** + Consts::... + +*/ +const char* clsLEAMDNSHost::clsConsts::pcLocal = "local"; +const char* clsLEAMDNSHost::clsConsts::pcServices = "services"; +const char* clsLEAMDNSHost::clsConsts::pcDNSSD = "dns-sd"; +const char* clsLEAMDNSHost::clsConsts::pcUDP = "udp"; +//const char* clsLEAMDNSHost::clsConsts::pcTCP = "tcp"; + +#ifdef MDNS_IPV4_SUPPORT +const char* clsLEAMDNSHost::clsConsts::pcReverseIPv4Domain = "in-addr"; +#endif +#ifdef MDNS_IPV6_SUPPORT +const char* clsLEAMDNSHost::clsConsts::pcReverseIPv6Domain = "ip6"; +#endif +const char* clsLEAMDNSHost::clsConsts::pcReverseTopDomain = "arpa"; + + +/* + clsLEAmDNS2_Host::clsLEAmDNS2_Host constructor + +*/ +clsLEAMDNSHost::clsLEAMDNSHost(void) + : m_pNetIf(0), + m_NetIfState(static_cast(enuNetIfState::None)), + m_pUDPContext(0), + m_pcHostName(0), + m_pcDefaultInstanceName(0), + m_ProbeInformation() +{ +} + +/* + clsLEAmDNS2_Host::~clsLEAmDNS2_Host destructor + +*/ +clsLEAMDNSHost::~clsLEAMDNSHost(void) +{ + close(); +} + +/* + + INIT + +*/ + +/* + clsLEAmDNS2_Host::begin (hostname, netif, probe_callback) + + Creates a new mDNS host (adding the netif to the multicast groups), + sets up the instance data (hostname, ...) and starts the probing process + +*/ +bool clsLEAMDNSHost::begin(const char* p_pcHostName, + netif* p_pNetIf, + clsLEAMDNSHost::fnProbeResultCallback p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, netif: %u)\n"), _DH(), (p_pcHostName ? : "_"), (p_pNetIf ? netif_get_index(p_pNetIf) : 0));); + + bool bResult = false; + + if (!((bResult = ((setHostName(p_pcHostName)) && + ((m_pNetIf = p_pNetIf)) && + (_joinMulticastGroups()) && + (p_fnCallback ? setProbeResultCallback(p_fnCallback) : true) && + ((m_pUDPContext = _allocBackbone())) && + (restart()))))) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s begin: FAILED for '%s'!\n"), _DH(), (p_pcHostName ? : "-"));); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin: %s to init with hostname %s!\n"), _DH(), (bResult ? "Succeeded" : "FAILED"), (p_pcHostName ? : "-"));); + return bResult; +} + +/* + clsLEAmDNS2_Host::begin (hostname, probe_callback) + +*/ +bool clsLEAMDNSHost::begin(const char* p_pcHostName, + clsLEAMDNSHost::fnProbeResultCallback p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s)\n"), _DH(), (p_pcHostName ? : "_"));); + + return begin(p_pcHostName, (WiFiMode_t)wifi_get_opmode(), p_fnCallback); +} + +/* + clsLEAmDNS2_Host::begin (hostname, WiFiMode, probe_callback) + +*/ +bool clsLEAMDNSHost::begin(const char* p_pcHostName, + WiFiMode_t p_WiFiMode, + clsLEAMDNSHost::fnProbeResultCallback p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, opmode: %u)\n"), _DH(), (p_pcHostName ? : "_"), (uint32_t)p_WiFiMode);); + + bool bResult = false; + + if (p_WiFiMode == WIFI_STA) + { + bResult = begin(p_pcHostName, netif_get_by_index(WIFI_STA), p_fnCallback); + } + else if (p_WiFiMode == WIFI_AP) + { + bResult = begin(p_pcHostName, netif_get_by_index(WIFI_AP), p_fnCallback); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s begin: FAILED for WiFi mode '%u'! Only 'WIFI_STA' or 'WIFI_AP' is allowed (HostName: %s)!\n"), _DH(), (bResult ? "Succeeded" : "FAILED"), p_WiFiMode, (p_pcHostName ? : "-"));); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin: %s for WiFi mode '%u' (HostName: %s)!\n"), _DH(), (bResult ? "Succeeded" : "FAILED"), p_WiFiMode, (p_pcHostName ? : "-"));); + return bResult; +} + +/* + clsLEAmDNS2_Host::close + +*/ +bool clsLEAMDNSHost::close(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s close\n"), _DH());); + + m_pUDPContext = 0; + return ((_leaveMulticastGroups()) && + (_releaseBackbone())); +} + + +/* + + HOSTNAME + +*/ + +/* + clsLEAmDNS2_Host::setHostName + +*/ +bool clsLEAMDNSHost::setHostName(const char* p_pcHostName) +{ + bool bResult; + if ((bResult = _allocHostName(p_pcHostName))) + { + m_ProbeInformation.clear(false); + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::ReadyToStart; + + // Replace 'auto-set' service names + for (clsService* pService : m_Services) + { + if ((pService->m_bAutoName) && + (!m_pcDefaultInstanceName)) + { + if (!((bResult = pService->setInstanceName(p_pcHostName)))) + { + break; + } + } + } + } + return bResult; +} + +/* + clsLEAmDNS2_Host::indexHostName + +*/ +bool clsLEAMDNSHost::indexHostName(void) +{ + return setHostName(clsLEAMDNSHost::indexDomainName(hostName(), "-", 0)); +} + +/* + clsLEAmDNS2_Host::hostName + +*/ +const char* clsLEAMDNSHost::hostName(void) const +{ + return m_pcHostName; +} + +/* + clsLEAmDNS2_Host::setProbeResultCallback + +*/ +bool clsLEAMDNSHost::setProbeResultCallback(clsLEAMDNSHost::fnProbeResultCallback p_fnCallback) +{ + m_ProbeInformation.m_fnProbeResultCallback = p_fnCallback; + return true; +} + +/* + clsLEAmDNS2_Host::probeStatus + +*/ +bool clsLEAMDNSHost::probeStatus(void) const +{ + return (clsProbeInformation_Base::enuProbingStatus::DoneFinally == m_ProbeInformation.m_ProbingStatus); +} + + +/* + + SERVICES + +*/ + +/* + clsLEAmDNS2_Host::setDefaultInstanceName + +*/ +bool clsLEAMDNSHost::setDefaultInstanceName(const char* p_pcDefaultInstanceName) +{ + bool bResult; + if ((bResult = _allocDefaultInstanceName(p_pcDefaultInstanceName))) + { + // Replace 'auto-set' service names + for (clsService* pService : m_Services) + { + if (pService->m_bAutoName) + { + if (!((bResult = pService->setInstanceName(p_pcDefaultInstanceName)))) + { + break; + } + } + } + } + return bResult; +} + +/* + clsLEAmDNS2_Host::defaultInstanceName + +*/ +const char* clsLEAMDNSHost::defaultInstanceName(void) const +{ + return m_pcDefaultInstanceName; +} + +/* + clsLEAmDNS2_Host::addService + +*/ +clsLEAMDNSHost::clsService* clsLEAMDNSHost::addService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port, + clsLEAMDNSHost::clsService::fnProbeResultCallback p_fnCallback /*= 0*/) +{ + clsService* pService = 0; + + if (!((pService = findService(_instanceName(p_pcInstanceName), p_pcType, p_pcProtocol, p_u16Port)))) + { + // Not already used + if ((pService = new clsService)) + { + if ((pService->setInstanceName(_instanceName(p_pcInstanceName))) && + (pService->setType(p_pcType)) && + (pService->setProtocol(p_pcProtocol)) && + (pService->setPort(p_u16Port)) && + (p_fnCallback ? pService->setProbeResultCallback(p_fnCallback) : true)) + { + m_Services.push_back(pService); + } + else + { + delete pService; + pService = 0; + } + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s addService: %s to add service '%s.%s.%s.local'!\n"), _DH(pService), (pService ? "Succeeded" : "FAILED"), _instanceName(p_pcInstanceName, false), (p_pcType ? : ""), (p_pcProtocol ? : ""));); + DEBUG_EX_ERR(if (!pService) DEBUG_OUTPUT.printf_P(PSTR("%s addService: FAILED to add service '%s.%s.%s.local'!\n"), _DH(pService), _instanceName(p_pcInstanceName, false), (p_pcType ? : ""), (p_pcProtocol ? : ""));); + return pService; +} + +/* + clsLEAmDNS2_Host::removeService + +*/ +bool clsLEAMDNSHost::removeService(clsLEAMDNSHost::clsService* p_pService) +{ + bool bResult = false; + + if ((bResult = ((p_pService) && + (m_Services.end() != std::find(m_Services.begin(), m_Services.end(), p_pService)) && + (_announceService(*p_pService, false))))) + { + m_Services.remove(p_pService); + delete p_pService; + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _removeService: FAILED!\n"), _DH(p_pService));); + return bResult; +} + +/* + clsLEAmDNS2_Host::findService (const) + +*/ +const clsLEAMDNSHost::clsService* clsLEAMDNSHost::findService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port/*= (uint16_t)(-1)*/) const +{ + clsService* pFoundService = 0; + + for (clsService* pService : m_Services) + { + if ((0 == strcmp(pService->instanceName(), _instanceName(p_pcInstanceName))) && + (0 == strcmp(pService->type(), p_pcType)) && + (0 == strcmp(pService->protocol(), p_pcProtocol)) && + (((uint16_t)(-1) == p_u16Port) || + (pService->port() == p_u16Port))) + { + pFoundService = pService; + break; + } + } + return pFoundService; +} + +/* + clsLEAmDNS2_Host::findService + +*/ +clsLEAMDNSHost::clsService* clsLEAMDNSHost::findService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port /*= (uint16_t)(-1)*/) +{ + return (clsService*)((const clsLEAMDNSHost*)this)->findService(p_pcInstanceName, p_pcType, p_pcProtocol, p_u16Port); +} + +/* + clsLEAMDNSHost::services + +*/ +const clsLEAMDNSHost::clsService::list& clsLEAMDNSHost::services(void) const +{ + return m_Services; +} + + +/* + + QUERIES + +*/ + +/* + clsLEAmDNS2_Host::queryService + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector clsLEAMDNSHost::queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local'\n"), _DH(), p_pcService, p_pcProtocol);); + + clsQuery* pQuery = 0; + if ((p_pcService) && (*p_pcService) && + (p_pcProtocol) && (*p_pcProtocol) && + (p_u16Timeout) && + ((pQuery = _allocQuery(clsQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pQuery->m_Domain))) + { + if ((_removeLegacyQuery()) && + ((pQuery->m_bStaticQuery = true)) && + (_sendQuery(*pQuery))) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + pQuery->m_bAwaitingAnswers = false; + } + else + { + // FAILED to send query + _removeQuery(pQuery); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: INVALID input data!\n"), _DH());); + } + return ((pQuery) + ? pQuery->answerAccessors() + : clsQuery::clsAnswerAccessor::vector()); +} + +/* + clsLEAmDNS2_Host::queryHost + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector clsLEAMDNSHost::queryHost(const char* p_pcHostName, + const uint16_t p_u16Timeout) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local'\n"), _DH(), p_pcHostName);); + + clsQuery* pQuery = 0; + if ((p_pcHostName) && (*p_pcHostName) && + (p_u16Timeout) && + ((pQuery = _allocQuery(clsQuery::enuQueryType::Host))) && + (_buildDomainForHost(p_pcHostName, pQuery->m_Domain))) + { + if ((_removeLegacyQuery()) && + ((pQuery->m_bStaticQuery = true)) && + (_sendQuery(*pQuery))) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + pQuery->m_bAwaitingAnswers = false; + } + else + { + // FAILED to send query + _removeQuery(pQuery); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: INVALID input data!\n"), _DH());); + } + return ((pQuery) + ? pQuery->answerAccessors() + : clsQuery::clsAnswerAccessor::vector()); +} + +/* + clsLEAmDNS2_Host::removeQuery + +*/ +bool clsLEAMDNSHost::removeQuery(void) +{ + return _removeLegacyQuery(); +} + +/* + clsLEAmDNS2_Host::hasQuery + +*/ +bool clsLEAMDNSHost::hasQuery(void) +{ + return (0 != _findLegacyQuery()); +} + +/* + clsLEAmDNS2_Host::getQuery + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::getQuery(void) +{ + return _findLegacyQuery(); +} + +/* + clsLEAmDNS2_Host::installServiceQuery (answer) + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + clsLEAMDNSHost::clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer) +{ + clsQuery* pQuery = 0; + if ((pQuery = _installServiceQuery(p_pcService, p_pcProtocol))) + { + pQuery->m_fnCallbackAnswer = p_fnCallbackAnswer; + } + return pQuery; +} + +/* + clsLEAmDNS2_Host::installServiceQuery (accessor) + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + clsLEAMDNSHost::clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor) +{ + clsQuery* pQuery = 0; + if ((pQuery = _installServiceQuery(p_pcService, p_pcProtocol))) + { + pQuery->m_fnCallbackAccessor = p_fnCallbackAccessor; + } + return pQuery; +} + +/* + clsLEAmDNS2_Host::installHostQuery (answer) +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installHostQuery(const char* p_pcHostName, + clsLEAMDNSHost::clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer) +{ + clsQuery* pQuery = 0; + if ((p_pcHostName) && (*p_pcHostName)) + { + clsRRDomain domain; + if ((pQuery = ((_buildDomainForHost(p_pcHostName, domain)) + ? _installDomainQuery(domain, clsQuery::enuQueryType::Host) + : 0))) + { + pQuery->m_fnCallbackAnswer = p_fnCallbackAnswer; + } + } + return pQuery; +} + +/* + clsLEAmDNS2_Host::installHostQuery (accessor) +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installHostQuery(const char* p_pcHostName, + clsLEAMDNSHost::clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor) +{ + clsQuery* pQuery = 0; + if ((p_pcHostName) && (*p_pcHostName)) + { + clsRRDomain domain; + if ((pQuery = ((_buildDomainForHost(p_pcHostName, domain)) + ? _installDomainQuery(domain, clsQuery::enuQueryType::Host) + : 0))) + { + pQuery->m_fnCallbackAccessor = p_fnCallbackAccessor; + } + } + return pQuery; +} + +/* + clsLEAmDNS2_Host::removeQuery +*/ +bool clsLEAMDNSHost::removeQuery(clsLEAMDNSHost::clsQuery* p_pMDNSQuery) +{ + bool bResult = ((p_pMDNSQuery) && + (_removeQuery(p_pMDNSQuery))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeQuery: FAILED!\n"), _DH());); + return bResult; +} + + +/* + PROCESSING +*/ + +/* + clsLEAmDNS2_Host::update +*/ +bool clsLEAMDNSHost::update(void) +{ + bool bResult = false; + + //if (clsBackbone::sm_pBackbone->setDelayUDPProcessing(true)) + //{ + bResult = ((_checkNetIfState()) && // Any changes in the netif state? + (_updateProbeStatus()) && // Probing and announcing + (_checkQueryCache())); + + // clsBackbone::sm_pBackbone->setDelayUDPProcessing(false); + //} + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s update: FAILED (Not connected?)!\n"), _DH());); + + return bResult; +} + +/* + clsLEAmDNS2_Host::announce +*/ +bool clsLEAMDNSHost::announce(bool p_bAnnounce /*= true*/, + bool p_bIncludeServices /*= true*/) +{ + return _announce(p_bAnnounce, p_bIncludeServices); +} + +/* + clsLEAmDNS2_Host::announceService +*/ +bool clsLEAMDNSHost::announceService(clsService* p_pService, + bool p_bAnnounce /*= true*/) +{ + return _announceService(*p_pService, p_bAnnounce); +} + +/* + clsLEAmDNS2_Host::restart +*/ +bool clsLEAMDNSHost::restart(void) +{ + return (_resetProbeStatus(true)); // Stop and restart probing +} + + + +/* + P R O T E C T E D +*/ + +/* + + BACKBONE + +*/ + +/* + clsLEAmDNS2_Host::_allocBackbone + +*/ +UdpContext* clsLEAMDNSHost::_allocBackbone(void) +{ + UdpContext* pUDPContext = 0; + + if (!clsBackbone::sm_pBackbone) + { + // Not yet created + clsBackbone::sm_pBackbone = new clsBackbone; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocBackbone: Created backbone.\n"), _DH());); + + if ((clsBackbone::sm_pBackbone) && + (!clsBackbone::sm_pBackbone->init())) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocBackbone: FAILED to init backbone!\n"), _DH());); + + delete clsBackbone::sm_pBackbone; + clsBackbone::sm_pBackbone = 0; + } + } + if (clsBackbone::sm_pBackbone) + { + pUDPContext = clsBackbone::sm_pBackbone->addHost(this); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocBackbone: %s to add host to backbone.\n"), _DH(), (pUDPContext ? "Succeeded" : "FAILED"));); + return pUDPContext; +} + +/* + clsLEAmDNS2_Host::_releaseBackbone + +*/ +bool clsLEAMDNSHost::_releaseBackbone(void) +{ + bool bResult = false; + + if ((clsBackbone::sm_pBackbone) && + ((bResult = clsBackbone::sm_pBackbone->removeHost(this))) && + (0 == clsBackbone::sm_pBackbone->hostCount())) + { + delete clsBackbone::sm_pBackbone; + clsBackbone::sm_pBackbone = 0; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseBackbone: Released backbone."), _DH());); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseBackbone: %s to remove host from backbone."), _DH(), (bResult ? "Succeeded" : "FAILED"));); + return bResult; +} + + +/* + + MULTICAST GROUPS + +*/ + +/* + clsLEAmDNS2_Host::_joinMulticastGroups +*/ +bool clsLEAMDNSHost::_joinMulticastGroups(void) +{ + bool bResult = false; + + // Join multicast group(s) + if (m_pNetIf) + { + bResult = true; + +#ifdef MDNS_IPV4_SUPPORT + ip_addr_t multicast_addr_V4 = DNS_MQUERY_IPV4_GROUP_INIT; + if (!(m_pNetIf->flags & NETIF_FLAG_IGMP)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: Setting flag: flags & NETIF_FLAG_IGMP\n"), _DH());); + m_pNetIf->flags |= NETIF_FLAG_IGMP; + + if (ERR_OK != igmp_start(m_pNetIf)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: igmp_start FAILED!\n"), _DH());); + } + } + + bResult = ((bResult) && +#if LWIP_VERSION_MAJOR == 1 + (ERR_OK == igmp_joingroup(ip_2_ip4(&m_pNetIf->ip_addr), ip_2_ip4(&multicast_addr_V4)))); +#else + (ERR_OK == igmp_joingroup_netif(m_pNetIf, ip_2_ip4(&multicast_addr_V4)))); +#endif + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: igmp_joingroup_netif(%s) FAILED!\n"), _DH(), IPAddress(multicast_addr_V4).toString().c_str());); +#endif + +#ifdef MDNS_IPV6_SUPPORT + ip_addr_t multicast_addr_V6 = DNS_MQUERY_IPV6_GROUP_INIT; + bResult = ((bResult) && + (ERR_OK == mld6_joingroup_netif(m_pNetIf, ip_2_ip6(&multicast_addr_V6)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: mld6_joingroup_netif FAILED!\n"), _DH());); +#endif + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_leaveMulticastGroups +*/ +bool clsLEAMDNSHost::_leaveMulticastGroups(void) +{ + bool bResult = false; + + if (m_pNetIf) + { + bResult = true; + /* _resetProbeStatus(false); // Stop probing + + _releaseQueries(); + _releaseServices(); + _releaseHostName();*/ + + // Leave multicast group(s) +#ifdef MDNS_IPV4_SUPPORT + ip_addr_t multicast_addr_V4 = DNS_MQUERY_IPV4_GROUP_INIT; +#if LWIP_VERSION_MAJOR == 1 + if (ERR_OK != igmp_leavegroup(ip_2_ip4(&m_rNetIf.ip_addr), ip_2_ip4(&multicast_addr_V4))) +#else + if (ERR_OK != igmp_leavegroup_netif(m_pNetIf, ip_2_ip4(&multicast_addr_V4))) +#endif + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("\n"));); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + ip_addr_t multicast_addr_V6 = DNS_MQUERY_IPV6_GROUP_INIT; + if (ERR_OK != mld6_leavegroup_netif(m_pNetIf, ip_2_ip6(&multicast_addr_V6)/*&(multicast_addr_V6.u_addr.ip6)*/)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("\n"));); + } +#endif + } + return bResult; +} + + +/* + NETIF +*/ + +/* + clsLEAmDNS2_Host::_getNetIfState + + Returns the current netif state. + +*/ +clsLEAMDNSHost::typeNetIfState clsLEAMDNSHost::_getNetIfState(void) const +{ + typeNetIfState curNetIfState = static_cast(enuNetIfState::None); + + if ((m_pNetIf) && + (netif_is_up(m_pNetIf))) + { + curNetIfState |= static_cast(enuNetIfState::IsUp); + + // Check if netif link is up + if ((netif_is_link_up(m_pNetIf)) && + ((m_pNetIf != netif_get_by_index(WIFI_STA)) || + (STATION_GOT_IP == wifi_station_get_connect_status()))) + { + curNetIfState |= static_cast(enuNetIfState::LinkIsUp); + } + +#ifdef MDNS_IPV4_SUPPORT + // Check for IPv4 address + if (_getResponderIPAddress(enuIPProtocolType::V4).isSet()) + { + curNetIfState |= static_cast(enuNetIfState::IPv4); + } +#endif +#ifdef MDNS_IPV6_SUPPORT + // Check for IPv6 address + if (_getResponderIPAddress(enuIPProtocolType::V6).isSet()) + { + curNetIfState |= static_cast(enuNetIfState::IPv6); + } +#endif + } + return curNetIfState; +} + +/* + clsLEAmDNS2_Host::_checkNetIfState + + Checks the netif state. + If eg. a new address appears, the announcing is restarted. + +*/ +bool clsLEAMDNSHost::_checkNetIfState(void) +{ + typeNetIfState curNetIfState; + if (m_NetIfState != ((curNetIfState = _getNetIfState()))) + { + // Some state change happened + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: DID CHANGE NETIF STATE\n\n"), _DH());); + DEBUG_EX_INFO( + if ((curNetIfState & static_cast(enuNetIfState::IsUp)) != (m_NetIfState & static_cast(enuNetIfState::IsUp))) DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Netif is up: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::IsUp)) ? "YES" : "NO")); + if ((curNetIfState & static_cast(enuNetIfState::LinkIsUp)) != (m_NetIfState & static_cast(enuNetIfState::LinkIsUp))) DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Netif link is up: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::LinkIsUp)) ? "YES" : "NO")); +#ifdef MDNS_IPV4_SUPPORT + if ((curNetIfState & static_cast(enuNetIfState::IPv4)) != (m_NetIfState & static_cast(enuNetIfState::IPv4))) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv4 address is set: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::IPv4)) ? "YES" : "NO")); + if (curNetIfState & static_cast(enuNetIfState::IPv4)) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv4 address: %s\n"), _DH(), _getResponderIPAddress(enuIPProtocolType::V4).toString().c_str()); + } + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if ((curNetIfState & static_cast(enuNetIfState::IPv6)) != (m_NetIfState & static_cast(enuNetIfState::IPv6))) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv6 address is set: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::IPv6)) ? "YES" : "NO")); + if (curNetIfState & static_cast(enuNetIfState::IPv6)) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv6 address: %s\n"), _DH(), _getResponderIPAddress(enuIPProtocolType::V6).toString().c_str()); + } + } +#endif + ); + if ((curNetIfState & static_cast(enuNetIfState::LinkMask)) != (m_NetIfState & static_cast(enuNetIfState::LinkMask))) + { + // Link came up or down + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Link state changed -> restarting\n"), _DH());); + restart(); + } + else if (curNetIfState & static_cast(enuNetIfState::LinkIsUp)) + { + // Link is up (unchanged) + if ((curNetIfState & static_cast(enuNetIfState::IPMask)) != (m_NetIfState & static_cast(enuNetIfState::IPMask))) + { + // IP state changed + // TODO: If just a new IP address was added, a simple re-announcement should be enough + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IP state changed -> restarting\n"), _DH());); + restart(); + } + } + /* if (enuProbingStatus::Done == m_HostProbeInformation.m_ProbingStatus) { + // Probing is done, prepare to (re)announce host + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Preparing to (re)announce host.\n"));); + //m_HostProbeInformation.m_ProbingStatus = enuProbingStatus::Done; + m_HostProbeInformation.m_u8SentCount = 0; + m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + }*/ + m_NetIfState = curNetIfState; + } + + bool bResult = ((curNetIfState & static_cast(enuNetIfState::LinkMask)) && // Continue if Link is UP + (curNetIfState & static_cast(enuNetIfState::IPMask))); // AND has any IP + DEBUG_EX_INFO(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Link is DOWN(%s) or NO IP address(%s)!\n"), _DH(), (curNetIfState & static_cast(enuNetIfState::LinkMask) ? "NO" : "YES"), (curNetIfState & static_cast(enuNetIfState::IPMask) ? "NO" : "YES"));); + return bResult; +} + + +/* + PROCESSING +*/ + +/* + clsLEAmDNS2_Host::_processUDPInput +*/ +bool clsLEAMDNSHost::_processUDPInput(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput\n"), _DH());); + + bool bResult = _parseMessage(); + + /* bResult = ((_checkNetIfState()) && // Any changes in the netif state? + (_parseMessage()));*/ + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s processUDPInput: FAILED!\n"), _DH());); + + return bResult; +} + + +/* + DOMAIN NAMES +*/ + +/* + clsLEAmDNS2_Host::_allocDomainName +*/ +bool clsLEAMDNSHost::_allocDomainName(const char* p_pcNewDomainName, + char*& p_rpcDomainName) +{ + bool bResult = false; + + _releaseDomainName(p_rpcDomainName); + + size_t stLength = 0; + if ((p_pcNewDomainName) && + (clsConsts::stDomainLabelMaxLength >= (stLength = strlen(p_pcNewDomainName)))) // char max size for a single label + { + // Copy in hostname characters as lowercase + if ((bResult = (0 != (p_rpcDomainName = new char[stLength + 1])))) + { +#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME + size_t i = 0; + for (; i < stLength; ++i) + { + p_rpcDomainName[i] = (isupper(p_pcNewDomainName[i]) ? tolower(p_pcNewDomainName[i]) : p_pcNewDomainName[i]); + } + p_rpcDomainName[i] = 0; +#else + strncpy(p_rpcDomainName, p_pcNewDomainName, (stLength + 1)); +#endif + } + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_releaseDomainName +*/ +bool clsLEAMDNSHost::_releaseDomainName(char*& p_rpcDomainName) +{ + bool bResult; + if ((bResult = (0 != p_rpcDomainName))) + { + delete[] p_rpcDomainName; + p_rpcDomainName = 0; + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_allocHostName +*/ +bool clsLEAMDNSHost::_allocHostName(const char* p_pcHostName) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocHostName (%s)\n"), _DH(), p_pcHostName);); + return _allocDomainName(p_pcHostName, m_pcHostName); +} + +/* + clsLEAmDNS2_Host::_releaseHostName +*/ +bool clsLEAMDNSHost::_releaseHostName(void) +{ + return _releaseDomainName(m_pcHostName); +} + +/* + clsLEAmDNS2_Host::_allocDefaultInstanceName +*/ +bool clsLEAMDNSHost::_allocDefaultInstanceName(const char* p_pcDefaultInstanceName) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocDefaultInstanceName (%s)\n"), _DH(), p_pcDefaultInstanceName);); + return _allocDomainName(p_pcDefaultInstanceName, m_pcDefaultInstanceName); +} + +/* + clsLEAmDNS2_Host::_releaseDefaultInstanceName +*/ +bool clsLEAMDNSHost::_releaseDefaultInstanceName(void) +{ + return _releaseDomainName(m_pcDefaultInstanceName); +} + +/* + clsLEAmDNS2_Host::_instanceName +*/ +const char* clsLEAMDNSHost::_instanceName(const char* p_pcInstanceName, + bool p_bReturnZero /*= true*/) const +{ + return (p_pcInstanceName ? : (m_pcDefaultInstanceName ? : (m_pcHostName ? : (p_bReturnZero ? 0 : "-")))); +} + + +/* + SERVICE TXT +*/ + +/* + clsLEAmDNS2_Host::_collectServiceTxts +*/ +bool clsLEAMDNSHost::_collectServiceTxts(clsLEAMDNSHost::clsService& p_rService) +{ + if (p_rService.m_fnTxtCallback) + { + p_rService.m_fnTxtCallback(p_rService); + } + return true; +} + +/* + clsLEAmDNS2_Host::_releaseTempServiceTxts +*/ +bool clsLEAMDNSHost::_releaseTempServiceTxts(clsLEAMDNSHost::clsService& p_rService) +{ + return (p_rService.m_Txts.removeTempTxts()); +} + + +/* + + QUERIES + +*/ + +/* + MDNSResponder::_allocQuery + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_allocQuery(clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType) +{ + clsQuery* pQuery = new clsQuery(p_QueryType); + if (pQuery) + { + // Link to query list + m_Queries.push_back(pQuery); + } + return pQuery; +} + +/* + MDNSResponder:clsHost:::_removeQuery + +*/ +bool clsLEAMDNSHost::_removeQuery(clsLEAMDNSHost::clsQuery* p_pQuery) +{ + bool bResult = false; + + clsQuery::list::iterator it(p_pQuery + ? std::find(m_Queries.begin(), m_Queries.end(), p_pQuery) + : m_Queries.end()); + if (m_Queries.end() != it) + { + m_Queries.erase(it); + delete p_pQuery; + + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseQuery: INVALID query!"), _DH());); + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_removeLegacyQuery + +*/ +bool clsLEAMDNSHost::_removeLegacyQuery(void) +{ + clsQuery* pLegacyQuery = 0; + return (((pLegacyQuery = _findLegacyQuery())) + ? _removeQuery(pLegacyQuery) + : true); +} + +/* + clsLEAmDNS2_Host::_findLegacyQuery + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_findLegacyQuery(void) +{ + clsQuery* pLegacyQuery = 0; + + for (clsQuery* pQuery : m_Queries) + { + if (pQuery->m_bStaticQuery) + { + pLegacyQuery = pQuery; + break; + } + } + return pLegacyQuery; +} + +/* + clsLEAmDNS2_Host::_releaseQueries + +*/ +bool clsLEAMDNSHost::_releaseQueries(void) +{ + for (clsQuery* pQuery : m_Queries) + { + delete pQuery; + } + m_Queries.clear(); + return true; +} + +/* + clsLEAmDNS2_Host::_findNextQueryByDomain + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_findNextQueryByDomain(const clsLEAMDNSHost::clsRRDomain& p_Domain, + const clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType, + const clsQuery* p_pPrevQuery) +{ + clsQuery* pMatchingQuery = 0; + + clsQuery::list::iterator it(m_Queries.begin()); + if (p_pPrevQuery) + { + if (m_Queries.end() != ((it = std::find(m_Queries.begin(), m_Queries.end(), p_pPrevQuery)))) + { // Found previous object + it++; + } + DEBUG_EX_ERR(else DEBUG_OUTPUT.printf_P(PSTR("%s _findNextQueryByDomain: FAILED to find 'previous' object!\n"), _DH());); // if not prev was found -> 'cancel' + } + + for (; it != m_Queries.end(); it++) + { + if (((clsQuery::enuQueryType::None == p_QueryType) || + ((*it)->m_QueryType == p_QueryType)) && + (p_Domain == (*it)->m_Domain)) + { + pMatchingQuery = *it; + break; + } + } + return pMatchingQuery; +} + +/* + clsLEAmDNS2_Host::_installServiceQuery + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_installServiceQuery(const char* p_pcService, + const char* p_pcProtocol) +{ + clsQuery* pMDNSQuery = 0; + + if ((p_pcService) && (*p_pcService) && + (p_pcProtocol) && (*p_pcProtocol) && + ((pMDNSQuery = _allocQuery(clsQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) + { + pMDNSQuery->m_bStaticQuery = false; + + if (_sendQuery(*pMDNSQuery)) + { + pMDNSQuery->m_u8SentCount = 1; + pMDNSQuery->m_ResendTimeout.reset(clsConsts::u32DynamicQueryResendDelay); + } + else + { + _removeQuery(pMDNSQuery); + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _installServiceQuery: %s for '_%s._%s.local'!\n\n"), _DH(), (pMDNSQuery ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + DEBUG_EX_ERR(if (!pMDNSQuery) DEBUG_OUTPUT.printf_P(PSTR("%s _installServiceQuery: FAILED for '_%s._%s.local'!\n\n"), _DH(), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + return pMDNSQuery; +} + +/* + clsLEAmDNS2_Host::_installDomainQuery +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_installDomainQuery(clsLEAMDNSHost::clsRRDomain& p_Domain, + clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType) +{ + clsQuery* pQuery = 0; + + if ((pQuery = _allocQuery(p_QueryType))) + { + pQuery->m_Domain = p_Domain; + pQuery->m_bStaticQuery = false; + + if (_sendQuery(*pQuery)) + { + pQuery->m_u8SentCount = 1; + pQuery->m_ResendTimeout.reset(clsConsts::u32DynamicQueryResendDelay); + } + else + { + _removeQuery(pQuery); + } + } + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _installDomainQuery: %s for "), (pQuery ? "Succeeded" : "FAILED"), _DH()); + _printRRDomain(p_Domain); + DEBUG_OUTPUT.println(); + ); + DEBUG_EX_ERR(if (!pQuery) +{ + DEBUG_OUTPUT.printf_P(PSTR("%s _installDomainQuery: FAILED for "), _DH()); + _printRRDomain(p_Domain); + DEBUG_OUTPUT.println(); + } + ); + return pQuery; +} + +/* + clsLEAmDNS2_Host::_hasQueriesWaitingForAnswers +*/ +bool clsLEAMDNSHost::_hasQueriesWaitingForAnswers(void) const +{ + bool bOpenQueries = false; + + for (const clsQuery* pQuery : m_Queries) + { + if (pQuery->m_bAwaitingAnswers) + { + bOpenQueries = true; + break; + } + } + return bOpenQueries; +} + +/* + clsLEAmDNS2_Host::_executeQueryCallback +*/ +bool clsLEAMDNSHost::_executeQueryCallback(const clsQuery& p_Query, + const clsQuery::clsAnswer& p_Answer, + clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_bSetContent) +{ + if (p_Query.m_fnCallbackAnswer) + { + p_Query.m_fnCallbackAnswer(p_Query, p_Answer, p_QueryAnswerTypeFlags, p_bSetContent); + } + if (p_Query.m_fnCallbackAccessor) + { + p_Query.m_fnCallbackAccessor(p_Query, clsQuery::clsAnswerAccessor(&p_Answer), p_QueryAnswerTypeFlags, p_bSetContent); + } + return true; +} + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host.h b/libraries/ESP8266mDNS/src/LEAmDNS2Host.h new file mode 100644 index 0000000000..5a63d1f59e --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host.h @@ -0,0 +1,1658 @@ +/* + LEAmDNS2Host.h + (c) 2020, LaborEtArs + + Version 0.9 beta + + Some notes (from LaborEtArs, 2020): + + Supported mDNS features (in some cases somewhat limited): + - Announcing a DNS-SD service to interested observers, eg. a http server by announcing a esp8266._http._tcp.local. service + - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented + - Probing host and service domains for uniqueness in the local network + - Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak) + - Announcing available services after successful probing + - Using fixed service TXT items or + - Using dynamic service TXT items for presented services (via callback) + - Remove services (and un-announcing them to the observers by sending goodbye-messages) + - Static queries for hosts or DNS-SD services (creating a fixed answer set after a certain timeout period) + - Dynamic queries for hosts or DNS-SD services with cached and updated answers and user notifications + + + Usage: + A LEAmDNS2Host is attached to an existing netif (Network Interface). + If more than one netif is used (eg. in WIFI_AP_STA mode) and mDNS support is needed, every used netif needs its own LEAmDNS2Host! + + For presenting services: + In 'setup()': + Create an clsLEAMDNSHost instance for every netif you plan to use. + Call 'begin' on every instance with the intended hostname and the associated netif (or WiFi mode, WIFI_STA). + The given hostname is the 'probed' for uniqueness in the netifs local link. If domain name conflicts occure, the host name + will be automatically changed until it is unique in the local link. + Optionally a callback can be registered in 'begin', to control the probing process manually. + Next you can register DNS-SD services with 'addService("MyESP", "http", "tcp", 5000)' + All added service domain names are also probed for uniqueness and updated if needed. + Optionally a 'probe result' callback can be given for every service in 'addService', too. + + Finally you can add service TXT items with 'pService->addServiceTxt("c#", "1")' or by installing a service TXT callback + using 'pService->setDynamicServiceTxtCallback()' and calling 'pService->addDynamicServiceTxt("c#", "1")' inside. + + In 'loop()': + Call 'update()' for every clsLEAmDNS_Host instance. + + For querying services/hosts: + Static: + Call 'queryService("http", "tcp")' or 'queryHost("esp8266")'; + You should call MDNS.removeQuery() sometimes later (when the answers are not needed anymore) + + Dynamic: + Install a dynamic service query by calling 'installService/HostQuery("http", "tcp", serviceQueryCallback);' + The callback is called for any change in the answer set. + Call 'MDNS.removeQuery(pQuery)' when the answers are not needed anymore + + + Reference: + Used mDNS messages: + A (0x01): eg. esp8266.local A OP TTL 123.456.789.012 + AAAA (0x1C): eg. esp8266.local AAAA OP TTL 1234:5678::90 + PTR (0x0C, srv name): eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local + PTR (0x0C, srv type): eg. _services._dns-sd._udp.local PTR OP TTL _http._tcp.local + PTR (0x0C, IPv4): eg. 012.789.456.123.in-addr.arpa PTR OP TTL esp8266.local + PTR (0x0C, IPv6): eg. 90.0.0.0.0.0.0.0.0.0.0.0.78.56.34.12.ip6.arpa PTR OP TTL esp8266.local + SRV (0x21): eg. MyESP._http._tcp.local SRV OP TTL PRIORITY WEIGHT PORT esp8266.local + TXT (0x10): eg. MyESP._http._tcp.local TXT OP TTL c#=1 + NSEC (0x2F): eg. esp8266.local ... (DNSSEC) + + Some NOT used message types: + OPT (0x29): eDNS + + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef __LEAMDNS2HOST_H__ +#define __LEAMDNS2HOST_H__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "LEAmDNS2_lwIPdefs.h" + + +#define MDNS_IPV4_SUPPORT +#if LWIP_IPV6 +#define MDNS_IPV6_SUPPORT // If we've got IPv6 support, then we need IPv6 support :-) +#endif + +/* + LWIP_OPEN_SRC +*/ +#ifndef LWIP_OPEN_SRC +#define LWIP_OPEN_SRC +#endif + +/* + Enable class debug functions +*/ +#define ESP_8266_MDNS_INCLUDE +#define DEBUG_ESP_MDNS_RESPONDER + +/* + Enable/disable debug trace macros +*/ +#ifdef DEBUG_ESP_MDNS_RESPONDER +//#define DEBUG_ESP_MDNS_INFO +//#define DEBUG_ESP_MDNS_INFO2 +#define DEBUG_ESP_MDNS_ERR +#define DEBUG_ESP_MDNS_TX +#define DEBUG_ESP_MDNS_RX +#endif + +#ifdef DEBUG_ESP_MDNS_RESPONDER +#ifdef DEBUG_ESP_MDNS_INFO +#define DEBUG_EX_INFO(A) A +#else +#define DEBUG_EX_INFO(A) +#endif +#ifdef DEBUG_ESP_MDNS_INFO2 +#define DEBUG_EX_INFO2(A) A +#else +#define DEBUG_EX_INFO2(A) +#endif +#ifdef DEBUG_ESP_MDNS_ERR +#define DEBUG_EX_ERR(A) A +#else +#define DEBUG_EX_ERR(A) +#endif +#ifdef DEBUG_ESP_MDNS_TX +#define DEBUG_EX_TX(A) A +#else +#define DEBUG_EX_TX(A) +#endif +#ifdef DEBUG_ESP_MDNS_RX +#define DEBUG_EX_RX(A) A +#else +#define DEBUG_EX_RX(A) +#endif + +#ifdef DEBUG_ESP_PORT +#define DEBUG_OUTPUT DEBUG_ESP_PORT +#else +#define DEBUG_OUTPUT Serial +#endif +#else +#define DEBUG_EX_INFO(A) +#define DEBUG_EX_INFO2(A) +#define DEBUG_EX_ERR(A) +#define DEBUG_EX_TX(A) +#define DEBUG_EX_RX(A) +#endif + +/* + Enable/disable the usage of the F() macro in debug trace printf calls. + There needs to be an PGM comptible printf function to use this. + + USE_PGM_PRINTF and F +*/ +#define USE_PGM_PRINTF + +#ifdef USE_PGM_PRINTF +#else +#ifdef F +#undef F +#endif +#define F(A) A +#endif + + +namespace esp8266 +{ + + +namespace experimental +{ + + +/** + clsLEAMDNSHost +*/ +class clsLEAMDNSHost +{ +protected: + /* + clsConsts + */ + class clsConsts + { + public: +#ifdef MDNS_IPV4_SUPPORT + static const uint16_t u16IPv4Size = 4; // IPv4 address size in bytes +#endif +#ifdef MDNS_IPV6_SUPPORT + static const uint16_t u16IPv6Size = 16; // IPv6 address size in bytes +#endif + static const size_t stServiceTxtMaxLength = 1300; // Maximum length for all service txts for one service + static const size_t stDomainMaxLength = 256; // Maximum length for a full domain name eg. MyESP._http._tcp.local + static const size_t stDomainLabelMaxLength = 63; // Maximum length of on label in a domain name (length info fits into 6 bits) + static const size_t stServiceTypeMaxLength = 15; // Maximum length of a service name eg. http + static const size_t stServiceProtocolMaxLength = 3; // Maximum length of a service protocol name eg. tcp + + static const uint32_t u32LegacyTTL = 10; // Legacy DNS record TTL + static const uint32_t u32HostTTL = 120; // Host level records are set to 2min (120s) + static const uint32_t u32ServiceTTL = 4500; // Service level records are set to 75min (4500s) + + static const uint16_t u16SRVPriority = 0; // Default service priority and weight in SRV answers + static const uint16_t u16SRVWeight = 0; // + static const uint8_t u8DomainCompressMark = 0xC0; // Compressed labels are flaged by the two topmost bits of the length byte being set + static const uint8_t u8DomainMaxRedirections = 6; // Avoid endless recursion because of malformed compressed labels + + static const uint32_t u32ProbeDelay = 1000; // Default 250, but ESP is slow...; delay between and number of probes for host and service domains + static const uint32_t u32ProbeCount = 3; + static const uint32_t u32AnnounceDelay = 1000; // Delay between and number of announces for host and service domains + static const uint32_t u32AnnounceCount = 3; + static const uint32_t u32DynamicQueryResendDelay = 1000; // Delay between and number of queries; the delay is multiplied by the resent number in '_checkQueryCache' + + static const char* pcLocal; // "local"; + static const char* pcServices; // "services"; + static const char* pcDNSSD; // "dns-sd"; + static const char* pcUDP; // "udp"; + //static const char* pcTCP; // "tcp"; + +#ifdef MDNS_IPV4_SUPPORT + static const char* pcReverseIPv4Domain; // "in-addr"; +#endif +#ifdef MDNS_IPV6_SUPPORT + static const char* pcReverseIPv6Domain; // "ip6"; +#endif + static const char* pcReverseTopDomain; // "arpa"; + +#ifdef DNS_RRTYPE_NSEC + static const uint8_t u8DNS_RRTYPE_NSEC = DNS_RRTYPE_NSEC; +#else + static const uint8_t u8DNS_RRTYPE_NSEC = 0x2F; +#endif + static const uint32_t u32SendCooldown = 50; // Delay (ms) between to 'UDPContext->send()' calls + + }; + + /** + list + */ + using list = std::list; + + // File: ..._Backbone + /** + clsBackbone + */ + class clsBackbone + { + public: + static clsBackbone* sm_pBackbone; + clsBackbone(void); + ~clsBackbone(void); + + bool init(void); + + UdpContext* addHost(clsLEAMDNSHost* p_pHost); + bool removeHost(clsLEAMDNSHost* p_pHost); + size_t hostCount(void) const; + bool setDelayUDPProcessing(bool p_bDelayProcessing); + + protected: + UdpContext* m_pUDPContext; + bool m_bDelayUDPProcessing; + uint32_t m_u32DelayedDatagrams; + list m_HostList; + + bool _allocUDPContext(void); + bool _releaseUDPContext(void); + + bool _processUDPInput(void); + + const clsLEAMDNSHost* _findHost(netif* p_pNetIf) const; + clsLEAMDNSHost* _findHost(netif* p_pNetIf); + + const char* _DH(void) const; + }; + + + // File: ..._Host_Structs + /** + typeIPProtocolType & enuIPProtocolType + */ + using typeIPProtocolType = uint8_t; + enum class enuIPProtocolType : typeIPProtocolType + { +#ifdef MDNS_IPV4_SUPPORT + V4 = 0x01, +#endif +#ifdef MDNS_IPV6_SUPPORT + V6 = 0x02, +#endif + }; + + /** + typeNetIfState & enuNetIfState + */ + using typeNetIfState = uint8_t; + enum class enuNetIfState : typeNetIfState + { + None = 0x00, + + IsUp = 0x01, + UpMask = (IsUp), + + LinkIsUp = 0x02, + LinkMask = (LinkIsUp), + + IPv4 = 0x04, + IPv6 = 0x08, + IPMask = (IPv4 | IPv6), + }; + +public: + /** + clsServiceTxt + */ + class clsServiceTxt + { + public: + char* m_pcKey; + char* m_pcValue; + bool m_bTemp; + + clsServiceTxt(const char* p_pcKey = 0, + const char* p_pcValue = 0, + bool p_bTemp = false); + clsServiceTxt(const clsServiceTxt& p_Other); + ~clsServiceTxt(void); + + clsServiceTxt& operator=(const clsServiceTxt& p_Other); + bool clear(void); + + char* allocKey(size_t p_stLength); + bool setKey(const char* p_pcKey, + size_t p_stLength); + bool setKey(const char* p_pcKey); + bool releaseKey(void); + + char* allocValue(size_t p_stLength); + bool setValue(const char* p_pcValue, + size_t p_stLength); + bool setValue(const char* p_pcValue); + bool releaseValue(void); + + bool set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp = false); + + bool update(const char* p_pcValue); + + size_t length(void) const; + + /** + list + */ + using list = std::list; + }; + + /** + clsServiceTxts + */ + class clsServiceTxts + { + public: + clsServiceTxt::list m_Txts; + char* m_pcCache; + + clsServiceTxts(void); + clsServiceTxts(const clsServiceTxts& p_Other); + ~clsServiceTxts(void); + + clsServiceTxts& operator=(const clsServiceTxts& p_Other); + + bool clear(void); + bool clearCache(void); + + bool add(clsServiceTxt* p_pTxt); + bool remove(clsServiceTxt* p_pTxt); + + size_t count(void) const; + + bool removeTempTxts(void); + + clsServiceTxt* find(const char* p_pcKey); + const clsServiceTxt* find(const char* p_pcKey) const; + clsServiceTxt* find(const clsServiceTxt* p_pTxt); + + size_t length(void) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer); + const char* c_str(void) const; + + size_t bufferLength(void) const; + bool buffer(char* p_pcBuffer); + + bool compare(const clsServiceTxts& p_Other) const; + bool operator==(const clsServiceTxts& p_Other) const; + bool operator!=(const clsServiceTxts& p_Other) const; + }; + +protected: + /** + clsProbeInformation_Base + */ + class clsProbeInformation_Base + { + public: + /** + typeProbingStatus & enuProbingStatus + */ + using typeProbingStatus = uint8_t; + enum class enuProbingStatus : typeProbingStatus + { + WaitingForData, + ReadyToStart, + InProgress, + ReadyToAnnounce, + DoneFinally + }; + + enuProbingStatus m_ProbingStatus; + uint8_t m_u8SentCount; // Used for probes and announcements + esp8266::polledTimeout::oneShot m_Timeout; // Used for probes and announcements + bool m_bConflict; + bool m_bTiebreakNeeded; + + clsProbeInformation_Base(void); + + bool clear(void); // No 'virtual' needed, no polymorphic use (save 4 bytes) + }; + +public: + /** + fnProbeResultCallback + Callback function for host domain probe results + */ + using fnProbeResultCallback = std::function; + +protected: + /** + clsProbeInformation + */ + class clsProbeInformation : public clsProbeInformation_Base + { + public: + fnProbeResultCallback m_fnProbeResultCallback; + + clsProbeInformation(void); + + bool clear(bool p_bClearUserdata = false); + }; + +public: + /** + clsService + */ + struct clsService + { + public: + /** + fnDynamicServiceTxtCallback + */ + using fnDynamicServiceTxtCallback = std::function; + + /** + fnProbeResultCallback + */ + using fnProbeResultCallback = std::function; + + protected: + friend clsLEAMDNSHost; + /** + clsProbeInformation + */ + class clsProbeInformation : public clsProbeInformation_Base + { + public: + fnProbeResultCallback m_fnProbeResultCallback; + + clsProbeInformation(void); + + bool clear(bool p_bClearUserdata = false); + }; + + char* m_pcInstanceName; + bool m_bAutoName; // Name was set automatically to hostname (if no name was supplied) + char* m_pcType; + char* m_pcProtocol; + uint16_t m_u16Port; + uint32_t m_u32ReplyMask; + clsServiceTxts m_Txts; + fnDynamicServiceTxtCallback m_fnTxtCallback; + clsProbeInformation m_ProbeInformation; + + clsService(void); + ~clsService(void); + + bool _releaseInstanceName(void); + bool _releaseType(void); + bool _releaseProtocol(void); + + void _resetProbeStatus(void); + + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + uint32_t p_u32Value, + bool p_bTemp); + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + uint16_t p_u16Value, + bool p_bTemp); + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + uint8_t p_u8Value, + bool p_bTemp); + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + int32_t p_i32Value, + bool p_bTemp); + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + int16_t p_i16Value, + bool p_bTemp); + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + int8_t p_i8Value, + bool p_bTemp); + + public: + bool setInstanceName(const char* p_pcInstanceName); + bool indexInstanceName(void); + const char* instanceName(void) const; + + bool setType(const char* p_pcType); + const char* type(void) const; + + bool setProtocol(const char* p_pcProtocol); + const char* protocol(void) const; + + bool setPort(uint16_t p_i16Port); + uint16_t port(void) const; + + bool setProbeResultCallback(fnProbeResultCallback p_fnProbeResultCallback); + bool probeStatus(void) const; + + // TXT + // Add a (static) MDNS TXT item ('key' = 'value') to the service + clsServiceTxt* addServiceTxt(const char* p_pcKey, + const char* p_pcValue); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + uint32_t p_u32Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + uint16_t p_u16Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + uint8_t p_u8Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + int32_t p_i32Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + int16_t p_i16Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + int8_t p_i8Value); + + bool removeServiceTxt(const char* p_pcKey); + bool removeServiceTxt(clsServiceTxt* p_pTxt); + const clsServiceTxt* findServiceTxt(const char* p_pcKey) const; + clsServiceTxt* findServiceTxt(const char* p_pcKey); + + // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + // Dynamic TXT items are removed right after one-time use. So they need to be added + // every time the value s needed (via callback). + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + const char* p_pcValue); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + uint32_t p_u32Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + uint16_t p_u16Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + uint8_t p_u8Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + int32_t p_i32Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + int16_t p_i16Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + int8_t p_i8Value); + + bool setDynamicServiceTxtCallback(fnDynamicServiceTxtCallback p_fnCallback); + + /** + list + */ + using list = std::list; + }; + +protected: + /** + typeContentFlag & enuContentFlag + */ + using typeContentFlag = uint16_t; + enum class enuContentFlag : typeContentFlag + { + // Host + A = 0x0001, + PTR_IPv4 = 0x0002, + PTR_IPv6 = 0x0004, + AAAA = 0x0008, + // Service + PTR_TYPE = 0x0010, + PTR_NAME = 0x0020, + TXT = 0x0040, + SRV = 0x0080, + // DNSSEC + NSEC = 0x0100, + + PTR = (PTR_IPv4 | PTR_IPv6 | PTR_TYPE | PTR_NAME) + }; + + /** + clsMsgHeader + */ + class clsMsgHeader + { + public: + uint16_t m_u16ID; // Identifier + bool m_1bQR : 1; // Query/Response flag + uint8_t m_4bOpcode : 4; // Operation code + bool m_1bAA : 1; // Authoritative Answer flag + bool m_1bTC : 1; // Truncation flag + bool m_1bRD : 1; // Recursion desired + bool m_1bRA : 1; // Recursion available + uint8_t m_3bZ : 3; // Zero + uint8_t m_4bRCode : 4; // Response code + uint16_t m_u16QDCount; // Question count + uint16_t m_u16ANCount; // Answer count + uint16_t m_u16NSCount; // Authority Record count + uint16_t m_u16ARCount; // Additional Record count + + clsMsgHeader(uint16_t p_u16ID = 0, + bool p_bQR = false, + uint8_t p_u8Opcode = 0, + bool p_bAA = false, + bool p_bTC = false, + bool p_bRD = false, + bool p_bRA = false, + uint8_t p_u8RCode = 0, + uint16_t p_u16QDCount = 0, + uint16_t p_u16ANCount = 0, + uint16_t p_u16NSCount = 0, + uint16_t p_u16ARCount = 0); + }; + + /** + clsRRDomain + */ + class clsRRDomain + { + public: + char m_acName[clsConsts::stDomainMaxLength]; // Encoded domain name + uint16_t m_u16NameLength; // Length (incl. '\0') + char* m_pcDecodedName; + + clsRRDomain(void); + clsRRDomain(const clsRRDomain& p_Other); + ~clsRRDomain(void); + + clsRRDomain& operator=(const clsRRDomain& p_Other); + + bool clear(void); + bool clearNameCache(void); + + bool addLabel(const char* p_pcLabel, + bool p_bPrependUnderline = false); + + bool compare(const clsRRDomain& p_Other) const; + bool operator==(const clsRRDomain& p_Other) const; + bool operator!=(const clsRRDomain& p_Other) const; + bool operator>(const clsRRDomain& p_Other) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer) const; + const char* c_str(void) const; + }; + + /** + clsRRAttributes + */ + class clsRRAttributes + { + public: + uint16_t m_u16Type; // Type + uint16_t m_u16Class; // Class, nearly always 'IN' + + clsRRAttributes(uint16_t p_u16Type = 0, + uint16_t p_u16Class = 1 /*DNS_RRCLASS_IN Internet*/); + clsRRAttributes(const clsRRAttributes& p_Other); + + clsRRAttributes& operator=(const clsRRAttributes& p_Other); + }; + + /** + clsRRHeader + */ + class clsRRHeader + { + public: + clsRRDomain m_Domain; + clsRRAttributes m_Attributes; + + clsRRHeader(void); + clsRRHeader(const clsRRHeader& p_Other); + + clsRRHeader& operator=(const clsRRHeader& p_Other); + + bool clear(void); + }; + + /** + clsRRQuestion + */ + struct clsRRQuestion + { + clsRRHeader m_Header; + bool m_bUnicast; // Unicast reply requested + + /** + list + */ + using list = std::list; + + clsRRQuestion(void); + }; + + /** + clsNSECBitmap + */ + class clsNSECBitmap + { + public: + uint8_t m_au8BitmapData[6]; // 6 bytes data + + clsNSECBitmap(void); + + bool clear(void); + uint16_t length(void) const; + bool setBit(uint16_t p_u16Bit); + bool getBit(uint16_t p_u16Bit) const; + }; + + /** + typeAnswerType & enuAnswerType + */ + using typeAnswerType = uint8_t; + enum class enuAnswerType : typeAnswerType + { + A, + PTR, + TXT, + AAAA, + SRV, + //NSEC, + Generic + }; + + /** + clsRRAnswer + */ + struct clsRRAnswer + { + clsRRAnswer* m_pNext; + const enuAnswerType m_AnswerType; + clsRRHeader m_Header; + bool m_bCacheFlush; // Cache flush command bit + uint32_t m_u32TTL; // Validity time in seconds + + virtual ~clsRRAnswer(void); + + enuAnswerType answerType(void) const; + + bool clear(void); + + protected: + clsRRAnswer(enuAnswerType p_AnswerType, + const clsRRHeader& p_Header, + uint32_t p_u32TTL); + }; + +#ifdef MDNS_IPV4_SUPPORT + /** + clsRRAnswerA + */ + class clsRRAnswerA : public clsRRAnswer + { + public: + IPAddress m_IPAddress; + + clsRRAnswerA(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerA(void); + + bool clear(void); + }; +#endif + + /** + clsRRAnswerPTR + */ + class clsRRAnswerPTR : public clsRRAnswer + { + public: + clsRRDomain m_PTRDomain; + + clsRRAnswerPTR(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerPTR(void); + + bool clear(void); + }; + + /** + clsRRAnswerTXT + */ + class clsRRAnswerTXT : public clsRRAnswer + { + public: + clsServiceTxts m_Txts; + + clsRRAnswerTXT(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerTXT(void); + + bool clear(void); + }; + +#ifdef MDNS_IPV6_SUPPORT + /** + clsRRAnswerAAAA + */ + class clsRRAnswerAAAA : public clsRRAnswer + { + public: + IPAddress m_IPAddress; + + clsRRAnswerAAAA(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerAAAA(void); + + bool clear(void); + }; +#endif + + /** + clsRRAnswerSRV + */ + class clsRRAnswerSRV : public clsRRAnswer + { + public: + uint16_t m_u16Priority; + uint16_t m_u16Weight; + uint16_t m_u16Port; + clsRRDomain m_SRVDomain; + + clsRRAnswerSRV(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerSRV(void); + + bool clear(void); + }; + + /** + clsRRAnswerGeneric + */ + class clsRRAnswerGeneric : public clsRRAnswer + { + public: + uint16_t m_u16RDLength; // Length of variable answer + uint8_t* m_pu8RDData; // Offset of start of variable answer in packet + + clsRRAnswerGeneric(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerGeneric(void); + + bool clear(void); + }; + + + /** + clsSendParameter + */ + class clsSendParameter + { + protected: + /** + clsDomainCacheItem + */ + class clsDomainCacheItem + { + public: + const void* m_pHostNameOrService; // Opaque id for host or service domain (pointer) + bool m_bAdditionalData; // Opaque flag for special info (service domain included) + uint16_t m_u16Offset; // Offset in UDP output buffer + + /** + list + */ + using list = std::list; + + clsDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset); + }; + + public: + /** + typeResponseType & enuResponseType + */ + using typeResponseType = uint8_t; + enum class enuResponseType : typeResponseType + { + None, + Response, + Unsolicited + }; + + uint16_t m_u16ID; // Query ID (used only in lagacy queries) + clsRRQuestion::list m_RRQuestions; // A list of queries + uint32_t m_u32HostReplyMask; // Flags for reply components/answers + bool m_bLegacyDNSQuery; // Flag: Legacy query + enuResponseType m_Response; // Enum: Response to a query + bool m_bAuthorative; // Flag: Authorative (owner) response + bool m_bCacheFlush; // Flag: Clients should flush their caches + bool m_bUnicast; // Flag: Unicast response + bool m_bUnannounce; // Flag: Unannounce service + + // Temp content; created while processing _prepareMessage + uint16_t m_u16Offset; // Current offset in UDP write buffer (mainly for domain cache) + clsDomainCacheItem::list m_DomainCacheItems; // Cached host and service domains + + clsSendParameter(void); + ~clsSendParameter(void); + + bool clear(void); + bool flushQuestions(void); + bool flushDomainCache(void); + bool flushTempContent(void); + + bool shiftOffset(uint16_t p_u16Shift); + + bool addDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset); + uint16_t findCachedDomainOffset(const void* p_pHostNameOrService, + bool p_bAdditionalData) const; + }; + +public: + // QUERIES & ANSWERS + + /** + clsQuery + */ + class clsQuery + { + public: + /** + clsAnswer + */ + class clsAnswer + { + public: + /** + typeQueryAnswerType & enuQueryAnswerType + */ + using typeQueryAnswerType = uint8_t; + enum class enuQueryAnswerType : typeQueryAnswerType + { + Unknown = 0x00, + ServiceDomain = 0x01, // Service domain + HostDomain = 0x02, // Host domain + Port = 0x04, // Port + Txts = 0x08, // TXT items +#ifdef MDNS_IPV4_SUPPORT + IPv4Address = 0x10, // IPv4 address +#endif +#ifdef MDNS_IPV6_SUPPORT + IPv6Address = 0x20, // IPv6 address +#endif + }; + + /** + stcTTL + */ + class clsTTL + { + public: + /** + typeTimeoutLevel & enuTimeoutLevel + */ + using typeTimeoutLevel = uint8_t; + enum class enuTimeoutLevel : typeTimeoutLevel + { + None = 0, + Base = 80, + Interval = 5, + Final = 100 + }; + + uint32_t m_u32TTL; + esp8266::polledTimeout::oneShot m_TTLTimeout; + typeTimeoutLevel m_TimeoutLevel; + + clsTTL(void); + bool set(uint32_t p_u32TTL); + + bool flagged(void) const; + bool restart(void); + + bool prepareDeletion(void); + bool finalTimeoutLevel(void) const; + + unsigned long timeout(void) const; + }; + + /** + clsIPAddressWithTTL + */ + class clsIPAddressWithTTL + { + public: + IPAddress m_IPAddress; + clsTTL m_TTL; + + /** + list + */ + using list = std::list; + + clsIPAddressWithTTL(IPAddress p_IPAddress, + uint32_t p_u32TTL = 0); + }; + + // The service domain is the first 'answer' (from PTR answer, using service and protocol) to be set + // Defines the key for additional answer, like host domain, etc. + clsRRDomain m_ServiceDomain; // 1. level answer (PTR), eg. MyESP._http._tcp.local + clsTTL m_TTLServiceDomain; + clsRRDomain m_HostDomain; // 2. level answer (SRV, using service domain), eg. esp8266.local + uint16_t m_u16Port; // 2. level answer (SRV, using service domain), eg. 5000 + clsTTL m_TTLHostDomainAndPort; + clsServiceTxts m_Txts; // 2. level answer (TXT, using service domain), eg. c#=1 + clsTTL m_TTLTxts; +#ifdef MDNS_IPV4_SUPPORT + clsIPAddressWithTTL::list m_IPv4Addresses; // 3. level answer (A, using host domain), eg. 123.456.789.012 +#endif +#ifdef MDNS_IPV6_SUPPORT + clsIPAddressWithTTL::list m_IPv6Addresses; // 3. level answer (AAAA, using host domain), eg. 1234::09 +#endif + typeQueryAnswerType m_QueryAnswerFlags; // enuQueryAnswerType + + /** + list + */ + using list = std::list; + + clsAnswer(void); + ~clsAnswer(void); + + bool clear(void); + +#ifdef MDNS_IPV4_SUPPORT + bool releaseIPv4Addresses(void); + bool addIPv4Address(clsIPAddressWithTTL* p_pIPAddress); + bool removeIPv4Address(clsIPAddressWithTTL* p_pIPAddress); + const clsIPAddressWithTTL* findIPv4Address(const IPAddress& p_IPAddress) const; + clsIPAddressWithTTL* findIPv4Address(const IPAddress& p_IPAddress); + uint32_t IPv4AddressCount(void) const; + const clsIPAddressWithTTL* IPv4AddressAtIndex(uint32_t p_u32Index) const; + clsIPAddressWithTTL* IPv4AddressAtIndex(uint32_t p_u32Index); +#endif +#ifdef MDNS_IPV6_SUPPORT + bool releaseIPv6Addresses(void); + bool addIPv6Address(clsIPAddressWithTTL* p_pIPAddress); + bool removeIPv6Address(clsIPAddressWithTTL* p_pIPAddress); + const clsIPAddressWithTTL* findIPv6Address(const IPAddress& p_IPAddress) const; + clsIPAddressWithTTL* findIPv6Address(const IPAddress& p_IPAddress); + uint32_t IPv6AddressCount(void) const; + const clsIPAddressWithTTL* IPv6AddressAtIndex(uint32_t p_u32Index) const; + clsIPAddressWithTTL* IPv6AddressAtIndex(uint32_t p_u32Index); +#endif + }; // clsAnswer + + /** + clsAnswerAccessor + */ + class clsAnswerAccessor + { + protected: + /** + stcCompareTxtKey + */ + struct stcCompareTxtKey + { + bool operator()(char const* p_pA, char const* p_pB) const; + }; + public: + clsAnswerAccessor(const clsAnswer* p_pAnswer); + ~clsAnswerAccessor(void); + + /** + clsTxtKeyValueMap + */ + using clsTxtKeyValueMap = std::map; + /** + clsIPAddressVector + */ + using clsIPAddressVector = std::vector; + /** + vector + */ + using vector = std::vector; + + bool serviceDomainAvailable(void) const; + const char* serviceDomain(void) const; + bool hostDomainAvailable(void) const; + const char* hostDomain(void) const; + bool hostPortAvailable(void) const; + uint16_t hostPort(void) const; +#ifdef MDNS_IPV4_SUPPORT + bool IPv4AddressAvailable(void) const; + clsIPAddressVector IPv4Addresses(void) const; +#endif +#ifdef MDNS_IPV6_SUPPORT + bool IPv6AddressAvailable(void) const; + clsIPAddressVector IPv6Addresses(void) const; +#endif + bool txtsAvailable(void) const; + const char* txts(void) const; + const clsTxtKeyValueMap& txtKeyValues(void) const; + const char* txtValue(const char* p_pcKey) const; + + size_t printTo(Print& p_Print) const; + + protected: + const clsAnswer* m_pAnswer; + clsTxtKeyValueMap m_TxtKeyValueMap; + }; + + /** + typeQueryType & enuQueryType + */ + using typeQueryType = uint8_t; + enum class enuQueryType : typeQueryType + { + None, + Service, + Host + }; + + /** + QueryCallbackAnswerFn + */ + using QueryCallbackAnswerFn = std::function; // true: Answer component set, false: component deleted + /** + QueryCallbackAccessorFn + */ + using QueryCallbackAccessorFn = std::function; // true: Answer component set, false: component deleted + + protected: + friend clsLEAMDNSHost; + + enuQueryType m_QueryType; + clsRRDomain m_Domain; // Type:Service -> _http._tcp.local; Type:Host -> esp8266.local + QueryCallbackAnswerFn m_fnCallbackAnswer; + QueryCallbackAccessorFn m_fnCallbackAccessor; + bool m_bStaticQuery; + uint8_t m_u8SentCount; + esp8266::polledTimeout::oneShot m_ResendTimeout; + bool m_bAwaitingAnswers; + clsAnswer::list m_Answers; + + /** + list + */ + using list = std::list; + + clsQuery(const enuQueryType p_QueryType); + ~clsQuery(void); + + bool clear(void); + + bool addAnswer(clsAnswer* p_pAnswer); + bool removeAnswer(clsAnswer* p_pAnswer); + + clsAnswer* findAnswerForServiceDomain(const clsRRDomain& p_ServiceDomain); + clsAnswer* findAnswerForHostDomain(const clsRRDomain& p_HostDomain); + + public: + uint32_t answerCount(void) const; + const clsAnswer* answer(uint32_t p_u32Index) const; + uint32_t indexOfAnswer(const clsAnswer* p_pAnswer) const; + + clsAnswerAccessor::vector answerAccessors(void) const; + clsAnswerAccessor answerAccessor(uint32 p_u32AnswerIndex) const; + }; + +public: + static const char* indexDomainName(const char* p_pcDomainName, + const char* p_pcDivider = "-", + const char* p_pcDefaultDomainName = 0); + static bool setNetIfHostName(netif* p_pNetIf, + const char* p_pcHostName); + + clsLEAMDNSHost(void); + ~clsLEAMDNSHost(void); + + // INIT + // Create a MDNS host by setting the default hostname + // Later call 'update()' in every 'loop' to run the process loop + // (probing, announcing, responding, ...) + // If no callback is given, the (maybe) already installed callback stays set + bool begin(const char* p_pcHostName, + netif* p_pNetIf, + fnProbeResultCallback p_fnCallback = 0); + bool begin(const char* p_pcHostName, + WiFiMode_t p_WiFiMode, + fnProbeResultCallback p_fnCallback = 0); + bool begin(const char* p_pcHostName, + fnProbeResultCallback p_fnCallback = 0); + + bool close(void); + + // HOST + bool setHostName(const char* p_pcHostName); + bool indexHostName(void); + const char* hostName(void) const; + + bool setProbeResultCallback(fnProbeResultCallback p_fnCallback); + + // Returns 'true' is host domain probing is done + bool probeStatus(void) const; + + // SERVICE + bool setDefaultInstanceName(const char* p_pcInstanceName); + const char* defaultInstanceName(void) const; + + clsService* addService(const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port, + clsService::fnProbeResultCallback p_fnCallback = 0); + bool removeService(clsService* p_pMDNSService); + + const clsService* findService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port = (uint16_t)(-1)) const; + clsService* findService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port = (uint16_t)(-1)); + const clsService::list& services(void) const; + + // QUERIES + + // - STATIC + // Perform a (static) service/host query. The function returns after p_u16Timeout milliseconds + // The answers (the number of received answers is returned) can be retrieved by calling + // - answerHostName (or hostname) + // - answerIP (or IP) + // - answerPort (or port) + clsQuery::clsAnswerAccessor::vector queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout); + clsQuery::clsAnswerAccessor::vector queryHost(const char* p_pcHostName, + const uint16_t p_u16Timeout); + bool removeQuery(void); + bool hasQuery(void); + clsQuery* getQuery(void); + + // - DYNAMIC + // Install a dynamic service/host query. For every received answer (part) the given callback + // function is called. The query will be updated every time, the TTL for an answer + // has timed-out. + // The answers can also be retrieved by calling + // - answerCount service/host (for host queries, this should never be >1) + // - answerServiceDomain service + // - hasAnswerHostDomain/answerHostDomain service/host + // - hasAnswerIPv4Address/answerIPv4Address service/host + // - hasAnswerIPv6Address/answerIPv6Address service/host + // - hasAnswerPort/answerPort service + // - hasAnswerTxts/answerTxts service + clsQuery* installServiceQuery(const char* p_pcServiceType, + const char* p_pcProtocol, + clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer); + clsQuery* installServiceQuery(const char* p_pcServiceType, + const char* p_pcProtocol, + clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor); + clsQuery* installHostQuery(const char* p_pcHostName, + clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer); + clsQuery* installHostQuery(const char* p_pcHostName, + clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor); + // Remove a dynamic service query + bool removeQuery(clsQuery* p_pQuery); + + // PROCESSING + bool update(void); + + bool announce(bool p_bAnnounce = true, + bool p_bIncludeServices = true); + bool announceService(clsService* p_pService, + bool p_bAnnounce = true); + + bool restart(void); + +protected: + // File: ..._Host + UdpContext* _allocBackbone(void); + bool _releaseBackbone(void); + + bool _joinMulticastGroups(void); + bool _leaveMulticastGroups(void); + + // NETIF + typeNetIfState _getNetIfState(void) const; + bool _checkNetIfState(void); + + // PROCESSING + bool _processUDPInput(void); + + // DOMAIN NAMES + bool _allocDomainName(const char* p_pcNewDomainName, + char*& p_rpcDomainName); + bool _releaseDomainName(char*& p_rpcDomainName); + bool _allocHostName(const char* p_pcHostName); + bool _releaseHostName(void); + + bool _allocDefaultInstanceName(const char* p_pcInstanceName); + bool _releaseDefaultInstanceName(void); + const char* _instanceName(const char* p_pcInstanceName, + bool p_bReturnZero = true) const; + + // SERVICE + clsService* _allocService(const char* p_pcName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port); + bool _releaseService(clsService* p_pService); + + // SERVICE TXT + clsServiceTxt* _allocServiceTxt(clsService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + bool _releaseServiceTxt(clsService* p_pService, + clsServiceTxt* p_pTxt); + clsServiceTxt* _updateServiceTxt(clsService* p_pService, + clsServiceTxt* p_pTxt, + const char* p_pcValue, + bool p_bTemp); + clsServiceTxt* _findServiceTxt(clsService* p_pService, + const char* p_pcKey); + clsServiceTxt* _addServiceTxt(clsService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + clsServiceTxt* _answerKeyValue(const clsQuery p_pQuery, + const uint32_t p_u32AnswerIndex); + bool _collectServiceTxts(clsService& p_rService); + bool _releaseTempServiceTxts(clsService& p_rService); + + + // QUERIES + clsQuery* _allocQuery(clsQuery::enuQueryType p_QueryType); + bool _removeQuery(clsQuery* p_pQuery); + bool _removeLegacyQuery(void); + clsQuery* _findLegacyQuery(void); + bool _releaseQueries(void); + clsQuery* _findNextQueryByDomain(const clsRRDomain& p_Domain, + const clsQuery::enuQueryType p_QueryType, + const clsQuery* p_pPrevQuery); + clsQuery* _installServiceQuery(const char* p_pcService, + const char* p_pcProtocol); + clsQuery* _installDomainQuery(clsRRDomain& p_Domain, + clsQuery::enuQueryType p_QueryType); + bool _hasQueriesWaitingForAnswers(void) const; + bool _executeQueryCallback(const clsQuery& p_Query, + const clsQuery::clsAnswer& p_Answer, + clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_SetContent); + + + // File: ..._Host_Control + // RECEIVING + bool _parseMessage(void); + bool _parseQuery(const clsMsgHeader& p_Header); + + bool _parseResponse(const clsMsgHeader& p_Header); + bool _processAnswers(const clsRRAnswer* p_pPTRAnswers); + bool _processPTRAnswer(const clsRRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processSRVAnswer(const clsRRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processTXTAnswer(const clsRRAnswerTXT* p_pTXTAnswer); +#ifdef MDNS_IPV4_SUPPORT + bool _processAAnswer(const clsRRAnswerA* p_pAAnswer); +#endif +#ifdef MDNS_IPV6_SUPPORT + bool _processAAAAAnswer(const clsRRAnswerAAAA* p_pAAAAAnswer); +#endif + + // PROBING + bool _updateProbeStatus(void); + bool _resetProbeStatus(bool p_bRestart = true); + bool _hasProbesWaitingForAnswers(void) const; + bool _sendHostProbe(void); + bool _sendServiceProbe(clsService& p_rService); + bool _cancelProbingForHost(void); + bool _cancelProbingForService(clsService& p_rService); + bool _callHostProbeResultCallback(bool p_bResult); + bool _callServiceProbeResultCallback(clsService& p_rService, + bool p_bResult); + + // ANNOUNCE + bool _announce(bool p_bAnnounce, + bool p_bIncludeServices); + bool _announceService(clsService& p_pService, + bool p_bAnnounce = true); + + // QUERY CACHE + bool _checkQueryCache(void); + + uint32_t _replyMaskForHost(const clsRRHeader& p_RRHeader, + bool* p_pbFullNameMatch = 0) const; + uint32_t _replyMaskForService(const clsRRHeader& p_RRHeader, + clsService& p_rService, + bool* p_pbFullNameMatch = 0); + + + // File: ..._Host_Transfer + // SENDING + bool _sendMessage(clsSendParameter& p_SendParameter); + bool _sendMessage_Multicast(clsSendParameter& p_rSendParameter, + uint8_t p_IPProtocolTypes); + bool _prepareMessage(clsSendParameter& p_SendParameter); + bool _addQueryRecord(clsSendParameter& p_rSendParameter, + const clsRRDomain& p_QueryDomain, + uint16_t p_u16QueryType); + bool _sendQuery(const clsQuery& p_Query, + clsQuery::clsAnswer::list* p_pKnownAnswers = 0); + bool _sendQuery(const clsRRDomain& p_QueryDomain, + uint16_t p_u16RecordType, + clsQuery::clsAnswer::list* p_pKnownAnswers = 0); + + IPAddress _getResponderIPAddress(enuIPProtocolType p_IPProtocolType) const; + + // RESOURCE RECORD + bool _readRRQuestion(clsRRQuestion& p_rQuestion); + bool _readRRAnswer(clsRRAnswer*& p_rpAnswer); +#ifdef MDNS_IPV4_SUPPORT + bool _readRRAnswerA(clsRRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerPTR(clsRRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength); + bool _readRRAnswerTXT(clsRRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength); +#ifdef MDNS_IPV6_SUPPORT + bool _readRRAnswerAAAA(clsRRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerSRV(clsRRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength); + bool _readRRAnswerGeneric(clsRRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength); + + bool _readRRHeader(clsRRHeader& p_rHeader); + bool _readRRDomain(clsRRDomain& p_rRRDomain); + bool _readRRDomain_Loop(clsRRDomain& p_rRRDomain, + uint8_t p_u8Depth); + bool _readRRAttributes(clsRRAttributes& p_rAttributes); + + // DOMAIN NAMES + bool _buildDomainForHost(const char* p_pcHostName, + clsRRDomain& p_rHostDomain) const; + bool _buildDomainForDNSSD(clsRRDomain& p_rDNSSDDomain) const; + bool _buildDomainForService(const clsService& p_Service, + bool p_bIncludeName, + clsRRDomain& p_rServiceDomain) const; + bool _buildDomainForService(const char* p_pcService, + const char* p_pcProtocol, + clsRRDomain& p_rServiceDomain) const; +#ifdef MDNS_IPV4_SUPPORT + bool _buildDomainForReverseIPv4(IPAddress p_IPv4Address, + clsRRDomain& p_rReverseIPv4Domain) const; +#endif +#ifdef MDNS_IPV6_SUPPORT + bool _buildDomainForReverseIPv6(IPAddress p_IPv4Address, + clsRRDomain& p_rReverseIPv6Domain) const; +#endif + + // UDP + bool _udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength); + bool _udpRead8(uint8_t& p_ru8Value); + bool _udpRead16(uint16_t& p_ru16Value); + bool _udpRead32(uint32_t& p_ru32Value); + + bool _udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength); + bool _udpAppend8(uint8_t p_u8Value); + bool _udpAppend16(uint16_t p_u16Value); + bool _udpAppend32(uint32_t p_u32Value); + +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + bool _udpDump(bool p_bMovePointer = false); + bool _udpDump(unsigned p_uOffset, + unsigned p_uLength); +#endif + + // READ/WRITE MDNS STRUCTS + bool _readMDNSMsgHeader(clsMsgHeader& p_rMsgHeader); + + bool _write8(uint8_t p_u8Value, + clsSendParameter& p_rSendParameter); + bool _write16(uint16_t p_u16Value, + clsSendParameter& p_rSendParameter); + bool _write32(uint32_t p_u32Value, + clsSendParameter& p_rSendParameter); + + bool _writeMDNSMsgHeader(const clsMsgHeader& p_MsgHeader, + clsSendParameter& p_rSendParameter); + bool _writeMDNSRRAttributes(const clsRRAttributes& p_Attributes, + clsSendParameter& p_rSendParameter); + bool _writeMDNSRRDomain(const clsRRDomain& p_Domain, + clsSendParameter& p_rSendParameter); + bool _writeMDNSHostDomain(const char* m_pcHostName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsSendParameter& p_rSendParameter); + bool _writeMDNSServiceDomain(const clsService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsSendParameter& p_rSendParameter); + + bool _writeMDNSQuestion(clsRRQuestion& p_Question, + clsSendParameter& p_rSendParameter); + +#ifdef MDNS_IPV4_SUPPORT + bool _writeMDNSAnswer_A(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_PTR_TYPE(clsService& p_rService, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_NAME(clsService& p_rService, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_TXT(clsService& p_rService, + clsSendParameter& p_rSendParameter); +#ifdef MDNS_IPV6_SUPPORT + bool _writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_SRV(clsService& p_rService, + clsSendParameter& p_rSendParameter); + clsNSECBitmap* _createNSECBitmap(uint32_t p_u32NSECContent); + bool _writeMDNSNSECBitmap(const clsNSECBitmap& p_NSECBitmap, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_NSEC(uint32_t p_u32NSECContent, + clsSendParameter& p_rSendParameter); +#ifdef MDNS_IPV4_SUPPORT + bool _writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); +#endif +#ifdef MDNS_IPV6_SUPPORT + bool _writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_NSEC(clsService& p_rService, + uint32_t p_u32NSECContent, + clsSendParameter& p_rSendParameter); + + + // File: ..._Host_Debug +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + const char* _DH(const clsService* p_pMDNSService = 0) const; + const char* _service2String(const clsService* p_pMDNSService) const; + + bool _printRRDomain(const clsRRDomain& p_rRRDomain) const; + bool _printRRAnswer(const clsRRAnswer& p_RRAnswer) const; + const char* _RRType2Name(uint16_t p_u16RRType) const; + const char* _RRClass2String(uint16_t p_u16RRClass, + bool p_bIsQuery) const; + const char* _replyFlags2String(uint32_t p_u32ReplyFlags) const; + const char* _NSECBitmap2String(const clsNSECBitmap* p_pNSECBitmap) const; +#endif + + +protected: + netif* m_pNetIf; + typeNetIfState m_NetIfState; + UdpContext* m_pUDPContext; + + char* m_pcHostName; + char* m_pcDefaultInstanceName; + clsService::list m_Services; + clsQuery::list m_Queries; + clsProbeInformation m_ProbeInformation; +}; + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + +#endif // __LEAMDNS2HOST_H__ + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp old mode 100755 new mode 100644 similarity index 66% rename from libraries/ESP8266mDNS/src/LEAmDNS2_Host_Control.cpp rename to libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp index 7b4402c587..11fece09c1 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Control.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp @@ -1,5 +1,5 @@ /* - LEAmDNS2_Host_Control.cpp + LEAmDNS2Host_Control.cpp License (MIT license): Permission is hereby granted, free of charge, to any person obtaining a copy @@ -22,54 +22,41 @@ */ -#include -#include -#include -#include -#include -#include -#include +#include "LEAmDNS2Host.h" -/* - ESP8266mDNS Control.cpp -*/ - -extern "C" { -#include "user_interface.h" -} - -#include "LEAmDNS2_lwIPdefs.h" -#include "LEAmDNS2_Priv.h" namespace esp8266 { -/* - LEAmDNS -*/ + + namespace experimental { -/** + +/* + RECEIVING + */ /* - MDNSResponder::clsHost::_parseMessage + clsLEAmDNS2_Host::_parseMessage + */ -bool MDNSResponder::clsHost::_parseMessage(void) +bool clsLEAMDNSHost::_parseMessage(void) { DEBUG_EX_INFO( unsigned long ulStartTime = millis(); unsigned uStartMemory = ESP.getFreeHeap(); DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage (Time: %lu ms, heap: %u bytes, from %s, to %s)\n"), _DH(), ulStartTime, uStartMemory, - m_rUDPContext.getRemoteAddress().toString().c_str(), - m_rUDPContext.getDestAddress().toString().c_str()); + m_pUDPContext->getRemoteAddress().toString().c_str(), + m_pUDPContext->getDestAddress().toString().c_str()); ); //DEBUG_EX_INFO(_udpDump();); bool bResult = false; - stcMsgHeader header; + clsMsgHeader header; if (_readMDNSMsgHeader(header)) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), @@ -81,15 +68,18 @@ bool MDNSResponder::clsHost::_parseMessage(void) (unsigned)header.m_u16ANCount, (unsigned)header.m_u16NSCount, (unsigned)header.m_u16ARCount)); - if (0 == header.m_4bOpcode) // A standard query + if (0 == header.m_4bOpcode) { - if (header.m_1bQR) // Received a response -> answers to a query + // A standard query + if (header.m_1bQR) { + // Received a response -> answers to a query //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Reading answers: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), _DH(), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); bResult = _parseResponse(header); } - else // Received a query (Questions) + else { + // Received a query (Questions) //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Reading query: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), _DH(), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); bResult = _parseQuery(header); } @@ -97,13 +87,13 @@ bool MDNSResponder::clsHost::_parseMessage(void) else { DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Received UNEXPECTED opcode:%u. Ignoring message!\n"), _DH(), header.m_4bOpcode);); - m_rUDPContext.flush(); + m_pUDPContext->flush(); } } else { DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: FAILED to read header\n"), _DH());); - m_rUDPContext.flush(); + m_pUDPContext->flush(); } DEBUG_EX_INFO( unsigned uFreeHeap = ESP.getFreeHeap(); @@ -113,7 +103,7 @@ bool MDNSResponder::clsHost::_parseMessage(void) } /* - MDNSResponder::clsHost::_parseQuery + clsLEAmDNS2_Host::_parseQuery Queries are of interest in two cases: 1. allow for tiebreaking while probing in the case of a race condition between two instances probing for @@ -127,17 +117,17 @@ bool MDNSResponder::clsHost::_parseMessage(void) As any mDNS responder should be able to handle 'legacy' queries (from DNS clients), this case is handled here also. Legacy queries have got only one (unicast) question and are directed to the local DNS port (not the multicast port). - 1. */ -bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHeader& p_MsgHeader) +bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader) { bool bResult = true; - stcSendParameter sendParameter; - uint32_t u32HostOrServiceReplies = 0; + clsSendParameter sendParameter; + uint32_t u32HostOrServiceReplies = 0; + bool bHostOrServiceTiebreakNeeded = false; for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) { - stcRRQuestion questionRR; + clsRRQuestion questionRR; if ((bResult = _readRRQuestion(questionRR))) { // Define host replies, BUT only answer queries after probing is done @@ -148,26 +138,28 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea DEBUG_EX_INFO(if (u32HostOrServiceReplies) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Host reply needed %s\n"), _DH(), _replyFlags2String(u32HostOrServiceReplies));); // Check tiebreak need for host domain - if (enuProbingStatus::InProgress == m_HostProbeInformation.m_ProbingStatus) + if (clsProbeInformation_Base::clsProbeInformation_Base::enuProbingStatus::InProgress == m_ProbeInformation.m_ProbingStatus) { bool bFullNameMatch = false; if ((_replyMaskForHost(questionRR.m_Header, &bFullNameMatch)) && (bFullNameMatch)) { // We're in 'probing' state and someone is asking for our host domain: this might be - // a race-condition: Two host with the same domain names try simutanously to probe their domains + // a race-condition: Two hosts with the same domain names try simutanously to probe their domains // See: RFC 6762, 8.2 (Tiebraking) // However, we're using a max. reduced approach for tiebreaking here: The higher IP-address wins! DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Possible race-condition for host domain detected while probing.\n"), _DH());); - Serial.printf_P(PSTR("%s _parseQuery: Possible race-condition for host domain detected while probing.\n"), _DH()); - m_HostProbeInformation.m_bTiebreakNeeded = true; + bHostOrServiceTiebreakNeeded = + m_ProbeInformation.m_bTiebreakNeeded = true; } } // Define service replies - for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) { + clsService* pService = *it; + // Define service replies, BUT only answer queries after probing is done uint32_t u32ReplyMaskForQuestion = ((pService->probeStatus()) ? _replyMaskForService(questionRR.m_Header, *pService, 0) @@ -176,7 +168,7 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea DEBUG_EX_INFO(if (u32ReplyMaskForQuestion) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service reply needed: %s\n"), _DH(pService), _replyFlags2String(u32ReplyMaskForQuestion));); // Check tiebreak need for service domain - if (enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) + if (clsProbeInformation_Base::clsProbeInformation_Base::enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) { bool bFullNameMatch = false; if ((_replyMaskForService(questionRR.m_Header, *pService, &bFullNameMatch)) && @@ -187,26 +179,25 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea // See: RFC 6762, 8.2 (Tiebraking) // However, we're using a max. reduced approach for tiebreaking here: The 'higher' SRV host wins! DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Possible race-condition for service domain detected while probing.\n"), _DH(pService));); - Serial.printf_P(PSTR("%s _parseQuery: Possible race-condition for service domain detected while probing.\n"), _DH(pService)); - pService->m_ProbeInformation.m_bTiebreakNeeded = true; + bHostOrServiceTiebreakNeeded = + pService->m_ProbeInformation.m_bTiebreakNeeded = true; } } } // Handle unicast and legacy specialities // If only one question asks for unicast reply, the whole reply packet is send unicast - if (((DNS_MQUERY_PORT != m_rUDPContext.getRemotePort()) || // Unicast (maybe legacy) query OR + if (((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) || // Unicast (maybe legacy) query OR (questionRR.m_bUnicast)) && // Expressivly unicast query (!sendParameter.m_bUnicast)) { - sendParameter.m_bUnicast = true; //sendParameter.m_bCacheFlush = false; - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Unicast response asked for %s!\n"), _DH(), m_rUDPContext.getRemoteAddress().toString().c_str());); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Unicast response asked for %s!\n"), _DH(), m_pUDPContext->getRemoteAddress().toString().c_str());); //Serial.printf_P(PSTR("%s _parseQuery: Ignored Unicast response asked for by %s!\n"), _DH(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()); - if ((DNS_MQUERY_PORT != m_rUDPContext.getRemotePort()) && // Unicast (maybe legacy) query AND + if ((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) && // Unicast (maybe legacy) query AND (1 == p_MsgHeader.m_u16QDCount) && // Only one question AND ((sendParameter.m_u32HostReplyMask) || // Host replies OR (u32HostOrServiceReplies))) // Host or service replies available @@ -217,22 +208,23 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea #ifdef MDNS_IPV4_SUPPORT ip_info IPInfo_Local; #endif - if ( + if ((m_pNetIf) && + (m_pUDPContext) && #ifdef MDNS_IPV4_SUPPORT - (m_rUDPContext.getRemoteAddress().isV4()) && - ((wifi_get_ip_info(netif_get_index(&m_rNetIf), &IPInfo_Local))) && - (ip4_addr_netcmp(ip_2_ip4((const ip_addr_t*)m_rUDPContext.getRemoteAddress()), &IPInfo_Local.ip, &IPInfo_Local.netmask)) + (m_pUDPContext->getRemoteAddress().isV4()) && + ((wifi_get_ip_info(netif_get_index(m_pNetIf), &IPInfo_Local))) && + (ip4_addr_netcmp(ip_2_ip4((const ip_addr_t*)m_pUDPContext->getRemoteAddress()), &IPInfo_Local.ip, &IPInfo_Local.netmask)) #else (true) #endif && #ifdef MDNS_IPV6_SUPPORT - (m_rUDPContext.getRemoteAddress().isV6()) && - (ip6_addr_islinklocal(ip_2_ip6((const ip_addr_t*)m_rUDPContext.getRemoteAddress()))) + (m_pUDPContext->getRemoteAddress().isV6()) && + (ip6_addr_islinklocal(ip_2_ip6((const ip_addr_t*)m_pUDPContext->getRemoteAddress()))) #else (true) #endif - ) + ) { /* ip_info IPInfo_Local; ip_info IPInfo_Remote; @@ -243,27 +235,29 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))))) // Remote IP in STATION's subnet {*/ Serial.println("\n\n\nUNICAST QUERY\n\n"); - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Legacy query from local host %s!\n"), _DH(), m_rUDPContext.getRemoteAddress().toString().c_str());); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Legacy DNS query from local host %s!\n"), _DH(), m_pUDPContext->getRemoteAddress().toString().c_str());); sendParameter.m_u16ID = p_MsgHeader.m_u16ID; - sendParameter.m_bLegacyQuery = true; + sendParameter.m_bLegacyDNSQuery = true; sendParameter.m_bCacheFlush = false; - sendParameter.m_pQuestions = new stcRRQuestion; - if ((bResult = (0 != sendParameter.m_pQuestions))) + clsRRQuestion* pNewRRQuestion = new clsRRQuestion; + if (pNewRRQuestion) { - sendParameter.m_pQuestions->m_Header.m_Domain = questionRR.m_Header.m_Domain; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = questionRR.m_Header.m_Attributes.m_u16Type; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = questionRR.m_Header.m_Attributes.m_u16Class; + pNewRRQuestion->m_Header.m_Domain = questionRR.m_Header.m_Domain; + pNewRRQuestion->m_Header.m_Attributes.m_u16Type = questionRR.m_Header.m_Attributes.m_u16Type; + pNewRRQuestion->m_Header.m_Attributes.m_u16Class = questionRR.m_Header.m_Attributes.m_u16Class; + + sendParameter.m_RRQuestions.push_back(pNewRRQuestion); } else { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED to add legacy question!\n"), _DH());); + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED to add legacy DNS question!\n"), _DH());); } } else { - Serial.println("\n\n\nINVALID UNICAST QUERY\n\n"); - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Legacy query from NON-LOCAL host!\n"), _DH());); + Serial.printf("\n\n\nINVALID UNICAST QUERY from %s\n\n\n", m_pUDPContext->getRemoteAddress().toString().c_str()); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Legacy DNS query from NON-LOCAL host at %s!\n"), _DH(), m_pUDPContext->getRemoteAddress().toString().c_str());); bResult = false; } } @@ -276,30 +270,31 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea } // for questions //DEBUG_EX_INFO(if (u8HostOrServiceReplies) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Reply needed: %u (%s: %s->%s)\n"), _DH(), u8HostOrServiceReplies, clsTimeSyncer::timestr(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), IPAddress(m_pUDPContext->getDestAddress()).toString().c_str());); + //bHostOrServiceTiebreakNeeded = false; // Handle known answers uint32_t u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); - if ((u32HostOrServiceReplies) && + if (((u32HostOrServiceReplies) || + (bHostOrServiceTiebreakNeeded)) && (u32Answers)) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Reading known answers(%u):\n"), _DH(), u32Answers);); for (uint32_t an = 0; ((bResult) && (an < u32Answers)); ++an) { - stcRRAnswer* pKnownRRAnswer = 0; + clsRRAnswer* pKnownRRAnswer = 0; if (((bResult = _readRRAnswer(pKnownRRAnswer))) && (pKnownRRAnswer)) { - if ((DNS_RRTYPE_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Type) && // No ANY type answer (DNS_RRCLASS_ANY != (pKnownRRAnswer->m_Header.m_Attributes.m_u16Class & (~0x8000)))) // No ANY class answer { - - // Find match between planned answer (sendParameter.m_u8HostReplyMask) and this 'known answer' - uint32_t u32HostMatchMask = (sendParameter.m_u32HostReplyMask & _replyMaskForHost(pKnownRRAnswer->m_Header)); - if ((u32HostMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND - ((MDNS_HOST_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new host TTL (120s) - { + /* - RFC6762 7.1 Suppression only for 'Shared Records' - + // Find match between planned answer (sendParameter.m_u8HostReplyMask) and this 'known answer' + uint32_t u32HostMatchMask = (sendParameter.m_u32HostReplyMask & _replyMaskForHost(pKnownRRAnswer->m_Header)); + if ((u32HostMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND + ((Consts::u32HostTTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new host TTL (120s) + { // Compare contents if (enuAnswerType::PTR == pKnownRRAnswer->answerType()) @@ -309,41 +304,41 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea (((stcRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain == hostDomain)) { // Host domain match -#ifdef MDNS_IPV4_SUPPORT + #ifdef MDNS_IPV4_SUPPORT if (u32HostMatchMask & static_cast(enuContentFlag::PTR_IPv4)) { // IPv4 PTR was asked for, but is already known -> skipping - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv4 PTR already known... skipping!\n"), _DH());); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv4 PTR already known (TTL:%u)... skipping!\n"), _DH(), pKnownRRAnswer->m_u32TTL);); sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::PTR_IPv4); } -#endif -#ifdef MDNS_IPV6_SUPPORT + #endif + #ifdef MDNS_IPV6_SUPPORT if (u32HostMatchMask & static_cast(enuContentFlag::PTR_IPv6)) { // IPv6 PTR was asked for, but is already known -> skipping - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv6 PTR already known... skipping!\n"), _DH());); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv6 PTR already known (TTL:%u)... skipping!\n"), _DH(), pKnownRRAnswer->m_u32TTL);); sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::PTR_IPv6); } -#endif + #endif } } else if (u32HostMatchMask & static_cast(enuContentFlag::A)) { // IPv4 address was asked for -#ifdef MDNS_IPV4_SUPPORT + #ifdef MDNS_IPV4_SUPPORT if ((enuAnswerType::A == pKnownRRAnswer->answerType()) && (((stcRRAnswerA*)pKnownRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V4))) { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv4 address already known... skipping!\n"), _DH());); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv4 address already known (TTL:%u)... skipping!\n"), _DH(), pKnownRRAnswer->m_u32TTL);); sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::A); } // else: RData NOT IPv4 length !! -#endif + #endif } else if (u32HostMatchMask & static_cast(enuContentFlag::AAAA)) { // IPv6 address was asked for -#ifdef MDNS_IPV6_SUPPORT + #ifdef MDNS_IPV6_SUPPORT if ((enuAnswerType::AAAA == pKnownRRAnswer->answerType()) && (((stcRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V6))) { @@ -351,15 +346,16 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv6 address already known... skipping!\n"), _DH());); sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::AAAA); } // else: RData NOT IPv6 length !! -#endif + #endif } - } // Host match /*and TTL*/ + } // Host match and TTL + */ // // Check host tiebreak possibility - if (m_HostProbeInformation.m_bTiebreakNeeded) + if (m_ProbeInformation.m_bTiebreakNeeded) { - stcRRDomain hostDomain; + clsRRDomain hostDomain; if ((_buildDomainForHost(m_pcHostName, hostDomain)) && (pKnownRRAnswer->m_Header.m_Domain == hostDomain)) { @@ -369,26 +365,26 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea { // CHECK IPAddress localIPAddress(_getResponderIPAddress(enuIPProtocolType::V4)); - if (((stcRRAnswerA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) + if (((clsRRAnswerA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) { // SAME IP address -> We've received an old message from ourselfs (same IP) DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) WON (was an old message)!\n"), _DH());); - m_HostProbeInformation.m_bTiebreakNeeded = false; + m_ProbeInformation.m_bTiebreakNeeded = false; } else { - if ((uint32_t)(((stcRRAnswerA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST + if ((uint32_t)(((clsRRAnswerA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST { // LOST tiebreak - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) LOST (lower)!\n"), _DH());); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) LOST (lower IPv4)!\n"), _DH());); _cancelProbingForHost(); - m_HostProbeInformation.m_bTiebreakNeeded = false; + m_ProbeInformation.m_bTiebreakNeeded = false; } - else // WON tiebreak + else { - //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) WON (higher IP)!\n"), _DH());); - m_HostProbeInformation.m_bTiebreakNeeded = false; + // WON tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) WON (higher IPv4)!\n"), _DH());); + m_ProbeInformation.m_bTiebreakNeeded = false; } } } @@ -396,28 +392,28 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea #ifdef MDNS_IPV6_SUPPORT if (enuAnswerType::AAAA == pKnownRRAnswer->answerType()) { - // TODO / CHECK IPAddress localIPAddress(_getResponderIPAddress(enuIPProtocolType::V6)); - if (((stcRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) + if (((clsRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) { // SAME IP address -> We've received an old message from ourselfs (same IP) DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) WON (was an old message)!\n"), _DH());); - m_HostProbeInformation.m_bTiebreakNeeded = false; + m_ProbeInformation.m_bTiebreakNeeded = false; } else { - if ((uint32_t)(((stcRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST + // memcmp delivers >0 (positive) if the first non-matching byte in A is higher than in B + if (0 < memcmp((((clsRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress).raw6(), localIPAddress.raw6(), clsConsts::u16IPv6Size)) // The OTHER IP is 'higher' -> LOST { // LOST tiebreak - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) LOST (lower)!\n"), _DH());); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) LOST (lower IPv6)!\n"), _DH());); _cancelProbingForHost(); - m_HostProbeInformation.m_bTiebreakNeeded = false; + m_ProbeInformation.m_bTiebreakNeeded = false; } - else // WON tiebreak + else { - //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) WON (higher IP)!\n"), _DH());); - m_HostProbeInformation.m_bTiebreakNeeded = false; + // WON tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) WON (higher IPv6)!\n"), _DH());); + m_ProbeInformation.m_bTiebreakNeeded = false; } } } @@ -426,97 +422,98 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea } // Host tiebreak possibility // Check service answers - for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) { + clsService* pService = *it; uint32_t u32ServiceMatchMask = (pService->m_u32ReplyMask & _replyMaskForService(pKnownRRAnswer->m_Header, *pService)); if ((u32ServiceMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND - ((MDNS_SERVICE_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) + ((clsConsts::u32ServiceTTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) { - if (enuAnswerType::PTR == pKnownRRAnswer->answerType()) { - stcRRDomain serviceDomain; + clsRRDomain serviceDomain; if ((u32ServiceMatchMask & static_cast(enuContentFlag::PTR_TYPE)) && (_buildDomainForService(*pService, false, serviceDomain)) && - (serviceDomain == ((stcRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + (serviceDomain == ((clsRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service type PTR already known... skipping!\n"), _DH());); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service type PTR already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::PTR_TYPE); } if ((u32ServiceMatchMask & static_cast(enuContentFlag::PTR_NAME)) && (_buildDomainForService(*pService, true, serviceDomain)) && - (serviceDomain == ((stcRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + (serviceDomain == ((clsRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service name PTR already known... skipping!\n"), _DH());); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service name PTR already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::PTR_NAME); } } - else if (u32ServiceMatchMask & static_cast(enuContentFlag::SRV)) - { - DEBUG_EX_ERR(if (enuAnswerType::SRV != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: ERROR! INVALID answer type (SRV)!\n"), _DH());); + /* - RFC6762 7.1 Suppression only for 'Shared Records' + else if (u32ServiceMatchMask & static_cast(enuContentFlag::SRV)) + { + DEBUG_EX_ERR(if (enuAnswerType::SRV != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: ERROR! INVALID answer type (SRV)!\n"), _DH(pService));); stcRRDomain hostDomain; if ((_buildDomainForHost(m_pcHostName, hostDomain)) && (hostDomain == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match { - if ((MDNS_SRV_PRIORITY == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Priority) && - (MDNS_SRV_WEIGHT == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Weight) && + if ((Consts::u16SRVPriority == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Priority) && + (Consts::u16SRVWeight == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Weight) && (pService->m_u16Port == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Port)) { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service SRV answer already known... skipping!\n"), _DH());); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service SRV answer already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::SRV); } // else: Small differences -> send update message } - } - else if (u32ServiceMatchMask & static_cast(enuContentFlag::TXT)) - { - DEBUG_EX_ERR(if (enuAnswerType::TXT != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: ERROR! INVALID answer type (TXT)!\n"), _DH());); + }*/ + /* - RFC6762 7.1 Suppression only for 'Shared Records' + else if (u32ServiceMatchMask & static_cast(enuContentFlag::TXT)) + { + DEBUG_EX_ERR(if (enuAnswerType::TXT != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: ERROR! INVALID answer type (TXT)!\n"), _DH(pService));); _collectServiceTxts(*pService); if (pService->m_Txts == ((stcRRAnswerTXT*)pKnownRRAnswer)->m_Txts) { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service TXT answer already known... skipping!\n"), _DH());); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service TXT answer already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::TXT); } _releaseTempServiceTxts(*pService); - } + }*/ } // Service match and enough TTL // // Check service tiebreak possibility if (pService->m_ProbeInformation.m_bTiebreakNeeded) { - stcRRDomain serviceDomain; + clsRRDomain serviceDomain; if ((_buildDomainForService(*pService, true, serviceDomain)) && (pKnownRRAnswer->m_Header.m_Domain == serviceDomain)) { // Service domain match if (enuAnswerType::SRV == pKnownRRAnswer->answerType()) { - stcRRDomain hostDomain; + clsRRDomain hostDomain; if ((_buildDomainForHost(m_pcHostName, hostDomain)) && - (hostDomain == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + (hostDomain == ((clsRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match { - // We've received an old message from ourselfs (same SRV) - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) won (was an old message)!\n"), _DH());); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) won (was an old message)!\n"), _DH(pService));); pService->m_ProbeInformation.m_bTiebreakNeeded = false; } else { - if (((stcRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain > hostDomain) // The OTHER domain is 'higher' -> LOST + if (((clsRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain > hostDomain) // The OTHER domain is 'higher' -> LOST { // LOST tiebreak - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) LOST (lower)!\n"), _DH());); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) LOST (lower)!\n"), _DH(pService));); _cancelProbingForService(*pService); pService->m_ProbeInformation.m_bTiebreakNeeded = false; } - else // WON tiebreak + else { - //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) won (higher)!\n"), _DH());); + // WON tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) won (higher)!\n"), _DH(pService));); pService->m_ProbeInformation.m_bTiebreakNeeded = false; } } @@ -541,48 +538,47 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea else { DEBUG_EX_INFO(if (u32Answers) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Skipped %u known answers!\n"), _DH(), u32Answers);); - m_rUDPContext.flush(); + m_pUDPContext->flush(); } if (bResult) { // Check, if a reply is needed uint32_t u32ReplyNeeded = sendParameter.m_u32HostReplyMask; - for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + for (const clsService* pService : m_Services) { u32ReplyNeeded |= pService->m_u32ReplyMask; } if (u32ReplyNeeded) { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Sending answer(%s)...\n"), _DH(), _replyFlags2String(u32ReplyNeeded));); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Sending %s answer(%s)...\n"), _DH(), (sendParameter.m_bUnicast ? "UC" : "MC"), _replyFlags2String(u32ReplyNeeded));); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Sending %s answer(%s)...\n"), _DH(), (sendParameter.m_bUnicast ? "UC" : "MC"), _replyFlags2String(u32ReplyNeeded));); - sendParameter.m_Response = stcSendParameter::enuResponseType::Response; + sendParameter.m_Response = clsSendParameter::enuResponseType::Response; sendParameter.m_bAuthorative = true; - bResult = _sendMDNSMessage(sendParameter); + bResult = _sendMessage(sendParameter); } - DEBUG_EX_INFO( - else + DEBUG_EX_INFO(else { DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: No reply needed\n"), _DH()); - } - ); + }); } else { DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Something FAILED!\n"), _DH());); - m_rUDPContext.flush(); + m_pUDPContext->flush(); } // // Check and reset tiebreak-states - if (m_HostProbeInformation.m_bTiebreakNeeded) + if (m_ProbeInformation.m_bTiebreakNeeded) { DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: UNSOLVED tiebreak-need for host domain!\n"), _DH());); - m_HostProbeInformation.m_bTiebreakNeeded = false; + m_ProbeInformation.m_bTiebreakNeeded = false; } - for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + for (clsService* pService : m_Services) { if (pService->m_ProbeInformation.m_bTiebreakNeeded) { @@ -595,7 +591,7 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea } /* - MDNSResponder::clsHost::_parseResponse + clsLEAmDNS2_Host::_parseResponse Responses are of interest in two cases: 1. find domain name conflicts while probing @@ -621,7 +617,7 @@ bool MDNSResponder::clsHost::_parseQuery(const MDNSResponder::clsHost::stcMsgHea TXT - links the instance name to services TXTs Level 3: A/AAAA - links the host domain to an IP address */ -bool MDNSResponder::clsHost::_parseResponse(const MDNSResponder::clsHost::stcMsgHeader& p_MsgHeader) +bool clsLEAMDNSHost::_parseResponse(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse\n"));); //DEBUG_EX_INFO(_udpDump();); @@ -632,7 +628,6 @@ bool MDNSResponder::clsHost::_parseResponse(const MDNSResponder::clsHost::stcMsg if ((_hasQueriesWaitingForAnswers()) || // Waiting for query answers OR (_hasProbesWaitingForAnswers())) // Probe responses { - DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received a response\n"), _DH()); //_udpDump(); @@ -641,7 +636,7 @@ bool MDNSResponder::clsHost::_parseResponse(const MDNSResponder::clsHost::stcMsg bResult = true; // // Ignore questions here - stcRRQuestion dummyRRQ; + clsRRQuestion dummyRRQ; for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received a response containing a question... ignoring!\n"), _DH());); @@ -650,11 +645,11 @@ bool MDNSResponder::clsHost::_parseResponse(const MDNSResponder::clsHost::stcMsg // // Read and collect answers - stcRRAnswer* pCollectedRRAnswers = 0; + clsRRAnswer* pCollectedRRAnswers = 0; uint32_t u32NumberOfAnswerRRs = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); for (uint32_t an = 0; ((bResult) && (an < u32NumberOfAnswerRRs)); ++an) { - stcRRAnswer* pRRAnswer = 0; + clsRRAnswer* pRRAnswer = 0; if (((bResult = _readRRAnswer(pRRAnswer))) && (pRRAnswer)) { @@ -684,14 +679,14 @@ bool MDNSResponder::clsHost::_parseResponse(const MDNSResponder::clsHost::stcMsg else // Some failure while reading answers { DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: FAILED to read answers!\n"), _DH());); - m_rUDPContext.flush(); + m_pUDPContext->flush(); } // Delete collected answers while (pCollectedRRAnswers) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: DELETING answer!\n"), _DH());); - stcRRAnswer* pNextAnswer = pCollectedRRAnswers->m_pNext; + clsRRAnswer* pNextAnswer = pCollectedRRAnswers->m_pNext; delete pCollectedRRAnswers; pCollectedRRAnswers = pNextAnswer; } @@ -719,7 +714,7 @@ bool MDNSResponder::clsHost::_parseResponse(const MDNSResponder::clsHost::stcMsg } */ ); - m_rUDPContext.flush(); + m_pUDPContext->flush(); bResult = true; } DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: FAILED!\n"), _DH());); @@ -727,7 +722,7 @@ bool MDNSResponder::clsHost::_parseResponse(const MDNSResponder::clsHost::stcMsg } /* - MDNSResponder::clsHost::_processAnswers + clsLEAmDNS2_Host::_processAnswers Host: A (0x01): eg. esp8266.local A OP TTL 123.456.789.012 AAAA (01Cx): eg. esp8266.local AAAA OP TTL 1234:5678::90 @@ -740,7 +735,7 @@ bool MDNSResponder::clsHost::_parseResponse(const MDNSResponder::clsHost::stcMsg TXT (0x10): eg. MyESP._http._tcp.local TXT OP TTL c#=1 */ -bool MDNSResponder::clsHost::_processAnswers(const MDNSResponder::clsHost::stcRRAnswer* p_pAnswers) +bool clsLEAMDNSHost::_processAnswers(const clsLEAMDNSHost::clsRRAnswer* p_pAnswers) { bool bResult = false; @@ -756,78 +751,70 @@ bool MDNSResponder::clsHost::_processAnswers(const MDNSResponder::clsHost::stcRR { bFoundNewKeyAnswer = false; - const stcRRAnswer* pRRAnswer = p_pAnswers; + const clsRRAnswer* pRRAnswer = p_pAnswers; while ((pRRAnswer) && (bResult)) { // 1. level answer (PTR) if (enuAnswerType::PTR == pRRAnswer->answerType()) - { - // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local - bResult = _processPTRAnswer((stcRRAnswerPTR*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new SRV or TXT answers to be linked to queries + { // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + bResult = _processPTRAnswer((clsRRAnswerPTR*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new SRV or TXT answers to be linked to queries } // 2. level answers // SRV -> host domain and port else if (enuAnswerType::SRV == pRRAnswer->answerType()) - { - // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local - bResult = _processSRVAnswer((stcRRAnswerSRV*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new A/AAAA answers to be linked to queries + { // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + bResult = _processSRVAnswer((clsRRAnswerSRV*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new A/AAAA answers to be linked to queries } // TXT -> Txts else if (enuAnswerType::TXT == pRRAnswer->answerType()) - { - // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 - bResult = _processTXTAnswer((stcRRAnswerTXT*)pRRAnswer); + { // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 + bResult = _processTXTAnswer((clsRRAnswerTXT*)pRRAnswer); } // 3. level answers #ifdef MDNS_IPV4_SUPPORT // A -> IPv4Address else if (enuAnswerType::A == pRRAnswer->answerType()) - { - // eg. esp8266.local A xxxx xx 192.168.2.120 - bResult = _processAAnswer((stcRRAnswerA*)pRRAnswer); + { // eg. esp8266.local A xxxx xx 192.168.2.120 + bResult = _processAAnswer((clsRRAnswerA*)pRRAnswer); } #endif #ifdef MDNS_IPV6_SUPPORT // AAAA -> IPv6Address else if (enuAnswerType::AAAA == pRRAnswer->answerType()) - { - // eg. esp8266.local AAAA xxxx xx 09cf::0c - bResult = _processAAAAAnswer((stcRRAnswerAAAA*)pRRAnswer); + { // eg. esp8266.local AAAA xxxx xx 09cf::0c + bResult = _processAAAAAnswer((clsRRAnswerAAAA*)pRRAnswer); } #endif // Finally check for probing conflicts // Host domain - if ((enuProbingStatus::InProgress == m_HostProbeInformation.m_ProbingStatus) && + if ((clsProbeInformation_Base::enuProbingStatus::InProgress == m_ProbeInformation.m_ProbingStatus) && ((enuAnswerType::A == pRRAnswer->answerType()) || (enuAnswerType::AAAA == pRRAnswer->answerType()))) { - - stcRRDomain hostDomain; + clsRRDomain hostDomain; if ((_buildDomainForHost(m_pcHostName, hostDomain)) && (pRRAnswer->m_Header.m_Domain == hostDomain)) { - bool bPossibleEcho = false; #ifdef MDNS_IPV4_SUPPORT if ((enuAnswerType::A == pRRAnswer->answerType()) && - (((stcRRAnswerA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V4))) + (((clsRRAnswerA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V4))) { - bPossibleEcho = true; } #endif #ifdef MDNS_IPV6_SUPPORT if ((enuAnswerType::AAAA == pRRAnswer->answerType()) && - (((stcRRAnswerAAAA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V6))) + (((clsRRAnswerAAAA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V6))) { - bPossibleEcho = true; } #endif if (!bPossibleEcho) { + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s.local'\n"), _DH(), m_pcHostName);); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s.local'\n"), _DH(), m_pcHostName);); _cancelProbingForHost(); } @@ -838,19 +825,18 @@ bool MDNSResponder::clsHost::_processAnswers(const MDNSResponder::clsHost::stcRR } } // Service domains - for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + for (clsService* pService : m_Services) { - if ((enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && + if ((clsProbeInformation_Base::enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && ((enuAnswerType::TXT == pRRAnswer->answerType()) || (enuAnswerType::SRV == pRRAnswer->answerType()))) { - - stcRRDomain serviceDomain; + clsRRDomain serviceDomain; if ((_buildDomainForService(*pService, true, serviceDomain)) && (pRRAnswer->m_Header.m_Domain == serviceDomain)) { - // TODO: Echo management needed? + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s'\n"), _DH(), _service2String(pService));); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s'\n"), _DH(), _service2String(pService));); _cancelProbingForService(*pService); } @@ -867,10 +853,10 @@ bool MDNSResponder::clsHost::_processAnswers(const MDNSResponder::clsHost::stcRR } /* - MDNSResponder::clsHost::_processPTRAnswer (level 1) + clsLEAmDNS2_Host::_processPTRAnswer (level 1) */ -bool MDNSResponder::clsHost::_processPTRAnswer(const MDNSResponder::clsHost::stcRRAnswerPTR* p_pPTRAnswer, - bool& p_rbFoundNewKeyAnswer) +bool clsLEAMDNSHost::_processPTRAnswer(const clsLEAMDNSHost::clsRRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer) { bool bResult = false; @@ -880,17 +866,16 @@ bool MDNSResponder::clsHost::_processPTRAnswer(const MDNSResponder::clsHost::stc // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local // Check pending service queries for eg. '_http._tcp' - stcQuery* pQuery = _findNextQueryByDomain(p_pPTRAnswer->m_Header.m_Domain, stcQuery::enuQueryType::Service, 0); + clsQuery* pQuery = _findNextQueryByDomain(p_pPTRAnswer->m_Header.m_Domain, clsQuery::enuQueryType::Service, 0); while (pQuery) { if (pQuery->m_bAwaitingAnswers) - { - // Find answer for service domain (eg. MyESP._http._tcp.local) - stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pPTRAnswer->m_PTRDomain); - if (pSQAnswer) // existing answer - { - if (p_pPTRAnswer->m_u32TTL) // Received update message - { + { // Find answer for service domain (eg. MyESP._http._tcp.local) + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pPTRAnswer->m_PTRDomain); + if (pSQAnswer) + { // existing answer + if (p_pPTRAnswer->m_u32TTL) + { // Received update message pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); // Update TTL tag DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: Updated TTL(%lu) for "), _DH(), p_pPTRAnswer->m_u32TTL); @@ -898,8 +883,8 @@ bool MDNSResponder::clsHost::_processPTRAnswer(const MDNSResponder::clsHost::stc DEBUG_OUTPUT.printf_P(PSTR("\n")); ); } - else // received goodbye-message - { + else + { // received goodbye-message pSQAnswer->m_TTLServiceDomain.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: 'Goodbye' received for "), _DH()); @@ -908,11 +893,11 @@ bool MDNSResponder::clsHost::_processPTRAnswer(const MDNSResponder::clsHost::stc ); } } - else if ((p_pPTRAnswer->m_u32TTL) && // Not just a goodbye-message - ((pSQAnswer = new stcQuery::stcAnswer))) // Not yet included -> add answer + else if ((p_pPTRAnswer->m_u32TTL) && // Not just a goodbye-message + ((pSQAnswer = new clsQuery::clsAnswer))) // Not yet included -> add answer { pSQAnswer->m_ServiceDomain = p_pPTRAnswer->m_PTRDomain; - pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::ServiceDomain); + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain); pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); //pSQAnswer->releaseServiceDomain(); @@ -925,10 +910,10 @@ bool MDNSResponder::clsHost::_processPTRAnswer(const MDNSResponder::clsHost::stc ); p_rbFoundNewKeyAnswer = true; - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::ServiceDomain), true); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain), true); } } - pQuery = _findNextQueryByDomain(p_pPTRAnswer->m_Header.m_Domain, stcQuery::enuQueryType::Service, pQuery); + pQuery = _findNextQueryByDomain(p_pPTRAnswer->m_Header.m_Domain, clsQuery::enuQueryType::Service, pQuery); } } // else: No p_pPTRAnswer DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: FAILED!\n"), _DH());); @@ -936,27 +921,28 @@ bool MDNSResponder::clsHost::_processPTRAnswer(const MDNSResponder::clsHost::stc } /* - MDNSResponder::clsHost::_processSRVAnswer (level 2) + clsLEAmDNS2_Host::_processSRVAnswer (level 2) */ -bool MDNSResponder::clsHost::_processSRVAnswer(const MDNSResponder::clsHost::stcRRAnswerSRV* p_pSRVAnswer, - bool& p_rbFoundNewKeyAnswer) +bool clsLEAMDNSHost::_processSRVAnswer(const clsLEAMDNSHost::clsRRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer) { bool bResult = false; if ((bResult = (0 != p_pSRVAnswer))) { // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local - - stcQuery* pQuery = m_pQueries; - while (pQuery) + for (clsQuery::list::iterator it = m_Queries.begin(); ((bResult) && (it != m_Queries.end())); it++) { + clsQuery* pQuery = *it; + if (pQuery->m_bAwaitingAnswers) { - stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pSRVAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pSRVAnswer->m_Header.m_Domain); + if (pSQAnswer) { - if (p_pSRVAnswer->m_u32TTL) // First or update message (TTL != 0) - { + // Answer for this service domain (eg. MyESP._http._tcp.local) available + if (p_pSRVAnswer->m_u32TTL) + { // First or update message (TTL != 0) pSQAnswer->m_TTLHostDomainAndPort.set(p_pSRVAnswer->m_u32TTL); // Update TTL tag DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: Updated TTL(%lu) for "), _DH(), p_pSRVAnswer->m_u32TTL); @@ -971,7 +957,7 @@ bool MDNSResponder::clsHost::_processSRVAnswer(const MDNSResponder::clsHost::stc pSQAnswer->m_HostDomain = p_pSRVAnswer->m_SRVDomain; //pSQAnswer->releaseHostDomain(); pSQAnswer->m_u16Port = p_pSRVAnswer->m_u16Port; - pSQAnswer->m_QueryAnswerFlags |= (static_cast(enuQueryAnswerType::HostDomain) | static_cast(enuQueryAnswerType::Port)); + pSQAnswer->m_QueryAnswerFlags |= (static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain) | static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Port)); DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processSVRAnswer: Added host domain and port to "), _DH()); @@ -982,11 +968,11 @@ bool MDNSResponder::clsHost::_processSRVAnswer(const MDNSResponder::clsHost::stc ); p_rbFoundNewKeyAnswer = true; - _executeQueryCallback(*pQuery, *pSQAnswer, (static_cast(enuQueryAnswerType::HostDomain) | static_cast(enuQueryAnswerType::Port)), true); + _executeQueryCallback(*pQuery, *pSQAnswer, (static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain) | static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Port)), true); } } - else // Goodby message - { + else + { // Goodby message pSQAnswer->m_TTLHostDomainAndPort.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: 'Goodbye' received for "), _DH()); @@ -996,34 +982,33 @@ bool MDNSResponder::clsHost::_processSRVAnswer(const MDNSResponder::clsHost::stc } } } // m_bAwaitingAnswers - pQuery = pQuery->m_pNext; - } // while(service query) + } // for(queries) } // else: No p_pSRVAnswer DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: FAILED!\n"), _DH());); return bResult; } /* - MDNSResponder::clsHost::_processTXTAnswer (level 2) + clsLEAmDNS2_Host::_processTXTAnswer (level 2) */ -bool MDNSResponder::clsHost::_processTXTAnswer(const MDNSResponder::clsHost::stcRRAnswerTXT* p_pTXTAnswer) +bool clsLEAMDNSHost::_processTXTAnswer(const clsLEAMDNSHost::clsRRAnswerTXT* p_pTXTAnswer) { bool bResult = false; if ((bResult = (0 != p_pTXTAnswer))) { // eg. MyESP._http._tcp.local TXT xxxx xx c#=1 - - stcQuery* pQuery = m_pQueries; - while (pQuery) + for (clsQuery::list::iterator it = m_Queries.begin(); ((bResult) && (it != m_Queries.end())); it++) { + clsQuery* pQuery = *it; + if (pQuery->m_bAwaitingAnswers) { - stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pTXTAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available - { - if (p_pTXTAnswer->m_u32TTL) // First or update message - { + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pTXTAnswer->m_Header.m_Domain); + if (pSQAnswer) + { // Answer for this service domain (eg. MyESP._http._tcp.local) available + if (p_pTXTAnswer->m_u32TTL) + { // First or update message pSQAnswer->m_TTLTxts.set(p_pTXTAnswer->m_u32TTL); // Update TTL tag DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: Updated TTL(%lu) for "), _DH(), p_pTXTAnswer->m_u32TTL); @@ -1033,7 +1018,7 @@ bool MDNSResponder::clsHost::_processTXTAnswer(const MDNSResponder::clsHost::stc if (!pSQAnswer->m_Txts.compare(p_pTXTAnswer->m_Txts)) { pSQAnswer->m_Txts = p_pTXTAnswer->m_Txts; - pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::Txts); + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts); //pSQAnswer->releaseTxts(); DEBUG_EX_INFO( @@ -1042,11 +1027,11 @@ bool MDNSResponder::clsHost::_processTXTAnswer(const MDNSResponder::clsHost::stc DEBUG_OUTPUT.println(); ); - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::Txts), true); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts), true); } } - else // Goodby message - { + else + { // Goodby message pSQAnswer->m_TTLTxts.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: 'Goodbye' received for "), _DH()); @@ -1056,8 +1041,7 @@ bool MDNSResponder::clsHost::_processTXTAnswer(const MDNSResponder::clsHost::stc } } } // m_bAwaitingAnswers - pQuery = pQuery->m_pNext; - } // while(service query) + } // for(queries) } // else: No p_pTXTAnswer DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: FAILED!\n"), _DH());); return bResult; @@ -1065,32 +1049,29 @@ bool MDNSResponder::clsHost::_processTXTAnswer(const MDNSResponder::clsHost::stc #ifdef MDNS_IPV4_SUPPORT /* - MDNSResponder::clsHost::_processAAnswer (level 3) + clsLEAmDNS2_Host::_processAAnswer (level 3) */ -bool MDNSResponder::clsHost::_processAAnswer(const MDNSResponder::clsHost::stcRRAnswerA* p_pAAnswer) +bool clsLEAMDNSHost::_processAAnswer(const clsLEAMDNSHost::clsRRAnswerA* p_pAAnswer) { bool bResult = false; if ((bResult = (0 != p_pAAnswer))) { // eg. esp8266.local A xxxx xx 192.168.2.120 - - stcQuery* pQuery = m_pQueries; - while (pQuery) + for (clsQuery::list::iterator it = m_Queries.begin(); ((bResult) && (it != m_Queries.end())); it++) { + clsQuery* pQuery = *it; + if (pQuery->m_bAwaitingAnswers) - { - // Look for answers to host queries - if ((p_pAAnswer->m_u32TTL) && // NOT just a goodbye message - (stcQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query - (pQuery->m_Domain == p_pAAnswer->m_Header.m_Domain)) // AND a matching host domain + { // Look for answers to host queries + if ((p_pAAnswer->m_u32TTL) && // NOT just a goodbye message + (clsQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query + (pQuery->m_Domain == p_pAAnswer->m_Header.m_Domain)) // AND a matching host domain { - - stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); if ((!pSQAnswer) && - ((pSQAnswer = new stcQuery::stcAnswer))) - { - // Add not yet included answer + ((pSQAnswer = new clsQuery::clsAnswer))) + { // Add not yet included answer pSQAnswer->m_HostDomain = p_pAAnswer->m_Header.m_Domain; //pSQAnswer->releaseHostDomain(); @@ -1101,21 +1082,20 @@ bool MDNSResponder::clsHost::_processAAnswer(const MDNSResponder::clsHost::stcRR DEBUG_OUTPUT.println(); ); - pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::HostDomain); - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::HostDomain), true); + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain), true); } } // Look for answers to service queries - stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available - { - stcQuery::stcAnswer::stcIPAddress* pIPAddress = pSQAnswer->findIPv4Address(p_pAAnswer->m_IPAddress); + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); + if (pSQAnswer) + { // Answer for this host domain (eg. esp8266.local) available + clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddress = pSQAnswer->findIPv4Address(p_pAAnswer->m_IPAddress); if (pIPAddress) - { - // Already known IPv4 address - if (p_pAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL - { + { // Already known IPv4 address + if (p_pAAnswer->m_u32TTL) + { // Valid TTL -> Update answers TTL pIPAddress->m_TTL.set(p_pAAnswer->m_u32TTL); DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Updated TTL(%lu) for "), _DH(), p_pAAnswer->m_u32TTL); @@ -1123,8 +1103,8 @@ bool MDNSResponder::clsHost::_processAAnswer(const MDNSResponder::clsHost::stcRR DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); ); } - else // 'Goodbye' message for known IPv4 address - { + else + { // 'Goodbye' message for known IPv4 address pIPAddress->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: 'Goodbye' received for "), _DH()); @@ -1134,23 +1114,21 @@ bool MDNSResponder::clsHost::_processAAnswer(const MDNSResponder::clsHost::stcRR } } else - { - // Until now unknown IPv4 address -> Add (if the message isn't just a 'Goodbye' note) - if (p_pAAnswer->m_u32TTL) // NOT just a 'Goodbye' message - { - pIPAddress = new stcQuery::stcAnswer::stcIPAddress(p_pAAnswer->m_IPAddress, p_pAAnswer->m_u32TTL); + { // Until now unknown IPv4 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAnswer->m_u32TTL) + { // NOT just a 'Goodbye' message + pIPAddress = new clsQuery::clsAnswer::clsIPAddressWithTTL(p_pAAnswer->m_IPAddress, p_pAAnswer->m_u32TTL); if ((pIPAddress) && (pSQAnswer->addIPv4Address(pIPAddress))) { - DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Added IPv4 address to "), _DH()); _printRRDomain(pSQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(": %s\n"), pIPAddress->m_IPAddress.toString().c_str()); ); - pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::IPv4Address); - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::IPv4Address), true); + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address), true); } else { @@ -1160,8 +1138,7 @@ bool MDNSResponder::clsHost::_processAAnswer(const MDNSResponder::clsHost::stcRR } } } // m_bAwaitingAnswers - pQuery = pQuery->m_pNext; - } // while(service query) + } // for(queries) } // else: No p_pAAnswer DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: FAILED!\n"), _DH());); return bResult; @@ -1170,32 +1147,29 @@ bool MDNSResponder::clsHost::_processAAnswer(const MDNSResponder::clsHost::stcRR #ifdef MDNS_IPV6_SUPPORT /* - MDNSResponder::clsHost::_processAAAAAnswer (level 3) + clsLEAmDNS2_Host::_processAAAAAnswer (level 3) */ -bool MDNSResponder::clsHost::_processAAAAAnswer(const MDNSResponder::clsHost::stcRRAnswerAAAA* p_pAAAAAnswer) +bool clsLEAMDNSHost::_processAAAAAnswer(const clsLEAMDNSHost::clsRRAnswerAAAA* p_pAAAAAnswer) { bool bResult = false; if ((bResult = (0 != p_pAAAAAnswer))) { // eg. esp8266.local AAAA xxxx xx 0bf3::0c - - stcQuery* pQuery = m_pQueries; - while (pQuery) + for (clsQuery::list::iterator it = m_Queries.begin(); ((bResult) && (it != m_Queries.end())); it++) { + clsQuery* pQuery = *it; + if (pQuery->m_bAwaitingAnswers) - { - // Look for answers to host queries - if ((p_pAAAAAnswer->m_u32TTL) && // NOT just a goodbye message - (stcQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query - (pQuery->m_Domain == p_pAAAAAnswer->m_Header.m_Domain)) // AND a matching host domain + { // Look for answers to host queries + if ((p_pAAAAAnswer->m_u32TTL) && // NOT just a goodbye message + (clsQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query + (pQuery->m_Domain == p_pAAAAAnswer->m_Header.m_Domain)) // AND a matching host domain { - - stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); if ((!pSQAnswer) && - ((pSQAnswer = new stcQuery::stcAnswer))) - { - // Add not yet included answer + ((pSQAnswer = new clsQuery::clsAnswer))) + { // Add not yet included answer pSQAnswer->m_HostDomain = p_pAAAAAnswer->m_Header.m_Domain; //pSQAnswer->releaseHostDomain(); @@ -1206,21 +1180,20 @@ bool MDNSResponder::clsHost::_processAAAAAnswer(const MDNSResponder::clsHost::st DEBUG_OUTPUT.println(); ); - pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::HostDomain); - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::HostDomain), true); + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain), true); } } // Look for answers to service queries - stcQuery::stcAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available { - stcQuery::stcAnswer::stcIPAddress* pIPAddress = pSQAnswer->findIPv6Address(p_pAAAAAnswer->m_IPAddress); + clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddress = pSQAnswer->findIPv6Address(p_pAAAAAnswer->m_IPAddress); if (pIPAddress) - { - // Already known IPv6 address - if (p_pAAAAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL - { + { // Already known IPv6 address + if (p_pAAAAAnswer->m_u32TTL) + { // Valid TTL -> Update answers TTL pIPAddress->m_TTL.set(p_pAAAAAnswer->m_u32TTL); DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Updated TTL(%lu) for "), _DH(), p_pAAAAAnswer->m_u32TTL); @@ -1228,8 +1201,8 @@ bool MDNSResponder::clsHost::_processAAAAAnswer(const MDNSResponder::clsHost::st DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); ); } - else // 'Goodbye' message for known IPv6 address - { + else + { // 'Goodbye' message for known IPv6 address pIPAddress->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: 'Goodbye' received for "), _DH()); @@ -1239,23 +1212,22 @@ bool MDNSResponder::clsHost::_processAAAAAnswer(const MDNSResponder::clsHost::st } } else - { - // Until now unknown IPv6 address -> Add (if the message isn't just a 'Goodbye' note) - if (p_pAAAAAnswer->m_u32TTL) // NOT just a 'Goodbye' message + { // Until now unknown IPv6 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAAAAnswer->m_u32TTL) { - pIPAddress = new stcQuery::stcAnswer::stcIPAddress(p_pAAAAAnswer->m_IPAddress, p_pAAAAAnswer->m_u32TTL); + // NOT just a 'Goodbye' message + pIPAddress = new clsQuery::clsAnswer::clsIPAddressWithTTL(p_pAAAAAnswer->m_IPAddress, p_pAAAAAnswer->m_u32TTL); if ((pIPAddress) && (pSQAnswer->addIPv6Address(pIPAddress))) { - DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Added IPv6 address to "), _DH()); _printRRDomain(pSQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(": %s\n"), pIPAddress->m_IPAddress.toString().c_str()); ); - pSQAnswer->m_QueryAnswerFlags |= static_cast(enuQueryAnswerType::IPv6Address); - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::IPv6Address), true); + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address), true); } else { @@ -1265,8 +1237,7 @@ bool MDNSResponder::clsHost::_processAAAAAnswer(const MDNSResponder::clsHost::st } } } // m_bAwaitingAnswers - pQuery = pQuery->m_pNext; - } // while(service query) + } // for(queries) } // else: No p_pAAAAAnswer return bResult; @@ -1275,11 +1246,13 @@ bool MDNSResponder::clsHost::_processAAAAAnswer(const MDNSResponder::clsHost::st /* + PROBING + */ /* - MDNSResponder::clsHost::_updateProbeStatus + clsLEAmDNS2_Host::_updateProbeStatus Manages the (outgoing) probing process. - If probing has not been started yet (ProbingStatus_NotStarted), the initial delay (see RFC 6762) is determined and @@ -1290,13 +1263,13 @@ bool MDNSResponder::clsHost::_processAAAAAnswer(const MDNSResponder::clsHost::st Conflict management is handled in '_parseResponse ff.' Tiebraking is handled in 'parseQuery ff.' */ -bool MDNSResponder::clsHost::_updateProbeStatus(void) +bool clsLEAMDNSHost::_updateProbeStatus(void) { bool bResult = true; // // Probe host domain - if ((enuProbingStatus::ReadyToStart == m_HostProbeInformation.m_ProbingStatus) && // Ready to get started AND + if ((clsProbeInformation_Base::enuProbingStatus::ReadyToStart == m_ProbeInformation.m_ProbingStatus) && // Ready to get started AND (( #ifdef MDNS_IPV4_SUPPORT _getResponderIPAddress(enuIPProtocolType::V4).isSet() // AND has IPv4 address @@ -1314,111 +1287,122 @@ bool MDNSResponder::clsHost::_updateProbeStatus(void) DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Starting host probing...\n"), _DH());); // First probe delay SHOULD be random 0-250 ms - m_HostProbeInformation.m_Timeout.reset(rand() % MDNS_PROBE_DELAY); - m_HostProbeInformation.m_ProbingStatus = enuProbingStatus::InProgress; + m_ProbeInformation.m_Timeout.reset(rand() % clsConsts::u32ProbeDelay); + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::InProgress; } - else if ((enuProbingStatus::InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing AND - (m_HostProbeInformation.m_Timeout.expired())) // Time for next probe + else if ((clsProbeInformation_Base::enuProbingStatus::InProgress == m_ProbeInformation.m_ProbingStatus) && // Probing AND + (m_ProbeInformation.m_Timeout.expired())) // Time for next probe { - - if (MDNS_PROBE_COUNT > m_HostProbeInformation.m_u8SentCount) // Send next probe + if (clsConsts::u32ProbeCount > m_ProbeInformation.m_u8SentCount) { + // Send next probe if ((bResult = _sendHostProbe())) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Did sent host probe for '%s.local'\n\n"), _DH(), (m_pcHostName ? : ""));); - m_HostProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); - ++m_HostProbeInformation.m_u8SentCount; + m_ProbeInformation.m_Timeout.reset(clsConsts::u32ProbeDelay); + ++m_ProbeInformation.m_u8SentCount; } } - else // Probing finished + else { + // Probing finished DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("\n%s _updateProbeStatus: Done host probing for '%s.local'.\n\n\n"), _DH(), (m_pcHostName ? : ""));); - m_HostProbeInformation.m_ProbingStatus = enuProbingStatus::Done; - m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce; + m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShot::neverExpires); _callHostProbeResultCallback(true); // Prepare to announce host - m_HostProbeInformation.m_u8SentCount = 0; - m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + m_ProbeInformation.m_u8SentCount = 0; + m_ProbeInformation.m_Timeout.reset(clsConsts::u32AnnounceDelay); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Prepared host announcing.\n\n"), _DH());); } } // else: Probing already finished OR waiting for next time slot - else if ((enuProbingStatus::Done == m_HostProbeInformation.m_ProbingStatus) && - (m_HostProbeInformation.m_Timeout.expired())) + else if ((clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == m_ProbeInformation.m_ProbingStatus) && + (m_ProbeInformation.m_Timeout.expired())) { - - if ((bResult = _announce(true, false))) // Don't announce services here + if ((bResult = _announce(true, false))) { - ++m_HostProbeInformation.m_u8SentCount; // 1.. + // Don't announce services here + ++m_ProbeInformation.m_u8SentCount; // 1.. - if (MDNS_ANNOUNCE_COUNT > m_HostProbeInformation.m_u8SentCount) + if (clsConsts::u32AnnounceCount > m_ProbeInformation.m_u8SentCount) { - m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY * pow(2, (m_HostProbeInformation.m_u8SentCount - 1))); // 2^(0..) -> 1, 2, 4, ... - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Announcing host '%s.local' (%lu).\n\n"), _DH(), (m_pcHostName ? : ""), m_HostProbeInformation.m_u8SentCount);); + m_ProbeInformation.m_Timeout.reset(clsConsts::u32AnnounceDelay * pow(2, (m_ProbeInformation.m_u8SentCount - 1))); // 2^(0..) -> 1, 2, 4, ... + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Announcing host '%s.local' (%lu).\n\n"), _DH(), (m_pcHostName ? : ""), m_ProbeInformation.m_u8SentCount);); } else { - m_HostProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::DoneFinally; + m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShot::neverExpires); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done host announcing for '%s.local'.\n"), _DH(), (m_pcHostName ? : ""));); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done host announcing for '%s.local'.\n\n"), _DH(), (m_pcHostName ? : ""));); + //DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done host announcing for '%s.local'.\n"), _DH(), (m_pcHostName ? : "")); } } } // // Probe services - for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) { - if (enuProbingStatus::ReadyToStart == pService->m_ProbeInformation.m_ProbingStatus) // Ready to get started - { + clsService* pService = *it; - pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); // More or equal than first probe for host domain - pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::InProgress; + if (clsProbeInformation_Base::enuProbingStatus::ReadyToStart == pService->m_ProbeInformation.m_ProbingStatus) + { + // Ready to get started + pService->m_ProbeInformation.m_Timeout.reset(clsConsts::u32ProbeDelay); // More or equal than first probe for host domain + pService->m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::InProgress; } - else if ((enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND - (pService->m_ProbeInformation.m_Timeout.expired())) // Time for next probe + else if ((clsProbeInformation_Base::enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND + (pService->m_ProbeInformation.m_Timeout.expired())) // Time for next probe { - - if (MDNS_PROBE_COUNT > pService->m_ProbeInformation.m_u8SentCount) // Send next probe + if (clsConsts::u32ProbeCount > pService->m_ProbeInformation.m_u8SentCount) { + // Send next probe if ((bResult = _sendServiceProbe(*pService))) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Did sent service probe for '%s' (%u)\n\n"), _DH(), _service2String(pService), (pService->m_ProbeInformation.m_u8SentCount + 1));); - pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); + pService->m_ProbeInformation.m_Timeout.reset(clsConsts::u32ProbeDelay); ++pService->m_ProbeInformation.m_u8SentCount; } } - else // Probing finished + else { + // Probing finished DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("\n%s _updateProbeStatus: Done service probing '%s'\n\n\n"), _DH(), _service2String(pService));); - pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::Done; - pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + pService->m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce; + pService->m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShot::neverExpires); _callServiceProbeResultCallback(*pService, true); // Prepare to announce service pService->m_ProbeInformation.m_u8SentCount = 0; - pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + pService->m_ProbeInformation.m_Timeout.reset(clsConsts::u32AnnounceDelay); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Prepared service announcing.\n\n"), _DH());); } - } // else: Probing already finished OR waiting for next time slot - else if ((enuProbingStatus::Done == pService->m_ProbeInformation.m_ProbingStatus) && + } + else if ((clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == pService->m_ProbeInformation.m_ProbingStatus) && (pService->m_ProbeInformation.m_Timeout.expired())) { - - if ((bResult = _announceService(*pService))) // Announce service + // Probing already finished OR waiting for next time slot + if ((bResult = _announceService(*pService))) { + // Announce service ++pService->m_ProbeInformation.m_u8SentCount; // 1.. - if (MDNS_ANNOUNCE_COUNT > pService->m_ProbeInformation.m_u8SentCount) + if (clsConsts::u32AnnounceCount > pService->m_ProbeInformation.m_u8SentCount) { - pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY * pow(2, (pService->m_ProbeInformation.m_u8SentCount - 1))); // 2^(0..) -> 1, 2, 4, ... + pService->m_ProbeInformation.m_Timeout.reset(clsConsts::u32AnnounceDelay * pow(2, (pService->m_ProbeInformation.m_u8SentCount - 1))); // 2^(0..) -> 1, 2, 4, ... DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Announcing service '%s' (%lu)\n\n"), _DH(), _service2String(pService), pService->m_ProbeInformation.m_u8SentCount);); } else { - pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits::max()); + pService->m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::DoneFinally; + pService->m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShot::neverExpires); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done service announcing for '%s'\n"), _DH(), _service2String(pService));); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done service announcing for '%s'\n\n"), _DH(), _service2String(pService));); + //DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done service announcing for '%s'\n"), _DH(), _service2String(pService)); } } } @@ -1428,44 +1412,48 @@ bool MDNSResponder::clsHost::_updateProbeStatus(void) } /* - MDNSResponder::clsHost::_resetProbeStatus + clsLEAmDNS2_Host::_resetProbeStatus Resets the probe status. If 'p_bRestart' is set, the status is set to ProbingStatus_NotStarted. Consequently, when running 'updateProbeStatus' (which is done in every '_update' loop), the probing process is restarted. + */ -bool MDNSResponder::clsHost::_resetProbeStatus(bool p_bRestart /*= true*/) +bool clsLEAMDNSHost::_resetProbeStatus(bool p_bRestart /*= true*/) { - m_HostProbeInformation.clear(false); - m_HostProbeInformation.m_ProbingStatus = (p_bRestart ? enuProbingStatus::ReadyToStart : enuProbingStatus::Done); + m_ProbeInformation.clear(false); + m_ProbeInformation.m_ProbingStatus = (p_bRestart ? clsProbeInformation_Base::enuProbingStatus::ReadyToStart : clsProbeInformation_Base::enuProbingStatus::DoneFinally); - for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) + for (clsService* pService : m_Services) { pService->m_ProbeInformation.clear(false); - pService->m_ProbeInformation.m_ProbingStatus = (p_bRestart ? enuProbingStatus::ReadyToStart : enuProbingStatus::Done); + pService->m_ProbeInformation.m_ProbingStatus = (p_bRestart ? clsProbeInformation_Base::enuProbingStatus::ReadyToStart : clsProbeInformation_Base::enuProbingStatus::DoneFinally); } return true; } /* - MDNSResponder::clsHost::_hasProbesWaitingForAnswers + clsLEAmDNS2_Host::_hasProbesWaitingForAnswers + */ -bool MDNSResponder::clsHost::_hasProbesWaitingForAnswers(void) const +bool clsLEAMDNSHost::_hasProbesWaitingForAnswers(void) const { - bool bResult = ((enuProbingStatus::InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing - (0 < m_HostProbeInformation.m_u8SentCount)); // And really probing + bool bResult = ((clsProbeInformation_Base::enuProbingStatus::InProgress == m_ProbeInformation.m_ProbingStatus) && // Probing + (0 < m_ProbeInformation.m_u8SentCount)); // And really probing - for (stcService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) + for (clsService::list::const_iterator it = m_Services.cbegin(); ((!bResult) && (it != m_Services.cend())); it++) { - bResult = ((enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing - (0 < pService->m_ProbeInformation.m_u8SentCount)); // And really probing + clsService* pService = *it; + + bResult = ((clsProbeInformation_Base::enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing + (0 < pService->m_ProbeInformation.m_u8SentCount)); // And really probing } return bResult; } /* - MDNSResponder::clsHost::_sendHostProbe + clsLEAmDNS2_Host::_sendHostProbe Asks (probes) in the local network for the planned host domain - (eg. esp8266.local) @@ -1474,50 +1462,52 @@ bool MDNSResponder::clsHost::_hasProbesWaitingForAnswers(void) const the 'knwon answers' section of the query. Host domain: - A/AAAA (eg. esp8266.esp -> 192.168.2.120) + */ -bool MDNSResponder::clsHost::_sendHostProbe(void) +bool clsLEAMDNSHost::_sendHostProbe(void) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendHostProbe (%s.local, %lu)\n"), _DH(), m_pcHostName, millis());); bool bResult = true; // Requests for host domain - stcSendParameter sendParameter; + clsSendParameter sendParameter; sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 - sendParameter.m_pQuestions = new stcRRQuestion; - if (((bResult = (0 != sendParameter.m_pQuestions))) && - ((bResult = _buildDomainForHost(m_pcHostName, sendParameter.m_pQuestions->m_Header.m_Domain)))) + clsRRQuestion* pNewRRQuestion = new clsRRQuestion; + if (((bResult = (0 != pNewRRQuestion))) && + ((bResult = _buildDomainForHost(m_pcHostName, pNewRRQuestion->m_Header.m_Domain)))) { - //sendParameter.m_pQuestions->m_bUnicast = true; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + pNewRRQuestion->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + pNewRRQuestion->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + + sendParameter.m_RRQuestions.push_back(pNewRRQuestion); // Add known answers #ifdef MDNS_IPV4_SUPPORT - sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::A); // Add A answer + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::A); // Add A answer #endif #ifdef MDNS_IPV6_SUPPORT - sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::AAAA); // Add AAAA answer + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::AAAA); // Add AAAA answer #endif } else { DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _sendHostProbe: FAILED to create host question!\n"), _DH());); - if (sendParameter.m_pQuestions) + if (pNewRRQuestion) { - delete sendParameter.m_pQuestions; - sendParameter.m_pQuestions = 0; + delete pNewRRQuestion; + pNewRRQuestion = 0; } } DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendHostProbe: FAILED!\n"), _DH());); return ((bResult) && - (_sendMDNSMessage(sendParameter))); + (_sendMessage(sendParameter))); } /* - MDNSResponder::clsHost::_sendServiceProbe + clsLEAmDNS2_Host::_sendServiceProbe Asks (probes) in the local network for the planned service instance domain - (eg. MyESP._http._tcp.local). @@ -1527,25 +1517,27 @@ bool MDNSResponder::clsHost::_sendHostProbe(void) Service domain: - SRV (eg. MyESP._http._tcp.local -> 5000 esp8266.local) - PTR NAME (eg. _http._tcp.local -> MyESP._http._tcp.local) (TODO: Check if needed, maybe TXT is better) + */ -bool MDNSResponder::clsHost::_sendServiceProbe(stcService& p_rService) +bool clsLEAMDNSHost::_sendServiceProbe(clsService& p_rService) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendServiceProbe (%s, %lu)\n"), _DH(), _service2String(&p_rService), millis());); bool bResult = true; // Requests for service instance domain - stcSendParameter sendParameter; + clsSendParameter sendParameter; sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 - sendParameter.m_pQuestions = new stcRRQuestion; - if (((bResult = (0 != sendParameter.m_pQuestions))) && - ((bResult = _buildDomainForService(p_rService, true, sendParameter.m_pQuestions->m_Header.m_Domain)))) + clsRRQuestion* pNewRRQuestion = new clsRRQuestion; + if (((bResult = (0 != pNewRRQuestion))) && + ((bResult = _buildDomainForService(p_rService, true, pNewRRQuestion->m_Header.m_Domain)))) { + pNewRRQuestion->m_bUnicast = true; + pNewRRQuestion->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + pNewRRQuestion->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet - sendParameter.m_pQuestions->m_bUnicast = true; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + sendParameter.m_RRQuestions.push_back(pNewRRQuestion); // Add known answers p_rService.m_u32ReplyMask = (static_cast(enuContentFlag::SRV) | static_cast(enuContentFlag::PTR_NAME)); // Add SRV and PTR NAME answers @@ -1553,30 +1545,31 @@ bool MDNSResponder::clsHost::_sendServiceProbe(stcService& p_rService) else { DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _sendServiceProbe: FAILED to create service question!\n"), _DH());); - if (sendParameter.m_pQuestions) + if (pNewRRQuestion) { - delete sendParameter.m_pQuestions; - sendParameter.m_pQuestions = 0; + delete pNewRRQuestion; + pNewRRQuestion = 0; } } DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendServiceProbe: FAILED!\n"), _DH());); return ((bResult) && - (_sendMDNSMessage(sendParameter))); + (_sendMessage(sendParameter))); } /* - MDNSResponder::clsHost::_cancelProbingForHost + clsLEAmDNS2_Host::_cancelProbingForHost + */ -bool MDNSResponder::clsHost::_cancelProbingForHost(void) +bool clsLEAMDNSHost::_cancelProbingForHost(void) { bool bResult = false; - m_HostProbeInformation.clear(false); + m_ProbeInformation.clear(false); // Send host notification bResult = _callHostProbeResultCallback(false); - for (stcService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) + for (clsService* pService : m_Services) { bResult = _cancelProbingForService(*pService); } @@ -1584,9 +1577,10 @@ bool MDNSResponder::clsHost::_cancelProbingForHost(void) } /* - MDNSResponder::clsHost::_cancelProbingForService + clsLEAmDNS2_Host::_cancelProbingForService + */ -bool MDNSResponder::clsHost::_cancelProbingForService(stcService& p_rService) +bool clsLEAMDNSHost::_cancelProbingForService(clsService& p_rService) { p_rService.m_ProbeInformation.clear(false); @@ -1595,81 +1589,53 @@ bool MDNSResponder::clsHost::_cancelProbingForService(stcService& p_rService) } /* - MDNSResponder::clsHost::_callHostProbeResultCallback + clsLEAmDNS2_Host::_callHostProbeResultCallback */ -bool MDNSResponder::clsHost::_callHostProbeResultCallback(bool p_bResult) +bool clsLEAMDNSHost::_callHostProbeResultCallback(bool p_bResult) { - if (m_HostProbeInformation.m_fnProbeResultCallback) + if (m_ProbeInformation.m_fnProbeResultCallback) { - m_HostProbeInformation.m_fnProbeResultCallback(*this, m_pcHostName, p_bResult); + m_ProbeInformation.m_fnProbeResultCallback(*this, m_pcHostName, p_bResult); } else if (!p_bResult) { // Auto-Handle failure by changing the host name, use '-' as divider between base name and index - char* pcHostDomainTemp = strdup(m_pcHostName); - if (pcHostDomainTemp) - { - if (MDNSResponder::indexDomain(pcHostDomainTemp, "-", 0)) - { - setHostName(pcHostDomainTemp); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _callHostProbeResultCallback: FAILED to update host domain '%s'!\n"), _DH(), (m_pcHostName ? : ""));); - } - free(pcHostDomainTemp); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _callHostProbeResultCallback: FAILED to copy host domain '%s'!\n"), _DH(), (m_pcHostName ? : ""));); - } + indexHostName(); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _callHostProbeResultCallback: Changed Host Name: %s\n"), _DH(), (m_pcHostName ? : ""))); } return true; } /* - MDNSResponder::clsHost::_callServiceProbeResultCallback + clsLEAmDNS2_Host::_callServiceProbeResultCallback */ -bool MDNSResponder::clsHost::_callServiceProbeResultCallback(MDNSResponder::clsHost::stcService& p_rService, - bool p_bResult) +bool clsLEAMDNSHost::_callServiceProbeResultCallback(clsLEAMDNSHost::clsService& p_rService, + bool p_bResult) { if (p_rService.m_ProbeInformation.m_fnProbeResultCallback) { - p_rService.m_ProbeInformation.m_fnProbeResultCallback(*this, p_rService, p_rService.m_pcName, p_bResult); + p_rService.m_ProbeInformation.m_fnProbeResultCallback(p_rService, p_rService.instanceName(), p_bResult); } else if (!p_bResult) { // Auto-Handle failure by changing the service name, use ' #' as divider between base name and index - char* pcServiceNameTemp = strdup(p_rService.m_pcName); - if (pcServiceNameTemp) - { - if (MDNSResponder::indexDomain(pcServiceNameTemp, " #", 0)) - { - setServiceName(&p_rService, pcServiceNameTemp); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _callServiceProbeResultCallback: FAILED to update service name for '%s'!\n"), _DH(), _service2String(&p_rService));); - } - free(pcServiceNameTemp); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _callServiceProbeResultCallback: FAILED to copy service name for '%s'!\n"), _DH(), _service2String(&p_rService));); - } + p_rService.indexInstanceName(); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _callServiceProbeResultCallback: Changed Service Domain: %s\n"), _DH(), _service2String(&p_rService))); } return true; } -/** +/* + ANNOUNCING + */ /* - MDNSResponder::clsHost::_announce + clsLEAmDNS2_Host::_announce Announces the host domain: - A/AAAA (eg. esp8266.local -> 192.168.2.120) @@ -1684,18 +1650,19 @@ bool MDNSResponder::clsHost::_callServiceProbeResultCallback(MDNSResponder::clsH Goodbye (Un-Announcing) for the host domain and all services is also handled here. Goodbye messages are created by setting the TTL for the answer to 0, this happens inside the '_writeXXXAnswer' procs via 'sendParameter.m_bUnannounce = true' + */ -bool MDNSResponder::clsHost::_announce(bool p_bAnnounce, - bool p_bIncludeServices) +bool clsLEAMDNSHost::_announce(bool p_bAnnounce, + bool p_bIncludeServices) { bool bResult = false; - stcSendParameter sendParameter; - if (enuProbingStatus::Done == m_HostProbeInformation.m_ProbingStatus) + clsSendParameter sendParameter; + if (clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == m_ProbeInformation.m_ProbingStatus) { bResult = true; - sendParameter.m_Response = stcSendParameter::enuResponseType::Unsolicited; // Announces are 'Unsolicited authorative responses' + sendParameter.m_Response = clsSendParameter::enuResponseType::Unsolicited; // Announces are 'Unsolicited authorative responses' sendParameter.m_bAuthorative = true; sendParameter.m_bCacheFlush = true; // RFC 6762 8.3 sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers @@ -1716,12 +1683,14 @@ bool MDNSResponder::clsHost::_announce(bool p_bAnnounce, if (p_bIncludeServices) { // Announce services (service type, name, SRV (location) and TXTs) - for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + for (clsService* pService : m_Services) { - if (enuProbingStatus::Done == pService->m_ProbeInformation.m_ProbingStatus) + if (clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == pService->m_ProbeInformation.m_ProbingStatus) { - pService->m_u32ReplyMask = (static_cast(enuContentFlag::PTR_TYPE) | static_cast(enuContentFlag::PTR_NAME) | static_cast(enuContentFlag::SRV) | static_cast(enuContentFlag::TXT)); - + pService->m_u32ReplyMask = (static_cast(enuContentFlag::PTR_TYPE) | + static_cast(enuContentFlag::PTR_NAME) | + static_cast(enuContentFlag::SRV) | + static_cast(enuContentFlag::TXT)); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _announce: Announcing service '%s' (content %s)\n"), _DH(), _service2String(pService), _replyFlags2String(pService->m_u32ReplyMask));); } } @@ -1729,22 +1698,22 @@ bool MDNSResponder::clsHost::_announce(bool p_bAnnounce, } DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _announce: FAILED!\n"), _DH());); return ((bResult) && - (_sendMDNSMessage(sendParameter))); + (_sendMessage(sendParameter))); } /* - MDNSResponder::clsHost::_announceService + clsLEAmDNS2_Host::_announceService + */ -bool MDNSResponder::clsHost::_announceService(MDNSResponder::clsHost::stcService& p_rService, - bool p_bAnnounce /*= true*/) +bool clsLEAMDNSHost::_announceService(clsLEAMDNSHost::clsService& p_rService, + bool p_bAnnounce /*= true*/) { bool bResult = false; - stcSendParameter sendParameter; - if (enuProbingStatus::Done == p_rService.m_ProbeInformation.m_ProbingStatus) + clsSendParameter sendParameter; + if (clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == p_rService.m_ProbeInformation.m_ProbingStatus) { - - sendParameter.m_Response = stcSendParameter::enuResponseType::Unsolicited; // Announces are 'Unsolicited authorative responses' + sendParameter.m_Response = clsSendParameter::enuResponseType::Unsolicited; // Announces are 'Unsolicited authorative responses' sendParameter.m_bAuthorative = true; sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers @@ -1752,23 +1721,28 @@ bool MDNSResponder::clsHost::_announceService(MDNSResponder::clsHost::stcService sendParameter.m_u32HostReplyMask = 0; // Announce services (service type, name, SRV (location) and TXTs) - p_rService.m_u32ReplyMask = (static_cast(enuContentFlag::PTR_TYPE) | static_cast(enuContentFlag::PTR_NAME) | static_cast(enuContentFlag::SRV) | static_cast(enuContentFlag::TXT)); + p_rService.m_u32ReplyMask = (static_cast(enuContentFlag::PTR_TYPE) | + static_cast(enuContentFlag::PTR_NAME) | + static_cast(enuContentFlag::SRV) | + static_cast(enuContentFlag::TXT)); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _announceService: Announcing service '%s' (content: %s)\n"), _DH(), _service2String(&p_rService), _replyFlags2String(p_rService.m_u32ReplyMask));); bResult = true; } DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _announceService: FAILED!\n"), _DH());); return ((bResult) && - (_sendMDNSMessage(sendParameter))); + (_sendMessage(sendParameter))); } -/** +/* + QUERY CACHE + */ /* - MDNSResponder::clsHost::_checkQueryCache + clsLEAmDNS2_Host::_checkQueryCache For any 'living' query (m_bAwaitingAnswers == true) all available answers (their components) are checked for topicality based on the stored reception time and the answers TTL. @@ -1776,29 +1750,33 @@ bool MDNSResponder::clsHost::_announceService(MDNSResponder::clsHost::stcService When no update arrived (in time), the component is removed from the answer (cache). */ -bool MDNSResponder::clsHost::_checkQueryCache(void) +bool clsLEAMDNSHost::_checkQueryCache(void) { bool bResult = true; DEBUG_EX_INFO( bool printedInfo = false; ); - for (stcQuery* pQuery = m_pQueries; ((bResult) && (pQuery)); pQuery = pQuery->m_pNext) + for (clsQuery::list::iterator itQ = m_Queries.begin(); ((bResult) && (itQ != m_Queries.end())); itQ++) { + clsQuery* pQuery = *itQ; // // Resend dynamic queries, if not already done often enough - if ((!pQuery->m_bLegacyQuery) && + if ((!pQuery->m_bStaticQuery) && (pQuery->m_ResendTimeout.expired())) { - - if ((bResult = _sendMDNSQuery(*pQuery))) + if ((bResult = _sendQuery(*pQuery))) { // The re-query rate is increased to more than one hour (RFC 6762 5.2) ++pQuery->m_u8SentCount; - uint32_t u32NewDelay = (MDNS_DYNAMIC_QUERY_RESEND_DELAY * pow(2, std::min((pQuery->m_u8SentCount - 1), 12))); + uint32_t u32NewDelay = (clsConsts::u32DynamicQueryResendDelay * pow(2, std::min((pQuery->m_u8SentCount - 1), 12))); DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Next query in %u seconds!\n"), _DH(), (u32NewDelay));); pQuery->m_ResendTimeout.reset(u32NewDelay); } + else + { + break; + } DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: %s to resend query!\n"), _DH(), (bResult ? "Succeeded" : "FAILED")); printedInfo = true; @@ -1809,25 +1787,22 @@ bool MDNSResponder::clsHost::_checkQueryCache(void) // Schedule updates for cached answers if (pQuery->m_bAwaitingAnswers) { - stcQuery::stcAnswer* pSQAnswer = pQuery->m_pAnswers; - while ((bResult) && - (pSQAnswer)) + clsQuery::clsAnswer::list expiredAnswers; + for (clsQuery::clsAnswer::list::iterator itQA = pQuery->m_Answers.begin(); ((bResult) && (itQA != pQuery->m_Answers.end())); itQA++) { - stcQuery::stcAnswer* pNextSQAnswer = pSQAnswer->m_pNext; + clsQuery::clsAnswer* pQAnswer = *itQA; // 1. level answer if ((bResult) && - (pSQAnswer->m_TTLServiceDomain.flagged())) + (pQAnswer->m_TTLServiceDomain.flagged())) { - - if (!pSQAnswer->m_TTLServiceDomain.finalTimeoutLevel()) + if (!pQAnswer->m_TTLServiceDomain.finalTimeoutLevel()) { - - bResult = ((_sendMDNSQuery(*pQuery)) && - (pSQAnswer->m_TTLServiceDomain.restart())); + bResult = ((_sendQuery(*pQuery)) && + (pQAnswer->m_TTLServiceDomain.restart())); DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: PTR update scheduled for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), (bResult ? "OK" : "FAILURE")); printedInfo = true; ); @@ -1835,16 +1810,15 @@ bool MDNSResponder::clsHost::_checkQueryCache(void) else { // Timed out! -> Delete - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::ServiceDomain), false); + _executeQueryCallback(*pQuery, *pQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain), false); DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove PTR answer for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR("\n")); printedInfo = true; ); - bResult = pQuery->removeAnswer(pSQAnswer); - pSQAnswer = 0; + expiredAnswers.push_back(pQAnswer); continue; // Don't use this answer anymore } } // ServiceDomain flagged @@ -1852,17 +1826,15 @@ bool MDNSResponder::clsHost::_checkQueryCache(void) // 2. level answers // HostDomain & Port (from SRV) if ((bResult) && - (pSQAnswer->m_TTLHostDomainAndPort.flagged())) + (pQAnswer->m_TTLHostDomainAndPort.flagged())) { - - if (!pSQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) + if (!pQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) { - - bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_SRV)) && - (pSQAnswer->m_TTLHostDomainAndPort.restart())); + bResult = ((_sendQuery(pQAnswer->m_ServiceDomain, DNS_RRTYPE_SRV)) && + (pQAnswer->m_TTLHostDomainAndPort.restart())); DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: SRV update scheduled for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(" host domain and port %s\n"), (bResult ? "OK" : "FAILURE")); printedInfo = true; ); @@ -1872,45 +1844,43 @@ bool MDNSResponder::clsHost::_checkQueryCache(void) // Timed out! -> Delete DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove SRV answer for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); printedInfo = true; ); // Delete - pSQAnswer->m_HostDomain.clear(); + pQAnswer->m_HostDomain.clear(); //pSQAnswer->releaseHostDomain(); - pSQAnswer->m_u16Port = 0; - pSQAnswer->m_TTLHostDomainAndPort.set(0); - typeQueryAnswerType queryAnswerContentFlags = (static_cast(enuQueryAnswerType::HostDomain) | static_cast(enuQueryAnswerType::Port)); + pQAnswer->m_u16Port = 0; + pQAnswer->m_TTLHostDomainAndPort.set(0); + clsQuery::clsAnswer::typeQueryAnswerType queryAnswerContentFlags = (static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain) | static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Port)); // As the host domain is the base for the IPv4- and IPv6Address, remove these too #ifdef MDNS_IPV4_SUPPORT - pSQAnswer->releaseIPv4Addresses(); - queryAnswerContentFlags |= static_cast(enuQueryAnswerType::IPv4Address); + pQAnswer->releaseIPv4Addresses(); + queryAnswerContentFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address); #endif #ifdef MDNS_IPV6_SUPPORT - pSQAnswer->releaseIPv6Addresses(); - queryAnswerContentFlags |= static_cast(enuQueryAnswerType::IPv6Address); + pQAnswer->releaseIPv6Addresses(); + queryAnswerContentFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address); #endif // Remove content flags for deleted answer parts - pSQAnswer->m_QueryAnswerFlags &= ~queryAnswerContentFlags; - _executeQueryCallback(*pQuery, *pSQAnswer, queryAnswerContentFlags, false); + pQAnswer->m_QueryAnswerFlags &= ~queryAnswerContentFlags; + _executeQueryCallback(*pQuery, *pQAnswer, queryAnswerContentFlags, false); } } // HostDomainAndPort flagged // Txts (from TXT) if ((bResult) && - (pSQAnswer->m_TTLTxts.flagged())) + (pQAnswer->m_TTLTxts.flagged())) { - - if (!pSQAnswer->m_TTLTxts.finalTimeoutLevel()) + if (!pQAnswer->m_TTLTxts.finalTimeoutLevel()) { - - bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_TXT)) && - (pSQAnswer->m_TTLTxts.restart())); + bResult = ((_sendQuery(pQAnswer->m_ServiceDomain, DNS_RRTYPE_TXT)) && + (pQAnswer->m_TTLTxts.restart())); DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: TXT update scheduled for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(" TXTs %s\n"), (bResult ? "OK" : "FAILURE")); printedInfo = true; ); @@ -1920,47 +1890,43 @@ bool MDNSResponder::clsHost::_checkQueryCache(void) // Timed out! -> Delete DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove TXT answer for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); printedInfo = true; ); // Delete - pSQAnswer->m_Txts.clear(); - pSQAnswer->m_TTLTxts.set(0); + pQAnswer->m_Txts.clear(); + pQAnswer->m_TTLTxts.set(0); // Remove content flags for deleted answer parts - pSQAnswer->m_QueryAnswerFlags &= ~static_cast(enuQueryAnswerType::Txts); - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::Txts), false); + pQAnswer->m_QueryAnswerFlags &= ~static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts); + _executeQueryCallback(*pQuery, *pQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts), false); } } // TXTs flagged // 3. level answers #ifdef MDNS_IPV4_SUPPORT // IPv4Address (from A) - stcQuery::stcAnswer::stcIPAddress* pIPv4Address = pSQAnswer->m_pIPv4Addresses; + clsQuery::clsAnswer::clsIPAddressWithTTL::list expiredIPv4Addresses; bool bAUpdateQuerySent = false; - while ((pIPv4Address) && - (bResult)) + for (clsQuery::clsAnswer::clsIPAddressWithTTL::list::iterator itQAIPv4 = pQAnswer->m_IPv4Addresses.begin(); ((bResult) && (itQAIPv4 != pQAnswer->m_IPv4Addresses.end())); itQAIPv4++) { - - stcQuery::stcAnswer::stcIPAddress* pNextIPv4Address = pIPv4Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... + clsQuery::clsAnswer::clsIPAddressWithTTL* pIPv4Address = *itQAIPv4; if (pIPv4Address->m_TTL.flagged()) { - - if (!pIPv4Address->m_TTL.finalTimeoutLevel()) // Needs update + if (!pIPv4Address->m_TTL.finalTimeoutLevel()) { - + // Needs update if ((bAUpdateQuerySent) || - ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_A)))) + ((bResult = _sendQuery(pQAnswer->m_HostDomain, DNS_RRTYPE_A)))) { - pIPv4Address->m_TTL.restart(); bAUpdateQuerySent = true; DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: IPv4 update scheduled for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address (%s)\n"), (pIPv4Address->m_IPAddress.toString().c_str())); printedInfo = true; ); @@ -1971,49 +1937,49 @@ bool MDNSResponder::clsHost::_checkQueryCache(void) // Timed out! -> Delete DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove IPv4 answer for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address\n")); printedInfo = true; ); - pSQAnswer->removeIPv4Address(pIPv4Address); - if (!pSQAnswer->m_pIPv4Addresses) // NO IPv4 address left -> remove content flag + if (1 == pQAnswer->m_IPv4Addresses.size()) { - pSQAnswer->m_QueryAnswerFlags &= ~static_cast(enuQueryAnswerType::IPv4Address); + // NO IPv4 address left after this -> remove content flag + pQAnswer->m_QueryAnswerFlags &= ~static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address); } // Notify client - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::IPv4Address), false); + _executeQueryCallback(*pQuery, *pQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address), false); + expiredIPv4Addresses.push_back(pIPv4Address); } } // IPv4 flagged - - pIPv4Address = pNextIPv4Address; // Next - } // while + } // for + // Finally remove expired IPv4 addresses + for (clsQuery::clsAnswer::clsIPAddressWithTTL* pIPv4Address : expiredIPv4Addresses) + { + pQAnswer->removeIPv4Address(pIPv4Address); + } #endif #ifdef MDNS_IPV6_SUPPORT // IPv6Address (from AAAA) - stcQuery::stcAnswer::stcIPAddress* pIPv6Address = pSQAnswer->m_pIPv6Addresses; + clsQuery::clsAnswer::clsIPAddressWithTTL::list expiredIPv6Addresses; bool bAAAAUpdateQuerySent = false; - while ((pIPv6Address) && - (bResult)) + for (clsQuery::clsAnswer::clsIPAddressWithTTL::list::iterator itQAIPv6 = pQAnswer->m_IPv6Addresses.begin(); ((bResult) && (itQAIPv6 != pQAnswer->m_IPv6Addresses.end())); itQAIPv6++) { - - stcQuery::stcAnswer::stcIPAddress* pNextIPv6Address = pIPv6Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... + clsQuery::clsAnswer::clsIPAddressWithTTL* pIPv6Address = *itQAIPv6; if (pIPv6Address->m_TTL.flagged()) { - - if (!pIPv6Address->m_TTL.finalTimeoutLevel()) // Needs update + if (!pIPv6Address->m_TTL.finalTimeoutLevel()) { - + // Needs update if ((bAAAAUpdateQuerySent) || - ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) + ((bResult = _sendQuery(pQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) { - pIPv6Address->m_TTL.restart(); bAAAAUpdateQuerySent = true; DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: IPv6 update scheduled for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address (%s)\n"), (pIPv6Address->m_IPAddress.toString().c_str())); printedInfo = true; ); @@ -2024,24 +1990,33 @@ bool MDNSResponder::clsHost::_checkQueryCache(void) // Timed out! -> Delete DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove answer for "), _DH()); - _printRRDomain(pSQAnswer->m_ServiceDomain); + _printRRDomain(pQAnswer->m_ServiceDomain); DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address\n")); printedInfo = true; ); - pSQAnswer->removeIPv6Address(pIPv6Address); - if (!pSQAnswer->m_pIPv6Addresses) // NO IPv6 address left -> remove content flag + if (1 == pQAnswer->m_IPv6Addresses.size()) { - pSQAnswer->m_QueryAnswerFlags &= ~static_cast(enuQueryAnswerType::IPv6Address); + // NO IPv6 address left after this -> remove content flag + pQAnswer->m_QueryAnswerFlags &= ~static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address); } // Notify client - _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(enuQueryAnswerType::IPv6Address), false); + _executeQueryCallback(*pQuery, *pQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address), false); + expiredIPv6Addresses.push_back(pIPv6Address); } } // IPv6 flagged - - pIPv6Address = pNextIPv6Address; // Next + // Finally remove expired IPv6 addresses + for (clsQuery::clsAnswer::clsIPAddressWithTTL* pIPv6Address : expiredIPv6Addresses) + { + pQAnswer->removeIPv6Address(pIPv6Address); + } } // while #endif - pSQAnswer = pNextSQAnswer; + } + + // Finally remove expired answers + for (clsQuery::clsAnswer* pAnswer : expiredAnswers) + { + pQuery->removeAnswer(pAnswer); } } } @@ -2052,7 +2027,7 @@ bool MDNSResponder::clsHost::_checkQueryCache(void) /* - MDNSResponder::clsHost::_replyMaskForHost + clsLEAmDNS2_Host::_replyMaskForHost Determines the relavant host answers for the given question. - A question for the hostname (eg. esp8266.local) will result in an A/AAAA (eg. 192.168.2.129) reply. @@ -2060,8 +2035,8 @@ bool MDNSResponder::clsHost::_checkQueryCache(void) In addition, a full name match (question domain == host domain) is marked. */ -uint32_t MDNSResponder::clsHost::_replyMaskForHost(const MDNSResponder::clsHost::stcRRHeader& p_RRHeader, - bool* p_pbFullNameMatch /*= 0*/) const +uint32_t clsLEAMDNSHost::_replyMaskForHost(const clsLEAMDNSHost::clsRRHeader& p_RRHeader, + bool* p_pbFullNameMatch /*= 0*/) const { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForHost\n"));); @@ -2077,7 +2052,7 @@ uint32_t MDNSResponder::clsHost::_replyMaskForHost(const MDNSResponder::clsHost: { // PTR request #ifdef MDNS_IPV4_SUPPORT - stcRRDomain reverseIPv4Domain; + clsRRDomain reverseIPv4Domain; if ((_getResponderIPAddress(enuIPProtocolType::V4).isSet()) && (_buildDomainForReverseIPv4(_getResponderIPAddress(enuIPProtocolType::V4), reverseIPv4Domain)) && (p_RRHeader.m_Domain == reverseIPv4Domain)) @@ -2087,7 +2062,7 @@ uint32_t MDNSResponder::clsHost::_replyMaskForHost(const MDNSResponder::clsHost: } #endif #ifdef MDNS_IPV6_SUPPORT - stcRRDomain reverseIPv6Domain; + clsRRDomain reverseIPv6Domain; if ((_getResponderIPAddress(enuIPProtocolType::V6).isSet()) && (_buildDomainForReverseIPv6(_getResponderIPAddress(enuIPProtocolType::V6), reverseIPv6Domain)) && (p_RRHeader.m_Domain == reverseIPv6Domain)) @@ -2098,11 +2073,10 @@ uint32_t MDNSResponder::clsHost::_replyMaskForHost(const MDNSResponder::clsHost: #endif } // Address qeuest - stcRRDomain hostDomain; + clsRRDomain hostDomain; if ((_buildDomainForHost(m_pcHostName, hostDomain)) && (p_RRHeader.m_Domain == hostDomain)) // Host domain match { - (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); #ifdef MDNS_IPV4_SUPPORT @@ -2132,7 +2106,7 @@ uint32_t MDNSResponder::clsHost::_replyMaskForHost(const MDNSResponder::clsHost: } /* - MDNSResponder::clsHost::_replyMaskForService + clsLEAmDNS2_Host::_replyMaskForService Determines the relevant service answers for the given question - A PTR dns-sd service enum question (_services.dns-sd._udp.local) will result into an PTR_TYPE (eg. _http._tcp.local) answer @@ -2142,10 +2116,11 @@ uint32_t MDNSResponder::clsHost::_replyMaskForHost(const MDNSResponder::clsHost: - A TXT service name question (eg. MyESP._http._tcp.local) will result into an TXT (eg. c#=1) answer In addition, a full name match (question domain == service instance domain) is marked. + */ -uint32_t MDNSResponder::clsHost::_replyMaskForService(const MDNSResponder::clsHost::stcRRHeader& p_RRHeader, - const MDNSResponder::clsHost::stcService& p_Service, - bool* p_pbFullNameMatch /*= 0*/) const +uint32_t clsLEAMDNSHost::_replyMaskForService(const clsLEAMDNSHost::clsRRHeader& p_RRHeader, + clsLEAMDNSHost::clsService& p_rService, + bool* p_pbFullNameMatch /*= 0*/) { uint32_t u32ReplyMask = 0; (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); @@ -2153,8 +2128,7 @@ uint32_t MDNSResponder::clsHost::_replyMaskForService(const MDNSResponder::clsHo if ((DNS_RRCLASS_IN == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000))) || (DNS_RRCLASS_ANY == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000)))) { - - stcRRDomain DNSSDDomain; + clsRRDomain DNSSDDomain; if ((_buildDomainForDNSSD(DNSSDDomain)) && // _services._dns-sd._udp.local (p_RRHeader.m_Domain == DNSSDDomain) && ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || @@ -2164,8 +2138,8 @@ uint32_t MDNSResponder::clsHost::_replyMaskForService(const MDNSResponder::clsHo u32ReplyMask |= static_cast(enuContentFlag::PTR_TYPE); } - stcRRDomain serviceDomain; - if ((_buildDomainForService(p_Service, false, serviceDomain)) && // eg. _http._tcp.local + clsRRDomain serviceDomain; + if ((_buildDomainForService(p_rService, false, serviceDomain)) && // eg. _http._tcp.local (p_RRHeader.m_Domain == serviceDomain) && ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) @@ -2174,10 +2148,9 @@ uint32_t MDNSResponder::clsHost::_replyMaskForService(const MDNSResponder::clsHo u32ReplyMask |= static_cast(enuContentFlag::PTR_NAME); } - if ((_buildDomainForService(p_Service, true, serviceDomain)) && // eg. MyESP._http._tcp.local + if ((_buildDomainForService(p_rService, true, serviceDomain)) && // eg. MyESP._http._tcp.local (p_RRHeader.m_Domain == serviceDomain)) { - (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); if ((DNS_RRTYPE_SRV == p_RRHeader.m_Attributes.m_u16Type) || @@ -2198,10 +2171,15 @@ uint32_t MDNSResponder::clsHost::_replyMaskForService(const MDNSResponder::clsHo { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForService: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); } - DEBUG_EX_INFO(if (u32ReplyMask) DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForService(%s.%s.%s): %s\n"), _DH(), p_Service.m_pcName, p_Service.m_pcServiceType, p_Service.m_pcProtocol, _replyFlags2String(u32ReplyMask));); + DEBUG_EX_INFO(if (u32ReplyMask) DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForService(%s.%s.%s): %s\n"), _DH(), p_rService.m_pcInstanceName, p_rService.m_pcType, p_rService.m_pcProtocol, _replyFlags2String(u32ReplyMask));); return u32ReplyMask; } + } // namespace MDNSImplementation + } // namespace esp8266 + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Debug.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp old mode 100755 new mode 100644 similarity index 65% rename from libraries/ESP8266mDNS/src/LEAmDNS2_Host_Debug.cpp rename to libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp index 3f43a54089..434f61a0ea --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Debug.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp @@ -1,5 +1,5 @@ /* - LEAmDNS2_Host_Debug.h + LEAmDNS2Host_Debug.h License (MIT license): Permission is hereby granted, free of charge, to any person obtaining a copy @@ -22,88 +22,70 @@ */ -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include - -/* - ESP8266mDNS Control.cpp -*/ - -extern "C" { - //#include "user_interface.h" -} - -#include "LEAmDNS2_lwIPdefs.h" -#include "LEAmDNS2_Priv.h" - -#ifdef MDNS_IPV4_SUPPORT -//#include -#endif -#ifdef MDNS_IPV6_SUPPORT -//#include -#endif +#include "LEAmDNS2Host.h" namespace esp8266 { -/* - LEAmDNS -*/ + namespace experimental { + #ifdef DEBUG_ESP_MDNS_RESPONDER /* - MDNSResponder::clsHost::_DH + clsLEAmDNS2_Host::_DH + */ -const char* MDNSResponder::clsHost::_DH(const MDNSResponder::clsHost::stcService* p_pMDNSService /*= 0*/) const +const char* clsLEAMDNSHost::_DH(const clsLEAMDNSHost::clsService* p_pService /*= 0*/) const { static char acBuffer[16 + 64]; *acBuffer = 0; - if (p_pMDNSService) + if (m_pNetIf) { - sprintf_P(acBuffer, PSTR("[MDNSResponder (%c%c%u)->%s]"), m_rNetIf.name[0], m_rNetIf.name[1], m_rNetIf.num, _service2String(p_pMDNSService)); + sprintf_P(acBuffer, PSTR("[mDNS %c%c%u]"), m_pNetIf->name[0], m_pNetIf->name[1], m_pNetIf->num); + if (p_pService) + { + strcat_P(acBuffer, PSTR(">")); + strcat(acBuffer, _service2String(p_pService)); + } } else { - sprintf_P(acBuffer, PSTR("[MDNSResponder (%c%c%u)]"), m_rNetIf.name[0], m_rNetIf.name[1], m_rNetIf.num); + strcpy_P(acBuffer, PSTR("[mDNS]")); } return acBuffer; } /* - MDNSResponder::clsHost::_service2String + clsLEAmDNS2_Host::_service2String + */ -const char* MDNSResponder::clsHost::_service2String(const MDNSResponder::clsHost::stcService* p_pMDNSService) const +const char* clsLEAMDNSHost::_service2String(const clsLEAMDNSHost::clsService* p_pService) const { static char acBuffer[64]; *acBuffer = 0; - if (p_pMDNSService) + if (p_pService) { sprintf_P(acBuffer, PSTR("%s.%s%s.%s%s.local"), - (p_pMDNSService->m_pcName ? : "-"), - (p_pMDNSService->m_pcServiceType ? ('_' == *(p_pMDNSService->m_pcServiceType) ? "" : "_") : "-"), - (p_pMDNSService->m_pcServiceType ? : "-"), - (p_pMDNSService->m_pcProtocol ? ('_' == *(p_pMDNSService->m_pcProtocol) ? "" : "_") : "-"), - (p_pMDNSService->m_pcProtocol ? : "-")); + (p_pService->m_pcInstanceName ? : "-"), + (p_pService->m_pcType ? ('_' == *(p_pService->m_pcType) ? "" : "_") : "-"), + (p_pService->m_pcType ? : "-"), + (p_pService->m_pcProtocol ? ('_' == *(p_pService->m_pcProtocol) ? "" : "_") : "-"), + (p_pService->m_pcProtocol ? : "-")); } return acBuffer; } /* - MDNSResponder::clsHost::_printRRDomain + clsLEAmDNS2_Host::_printRRDomain + */ -bool MDNSResponder::clsHost::_printRRDomain(const MDNSResponder::clsHost::stcRRDomain& p_RRDomain) const +bool clsLEAMDNSHost::_printRRDomain(const clsLEAMDNSHost::clsRRDomain& p_RRDomain) const { //DEBUG_OUTPUT.printf_P(PSTR("Domain: ")); @@ -134,9 +116,10 @@ bool MDNSResponder::clsHost::_printRRDomain(const MDNSResponder::clsHost::stcRRD } /* - MDNSResponder::clsHost::_printRRAnswer + clsLEAmDNS2_Host::_printRRAnswer + */ -bool MDNSResponder::clsHost::_printRRAnswer(const MDNSResponder::clsHost::stcRRAnswer& p_RRAnswer) const +bool clsLEAMDNSHost::_printRRAnswer(const clsLEAMDNSHost::clsRRAnswer& p_RRAnswer) const { DEBUG_OUTPUT.printf_P(PSTR("%s RRAnswer: "), _DH()); _printRRDomain(p_RRAnswer.m_Header.m_Domain); @@ -145,20 +128,20 @@ bool MDNSResponder::clsHost::_printRRAnswer(const MDNSResponder::clsHost::stcRRA { #ifdef MDNS_IPV4_SUPPORT case DNS_RRTYPE_A: - DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((const stcRRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str()); + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((const clsRRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str()); break; #endif case DNS_RRTYPE_PTR: DEBUG_OUTPUT.printf_P(PSTR("PTR ")); - _printRRDomain(((const stcRRAnswerPTR*)&p_RRAnswer)->m_PTRDomain); + _printRRDomain(((const clsRRAnswerPTR*)&p_RRAnswer)->m_PTRDomain); break; case DNS_RRTYPE_TXT: { - size_t stTxtLength = ((const stcRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength(); + size_t stTxtLength = ((const clsRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength(); char* pTxts = new char[stTxtLength]; if (pTxts) { - ((/*const c_str()!!*/stcRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts); + ((/*const c_str()!!*/clsRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts); DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); delete[] pTxts; } @@ -166,12 +149,12 @@ bool MDNSResponder::clsHost::_printRRAnswer(const MDNSResponder::clsHost::stcRRA } #ifdef MDNS_IPV6_SUPPORT case DNS_RRTYPE_AAAA: - DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcRRAnswerAAAA*&)p_RRAnswer)->m_IPAddress.toString().c_str()); + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((clsRRAnswerAAAA*&)p_RRAnswer)->m_IPAddress.toString().c_str()); break; #endif case DNS_RRTYPE_SRV: - DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((const stcRRAnswerSRV*)&p_RRAnswer)->m_u16Port); - _printRRDomain(((const stcRRAnswerSRV*)&p_RRAnswer)->m_SRVDomain); + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((const clsRRAnswerSRV*)&p_RRAnswer)->m_u16Port); + _printRRDomain(((const clsRRAnswerSRV*)&p_RRAnswer)->m_SRVDomain); break; default: DEBUG_OUTPUT.printf_P(PSTR("generic ")); @@ -183,33 +166,38 @@ bool MDNSResponder::clsHost::_printRRAnswer(const MDNSResponder::clsHost::stcRRA } /* - MDNSResponder::clsHost::_RRType2Name + clsLEAmDNS2_Host::_RRType2Name + */ -const char* MDNSResponder::clsHost::_RRType2Name(uint16_t p_u16RRType) const +const char* clsLEAMDNSHost::_RRType2Name(uint16_t p_u16RRType) const { static char acRRName[16]; *acRRName = 0; switch (p_u16RRType & (~0x8000)) // Topmost bit might carry 'cache flush' flag { - case DNS_RRTYPE_A: strcpy(acRRName, "A"); break; - case DNS_RRTYPE_PTR: strcpy(acRRName, "PTR"); break; - case DNS_RRTYPE_TXT: strcpy(acRRName, "TXT"); break; - case DNS_RRTYPE_AAAA: strcpy(acRRName, "AAAA"); break; - case DNS_RRTYPE_SRV: strcpy(acRRName, "SRV"); break; - case DNS_RRTYPE_NSEC: strcpy(acRRName, "NSEC"); break; - case DNS_RRTYPE_ANY: strcpy(acRRName, "ANY"); break; - default: - sprintf(acRRName, "Unknown(0x%04X)", p_u16RRType); // MAX 15! +#ifdef MDNS_IPV4_SUPPORT + case DNS_RRTYPE_A: strcpy(acRRName, "A"); break; +#endif + case DNS_RRTYPE_PTR: strcpy(acRRName, "PTR"); break; + case DNS_RRTYPE_TXT: strcpy(acRRName, "TXT"); break; +#ifdef MDNS_IPV6_SUPPORT + case DNS_RRTYPE_AAAA: strcpy(acRRName, "AAAA"); break; +#endif + case DNS_RRTYPE_SRV: strcpy(acRRName, "SRV"); break; + case clsConsts::u8DNS_RRTYPE_NSEC: strcpy(acRRName, "NSEC"); break; + case DNS_RRTYPE_ANY: strcpy(acRRName, "ANY"); break; + default: sprintf(acRRName, "Unknown(0x%04X)", p_u16RRType); // MAX 15! } return acRRName; } /* - MDNSResponder::clsHost::_RRClass2String + clsLEAmDNS2_Host::_RRClass2String + */ -const char* MDNSResponder::clsHost::_RRClass2String(uint16_t p_u16RRClass, - bool p_bIsQuery) const +const char* clsLEAMDNSHost::_RRClass2String(uint16_t p_u16RRClass, + bool p_bIsQuery) const { static char acClassString[16]; *acClassString = 0; @@ -227,9 +215,10 @@ const char* MDNSResponder::clsHost::_RRClass2String(uint16_t p_u16RRClass, } /* - MDNSResponder::clsHost::_replyFlags2String + clsLEAmDNS2_Host::_replyFlags2String + */ -const char* MDNSResponder::clsHost::_replyFlags2String(uint32_t p_u32ReplyFlags) const +const char* clsLEAMDNSHost::_replyFlags2String(uint32_t p_u32ReplyFlags) const { static char acFlagsString[64]; @@ -276,29 +265,41 @@ const char* MDNSResponder::clsHost::_replyFlags2String(uint32_t p_u32ReplyFlags) strcpy(acFlagsString, "none"); } + // Remove trailing spaces + while ((*acFlagsString) && + (' ' == acFlagsString[strlen(acFlagsString) - 1])) + { + acFlagsString[strlen(acFlagsString) - 1] = 0; + } + return acFlagsString; // 63 } /* - MDNSResponder::clsHost::_NSECBitmap2String + clsLEAmDNS2_Host::_NSECBitmap2String + */ -const char* MDNSResponder::clsHost::_NSECBitmap2String(const stcNSECBitmap* p_pNSECBitmap) const +const char* clsLEAMDNSHost::_NSECBitmap2String(const clsNSECBitmap* p_pNSECBitmap) const { static char acFlagsString[32]; *acFlagsString = 0; +#ifdef MDNS_IPV4_SUPPORT if (p_pNSECBitmap->getBit(DNS_RRTYPE_A)) { strcat(acFlagsString, "A "); // 2 } +#endif if (p_pNSECBitmap->getBit(DNS_RRTYPE_PTR)) { strcat(acFlagsString, "PTR "); // 4 } +#ifdef MDNS_IPV6_SUPPORT if (p_pNSECBitmap->getBit(DNS_RRTYPE_AAAA)) { strcat(acFlagsString, "AAAA "); // 5 } +#endif if (p_pNSECBitmap->getBit(DNS_RRTYPE_TXT)) { strcat(acFlagsString, "TXT "); // 4 @@ -307,7 +308,7 @@ const char* MDNSResponder::clsHost::_NSECBitmap2String(const stcNSECBitmap* p_pN { strcat(acFlagsString, "SRV "); // 4 } - if (p_pNSECBitmap->getBit(DNS_RRTYPE_NSEC)) + if (p_pNSECBitmap->getBit(clsConsts::u8DNS_RRTYPE_NSEC)) { strcat(acFlagsString, "NSEC "); // 5 } @@ -322,6 +323,12 @@ const char* MDNSResponder::clsHost::_NSECBitmap2String(const stcNSECBitmap* p_pN #endif // DEBUG_ESP_MDNS_RESPONDER + } // namespace MDNSImplementation + } // namespace esp8266 + + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp new file mode 100644 index 0000000000..b4db3c0531 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp @@ -0,0 +1,3253 @@ +/* + LEAmDNS2Host_Structs.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "LEAmDNS2Host.h" + + +namespace esp8266 +{ + + +namespace experimental +{ + + +/** + Internal CLASSES & STRUCTS +*/ + +/** + clsLEAMDNSHost::clsServiceTxt + + One MDNS TXT item. + m_pcValue may be '\0'. + Objects can be chained together (list). + A 'm_bTemp' flag differentiates between static and dynamic items. + Output as byte array 'c#=1' is supported. +*/ + +/* + clsLEAMDNSHost::clsServiceTxt::clsServiceTxt constructor + +*/ +clsLEAMDNSHost::clsServiceTxt::clsServiceTxt(const char* p_pcKey /*= 0*/, + const char* p_pcValue /*= 0*/, + bool p_bTemp /*= false*/) + : m_pcKey(0), + m_pcValue(0), + m_bTemp(p_bTemp) +{ + setKey(p_pcKey); + setValue(p_pcValue); +} + +/* + clsLEAMDNSHost::clsServiceTxt::clsServiceTxt copy-constructor + +*/ +clsLEAMDNSHost::clsServiceTxt::clsServiceTxt(const clsLEAMDNSHost::clsServiceTxt& p_Other) + : m_pcKey(0), + m_pcValue(0), + m_bTemp(false) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsServiceTxt::~stcServiceTxt destructor + +*/ +clsLEAMDNSHost::clsServiceTxt::~clsServiceTxt(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsServiceTxt::operator= + +*/ +clsLEAMDNSHost::clsServiceTxt& clsLEAMDNSHost::clsServiceTxt::operator=(const clsLEAMDNSHost::clsServiceTxt& p_Other) +{ + if (&p_Other != this) + { + clear(); + set(p_Other.m_pcKey, p_Other.m_pcValue, p_Other.m_bTemp); + } + return *this; +} + +/* + clsLEAMDNSHost::clsServiceTxt::clear + +*/ +bool clsLEAMDNSHost::clsServiceTxt::clear(void) +{ + releaseKey(); + releaseValue(); + return true; +} + +/* + clsLEAMDNSHost::clsServiceTxt::allocKey + +*/ +char* clsLEAMDNSHost::clsServiceTxt::allocKey(size_t p_stLength) +{ + releaseKey(); + if (p_stLength) + { + m_pcKey = new char[p_stLength + 1]; + } + return m_pcKey; +} + +/* + clsLEAMDNSHost::clsServiceTxt::setKey + +*/ +bool clsLEAMDNSHost::clsServiceTxt::setKey(const char* p_pcKey, + size_t p_stLength) +{ + bool bResult = false; + + releaseKey(); + if (p_stLength) + { + if (allocKey(p_stLength)) + { + strncpy(m_pcKey, p_pcKey, p_stLength); + m_pcKey[p_stLength] = 0; + bResult = true; + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxt::setKey + +*/ +bool clsLEAMDNSHost::clsServiceTxt::setKey(const char* p_pcKey) +{ + return setKey(p_pcKey, (p_pcKey ? strlen(p_pcKey) : 0)); +} + +/* + clsLEAMDNSHost::clsServiceTxt::releaseKey + +*/ +bool clsLEAMDNSHost::clsServiceTxt::releaseKey(void) +{ + if (m_pcKey) + { + delete[] m_pcKey; + m_pcKey = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsServiceTxt::allocValue + +*/ +char* clsLEAMDNSHost::clsServiceTxt::allocValue(size_t p_stLength) +{ + releaseValue(); + if (p_stLength) + { + m_pcValue = new char[p_stLength + 1]; + } + return m_pcValue; +} + +/* + clsLEAMDNSHost::clsServiceTxt::setValue + +*/ +bool clsLEAMDNSHost::clsServiceTxt::setValue(const char* p_pcValue, + size_t p_stLength) +{ + bool bResult = false; + + releaseValue(); + if (p_stLength) + { + if (allocValue(p_stLength)) + { + strncpy(m_pcValue, p_pcValue, p_stLength); + m_pcValue[p_stLength] = 0; + bResult = true; + } + } + else + { + // No value -> also OK + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxt::setValue + +*/ +bool clsLEAMDNSHost::clsServiceTxt::setValue(const char* p_pcValue) +{ + return setValue(p_pcValue, (p_pcValue ? strlen(p_pcValue) : 0)); +} + +/* + clsLEAMDNSHost::clsServiceTxt::releaseValue + +*/ +bool clsLEAMDNSHost::clsServiceTxt::releaseValue(void) +{ + if (m_pcValue) + { + delete[] m_pcValue; + m_pcValue = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsServiceTxt::set + +*/ +bool clsLEAMDNSHost::clsServiceTxt::set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp /*= false*/) +{ + m_bTemp = p_bTemp; + return ((setKey(p_pcKey)) && + (setValue(p_pcValue))); +} + +/* + clsLEAMDNSHost::clsServiceTxt::update + +*/ +bool clsLEAMDNSHost::clsServiceTxt::update(const char* p_pcValue) +{ + return setValue(p_pcValue); +} + +/* + clsLEAMDNSHost::clsServiceTxt::length + + length of eg. 'c#=1' without any closing '\0' + +*/ +size_t clsLEAMDNSHost::clsServiceTxt::length(void) const +{ + size_t stLength = 0; + if (m_pcKey) + { + stLength += strlen(m_pcKey); // Key + stLength += 1; // '=' + stLength += (m_pcValue ? strlen(m_pcValue) : 0); // Value + } + return stLength; +} + + +/** + clsLEAMDNSHost::clsServiceTxts + + A list of zero or more MDNS TXT (stcServiceTxt) items. + Dynamic TXT items can be removed by 'removeTempTxts'. + A TXT item can be looked up by its 'key' member. + Export as ';'-separated byte array is supported. + Export as 'length byte coded' byte array is supported. + Comparison ((all A TXT items in B and equal) AND (all B TXT items in A and equal)) is supported. + +*/ + +/* + clsLEAMDNSHost::clsServiceTxts::clsServiceTxts contructor + +*/ +clsLEAMDNSHost::clsServiceTxts::clsServiceTxts(void) + : m_pcCache(0) +{ +} + +/* + clsLEAMDNSHost::clsServiceTxts::clsServiceTxts copy-constructor + +*/ +clsLEAMDNSHost::clsServiceTxts::clsServiceTxts(const clsServiceTxts& p_Other) + : m_pcCache(0) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsServiceTxts::~stcServiceTxts destructor + +*/ +clsLEAMDNSHost::clsServiceTxts::~clsServiceTxts(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsServiceTxts::operator= + +*/ +clsLEAMDNSHost::clsServiceTxts& clsLEAMDNSHost::clsServiceTxts::operator=(const clsServiceTxts& p_Other) +{ + if (this != &p_Other) + { + clear(); + + for (const clsServiceTxt* pOtherTxt : p_Other.m_Txts) + { + add(new clsServiceTxt(*pOtherTxt)); + } + } + return *this; +} + +/* + clsLEAMDNSHost::clsServiceTxts::clear + +*/ +bool clsLEAMDNSHost::clsServiceTxts::clear(void) +{ + for (clsServiceTxt* pTxt : m_Txts) + { + delete pTxt; + } + m_Txts.clear(); + + return clearCache(); +} + +/* + clsLEAMDNSHost::clsServiceTxts::clearCache + +*/ +bool clsLEAMDNSHost::clsServiceTxts::clearCache(void) +{ + if (m_pcCache) + { + delete[] m_pcCache; + m_pcCache = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsServiceTxts::add + +*/ +bool clsLEAMDNSHost::clsServiceTxts::add(clsLEAMDNSHost::clsServiceTxt* p_pTxt) +{ + bool bResult = false; + + if (p_pTxt) + { + m_Txts.push_back(p_pTxt); + bResult = true; + } + return ((clearCache()) && + (bResult)); +} + +/* + clsLEAMDNSHost::clsServiceTxts::remove + +*/ +bool clsLEAMDNSHost::clsServiceTxts::remove(clsServiceTxt* p_pTxt) +{ + bool bResult = false; + + clsServiceTxt::list::iterator it(p_pTxt + ? std::find(m_Txts.begin(), m_Txts.end(), p_pTxt) + : m_Txts.end()); + if (m_Txts.end() != it) + { + m_Txts.erase(it); + delete p_pTxt; + + bResult = true; + } + return ((clearCache()) && + (bResult)); +} + +/* + clsLEAMDNSHost::clsServiceTxts::count + +*/ +size_t clsLEAMDNSHost::clsServiceTxts::count(void) const +{ + size_t stResult = m_Txts.size(); + return stResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::removeTempTxts + +*/ +bool clsLEAMDNSHost::clsServiceTxts::removeTempTxts(void) +{ + bool bResult = true; + + // Delete content + clsServiceTxt::list tempTxts; + for (clsServiceTxt* pTxt : m_Txts) + { + if (pTxt->m_bTemp) + { + tempTxts.push_back(pTxt); + delete pTxt; + } + } + // Remove objects from list + for (clsServiceTxt* pTempTxt : tempTxts) + { + m_Txts.remove(pTempTxt); + } + return ((clearCache()) && + (bResult)); +} + +/* + clsLEAMDNSHost::clsServiceTxts::find + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsServiceTxts::find(const char* p_pcKey) +{ + clsServiceTxt* pResult = 0; + + for (clsServiceTxt* pTxt : m_Txts) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::find (const) + +*/ +const clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsServiceTxts::find(const char* p_pcKey) const +{ + const clsServiceTxt* pResult = 0; + + for (const clsServiceTxt* pTxt : m_Txts) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::find + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsServiceTxts::find(const clsServiceTxt* p_pTxt) +{ + clsServiceTxt* pResult = 0; + + for (clsServiceTxt* pTxt : m_Txts) + { + if (p_pTxt == pTxt) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::length + +*/ +size_t clsLEAMDNSHost::clsServiceTxts::length(void) const +{ + size_t szLength = 0; + + for (clsServiceTxt* pTxt : m_Txts) + { + szLength += 1; // Length byte + szLength += pTxt->length(); // Text + } + return szLength; +} + +/* + clsLEAMDNSHost::clsServiceTxts::c_strLength + + (incl. closing '\0'). Length bytes place is used for delimiting ';' and closing '\0' + +*/ +size_t clsLEAMDNSHost::clsServiceTxts::c_strLength(void) const +{ + return length(); +} + +/* + clsLEAMDNSHost::clsServiceTxts::c_str + +*/ +bool clsLEAMDNSHost::clsServiceTxts::c_str(char* p_pcBuffer) +{ + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + char* pcCursor = p_pcBuffer; + *pcCursor = 0; + for (const clsServiceTxt* pTxt : m_Txts) + { + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + if (pcCursor != p_pcBuffer) + { + *pcCursor++ = ';'; + } + strncpy(pcCursor, pTxt->m_pcKey, stLength); pcCursor[stLength] = 0; + pcCursor += stLength; + *pcCursor++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + strncpy(pcCursor, pTxt->m_pcValue, stLength); pcCursor[stLength] = 0; + pcCursor += stLength; + } + } + else + { + break; + } + } + *pcCursor++ = 0; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::c_str + +*/ +const char* clsLEAMDNSHost::clsServiceTxts::c_str(void) const +{ + + if ((!m_pcCache) && + (m_Txts.size()) && + ((((clsServiceTxts*)this)->m_pcCache = new char[c_strLength()]))) // TRANSPARENT caching + { + ((clsServiceTxts*)this)->c_str(m_pcCache); + } + return m_pcCache; +} + +/* + clsLEAMDNSHost::clsServiceTxts::bufferLength + + (incl. closing '\0'). + +*/ +size_t clsLEAMDNSHost::clsServiceTxts::bufferLength(void) const +{ + return (length() + 1); +} + +/* + clsLEAMDNSHost::clsServiceTxts::toBuffer + +*/ +bool clsLEAMDNSHost::clsServiceTxts::buffer(char* p_pcBuffer) +{ + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + *p_pcBuffer = 0; + for (const clsServiceTxt* pTxt : m_Txts) + { + *(unsigned char*)p_pcBuffer++ = pTxt->length(); + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + memcpy(p_pcBuffer, pTxt->m_pcKey, stLength); + p_pcBuffer += stLength; + *p_pcBuffer++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + memcpy(p_pcBuffer, pTxt->m_pcValue, stLength); + p_pcBuffer += stLength; + } + } + else + { + break; + } + } + *p_pcBuffer++ = 0; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::compare + +*/ +bool clsLEAMDNSHost::clsServiceTxts::compare(const clsLEAMDNSHost::clsServiceTxts& p_Other) const +{ + bool bResult = false; + + if ((bResult = (length() == p_Other.length()))) + { + // Compare A->B + for (const clsServiceTxt* pTxt : m_Txts) + { + const clsServiceTxt* pOtherTxt = p_Other.find(pTxt->m_pcKey); + if (!((bResult = ((pOtherTxt) && + (pTxt->m_pcValue) && + (pOtherTxt->m_pcValue) && + (strlen(pTxt->m_pcValue) == strlen(pOtherTxt->m_pcValue)) && + (0 == strcmp(pTxt->m_pcValue, pOtherTxt->m_pcValue)))))) + { + break; + } + } + // Compare B->A + for (const clsServiceTxt* pOtherTxt : p_Other.m_Txts) + { + const clsServiceTxt* pTxt = find(pOtherTxt->m_pcKey); + if (!((bResult = ((pTxt) && + (pOtherTxt->m_pcValue) && + (pTxt->m_pcValue) && + (strlen(pOtherTxt->m_pcValue) == strlen(pTxt->m_pcValue)) && + (0 == strcmp(pOtherTxt->m_pcValue, pTxt->m_pcValue)))))) + { + break; + } + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::operator== + +*/ +bool clsLEAMDNSHost::clsServiceTxts::operator==(const clsServiceTxts& p_Other) const +{ + return compare(p_Other); +} + +/* + clsLEAMDNSHost::clsServiceTxts::operator!= + +*/ +bool clsLEAMDNSHost::clsServiceTxts::operator!=(const clsServiceTxts& p_Other) const +{ + return !compare(p_Other); +} + + +/** + clsLEAMDNSHost::clsProbeInformation_Base + + Probing status information for a host or service domain + +*/ + +/* + clsLEAMDNSHost::clsProbeInformation_Base::clsProbeInformation_Base constructor +*/ +clsLEAMDNSHost::clsProbeInformation_Base::clsProbeInformation_Base(void) + : m_ProbingStatus(enuProbingStatus::WaitingForData), + m_u8SentCount(0), + m_Timeout(std::numeric_limits::max()), + m_bConflict(false), + m_bTiebreakNeeded(false) +{ +} + +/* + clsLEAMDNSHost::clsProbeInformation_Base::clear +*/ +bool clsLEAMDNSHost::clsProbeInformation_Base::clear(void) +{ + m_ProbingStatus = enuProbingStatus::WaitingForData; + m_u8SentCount = 0; + m_Timeout.reset(std::numeric_limits::max()); + m_bConflict = false; + m_bTiebreakNeeded = false; + + return true; +} + + +/** + clsLEAMDNSHost::clsProbeInformation_Host + + Probing status information for a host or service domain + +*/ + +/* + clsLEAMDNSHost::clsProbeInformation::clsProbeInformation constructor +*/ +clsLEAMDNSHost::clsProbeInformation::clsProbeInformation(void) + : m_fnProbeResultCallback(0) +{ +} + +/* + clsLEAMDNSHost::clsProbeInformation::clear +*/ +bool clsLEAMDNSHost::clsProbeInformation::clear(bool p_bClearUserdata /*= false*/) +{ + if (p_bClearUserdata) + { + m_fnProbeResultCallback = 0; + } + return clsProbeInformation_Base::clear(); +} + + +/** + clsLEAMDNSHost::clsService::clsProbeInformation + + Probing status information for a host or service domain + +*/ + +/* + clsLEAMDNSHost::clsService::clsProbeInformation::clsProbeInformation constructor +*/ +clsLEAMDNSHost::clsService::clsProbeInformation::clsProbeInformation(void) + : m_fnProbeResultCallback(0) +{ +} + +/* + clsLEAMDNSHost::clsService::clsProbeInformation::clear +*/ +bool clsLEAMDNSHost::clsService::clsProbeInformation::clear(bool p_bClearUserdata /*= false*/) +{ + if (p_bClearUserdata) + { + m_fnProbeResultCallback = 0; + } + return clsProbeInformation_Base::clear(); +} + + +/** + clsLEAMDNSHost::clsService + + A MDNS service object (to be announced by the MDNS responder) + The service instance may be '\0'; in this case the hostname is used + and the flag m_bAutoName is set. If the hostname changes, all 'auto- + named' services are renamed also. + m_u8Replymask is used while preparing a response to a MDNS query. It is + resetted in '_sendMDNSMessage' afterwards. +*/ + +/* + clsLEAMDNSHost::clsService::clsService constructor + +*/ +clsLEAMDNSHost::clsService::clsService(void) + : m_pcInstanceName(0), + m_bAutoName(false), + m_pcType(0), + m_pcProtocol(0), + m_u16Port(0), + m_u32ReplyMask(0), + m_fnTxtCallback(0) +{ +} + +/* + clsLEAMDNSHost::clsService::~clsService destructor + +*/ +clsLEAMDNSHost::clsService::~clsService(void) +{ + _releaseInstanceName(); + _releaseType(); + _releaseProtocol(); +} + +/* + clsLEAMDNSHost::clsService::setInstanceName + +*/ +bool clsLEAMDNSHost::clsService::setInstanceName(const char* p_pcInstanceName) +{ + bool bResult = false; + + _releaseInstanceName(); + size_t stLength = (p_pcInstanceName ? strlen(p_pcInstanceName) : 0); + if ((stLength) && + (stLength <= clsConsts::stDomainLabelMaxLength)) + { + if ((bResult = (0 != (m_pcInstanceName = new char[stLength + 1])))) + { + strncpy(m_pcInstanceName, p_pcInstanceName, stLength); + m_pcInstanceName[stLength] = 0; + + _resetProbeStatus(); + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::indexInstanceName + +*/ +bool clsLEAMDNSHost::clsService::indexInstanceName(void) +{ + bool bResult = false; + + if ((bResult = setInstanceName(clsLEAMDNSHost::indexDomainName(m_pcInstanceName, "#", 0)))) + { + _resetProbeStatus(); + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::instanceName + +*/ +const char* clsLEAMDNSHost::clsService::instanceName(void) const +{ + return m_pcInstanceName; +} + +/* + clsLEAMDNSHost::clsService::_releaseInstanceName + +*/ +bool clsLEAMDNSHost::clsService::_releaseInstanceName(void) +{ + if (m_pcInstanceName) + { + delete[] m_pcInstanceName; + m_pcInstanceName = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsService::setType + +*/ +bool clsLEAMDNSHost::clsService::setType(const char* p_pcType) +{ + bool bResult = false; + + _releaseType(); + size_t stLength = (p_pcType ? strlen(p_pcType) : 0); + if ((stLength) && + (stLength <= clsConsts::stServiceTypeMaxLength)) + { + if ((bResult = (0 != (m_pcType = new char[stLength + 1])))) + { + strncpy(m_pcType, p_pcType, stLength); + m_pcType[stLength] = 0; + + _resetProbeStatus(); + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::type + +*/ +const char* clsLEAMDNSHost::clsService::type(void) const +{ + return m_pcType; +} + +/* + clsLEAMDNSHost::clsService::_releaseType + +*/ +bool clsLEAMDNSHost::clsService::_releaseType(void) +{ + if (m_pcType) + { + delete[] m_pcType; + m_pcType = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsService::setProtocol + +*/ +bool clsLEAMDNSHost::clsService::setProtocol(const char* p_pcProtocol) +{ + bool bResult = false; + + _releaseProtocol(); + size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); + if ((stLength) && + (stLength <= clsConsts::stServiceProtocolMaxLength)) + { + if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) + { + strncpy(m_pcProtocol, p_pcProtocol, stLength); + m_pcProtocol[stLength] = 0; + + _resetProbeStatus(); + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::protocol + +*/ +const char* clsLEAMDNSHost::clsService::protocol(void) const +{ + return m_pcProtocol; +} + +/* + clsLEAMDNSHost::clsService::_releaseProtocol + +*/ +bool clsLEAMDNSHost::clsService::_releaseProtocol(void) +{ + if (m_pcProtocol) + { + delete[] m_pcProtocol; + m_pcProtocol = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsService::setPort + +*/ +bool clsLEAMDNSHost::clsService::setPort(uint16_t p_u16Port) +{ + bool bResult = false; + + if ((bResult = (0 != p_u16Port))) + { + m_u16Port = p_u16Port; + + _resetProbeStatus(); + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::port + +*/ +uint16_t clsLEAMDNSHost::clsService::port(void) const +{ + return m_u16Port; +} + +/* + clsLEAMDNSHost::clsService::setProbeResultCallback + +*/ +bool clsLEAMDNSHost::clsService::setProbeResultCallback(fnProbeResultCallback p_fnProbeResultCallback) +{ + m_ProbeInformation.m_fnProbeResultCallback = p_fnProbeResultCallback; + return true; +} + +/* + clsLEAMDNSHost::clsService::probeStatus + +*/ +bool clsLEAMDNSHost::clsService::probeStatus(void) const +{ + return (clsProbeInformation_Base::enuProbingStatus::DoneFinally == m_ProbeInformation.m_ProbingStatus); +} + +/* + clsLEAMDNSHost::clsService::_resetProbeStatus + +*/ +void clsLEAMDNSHost::clsService::_resetProbeStatus(void) +{ + m_ProbeInformation.clear(false); + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::ReadyToStart; +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (const char*) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_pcKey, p_pcValue, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (uint32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + uint32_t p_u32Value) +{ + return _addServiceTxt(p_pcKey, p_u32Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (uint16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + uint16_t p_u16Value) +{ + return _addServiceTxt(p_pcKey, p_u16Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (uint8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + uint8_t p_u8Value) +{ + return _addServiceTxt(p_pcKey, p_u8Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (int32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + int32_t p_i32Value) +{ + return _addServiceTxt(p_pcKey, p_i32Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (int16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + int16_t p_i16Value) +{ + return _addServiceTxt(p_pcKey, p_i16Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (int8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + int8_t p_i8Value) +{ + return _addServiceTxt(p_pcKey, p_i8Value, false); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (const char*) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_pcKey, p_pcValue, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (uint32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + uint32_t p_u32Value) +{ + return _addServiceTxt(p_pcKey, p_u32Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (uint16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + uint16_t p_u16Value) +{ + return _addServiceTxt(p_pcKey, p_u16Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (uint8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + uint8_t p_u8Value) +{ + return _addServiceTxt(p_pcKey, p_u8Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (int32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + int32_t p_i32Value) +{ + return _addServiceTxt(p_pcKey, p_i32Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (int16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + int16_t p_i16Value) +{ + return _addServiceTxt(p_pcKey, p_i16Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (int8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + int8_t p_i8Value) +{ + return _addServiceTxt(p_pcKey, p_i8Value, true); +} + +/* + clsLEAMDNSHost::clsService::setDynamicServiceTxtCallback + +*/ +bool clsLEAMDNSHost::clsService::setDynamicServiceTxtCallback(fnDynamicServiceTxtCallback p_fnCallback) +{ + m_fnTxtCallback = p_fnCallback; + return true; +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (const char*) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp) +{ + clsServiceTxt* pServiceTxt = 0; + + if ((p_pcKey) && + (*p_pcKey)) + { + if ((pServiceTxt = m_Txts.find(p_pcKey))) + { + // Change existing TXT + if (clsConsts::stServiceTxtMaxLength > (m_Txts.length() - + (pServiceTxt->m_pcValue ? strlen(pServiceTxt->m_pcValue) : 0) + + (p_pcValue ? strlen(p_pcValue) : 0))) + { + // Enough space left for changed content + if (!pServiceTxt->update(p_pcValue)) + { + // FAILED to update + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[LEAmDNS2_Host] clsService::_addServiceTxt: FAILED to update TXT item '%s'!\n"), p_pcKey)); + pServiceTxt = 0; + } + } + else + { + // NOT enough space for changed TXT content + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[LEAmDNS2_Host] clsService::_addServiceTxt: FAILED to change TXT item '%s' (too large)!\n"), p_pcKey)); + pServiceTxt = 0; + } + } + else + { + // Create new TXT + if (clsConsts::stServiceTxtMaxLength > (m_Txts.length() + + 1 + // Length byte + (p_pcKey ? strlen(p_pcKey) : 0) + + 1 + // '=' + (p_pcValue ? strlen(p_pcValue) : 0))) + { + if (!(((pServiceTxt = new clsServiceTxt)) && + (pServiceTxt->set(p_pcKey, p_pcValue, p_bTemp)) && + (m_Txts.add(pServiceTxt)))) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[LEAmDNS2_Host] clsService::_addServiceTxt: FAILED to add TXT item '%s'!\n"), p_pcKey)); + if (pServiceTxt) + { + delete pServiceTxt; + pServiceTxt = 0; + } + } + } + else + { + // NOT enough space for added TXT item + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[LEAmDNS2_Host] clsService::_addServiceTxt: FAILED to add TXT item '%s' (too large)!\n"), p_pcKey)); + pServiceTxt = 0; + } + } + } + return pServiceTxt; +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (uint32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + uint32_t p_u32Value, + bool p_bTemp) +{ + char acValueBuffer[16]; // 32-bit max 10 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%u", p_u32Value); + + return _addServiceTxt(p_pcKey, acValueBuffer, p_bTemp); +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (uint16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + uint16_t p_u16Value, + bool p_bTemp) +{ + char acValueBuffer[8]; // 16-bit max 5 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hu", p_u16Value); + + return _addServiceTxt(p_pcKey, acValueBuffer, p_bTemp); +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (uint8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + uint8_t p_u8Value, + bool p_bTemp) +{ + char acValueBuffer[8]; // 8-bit max 3 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hhu", p_u8Value); + + return _addServiceTxt(p_pcKey, acValueBuffer, p_bTemp); +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (int32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + int32_t p_i32Value, + bool p_bTemp) +{ + char acValueBuffer[16]; // 32-bit max 10 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%i", p_i32Value); + + return _addServiceTxt(p_pcKey, acValueBuffer, p_bTemp); +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (int16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + int16_t p_i16Value, + bool p_bTemp) +{ + char acValueBuffer[8]; // 16-bit max 5 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hi", p_i16Value); + + return _addServiceTxt(p_pcKey, acValueBuffer, p_bTemp); +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (int8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + int8_t p_i8Value, + bool p_bTemp) +{ + char acValueBuffer[8]; // 8-bit max 3 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hhi", p_i8Value); + + return _addServiceTxt(p_pcKey, acValueBuffer, p_bTemp); +} + + +/** + clsLEAMDNSHost::clsMsgHeader + + A MDNS message header. + +*/ + +/* + clsLEAMDNSHost::clsMsgHeader::clsMsgHeader + +*/ +clsLEAMDNSHost::clsMsgHeader::clsMsgHeader(uint16_t p_u16ID /*= 0*/, + bool p_bQR /*= false*/, + uint8_t p_u8Opcode /*= 0*/, + bool p_bAA /*= false*/, + bool p_bTC /*= false*/, + bool p_bRD /*= false*/, + bool p_bRA /*= false*/, + uint8_t p_u8RCode /*= 0*/, + uint16_t p_u16QDCount /*= 0*/, + uint16_t p_u16ANCount /*= 0*/, + uint16_t p_u16NSCount /*= 0*/, + uint16_t p_u16ARCount /*= 0*/) + : m_u16ID(p_u16ID), + m_1bQR(p_bQR), m_4bOpcode(p_u8Opcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), + m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_u8RCode), + m_u16QDCount(p_u16QDCount), + m_u16ANCount(p_u16ANCount), + m_u16NSCount(p_u16NSCount), + m_u16ARCount(p_u16ARCount) +{ +} + + +/** + clsLEAMDNSHost::clsRRDomain + + A MDNS domain object. + The labels of the domain are stored (DNS-like encoded) in 'm_acName': + [length byte]varlength label[length byte]varlength label[0] + 'm_u16NameLength' stores the used length of 'm_acName'. + Dynamic label addition is supported. + Comparison is supported. + Export as byte array 'esp8266.local' is supported. + +*/ + +/* + clsLEAMDNSHost::clsRRDomain::clsRRDomain constructor + +*/ +clsLEAMDNSHost::clsRRDomain::clsRRDomain(void) + : m_u16NameLength(0), + m_pcDecodedName(0) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRDomain::clsRRDomain copy-constructor + +*/ +clsLEAMDNSHost::clsRRDomain::clsRRDomain(const clsRRDomain& p_Other) + : m_u16NameLength(0), + m_pcDecodedName(0) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsRRDomain::clsRRDomain destructor + +*/ +clsLEAMDNSHost::clsRRDomain::~clsRRDomain(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRDomain::operator = + +*/ +clsLEAMDNSHost::clsRRDomain& clsLEAMDNSHost::clsRRDomain::operator=(const clsRRDomain& p_Other) +{ + if (&p_Other != this) + { + clear(); + memcpy(m_acName, p_Other.m_acName, sizeof(m_acName)); + m_u16NameLength = p_Other.m_u16NameLength; + } + return *this; +} + +/* + clsLEAMDNSHost::clsRRDomain::clear + +*/ +bool clsLEAMDNSHost::clsRRDomain::clear(void) +{ + memset(m_acName, 0, sizeof(m_acName)); + m_u16NameLength = 0; + return clearNameCache(); +} + +/* + clsLEAMDNSHost::clsRRDomain::clearNameCache + +*/ +bool clsLEAMDNSHost::clsRRDomain::clearNameCache(void) +{ + if (m_pcDecodedName) + { + delete[] m_pcDecodedName; + m_pcDecodedName = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsRRDomain::addLabel + +*/ +bool clsLEAMDNSHost::clsRRDomain::addLabel(const char* p_pcLabel, + bool p_bPrependUnderline /*= false*/) +{ + bool bResult = false; + + size_t stLength = (p_pcLabel + ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) + : 0); + if ((clsConsts::stDomainLabelMaxLength >= stLength) && + (clsConsts::stDomainMaxLength >= (m_u16NameLength + (1 + stLength)))) + { + // Length byte + m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! + ++m_u16NameLength; + // Label + if (stLength) + { + if (p_bPrependUnderline) + { + m_acName[m_u16NameLength++] = '_'; + --stLength; + } + strncpy(&(m_acName[m_u16NameLength]), p_pcLabel, stLength); m_acName[m_u16NameLength + stLength] = 0; + m_u16NameLength += stLength; + } + bResult = clearNameCache(); + } + return bResult; +} + +/* + clsLEAMDNSHost::clsRRDomain::compare + +*/ +bool clsLEAMDNSHost::clsRRDomain::compare(const clsRRDomain& p_Other) const +{ + bool bResult = false; + + if (m_u16NameLength == p_Other.m_u16NameLength) + { + const char* pT = m_acName; + const char* pO = p_Other.m_acName; + while ((pT) && + (pO) && + (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND + (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content + { + if (*((unsigned char*)pT)) // Not 0 + { + pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and lenght + pO += (1 + * ((unsigned char*)pO)); + } + else // Is 0 -> Successfully reached the end + { + bResult = true; + break; + } + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsRRDomain::operator == + +*/ +bool clsLEAMDNSHost::clsRRDomain::operator==(const clsRRDomain& p_Other) const +{ + return compare(p_Other); +} + +/* + clsLEAMDNSHost::clsRRDomain::operator != + +*/ +bool clsLEAMDNSHost::clsRRDomain::operator!=(const clsRRDomain& p_Other) const +{ + return !compare(p_Other); +} + +/* + clsLEAMDNSHost::clsRRDomain::operator > + +*/ +bool clsLEAMDNSHost::clsRRDomain::operator>(const clsRRDomain& p_Other) const +{ + // TODO: Check, if this is a good idea... + return !compare(p_Other); +} + +/* + clsLEAMDNSHost::clsRRDomain::c_strLength + +*/ +size_t clsLEAMDNSHost::clsRRDomain::c_strLength(void) const +{ + size_t stLength = 0; + + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + stLength += (*pucLabelLength + 1 /* +1 for '.' or '\0'*/); + pucLabelLength += (*pucLabelLength + 1); + } + return stLength; +} + +/* + clsLEAMDNSHost::clsRRDomain::c_str (const) + +*/ +bool clsLEAMDNSHost::clsRRDomain::c_str(char* p_pcBuffer) const +{ + bool bResult = false; + + if (p_pcBuffer) + { + *p_pcBuffer = 0; + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + memcpy(p_pcBuffer, (const char*)(pucLabelLength + 1), *pucLabelLength); + p_pcBuffer += *pucLabelLength; + pucLabelLength += (*pucLabelLength + 1); + *p_pcBuffer++ = (*pucLabelLength ? '.' : '\0'); + } + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsRRDomain::c_str + +*/ +const char* clsLEAMDNSHost::clsRRDomain::c_str(void) const +{ + if ((!m_pcDecodedName) && + (m_u16NameLength) && + ((((clsRRDomain*)this)->m_pcDecodedName = new char[c_strLength()]))) // TRANSPARENT caching + { + ((clsRRDomain*)this)->c_str(m_pcDecodedName); + } + return m_pcDecodedName; +} + + +/** + clsLEAMDNSHost::clsRRAttributes + + A MDNS attributes object. + +*/ + +/* + clsLEAMDNSHost::clsRRAttributes::clsRRAttributes constructor + +*/ +clsLEAMDNSHost::clsRRAttributes::clsRRAttributes(uint16_t p_u16Type /*= 0*/, + uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) + : m_u16Type(p_u16Type), + m_u16Class(p_u16Class) +{ +} + +/* + clsLEAMDNSHost::clsRRAttributes::clsRRAttributes copy-constructor + +*/ +clsLEAMDNSHost::clsRRAttributes::clsRRAttributes(const clsLEAMDNSHost::clsRRAttributes& p_Other) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsRRAttributes::operator = + +*/ +clsLEAMDNSHost::clsRRAttributes& clsLEAMDNSHost::clsRRAttributes::operator=(const clsLEAMDNSHost::clsRRAttributes& p_Other) +{ + if (&p_Other != this) + { + m_u16Type = p_Other.m_u16Type; + m_u16Class = p_Other.m_u16Class; + } + return *this; +} + + +/** + clsLEAMDNSHost::clsRRHeader + + A MDNS record header (domain and attributes) object. + +*/ + +/* + clsLEAMDNSHost::clsRRHeader::clsRRHeader constructor + +*/ +clsLEAMDNSHost::clsRRHeader::clsRRHeader(void) +{ +} + +/* + clsLEAMDNSHost::clsRRHeader::clsRRHeader copy-constructor + +*/ +clsLEAMDNSHost::clsRRHeader::clsRRHeader(const clsRRHeader& p_Other) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsRRHeader::operator = + +*/ +clsLEAMDNSHost::clsRRHeader& clsLEAMDNSHost::clsRRHeader::operator=(const clsLEAMDNSHost::clsRRHeader& p_Other) +{ + if (&p_Other != this) + { + m_Domain = p_Other.m_Domain; + m_Attributes = p_Other.m_Attributes; + } + return *this; +} + +/* + clsLEAMDNSHost::clsRRHeader::clear + +*/ +bool clsLEAMDNSHost::clsRRHeader::clear(void) +{ + m_Domain.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRQuestion + + A MDNS question record object (header + question flags) + +*/ + +/* + clsLEAMDNSHost::clsRRQuestion::clsRRQuestion constructor +*/ +clsLEAMDNSHost::clsRRQuestion::clsRRQuestion(void) + : m_bUnicast(false) +{ +} + + +/** + clsLEAMDNSHost::clsNSECBitmap + + A MDNS question record object (header + question flags) + +*/ + +/* + clsLEAMDNSHost::clsNSECBitmap::clsNSECBitmap constructor + +*/ +clsLEAMDNSHost::clsNSECBitmap::clsNSECBitmap(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsNSECBitmap::clsNSECBitmap destructor + +*/ +bool clsLEAMDNSHost::clsNSECBitmap::clear(void) +{ + memset(m_au8BitmapData, 0, sizeof(m_au8BitmapData)); + return true; +} + +/* + clsLEAMDNSHost::clsNSECBitmap::length + +*/ +uint16_t clsLEAMDNSHost::clsNSECBitmap::length(void) const +{ + return sizeof(m_au8BitmapData); // 6 +} + +/* + clsLEAMDNSHost::clsNSECBitmap::setBit + +*/ +bool clsLEAMDNSHost::clsNSECBitmap::setBit(uint16_t p_u16Bit) +{ + bool bResult = false; + + if ((p_u16Bit) && + (length() > (p_u16Bit / 8))) // bit between 0..47(2F) + { + + uint8_t& ru8Byte = m_au8BitmapData[p_u16Bit / 8]; + uint8_t u8Flag = 1 << (7 - (p_u16Bit % 8)); // (7 - (0..7)) = 7..0 + + ru8Byte |= u8Flag; + + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsNSECBitmap::getBit + +*/ +bool clsLEAMDNSHost::clsNSECBitmap::getBit(uint16_t p_u16Bit) const +{ + bool bResult = false; + + if ((p_u16Bit) && + (length() > (p_u16Bit / 8))) // bit between 0..47(2F) + { + + uint8_t u8Byte = m_au8BitmapData[p_u16Bit / 8]; + uint8_t u8Flag = 1 << (7 - (p_u16Bit % 8)); // (7 - (0..7)) = 7..0 + + bResult = (u8Byte & u8Flag); + } + return bResult; +} + + +/** + clsLEAMDNSHost::clsRRAnswer + + A MDNS answer record object (header + answer content). + This is a 'virtual' base class for all other MDNS answer classes. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswer::clsRRAnswer constructor + +*/ +clsLEAMDNSHost::clsRRAnswer::clsRRAnswer(enuAnswerType p_AnswerType, + const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : m_pNext(0), + m_AnswerType(p_AnswerType), + m_Header(p_Header), + m_u32TTL(p_u32TTL) +{ + // Extract 'cache flush'-bit + m_bCacheFlush = (m_Header.m_Attributes.m_u16Class & 0x8000); + m_Header.m_Attributes.m_u16Class &= (~0x8000); +} + +/* + clsLEAMDNSHost::clsRRAnswer::~stcRRAnswer destructor + +*/ +clsLEAMDNSHost::clsRRAnswer::~clsRRAnswer(void) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswer::answerType + +*/ +clsLEAMDNSHost::enuAnswerType clsLEAMDNSHost::clsRRAnswer::answerType(void) const +{ + return m_AnswerType; +} + +/* + clsLEAMDNSHost::clsRRAnswer::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswer::clear(void) +{ + m_pNext = 0; + m_Header.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRAnswerA + + A MDNS A answer object. + Extends the base class by an IPv4 address member. + +*/ + +#ifdef MDNS_IPV4_SUPPORT +/* + clsLEAMDNSHost::clsRRAnswerA::clsRRAnswerA constructor + +*/ +clsLEAMDNSHost::clsRRAnswerA::clsRRAnswerA(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::A, p_Header, p_u32TTL), + m_IPAddress() +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerA::clsRRAnswerA destructor + +*/ +clsLEAMDNSHost::clsRRAnswerA::~clsRRAnswerA(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerA::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerA::clear(void) +{ + m_IPAddress = IPAddress(); + return true; +} +#endif + + +/** + clsLEAMDNSHost::clsRRAnswerPTR + + A MDNS PTR answer object. + Extends the base class by a MDNS domain member. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswerPTR::clsRRAnswerPTR constructor + +*/ +clsLEAMDNSHost::clsRRAnswerPTR::clsRRAnswerPTR(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::PTR, p_Header, p_u32TTL) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerPTR::~stcRRAnswerPTR destructor + +*/ +clsLEAMDNSHost::clsRRAnswerPTR::~clsRRAnswerPTR(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerPTR::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerPTR::clear(void) +{ + m_PTRDomain.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRAnswerTXT + + A MDNS TXT answer object. + Extends the base class by a MDNS TXT items list member. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswerTXT::clsRRAnswerTXT constructor + +*/ +clsLEAMDNSHost::clsRRAnswerTXT::clsRRAnswerTXT(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::TXT, p_Header, p_u32TTL) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerTXT::~stcRRAnswerTXT destructor + +*/ +clsLEAMDNSHost::clsRRAnswerTXT::~clsRRAnswerTXT(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerTXT::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerTXT::clear(void) +{ + m_Txts.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRAnswerAAAA + + A MDNS AAAA answer object. + Extends the base class by an IPv6 address member. + +*/ + +#ifdef MDNS_IPV6_SUPPORT +/* + clsLEAMDNSHost::clsRRAnswerAAAA::clsRRAnswerAAAA constructor + +*/ +clsLEAMDNSHost::clsRRAnswerAAAA::clsRRAnswerAAAA(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::AAAA, p_Header, p_u32TTL), + m_IPAddress() +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerAAAA::~stcRRAnswerAAAA destructor + +*/ +clsLEAMDNSHost::clsRRAnswerAAAA::~clsRRAnswerAAAA(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerAAAA::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerAAAA::clear(void) +{ + m_IPAddress = IPAddress(); + return true; +} +#endif + + +/** + clsLEAMDNSHost::clsRRAnswerSRV + + A MDNS SRV answer object. + Extends the base class by a port member. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswerSRV::clsRRAnswerSRV constructor + +*/ +clsLEAMDNSHost::clsRRAnswerSRV::clsRRAnswerSRV(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::SRV, p_Header, p_u32TTL), + m_u16Priority(0), + m_u16Weight(0), + m_u16Port(0) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerSRV::~stcRRAnswerSRV destructor + +*/ +clsLEAMDNSHost::clsRRAnswerSRV::~clsRRAnswerSRV(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerSRV::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerSRV::clear(void) +{ + m_u16Priority = 0; + m_u16Weight = 0; + m_u16Port = 0; + m_SRVDomain.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRAnswerGeneric + + An unknown (generic) MDNS answer object. + Extends the base class by a RDATA buffer member. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswerGeneric::clsRRAnswerGeneric constructor + +*/ +clsLEAMDNSHost::clsRRAnswerGeneric::clsRRAnswerGeneric(const clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::Generic, p_Header, p_u32TTL), + m_u16RDLength(0), + m_pu8RDData(0) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerGeneric::~stcRRAnswerGeneric destructor + +*/ +clsLEAMDNSHost::clsRRAnswerGeneric::~clsRRAnswerGeneric(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerGeneric::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerGeneric::clear(void) +{ + if (m_pu8RDData) + { + delete[] m_pu8RDData; + m_pu8RDData = 0; + } + m_u16RDLength = 0; + + return true; +} + + +/** + clsLEAMDNSHost::clsSendParameter + + A 'collection' of properties and flags for one MDNS query or response. + Mainly managed by the 'Control' functions. + The current offset in the UPD output buffer is tracked to be able to do + a simple host or service domain compression. + +*/ + +/** + clsLEAMDNSHost::clsSendParameter::clsDomainCacheItem + + A cached host or service domain, incl. the offset in the UDP output buffer. + +*/ + +/* + clsLEAMDNSHost::clsSendParameter::clsDomainCacheItem::clsDomainCacheItem constructor + +*/ +clsLEAMDNSHost::clsSendParameter::clsDomainCacheItem::clsDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset) + : m_pHostNameOrService(p_pHostNameOrService), + m_bAdditionalData(p_bAdditionalData), + m_u16Offset(p_u16Offset) +{ +} + +/** + clsLEAMDNSHost::clsSendParameter + +*/ + +/* + clsLEAMDNSHost::clsSendParameter::clsSendParameter constructor + +*/ +clsLEAMDNSHost::clsSendParameter::clsSendParameter(void) + : m_u16ID(0), + m_u32HostReplyMask(0), + m_bLegacyDNSQuery(false), + m_Response(enuResponseType::None), + m_bAuthorative(false), + m_bCacheFlush(false), + m_bUnicast(false), + m_bUnannounce(false), + m_u16Offset(0) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsSendParameter::~stcSendParameter destructor + +*/ +clsLEAMDNSHost::clsSendParameter::~clsSendParameter(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsSendParameter::clear + +*/ +bool clsLEAMDNSHost::clsSendParameter::clear(void) +{ + m_u16ID = 0; + flushQuestions(); + m_u32HostReplyMask = 0; + + m_bLegacyDNSQuery = false; + m_Response = enuResponseType::None; + m_bAuthorative = false; + m_bCacheFlush = true; + m_bUnicast = false; + m_bUnannounce = false; + + m_u16Offset = 0; + flushDomainCache(); + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::flushQuestions + +*/ +bool clsLEAMDNSHost::clsSendParameter::flushQuestions(void) +{ + for (clsRRQuestion* pRRQuestion : m_RRQuestions) + { + delete pRRQuestion; + } + m_RRQuestions.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::flushDomainCache + +*/ +bool clsLEAMDNSHost::clsSendParameter::flushDomainCache(void) +{ + for (clsDomainCacheItem* pDomainCacheItem : m_DomainCacheItems) + { + delete pDomainCacheItem; + } + m_DomainCacheItems.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::flushTempContent + +*/ +bool clsLEAMDNSHost::clsSendParameter::flushTempContent(void) +{ + m_u16Offset = 0; + flushDomainCache(); + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::shiftOffset + +*/ +bool clsLEAMDNSHost::clsSendParameter::shiftOffset(uint16_t p_u16Shift) +{ + m_u16Offset += p_u16Shift; + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::addDomainCacheItem + +*/ +bool clsLEAMDNSHost::clsSendParameter::addDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset) +{ + bool bResult = false; + + clsDomainCacheItem* pNewItem = 0; + if ((p_pHostNameOrService) && + (p_u16Offset) && + ((pNewItem = new clsDomainCacheItem(p_pHostNameOrService, p_bAdditionalData, p_u16Offset)))) + { + m_DomainCacheItems.push_back(pNewItem); + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsSendParameter::findCachedDomainOffset + +*/ +uint16_t clsLEAMDNSHost::clsSendParameter::findCachedDomainOffset(const void* p_pHostNameOrService, + bool p_bAdditionalData) const +{ + const clsDomainCacheItem* pMatchingCacheItem = 0; + + for (const clsDomainCacheItem* pCacheItem : m_DomainCacheItems) + { + if ((pCacheItem->m_pHostNameOrService == p_pHostNameOrService) && + (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item + { + pMatchingCacheItem = pCacheItem; + break; + } + } + return (pMatchingCacheItem ? pMatchingCacheItem->m_u16Offset : 0); +} + + +/** + clsLEAMDNSHost::clsQuery + + A MDNS service query object. + Service queries may be static or dynamic. + As the static service query is processed in the blocking function 'queryService', + only one static service service may exist. The processing of the answers is done + on the WiFi-stack side of the ESP stack structure (via 'UDPContext.onRx(_update)'). + +*/ + +/** + clsLEAMDNSHost::clsQuery::clsAnswer + + One answer for a query. + Every answer must contain + - a service instance entry (pivot), + and may contain + - a host domain, + - a port + - an IPv4 address + (- an IPv6 address) + - a MDNS TXTs + The existance of a component is flaged in 'm_u32ContentFlags'. + For every answer component a TTL value is maintained. + Answer objects can be connected to a linked list. + + For the host domain, service domain and TXTs components, a char array + representation can be retrieved (which is created on demand). + +*/ + +/** + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL + + The TTL (Time-To-Live) for an specific answer content. + If the answer is scheduled for an update, the corresponding flag should be set. + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::clsTTL constructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::clsTTL(void) + : m_u32TTL(0), + m_TTLTimeout(std::numeric_limits::max()), + m_TimeoutLevel(static_cast(enuTimeoutLevel::None)) +{ +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::set + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::set(uint32_t p_u32TTL) +{ + m_u32TTL = p_u32TTL; + if (m_u32TTL) + { + m_TimeoutLevel = static_cast(enuTimeoutLevel::Base); // Set to 80% + m_TTLTimeout.reset(timeout()); + } + else + { + m_TimeoutLevel = static_cast(enuTimeoutLevel::None); // undef + m_TTLTimeout.reset(std::numeric_limits::max()); + } + return true; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::flagged + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::flagged(void) const +{ + return ((m_u32TTL) && + (static_cast(enuTimeoutLevel::None) != m_TimeoutLevel) && + (((esp8266::polledTimeout::timeoutTemplate*)&m_TTLTimeout)->expired())); // Cast-away the const; in case of oneShot-timer OK (but ugly...) +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::restart + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::restart(void) +{ + bool bResult = true; + + if ((static_cast(enuTimeoutLevel::Base) <= m_TimeoutLevel) && // >= 80% AND + (static_cast(enuTimeoutLevel::Final) > m_TimeoutLevel)) // < 100% + { + m_TimeoutLevel += static_cast(enuTimeoutLevel::Interval); // increment by 5% + m_TTLTimeout.reset(timeout()); + } + else + { + bResult = false; + m_TTLTimeout.reset(std::numeric_limits::max()); + m_TimeoutLevel = static_cast(enuTimeoutLevel::None); + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::prepareDeletion + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::prepareDeletion(void) +{ + m_TimeoutLevel = static_cast(enuTimeoutLevel::Final); + m_TTLTimeout.reset(1 * 1000); // See RFC 6762, 10.1 + + return true; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::finalTimeoutLevel + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::finalTimeoutLevel(void) const +{ + return (static_cast(enuTimeoutLevel::Final) == m_TimeoutLevel); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::timeout + +*/ +unsigned long clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::timeout(void) const +{ + uint32_t u32Timeout = std::numeric_limits::max(); + + if (static_cast(enuTimeoutLevel::Base) == m_TimeoutLevel) // 80% + { + u32Timeout = (m_u32TTL * 800); // to milliseconds + } + else if ((static_cast(enuTimeoutLevel::Base) < m_TimeoutLevel) && // >80% AND + (static_cast(enuTimeoutLevel::Final) >= m_TimeoutLevel)) // <= 100% + { + u32Timeout = (m_u32TTL * 50); + } // else: invalid + return u32Timeout; +} + + +/** + clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddress + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddress::clsIPAddress constructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL::clsIPAddressWithTTL(IPAddress p_IPAddress, + uint32_t p_u32TTL /*= 0*/) + : m_IPAddress(p_IPAddress) +{ + m_TTL.set(p_u32TTL); +} + + +/** + clsLEAMDNSHost::clsQuery::clsAnswer + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsAnswer constructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsAnswer(void) + : m_u16Port(0), + m_QueryAnswerFlags(0) +{ +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::~clsAnswer destructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::~clsAnswer(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clear + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clear(void) +{ + return ( +#ifdef MDNS_IPV4_SUPPORT + (releaseIPv4Addresses()) +#else + (true) +#endif + && +#ifdef MDNS_IPV6_SUPPORT + (releaseIPv6Addresses()) +#else + (true) +#endif + ); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + clsLEAMDNSHost::clsQuery::clsAnswer::releaseIPv4Addresses + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::releaseIPv4Addresses(void) +{ + for (clsIPAddressWithTTL* pIPAddress : m_IPv4Addresses) + { + delete pIPAddress; + } + m_IPv4Addresses.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::addIPv4Address + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::addIPv4Address(clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* p_pIPv4Address) +{ + bool bResult = false; + + if (p_pIPv4Address) + { + m_IPv4Addresses.push_back(p_pIPv4Address); + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv4Address + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv4Address(clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* p_pIPv4Address) +{ + bool bResult = false; + + clsIPAddressWithTTL::list::iterator it(p_pIPv4Address + ? std::find(m_IPv4Addresses.begin(), m_IPv4Addresses.end(), p_pIPv4Address) + : m_IPv4Addresses.end()); + if (m_IPv4Addresses.end() != it) + { + m_IPv4Addresses.erase(it); + delete p_pIPv4Address; + + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::findIPv4Address (const) + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::findIPv4Address(const IPAddress& p_IPAddress) const +{ + return (clsIPAddressWithTTL*)(((const clsAnswer*)this)->findIPv4Address(p_IPAddress)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::findIPv4Address + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::findIPv4Address(const IPAddress& p_IPAddress) +{ + clsIPAddressWithTTL* pMatchingIPv4Address = 0; + + for (clsIPAddressWithTTL* pIPv4Address : m_IPv4Addresses) + { + if (pIPv4Address->m_IPAddress == p_IPAddress) + { + pMatchingIPv4Address = pIPv4Address; + break; + } + } + return pMatchingIPv4Address; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressCount + +*/ +uint32_t clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressCount(void) const +{ + uint32_t u32Count = m_IPv4Addresses.size(); + return u32Count; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressAtIndex + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressAtIndex(uint32_t p_u32Index) +{ + return (clsIPAddressWithTTL*)(((const clsAnswer*)this)->IPv4AddressAtIndex(p_u32Index)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressAtIndex (const) + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressAtIndex(uint32_t p_u32Index) const +{ + const clsIPAddressWithTTL* pIPv4AddressAtIndex = 0; + + uint32_t u32CurIndex = 0; + for (clsIPAddressWithTTL::list::const_iterator it = m_IPv4Addresses.begin(); + (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_IPv4Addresses.end())); + it++, u32CurIndex++) + { + if (p_u32Index == u32CurIndex++) + { + pIPv4AddressAtIndex = *it; + break; + } + } + return pIPv4AddressAtIndex; +} +#endif + +#ifdef MDNS_IPV6_SUPPORT +/* + clsLEAMDNSHost::clsQuery::clsAnswer::releaseIPv6Addresses + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::releaseIPv6Addresses(void) +{ + for (clsIPAddressWithTTL* pIPAddress : m_IPv6Addresses) + { + delete pIPAddress; + } + m_IPv6Addresses.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::addIPv6Address + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::addIPv6Address(clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* p_pIPv6Address) +{ + bool bResult = false; + + if (p_pIPv6Address) + { + m_IPv6Addresses.push_back(p_pIPv6Address); + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv6Address + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv6Address(clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* p_pIPv6Address) +{ + bool bResult = false; + + clsIPAddressWithTTL::list::iterator it(p_pIPv6Address + ? std::find(m_IPv6Addresses.begin(), m_IPv6Addresses.end(), p_pIPv6Address) + : m_IPv6Addresses.end()); + if (m_IPv6Addresses.end() != it) + { + m_IPv6Addresses.erase(it); + delete p_pIPv6Address; + + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::findIPv6Address + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::findIPv6Address(const IPAddress& p_IPAddress) +{ + return (clsIPAddressWithTTL*)(((const clsAnswer*)this)->findIPv6Address(p_IPAddress)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::findIPv6Address (const) + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::findIPv6Address(const IPAddress& p_IPAddress) const +{ + clsIPAddressWithTTL* pMatchingIPv6Address = 0; + + for (clsIPAddressWithTTL* pIPv6Address : m_IPv6Addresses) + { + if (pIPv6Address->m_IPAddress == p_IPAddress) + { + pMatchingIPv6Address = pIPv6Address; + break; + } + } + return pMatchingIPv6Address; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressCount + +*/ +uint32_t clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressCount(void) const +{ + uint32_t u32Count = m_IPv6Addresses.size(); + return u32Count; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressAtIndex + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressAtIndex(uint32_t p_u32Index) +{ + return (clsIPAddressWithTTL*)(((const clsAnswer*)this)->IPv6AddressAtIndex(p_u32Index)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressAtIndex (const) + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressAtIndex(uint32_t p_u32Index) const +{ + const clsIPAddressWithTTL* pIPv6AddressAtIndex = 0; + + uint32_t u32CurIndex = 0; + for (clsIPAddressWithTTL::list::const_iterator it = m_IPv6Addresses.begin(); + (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_IPv6Addresses.end())); + it++, u32CurIndex++) + { + if (p_u32Index == u32CurIndex++) + { + pIPv6AddressAtIndex = *it; + break; + } + } + return pIPv6AddressAtIndex; +} +#endif + + +/** + clsLEAMDNSHost::clsQuery::clsAnswerAccessor + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsAnswerAccessor constructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsAnswerAccessor(const clsLEAMDNSHost::clsQuery::clsAnswer* p_pAnswer) + : m_pAnswer(p_pAnswer) +{ + if ((m_pAnswer) && + (txtsAvailable())) + { + // Prepare m_TxtKeyValueMap + for (const clsLEAMDNSHost::clsServiceTxt* pTxt : m_pAnswer->m_Txts.m_Txts) + { + m_TxtKeyValueMap.emplace(std::pair(pTxt->m_pcKey, pTxt->m_pcValue)); + } + } +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::~clsAnswerAccessor destructor +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::~clsAnswerAccessor(void) +{ +} + +/** + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsCompareTxtKey + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::stcCompareTxtKey::operator() + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::stcCompareTxtKey::operator()(char const* p_pA, + char const* p_pB) const +{ + return (0 > strcasecmp(p_pA, p_pB)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::serviceDomainAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::serviceDomainAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::serviceDomain + +*/ +const char* clsLEAMDNSHost::clsQuery::clsAnswerAccessor::serviceDomain(void) const +{ + return ((m_pAnswer) + ? m_pAnswer->m_ServiceDomain.c_str() + : 0); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostDomainAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostDomainAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostDomain + +*/ +const char* clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostDomain(void) const +{ + return ((m_pAnswer) + ? m_pAnswer->m_HostDomain.c_str() + : 0); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostPortAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostPortAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Port))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostPort + +*/ +uint16_t clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostPort(void) const +{ + return ((m_pAnswer) + ? (m_pAnswer->m_u16Port) + : 0); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv4AddressAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv4AddressAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv4Addresses + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsIPAddressVector clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv4Addresses(void) const +{ + clsIPAddressVector internalIP; + if ((m_pAnswer) && + (IPv4AddressAvailable())) + { + for (uint32_t u = 0; u < m_pAnswer->IPv4AddressCount(); ++u) + { + const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddr = m_pAnswer->IPv4AddressAtIndex(u); + if (pIPAddr) + { + internalIP.emplace_back(pIPAddr->m_IPAddress); + } + } + } + return internalIP; +} +#endif + +#ifdef MDNS_IPV6_SUPPORT +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv6AddressAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv6AddressAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv6Addresses + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsIPAddressVector clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv6Addresses(void) const +{ + clsIPAddressVector internalIP; + if ((m_pAnswer) && + (IPv6AddressAvailable())) + { + for (uint32_t u = 0; u < m_pAnswer->IPv6AddressCount(); ++u) + { + const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddr = m_pAnswer->IPv6AddressAtIndex(u); + if (pIPAddr) + { + internalIP.emplace_back(pIPAddr->m_IPAddress); + } + } + } + return internalIP; +} +#endif + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtsAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtsAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txts + + Returns all TXT items for the given service as a ';'-separated string. + If not already existing; the string is alloced, filled and attached to the answer. + +*/ +const char* clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txts(void) const +{ + return ((m_pAnswer) + ? m_pAnswer->m_Txts.c_str() + : 0); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtKeyValues + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsTxtKeyValueMap& clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtKeyValues(void) const +{ + return m_TxtKeyValueMap; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtValue + +*/ +const char* clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtValue(const char* p_pcKey) const +{ + char* pcResult = 0; + + if (m_pAnswer) + { + for (const clsLEAMDNSHost::clsServiceTxt* pTxt : m_pAnswer->m_Txts.m_Txts) + { + if ((p_pcKey) && + (0 == strcasecmp(pTxt->m_pcKey, p_pcKey))) + { + pcResult = pTxt->m_pcValue; + break; + } + } + } + return pcResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::printTo + +*/ +size_t clsLEAMDNSHost::clsQuery::clsAnswerAccessor::printTo(Print& p_Print) const +{ + size_t stLen = 0; + const char* cpcI = " * "; + const char* cpcS = " "; + + stLen += p_Print.println(" * * * * *"); + if (hostDomainAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("Host domain: "); + stLen += p_Print.println(hostDomain()); + } +#ifdef MDNS_IPV4_SUPPORT + if (IPv4AddressAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.println("IPv4 address(es):"); + for (const IPAddress& addr : IPv4Addresses()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print(cpcS); + stLen += p_Print.println(addr); + } + } +#endif +#ifdef MDNS_IPV6_SUPPORT + if (IPv6AddressAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.println("IPv6 address(es):"); + for (const IPAddress& addr : IPv6Addresses()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print(cpcS); + stLen += p_Print.println(addr); + } + } +#endif + if (serviceDomainAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("Service domain: "); + stLen += p_Print.println(serviceDomain()); + } + if (hostPortAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("Host port: "); + stLen += p_Print.println(hostPort()); + } + if (txtsAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("TXTs:"); + for (auto const& x : txtKeyValues()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print(cpcS); + stLen += p_Print.print(x.first); + stLen += p_Print.print("="); + stLen += p_Print.println(x.second); + } + } + stLen += p_Print.println(" * * * * *"); + + return stLen; +} + + +/** + clsLEAMDNSHost::clsQuery + + A service or host query object. + A static query is flaged via 'm_bLegacyQuery'; while the function 'queryService' + is waiting for answers, the internal flag 'm_bAwaitingAnswers' is set. When the + timeout is reached, the flag is removed. These two flags are only used for static + service queries. + All answers to the query are stored in the 'm_Answers' list. + Individual answers may be addressed by index (in the list of answers). + Every time a answer component is added (or changed) in a dynamic query, + the callback 'm_fnCallback' is called. + The answer list may be searched by service and host domain. + + Query object may be connected to a linked list. + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsQuery constructor + +*/ +clsLEAMDNSHost::clsQuery::clsQuery(const enuQueryType p_QueryType) + : m_QueryType(p_QueryType), + m_fnCallbackAnswer(0), + m_fnCallbackAccessor(0), + m_bStaticQuery(false), + m_u8SentCount(0), + m_ResendTimeout(std::numeric_limits::max()), + m_bAwaitingAnswers(true) +{ + clear(); + m_QueryType = p_QueryType; +} + +/* + clsLEAMDNSHost::clsQuery::~stcQuery destructor + +*/ +clsLEAMDNSHost::clsQuery::~clsQuery(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsQuery::clear + +*/ +bool clsLEAMDNSHost::clsQuery::clear(void) +{ + m_QueryType = enuQueryType::None; + m_fnCallbackAnswer = 0; + m_fnCallbackAccessor = 0; + m_bStaticQuery = false; + m_u8SentCount = 0; + m_ResendTimeout.reset(std::numeric_limits::max()); + m_bAwaitingAnswers = true; + for (clsAnswer* pAnswer : m_Answers) + { + delete pAnswer; + } + m_Answers.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsQuery::answerCount + +*/ +uint32_t clsLEAMDNSHost::clsQuery::answerCount(void) const +{ + uint32_t u32Count = m_Answers.size(); + return u32Count; +} + +/* + clsLEAMDNSHost::clsQuery::answer + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer* clsLEAMDNSHost::clsQuery::answer(uint32_t p_u32Index) const +{ + const clsAnswer* pAnswerAtIndex = 0; + + uint32_t u32CurIndex = 0; + for (clsAnswer::list::const_iterator it = m_Answers.begin(); + (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_Answers.end())); + it++, u32CurIndex++) + { + if (p_u32Index == u32CurIndex++) + { + pAnswerAtIndex = *it; + break; + } + } + return pAnswerAtIndex; +} + +/* + clsLEAMDNSHost::clsQuery::indexOfAnswer + +*/ +uint32_t clsLEAMDNSHost::clsQuery::indexOfAnswer(const clsLEAMDNSHost::clsQuery::clsAnswer* p_pAnswer) const +{ + uint32_t u32IndexOfAnswer = ((uint32_t)(-1)); + + uint32_t u32CurIndex = 0; + for (const clsAnswer* pAnswer : m_Answers) + { + if (pAnswer == p_pAnswer) + { + u32IndexOfAnswer = u32CurIndex; + break; + } + ++u32CurIndex; + } + return u32IndexOfAnswer; +} + +/* + clsLEAMDNSHost::clsQuery::answerAccessors + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector clsLEAMDNSHost::clsQuery::answerAccessors(void) const +{ + clsAnswerAccessor::vector tempAccessors; + for (const clsAnswer* pAnswer : m_Answers) + { + tempAccessors.emplace_back(pAnswer); + } + return tempAccessors; +} + +/* + clsLEAMDNSHost::clsQuery::answerAccessor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor clsLEAMDNSHost::clsQuery::answerAccessor(uint32 p_u32AnswerIndex) const +{ + return clsAnswerAccessor(answer(p_u32AnswerIndex)); +} + +/* + clsLEAMDNSHost::clsQuery::addAnswer + +*/ +bool clsLEAMDNSHost::clsQuery::addAnswer(clsLEAMDNSHost::clsQuery::clsAnswer* p_pAnswer) +{ + bool bResult = false; + + if (p_pAnswer) + { + m_Answers.push_back(p_pAnswer); + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::removeAnswer + +*/ +bool clsLEAMDNSHost::clsQuery::removeAnswer(clsLEAMDNSHost::clsQuery::clsAnswer* p_pAnswer) +{ + bool bResult = false; + + clsAnswer::list::iterator it(p_pAnswer + ? std::find(m_Answers.begin(), m_Answers.end(), p_pAnswer) + : m_Answers.end()); + if (m_Answers.end() != it) + { + m_Answers.erase(it); + delete p_pAnswer; + + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::findAnswerForServiceDomain + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer* clsLEAMDNSHost::clsQuery::findAnswerForServiceDomain(const clsLEAMDNSHost::clsRRDomain& p_ServiceDomain) +{ + clsAnswer* pAnswerForServiceDomain = 0; + + for (clsAnswer* pAnswer : m_Answers) + { + if (pAnswer->m_ServiceDomain == p_ServiceDomain) + { + pAnswerForServiceDomain = pAnswer; + break; + } + } + return pAnswerForServiceDomain; +} + +/* + clsLEAMDNSHost::clsQuery::findAnswerForHostDomain + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer* clsLEAMDNSHost::clsQuery::findAnswerForHostDomain(const clsLEAMDNSHost::clsRRDomain& p_HostDomain) +{ + clsAnswer* pAnswerForHostDomain = 0; + + for (clsAnswer* pAnswer : m_Answers) + { + if (pAnswer->m_HostDomain == p_HostDomain) + { + pAnswerForHostDomain = pAnswer; + break; + } + } + return pAnswerForHostDomain; +} + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Transfer.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp old mode 100755 new mode 100644 similarity index 71% rename from libraries/ESP8266mDNS/src/LEAmDNS2_Host_Transfer.cpp rename to libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp index 5da81255ab..50880585cc --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Transfer.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp @@ -1,5 +1,5 @@ /* - LEAmDNS2_Host_Transfer.cpp + LEAmDNS2Host_Transfer.cpp License (MIT license): Permission is hereby granted, free of charge, to any person obtaining a copy @@ -22,61 +22,35 @@ */ -extern "C" { -#include "user_interface.h" -} - -#include "lwip/netif.h" +#include // for can_yield() -#include "LEAmDNS2_lwIPdefs.h" -#include "LEAmDNS2_Priv.h" +#include "LEAmDNS2Host.h" namespace esp8266 { -/* - LEAmDNS -*/ + namespace experimental { -/** - CONST STRINGS -*/ -static const char* scpcLocal = "local"; -static const char* scpcServices = "services"; -static const char* scpcDNSSD = "dns-sd"; -static const char* scpcUDP = "udp"; -//static const char* scpcTCP = "tcp"; - -#ifdef MDNS_IPV4_SUPPORT -static const char* scpcReverseIPv4Domain = "in-addr"; -#endif -#ifdef MDNS_IPV6_SUPPORT -static const char* scpcReverseIPv6Domain = "ip6"; -#endif -static const char* scpcReverseTopDomain = "arpa"; - -/** - TRANSFER -*/ +/* -/** SENDING + */ /* - MDNSResponder::_sendMDNSMessage + MDNSResponder::_sendMessage Unicast responses are prepared and sent directly to the querier. - Multicast responses or queries are transferred to _sendMDNSMessage_Multicast + Multicast responses or queries are transferred to _sendMessage_Multicast Any reply flags in installed services are removed at the end! */ -bool MDNSResponder::clsHost::_sendMDNSMessage(MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_sendMessage(clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { bool bResult = false; @@ -89,7 +63,7 @@ bool MDNSResponder::clsHost::_sendMDNSMessage(MDNSResponder::clsHost::stcSendPar } DEBUG_EX_INFO(else { - DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: No IPv4 address available!\n"), _DH()); + DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: No IPv4 address available!\n"), _DH()); }); #endif #ifdef MDNS_IPV6_SUPPORT @@ -100,72 +74,86 @@ bool MDNSResponder::clsHost::_sendMDNSMessage(MDNSResponder::clsHost::stcSendPar } DEBUG_EX_INFO(else { - DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: No IPv6 address available!\n"), _DH()); + DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: No IPv6 address available!\n"), _DH()); }); #endif - if (stcSendParameter::enuResponseType::None != p_rSendParameter.m_Response) + if (clsBackbone::sm_pBackbone->setDelayUDPProcessing(true)) { - IPAddress ipRemote = ((stcSendParameter::enuResponseType::Response == p_rSendParameter.m_Response) - ? m_rUDPContext.getRemoteAddress() - : IPAddress()); - - if (p_rSendParameter.m_bUnicast) // Unicast response -> Send to querier + // Avoid 're-entry-like problems because delay() is called! + if (clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response) { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: Will send unicast to '%s'.\n"), _DH(), ipRemote.toString().c_str());); - DEBUG_EX_ERR(if (!ipRemote.isSet()) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: MISSING remote address for unicast response!\n"), _DH());); + IPAddress ipRemote = ((clsSendParameter::enuResponseType::Response == p_rSendParameter.m_Response) + ? m_pUDPContext->getRemoteAddress() + : IPAddress()); - bResult = ((ipRemote.isSet()) && - (_prepareMDNSMessage(p_rSendParameter)) && - (m_rUDPContext.send(ipRemote, m_rUDPContext.getRemotePort()))); - } - else // Multicast response -> Send via the same network interface, that received the query - { -#ifdef MDNS_IPV4_SUPPORT - if (((!ipRemote.isSet()) || // NO remote IP - (ipRemote.isV4())) && // OR IPv4 - (u8AvailableProtocols & static_cast(enuIPProtocolType::V4))) // AND IPv4 protocol available + if (p_rSendParameter.m_bUnicast) { - - bResult = _sendMDNSMessage_Multicast(p_rSendParameter, static_cast(enuIPProtocolType::V4)); + // Unicast response -> Send to querier + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: Will send unicast to '%s'.\n"), _DH(), ipRemote.toString().c_str());); + DEBUG_EX_ERR(if (!ipRemote.isSet()) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: MISSING remote address for unicast response!\n"), _DH());); + + bResult = ((ipRemote.isSet()) && + (_prepareMessage(p_rSendParameter)) && + (m_pUDPContext->send(ipRemote, m_pUDPContext->getRemotePort())) /*&& + (Serial.println("Did send UC"), true)*/); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage (V4): FAILED!\n"), _DH());); + + if ((clsConsts::u32SendCooldown) && + (can_yield())) + { + delay(clsConsts::u32SendCooldown); + } } + else + { + // Multicast response -> Send via the same network interface, that received the query +#ifdef MDNS_IPV4_SUPPORT + if (((!ipRemote.isSet()) || // NO remote IP + (ipRemote.isV4())) && // OR IPv4 + (u8AvailableProtocols & static_cast(enuIPProtocolType::V4))) // AND IPv4 protocol available + { + bResult = _sendMessage_Multicast(p_rSendParameter, static_cast(enuIPProtocolType::V4)); + } #endif #ifdef MDNS_IPV6_SUPPORT - if (((!ipRemote.isSet()) || // NO remote IP - (ipRemote.isV6())) && // OR IPv6 - (u8AvailableProtocols & static_cast(enuIPProtocolType::V6))) // AND IPv6 protocol available - { - - bResult = _sendMDNSMessage_Multicast(p_rSendParameter, static_cast(enuIPProtocolType::V6)); - } + if (((!ipRemote.isSet()) || // NO remote IP + (ipRemote.isV6())) && // OR IPv6 + (u8AvailableProtocols & static_cast(enuIPProtocolType::V6))) // AND IPv6 protocol available + { + bResult = _sendMessage_Multicast(p_rSendParameter, static_cast(enuIPProtocolType::V6)); + } #endif + } + } + else + { + // Multicast query -> Send by all available protocols + bResult = ((u8AvailableProtocols) && + (_sendMessage_Multicast(p_rSendParameter, u8AvailableProtocols))); } - } - else // Multicast query -> Send by all available protocols - { - bResult = ((u8AvailableProtocols) && - (_sendMDNSMessage_Multicast(p_rSendParameter, u8AvailableProtocols))); - } - // Finally clear service reply masks - for (stcService* pService = m_pServices; pService; pService = pService->m_pNext) - { - pService->m_u32ReplyMask = 0; + // Finally clear service reply masks + for (clsService* pService : m_Services) + { + pService->m_u32ReplyMask = 0; + } + + clsBackbone::sm_pBackbone->setDelayUDPProcessing(false); } - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage: FAILED!\n"), _DH());); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: FAILED!\n"), _DH());); return bResult; } -#include "cont.h" /* - MDNSResponder::_sendMDNSMessage_Multicast + MDNSResponder::_sendMessage_Multicast - Fills the UDP output buffer (via _prepareMDNSMessage) and sends the buffer + Fills the UDP output buffer (via _prepareMessage) and sends the buffer via the selected WiFi protocols */ -bool MDNSResponder::clsHost::_sendMDNSMessage_Multicast(MDNSResponder::clsHost::stcSendParameter& p_rSendParameter, - uint8_t p_IPProtocolTypes) +bool clsLEAMDNSHost::_sendMessage_Multicast(clsLEAMDNSHost::clsSendParameter& p_rSendParameter, + uint8_t p_IPProtocolTypes) { bool bIPv4Result = true; bool bIPv6Result = true; @@ -175,13 +163,20 @@ bool MDNSResponder::clsHost::_sendMDNSMessage_Multicast(MDNSResponder::clsHost:: { IPAddress ip4MulticastAddress(DNS_MQUERY_IPV4_GROUP_INIT); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast v4: Will send to '%s'.\n"), _DH(), ip4MulticastAddress.toString().c_str());); - DEBUG_EX_INFO(if (!_getResponderIPAddress(enuIPProtocolType::V4)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast v4: NO IPv4 address!.\n"), _DH());); - bIPv4Result = ((_prepareMDNSMessage(p_rSendParameter)) && - (m_rUDPContext.setMulticastInterface(&m_rNetIf), true) && - (m_rUDPContext.send(ip4MulticastAddress, DNS_MQUERY_PORT)) && - (m_rUDPContext.setMulticastInterface(0), true)); - DEBUG_EX_ERR(if (!bIPv4Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast (V4): FAILED!\n"), _DH());); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast IPv4: Will send to '%s'.\n"), _DH(), ip4MulticastAddress.toString().c_str());); + DEBUG_EX_INFO(if (!_getResponderIPAddress(enuIPProtocolType::V4)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast IPv4: NO IPv4 address!.\n"), _DH());); + bIPv4Result = ((_prepareMessage(p_rSendParameter)) && + (m_pUDPContext->setMulticastInterface(m_pNetIf), true) && + (m_pUDPContext->send(ip4MulticastAddress, DNS_MQUERY_PORT)) && + (m_pUDPContext->setMulticastInterface(0), true) /*&& + (Serial.println("Did send MC V4"), true)*/); + DEBUG_EX_ERR(if (!bIPv4Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast (V4): FAILED!\n"), _DH());); + + if ((clsConsts::u32SendCooldown) && + (can_yield())) + { + delay(clsConsts::u32SendCooldown); + } } #endif @@ -190,27 +185,34 @@ bool MDNSResponder::clsHost::_sendMDNSMessage_Multicast(MDNSResponder::clsHost:: { IPAddress ip6MulticastAddress(DNS_MQUERY_IPV6_GROUP_INIT); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast v6: Will send to '%s'.\n"), _DH(), ip6MulticastAddress.toString().c_str());); - DEBUG_EX_INFO(if (!_getResponderIPAddress(enuIPProtocolType::V6)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast v6: NO IPv6 address!.\n"), _DH());); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast IPv6: Will send to '%s'.\n"), _DH(), ip6MulticastAddress.toString().c_str());); + DEBUG_EX_INFO(if (!_getResponderIPAddress(enuIPProtocolType::V6)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast IPv6: NO IPv6 address!.\n"), _DH());); DEBUG_EX_ERR( bool bPrepareMessage = false; bool bUDPContextSend = false; ); - bIPv6Result = ((DEBUG_EX_ERR(bPrepareMessage =)_prepareMDNSMessage(p_rSendParameter)) && - (m_rUDPContext.setMulticastInterface(&m_rNetIf), true) && - (DEBUG_EX_ERR(bUDPContextSend =)m_rUDPContext.send(ip6MulticastAddress, DNS_MQUERY_PORT)) && - (m_rUDPContext.setMulticastInterface(0), true)); - DEBUG_EX_ERR(if (!bIPv6Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast (V6): FAILED! (%s, %s, %s)\n"), _DH(), (_getResponderIPAddress(enuIPProtocolType::V6).isSet() ? "1" : "0"), (bPrepareMessage ? "1" : "0"), (bUDPContextSend ? "1" : "0"));); + bIPv6Result = ((DEBUG_EX_ERR(bPrepareMessage =)_prepareMessage(p_rSendParameter)) && + (m_pUDPContext->setMulticastInterface(m_pNetIf), true) && + (DEBUG_EX_ERR(bUDPContextSend =)m_pUDPContext->send(ip6MulticastAddress, DNS_MQUERY_PORT)) && + (m_pUDPContext->setMulticastInterface(0), true) /*&& + (Serial.println("Did send MC V6"), true)*/); + DEBUG_EX_ERR(if (!bIPv6Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast (IPv6): FAILED! (%s, %s, %s)\n"), _DH(), (_getResponderIPAddress(enuIPProtocolType::V6).isSet() ? "1" : "0"), (bPrepareMessage ? "1" : "0"), (bUDPContextSend ? "1" : "0"));); + + if ((clsConsts::u32SendCooldown) && + (can_yield())) + { + delay(clsConsts::u32SendCooldown); + } } #endif - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast: %s!\n\n"), _DH(), ((bIPv4Result && bIPv6Result) ? "Succeeded" : "FAILED"));); - DEBUG_EX_ERR(if (!(bIPv4Result && bIPv6Result)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSMessage_Multicast: FAILED!\n"), _DH());); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast: %s!\n\n"), _DH(), ((bIPv4Result && bIPv6Result) ? "Succeeded" : "FAILED"));); + DEBUG_EX_ERR(if (!(bIPv4Result && bIPv6Result)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast: FAILED!\n"), _DH());); return (bIPv4Result && bIPv6Result); } /* - MDNSResponder::_prepareMDNSMessage + MDNSResponder::_prepareMessage The MDNS message is composed in a two-step process. In the first loop 'only' the header informations (mainly number of answers) are collected, @@ -218,7 +220,7 @@ bool MDNSResponder::clsHost::_sendMDNSMessage_Multicast(MDNSResponder::clsHost:: output buffer. */ -bool MDNSResponder::clsHost::_prepareMDNSMessage(MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage\n"));); bool bResult = true; @@ -227,13 +229,13 @@ bool MDNSResponder::clsHost::_prepareMDNSMessage(MDNSResponder::clsHost::stcSend p_rSendParameter.flushTempContent(); // Prepare header; count answers - stcMsgHeader msgHeader(p_rSendParameter.m_u16ID, - (static_cast(stcSendParameter::enuResponseType::None) != p_rSendParameter.m_Response), + clsMsgHeader msgHeader(p_rSendParameter.m_u16ID, + (static_cast(clsSendParameter::enuResponseType::None) != p_rSendParameter.m_Response), 0, p_rSendParameter.m_bAuthorative); // If this is a response, the answers are anwers, // else this is a query or probe and the answers go into auth section - uint16_t& ru16Answers = ((stcSendParameter::enuResponseType::None != p_rSendParameter.m_Response) + uint16_t& ru16Answers = ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response) ? msgHeader.m_u16ANCount // Usual answers : msgHeader.m_u16NSCount); // Authorative answers @@ -269,8 +271,10 @@ bool MDNSResponder::clsHost::_prepareMDNSMessage(MDNSResponder::clsHost::stcSend : _writeMDNSMsgHeader(msgHeader, p_rSendParameter)); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSMsgHeader FAILED!\n"), _DH());); // Questions - for (stcRRQuestion* pQuestion = p_rSendParameter.m_pQuestions; ((bResult) && (pQuestion)); pQuestion = pQuestion->m_pNext) + for (clsRRQuestion::list::iterator it = p_rSendParameter.m_RRQuestions.begin(); ((bResult) && (it != p_rSendParameter.m_RRQuestions.end())); it++) { + clsRRQuestion* pQuestion = *it; + ((static_cast(enuSequence::Count) == sequence) ? ++msgHeader.m_u16QDCount : (bResult = _writeMDNSQuestion(*pQuestion, p_rSendParameter))); @@ -333,8 +337,10 @@ bool MDNSResponder::clsHost::_prepareMDNSMessage(MDNSResponder::clsHost::stcSend } #endif - for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) { + clsService* pService = *it; + // PTR_TYPE if ((bResult) && (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_TYPE))) @@ -382,8 +388,10 @@ bool MDNSResponder::clsHost::_prepareMDNSMessage(MDNSResponder::clsHost::stcSend #ifdef MDNS_IPV6_SUPPORT bool bNeedsAdditionalAnswerAAAA = false; #endif - for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) { + clsService* pService = *it; + if ((bResult) && (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_NAME)) && // If PTR_NAME is requested, AND (!(pService->m_u32ReplyMask & static_cast(enuContentFlag::SRV)))) // NOT SRV -> add SRV as additional answer @@ -425,9 +433,8 @@ bool MDNSResponder::clsHost::_prepareMDNSMessage(MDNSResponder::clsHost::stcSend // NSEC record for service if ((bResult) && (pService->m_u32ReplyMask) && - ((stcSendParameter::enuResponseType::None != p_rSendParameter.m_Response))) + ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response))) { - ((static_cast(enuSequence::Count) == sequence) ? ++ru16AdditionalAnswers : (bResult = _writeMDNSAnswer_NSEC(*pService, (static_cast(enuContentFlag::TXT) | static_cast(enuContentFlag::SRV)), p_rSendParameter))); @@ -468,10 +475,9 @@ bool MDNSResponder::clsHost::_prepareMDNSMessage(MDNSResponder::clsHost::stcSend // NSEC host (part 2) if ((bResult) && - ((stcSendParameter::enuResponseType::None != p_rSendParameter.m_Response)) && + ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response)) && (u32NSECContent)) { - // NSEC PTR IPv4/IPv6 are separate answers; make sure, that this is counted for #ifdef MDNS_IPV4_SUPPORT uint32_t u32NSECContent_PTR_IPv4 = (u32NSECContent & static_cast(enuContentFlag::PTR_IPv4)); @@ -518,61 +524,60 @@ bool MDNSResponder::clsHost::_prepareMDNSMessage(MDNSResponder::clsHost::stcSend } /* - MDNSResponder::_addMDNSQueryRecord + MDNSResponder::_addQueryRecord Adds a query for the given domain and query type. */ -bool MDNSResponder::clsHost::_addMDNSQueryRecord(MDNSResponder::clsHost::stcSendParameter& p_rSendParameter, - const MDNSResponder::clsHost::stcRRDomain& p_QueryDomain, - uint16_t p_u16RecordType) +bool clsLEAMDNSHost::_addQueryRecord(clsLEAMDNSHost::clsSendParameter& p_rSendParameter, + const clsLEAMDNSHost::clsRRDomain& p_QueryDomain, + uint16_t p_u16RecordType) { bool bResult = false; - stcRRQuestion* pQuestion = new stcRRQuestion; - if ((bResult = (0 != pQuestion))) + clsRRQuestion* pNewRRQuestion = new clsRRQuestion; + if ((bResult = (0 != pNewRRQuestion))) { // Link to list of questions - pQuestion->m_pNext = p_rSendParameter.m_pQuestions; - p_rSendParameter.m_pQuestions = pQuestion; + p_rSendParameter.m_RRQuestions.push_back(pNewRRQuestion); - pQuestion->m_Header.m_Domain = p_QueryDomain; + pNewRRQuestion->m_Header.m_Domain = p_QueryDomain; - pQuestion->m_Header.m_Attributes.m_u16Type = p_u16RecordType; + pNewRRQuestion->m_Header.m_Attributes.m_u16Type = p_u16RecordType; // It seems, that some mDNS implementations don't support 'unicast response' questions... - pQuestion->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN); // /*Unicast &*/ INternet + pNewRRQuestion->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN); // /*Unicast &*/ INternet } return bResult; } /* - MDNSResponder::_sendMDNSQuery + MDNSResponder::_sendQuery Creates and sends a query for the given domain and query type. */ -bool MDNSResponder::clsHost::_sendMDNSQuery(const MDNSResponder::clsHost::stcQuery& p_Query, - MDNSResponder::clsHost::stcQuery::stcAnswer* p_pKnownAnswers /*= 0*/) +bool clsLEAMDNSHost::_sendQuery(const clsLEAMDNSHost::clsQuery& p_Query, + clsLEAMDNSHost::clsQuery::clsAnswer::list* p_pKnownAnswers /*= 0*/) { bool bResult = false; - stcSendParameter sendParameter; + clsSendParameter sendParameter; switch (p_Query.m_QueryType) { - case stcQuery::enuQueryType::Host: + case clsQuery::enuQueryType::Host: #ifdef MDNS_IPV4_SUPPORT - bResult = _addMDNSQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_A); + bResult = _addQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_A); #endif #ifdef MDNS_IPV6_SUPPORT - bResult = _addMDNSQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_AAAA); + bResult = _addQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_AAAA); #endif break; - case stcQuery::enuQueryType::Service: - bResult = _addMDNSQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_PTR); + case clsQuery::enuQueryType::Service: + bResult = _addQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_PTR); break; - case stcQuery::enuQueryType::None: + case clsQuery::enuQueryType::None: default: break; } @@ -581,44 +586,48 @@ bool MDNSResponder::clsHost::_sendMDNSQuery(const MDNSResponder::clsHost::stcQue (void)p_pKnownAnswers; bResult = ((bResult) && - (_sendMDNSMessage(sendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSQuery: FAILED!\n"), _DH());); + (_sendMessage(sendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendQuery: FAILED!\n"), _DH());); return bResult; } /* - MDNSResponder::_sendMDNSQuery + MDNSResponder::_sendQuery Creates and sends a query for the given domain and record type. */ -bool MDNSResponder::clsHost::_sendMDNSQuery(const MDNSResponder::clsHost::stcRRDomain& p_QueryDomain, - uint16_t p_u16RecordType, - MDNSResponder::clsHost::stcQuery::stcAnswer* p_pKnownAnswers /*= 0*/) +bool clsLEAMDNSHost::_sendQuery(const clsLEAMDNSHost::clsRRDomain& p_QueryDomain, + uint16_t p_u16RecordType, + clsLEAMDNSHost::clsQuery::clsAnswer::list* p_pKnownAnswers /*= 0*/) { bool bResult = false; - stcSendParameter sendParameter; - bResult = ((_addMDNSQueryRecord(sendParameter, p_QueryDomain, p_u16RecordType)) && - (_sendMDNSMessage(sendParameter))); + clsSendParameter sendParameter; + bResult = ((_addQueryRecord(sendParameter, p_QueryDomain, p_u16RecordType)) && + (_sendMessage(sendParameter))); // TODO: Add known answer records (void) p_pKnownAnswers; - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMDNSQuery: FAILED!\n"), _DH());); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendQuery: FAILED!\n"), _DH());); return bResult; } /* MDNSResponder::_getResponderIPAddress */ -IPAddress MDNSResponder::clsHost::_getResponderIPAddress(enuIPProtocolType p_IPProtocolType) const +IPAddress clsLEAMDNSHost::_getResponderIPAddress(enuIPProtocolType p_IPProtocolType) const { IPAddress ipResponder; #ifdef MDNS_IPV4_SUPPORT if (enuIPProtocolType::V4 == p_IPProtocolType) { - ipResponder = netif_ip_addr4(&m_rNetIf); +#if LWIP_VERSION_MAJOR == 1 + ipResponder = ip_2_ip4(m_rNetIf.ip_addr); +#else + ipResponder = netif_ip_addr4(m_pNetIf); +#endif } #endif #ifdef MDNS_IPV6_SUPPORT @@ -629,13 +638,13 @@ IPAddress MDNSResponder::clsHost::_getResponderIPAddress(enuIPProtocolType p_IPP { for (int idx = 0; idx < LWIP_IPV6_NUM_ADDRESSES; ++idx) { - //DEBUG_EX_INFO(if ip6_addr_isvalid(netif_ip6_addr_state(&m_rNetIf, idx)) DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Checking IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(&m_rNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); - if ((ip6_addr_isvalid(netif_ip6_addr_state(&m_rNetIf, idx))) && + //DEBUG_EX_INFO(if ip6_addr_isvalid(netif_ip6_addr_state(&m_rNetIf, idx)) DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Checking IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(m_pNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); + if ((ip6_addr_isvalid(netif_ip6_addr_state(m_pNetIf, idx))) && (((!bCheckLinkLocal) || - (ip6_addr_islinklocal(netif_ip6_addr(&m_rNetIf, idx)))))) + (ip6_addr_islinklocal(netif_ip6_addr(m_pNetIf, idx)))))) { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Selected IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(&m_rNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); - ipResponder = netif_ip_addr6(&m_rNetIf, idx); + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Selected IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(m_pNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); + ipResponder = netif_ip_addr6(m_pNetIf, idx); break; } } @@ -661,7 +670,7 @@ IPAddress MDNSResponder::clsHost::_getResponderIPAddress(enuIPProtocolType p_IPP Reads a question (eg. MyESP._http._tcp.local ANY IN) from the UPD input buffer. */ -bool MDNSResponder::clsHost::_readRRQuestion(MDNSResponder::clsHost::stcRRQuestion& p_rRRQuestion) +bool clsLEAMDNSHost::_readRRQuestion(clsLEAMDNSHost::clsRRQuestion& p_rRRQuestion) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRQuestion\n"));); @@ -694,20 +703,19 @@ bool MDNSResponder::clsHost::_readRRQuestion(MDNSResponder::clsHost::stcRRQuesti from the input buffer). */ -bool MDNSResponder::clsHost::_readRRAnswer(MDNSResponder::clsHost::stcRRAnswer*& p_rpRRAnswer) +bool clsLEAMDNSHost::_readRRAnswer(clsLEAMDNSHost::clsRRAnswer*& p_rpRRAnswer) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer\n"));); bool bResult = false; - stcRRHeader header; + clsRRHeader header; uint32_t u32TTL; uint16_t u16RDLength; if ((_readRRHeader(header)) && (_udpRead32(u32TTL)) && (_udpRead16(u16RDLength))) { - /* DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: Reading 0x%04X answer (class:0x%04X, TTL:%u, RDLength:%u) for "), header.m_Attributes.m_u16Type, header.m_Attributes.m_u16Class, u32TTL, u16RDLength); _printRRDomain(header.m_Domain); @@ -718,31 +726,31 @@ bool MDNSResponder::clsHost::_readRRAnswer(MDNSResponder::clsHost::stcRRAnswer*& { #ifdef MDNS_IPV4_SUPPORT case DNS_RRTYPE_A: - p_rpRRAnswer = new stcRRAnswerA(header, u32TTL); - bResult = _readRRAnswerA(*(stcRRAnswerA*&)p_rpRRAnswer, u16RDLength); + p_rpRRAnswer = new clsRRAnswerA(header, u32TTL); + bResult = _readRRAnswerA(*(clsRRAnswerA*&)p_rpRRAnswer, u16RDLength); break; #endif case DNS_RRTYPE_PTR: - p_rpRRAnswer = new stcRRAnswerPTR(header, u32TTL); - bResult = _readRRAnswerPTR(*(stcRRAnswerPTR*&)p_rpRRAnswer, u16RDLength); + p_rpRRAnswer = new clsRRAnswerPTR(header, u32TTL); + bResult = _readRRAnswerPTR(*(clsRRAnswerPTR*&)p_rpRRAnswer, u16RDLength); break; case DNS_RRTYPE_TXT: - p_rpRRAnswer = new stcRRAnswerTXT(header, u32TTL); - bResult = _readRRAnswerTXT(*(stcRRAnswerTXT*&)p_rpRRAnswer, u16RDLength); + p_rpRRAnswer = new clsRRAnswerTXT(header, u32TTL); + bResult = _readRRAnswerTXT(*(clsRRAnswerTXT*&)p_rpRRAnswer, u16RDLength); break; #ifdef MDNS_IPV6_SUPPORT case DNS_RRTYPE_AAAA: - p_rpRRAnswer = new stcRRAnswerAAAA(header, u32TTL); - bResult = _readRRAnswerAAAA(*(stcRRAnswerAAAA*&)p_rpRRAnswer, u16RDLength); + p_rpRRAnswer = new clsRRAnswerAAAA(header, u32TTL); + bResult = _readRRAnswerAAAA(*(clsRRAnswerAAAA*&)p_rpRRAnswer, u16RDLength); break; #endif case DNS_RRTYPE_SRV: - p_rpRRAnswer = new stcRRAnswerSRV(header, u32TTL); - bResult = _readRRAnswerSRV(*(stcRRAnswerSRV*&)p_rpRRAnswer, u16RDLength); + p_rpRRAnswer = new clsRRAnswerSRV(header, u32TTL); + bResult = _readRRAnswerSRV(*(clsRRAnswerSRV*&)p_rpRRAnswer, u16RDLength); break; default: - p_rpRRAnswer = new stcRRAnswerGeneric(header, u32TTL); - bResult = _readRRAnswerGeneric(*(stcRRAnswerGeneric*&)p_rpRRAnswer, u16RDLength); + p_rpRRAnswer = new clsRRAnswerGeneric(header, u32TTL); + bResult = _readRRAnswerGeneric(*(clsRRAnswerGeneric*&)p_rpRRAnswer, u16RDLength); break; } DEBUG_EX_INFO( @@ -760,20 +768,20 @@ bool MDNSResponder::clsHost::_readRRAnswer(MDNSResponder::clsHost::stcRRAnswer*& { #ifdef MDNS_IPV4_SUPPORT case DNS_RRTYPE_A: - DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((stcRRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((clsRRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); break; #endif case DNS_RRTYPE_PTR: DEBUG_OUTPUT.printf_P(PSTR("PTR ")); - _printRRDomain(((stcRRAnswerPTR*&)p_rpRRAnswer)->m_PTRDomain); + _printRRDomain(((clsRRAnswerPTR*&)p_rpRRAnswer)->m_PTRDomain); break; case DNS_RRTYPE_TXT: { - size_t stTxtLength = ((stcRRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_strLength(); + size_t stTxtLength = ((clsRRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_strLength(); char* pTxts = new char[stTxtLength]; if (pTxts) { - ((stcRRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_str(pTxts); + ((clsRRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_str(pTxts); DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); delete[] pTxts; } @@ -781,12 +789,12 @@ bool MDNSResponder::clsHost::_readRRAnswer(MDNSResponder::clsHost::stcRRAnswer*& } #ifdef MDNS_IPV6_SUPPORT case DNS_RRTYPE_AAAA: - DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcRRAnswerAAAA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((clsRRAnswerAAAA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); break; #endif case DNS_RRTYPE_SRV: - DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((stcRRAnswerSRV*&)p_rpRRAnswer)->m_u16Port); - _printRRDomain(((stcRRAnswerSRV*&)p_rpRRAnswer)->m_SRVDomain); + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((clsRRAnswerSRV*&)p_rpRRAnswer)->m_u16Port); + _printRRDomain(((clsRRAnswerSRV*&)p_rpRRAnswer)->m_SRVDomain); break; /* case DNS_RRTYPE_NSEC: DEBUG_OUTPUT.printf_P(PSTR("NSEC ")); @@ -819,13 +827,12 @@ bool MDNSResponder::clsHost::_readRRAnswer(MDNSResponder::clsHost::stcRRAnswer*& /* MDNSResponder::_readRRAnswerA */ -bool MDNSResponder::clsHost::_readRRAnswerA(MDNSResponder::clsHost::stcRRAnswerA& p_rRRAnswerA, - uint16_t p_u16RDLength) +bool clsLEAMDNSHost::_readRRAnswerA(clsLEAMDNSHost::clsRRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength) { - uint32_t u32IPv4Address; - bool bResult = ((MDNS_IPV4_SIZE == p_u16RDLength) && - (_udpReadBuffer((unsigned char*)&u32IPv4Address, MDNS_IPV4_SIZE)) && + bool bResult = ((clsConsts::u16IPv4Size == p_u16RDLength) && + (_udpReadBuffer((unsigned char*)&u32IPv4Address, clsConsts::u16IPv4Size)) && ((p_rRRAnswerA.m_IPAddress = IPAddress(u32IPv4Address)))); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerA: FAILED!\n"), _DH());); return bResult; @@ -835,8 +842,8 @@ bool MDNSResponder::clsHost::_readRRAnswerA(MDNSResponder::clsHost::stcRRAnswerA /* MDNSResponder::_readRRAnswerPTR */ -bool MDNSResponder::clsHost::_readRRAnswerPTR(MDNSResponder::clsHost::stcRRAnswerPTR& p_rRRAnswerPTR, - uint16_t p_u16RDLength) +bool clsLEAMDNSHost::_readRRAnswerPTR(clsLEAMDNSHost::clsRRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength) { bool bResult = ((p_u16RDLength) && (_readRRDomain(p_rRRAnswerPTR.m_PTRDomain))); @@ -849,8 +856,8 @@ bool MDNSResponder::clsHost::_readRRAnswerPTR(MDNSResponder::clsHost::stcRRAnswe Read TXT items from a buffer like 4c#=15ff=20 */ -bool MDNSResponder::clsHost::_readRRAnswerTXT(MDNSResponder::clsHost::stcRRAnswerTXT& p_rRRAnswerTXT, - uint16_t p_u16RDLength) +bool clsLEAMDNSHost::_readRRAnswerTXT(clsLEAMDNSHost::clsRRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: RDLength:%u\n"), _DH(), p_u16RDLength);); bool bResult = true; @@ -873,7 +880,7 @@ bool MDNSResponder::clsHost::_readRRAnswerTXT(MDNSResponder::clsHost::stcRRAnswe { bResult = false; - stcServiceTxt* pTxt = 0; + clsServiceTxt* pTxt = 0; unsigned char ucLength = *pucCursor++; // Length of the next txt item if (ucLength) { @@ -890,7 +897,7 @@ bool MDNSResponder::clsHost::_readRRAnswerTXT(MDNSResponder::clsHost::stcRRAnswe ((ucKeyLength = (pucEqualSign - pucCursor)))) { unsigned char ucValueLength = (ucLength - (pucEqualSign - pucCursor + 1)); - bResult = (((pTxt = new stcServiceTxt)) && + bResult = (((pTxt = new clsServiceTxt)) && (pTxt->setKey((const char*)pucCursor, ucKeyLength)) && (pTxt->setValue((const char*)(pucEqualSign + 1), ucValueLength))); } @@ -902,25 +909,26 @@ bool MDNSResponder::clsHost::_readRRAnswerTXT(MDNSResponder::clsHost::stcRRAnswe } else // no/zero length TXT { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: TXT answer contains no items.\n"), _DH());); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: INFO! TXT answer contains no items.\n"), _DH());); bResult = true; } if ((bResult) && - (pTxt)) // Everythings fine so far + (pTxt)) { + // Everythings fine so far // Link TXT item to answer TXTs - pTxt->m_pNext = p_rRRAnswerTXT.m_Txts.m_pTxts; - p_rRRAnswerTXT.m_Txts.m_pTxts = pTxt; + p_rRRAnswerTXT.m_Txts.add(pTxt); } - else // At least no TXT (migth be OK, if length was 0) OR an error + else { + // At least no TXT (migth be OK, if length was 0) OR an error if (!bResult) { DEBUG_EX_ERR( DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED to read TXT item!\n"), _DH()); DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); - _udpDump((m_rUDPContext.tell() - p_u16RDLength), p_u16RDLength); + _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); DEBUG_OUTPUT.printf_P(PSTR("\n")); ); } @@ -937,7 +945,7 @@ bool MDNSResponder::clsHost::_readRRAnswerTXT(MDNSResponder::clsHost::stcRRAnswe if (!bResult) // Some failure { DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); - _udpDump((m_rUDPContext.tell() - p_u16RDLength), p_u16RDLength); + _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); DEBUG_OUTPUT.printf_P(PSTR("\n")); } ); @@ -956,23 +964,26 @@ bool MDNSResponder::clsHost::_readRRAnswerTXT(MDNSResponder::clsHost::stcRRAnswe } else { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: WARNING! No content!\n"), _DH());); + DEBUG_EX_ERR( + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: WARNING! No content in TXT answer from "), _DH()); + _printRRDomain(p_rRRAnswerTXT.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); } DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED!\n"), _DH());); return bResult; } #ifdef MDNS_IPV6_SUPPORT -bool MDNSResponder::clsHost::_readRRAnswerAAAA(MDNSResponder::clsHost::stcRRAnswerAAAA& p_rRRAnswerAAAA, - uint16_t p_u16RDLength) +bool clsLEAMDNSHost::_readRRAnswerAAAA(clsLEAMDNSHost::clsRRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength) { bool bResult = false; uint32_t au32IPv6Address[4]; // 16 bytes - if ((bResult = ((MDNS_IPV6_SIZE == p_u16RDLength) && - (_udpReadBuffer((uint8_t*)&au32IPv6Address[0], MDNS_IPV6_SIZE))))) + if ((bResult = ((clsConsts::u16IPv6Size == p_u16RDLength) && + (_udpReadBuffer((uint8_t*)&au32IPv6Address[0], clsConsts::u16IPv6Size))))) { - // ?? IPADDR6_INIT_HOST ?? ip_addr_t addr = IPADDR6_INIT(au32IPv6Address[0], au32IPv6Address[1], au32IPv6Address[2], au32IPv6Address[3]); p_rRRAnswerAAAA.m_IPAddress = IPAddress(addr); @@ -985,8 +996,8 @@ bool MDNSResponder::clsHost::_readRRAnswerAAAA(MDNSResponder::clsHost::stcRRAnsw /* MDNSResponder::_readRRAnswerSRV */ -bool MDNSResponder::clsHost::_readRRAnswerSRV(MDNSResponder::clsHost::stcRRAnswerSRV& p_rRRAnswerSRV, - uint16_t p_u16RDLength) +bool clsLEAMDNSHost::_readRRAnswerSRV(clsLEAMDNSHost::clsRRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength) { bool bResult = (((3 * sizeof(uint16_t)) < p_u16RDLength) && (_udpRead16(p_rRRAnswerSRV.m_u16Priority)) && @@ -1000,8 +1011,8 @@ bool MDNSResponder::clsHost::_readRRAnswerSRV(MDNSResponder::clsHost::stcRRAnswe /* MDNSResponder::_readRRAnswerGeneric */ -bool MDNSResponder::clsHost::_readRRAnswerGeneric(MDNSResponder::clsHost::stcRRAnswerGeneric& p_rRRAnswerGeneric, - uint16_t p_u16RDLength) +bool clsLEAMDNSHost::_readRRAnswerGeneric(clsLEAMDNSHost::clsRRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength) { bool bResult = (0 == p_u16RDLength); @@ -1009,7 +1020,6 @@ bool MDNSResponder::clsHost::_readRRAnswerGeneric(MDNSResponder::clsHost::stcRRA if (((p_rRRAnswerGeneric.m_u16RDLength = p_u16RDLength)) && ((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength]))) { - bResult = _udpReadBuffer(p_rRRAnswerGeneric.m_pu8RDData, p_rRRAnswerGeneric.m_u16RDLength); } DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerGeneric: FAILED!\n"), _DH());); @@ -1019,7 +1029,7 @@ bool MDNSResponder::clsHost::_readRRAnswerGeneric(MDNSResponder::clsHost::stcRRA /* MDNSResponder::_readRRHeader */ -bool MDNSResponder::clsHost::_readRRHeader(MDNSResponder::clsHost::stcRRHeader& p_rRRHeader) +bool clsLEAMDNSHost::_readRRHeader(clsLEAMDNSHost::clsRRHeader& p_rRRHeader) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRHeader\n"));); @@ -1035,7 +1045,7 @@ bool MDNSResponder::clsHost::_readRRHeader(MDNSResponder::clsHost::stcRRHeader& Reads a (maybe multilevel compressed) domain from the UDP input buffer. */ -bool MDNSResponder::clsHost::_readRRDomain(MDNSResponder::clsHost::stcRRDomain& p_rRRDomain) +bool clsLEAMDNSHost::_readRRDomain(clsLEAMDNSHost::clsRRDomain& p_rRRDomain) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain\n"));); @@ -1053,40 +1063,40 @@ bool MDNSResponder::clsHost::_readRRDomain(MDNSResponder::clsHost::stcRRDomain& the maximum recursion depth is set by MDNS_DOMAIN_MAX_REDIRCTION. */ -bool MDNSResponder::clsHost::_readRRDomain_Loop(MDNSResponder::clsHost::stcRRDomain& p_rRRDomain, - uint8_t p_u8Depth) +bool clsLEAMDNSHost::_readRRDomain_Loop(clsLEAMDNSHost::clsRRDomain& p_rRRDomain, + uint8_t p_u8Depth) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u)\n"), _DH(), p_u8Depth);); bool bResult = false; - if (MDNS_DOMAIN_MAX_REDIRCTION >= p_u8Depth) + if (clsConsts::u8DomainMaxRedirections >= p_u8Depth) { bResult = true; uint8_t u8Len = 0; do { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Offset:%u p0:%02x\n"), _DH(), p_u8Depth, m_rUDPContext.tell(), m_rUDPContext.peek());); + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Offset:%u p0:%02x\n"), _DH(), p_u8Depth, m_pUDPContext->tell(), m_pUDPContext->peek());); _udpRead8(u8Len); - if (u8Len & MDNS_DOMAIN_COMPRESS_MARK) + if (u8Len & clsConsts::u8DomainCompressMark) { // Compressed label(s) - uint16_t u16Offset = ((u8Len & ~MDNS_DOMAIN_COMPRESS_MARK) << 8); // Implicit BE to LE conversion! + uint16_t u16Offset = ((u8Len & ~clsConsts::u8DomainCompressMark) << 8); // Implicit BE to LE conversion! _udpRead8(u8Len); u16Offset |= u8Len; - if (m_rUDPContext.isValidOffset(u16Offset)) + if (m_pUDPContext->isValidOffset(u16Offset)) { - size_t stCurrentPosition = m_rUDPContext.tell(); // Prepare return from recursion + size_t stCurrentPosition = m_pUDPContext->tell(); // Prepare return from recursion //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Redirecting from %u to %u!\n"), _DH(), p_u8Depth, stCurrentPosition, u16Offset);); - m_rUDPContext.seek(u16Offset); + m_pUDPContext->seek(u16Offset); if (_readRRDomain_Loop(p_rRRDomain, p_u8Depth + 1)) // Do recursion { //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Succeeded to read redirected label! Returning to %u\n"), _DH(), p_u8Depth, stCurrentPosition);); - m_rUDPContext.seek(stCurrentPosition); // Restore after recursion + m_pUDPContext->seek(stCurrentPosition); // Restore after recursion } else { @@ -1104,7 +1114,7 @@ bool MDNSResponder::clsHost::_readRRDomain_Loop(MDNSResponder::clsHost::stcRRDom else { // Normal (uncompressed) label (maybe '\0' only) - if (MDNS_DOMAIN_MAXLENGTH > (p_rRRDomain.m_u16NameLength + u8Len)) + if (clsConsts::stDomainMaxLength > (p_rRRDomain.m_u16NameLength + u8Len)) { // Add length byte p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength] = u8Len; @@ -1121,7 +1131,7 @@ bool MDNSResponder::clsHost::_readRRDomain_Loop(MDNSResponder::clsHost::stcRRDom p_rRRDomain.m_u16NameLength += u8Len; } } - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(2) offset:%u p0:%x\n"), _DH(), m_rUDPContext.tell(), m_rUDPContext.peek());); + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(2) offset:%u p0:%x\n"), _DH(), m_pUDPContext->tell(), m_pUDPContext->peek());); } else { @@ -1142,8 +1152,9 @@ bool MDNSResponder::clsHost::_readRRDomain_Loop(MDNSResponder::clsHost::stcRRDom /* MDNSResponder::_readRRAttributes + */ -bool MDNSResponder::clsHost::_readRRAttributes(MDNSResponder::clsHost::stcRRAttributes& p_rRRAttributes) +bool clsLEAMDNSHost::_readRRAttributes(clsLEAMDNSHost::clsRRAttributes& p_rRRAttributes) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAttributes\n"));); @@ -1155,7 +1166,9 @@ bool MDNSResponder::clsHost::_readRRAttributes(MDNSResponder::clsHost::stcRRAttr /* + DOMAIN NAMES + */ /* @@ -1164,15 +1177,15 @@ bool MDNSResponder::clsHost::_readRRAttributes(MDNSResponder::clsHost::stcRRAttr Builds a MDNS host domain (eg. esp8266.local) for the given hostname. */ -bool MDNSResponder::clsHost::_buildDomainForHost(const char* p_pcHostName, - MDNSResponder::clsHost::stcRRDomain& p_rHostDomain) const +bool clsLEAMDNSHost::_buildDomainForHost(const char* p_pcHostName, + clsLEAMDNSHost::clsRRDomain& p_rHostDomain) const { p_rHostDomain.clear(); bool bResult = ((p_pcHostName) && (*p_pcHostName) && (p_rHostDomain.addLabel(p_pcHostName)) && - (p_rHostDomain.addLabel(scpcLocal)) && + (p_rHostDomain.addLabel(clsConsts::pcLocal)) && (p_rHostDomain.addLabel(0))); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForHost: FAILED!\n"), _DH());); return bResult; @@ -1185,13 +1198,13 @@ bool MDNSResponder::clsHost::_buildDomainForHost(const char* p_pcHostName, Used while detecting generic service enum question (DNS-SD) and answering these questions. */ -bool MDNSResponder::clsHost::_buildDomainForDNSSD(MDNSResponder::clsHost::stcRRDomain& p_rDNSSDDomain) const +bool clsLEAMDNSHost::_buildDomainForDNSSD(clsLEAMDNSHost::clsRRDomain& p_rDNSSDDomain) const { p_rDNSSDDomain.clear(); - bool bResult = ((p_rDNSSDDomain.addLabel(scpcServices, true)) && - (p_rDNSSDDomain.addLabel(scpcDNSSD, true)) && - (p_rDNSSDDomain.addLabel(scpcUDP, true)) && - (p_rDNSSDDomain.addLabel(scpcLocal)) && + bool bResult = ((p_rDNSSDDomain.addLabel(clsConsts::pcServices, true)) && + (p_rDNSSDDomain.addLabel(clsConsts::pcDNSSD, true)) && + (p_rDNSSDDomain.addLabel(clsConsts::pcUDP, true)) && + (p_rDNSSDDomain.addLabel(clsConsts::pcLocal)) && (p_rDNSSDDomain.addLabel(0))); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForDNSSD: FAILED!\n"), _DH());); return bResult; @@ -1204,16 +1217,16 @@ bool MDNSResponder::clsHost::_buildDomainForDNSSD(MDNSResponder::clsHost::stcRRD MyESP._http._tcp.local (if p_bIncludeName is set)). */ -bool MDNSResponder::clsHost::_buildDomainForService(const MDNSResponder::clsHost::stcService& p_Service, - bool p_bIncludeName, - MDNSResponder::clsHost::stcRRDomain& p_rServiceDomain) const +bool clsLEAMDNSHost::_buildDomainForService(const clsLEAMDNSHost::clsService& p_Service, + bool p_bIncludeName, + clsLEAMDNSHost::clsRRDomain& p_rServiceDomain) const { p_rServiceDomain.clear(); bool bResult = (((!p_bIncludeName) || - (p_rServiceDomain.addLabel(p_Service.m_pcName))) && - (p_rServiceDomain.addLabel(p_Service.m_pcServiceType, ('_' != *p_Service.m_pcServiceType))) && - (p_rServiceDomain.addLabel(p_Service.m_pcProtocol, ('_' != *p_Service.m_pcProtocol))) && - (p_rServiceDomain.addLabel(scpcLocal)) && + (p_rServiceDomain.addLabel(p_Service.instanceName()))) && + (p_rServiceDomain.addLabel(p_Service.type(), ('_' != *p_Service.type()))) && + (p_rServiceDomain.addLabel(p_Service.protocol(), ('_' != *p_Service.protocol()))) && + (p_rServiceDomain.addLabel(clsConsts::pcLocal)) && (p_rServiceDomain.addLabel(0))); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForService: FAILED!\n"), _DH());); return bResult; @@ -1226,16 +1239,16 @@ bool MDNSResponder::clsHost::_buildDomainForService(const MDNSResponder::clsHost The usual prepended '_' are added, if missing in the input strings. */ -bool MDNSResponder::clsHost::_buildDomainForService(const char* p_pcServiceType, - const char* p_pcProtocol, - MDNSResponder::clsHost::stcRRDomain& p_rServiceDomain) const +bool clsLEAMDNSHost::_buildDomainForService(const char* p_pcServiceType, + const char* p_pcProtocol, + clsLEAMDNSHost::clsRRDomain& p_rServiceDomain) const { p_rServiceDomain.clear(); bool bResult = ((p_pcServiceType) && (p_pcProtocol) && (p_rServiceDomain.addLabel(p_pcServiceType, ('_' != *p_pcServiceType))) && (p_rServiceDomain.addLabel(p_pcProtocol, ('_' != *p_pcProtocol))) && - (p_rServiceDomain.addLabel(scpcLocal)) && + (p_rServiceDomain.addLabel(clsConsts::pcLocal)) && (p_rServiceDomain.addLabel(0))); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForService: FAILED for (%s.%s)!\n"), _DH(), (p_pcServiceType ? : "-"), (p_pcProtocol ? : "-"));); return bResult; @@ -1248,9 +1261,10 @@ bool MDNSResponder::clsHost::_buildDomainForService(const char* p_pcServiceType, The IPv4 address is stringized by printing the four address bytes into a char buffer in reverse order and adding 'in-addr.arpa' (eg. 012.789.456.123.in-addr.arpa). Used while detecting reverse IPv4 questions and answering these + */ -bool MDNSResponder::clsHost::_buildDomainForReverseIPv4(IPAddress p_IPv4Address, - MDNSResponder::clsHost::stcRRDomain& p_rReverseIPv4Domain) const +bool clsLEAMDNSHost::_buildDomainForReverseIPv4(IPAddress p_IPv4Address, + clsLEAMDNSHost::clsRRDomain& p_rReverseIPv4Domain) const { bool bResult = ((p_IPv4Address.isSet()) && (p_IPv4Address.isV4())); @@ -1258,14 +1272,14 @@ bool MDNSResponder::clsHost::_buildDomainForReverseIPv4(IPAddress p_IPv4Address, p_rReverseIPv4Domain.clear(); char acBuffer[32]; - for (int i = MDNS_IPV4_SIZE; ((bResult) && (i >= 1)); --i) + for (int i = clsConsts::u16IPv4Size; ((bResult) && (i >= 1)); --i) { itoa(p_IPv4Address[i - 1], acBuffer, 10); bResult = p_rReverseIPv4Domain.addLabel(acBuffer); } bResult = ((bResult) && - (p_rReverseIPv4Domain.addLabel(scpcReverseIPv4Domain)) && - (p_rReverseIPv4Domain.addLabel(scpcReverseTopDomain)) && + (p_rReverseIPv4Domain.addLabel(clsConsts::pcReverseIPv4Domain)) && + (p_rReverseIPv4Domain.addLabel(clsConsts::pcReverseTopDomain)) && (p_rReverseIPv4Domain.addLabel(0))); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForReverseIPv4: FAILED!\n"), _DH());); return bResult; @@ -1279,9 +1293,10 @@ bool MDNSResponder::clsHost::_buildDomainForReverseIPv4(IPAddress p_IPv4Address, The IPv6 address is stringized by printing the 16 address bytes (32 nibbles) into a char buffer in reverse order and adding 'ip6.arpa' (eg. 3.B.6.E.A.1.B.B.A.B.F.7.F.8.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.8.E.F.ip6.arpa). Used while detecting reverse IPv6 questions and answering these + */ -bool MDNSResponder::clsHost::_buildDomainForReverseIPv6(IPAddress p_IPv6Address, - MDNSResponder::clsHost::stcRRDomain& p_rReverseIPv6Domain) const +bool clsLEAMDNSHost::_buildDomainForReverseIPv6(IPAddress p_IPv6Address, + clsLEAMDNSHost::clsRRDomain& p_rReverseIPv6Domain) const { bool bResult = ((p_IPv6Address.isSet()) && (p_IPv6Address.isV6())); @@ -1289,7 +1304,7 @@ bool MDNSResponder::clsHost::_buildDomainForReverseIPv6(IPAddress p_IPv6Address, p_rReverseIPv6Domain.clear(); const uint16_t* pRaw = p_IPv6Address.raw6(); - for (int8_t i8 = (MDNS_IPV6_SIZE / 2); ((bResult) && (i8 > 0)); --i8) // 8..1 + for (int8_t i8 = (clsConsts::u16IPv6Size / 2); ((bResult) && (i8 > 0)); --i8) // 8..1 { uint16_t u16Part = ntohs(pRaw[i8 - 1] & 0xFFFF); char acBuffer[2]; @@ -1301,8 +1316,8 @@ bool MDNSResponder::clsHost::_buildDomainForReverseIPv6(IPAddress p_IPv6Address, } } bResult = ((bResult) && - (p_rReverseIPv6Domain.addLabel(scpcReverseIPv6Domain)) && // .ip6.arpa - (p_rReverseIPv6Domain.addLabel(scpcReverseTopDomain)) && // .local + (p_rReverseIPv6Domain.addLabel(clsConsts::pcReverseIPv6Domain)) && // .ip6.arpa + (p_rReverseIPv6Domain.addLabel(clsConsts::pcReverseTopDomain)) && // .local (p_rReverseIPv6Domain.addLabel(0))); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForReverseIPv6: FAILED!\n"), _DH());); return bResult; @@ -1311,35 +1326,40 @@ bool MDNSResponder::clsHost::_buildDomainForReverseIPv6(IPAddress p_IPv6Address, /* + UDP + */ /* MDNSResponder::_udpReadBuffer + */ -bool MDNSResponder::clsHost::_udpReadBuffer(unsigned char* p_pBuffer, - size_t p_stLength) +bool clsLEAMDNSHost::_udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength) { - bool bResult = ((true/*m_rUDPContext.getSize() > p_stLength*/) && + bool bResult = ((m_pUDPContext->getSize() >= p_stLength) && (p_pBuffer) && (p_stLength) && - ((p_stLength == m_rUDPContext.read((char*)p_pBuffer, p_stLength)))); + ((p_stLength == m_pUDPContext->read((char*)p_pBuffer, p_stLength)))); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _udpReadBuffer: FAILED!\n"), _DH());); return bResult; } /* MDNSResponder::_udpRead8 + */ -bool MDNSResponder::clsHost::_udpRead8(uint8_t& p_ru8Value) +bool clsLEAMDNSHost::_udpRead8(uint8_t& p_ru8Value) { return _udpReadBuffer((unsigned char*)&p_ru8Value, sizeof(p_ru8Value)); } /* MDNSResponder::_udpRead16 + */ -bool MDNSResponder::clsHost::_udpRead16(uint16_t& p_ru16Value) +bool clsLEAMDNSHost::_udpRead16(uint16_t& p_ru16Value) { bool bResult = false; @@ -1353,8 +1373,9 @@ bool MDNSResponder::clsHost::_udpRead16(uint16_t& p_ru16Value) /* MDNSResponder::_udpRead32 + */ -bool MDNSResponder::clsHost::_udpRead32(uint32_t& p_ru32Value) +bool clsLEAMDNSHost::_udpRead32(uint32_t& p_ru32Value) { bool bResult = false; @@ -1368,29 +1389,32 @@ bool MDNSResponder::clsHost::_udpRead32(uint32_t& p_ru32Value) /* MDNSResponder::_udpAppendBuffer + */ -bool MDNSResponder::clsHost::_udpAppendBuffer(const unsigned char* p_pcBuffer, - size_t p_stLength) +bool clsLEAMDNSHost::_udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength) { bool bResult = ((p_pcBuffer) && (p_stLength) && - (p_stLength == m_rUDPContext.append((const char*)p_pcBuffer, p_stLength))); + (p_stLength == m_pUDPContext->append((const char*)p_pcBuffer, p_stLength))); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _udpAppendBuffer: FAILED!\n"), _DH());); return bResult; } /* MDNSResponder::_udpAppend8 + */ -bool MDNSResponder::clsHost::_udpAppend8(uint8_t p_u8Value) +bool clsLEAMDNSHost::_udpAppend8(uint8_t p_u8Value) { return (_udpAppendBuffer((unsigned char*)&p_u8Value, sizeof(p_u8Value))); } /* MDNSResponder::_udpAppend16 + */ -bool MDNSResponder::clsHost::_udpAppend16(uint16_t p_u16Value) +bool clsLEAMDNSHost::_udpAppend16(uint16_t p_u16Value) { p_u16Value = lwip_htons(p_u16Value); return (_udpAppendBuffer((unsigned char*)&p_u16Value, sizeof(p_u16Value))); @@ -1398,8 +1422,9 @@ bool MDNSResponder::clsHost::_udpAppend16(uint16_t p_u16Value) /* MDNSResponder::_udpAppend32 + */ -bool MDNSResponder::clsHost::_udpAppend32(uint32_t p_u32Value) +bool clsLEAMDNSHost::_udpAppend32(uint32_t p_u32Value) { p_u32Value = lwip_htonl(p_u32Value); return (_udpAppendBuffer((unsigned char*)&p_u32Value, sizeof(p_u32Value))); @@ -1408,12 +1433,13 @@ bool MDNSResponder::clsHost::_udpAppend32(uint32_t p_u32Value) #ifdef DEBUG_ESP_MDNS_RESPONDER /* MDNSResponder::_udpDump + */ -bool MDNSResponder::clsHost::_udpDump(bool p_bMovePointer /*= false*/) +bool clsLEAMDNSHost::_udpDump(bool p_bMovePointer /*= false*/) { const uint8_t cu8BytesPerLine = 16; - uint32_t u32StartPosition = m_rUDPContext.tell(); + uint32_t u32StartPosition = m_pUDPContext->tell(); DEBUG_OUTPUT.println("UDP Context Dump:"); uint32_t u32Counter = 0; uint8_t u8Byte = 0; @@ -1426,29 +1452,30 @@ bool MDNSResponder::clsHost::_udpDump(bool p_bMovePointer /*= false*/) if (!p_bMovePointer) // Restore { - m_rUDPContext.seek(u32StartPosition); + m_pUDPContext->seek(u32StartPosition); } return true; } /* MDNSResponder::_udpDump + */ -bool MDNSResponder::clsHost::_udpDump(unsigned p_uOffset, - unsigned p_uLength) +bool clsLEAMDNSHost::_udpDump(unsigned p_uOffset, + unsigned p_uLength) { - if (m_rUDPContext.isValidOffset(p_uOffset)) + if (m_pUDPContext->isValidOffset(p_uOffset)) { - unsigned uCurrentPosition = m_rUDPContext.tell(); // Remember start position + unsigned uCurrentPosition = m_pUDPContext->tell(); // Remember start position - m_rUDPContext.seek(p_uOffset); + m_pUDPContext->seek(p_uOffset); uint8_t u8Byte; for (unsigned u = 0; ((u < p_uLength) && (_udpRead8(u8Byte))); ++u) { DEBUG_OUTPUT.printf_P(PSTR("%02x "), u8Byte); } // Return to start position - m_rUDPContext.seek(uCurrentPosition); + m_pUDPContext->seek(uCurrentPosition); } return true; } @@ -1471,8 +1498,9 @@ bool MDNSResponder::clsHost::_udpDump(unsigned p_uOffset, All 16-bit and 32-bit elements need to be translated form network coding to host coding (done in _udpRead16 and _udpRead32) In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they need some mapping here + */ -bool MDNSResponder::clsHost::_readMDNSMsgHeader(MDNSResponder::clsHost::stcMsgHeader& p_rMsgHeader) +bool clsLEAMDNSHost::_readMDNSMsgHeader(clsLEAMDNSHost::clsMsgHeader& p_rMsgHeader) { bool bResult = false; @@ -1514,9 +1542,10 @@ bool MDNSResponder::clsHost::_readMDNSMsgHeader(MDNSResponder::clsHost::stcMsgHe /* MDNSResponder::_write8 + */ -bool MDNSResponder::clsHost::_write8(uint8_t p_u8Value, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_write8(uint8_t p_u8Value, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { return ((_udpAppend8(p_u8Value)) && (p_rSendParameter.shiftOffset(sizeof(p_u8Value)))); @@ -1524,9 +1553,10 @@ bool MDNSResponder::clsHost::_write8(uint8_t p_u8Value, /* MDNSResponder::_write16 + */ -bool MDNSResponder::clsHost::_write16(uint16_t p_u16Value, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_write16(uint16_t p_u16Value, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { return ((_udpAppend16(p_u16Value)) && (p_rSendParameter.shiftOffset(sizeof(p_u16Value)))); @@ -1534,9 +1564,10 @@ bool MDNSResponder::clsHost::_write16(uint16_t p_u16Value, /* MDNSResponder::_write32 + */ -bool MDNSResponder::clsHost::_write32(uint32_t p_u32Value, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_write32(uint32_t p_u32Value, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { return ((_udpAppend32(p_u32Value)) && (p_rSendParameter.shiftOffset(sizeof(p_u32Value)))); @@ -1550,9 +1581,10 @@ bool MDNSResponder::clsHost::_write32(uint32_t p_u32Value, All 16-bit and 32-bit elements need to be translated form host coding to network coding (done in _udpAppend16 and _udpAppend32) In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they need some mapping here + */ -bool MDNSResponder::clsHost::_writeMDNSMsgHeader(const MDNSResponder::clsHost::stcMsgHeader& p_MsgHeader, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSMsgHeader(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), _DH(), @@ -1580,9 +1612,10 @@ bool MDNSResponder::clsHost::_writeMDNSMsgHeader(const MDNSResponder::clsHost::s /* MDNSResponder::_writeRRAttributes + */ -bool MDNSResponder::clsHost::_writeMDNSRRAttributes(const MDNSResponder::clsHost::stcRRAttributes& p_Attributes, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSRRAttributes(const clsLEAMDNSHost::clsRRAttributes& p_Attributes, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { bool bResult = ((_write16(p_Attributes.m_u16Type, p_rSendParameter)) && (_write16(p_Attributes.m_u16Class, p_rSendParameter))); @@ -1593,9 +1626,10 @@ bool MDNSResponder::clsHost::_writeMDNSRRAttributes(const MDNSResponder::clsHost /* MDNSResponder::_writeMDNSRRDomain + */ -bool MDNSResponder::clsHost::_writeMDNSRRDomain(const MDNSResponder::clsHost::stcRRDomain& p_Domain, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSRRDomain(const clsLEAMDNSHost::clsRRDomain& p_Domain, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { bool bResult = ((_udpAppendBuffer((const unsigned char*)p_Domain.m_acName, p_Domain.m_u16NameLength)) && (p_rSendParameter.shiftOffset(p_Domain.m_u16NameLength))); @@ -1619,26 +1653,26 @@ bool MDNSResponder::clsHost::_writeMDNSRRDomain(const MDNSResponder::clsHost::st and written to the output buffer. */ -bool MDNSResponder::clsHost::_writeMDNSHostDomain(const char* p_pcHostName, - bool p_bPrependRDLength, - uint16_t p_u16AdditionalLength, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSHostDomain(const char* p_pcHostName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)p_pcHostName, false); - stcRRDomain hostDomain; + clsRRDomain hostDomain; bool bResult = (u16CachedDomainOffset // Found cached domain -> mark as compressed domain - ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + ? ((clsConsts::u8DomainCompressMark > ((u16CachedDomainOffset >> 8) & ~clsConsts::u8DomainCompressMark)) && // Valid offset ((!p_bPrependRDLength) || - (_write16((2 + p_u16AdditionalLength), p_rSendParameter))) && // Length of 'Cxxx' - (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write16((2 + p_u16AdditionalLength), p_rSendParameter))) && // Length of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | clsConsts::u8DomainCompressMark), p_rSendParameter)) && // Compression mark (and offset) (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) // No cached domain -> add this domain to cache and write full domain name - : ((_buildDomainForHost(p_pcHostName, hostDomain)) && // eg. esp8266.local + : ((_buildDomainForHost(p_pcHostName, hostDomain)) && // eg. esp8266.local ((!p_bPrependRDLength) || - (_write16((hostDomain.m_u16NameLength + p_u16AdditionalLength), p_rSendParameter))) && // RDLength (if needed) + (_write16((hostDomain.m_u16NameLength + p_u16AdditionalLength), p_rSendParameter))) && // RDLength (if needed) (p_rSendParameter.addDomainCacheItem((const void*)p_pcHostName, false, p_rSendParameter.m_u16Offset)) && (_writeMDNSRRDomain(hostDomain, p_rSendParameter)))); @@ -1659,27 +1693,27 @@ bool MDNSResponder::clsHost::_writeMDNSHostDomain(const char* p_pcHostName, the instance name (p_bIncludeName is set) and thoose who don't. */ -bool MDNSResponder::clsHost::_writeMDNSServiceDomain(const MDNSResponder::clsHost::stcService& p_Service, - bool p_bIncludeName, - bool p_bPrependRDLength, - uint16_t p_u16AdditionalLength, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSServiceDomain(const clsLEAMDNSHost::clsService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)&p_Service, p_bIncludeName); - stcRRDomain serviceDomain; + clsRRDomain serviceDomain; bool bResult = (u16CachedDomainOffset // Found cached domain -> mark as compressed domain - ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + ? ((clsConsts::u8DomainCompressMark > ((u16CachedDomainOffset >> 8) & ~clsConsts::u8DomainCompressMark)) && // Valid offset ((!p_bPrependRDLength) || - (_write16((2 + p_u16AdditionalLength), p_rSendParameter))) && // Lenght of 'Cxxx' - (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write16((2 + p_u16AdditionalLength), p_rSendParameter))) && // Lenght of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | clsConsts::u8DomainCompressMark), p_rSendParameter)) && // Compression mark (and offset) (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) // No cached domain -> add this domain to cache and write full domain name - : ((_buildDomainForService(p_Service, p_bIncludeName, serviceDomain)) && // eg. MyESP._http._tcp.local + : ((_buildDomainForService(p_Service, p_bIncludeName, serviceDomain)) && // eg. MyESP._http._tcp.local ((!p_bPrependRDLength) || - (_write16((serviceDomain.m_u16NameLength + p_u16AdditionalLength), p_rSendParameter))) && // RDLength (if needed) + (_write16((serviceDomain.m_u16NameLength + p_u16AdditionalLength), p_rSendParameter))) && // RDLength (if needed) (p_rSendParameter.addDomainCacheItem((const void*)&p_Service, p_bIncludeName, p_rSendParameter.m_u16Offset)) && (_writeMDNSRRDomain(serviceDomain, p_rSendParameter)))); @@ -1698,8 +1732,8 @@ bool MDNSResponder::clsHost::_writeMDNSServiceDomain(const MDNSResponder::clsHos QCLASS (16bit, eg. IN) */ -bool MDNSResponder::clsHost::_writeMDNSQuestion(MDNSResponder::clsHost::stcRRQuestion& p_Question, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSQuestion(clsLEAMDNSHost::clsRRQuestion& p_Question, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSQuestion\n"));); @@ -1716,7 +1750,6 @@ bool MDNSResponder::clsHost::_writeMDNSQuestion(MDNSResponder::clsHost::stcRRQue }); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSQuestion: FAILED!\n"), _DH());); return bResult; - } @@ -1735,24 +1768,25 @@ bool MDNSResponder::clsHost::_writeMDNSQuestion(MDNSResponder::clsHost::stcRRQue eg. esp8266.local A 0x8001 120 4 123.456.789.012 Ref: http://www.zytrax.com/books/dns/ch8/a.html + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_A(IPAddress p_IPAddress, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_A(IPAddress p_IPAddress, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_A (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); - stcRRAttributes attributes(DNS_RRTYPE_A, + clsRRAttributes attributes(DNS_RRTYPE_A, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - const unsigned char aucIPAddress[MDNS_IPV4_SIZE] = { p_IPAddress[0], p_IPAddress[1], p_IPAddress[2], p_IPAddress[3] }; + const unsigned char aucIPAddress[clsConsts::u16IPv4Size] = { p_IPAddress[0], p_IPAddress[1], p_IPAddress[2], p_IPAddress[3] }; bool bResult = ((p_IPAddress.isV4()) && (_writeMDNSHostDomain(m_pcHostName, false, 0, p_rSendParameter)) && (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL - (_write16(MDNS_IPV4_SIZE, p_rSendParameter)) && // RDLength - (_udpAppendBuffer(aucIPAddress, MDNS_IPV4_SIZE)) && // RData - (p_rSendParameter.shiftOffset(MDNS_IPV4_SIZE))); + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL + (_write16(clsConsts::u16IPv4Size, p_rSendParameter)) && // RDLength + (_udpAppendBuffer(aucIPAddress, clsConsts::u16IPv4Size)) && // RData + (p_rSendParameter.shiftOffset(clsConsts::u16IPv4Size))); DEBUG_EX_INFO(if (bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_A %s.local Type:%s Class:0x%04X TTL:%u %s\n"), @@ -1762,7 +1796,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_A(IPAddress p_IPAddress, attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_IPAddress.toString().c_str()); ); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_A: FAILED!\n"), _DH());); @@ -1778,23 +1812,24 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_A(IPAddress p_IPAddress, eg. 012.789.456.123.in-addr.arpa PTR 0x8001 120 15 esp8266.local Used while answering reverse IPv4 questions + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv4 (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); - stcRRDomain reverseIPv4Domain; - stcRRAttributes attributes(DNS_RRTYPE_PTR, + clsRRDomain reverseIPv4Domain; + clsRRAttributes attributes(DNS_RRTYPE_PTR, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - stcRRDomain hostDomain; + clsRRDomain hostDomain; bool bResult = ((p_IPAddress.isV4()) && (_buildDomainForReverseIPv4(p_IPAddress, reverseIPv4Domain)) && // 012.789.456.123.in-addr.arpa (_writeMDNSRRDomain(reverseIPv4Domain, p_rSendParameter)) && (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL (_writeMDNSHostDomain(m_pcHostName, true, 0, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) DEBUG_EX_INFO(if (bResult) @@ -1805,7 +1840,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), m_pcHostName); ); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv4: FAILED!\n"), _DH());); @@ -1822,21 +1857,22 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, PTR all-services -> service type eg. _services._dns-sd._udp.local PTR 0x8001 5400 xx _http._tcp.local http://www.zytrax.com/books/dns/ch8/ptr.html + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_TYPE(MDNSResponder::clsHost::stcService& p_rService, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_TYPE(clsLEAMDNSHost::clsService& p_rService, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_TYPE\n"));); - stcRRDomain dnssdDomain; - stcRRDomain serviceDomain; - stcRRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush for shared records! only INternet + clsRRDomain dnssdDomain; + clsRRDomain serviceDomain; + clsRRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush for shared records! only INternet bool bResult = ((_buildDomainForDNSSD(dnssdDomain)) && // _services._dns-sd._udp.local (_writeMDNSRRDomain(dnssdDomain, p_rSendParameter)) && (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), p_rSendParameter)) && // TTL + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), p_rSendParameter)) && // TTL (_writeMDNSServiceDomain(p_rService, false, true, 0, p_rSendParameter))); // RDLength & RData (service domain, eg. _http._tcp.local) DEBUG_EX_INFO(if (bResult) @@ -1847,8 +1883,8 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_TYPE(MDNSResponder::clsHost::s attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), - p_rService.m_pcServiceType, + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), + p_rService.m_pcType, p_rService.m_pcProtocol); ); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_TYPE: FAILED!\n"), _DH());); @@ -1864,32 +1900,33 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_TYPE(MDNSResponder::clsHost::s PTR service type -> service name eg. _http.tcp.local PTR 0x8001 120 xx myESP._http._tcp.local http://www.zytrax.com/books/dns/ch8/ptr.html + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_NAME(MDNSResponder::clsHost::stcService& p_rService, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_NAME(clsLEAMDNSHost::clsService& p_rService, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME\n"), _DH());); - stcRRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush for shared records! only INternet + clsRRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush for shared records! only INternet bool bResult = ((_writeMDNSServiceDomain(p_rService, false, false, 0, p_rSendParameter)) && // _http._tcp.local (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), p_rSendParameter)) && // TTL + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), p_rSendParameter)) && // TTL (_writeMDNSServiceDomain(p_rService, true, true, 0, p_rSendParameter))); // RDLength & RData (service domain, eg. MyESP._http._tcp.local) DEBUG_EX_INFO(if (bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME _%s._%s.local Type:%s Class:0x%04X TTL:%u %s._%s._%s.local\n"), _DH(), - p_rService.m_pcServiceType, + p_rService.m_pcType, p_rService.m_pcProtocol, _RRType2Name(attributes.m_u16Type), attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), - p_rService.m_pcName, - p_rService.m_pcServiceType, + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), + p_rService.m_pcInstanceName, + p_rService.m_pcType, p_rService.m_pcProtocol); ); DEBUG_EX_ERR(if (!bResult)DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME: FAILED!\n"), _DH());); @@ -1907,15 +1944,16 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_NAME(MDNSResponder::clsHost::s eg. myESP._http._tcp.local TXT 0x8001 120 4 c#=1 http://www.zytrax.com/books/dns/ch8/txt.html + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_TXT(MDNSResponder::clsHost::stcService& p_rService, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_TXT(clsLEAMDNSHost::clsService& p_rService, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"), _DH());); bool bResult = false; - stcRRAttributes attributes(DNS_RRTYPE_TXT, + clsRRAttributes attributes(DNS_RRTYPE_TXT, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet if ((_collectServiceTxts(p_rService)) && @@ -1923,42 +1961,59 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_TXT(MDNSResponder::clsHost::stcSer (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), p_rSendParameter)) && // TTL - (_write16(p_rService.m_Txts.length(), p_rSendParameter))) // RDLength + : (p_rSendParameter.m_bLegacyDNSQuery // TTL + ? clsConsts::u32LegacyTTL + : clsConsts::u32ServiceTTL)), p_rSendParameter)) && + (_write16((p_rService.m_Txts.count() // RDLength + ? p_rService.m_Txts.length() // default case + : 1), p_rSendParameter))) // If no TXT records exist, a single 0 byte is sent { - bResult = true; // RData Txts - for (stcServiceTxt* pTxt = p_rService.m_Txts.m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + if (p_rService.m_Txts.count()) { - unsigned char ucLengthByte = pTxt->length(); - bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length - (p_rSendParameter.shiftOffset(sizeof(ucLengthByte))) && - ((size_t)os_strlen(pTxt->m_pcKey) == m_rUDPContext.append(pTxt->m_pcKey, os_strlen(pTxt->m_pcKey))) && // Key - (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcKey))) && - (1 == m_rUDPContext.append("=", 1)) && // = - (p_rSendParameter.shiftOffset(1)) && - ((!pTxt->m_pcValue) || - (((size_t)os_strlen(pTxt->m_pcValue) == m_rUDPContext.append(pTxt->m_pcValue, os_strlen(pTxt->m_pcValue))) && // Value - (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcValue)))))); - - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: FAILED to write %sTxt %s=%s!\n"), _DH(), (pTxt->m_bTemp ? "temp. " : ""), (pTxt->m_pcKey ? : "?"), (pTxt->m_pcValue ? : "?"));); + for (const clsServiceTxt* pTxt : p_rService.m_Txts.m_Txts) + { + unsigned char ucLengthByte = pTxt->length(); + if (!((bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length + (p_rSendParameter.shiftOffset(sizeof(ucLengthByte))) && + ((size_t)os_strlen(pTxt->m_pcKey) == m_pUDPContext->append(pTxt->m_pcKey, os_strlen(pTxt->m_pcKey))) && // Key + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcKey))) && + (1 == m_pUDPContext->append("=", 1)) && // = + (p_rSendParameter.shiftOffset(1)) && + ((!pTxt->m_pcValue) || + (((size_t)os_strlen(pTxt->m_pcValue) == m_pUDPContext->append(pTxt->m_pcValue, os_strlen(pTxt->m_pcValue))) && // Value + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcValue))))))))) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: FAILED to write %sTxt %s=%s!\n"), _DH(), (pTxt->m_bTemp ? "temp. " : ""), (pTxt->m_pcKey ? : "?"), (pTxt->m_pcValue ? : "?"));); + break; + } + } + } + else + { + // RFC 6763 Ch.6: Every DNS-SD service MUST have a TXT record in addition to its SRV record, ... + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: Adding EMPTY TXT record!\n"), _DH());); + unsigned char ucLengthByte = 0; + bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length + (p_rSendParameter.shiftOffset(sizeof(ucLengthByte)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: FAILED to write EMPTY TXT record!\n"), _DH());); } } DEBUG_EX_INFO(if (bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT %s._%s._%s.local Type:%s Class:0x%04X TTL:%u \n"), _DH(), - p_rService.m_pcName, - p_rService.m_pcServiceType, + p_rService.m_pcInstanceName, + p_rService.m_pcType, p_rService.m_pcProtocol, _RRType2Name(attributes.m_u16Type), attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), - p_rService.m_pcName, - p_rService.m_pcServiceType, + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), + p_rService.m_pcInstanceName, + p_rService.m_pcType, p_rService.m_pcProtocol); ); @@ -1977,23 +2032,24 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_TXT(MDNSResponder::clsHost::stcSer eg. esp8266.local AAAA 0x8001 120 16 xxxx::xx http://www.zytrax.com/books/dns/ch8/aaaa.html + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); - stcRRAttributes attributes(DNS_RRTYPE_AAAA, + clsRRAttributes attributes(DNS_RRTYPE_AAAA, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet bool bResult = ((p_IPAddress.isV6()) && (_writeMDNSHostDomain(m_pcHostName, false, 0, p_rSendParameter)) && // esp8266.local (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL - (_write16(MDNS_IPV6_SIZE, p_rSendParameter)) && // RDLength - (_udpAppendBuffer((uint8_t*)p_IPAddress.raw6(), MDNS_IPV6_SIZE)) && // RData - (p_rSendParameter.shiftOffset(MDNS_IPV6_SIZE))); + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL + (_write16(clsConsts::u16IPv6Size, p_rSendParameter)) && // RDLength + (_udpAppendBuffer((uint8_t*)p_IPAddress.raw6(), clsConsts::u16IPv6Size)) && // RData + (p_rSendParameter.shiftOffset(clsConsts::u16IPv6Size))); DEBUG_EX_INFO(if (bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA %s.local Type:%s Class:0x%04X TTL:%u %s\n"), @@ -2003,7 +2059,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_IPAddress.toString().c_str()); ); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA: FAILED!\n"), _DH());); @@ -2018,14 +2074,15 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, eg. xxxx::xx.ip6.arpa PTR 0x8001 120 15 esp8266.local Used while answering reverse IPv6 questions + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv6%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); - stcRRDomain reverseIPv6Domain; - stcRRAttributes attributes(DNS_RRTYPE_PTR, + clsRRDomain reverseIPv6Domain; + clsRRAttributes attributes(DNS_RRTYPE_PTR, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet bool bResult = ((p_IPAddress.isV6()) && (_buildDomainForReverseIPv6(p_IPAddress, reverseIPv6Domain)) && // xxxx::xx.ip6.arpa @@ -2033,7 +2090,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL (_writeMDNSHostDomain(m_pcHostName, true, 0, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) DEBUG_EX_INFO(if (bResult) @@ -2044,7 +2101,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), m_pcHostName); ); DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv6: FAILED!\n"), _DH());); @@ -2057,24 +2114,25 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, eg. MyESP._http.tcp.local SRV 0x8001 120 0 0 60068 esp8266.local http://www.zytrax.com/books/dns/ch8/srv.html ???? Include instance name ???? + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_SRV(MDNSResponder::clsHost::stcService& p_rService, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_SRV(clsLEAMDNSHost::clsService& p_rService, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_SRV%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); - uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyQuery + uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyDNSQuery ? 0 : p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostName, false)); - stcRRAttributes attributes(DNS_RRTYPE_SRV, + clsRRAttributes attributes(DNS_RRTYPE_SRV, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - stcRRDomain hostDomain; + clsRRDomain hostDomain; bool bResult = ((_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL/*MDNS_SERVICE_TTL*/)), p_rSendParameter)) && // TTL + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL/*Consts::u32ServiceTTL*/)), p_rSendParameter)) && // TTL (!u16CachedDomainOffset // No cache for domain name (or no compression allowed) ? ((_buildDomainForHost(m_pcHostName, hostDomain)) && @@ -2082,36 +2140,36 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_SRV(MDNSResponder::clsHost::stcSer sizeof(uint16_t /*Weight*/) + sizeof(uint16_t /*Port*/) + hostDomain.m_u16NameLength), p_rSendParameter)) && // Domain length - (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority - (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight + (_write16(clsConsts::u16SRVPriority, p_rSendParameter)) && // Priority + (_write16(clsConsts::u16SRVWeight, p_rSendParameter)) && // Weight (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port (p_rSendParameter.addDomainCacheItem((const void*)m_pcHostName, false, p_rSendParameter.m_u16Offset)) && (_writeMDNSRRDomain(hostDomain, p_rSendParameter))) // Host, eg. esp8266.local // Cache available for domain - : ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + : ((clsConsts::u8DomainCompressMark > ((u16CachedDomainOffset >> 8) & ~clsConsts::u8DomainCompressMark)) && // Valid offset (_write16((sizeof(uint16_t /*Prio*/) + // RDLength sizeof(uint16_t /*Weight*/) + sizeof(uint16_t /*Port*/) + 2), p_rSendParameter)) && // Length of 'C0xx' - (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority - (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight + (_write16(clsConsts::u16SRVPriority, p_rSendParameter)) && // Priority + (_write16(clsConsts::u16SRVWeight, p_rSendParameter)) && // Weight (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port - (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8(((u16CachedDomainOffset >> 8) | clsConsts::u8DomainCompressMark), p_rSendParameter)) && // Compression mark (and offset) (_write8((uint8_t)u16CachedDomainOffset, p_rSendParameter))))); // Offset DEBUG_EX_INFO(if (bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_SRV %s._%s._%s.local Type:%s Class:0x%04X TTL:%u %u %u %u %s.local\n"), _DH(), - p_rService.m_pcName, - p_rService.m_pcServiceType, + p_rService.m_pcInstanceName, + p_rService.m_pcType, p_rService.m_pcProtocol, _RRType2Name(attributes.m_u16Type), attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), - MDNS_SRV_PRIORITY, - MDNS_SRV_WEIGHT, + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), + clsConsts::u16SRVPriority, + clsConsts::u16SRVWeight, p_rService.m_u16Port, m_pcHostName); ); @@ -2121,37 +2179,42 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_SRV(MDNSResponder::clsHost::stcSer /* MDNSResponder::_createNSECBitmap + */ -MDNSResponder::clsHost::stcNSECBitmap* MDNSResponder::clsHost::_createNSECBitmap(uint32_t p_u32NSECContent) +clsLEAMDNSHost::clsNSECBitmap* clsLEAMDNSHost::_createNSECBitmap(uint32_t p_u32NSECContent) { // Currently 6 bytes (6*8 -> 0..47) are long enough, and only this is implemented - stcNSECBitmap* pNSECBitmap = new stcNSECBitmap; + clsNSECBitmap* pNSECBitmap = new clsNSECBitmap; if (pNSECBitmap) { +#ifdef MDNS_IPV4_SUPPORT if (p_u32NSECContent & static_cast(enuContentFlag::A)) { - pNSECBitmap->setBit(DNS_RRTYPE_A); // 01/0x01 + pNSECBitmap->setBit(DNS_RRTYPE_A); // 01/0x01 } +#endif if ((p_u32NSECContent & static_cast(enuContentFlag::PTR_IPv4)) || (p_u32NSECContent & static_cast(enuContentFlag::PTR_IPv6))) { - pNSECBitmap->setBit(DNS_RRTYPE_PTR); // 12/0x0C + pNSECBitmap->setBit(DNS_RRTYPE_PTR); // 12/0x0C } +#ifdef MDNS_IPV6_SUPPORT if (p_u32NSECContent & static_cast(enuContentFlag::AAAA)) { - pNSECBitmap->setBit(DNS_RRTYPE_AAAA); // 28/0x1C + pNSECBitmap->setBit(DNS_RRTYPE_AAAA); // 28/0x1C } +#endif if (p_u32NSECContent & static_cast(enuContentFlag::TXT)) { - pNSECBitmap->setBit(DNS_RRTYPE_TXT); // 16/0x10 + pNSECBitmap->setBit(DNS_RRTYPE_TXT); // 16/0x10 } if (p_u32NSECContent & static_cast(enuContentFlag::SRV)) { - pNSECBitmap->setBit(DNS_RRTYPE_SRV); // 33/0x21 + pNSECBitmap->setBit(DNS_RRTYPE_SRV); // 33/0x21 } if (p_u32NSECContent & static_cast(enuContentFlag::NSEC)) { - pNSECBitmap->setBit(DNS_RRTYPE_NSEC); // 47/0x2F + pNSECBitmap->setBit(clsConsts::u8DNS_RRTYPE_NSEC); // 47/0x2F } } return pNSECBitmap; @@ -2159,9 +2222,10 @@ MDNSResponder::clsHost::stcNSECBitmap* MDNSResponder::clsHost::_createNSECBitmap /* MDNSResponder::_writeMDNSNSECBitmap + */ -bool MDNSResponder::clsHost::_writeMDNSNSECBitmap(const MDNSResponder::clsHost::stcNSECBitmap& p_NSECBitmap, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSNSECBitmap(const clsLEAMDNSHost::clsNSECBitmap& p_NSECBitmap, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("_writeMDNSNSECBitmap: ")); for (uint16_t u=0; ulength()), p_rSendParameter)) && // XX esp8266.local (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap @@ -2208,7 +2273,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC(uint32_t p_u32NSECContent, attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), m_pcHostName, _NSECBitmap2String(pNSECBitmap)); ); @@ -2228,18 +2293,19 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC(uint32_t p_u32NSECContent, /* MDNSResponder::_writeMDNSAnswer_NSEC_PTR_IPv4(host) - eg. 012.789.456.123.in-addr.arpa NSEC 0x8001 120 XX 012.789.456.123.in-addr.arpa xxx + eg. 012.789.456.123.in-addr.arpa NSEC 0x8001 120 XX 012.789.456.123.in-addr.arpa xyz http://www.zytrax.com/books/dns/ch8/nsec.html + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddress, - stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv4\n"));); - stcRRAttributes attributes(DNS_RRTYPE_NSEC, + clsRRAttributes attributes(clsConsts::u8DNS_RRTYPE_NSEC, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - stcNSECBitmap* pNSECBitmap = _createNSECBitmap(static_cast(enuContentFlag::PTR_IPv4)); - stcRRDomain reverseIPv4Domain; + clsNSECBitmap* pNSECBitmap = _createNSECBitmap(static_cast(enuContentFlag::PTR_IPv4)); + clsRRDomain reverseIPv4Domain; bool bResult = ((p_IPAddress.isV4()) && (pNSECBitmap) && // NSEC bitmap created (_buildDomainForReverseIPv4(p_IPAddress, reverseIPv4Domain)) && // 012.789.456.123.in-addr.arpa @@ -2247,7 +2313,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddres (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL (_write16((reverseIPv4Domain.m_u16NameLength + (2 + pNSECBitmap->length())), p_rSendParameter)) && (_writeMDNSRRDomain(reverseIPv4Domain, p_rSendParameter)) && // 012.789.456.123.in-addr.arpa (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap @@ -2261,7 +2327,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddres attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL))); + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL))); _printRRDomain(reverseIPv4Domain); DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), _NSECBitmap2String(pNSECBitmap)); }); @@ -2282,18 +2348,19 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddres /* MDNSResponder::_writeMDNSAnswer_NSEC_PTR_IPv6(host) - eg. 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa NSEC 0x8001 120 XX 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa xxx + eg. 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa NSEC 0x8001 120 XX 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa xyz http://www.zytrax.com/books/dns/ch8/nsec.html + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddress, - stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv6\n"));); - stcRRAttributes attributes(DNS_RRTYPE_NSEC, + clsRRAttributes attributes(clsConsts::u8DNS_RRTYPE_NSEC, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - stcNSECBitmap* pNSECBitmap = _createNSECBitmap(static_cast(enuContentFlag::PTR_IPv6)); - stcRRDomain reverseIPv6Domain; + clsNSECBitmap* pNSECBitmap = _createNSECBitmap(static_cast(enuContentFlag::PTR_IPv6)); + clsRRDomain reverseIPv6Domain; bool bResult = ((p_IPAddress.isV6()) && (pNSECBitmap) && // NSEC bitmap created (_buildDomainForReverseIPv6(p_IPAddress, reverseIPv6Domain)) && // 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa @@ -2301,7 +2368,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddres (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_HOST_TTL)), p_rSendParameter)) && // TTL + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL (_write16((reverseIPv6Domain.m_u16NameLength + (2 + pNSECBitmap->length())), p_rSendParameter)) && (_writeMDNSRRDomain(reverseIPv6Domain, p_rSendParameter)) && // 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap @@ -2315,7 +2382,7 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddres attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL))); + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL))); _printRRDomain(reverseIPv6Domain); DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), _NSECBitmap2String(pNSECBitmap)); }); @@ -2334,38 +2401,39 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddres /* MDNSResponder::_writeMDNSAnswer_NSEC(service) - eg. MyESP._http.tcp.local NSEC 0x8001 4500 XX MyESP._http.tcp.local xxx + eg. MyESP._http.tcp.local NSEC 0x8001 4500 XX MyESP._http.tcp.local xyz http://www.zytrax.com/books/dns/ch8/nsec.html + */ -bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC(MDNSResponder::clsHost::stcService& p_rService, - uint32_t p_u32NSECContent, - MDNSResponder::clsHost::stcSendParameter& p_rSendParameter) +bool clsLEAMDNSHost::_writeMDNSAnswer_NSEC(clsLEAMDNSHost::clsService& p_rService, + uint32_t p_u32NSECContent, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC (service: %s)\n"), _DH(), _replyFlags2String(p_u32NSECContent));); - stcRRAttributes attributes(DNS_RRTYPE_NSEC, + clsRRAttributes attributes(clsConsts::u8DNS_RRTYPE_NSEC, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - stcNSECBitmap* pNSECBitmap = _createNSECBitmap(p_u32NSECContent); + clsNSECBitmap* pNSECBitmap = _createNSECBitmap(p_u32NSECContent); bool bResult = ((pNSECBitmap) && // NSEC bitmap created (_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS (_write32((p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), p_rSendParameter)) && // TTL + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), p_rSendParameter)) && // TTL (_writeMDNSServiceDomain(p_rService, true, true, (2 + pNSECBitmap->length()), p_rSendParameter)) && // XX MyESP._http._tcp.local (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap DEBUG_EX_INFO(if (bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC %s._%s._%s.local Type:%s Class:0x%04X TTL:%u %s\n"), _DH(), - p_rService.m_pcName, - p_rService.m_pcServiceType, + p_rService.m_pcInstanceName, + p_rService.m_pcType, p_rService.m_pcProtocol, _RRType2Name(attributes.m_u16Type), attributes.m_u16Class, (p_rSendParameter.m_bUnannounce ? 0 - : (p_rSendParameter.m_bLegacyQuery ? MDNS_LEGACY_TTL : MDNS_SERVICE_TTL)), + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), _NSECBitmap2String(pNSECBitmap)); ); @@ -2379,8 +2447,10 @@ bool MDNSResponder::clsHost::_writeMDNSAnswer_NSEC(MDNSResponder::clsHost::stcSe return bResult; } + } // namespace MDNSImplementation + } // namespace esp8266 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp deleted file mode 100755 index 4b3d22902e..0000000000 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_API.cpp +++ /dev/null @@ -1,4164 +0,0 @@ -/* - LEAmDNS2_API.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - - -#include -#include - -#include "LEAmDNS2_Priv.h" - - -namespace -{ - -/* - strrstr (static) - - Backwards search for p_pcPattern in p_pcString - Based on: https://stackoverflow.com/a/1634398/2778898 - -*/ -const char* strrstr(const char*__restrict p_pcString, const char*__restrict p_pcPattern) -{ - const char* pcResult = 0; - - size_t stStringLength = (p_pcString ? strlen(p_pcString) : 0); - size_t stPatternLength = (p_pcPattern ? strlen(p_pcPattern) : 0); - - if ((stStringLength) && - (stPatternLength) && - (stPatternLength <= stStringLength)) - { - // Pattern is shorter or has the same length tham the string - - for (const char* s = (p_pcString + stStringLength - stPatternLength); s >= p_pcString; --s) - { - if (0 == strncmp(s, p_pcPattern, stPatternLength)) - { - pcResult = s; - break; - } - } - } - return pcResult; -} - -} // anonymous - - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace experimental -{ - -/** - STRINGIZE -*/ -#ifndef STRINGIZE -#define STRINGIZE(x) #x -#endif -#ifndef STRINGIZE_VALUE_OF -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) -#endif - -/** - HELPERS -*/ - -/* - MDNSResponder::indexDomain (static) - - Updates the given domain 'p_rpcHostName' by appending a delimiter and an index number. - - If the given domain already hasa numeric index (after the given delimiter), this index - incremented. If not, the delimiter and index '2' is added. - - If 'p_rpcHostName' is empty (==0), the given default name 'p_pcDefaultHostName' is used, - if no default is given, 'esp8266' is used. - -*/ -/*static*/ bool MDNSResponder::indexDomain(char*& p_rpcDomain, - const char* p_pcDivider /*= "-"*/, - const char* p_pcDefaultDomain /*= 0*/) -{ - bool bResult = false; - - // Ensure a divider exists; use '-' as default - const char* pcDivider = (p_pcDivider ? : "-"); - - if (p_rpcDomain) - { - const char* pFoundDivider = strrstr(p_rpcDomain, pcDivider); - if (pFoundDivider) // maybe already extended - { - char* pEnd = 0; - unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10); - if ((ulIndex) && - ((pEnd - p_rpcDomain) == (ptrdiff_t)strlen(p_rpcDomain)) && - (!*pEnd)) // Valid (old) index found - { - - char acIndexBuffer[16]; - sprintf(acIndexBuffer, "%lu", (++ulIndex)); - size_t stLength = ((pFoundDivider - p_rpcDomain + strlen(pcDivider)) + strlen(acIndexBuffer) + 1); - char* pNewHostName = new char[stLength]; - if (pNewHostName) - { - memcpy(pNewHostName, p_rpcDomain, (pFoundDivider - p_rpcDomain + strlen(pcDivider))); - pNewHostName[pFoundDivider - p_rpcDomain + strlen(pcDivider)] = 0; - strcat(pNewHostName, acIndexBuffer); - - delete[] p_rpcDomain; - p_rpcDomain = pNewHostName; - - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: FAILED to alloc new hostname!\n"));); - } - } - else - { - pFoundDivider = 0; // Flag the need to (base) extend the hostname - } - } - - if (!pFoundDivider) // not yet extended (or failed to increment extension) -> start indexing - { - size_t stLength = strlen(p_rpcDomain) + (strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0' - char* pNewHostName = new char[stLength]; - if (pNewHostName) - { - sprintf(pNewHostName, "%s%s2", p_rpcDomain, pcDivider); - - delete[] p_rpcDomain; - p_rpcDomain = pNewHostName; - - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: FAILED to alloc new hostname!\n"));); - } - } - } - else - { - // No given host domain, use base or default - const char* cpcDefaultName = (p_pcDefaultDomain ? : "esp8266"); - - size_t stLength = strlen(cpcDefaultName) + 1; // '\0' - p_rpcDomain = new char[stLength]; - if (p_rpcDomain) - { - strncpy(p_rpcDomain, cpcDefaultName, stLength); - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: FAILED to alloc new hostname!\n"));); - } - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: %s\n"), p_rpcDomain);); - return bResult; -} - - -/* - MDNSResponder::setStationHostName (static) - - Sets the staion hostname - -*/ -/*static*/ bool MDNSResponder::setNetIfHostName(netif* p_pNetIf, - const char* p_pcHostName) -{ - if ((p_pNetIf) && - (p_pcHostName)) - { - netif_set_hostname(p_pNetIf, p_pcHostName); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setNetIfHostName host name: %s!\n"), p_pcHostName);); - } - return true; -} - - -/** - INTERFACE -*/ - -/** - MDNSResponder::MDNSResponder -*/ -MDNSResponder::MDNSResponder(void) - : m_pUDPContext(0) -{ - _allocUDPContext(); -} - -/* - MDNSResponder::~MDNSResponder -*/ -MDNSResponder::~MDNSResponder(void) -{ - close(); -} - -/* - MDNSResponder::begin (hostname, netif, probe_callback) -*/ -MDNSResponder::hMDNSHost MDNSResponder::begin(const char* p_pcHostName, - netif* p_pNetIf, - MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, netif: %u)\n"), _DH(), (p_pcHostName ? : "-"), (p_pNetIf ? netif_get_index(p_pNetIf) : 0));); - - return (hMDNSHost)_begin(p_pcHostName, p_pNetIf, p_fnCallback); -} - -/* - MDNSResponder::begin (hostname, probe_callback) -*/ -bool MDNSResponder::begin(const char* p_pcHostName, - MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s)\n"), _DH(), (p_pcHostName ? : "_"));); - - return begin(p_pcHostName, (WiFiMode_t)wifi_get_opmode(), p_fnCallback); -} - -/* - MDNSResponder::begin (hostname, WiFiMode, probe_callback) -*/ -bool MDNSResponder::begin(const char* p_pcHostName, - WiFiMode_t p_WiFiMode, - MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, opmode: %u)\n"), _DH(), (p_pcHostName ? : "_"), (uint32_t)p_WiFiMode);); - - bool bResult = true; - - if ((bResult) && - (p_WiFiMode & WIFI_STA)) - { - bResult = (0 != _begin(p_pcHostName, netif_get_by_index(WIFI_STA), p_fnCallback)); - } - if ((bResult) && - (p_WiFiMode & WIFI_AP)) - { - bResult = (0 != _begin(p_pcHostName, netif_get_by_index(WIFI_AP), p_fnCallback)); - } - return bResult; -} - -/* - MDNSResponder::close -*/ -bool MDNSResponder::close(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_close(*(clsHost*)p_hMDNSHost))); -} - -/* - MDNSResponder::close (convenience) -*/ -bool MDNSResponder::close(void) -{ - clsHostList::iterator it(m_HostList.begin()); - while (m_HostList.end() != it) - { - _close(**it++); - } - - return _releaseUDPContext(); -} - - -/* - MDNSResponder::getMDNSHost (netif) -*/ -MDNSResponder::hMDNSHost MDNSResponder::getMDNSHost(netif* p_pNetIf) const -{ - return (hMDNSHost)(p_pNetIf ? _findHost(p_pNetIf) : 0); -} - -/* - MDNSResponder::getMDNSHost (WiFiMode) -*/ -MDNSResponder::hMDNSHost MDNSResponder::getMDNSHost(WiFiMode_t p_WiFiMode) const -{ - hMDNSHost hResult = 0; - - if (WIFI_STA == p_WiFiMode) - { - hResult = getMDNSHost(netif_get_by_index(WIFI_STA)); - } - else if (WIFI_AP == p_WiFiMode) - { - hResult = getMDNSHost(netif_get_by_index(WIFI_AP)); - } - return hResult; -} - -/* - MDNSResponder::setHostName -*/ -bool MDNSResponder::setHostName(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_NRH2Ptr(p_hMDNSHost)->setHostName(p_pcHostName)) && - (p_fnCallback ? setHostProbeResultCallback(p_hMDNSHost, p_fnCallback) : true)); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setHostName: FAILED for '%s'!\n"), _DH(p_hMDNSHost), (p_pcHostName ? : "-"));); - return bResult; -} - -/* - MDNSResponder::hostName -*/ -const char* MDNSResponder::hostName(const MDNSResponder::hMDNSHost p_hMDNSHost) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost) - ? (_NRH2Ptr(p_hMDNSHost)->hostName()) - : 0); -} - -/* - MDNSResponder::setHostProbeResultCallback -*/ -bool MDNSResponder::setHostProbeResultCallback(const hMDNSHost p_hMDNSHost, - MDNSHostProbeResultCallbackFn p_fnCallback) -{ - bool bResult = false; - if ((bResult = _validateMDNSHostHandle(p_hMDNSHost))) - { - if (p_fnCallback) - { - _NRH2Ptr(p_hMDNSHost)->m_HostProbeInformation.m_fnProbeResultCallback = [this, p_fnCallback](clsHost & p_rHost, - const char* p_pcDomainName, - bool p_bProbeResult)->void - { - p_fnCallback(*this, (hMDNSHost)&p_rHost, p_pcDomainName, p_bProbeResult); - }; - } - else - { - _NRH2Ptr(p_hMDNSHost)->m_HostProbeInformation.m_fnProbeResultCallback = 0; - } - } - return bResult; -} - -/* - MDNSResponder::status -*/ -bool MDNSResponder::status(const MDNSResponder::hMDNSHost p_hMDNSHost) const -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_NRH2Ptr(p_hMDNSHost)->probeStatus())); -} - - -/* - SERVICES -*/ - -/* - MDNSResponder::setInstanceName -*/ -bool MDNSResponder::setInstanceName(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcInstanceName) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_NRH2Ptr(p_hMDNSHost)->setInstanceName(p_pcInstanceName))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setInstanceName: FAILED for '%s'!\n"), _DH(p_hMDNSHost), (p_pcInstanceName ? : "-"));); - return bResult; -} - -/* - MDNSResponder::instanceName -*/ -const char* MDNSResponder::instanceName(const MDNSResponder::hMDNSHost p_hMDNSHost) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost) - ? (_NRH2Ptr(p_hMDNSHost)->instanceName()) - : 0); -} - -/* - MDNSResponder::addService - - Add service; using hostname if no name is explicitly provided for the service - The usual '_' underline, which is prepended to service and protocol, eg. _http, - may be given. If not, it is added automatically. - -*/ -MDNSResponder::hMDNSService MDNSResponder::addService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port, - MDNSServiceProbeResultCallbackFn p_fnCallback /*= 0*/) -{ - hMDNSService hService = (_validateMDNSHostHandle(p_hMDNSHost) - ? (hMDNSService)_NRH2Ptr(p_hMDNSHost)->addService(p_pcName, p_pcServiceType, p_pcProtocol, p_u16Port) - : 0); - if ((p_fnCallback) && - (hService)) - { - setServiceProbeResultCallback(p_hMDNSHost, hService, p_fnCallback); - } - DEBUG_EX_ERR(if (!hService) DEBUG_OUTPUT.printf_P(PSTR("%s addService: FAILED for '%s._%s._%s.local'!\n"), _DH(p_hMDNSHost), (p_pcName ? : "-"), (p_pcServiceType ? : "-"), (p_pcProtocol ? : "-"));); - return hService; -} - -/* - MDNSResponder::removeService - - Unanounce a service (by sending a goodbye message) and remove it - from the MDNS responder - -*/ -bool MDNSResponder::removeService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (_NRH2Ptr(p_hMDNSHost)->removeService(_SH2Ptr(p_hMDNSService)))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeService: FAILED!\n"), _DH(p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::removeService -*/ -bool MDNSResponder::removeService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcInstanceName, - const char* p_pcServiceType, - const char* p_pcProtocol) -{ - clsHost* pMDNSHost; - clsHost::stcService* pMDNSService; - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - (pMDNSHost = (clsHost*)p_hMDNSHost) && - ((pMDNSService = _NRH2Ptr(p_hMDNSHost)->findService(p_pcInstanceName, p_pcServiceType, p_pcProtocol))) && - (_NRH2Ptr(p_hMDNSHost)->removeService(pMDNSService))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeService: FAILED for '%s._%s._%s.local'!\n"), _DH(p_hMDNSHost), (p_pcInstanceName ? : "-"), (p_pcServiceType ? : "-"), (p_pcProtocol ? : "-"));); - return bResult; -} - -/* - MDNSResponder::findService - - Find an existing service. - -*/ -MDNSResponder::hMDNSService MDNSResponder::findService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcInstanceName, - const char* p_pcServiceType, - const char* p_pcProtocol) -{ - clsHost* pMDNSHost; - return (((_validateMDNSHostHandle(p_hMDNSHost)) && - (pMDNSHost = (clsHost*)p_hMDNSHost)) - ? _NRH2Ptr(p_hMDNSHost)->findService(p_pcInstanceName, p_pcServiceType, p_pcProtocol) - : 0); -} - -/* - MDNSResponder::setServiceName -*/ -bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcInstanceName, - MDNSServiceProbeResultCallbackFn p_fnCallback /*= 0*/) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (_NRH2Ptr(p_hMDNSHost)->setServiceName(_SH2Ptr(p_hMDNSService), p_pcInstanceName)) && - (p_fnCallback ? setServiceProbeResultCallback(p_hMDNSHost, p_hMDNSService, p_fnCallback) : true)); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setServiceName: FAILED for '%s'!\n"), _DH(p_hMDNSHost), (p_pcInstanceName ? : "-"));); - return bResult; -} - -/* - MDNSResponder::serviceName -*/ -const char* MDNSResponder::serviceName(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? (_SH2Ptr(p_hMDNSService)->m_pcName) - : 0); -} - -/* - MDNSResponder::serviceType -*/ -const char* MDNSResponder::serviceType(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? (_SH2Ptr(p_hMDNSService)->m_pcServiceType) - : 0); -} - -/* - MDNSResponder::serviceProtocol -*/ -const char* MDNSResponder::serviceProtocol(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? (_SH2Ptr(p_hMDNSService)->m_pcProtocol) - : 0); -} - -/* - MDNSResponder::serviceProtocol -*/ -uint16_t MDNSResponder::servicePort(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? (_SH2Ptr(p_hMDNSService)->m_u16Port) - : 0); -} - -/* - MDNSResponder::setServiceProbeResultCallback - - Set a service specific callback for probe results. The callback is called, when probing - for the service domain failes or succeedes. - In the case of failure, the service name should be changed via 'setServiceName'. - When succeeded, the service domain will be announced by the MDNS responder. - -*/ -bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - MDNSResponder::MDNSServiceProbeResultCallbackFn p_fnCallback) -{ - bool bResult = false; - if ((bResult = _validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService))) - { - if (p_fnCallback) - { - _SH2Ptr(p_hMDNSService)->m_ProbeInformation.m_fnProbeResultCallback = [this, p_fnCallback](clsHost & p_rHost, - clsHost::stcService & p_rMDNSService, - const char* p_pcDomainName, - bool p_bProbeResult)->void - { - p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSService)&p_rMDNSService, p_pcDomainName, p_bProbeResult); - }; - } - else - { - _SH2Ptr(p_hMDNSService)->m_ProbeInformation.m_fnProbeResultCallback = 0; - } - } - return bResult; -} - -/* - MDNSResponder::serviceStatus -*/ -bool MDNSResponder::serviceStatus(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (_SH2Ptr(p_hMDNSService)->probeStatus())); -} - - -/* - SERVICE TXT -*/ - -/* - MDNSResponder::addServiceTxt - - Add a static service TXT item ('Key'='Value') to a service. - -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue) -{ - hMDNSTxt hTxt = (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? (hMDNSTxt)_NRH2Ptr(p_hMDNSHost)->addServiceTxt(_SH2Ptr(p_hMDNSService), p_pcKey, p_pcValue) - : 0); - DEBUG_EX_ERR(if (!hTxt) DEBUG_OUTPUT.printf_P(PSTR("%s addServiceTxt: FAILED for '%s=%s'!\n"), _DH(p_hMDNSHost), (p_pcKey ? : "-"), (p_pcValue ? : "-"));); - return hTxt; -} - -/* - MDNSRESPONDER_xxx_TO_CHAR - Formats: http://www.cplusplus.com/reference/cstdio/printf/ -*/ -#define MDNSRESPONDER_U32_TO_CHAR(BUFFERNAME, U32VALUE) \ - char BUFFERNAME[16]; /* 32-bit max 10 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%u", U32VALUE); -#define MDNSRESPONDER_U16_TO_CHAR(BUFFERNAME, U16VALUE) \ - char BUFFERNAME[8]; /* 16-bit max 5 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%hu", U16VALUE); -#define MDNSRESPONDER_U8_TO_CHAR(BUFFERNAME, U8VALUE) \ - char BUFFERNAME[8]; /* 8-bit max 3 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%hhu", U8VALUE); -#define MDNSRESPONDER_I32_TO_CHAR(BUFFERNAME, I32VALUE) \ - char BUFFERNAME[16]; /* 32-bit max 10 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%i", I32VALUE); -#define MDNSRESPONDER_I16_TO_CHAR(BUFFERNAME, I16VALUE) \ - char BUFFERNAME[8]; /* 16-bit max 5 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%hi", I16VALUE); -#define MDNSRESPONDER_I8_TO_CHAR(BUFFERNAME, I8VALUE) \ - char BUFFERNAME[8]; /* 8-bit max 3 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%hhi", I8VALUE); - -/* - MDNSResponder::addServiceTxt (uint32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - MDNSRESPONDER_U32_TO_CHAR(acBuffer, p_u32Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (uint16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - MDNSRESPONDER_U16_TO_CHAR(acBuffer, p_u16Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (uint8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - MDNSRESPONDER_U8_TO_CHAR(acBuffer, p_u8Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (int32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value) -{ - MDNSRESPONDER_I32_TO_CHAR(acBuffer, p_i32Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (int16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value) -{ - MDNSRESPONDER_I16_TO_CHAR(acBuffer, p_i16Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (int8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value) -{ - MDNSRESPONDER_I8_TO_CHAR(acBuffer, p_i8Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::removeServiceTxt - - Remove a static service TXT item from a service. -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const MDNSResponder::hMDNSTxt p_hTxt) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (p_hTxt) && - (_NRH2Ptr(p_hMDNSHost)->removeServiceTxt(_SH2Ptr(p_hMDNSService), (clsHost::stcServiceTxt*)p_hTxt))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH(p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::removeServiceTxt -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (p_pcKey) && - (_NRH2Ptr(p_hMDNSHost)->removeServiceTxt(_SH2Ptr(p_hMDNSService), _NRH2Ptr(p_hMDNSHost)->findServiceTxt(_SH2Ptr(p_hMDNSService), p_pcKey)))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH(p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (binding) - - Set a netif binding specific callback for dynamic service TXT items. The callback is called, whenever - service TXT items are needed for any service on the netif binding. - -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, - MDNSResponder::MDNSDynamicServiceTxtCallbackFn p_fnCallback) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - ((!p_fnCallback) || - (_NRH2Ptr(p_hMDNSHost)->setDynamicServiceTxtCallback([this, p_fnCallback](clsHost & p_rHost, - clsHost::stcService & p_rMDNSService)->void - { - if (p_fnCallback) - { - p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSService)&p_rMDNSService); - } - })))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setDynamicServiceTxtCallback: FAILED!\n"), _DH(p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (service) - - Set a service specific callback for dynamic service TXT items. The callback is called, whenever - service TXT items are needed for the given service. -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - MDNSResponder::MDNSDynamicServiceTxtCallbackFn p_fnCallback) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - ((!p_fnCallback) || - (_NRH2Ptr(p_hMDNSHost)->setDynamicServiceTxtCallback(_SH2Ptr(p_hMDNSService), [this, p_fnCallback](clsHost & p_rHost, - clsHost::stcService & p_rMDNSService)->void - { - if (p_fnCallback) - { - p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSService)&p_rMDNSService); - } - })))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setDynamicServiceTxtCallback: FAILED!\n"), _DH(p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::addDynamicServiceTxt -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue) -{ - hMDNSTxt hTxt = (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? (hMDNSTxt)_NRH2Ptr(p_hMDNSHost)->addDynamicServiceTxt(_SH2Ptr(p_hMDNSService), p_pcKey, p_pcValue) - : 0); - DEBUG_EX_ERR(if (!hTxt) DEBUG_OUTPUT.printf_P(PSTR("%s addServiceTxt: FAILED for '%s=%s'!\n"), _DH(p_hMDNSHost), (p_pcKey ? : "-"), (p_pcValue ? : "-"));); - return hTxt; -} - -/* - MDNSResponder::addDynamicServiceTxt (uint32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - MDNSRESPONDER_U32_TO_CHAR(acBuffer, p_u32Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (uint16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - MDNSRESPONDER_U16_TO_CHAR(acBuffer, p_u16Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (uint8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - MDNSRESPONDER_U8_TO_CHAR(acBuffer, p_u8Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (int32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value) -{ - MDNSRESPONDER_I32_TO_CHAR(acBuffer, p_i32Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (int16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value) -{ - MDNSRESPONDER_I16_TO_CHAR(acBuffer, p_i16Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (int8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value) -{ - MDNSRESPONDER_I8_TO_CHAR(acBuffer, p_i8Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer); -} - - -/** - QUERIES -*/ - - -/** - MDNSResponder::clsMDNSAnswerAccessor - -*/ - -/* - MDNSResponder::clsMDNSAnswerAccessor::clsMDNSAnswerAccessor constructor -*/ -MDNSResponder::clsMDNSAnswerAccessor::clsMDNSAnswerAccessor(const MDNSResponder::clsHost::stcQuery::stcAnswer* p_pAnswer) - : m_pAnswer(p_pAnswer) -{ - if ((m_pAnswer) && - (txtsAvailable())) - { - // Prepare m_TxtKeyValueMap - for (const clsHost::stcServiceTxt* pTxt = m_pAnswer->m_Txts.m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - m_TxtKeyValueMap.emplace(std::pair(pTxt->m_pcKey, pTxt->m_pcValue)); - } - } -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::~clsMDNSAnswerAccessor destructor -*/ -MDNSResponder::clsMDNSAnswerAccessor::~clsMDNSAnswerAccessor(void) -{ -} - -/** - MDNSResponder::clsMDNSAnswerAccessor::stcCompareTxtKey -*/ - -/* - MDNSResponder::clsMDNSAnswerAccessor::stcCompareTxtKey::operator() -*/ -bool MDNSResponder::clsMDNSAnswerAccessor::stcCompareTxtKey::operator()(char const* p_pA, - char const* p_pB) const -{ - return (0 > strcasecmp(p_pA, p_pB)); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::serviceDomainAvailable -*/ -bool MDNSResponder::clsMDNSAnswerAccessor::serviceDomainAvailable(void) const -{ - return ((m_pAnswer) && - (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::ServiceDomain))); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::serviceDomain -*/ -const char* MDNSResponder::clsMDNSAnswerAccessor::serviceDomain(void) const -{ - return ((m_pAnswer) - ? m_pAnswer->m_ServiceDomain.c_str() - : 0); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::hostDomainAvailable -*/ -bool MDNSResponder::clsMDNSAnswerAccessor::hostDomainAvailable(void) const -{ - return ((m_pAnswer) && - (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::HostDomain))); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::hostDomain -*/ -const char* MDNSResponder::clsMDNSAnswerAccessor::hostDomain(void) const -{ - return ((m_pAnswer) - ? m_pAnswer->m_HostDomain.c_str() - : 0); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::hostPortAvailable -*/ -bool MDNSResponder::clsMDNSAnswerAccessor::hostPortAvailable(void) const -{ - return ((m_pAnswer) && - (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Port))); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::hostPort -*/ -uint16_t MDNSResponder::clsMDNSAnswerAccessor::hostPort(void) const -{ - return ((m_pAnswer) - ? (m_pAnswer->m_u16Port) - : 0); -} - -#ifdef MDNS_IPV4_SUPPORT -/* - MDNSResponder::clsMDNSAnswerAccessor::IPv4AddressAvailable -*/ -bool MDNSResponder::clsMDNSAnswerAccessor::IPv4AddressAvailable(void) const -{ - return ((m_pAnswer) && - (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv4Address))); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::IPv4Addresses -*/ -std::vector MDNSResponder::clsMDNSAnswerAccessor::IPv4Addresses(void) const -{ - std::vector internalIP; - if ((m_pAnswer) && - (IPv4AddressAvailable())) - { - for (uint32_t u = 0; u < m_pAnswer->IPv4AddressCount(); ++u) - { - const clsHost::stcQuery::stcAnswer::stcIPAddress* pIPAddr = m_pAnswer->IPv4AddressAtIndex(u); - if (pIPAddr) - { - internalIP.emplace_back(pIPAddr->m_IPAddress); - } - } - } - return internalIP; -} -#endif - -#ifdef MDNS_IPV6_SUPPORT -/* - MDNSResponder::clsMDNSAnswerAccessor::IPv6AddressAvailable -*/ -bool MDNSResponder::clsMDNSAnswerAccessor::IPv6AddressAvailable(void) const -{ - return ((m_pAnswer) && - (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv6Address))); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::IPv6Addresses -*/ -std::vector MDNSResponder::clsMDNSAnswerAccessor::IPv6Addresses(void) const -{ - std::vector internalIP; - if ((m_pAnswer) && - (IPv6AddressAvailable())) - { - for (uint32_t u = 0; u < m_pAnswer->IPv6AddressCount(); ++u) - { - const clsHost::stcQuery::stcAnswer::stcIPAddress* pIPAddr = m_pAnswer->IPv6AddressAtIndex(u); - if (pIPAddr) - { - internalIP.emplace_back(pIPAddr->m_IPAddress); - } - } - } - return internalIP; -} -#endif - -/* - MDNSResponder::clsMDNSAnswerAccessor::txtsAvailable -*/ -bool MDNSResponder::clsMDNSAnswerAccessor::txtsAvailable(void) const -{ - return ((m_pAnswer) && - (m_pAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Txts))); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::txts - - Returns all TXT items for the given service as a ';'-separated string. - If not already existing; the string is alloced, filled and attached to the answer. -*/ -const char* MDNSResponder::clsMDNSAnswerAccessor::txts(void) const -{ - return ((m_pAnswer) - ? m_pAnswer->m_Txts.c_str() - : 0); -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::txtKeyValues -*/ -const MDNSResponder::clsMDNSAnswerAccessor::clsTxtKeyValueMap& MDNSResponder::clsMDNSAnswerAccessor::txtKeyValues(void) const -{ - return m_TxtKeyValueMap; -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::txtValue -*/ -const char* MDNSResponder::clsMDNSAnswerAccessor::txtValue(const char* p_pcKey) const -{ - char* pcResult = 0; - - if (m_pAnswer) - { - for (const clsHost::stcServiceTxt* pTxt = m_pAnswer->m_Txts.m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if ((p_pcKey) && - (0 == strcasecmp(pTxt->m_pcKey, p_pcKey))) - { - pcResult = pTxt->m_pcValue; - break; - } - } - } - return pcResult; -} - -/* - MDNSResponder::clsMDNSAnswerAccessor::printTo - **/ -size_t MDNSResponder::clsMDNSAnswerAccessor::printTo(Print& p_Print) const -{ - size_t stLen = 0; - const char* cpcI = " * "; - const char* cpcS = " "; - - stLen += p_Print.println(" * * * * *"); - if (hostDomainAvailable()) - { - stLen += p_Print.print(cpcI); - stLen += p_Print.print("Host domain: "); - stLen += p_Print.println(hostDomain()); - } -#ifdef MDNS_IPV4_SUPPORT - if (IPv4AddressAvailable()) - { - stLen += p_Print.print(cpcI); - stLen += p_Print.println("IPv4 address(es):"); - for (const IPAddress& addr : IPv4Addresses()) - { - stLen += p_Print.print(cpcI); - stLen += p_Print.print(cpcS); - stLen += p_Print.println(addr); - } - } -#endif -#ifdef MDNS_IPV6_SUPPORT - if (IPv6AddressAvailable()) - { - stLen += p_Print.print(cpcI); - stLen += p_Print.println("IPv6 address(es):"); - for (const IPAddress& addr : IPv6Addresses()) - { - stLen += p_Print.print(cpcI); - stLen += p_Print.print(cpcS); - stLen += p_Print.println(addr); - } - } -#endif - if (serviceDomainAvailable()) - { - stLen += p_Print.print(cpcI); - stLen += p_Print.print("Service domain: "); - stLen += p_Print.println(serviceDomain()); - } - if (hostPortAvailable()) - { - stLen += p_Print.print(cpcI); - stLen += p_Print.print("Host port: "); - stLen += p_Print.println(hostPort()); - } - if (txtsAvailable()) - { - stLen += p_Print.print(cpcI); - stLen += p_Print.print("TXTs:"); - for (auto const& x : txtKeyValues()) - { - stLen += p_Print.print(cpcI); - stLen += p_Print.print(cpcS); - stLen += p_Print.print(x.first); - stLen += p_Print.print("="); - stLen += p_Print.println(x.second); - } - } - stLen += p_Print.println(" * * * * *"); - - return stLen; -} - -/** - STATIC QUERIES -*/ - -/* - MDNSResponder::queryService - - Perform a (blocking) static service query. - The arrived answers can be queried by calling: - - answerHostName (or 'hostname') - - answerIP (or 'IP') - - answerPort (or 'port') - -*/ -uint32_t MDNSResponder::queryService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local'\n"), _DH(p_hMDNSHost), p_pcService, p_pcProtocol);); - - uint32_t u32Result = ((_validateMDNSHostHandle(p_hMDNSHost)) - ? (_NRH2Ptr(p_hMDNSHost)->queryService(p_pcService, p_pcProtocol, p_u16Timeout)) - : 0); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local' returned %u hits!\n"), _DH(p_hMDNSHost), p_pcService, p_pcProtocol, u32Result);); - return u32Result; -} - -/* - MDNSResponder::queryHost - - Perform a (blocking) static host query. - The arrived answers can be queried by calling: - - answerHostName (or 'hostname') - - answerIP (or 'IP') - - answerPort (or 'port') - -*/ -uint32_t MDNSResponder::queryHost(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local'\n"), _DH(p_hMDNSHost), p_pcHostName);); - - uint32_t u32Result = ((_validateMDNSHostHandle(p_hMDNSHost)) - ? (_NRH2Ptr(p_hMDNSHost)->queryHost(p_pcHostName, p_u16Timeout)) - : 0); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local' returned %u hits!\n"), _DH(p_hMDNSHost), p_pcHostName, u32Result);); - return u32Result; -} - -/* - MDNSResponder::removeQuery - - Remove the last static query (and all answers). - -*/ -bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_NRH2Ptr(p_hMDNSHost)->removeQuery())); -} - -/* - MDNSResponder::hasQuery - - Return 'true', if a static query is currently installed - -*/ -bool MDNSResponder::hasQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (0 != _NRH2Ptr(p_hMDNSHost)->hasQuery())); -} - -/* - MDNSResponder::getQuery - - Return handle to the last static query - -*/ -MDNSResponder::hMDNSQuery MDNSResponder::getQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return (_validateMDNSHostHandle(p_hMDNSHost) - ? (hMDNSQuery)_NRH2Ptr(p_hMDNSHost)->getQuery() - : 0); -} - - -/* - MDNSResponder::answerAccessors -*/ -MDNSResponder::clsMDNSAnswerAccessorVector MDNSResponder::answerAccessors(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - hMDNSQuery hLegacyQuery = getQuery(p_hMDNSHost); - return ((hLegacyQuery) - ? answerAccessors(p_hMDNSHost, hLegacyQuery) - : clsMDNSAnswerAccessorVector()); -} - -/* - MDNSResponder::answerCount -*/ -uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - hMDNSQuery hLegacyQuery = getQuery(p_hMDNSHost); - return ((hLegacyQuery) - ? answerCount(p_hMDNSHost, hLegacyQuery) - : 0); -} - -/* - MDNSResponder::answerAccessor -*/ -MDNSResponder::clsMDNSAnswerAccessor MDNSResponder::answerAccessor(const MDNSResponder::hMDNSHost p_hMDNSHost, - uint32_t p_u32AnswerIndex) -{ - hMDNSQuery hLegacyQuery = getQuery(p_hMDNSHost); - return ((hLegacyQuery) - ? answerAccessor(p_hMDNSHost, hLegacyQuery, p_u32AnswerIndex) - : clsMDNSAnswerAccessor(0)); -} - - - -#ifdef NOTUSED - -/* - MDNSResponder::answerHostName -*/ -const char* MDNSResponder::answerHostName(const MDNSResponder::hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex) -{ - const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); - stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); - - if ((pSQAnswer) && - (pSQAnswer->m_HostDomain.m_u16NameLength) && - (!pSQAnswer->m_pcHostDomain)) - { - char* pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); - if (pcHostDomain) - { - pSQAnswer->m_HostDomain.c_str(pcHostDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); -} - -#ifdef MDNS_IPV4_SUPPORT -/* - MDNSResponder::answerIPv4 -*/ -IPAddress MDNSResponder::answerIPv4(const MDNSResponder::hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex) -{ - const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); - const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); - const stcQuery::stcAnswer::stcIPv4Address* pIPv4Address = (((pSQAnswer) && (pSQAnswer->m_pIPv4Addresses)) ? pSQAnswer->IPv4AddressAtIndex(0) : 0); - return (pIPv4Address ? pIPv4Address->m_IPAddress : IPAddress()); -} -#endif - -#ifdef MDNS_IPV6_SUPPORT -/* - MDNSResponder::answerIPv6 -*/ -IPAddress MDNSResponder::answerIPv6(const MDNSResponder::hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex) -{ - const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); - const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); - const stcQuery::stcAnswer::stcIPv6Address* pIPv6Address = (((pSQAnswer) && (pSQAnswer->m_pIPv6Addresses)) ? pSQAnswer->IPv6AddressAtIndex(0) : 0); - return (pIPv6Address ? pIPv6Address->m_IPAddress : IPAddress()); -} -#endif - -/* - MDNSResponder::answerPort -*/ -uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex) -{ - const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); - const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->m_u16Port : 0); -} - -#endif - - -/** - DYNAMIC SERVICE QUERY -*/ - -/* - MDNSResponder::installServiceQuery - - Add a dynamic service query and a corresponding callback to the MDNS responder. - The callback will be called for every answer update. - The answers can also be queried by calling: - - answerServiceDomain - - answerHostDomain - - answerIPv4Address/answerIPv6Address - - answerPort - - answerTxts - -*/ -MDNSResponder::hMDNSQuery MDNSResponder::installServiceQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcService, - const char* p_pcProtocol, - MDNSResponder::MDNSQueryCallbackFn p_fnCallback) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local'\n"), _DH(p_hMDNSHost), p_pcService, p_pcProtocol);); - - hMDNSQuery hResult = ((_validateMDNSHostHandle(p_hMDNSHost)) - ? (_NRH2Ptr(p_hMDNSHost)->installServiceQuery(p_pcService, p_pcProtocol, [this, p_fnCallback](clsHost & p_rHost, - const clsHost::stcQuery & p_Query, - const clsHost::stcQuery::stcAnswer & p_Answer, - clsHost::typeQueryAnswerType p_QueryAnswerTypeFlags, // flags for the updated answer item - bool p_bSetContent)->void - { - if (p_fnCallback) - { - p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSQuery)&p_Query, clsMDNSAnswerAccessor(&p_Answer), p_QueryAnswerTypeFlags, p_bSetContent); - } - })) - : 0); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: %s for '_%s._%s.local'!\n\n"), _DH(p_hMDNSHost), (hResult ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - DEBUG_EX_ERR(if (!hResult) DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: FAILED for '_%s._%s.local'!\n\n"), _DH(p_hMDNSHost), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - return hResult; -} - -/* - MDNSResponder::installHostQuery -*/ -MDNSResponder::hMDNSQuery MDNSResponder::installHostQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - MDNSResponder::MDNSQueryCallbackFn p_fnCallback) -{ - hMDNSQuery hResult = ((_validateMDNSHostHandle(p_hMDNSHost)) - ? (_NRH2Ptr(p_hMDNSHost)->installHostQuery(p_pcHostName, [this, p_fnCallback](clsHost & p_rHost, - const clsHost::stcQuery & p_Query, - const clsHost::stcQuery::stcAnswer & p_Answer, - clsHost::typeQueryAnswerType p_QueryAnswerTypeFlags, // flags for the updated answer item - bool p_bSetContent)->void - { - if (p_fnCallback) - { - p_fnCallback(*this, (hMDNSHost)&p_rHost, (hMDNSQuery)&p_Query, clsMDNSAnswerAccessor(&p_Answer), p_QueryAnswerTypeFlags, p_bSetContent); - } - })) - : 0); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: %s for '%s.local'!\n\n"), _DH(p_hMDNSHost), (hResult ? "Succeeded" : "FAILED"), (p_pcHostName ? : "-"));); - DEBUG_EX_ERR(if (!hResult) DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: FAILED for '%s.local'!\n\n"), _DH(p_hMDNSHost), (p_pcHostName ? : "-"));); - return hResult; -} - -/* - MDNSResponder::removeQuery - - Remove a dynamic query (and all collected answers) from the MDNS responder - -*/ -bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - (p_hMDNSQuery) && - (_NRH2Ptr(p_hMDNSHost)->removeQuery((clsHost::stcQuery*)p_hMDNSQuery))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeQuery: FAILED!\n"), _DH(p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::answerAccessors -*/ -MDNSResponder::clsMDNSAnswerAccessorVector MDNSResponder::answerAccessors(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery) -{ - clsMDNSAnswerAccessorVector tempVector; - for (uint32_t u = 0; u < answerCount(p_hMDNSHost, p_hMDNSQuery); ++u) - { - clsHost::stcQuery::stcAnswer* pAnswer = 0; - if ((_validateMDNSHostHandle(p_hMDNSHost)) && - (p_hMDNSQuery) && - ((pAnswer = ((clsHost::stcQuery*)p_hMDNSQuery)->answerAtIndex(u)))) - { - tempVector.emplace_back(clsMDNSAnswerAccessor(pAnswer)); - //tempVector.emplace_back(*pAnswer); - } - } - return tempVector; -} - -/* - MDNSResponder::answerCount -*/ -uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery) -{ - _validateMDNSHostHandle(p_hMDNSHost); - return ((clsHost::stcQuery*)p_hMDNSQuery)->answerCount(); -} - -/* - MDNSResponder::answerAccessor -*/ -MDNSResponder::clsMDNSAnswerAccessor MDNSResponder::answerAccessor(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - uint32_t p_u32AnswerIndex) -{ - clsHost::stcQuery::stcAnswer* pAnswer = (((_validateMDNSHostHandle(p_hMDNSHost)) && - (p_hMDNSQuery)) - ? ((clsHost::stcQuery*)p_hMDNSQuery)->answerAtIndex(p_u32AnswerIndex) - : 0); - return MDNSResponder::clsMDNSAnswerAccessor(pAnswer); -} - -#ifdef LATER -/* - MDNSResponder::hasAnswerServiceDomain -*/ -bool MDNSResponder::hasAnswerServiceDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::ServiceDomain))); -} - - /* - MDNSResponder::answerServiceDomain - - Returns the domain for the given service. - If not already existing, the string is allocated, filled and attached to the answer. - - */ - const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcServiceDomain (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_ServiceDomain.m_u16NameLength) && - (!pSQAnswer->m_pcServiceDomain)) -{ - - pSQAnswer->m_pcServiceDomain = pSQAnswer->allocServiceDomain(pSQAnswer->m_ServiceDomain.c_strLength()); - if (pSQAnswer->m_pcServiceDomain) - { - pSQAnswer->m_ServiceDomain.c_str(pSQAnswer->m_pcServiceDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcServiceDomain : 0); -} - -/* - MDNSResponder::hasAnswerHostDomain -*/ -bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::HostDomain))); -} - - /* - MDNSResponder::answerHostDomain - - Returns the host domain for the given service. - If not already existing, the string is allocated, filled and attached to the answer. - - */ - const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcHostDomain (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_HostDomain.m_u16NameLength) && - (!pSQAnswer->m_pcHostDomain)) -{ - - pSQAnswer->m_pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); - if (pSQAnswer->m_pcHostDomain) - { - pSQAnswer->m_HostDomain.c_str(pSQAnswer->m_pcHostDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); -} - -#ifdef MDNS_IPV4_SUPPORT -/* - MDNSResponder::hasAnswerIPv4Address -*/ -bool MDNSResponder::hasAnswerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv4Address))); -} - - /* - MDNSResponder::answerIPv4AddressCount - */ - uint32_t MDNSResponder::answerIPv4AddressCount(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->IPv4AddressCount() : 0); -} - - /* - MDNSResponder::answerIPv4Address - */ - IPAddress MDNSResponder::answerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - stcQuery::stcAnswer::stcIPv4Address* pIPv4Address = (pSQAnswer ? pSQAnswer->IPv4AddressAtIndex(p_u32AddressIndex) : 0); - return (pIPv4Address ? pIPv4Address->m_IPAddress : IPAddress()); -} -#endif - -#ifdef MDNS_IPV6_SUPPORT - /* - MDNSResponder::hasAnswerIPv6Address - */ - bool MDNSResponder::hasAnswerIPv6Address(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv6Address))); -} - - /* - MDNSResponder::answerIPv6AddressCount - */ - uint32_t MDNSResponder::answerIPv6AddressCount(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->IPv6AddressCount() : 0); -} - - /* - MDNSResponder::answerIPv6Address - */ - IPAddress MDNSResponder::answerIPv6Address(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - stcQuery::stcAnswer::stcIPv6Address* pIPv6Address = (pSQAnswer ? pSQAnswer->IPv6AddressAtIndex(p_u32AddressIndex) : 0); - return (pIPv6Address ? pIPv6Address->m_IPAddress : IPAddress()); -} -#endif - - /* - MDNSResponder::hasAnswerPort - */ - bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Port))); -} - - /* - MDNSResponder::answerPort - */ - uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->m_u16Port : 0); -} - - /* - MDNSResponder::hasAnswerTxts - */ - bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Txts))); -} - - /* - MDNSResponder::answerTxts - - Returns all TXT items for the given service as a ';'-separated string. - If not already existing; the string is alloced, filled and attached to the answer. - - */ - const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcTxts (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_Txts.m_pTxts) && - (!pSQAnswer->m_pcTxts)) -{ - - pSQAnswer->m_pcTxts = pSQAnswer->allocTxts(pSQAnswer->m_Txts.c_strLength()); - if (pSQAnswer->m_pcTxts) - { - pSQAnswer->m_Txts.c_str(pSQAnswer->m_pcTxts); - } - } - return (pSQAnswer ? pSQAnswer->m_pcTxts : 0); -} - - -/* - PROBING -*/ - -/* - MDNSResponder::setHostProbeResultCallback - - Set a callback for probe results. The callback is called, when probing - for the host domain failes or succeedes. - In the case of failure, the domain name should be changed via 'setHostName' - When succeeded, the host domain will be announced by the MDNS responder. - -*/ -bool MDNSResponder::setHostProbeResultCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, - MDNSResponder::MDNSHostProbeResultCallbackFn p_fnCallback) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (((clsHost*)p_hMDNSHost)->m_HostProbeInformation.m_fnProbeResultCallback = p_fnCallback, true)); -} - - -/* - MISC -*/ - -/* - MDNSResponder::notifyNetIfChange - - Should be called, whenever the AP for the MDNS responder changes. - A bit of this is caught by the event callbacks installed in the constructor. - -*/ -bool MDNSResponder::notifyNetIfChange(netif* p_pNetIf) -{ - clsHost* pMDNSHost; - return (((pMDNSHost = _findHost(p_pNetIf))) && - (_restart(*pMDNSHost))); -} - -/* - MDNSResponder::update - - Should be called in every 'loop'. - -*/ -bool MDNSResponder::update(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_process(*(clsHost*)p_hMDNSHost, true))); -} - -/* - MDNSResponder::update (convenience) -*/ -bool MDNSResponder::update(void) -{ - bool bResult = true; - for (clsHost*& pMDNSHost : m_HostList) - { - if (!_process(*it, true)) - { - bResult = false; - } - } - return bResult; -} - -/* - MDNSResponder::announce (convenience) - - Should be called, if the 'configuration' changes. Mainly this will be changes in the TXT items... -*/ -bool MDNSResponder::announce(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_announce(*(clsHost*)p_hMDNSHost, true, true))); -} - -/* - MDNSResponder::announce (convenience) -*/ -bool MDNSResponder::announce(void) -{ - bool bResult = true; - for (clsHost*& pMDNSHost : m_HostList) - { - if (!_announce(*it, true, true)) - { - bResult = false; - } - } - return bResult; -} - -/* - MDNSResponder::enableArduino - - Enable the OTA update service. - -*/ -MDNSResponder::hMDNSService MDNSResponder::enableArduino(const MDNSResponder::hMDNSHost p_hMDNSHost, - uint16_t p_u16Port, - bool p_bAuthUpload /*= false*/) -{ - hMDNSService hService = addService(p_hMDNSHost, 0, "arduino", "tcp", p_u16Port); - if (hService) - { - if ((!addServiceTxt(p_hMDNSHost, hService, "tcp_check", "no")) || - (!addServiceTxt(p_hMDNSHost, hService, "ssh_upload", "no")) || - (!addServiceTxt(p_hMDNSHost, hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) || - (!addServiceTxt(p_hMDNSHost, hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) - { - - removeService(p_hMDNSHost, hService); - hService = 0; - } - } - return hService; -} -#endif // LATER - -#ifdef __MDNS_USE_LEGACY - -/** - INTERFACE -*/ - -/** - MDNSResponder::MDNSResponder -*/ -MDNSResponder::MDNSResponder(void) - : m_pUDPContext(0) -{ -} - -/* - MDNSResponder::~MDNSResponder -*/ -MDNSResponder::~MDNSResponder(void) -{ - close(); -} - - -/* - MDNSResponder::getHost (netif) -*/ -MDNSResponder::hMDNSHost MDNSResponder::getHost(netif* p_pNetIf) const -{ - return (hMDNSHost)(p_pNetIf ? _findHost(p_pNetIf) : 0); -} - -/* - MDNSResponder::getHost (WiFiMode) -*/ -MDNSResponder::hMDNSHost MDNSResponder::getHost(WiFiMode_t p_WiFiMode) const -{ - hMDNSHost hResult = 0; - - if (WIFI_STA == p_WiFiMode) - { - hResult = getHost(netif_get_by_index(WIFI_STA)); - } - else if (WIFI_AP == p_WiFiMode) - { - hResult = getHost(netif_get_by_index(WIFI_AP)); - } - return hResult; -} - -/* - MDNSResponder::begin (hostname, netif, probe_callback) -*/ -MDNSResponder::hMDNSHost MDNSResponder::begin(const char* p_pcHostName, - netif* p_pNetIf, - MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, netif: %u)\n"), _DH(), (p_pcHostName ? : "_"), (p_pNetIf ? netif_get_index(p_pNetIf) : 0));); - - return (hMDNSHost)_begin(p_pcHostName, p_pNetIf, p_fnCallback); -} - -/* - MDNSResponder::begin (hostname, probe_callback) -*/ -bool MDNSResponder::begin(const char* p_pcHostName, - MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s)\n"), _DH(), (p_pcHostName ? : "_"));); - - return begin(p_pcHostName, (WiFiMode_t)wifi_get_opmode(), p_fnCallback); -} - -/* - MDNSResponder::begin (hostname, WiFiMode, probe_callback) -*/ -bool MDNSResponder::begin(const char* p_pcHostName, - WiFiMode_t p_WiFiMode, - MDNSHostProbeResultCallbackFn p_fnCallback /*= 0*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s, opmode: %u)\n"), _DH(), (p_pcHostName ? : "_"), (uint32_t)p_WiFiMode);); - - bool bResult = true; - - if ((bResult) && - (p_WiFiMode & WIFI_STA)) - { - bResult = (0 != _begin(p_pcHostName, netif_get_by_index(WIFI_STA), p_fnCallback)); - } - if ((bResult) && - (p_WiFiMode & WIFI_AP)) - { - bResult = (0 != _begin(p_pcHostName, netif_get_by_index(WIFI_AP), p_fnCallback)); - } - return bResult; -} - -/* - MDNSResponder::close -*/ -bool MDNSResponder::close(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_close(*(clsHost*)p_hMDNSHost))); -} - -/* - MDNSResponder::close (convenience) -*/ -bool MDNSResponder::close(void) -{ - clsHostList::iterator it(m_HostList.begin()); - while (m_HostList.end() != it) - { - _close(**it++); - } - - _releaseUDPContext(); - - return true; -} - -/* - MDNSResponder::end (ESP32) -*/ -bool MDNSResponder::end(void) -{ - return close(); -} - -/* - MDNSResponder::setHostName -*/ -bool MDNSResponder::setHostName(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcHostName) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_setHostName(*(clsHost*)p_hMDNSHost, p_pcHostName))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setHostName: FAILED for '%s'!\n"), _DH(), (p_pcHostName ? : "-"));); - return bResult; -} - -/* - MDNSResponder::setHostname (LEGACY 2) - - Set the host name in all netif bindings - -*/ -bool MDNSResponder::setHostname(const char* p_pcHostName) -{ - bool bResult = true; - for (clsHost*& pMDNSHost : m_HostList) - { - if (!setHostName((hMDNSHost)pMDNSHost, p_pcHostName)) - { - bResult = false; - } - } - return bResult; -} - -/* - MDNSResponder::setHostname (LEGACY) -*/ -bool MDNSResponder::setHostname(String p_strHostName) -{ - return setHostname(p_strHostName.c_str()); -} - -/* - MDNSResponder::hostName -*/ -const char* MDNSResponder::hostName(const MDNSResponder::hMDNSHost p_hMDNSHost) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost) - ? (((clsHost*)p_hMDNSHost)->m_pcHostName) - : 0); -} - -/* - MDNSResponder::hostname (LEGACY 2) -*/ -const char* MDNSResponder::hostname(void) const -{ - return ((!m_HostList.empty()) - ? hostName((hMDNSHost)m_HostList.front()) - : 0); -} - -/* - MDNSResponder::status -*/ -bool MDNSResponder::status(const MDNSResponder::hMDNSHost p_hMDNSHost) const -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (enuProbingStatus::Done == ((clsHost*)p_hMDNSHost)->m_HostProbeInformation.m_ProbingStatus)); -} - -/* - MDNSResponder::status (LEGACY 2) -*/ -bool MDNSResponder::status(void) const -{ - bool bResult = true; - for (clsHost * const& pMDNSHost : m_HostList) - { - if (!((bResult = status((hMDNSHost)pMDNSHost)))) - { - break; - } - } - return bResult; -} - - -/* - SERVICES -*/ - -/* - MDNSResponder::setInstanceName -*/ -bool MDNSResponder::setInstanceName(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcInstanceName) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_setInstanceName(*(clsHost*)p_hMDNSHost, p_pcInstanceName))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setInstanceName: FAILED for '%s'!\n"), _DH(), (p_pcInstanceName ? : "-"));); - return bResult; -} - -/* - MDNSResponder::setInstanceName (LEGACY 2) - - Set the instance name in all netif bindings - -*/ -bool MDNSResponder::setInstanceName(const char* p_pcInstanceName) -{ - bool bResult = true; - for (clsHost*& pMDNSHost : m_HostList) - { - if (!setInstanceName((hMDNSHost)pMDNSHost, p_pcInstanceName)) - { - bResult = false; - } - } - return bResult; -} - -/* - MDNSResponder::setInstanceName (LEGACY 2) -*/ -bool MDNSResponder::setInstanceName(const String& p_strInstanceName) -{ - return setInstanceName(p_strInstanceName.c_str()); -} - -/* - MDNSResponder::addService - - Add service; using hostname if no name is explicitly provided for the service - The usual '_' underline, which is prepended to service and protocol, eg. _http, - may be given. If not, it is added automatically. - -*/ -MDNSResponder::hMDNSService MDNSResponder::addService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port) -{ - hMDNSService hService = (_validateMDNSHostHandle(p_hMDNSHost) - ? (hMDNSService)_addService(*(clsHost*)p_hMDNSHost, p_pcName, p_pcService, p_pcProtocol, p_u16Port) - : 0); - DEBUG_EX_ERR(if (!hService) DEBUG_OUTPUT.printf_P(PSTR("%s addService: FAILED for '%s._%s._%s.local'!\n"), _DH((clsHost*)p_hMDNSHost), (p_pcName ? : "-"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - return hService; -} - -/* - MDNSResponder::addService (LEGACY 2) - - Add a service to all netif bindings. - (Only) the first service (handle) is returned. - -*/ -MDNSResponder::hMDNSService MDNSResponder::addService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port) -{ - hMDNSService hResult = 0; - for (clsHost*& pMDNSHost : m_HostList) - { - hMDNSService hNewService = addService((hMDNSHost)pMDNSHost, p_pcName, p_pcService, p_pcProtocol, p_u16Port); - if (!hResult) - { - hResult = hNewService; - } - } - return hResult; -} - -/* - MDNSResponder::removeService - - Unanounce a service (by sending a goodbye message) and remove it - from the MDNS responder - -*/ -bool MDNSResponder::removeService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (_removeService(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeService: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::removeService (LEGACY 2) - - Find and remove the service from one netif binding -*/ -bool MDNSResponder::removeService(const MDNSResponder::hMDNSService p_hMDNSService) -{ - clsHost* pHost = 0; - return ((_validateMDNSHostHandle(p_hMDNSService, &pHost)) && - (removeService((hMDNSHost)pHost, p_hMDNSService))); -} - -/* - MDNSResponder::removeService -*/ -bool MDNSResponder::removeService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol) -{ - clsHost* pMDNSHost; - stcService* pMDNSService; - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - (pMDNSHost = (clsHost*)p_hMDNSHost) && - ((pMDNSService = _findService(*pMDNSHost, (p_pcName ? : (pMDNSHost->m_pcInstanceName ? : pMDNSHost->m_pcHostName)), p_pcService, p_pcProtocol))) && - (_removeService(*(clsHost*)p_hMDNSHost, *pMDNSService))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeService: FAILED for '%s._%s._%s.local'!\n"), _DH((clsHost*)p_hMDNSHost), (p_pcName ? : "-"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - return bResult; -} - -/* - MDNSResponder::removeService (LEGACY 2) -*/ -bool MDNSResponder::removeService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol) -{ - bool bResult = true; - - for (clsHost*& pMDNSHost : m_HostList) - { - if (!removeService((hMDNSHost)pMDNSHost, p_pcName, p_pcService, p_pcProtocol)) - { - bResult = false; - } - } - return bResult; -} - -/* - MDNSResponder::addService (LEGACY) -*/ -bool MDNSResponder::addService(String p_strService, - String p_strProtocol, - uint16_t p_u16Port) -{ - return (0 != addService(0, p_strService.c_str(), p_strProtocol.c_str(), p_u16Port)); -} - -/* - MDNSResponder::findService - - Find an existing service. - -*/ -MDNSResponder::hMDNSService MDNSResponder::findService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol) -{ - clsHost* pMDNSHost; - return (((_validateMDNSHostHandle(p_hMDNSHost)) && - (pMDNSHost = (clsHost*)p_hMDNSHost)) - ? _findService(*pMDNSHost, (p_pcName ? : (pMDNSHost->m_pcInstanceName ? : pMDNSHost->m_pcHostName)), p_pcService, p_pcProtocol) - : 0); -} - -/* - MDNSResponder::findService (LEGACY 2) - - (Only) the first service handle is returned. - -*/ -MDNSResponder::hMDNSService MDNSResponder::findService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol) -{ - hMDNSService hResult = 0; - for (clsHost*& pMDNSHost : m_HostList) - { - if ((hResult = findService((hMDNSHost)pMDNSHost, p_pcName, p_pcService, p_pcProtocol))) - { - break; - } - } - return hResult; -} - -/* - MDNSResponder::setServiceName -*/ -bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcInstanceName) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (_setServiceName(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, p_pcInstanceName))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setServiceName: FAILED for '%s'!\n"), _DH((clsHost*)p_hMDNSHost), (p_pcInstanceName ? : "-"));); - return bResult; -} - -/* - MDNSResponder::setServiceName (LEGACY 2) -*/ -bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcInstanceName) -{ - clsHost* pHost = 0; - return ((_validateMDNSServiceHandle(p_hMDNSService, &pHost)) && - (setServiceName((hMDNSHost)pHost, p_hMDNSService, p_pcInstanceName))); -} - -/* - MDNSResponder::serviceName -*/ -const char* MDNSResponder::serviceName(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? ((stcService*)p_hMDNSService)->m_pcName - : 0); -} - -/* - MDNSResponder::serviceName (LEGACY 2) -*/ -const char* MDNSResponder::serviceName(const hMDNSService p_hMDNSService) const -{ - clsHost* pHost = 0; - return (_validateMDNSServiceHandle(p_hMDNSService, &pHost) - ? serviceName((hMDNSHost)pHost, p_hMDNSService) - : 0); -} - -/* - MDNSResponder::service -*/ -const char* MDNSResponder::service(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? ((stcService*)p_hMDNSService)->m_pcService - : 0); -} - -/* - MDNSResponder::service (LEGACY 2) -*/ -const char* MDNSResponder::service(const hMDNSService p_hMDNSService) const -{ - clsHost* pHost = 0; - return (_validateMDNSServiceHandle(p_hMDNSService, &pHost) - ? service((hMDNSHost)pHost, p_hMDNSService) - : 0); -} - -/* - MDNSResponder::serviceProtocol -*/ -const char* MDNSResponder::serviceProtocol(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? ((stcService*)p_hMDNSService)->m_pcProtocol - : 0); -} - -/* - MDNSResponder::serviceProtocol (LEGACY) -*/ -const char* MDNSResponder::serviceProtocol(const hMDNSService p_hMDNSService) const -{ - clsHost* pHost = 0; - return (_validateMDNSServiceHandle(p_hMDNSService, &pHost) - ? serviceProtocol((hMDNSHost)pHost, p_hMDNSService) - : 0); -} - -/* - MDNSResponder::serviceStatus -*/ -bool MDNSResponder::serviceStatus(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (enuProbingStatus::Done == ((stcService*)p_hMDNSService)->m_ProbeInformation.m_ProbingStatus)); -} - -/* - MDNSResponder::serviceStatus (LEGACY 2) - - Returns 'true' if probing for the service 'hMDNSService' is done - -*/ -bool MDNSResponder::serviceStatus(const hMDNSService p_hMDNSService) const -{ - clsHost* pHost = 0; - return (_validateMDNSServiceHandle(p_hMDNSService, &pHost) - ? serviceStatus((hMDNSHost)pHost, p_hMDNSService) - : false); -} - - -/* - SERVICE TXT -*/ - -/* - MDNSResponder::addServiceTxt - - Add a static service TXT item ('Key'='Value') to a service. - -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue) -{ - hMDNSTxt hTxt = (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? (hMDNSTxt)_addServiceTxt((clsHost*)p_hMDNSHost, (stcService*)p_hMDNSService, p_pcKey, p_pcValue, false) - : 0); - DEBUG_EX_ERR(if (!hTxt) DEBUG_OUTPUT.printf_P(PSTR("%s addServiceTxt: FAILED for '%s=%s'!\n"), _DH(), (p_pcKey ? : "-"), (p_pcValue ? : "-"));); - return hTxt; -} - -/* - MDNSResponder::addServiceTxt (LEGACY 2) - - Add a static service TXT item ('Key'='Value') to a service. - -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_pcValue) - : 0); -} - -/* - MDNSRESPONDER_xxx_TO_CHAR - Formats: http://www.cplusplus.com/reference/cstdio/printf/ -*/ -#define MDNSRESPONDER_U32_TO_CHAR(BUFFERNAME, U32VALUE) \ - char BUFFERNAME[16]; /* 32-bit max 10 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%u", U32VALUE); -#define MDNSRESPONDER_U16_TO_CHAR(BUFFERNAME, U16VALUE) \ - char BUFFERNAME[8]; /* 16-bit max 5 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%hu", U16VALUE); -#define MDNSRESPONDER_U8_TO_CHAR(BUFFERNAME, U8VALUE) \ - char BUFFERNAME[8]; /* 8-bit max 3 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%hhu", U8VALUE); -#define MDNSRESPONDER_I32_TO_CHAR(BUFFERNAME, I32VALUE) \ - char BUFFERNAME[16]; /* 32-bit max 10 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%i", I32VALUE); -#define MDNSRESPONDER_I16_TO_CHAR(BUFFERNAME, I16VALUE) \ - char BUFFERNAME[8]; /* 16-bit max 5 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%hi", I16VALUE); -#define MDNSRESPONDER_I8_TO_CHAR(BUFFERNAME, I8VALUE) \ - char BUFFERNAME[8]; /* 8-bit max 3 digits */ \ - *BUFFERNAME = 0; \ - sprintf(BUFFERNAME, "%hhi", I8VALUE); - - -/* - MDNSResponder::addServiceTxt (uint32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - MDNSRESPONDER_U32_TO_CHAR(acBuffer, p_u32Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addServiceTxt (uint32_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u32Value) - : 0); -} - -/* - MDNSResponder::addServiceTxt (uint16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - MDNSRESPONDER_U16_TO_CHAR(acBuffer, p_u16Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addServiceTxt (uint16_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u16Value) - : 0); -} - -/* - MDNSResponder::addServiceTxt (uint8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - MDNSRESPONDER_U8_TO_CHAR(acBuffer, p_u8Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addServiceTxt (uint8_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u8Value) - : 0); -} - -/* - MDNSResponder::addServiceTxt (int32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value) -{ - MDNSRESPONDER_I32_TO_CHAR(acBuffer, p_i32Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addServiceTxt (int32_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i32Value) - : 0); -} - -/* - MDNSResponder::addServiceTxt (int16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value) -{ - MDNSRESPONDER_I16_TO_CHAR(acBuffer, p_i16Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addServiceTxt (int16_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i16Value) - : 0); -} - -/* - MDNSResponder::addServiceTxt (int8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value) -{ - MDNSRESPONDER_I8_TO_CHAR(acBuffer, p_i8Value); - return addServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addServiceTxt (int8_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i8Value) - : 0); -} - -/* - MDNSResponder::removeServiceTxt - - Remove a static service TXT item from a service. -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const MDNSResponder::hMDNSTxt p_hTxt) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (p_hTxt) && - (_findServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, p_hTxt)) && - (_releaseServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, (stcServiceTxt*)p_hTxt))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::removeServiceTxt (LEGACY 2) -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const MDNSResponder::hMDNSTxt p_hTxt) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? removeServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_hTxt) - : false); -} - -/* - MDNSResponder::removeServiceTxt -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey) -{ - stcServiceTxt* pTxt; - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (p_pcKey) && - ((pTxt = _findServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, p_pcKey))) && - (_releaseServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, pTxt))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::removeServiceTxt (LEGACY 2) -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? removeServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey) - : false); -} - -/* - MDNSResponder::removeServiceTxt (LEGACY) -*/ -bool MDNSResponder::removeServiceTxt(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey) -{ - hMDNSService hService; - return (((hService = findService(p_pcName, p_pcService, p_pcProtocol))) - ? removeServiceTxt(hService, p_pcKey) - : false); -} - -/* - MDNSResponder::addServiceTxt (LEGACY) -*/ -bool MDNSResponder::addServiceTxt(const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey, - const char* p_pcValue) -{ - hMDNSService hService; - return (((hService = findService(p_pcName, p_pcService, p_pcProtocol))) - ? addServiceTxt(hService, p_pcKey, p_pcValue) - : false); -} - -/* - MDNSResponder::addServiceTxt (LEGACY) -*/ -bool MDNSResponder::addServiceTxt(String p_strService, - String p_strProtocol, - String p_strKey, - String p_strValue) -{ - return addServiceTxt(p_strService.c_str(), p_strProtocol.c_str(), p_strKey.c_str(), p_strValue.c_str()); -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (binding) - - Set a netif binding specific callback for dynamic service TXT items. The callback is called, whenever - service TXT items are needed for any service on the netif binding. - -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, - MDNSResponder::MDNSDynamicServiceTxtCallbackFn p_fnCallback) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - ((!p_fnCallback) || - ((((clsHost*)p_hMDNSHost)->m_fnServiceTxtCallback = p_fnCallback)))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setDynamicServiceTxtCallback: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (service) - - Set a service specific callback for dynamic service TXT items. The callback is called, whenever - service TXT items are needed for the given service. -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - MDNSResponder::MDNSDynamicServiceTxtCallbackFn p_fnCallback) -{ - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - ((!p_fnCallback) || - ((((stcService*)p_hMDNSService)->m_fnServiceTxtCallback = p_fnCallback)))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s setDynamicServiceTxtCallback: FAILED!\n"), _DH((clsHost*)p_hMDNSHost));); - return bResult; -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (global) (LEGACY 2) - - Set a global callback for dynamic service TXT items. The callback is called, whenever - service TXT items are needed. - -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::MDNSDynamicServiceTxtCallbackFn1 p_fnCallback) -{ - for (clsHostList : .iterator it : m_HostList) - { - setDynamicServiceTxtCallback((hMDNSHost)it, p_fnCallback); - } - return true; -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (global) (LEGACY 2 (Fn2)) -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::MDNSDynamicServiceTxtCallbackFn2 p_fnCallback) -{ - return setDynamicServiceTxtCallback([p_fnCallback](MDNSResponder*, const hMDNSService p_hMDNSService) - { - if (p_fnCallback) - { - p_fnCallback(p_hMDNSService); - } - }); -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (service) (LEGACY 2) -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::hMDNSService p_hMDNSService, - MDNSResponder::MDNSDynamicServiceTxtCallbackFn1 p_fnCallback) -{ - clsHost* pHost; - return ((_validateMDNSHostHandle(p_hMDNSService, &pHost)) && - (setDynamicServiceTxtCallback((hMDNSHost)pHost, hMDNSService, p_fnCallback))); -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (service) (LEGACY 2 (Fn2)) -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::hMDNSService p_hMDNSService, - MDNSResponder::MDNSDynamicServiceTxtCallbackFn2 p_fnCallback) -{ - return setDynamicServiceTxtCallback(p_hMDNSService, [p_fnCallback](MDNSResponder*, const hMDNSService p_hMDNSService) - { - if (p_fnCallback) - { - p_fnCallback(p_hMDNSService); - } - }); -} - -/* - MDNSResponder::addDynamicServiceTxt -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue) -{ - hMDNSTxt hTxt = (_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService) - ? _addServiceTxt(*(clsHost*)p_hMDNSHost, *(stcService*)p_hMDNSService, p_pcKey, p_pcValue, true) - : 0); - DEBUG_EX_ERR(if (!hTxt) DEBUG_OUTPUT.printf_P(PSTR("%s addDynamicServiceTxt: FAILED for '%s=%s'!\n"), _DH(), (p_pcKey ? : "-"), (p_pcValue ? : "-"));); - return hTxt; -} - -/* - MDNSResponder::addDynamicServiceTxt (LEGACY 2) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - const char* p_pcValue) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_pcValue) - : 0); -} - -/* - MDNSResponder::addDynamicServiceTxt (uint32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - MDNSRESPONDER_U32_TO_CHAR(acBuffer, p_u32Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addDynamicServiceTxt (uint32_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u32Value) - : 0); -} - -/* - MDNSResponder::addDynamicServiceTxt (uint16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - MDNSRESPONDER_U16_TO_CHAR(acBuffer, p_u16Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addDynamicServiceTxt (uint16_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u16Value) - : 0); -} - -/* - MDNSResponder::addDynamicServiceTxt (uint8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - MDNSRESPONDER_U8_TO_CHAR(acBuffer, p_u8Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addDynamicServiceTxt (uint8_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_u8Value) - : 0); -} - -/* - MDNSResponder::addDynamicServiceTxt (int32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int32_t p_i32Value) -{ - MDNSRESPONDER_I32_TO_CHAR(acBuffer, p_i32Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addDynamicServiceTxt (int32_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint32_t p_i32Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i32Value) - : 0); -} - -/* - MDNSResponder::addDynamicServiceTxt (int16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int16_t p_i16Value) -{ - MDNSRESPONDER_I16_TO_CHAR(acBuffer, p_i16Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addDynamicServiceTxt (int16_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint16_t p_i16Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i16Value) - : 0); -} - -/* - MDNSResponder::addDynamicServiceTxt (int8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - int8_t p_i8Value) -{ - MDNSRESPONDER_I8_TO_CHAR(acBuffer, p_i8Value); - return addDynamicServiceTxt(p_hMDNSHost, p_hMDNSService, p_pcKey, acBuffer): - } - - /* - MDNSResponder::addDynamicServiceTxt (int8_t) (LEGACY 2) - */ - MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(const MDNSResponder::hMDNSService p_hMDNSService, - const char* p_pcKey, - uint8_t p_i8Value) -{ - clsHost* pHost = 0; - return (_validateMDNSHostHandle(p_hMDNSService, &pHost) - ? addDynamicServiceTxt((hMDNSHost)pHost, p_hMDNSService, p_pcKey, p_i8Value) - : 0); -} - - -/** - STATIC QUERIES -*/ - -/* - MDNSResponder::queryService - - Perform a (blocking) static service query. - The arrived answers can be queried by calling: - - answerHostName (or 'hostname') - - answerIP (or 'IP') - - answerPort (or 'port') - -*/ -uint32_t MDNSResponder::queryService(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '%s.%s'\n"), _DH(), p_pcService, p_pcProtocol);); - - uint32_t u32Result = 0; - - stcQuery* pMDNSQuery = 0; - if ((_validateMDNSHostHandle(p_hMDNSHost)) && - (p_pcService) && - (os_strlen(p_pcService)) && - (p_pcProtocol) && - (os_strlen(p_pcProtocol)) && - (p_u16Timeout) && - (_removeLegacyQuery()) && - ((pMDNSQuery = _allocQuery(*(clsHost*)p_hMDNSHost, stcQuery::enuQueryType::Service))) && - (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) - { - pMDNSQuery->m_bLegacyQuery = true; - - if (_sendMDNSQuery(*(clsHost*)p_hMDNSHost, *pMDNSQuery)) - { - // Wait for answers to arrive - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); - delay(p_u16Timeout); - - // All answers should have arrived by now -> stop adding new answers - pMDNSQuery->m_bAwaitingAnswers = false; - u32Result = pMDNSQuery->answerCount(); - } - else // FAILED to send query - { - _removeQuery(*(clsHost*)p_hMDNSHost, pMDNSQuery); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: INVALID input data!\n"), _DH());); - } - return u32Result; -} - -/* - MDNSResponder::queryService (LEGACY 2) -*/ -uint32_t MDNSResponder::queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - return ((!m_HostList.empty()) - ? queryService((hMDNSHost)m_HostList.front(), p_pcService, p_pcProtocol, p_u16Timeout) - : 0); -} - -/* - MDNSResponder::queryService (LEGACY) -*/ -uint32_t MDNSResponder::queryService(const String& p_strService, - const String& p_strProtocol) -{ - return queryService(p_strService.c_str(), p_strProtocol.c_str()); -} - -/* - MDNSResponder::queryHost - - Perform a (blocking) static host query. - The arrived answers can be queried by calling: - - answerHostName (or 'hostname') - - answerIP (or 'IP') - - answerPort (or 'port') - -*/ -uint32_t MDNSResponder::queryHost(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local'\n"), _DH(), p_pcHostName);); - - uint32_t u32Result = 0; - - stcQuery* pHostQuery = 0; - if ((_validateMDNSHostHandle(p_hMDNSHost)) && - (p_pcHostName) && - (os_strlen(p_pcHostName)) && - (p_u16Timeout) && - (_removeLegacyQuery()) && - ((pHostQuery = _allocQuery(*(clsHost*)p_hMDNSHost, stcQuery::enuQueryType::Host))) && - (_buildDomainForHost(p_pcHostName, pHostQuery->m_Domain))) - { - - pHostQuery->m_bLegacyQuery = true; - - if (_sendMDNSQuery(*(clsHost*)p_hMDNSHost, *pHostQuery)) - { - // Wait for answers to arrive - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); - delay(p_u16Timeout); - - // All answers should have arrived by now -> stop adding new answers - pHostQuery->m_bAwaitingAnswers = false; - u32Result = pHostQuery->answerCount(); - } - else // FAILED to send query - { - _removeQuery(*(clsHost*)p_hMDNSHost, pHostQuery); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: INVALID input data!\n"), _DH());); - } - return u32Result; -} - -/* - queryHost (LEGACY 2) -*/ -uint32_t MDNSResponder::queryHost(const char* p_pcHostName, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - return ((!m_HostList.empty()) - ? queryHost((hMDNSHost)m_HostList.front(), p_pcService, p_pcProtocol, p_u16Timeout) - : 0); -} - -/* - MDNSResponder::removeQuery - - Remove the last static query (and all answers). - -*/ -bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_removeLegacyQuery(*(clsHost*)p_hMDNSHost))); -} - -/* - MDNSResponder::removeQuery (LEGACY 2) -*/ -bool MDNSResponder::removeQuery(void) -{ - return ((!m_HostList.empty()) - ? removeQuery((hMDNSHost)m_HostList.front()) - : false); -} - -/* - MDNSResponder::hasQuery - - Return 'true', if a static query is currently installed - -*/ -bool MDNSResponder::hasQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (0 != _findLegacyQuery(*(clsHost*)p_hMDNSHost))); -} - -/* - MDNSResponder::hasQuery (LEGACY 2) -*/ -bool MDNSResponder::hasQuery(void) -{ - return ((!m_HostList.empty()) - ? hasQuery((hMDNSHost)m_HostList.front()) - : false); -} - -/* - MDNSResponder::getQuery - - Return handle to the last static query - -*/ -MDNSResponder::hMDNSQuery MDNSResponder::getQuery(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return (_validateMDNSHostHandle(p_hMDNSHost) - ? (hMDNSQuery)_findLegacyQuery() - : 0); -} - -/* - MDNSResponder::getQuery (LEGACY 2) -*/ -MDNSResponder::hMDNSQuery MDNSResponder::getQuery(void) -{ - return ((!m_HostList.empty()) - ? getQuery((hMDNSHost)m_HostList.front()) - : false); -} - -/* - MDNSResponder::answerHostName -*/ -const char* MDNSResponder::answerHostName(const MDNSResponder::hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex) -{ - const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); - stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); - - if ((pSQAnswer) && - (pSQAnswer->m_HostDomain.m_u16NameLength) && - (!pSQAnswer->m_pcHostDomain)) - { - char* pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); - if (pcHostDomain) - { - pSQAnswer->m_HostDomain.c_str(pcHostDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); -} - -/* - MDNSResponder::answerHostName (LEGACY 2) -*/ -const char* MDNSResponder::answerHostName(const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerHostName((hMDNSHost)m_HostList.front(), p_u32AnswerIndex) - : 0); -} - -/* - MDNSResponder::hostname (LEGACY) -*/ -String MDNSResponder::hostname(const uint32_t p_u32AnswerIndex) -{ - return String(answerHostName(p_u32AnswerIndex)); -} - -#ifdef MDNS_IPV4_SUPPORT -/* - MDNSResponder::answerIPv4 -*/ -IPAddress MDNSResponder::answerIPv4(const MDNSResponder::hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex) -{ - const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); - const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); - const stcQuery::stcAnswer::stcIPv4Address* pIPv4Address = (((pSQAnswer) && (pSQAnswer->m_pIPv4Addresses)) ? pSQAnswer->IPv4AddressAtIndex(0) : 0); - return (pIPv4Address ? pIPv4Address->m_IPAddress : IPAddress()); -} - -/* - MDNSResponder::answerIPv4 (LEGACY 2) -*/ -IPAddress MDNSResponder::answerIPv4(const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerIPv4((hMDNSHost)m_HostList.front(), p_u32AnswerIndex) - : IPAddress()); -} - -/* - MDNSResponder::answerIP (LEGACY 2) -*/ -IPAddress MDNSResponder::answerIP(const uint32_t p_u32AnswerIndex) -{ - return answerIPv4(p_u32AnswerIndex); -} - -/* - MDNSResponder::IP (LEGACY) -*/ -IPAddress MDNSResponder::IP(const uint32_t p_u32AnswerIndex) -{ - return answerIPv4(p_u32AnswerIndex); -} -#endif - -#ifdef MDNS_IPV6_SUPPORT -/* - MDNSResponder::answerIPv6 -*/ -IPAddress MDNSResponder::answerIPv6(const MDNSResponder::hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex) -{ - const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); - const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); - const stcQuery::stcAnswer::stcIPv6Address* pIPv6Address = (((pSQAnswer) && (pSQAnswer->m_pIPv6Addresses)) ? pSQAnswer->IPv6AddressAtIndex(0) : 0); - return (pIPv6Address ? pIPv6Address->m_IPAddress : IPAddress()); -} - -/* - MDNSResponder::answerIPv6 (LEGACY 2) -*/ -IPAddress MDNSResponder::answerIPv6(const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerIPv6((hMDNSHost)m_HostList.front(), p_u32AnswerIndex) - : IPAddress()); -} -#endif - -/* - MDNSResponder::answerPort -*/ -uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, - const uint32_t p_u32AnswerIndex) -{ - const stcQuery* pQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findLegacyQuery(*(clsHost*)p_hMDNSHost) : 0); - const stcQuery::stcAnswer* pSQAnswer = (pQuery ? pQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->m_u16Port : 0); -} - -/* - MDNSResponder::answerPort (LEGACY 2) -*/ -uint16_t MDNSResponder::answerPort(const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerPort((hMDNSHost)m_HostList.front(), p_u32AnswerIndex) - : 0); -} - -/* - MDNSResponder::port (LEGACY) -*/ -uint16_t MDNSResponder::port(const uint32_t p_u32AnswerIndex) -{ - return answerPort(p_u32AnswerIndex); -} - - -/** - DYNAMIC SERVICE QUERY -*/ - -/* - MDNSResponder::installServiceQuery - - Add a dynamic service query and a corresponding callback to the MDNS responder. - The callback will be called for every answer update. - The answers can also be queried by calling: - - answerServiceDomain - - answerHostDomain - - answerIPv4Address/answerIPv6Address - - answerPort - - answerTxts - -*/ -MDNSResponder::hMDNSQuery MDNSResponder::installServiceQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcService, - const char* p_pcProtocol, - MDNSResponder::MDNSQueryCallbackFn p_fnCallback) -{ - hMDNSQuery hResult = 0; - - stcQuery* pMDNSQuery = 0; - if ((_validateMDNSHostHandle(p_hMDNSHost)) && - (p_pcService) && - (os_strlen(p_pcService)) && - (p_pcProtocol) && - (os_strlen(p_pcProtocol)) && - (p_fnCallback) && - ((pMDNSQuery = _allocQuery(*(clsHost*)p_hMDNSHost, stcQuery::enuQueryType::Service))) && - (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) - { - - pMDNSQuery->m_fnCallback = p_fnCallback; - pMDNSQuery->m_bLegacyQuery = false; - - if (_sendMDNSQuery(*(clsHost*)p_hMDNSHost, *pMDNSQuery)) - { - pMDNSQuery->m_u8SentCount = 1; - pMDNSQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); - - hResult = (hMDNSQuery)pMDNSQuery; - } - else - { - _removeQuery(*(clsHost*)p_hMDNSHost, pMDNSQuery); - } - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: %s for '%s.%s'!\n\n"), _DH(), (hResult ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - DEBUG_EX_ERR(if (!hResult) DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: FAILED for '%s.%s'!\n\n"), _DH(), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - return hResult; -} - -/* - MDNSResponder::installServiceQuery (LEGACY 2) -*/ -MDNSResponder::hMDNSQuery MDNSResponder::installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSResponder::MDNSQueryCallbackFn1 p_fnCallback) -{ - return ((!m_HostList.empty()) - ? installServiceQuery((hMDNSHost)m_HostList.front(), p_pcService, p_pcProtocol, [p_fnCallback])(MDNSResponder * p_pMDNSResponder, - MDNSResponder::hMDNSHost, - const stcAnswerAccessor & p_MDNSAnswerAccessor, - typeQueryAnswerType p_QueryAnswerTypeFlags, - bool p_bSetContent) - { - if (p_fnCallback) - { - p_fnCallback(p_pMDNSResponder, p_MDNSAnswerAccessor, p_QueryAnswerTypeFlags, p_bSetContent); - } - }) - : 0); - } - - /* - MDNSResponder::installServiceQuery (LEGACY 2) - */ - MDNSResponder::hMDNSQuery MDNSResponder::installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSResponder::MDNSQueryCallbackFn2 p_fnCallback) -{ - return ((!m_HostList.empty()) - ? installServiceQuery((hMDNSHost)m_HostList.front(), p_pcService, p_pcProtocol, [p_fnCallback])(MDNSResponder*, - MDNSResponder::hMDNSHost, - const stcAnswerAccessor & p_MDNSAnswerAccessor, - typeQueryAnswerType p_QueryAnswerTypeFlags, - bool p_bSetContent) - { - if (p_fnCallback) - { - p_fnCallback(p_MDNSAnswerAccessor, p_QueryAnswerTypeFlags, p_bSetContent); - } - }) - : 0); - } - - /* - MDNSResponder::installHostQuery - */ - MDNSResponder::hMDNSQuery MDNSResponder::installHostQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, - const char* p_pcHostName, - MDNSResponder::MDNSQueryCallbackFn p_fnCallback) -{ - hMDNSQuery hResult = 0; - - if ((_validateMDNSHostHandle(p_hMDNSHost)) && - (p_pcHostName) && - (os_strlen(p_pcHostName))) - { - stcRRDomain domain; - hResult = ((_buildDomainForHost(p_pcHostName, domain)) - ? _installDomainQuery(*(clsHost*)p_hMDNSHost, domain, stcQuery::enuQueryType::Host, p_fnCallback) - : 0); - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: %s for '%s.local'!\n\n"), _DH(), (hResult ? "Succeeded" : "FAILED"), (p_pcHostName ? : "-"));); - DEBUG_EX_ERR(if (!hResult) DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: FAILED for '%s.local'!\n\n"), _DH(), (p_pcHostName ? : "-"));); - return hResult; -} - -/* - MDNSResponder::installHostQuery (LEGACY 2) -*/ -MDNSResponder::hMDNSQuery MDNSResponder::installHostQuery(const char* p_pcHostName, - MDNSResponder::MDNSQueryCallbackFn1 p_fnCallback) -{ - return installHostQuery(p_pcHostName, [p_fnCallback](MDNSResponder * p_pMDNSResponder, - hMDNSHost, - const stcAnswerAccessor & p_MDNSAnswerAccessor, - typeQueryAnswerType p_QueryAnswerTypeFlags, - bool p_bSetContent) - { - if (p_fnCallback) - { - p_fnCallback(p_pMDNSResponder, p_MDNSAnswerAccessor, p_QueryAnswerTypeFlags, p_bSetContent); - } - }); -} - -/* - MDNSResponder::installHostQuery (LEGACY 2) -*/ -MDNSResponder::hMDNSQuery MDNSResponder::installHostQuery(const char* p_pcHostName, - MDNSResponder::MDNSQueryCallbackFn2 p_fnCallback) -{ - return installHostQuery(p_pcHostName, [p_fnCallback](MDNSResponder*, - hMDNSHost, - const stcAnswerAccessor & p_MDNSAnswerAccessor, - typeQueryAnswerType p_QueryAnswerTypeFlags, - bool p_bSetContent) - { - if (p_fnCallback) - { - p_fnCallback(p_MDNSAnswerAccessor, p_QueryAnswerTypeFlags, p_bSetContent); - } - }); -} - -/* - MDNSResponder::removeQuery - - Remove a dynamic query (and all collected answers) from the MDNS responder - -*/ -bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery) -{ - stcQuery* pMDNSQuery = 0; - bool bResult = ((_validateMDNSHostHandle(p_hMDNSHost)) && - ((pMDNSQuery = _findQuery(*(clsHost*)p_hMDNSHost, p_hQuery))) && - (_removeQuery(*(clsHost*)p_hMDNSHost, pMDNSQuery))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeQuery: FAILED!\n"), _DH());); - return bResult; -} - -/* - MDNSResponder::removeQuery (LEGACY 2) -*/ -bool MDNSResponder::removeQuery(const MDNSResponder::hMDNSQuery p_hMDNSQuery) -{ - return ((!m_HostList.empty()) - ? removeQuery((hMDNSHost)m_HostList.front(), p_hMDNSQuery) - : false); -} - -/* - MDNSResponder::answerAccessors -*/ -MDNSResponder::clsMDNSAnswerAccessorVector MDNSResponder::answerAccessors(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery) -{ - MDNSResponder::clsMDNSAnswerAccessorVector tempVector; - for (uint32_t u = 0; u < answerCount(p_hMDNSHost, p_hMDNSQuery); ++u) - { - tempVector.emplace_back(*this, p_hMDNSQuery, u); - } - return tempVector; -} - -/* - MDNSResponder::answerAccessors (LEGACY 2) -*/ -MDNSResponder::clsMDNSAnswerAccessorVector MDNSResponder::answerAccessors(const MDNSResponder::hMDNSQuery p_hMDNSQuery) -{ - return ((!m_HostList.empty()) - ? answerAccessors((hMDNSHost)m_HostList.front(), p_hMDNSQuery) - : MDNSResponder::clsMDNSAnswerAccessorVector()); -} - -/* - MDNSResponder::answerCount -*/ -uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery) : 0); - return (pMDNSQuery ? pMDNSQuery->answerCount() : 0); -} - -/* - MDNSResponder::answerCount (LEGACY 2) -*/ -uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSQuery p_hMDNSQuery) -{ - return ((!m_HostList.empty()) - ? answerCount((hMDNSHost)m_HostList.front(), p_hMDNSQuery) - : 0); -} - -/* - MDNSResponder::hasAnswerServiceDomain -*/ -bool MDNSResponder::hasAnswerServiceDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::ServiceDomain))); -} - - /* - MDNSResponder::hasAnswerServiceDomain (LEGACY 2) - */ - bool MDNSResponder::hasAnswerServiceDomain(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? hasAnswerServiceDomain((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : false); -} - -/* - MDNSResponder::answerServiceDomain - - Returns the domain for the given service. - If not already existing, the string is allocated, filled and attached to the answer. - -*/ -const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcServiceDomain (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_ServiceDomain.m_u16NameLength) && - (!pSQAnswer->m_pcServiceDomain)) -{ - - pSQAnswer->m_pcServiceDomain = pSQAnswer->allocServiceDomain(pSQAnswer->m_ServiceDomain.c_strLength()); - if (pSQAnswer->m_pcServiceDomain) - { - pSQAnswer->m_ServiceDomain.c_str(pSQAnswer->m_pcServiceDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcServiceDomain : 0); -} - -/* - MDNSResponder::answerServiceDomain (LEGACY 2) -*/ -const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerServiceDomain((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : 0); -} - -/* - MDNSResponder::hasAnswerHostDomain -*/ -bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::HostDomain))); -} - - /* - MDNSResponder::hasAnswerHostDomain (LEGACY 2) - */ - bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? hasAnswerHostDomain((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : false); -} - -/* - MDNSResponder::answerHostDomain - - Returns the host domain for the given service. - If not already existing, the string is allocated, filled and attached to the answer. - -*/ -const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcHostDomain (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_HostDomain.m_u16NameLength) && - (!pSQAnswer->m_pcHostDomain)) -{ - - pSQAnswer->m_pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); - if (pSQAnswer->m_pcHostDomain) - { - pSQAnswer->m_HostDomain.c_str(pSQAnswer->m_pcHostDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); -} - -/* - MDNSResponder::answerHostDomain (LEGACY 2) -*/ -const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerHostDomain((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : 0); -} - -#ifdef MDNS_IPV4_SUPPORT -/* - MDNSResponder::hasAnswerIPv4Address -*/ -bool MDNSResponder::hasAnswerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv4Address))); -} - - /* - MDNSResponder::hasAnswerIPv4Address (LEGACY 2) - */ - bool MDNSResponder::hasAnswerIPv4Address(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? hasAnswerIPv4Address((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : false); -} - -/* - MDNSResponder::answerIPv4AddressCount -*/ -uint32_t MDNSResponder::answerIPv4AddressCount(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->IPv4AddressCount() : 0); -} - - /* - MDNSResponder::answerIPv4AddressCount (LEGACY 2) - */ - uint32_t MDNSResponder::answerIPv4AddressCount(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerIPv4AddressCount((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : 0); -} - -/* - MDNSResponder::answerIPv4Address -*/ -IPAddress MDNSResponder::answerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - stcQuery::stcAnswer::stcIPv4Address* pIPv4Address = (pSQAnswer ? pSQAnswer->IPv4AddressAtIndex(p_u32AddressIndex) : 0); - return (pIPv4Address ? pIPv4Address->m_IPAddress : IPAddress()); -} - - /* - MDNSResponder::answerIPv4Address (LEGACY 2) - */ - IPAddress MDNSResponder::answerIPv4Address(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - return ((!m_HostList.empty()) - ? answerIPv4Address((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex, p_u32AddressIndex) - : IPAddress()); -} -#endif - -#ifdef MDNS_IPV6_SUPPORT -/* - MDNSResponder::hasAnswerIPv6Address -*/ -bool MDNSResponder::hasAnswerIPv6Address(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::IPv6Address))); -} - - /* - MDNSResponder::hasAnswerIPv6Address (LEGACY 2) - */ - bool MDNSResponder::hasAnswerIPv6Address(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? hasAnswerIPv6Address((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : false); -} - -/* - MDNSResponder::answerIPv6AddressCount -*/ -uint32_t MDNSResponder::answerIPv6AddressCount(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->IPv6AddressCount() : 0); -} - - /* - MDNSResponder::answerIPv6AddressCount (LEGACY 2) - */ - uint32_t MDNSResponder::answerIPv6AddressCount(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerIPv6AddressCount((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : 0); -} - -/* - MDNSResponder::answerIPv6Address -*/ -IPAddress MDNSResponder::answerIPv6Address(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - stcQuery::stcAnswer::stcIPv6Address* pIPv6Address = (pSQAnswer ? pSQAnswer->IPv6AddressAtIndex(p_u32AddressIndex) : 0); - return (pIPv6Address ? pIPv6Address->m_IPAddress : IPAddress()); -} - - /* - MDNSResponder::answerIPv6Address (LEGACY 2) - */ - IPAddress MDNSResponder::answerIPv6Address(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - return ((!m_HostList.empty()) - ? answerIPv6Address((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : IPAddress()); -} -#endif - -/* - MDNSResponder::hasAnswerPort -*/ -bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Port))); -} - - /* - MDNSResponder::hasAnswerPort (LEGACY 2) - */ - bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? hasAnswerPort((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : false); -} - -/* - MDNSResponder::answerPort -*/ -uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->m_u16Port : 0); -} - - /* - MDNSResponder::answerPort (LEGACY 2) - */ - uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerPort((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : 0); -} - -/* - MDNSResponder::hasAnswerTxts -*/ -bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_QueryAnswerFlags & static_cast(enuQueryAnswerType::Txts))); -} - - /* - MDNSResponder::hasAnswerTxts (LEGACY 2) - */ - bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? hasAnswerTxts((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : false); -} - -/* - MDNSResponder::answerTxts - - Returns all TXT items for the given service as a ';'-separated string. - If not already existing; the string is alloced, filled and attached to the answer. - -*/ -const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - stcQuery* pMDNSQuery = (_validateMDNSHostHandle(p_hMDNSHost) ? _findQuery(*(clsHost*)p_hMDNSHost, p_hMDNSQuery); - stcQuery::stcAnswer* pSQAnswer = (pMDNSQuery ? pMDNSQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcTxts (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_Txts.m_pTxts) && - (!pSQAnswer->m_pcTxts)) -{ - - pSQAnswer->m_pcTxts = pSQAnswer->allocTxts(pSQAnswer->m_Txts.c_strLength()); - if (pSQAnswer->m_pcTxts) - { - pSQAnswer->m_Txts.c_str(pSQAnswer->m_pcTxts); - } - } - return (pSQAnswer ? pSQAnswer->m_pcTxts : 0); -} - -/* - MDNSResponder::answerTxts (LEGACY 2) -*/ -const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSQuery p_hMDNSQuery, - const uint32_t p_u32AnswerIndex) -{ - return ((!m_HostList.empty()) - ? answerTxts((hMDNSHost)m_HostList.front(), p_hMDNSQuery, p_u32AnswerIndex) - : 0); -} - - -/* - PROBING -*/ - -/* - MDNSResponder::setHostProbeResultCallback - - Set a callback for probe results. The callback is called, when probing - for the host domain failes or succeedes. - In the case of failure, the domain name should be changed via 'setHostName' - When succeeded, the host domain will be announced by the MDNS responder. - -*/ -bool MDNSResponder::setHostProbeResultCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, - MDNSResponder::MDNSHostProbeResultCallbackFn p_fnCallback) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (((clsHost*)p_hMDNSHost)->m_HostProbeInformation.m_fnProbeResultCallback = p_fnCallback, true)); -} - -/* - MDNSResponder::setHostProbeResultCallback (LEGACY 2) -*/ -bool MDNSResponder::setHostProbeResultCallback(MDNSResponder::MDNSHostProbeResultCallbackFn1 p_fnCallback) -{ - return setHostProbeResultCallback([p_fnCallback](MDNSResponder * p_pMDNSResponder, - hMDNSHost, - const char* p_pcDomainName, - bool p_bProbeResult) - { - if (p_fnCallback) - { - p_fnCallback(p_pMDNSResponder, p_pcDomainName, p_bProbeResult); - } - }); -} - -/* - MDNSResponder::setHostProbeResultCallback (LEGACY 2) -*/ -bool MDNSResponder::setHostProbeResultCallback(MDNSResponder::MDNSHostProbeResultCallbackFn2 p_fnCallback) -{ - return setHostProbeResultCallback([p_fnCallback](MDNSResponder*, - hMDNSHost, - const char* p_pcDomainName, - bool p_bProbeResult) - { - if (p_fnCallback) - { - p_fnCallback(p_pcDomainName, p_bProbeResult); - } - }); -} - -/* - MDNSResponder::setServiceProbeResultCallback - - Set a service specific callback for probe results. The callback is called, when probing - for the service domain failes or succeedes. - In the case of failure, the service name should be changed via 'setServiceName'. - When succeeded, the service domain will be announced by the MDNS responder. - -*/ -bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSHost p_hMDNSHost, - const MDNSResponder::hMDNSService p_hMDNSService, - MDNSResponder::MDNSServiceProbeResultCallbackFn p_fnCallback) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost, p_hMDNSService)) && - (((stcService*)p_hMDNSService)->m_ProbeInformation.m_fnProbeResultCallback = p_fnCallback, true)); -} - -/* - MDNSResponder::setServiceProbeResultCallback (LEGACY 2) -*/ -bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hMDNSService, - MDNSResponder::MDNSServiceProbeResultCallbackFn1 p_fnCallback) -{ - return setServiceProbeResultCallback(p_hMDNSService, [p_fnCallback](MDNSResponder * p_pMDNSResponder, - hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcServiceName, - bool p_bProbeResult) - { - if (p_fnCallback) - { - p_fnCallback(p_pMDNSResponder, p_hMDNSService, p_pcServiceName, p_bProbeResult); - } - }); -} - -/* - MDNSResponder::setServiceProbeResultCallback (LEGACY 2) -*/ -bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hMDNSService, - MDNSResponder::MDNSServiceProbeResultCallbackFn2 p_fnCallback) -{ - return setServiceProbeResultCallback(p_hMDNSService, [p_fnCallback](MDNSResponder*, - hMDNSHost, - const hMDNSService p_hMDNSService, - const char* p_pcServiceName, - bool p_bProbeResult) - { - if (p_fnCallback) - { - p_fnCallback(p_hMDNSService, p_pcServiceName, p_bProbeResult); - } - }); -} -#endif - -/* - MISC -*/ - -/* - MDNSResponder::notifyNetIfChange - - Should be called, whenever the AP for the MDNS responder changes. - A bit of this is caught by the event callbacks installed in the constructor. - -*/ -bool MDNSResponder::notifyNetIfChange(netif* p_pNetIf) -{ - clsHost* pMDNSHost; - return (((pMDNSHost = _findHost(p_pNetIf))) && - (pMDNSHost->restart())); -} - -/* - MDNSResponder::update - - Should be called in every 'loop'. - -*/ -bool MDNSResponder::update(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_NRH2Ptr(p_hMDNSHost)->update())); -} - -/* - MDNSResponder::update (convenience) -*/ -bool MDNSResponder::update(void) -{ - bool bResult = true; - for (clsHost* pMDNSHost : m_HostList) - { - if (!pMDNSHost->update()) - { - bResult = false; - } - } - return bResult; -} - -/* - MDNSResponder::announce - - Should be called, if the 'configuration' changes. Mainly this will be changes in the TXT items... -*/ -bool MDNSResponder::announce(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_NRH2Ptr(p_hMDNSHost)->announce(true, true))); -} - -/* - MDNSResponder::announce (convenience) -*/ -bool MDNSResponder::announce(void) -{ - bool bResult = true; - for (clsHost* pMDNSHost : m_HostList) - { - if (!pMDNSHost->announce(true, true)) - { - bResult = false; - } - } - return bResult; -} - -/* - MDNSResponder::enableArduino - - Enable the OTA update service. - -*/ -MDNSResponder::hMDNSService MDNSResponder::enableArduino(const MDNSResponder::hMDNSHost p_hMDNSHost, - uint16_t p_u16Port, - bool p_bAuthUpload /*= false*/) -{ - hMDNSService hService = addService(p_hMDNSHost, 0, "arduino", "tcp", p_u16Port); - if (hService) - { - if ((!addServiceTxt(p_hMDNSHost, hService, "tcp_check", "no")) || - (!addServiceTxt(p_hMDNSHost, hService, "ssh_upload", "no")) || - (!addServiceTxt(p_hMDNSHost, hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) || - (!addServiceTxt(p_hMDNSHost, hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) - { - - removeService(p_hMDNSHost, hService); - hService = 0; - } - } - return hService; -} - -#ifdef LATER - -/* - MDNSResponder::enableArduino (LEGACY 2) -*/ -MDNSResponder::hMDNSService MDNSResponder::enableArduino(uint16_t p_u16Port, - bool p_bAuthUpload /*= false*/) -{ - hMDNSService hMDNSService = 0; - for (clsHost*& pMDNSHost : m_HostList) - { - hMDNSService hLastMDNSService = enableArduino((hMDNSHost)it, p_u16Port, p_bAuthUpload); - if ((hLastMDNSService) && - (!hMDNSService)) - { - hMDNSService = hLastMDNSService; - } - } - return hMDNSService; -} - -#endif - -} //namespace MDNSImplementation - -} //namespace esp8266 - - diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp deleted file mode 100755 index 7c144499e4..0000000000 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_APIHelpers.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* - LEAmDNS2_APIHelpers.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* - ESP8266mDNS Control.cpp -*/ - -extern "C" { -#include "user_interface.h" -} - -#include "LEAmDNS2_lwIPdefs.h" -#include "LEAmDNS2_Priv.h" - -namespace esp8266 -{ -/* - LEAmDNS -*/ -namespace experimental -{ - -/* - MDNSResponder::_allocUDPContext -*/ -bool MDNSResponder::_allocUDPContext(void) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext\n"), _DH());); - if (_releaseUDPContext()) - { - m_pUDPContext = new UdpContext; - if (m_pUDPContext) - { - m_pUDPContext->ref(); - - ip_set_option(m_pUDPContext->pcb(), SOF_REUSEADDR); - //udp_bind_netif(m_pUDPContext->pcb(), m_pNetIf); - - if (m_pUDPContext->listen(IP_ANY_TYPE, DNS_MQUERY_PORT)) - { - //m_pUDPContext->setMulticastInterface(m_pNetIf); - m_pUDPContext->setMulticastTTL(MDNS_MULTICAST_TTL); - m_pUDPContext->onRx(std::bind(&MDNSResponder::_processUDPInput, this)); - m_pUDPContext->connect(IP_ANY_TYPE, DNS_MQUERY_PORT); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: Succeeded to alloc UDPContext!\n"), _DH());); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to make UDPContext listening!\n"), _DH());); - _releaseUDPContext(); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to alloc UDPContext!\n"), _DH());); - } - } - DEBUG_EX_ERR(if (!m_pUDPContext) DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED!\n"), _DH());); - return (0 != m_pUDPContext); -} - -/* - MDNSResponder::_releaseUDPContext -*/ -bool MDNSResponder::_releaseUDPContext(void) -{ - if (m_pUDPContext) - { - m_pUDPContext->unref(); - m_pUDPContext = 0; - } - return true; -} - -/* - MDNSResponder::_processUDPInput - - Called in SYS context! - -*/ -bool MDNSResponder::_processUDPInput(void) -{ - //DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput\n"), _DH());); - - if (m_pUDPContext->next()) - { - netif* pNetIf = ip_current_input_netif(); - MDNSResponder::clsHost* pHost = 0; - if ((pNetIf) && - ((pHost = _findHost(pNetIf)))) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: netif:%u,src:%s,dest:%s\n"), _DH(), netif_get_index(pNetIf), IPAddress(ip_current_src_addr()).toString().c_str(), IPAddress(ip_current_dest_addr()).toString().c_str());); - pHost->processUDPInput(/*IPAddress(ip_current_src_addr()), IPAddress(ip_current_dest_addr())*/); - } - else - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Received UDP datagramm for unused netif at index: %u\n"), _DH(), (pNetIf ? netif_get_index(pNetIf) : (-1)));); - } - m_pUDPContext->flush(); - } - return true; -} - -/* - MDNSResponder::_createHost -*/ -MDNSResponder::clsHost* MDNSResponder::_createHost(netif* p_pNetIf) -{ - clsHost* pHost = 0; - - if ((p_pNetIf) && - (!((pHost = _findHost(p_pNetIf)))) && - (m_pUDPContext) && - ((pHost = new clsHost(*p_pNetIf, *m_pUDPContext)))) - { - if (pHost->init()) - { - //pHost->setHostProbeResultCallback(_defaultHostProbeResultCallback); - m_HostList.push_back(pHost); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: FAILED!\n"), _DH());); - _releaseHost(pHost); - pHost = 0; - } - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: Attaching to netif %s!\n"), _DH(), (pHost ? "succeeded" : "FAILED"));); - return pHost; -} - -/* - MDNSResponder::_releaseHost -*/ -bool MDNSResponder::_releaseHost(MDNSResponder::clsHost* p_pHost) -{ - bool bResult = false; - - if ((p_pHost) && - (m_HostList.end() != std::find(m_HostList.begin(), m_HostList.end(), p_pHost))) - { - // Delete and remove Responder object - delete p_pHost; - m_HostList.remove(p_pHost); - bResult = true; - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseHost: %s to release netif Responder!\n"), _DH(), (bResult ? "Succeeded" : "FAILED"));); - return bResult; -} - -/* - MDNSResponder::_findHost -*/ -const MDNSResponder::clsHost* MDNSResponder::_findHost(netif* p_pNetIf) const -{ - const clsHost* pResult = 0; - for (const clsHost* pHost : m_HostList) - { - if ((p_pNetIf) && - (&(pHost->m_rNetIf) == p_pNetIf)) - { - pResult = pHost; - break; - } - } - return pResult; -} - -/* - MDNSResponder::_findHost -*/ -MDNSResponder::clsHost* MDNSResponder::_findHost(netif* p_pNetIf) -{ - return (clsHost*)(((const MDNSResponder*)this)->_findHost(p_pNetIf)); -} - -/* - MDNSResponder::_findHost -*/ -const MDNSResponder::clsHost* MDNSResponder::_findHost(const MDNSResponder::hMDNSHost p_hMDNSHost) const -{ - clsHostList::const_iterator it(std::find(m_HostList.begin(), m_HostList.end(), _NRH2Ptr(p_hMDNSHost))); - return ((m_HostList.end() != it) ? *it : 0); -} - -/* - MDNSResponder::_findHost -*/ -MDNSResponder::clsHost* MDNSResponder::_findHost(const MDNSResponder::hMDNSHost p_hMDNSHost) -{ - return (clsHost*)(((const MDNSResponder*)this)->_findHost(p_hMDNSHost)); -} - - -/* - HANDLE HELPERS -*/ - -/* - MDNSResponder::_validateMDNSHostHandle -*/ -bool MDNSResponder::_validateMDNSHostHandle(const hMDNSHost p_hMDNSHost) const -{ - return (0 != _findHost(_NRH2Ptr(p_hMDNSHost))); -} - -/* - MDNSResponder::_validateMDNSHostHandle -*/ -bool MDNSResponder::_validateMDNSHostHandle(const hMDNSHost p_hMDNSHost, - const hMDNSService p_hMDNSService) const -{ - return ((_validateMDNSHostHandle(p_hMDNSHost)) && - (_NRH2Ptr(p_hMDNSHost)->validateService(_SH2Ptr(p_hMDNSService)))); -} - -/* - MDNSResponder::_NRH2Ptr -*/ -MDNSResponder::clsHost* MDNSResponder::_NRH2Ptr(const hMDNSHost p_hMDNSHost) -{ - return (clsHost*)p_hMDNSHost; -} - -/* - MDNSResponder::_NRH2Ptr -*/ -const MDNSResponder::clsHost* MDNSResponder::_NRH2Ptr(const hMDNSHost p_hMDNSHost) const -{ - return (const clsHost*)p_hMDNSHost; -} - -/* - MDNSResponder::_SH2Ptr -*/ -MDNSResponder::clsHost::stcService* MDNSResponder::_SH2Ptr(const hMDNSService p_hMDNSService) -{ - return (clsHost::stcService*)p_hMDNSService; -} - -/* - MDNSResponder::_SH2Ptr -*/ -const MDNSResponder::clsHost::stcService* MDNSResponder::_SH2Ptr(const hMDNSService p_hMDNSService) const -{ - return (const clsHost::stcService*)p_hMDNSService; -} - -/* - MDNSResponder::_begin - - Creates a new netif responder (adding the netif to the multicast groups), - sets up the instance data (hostname, ...) and starts the probing process - -*/ -MDNSResponder::clsHost* MDNSResponder::_begin(const char* p_pcHostName, - netif* p_pNetIf, - MDNSHostProbeResultCallbackFn p_fnCallback) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _begin(%s, netif: %u)\n"), _DH(), (p_pcHostName ?: "_"), (p_pNetIf ? netif_get_index(p_pNetIf) : 0));); - - clsHost* pHost = 0; - if ((!m_pUDPContext) || - (!p_pNetIf) || - (!((pHost = _createHost(p_pNetIf)))) || - (p_fnCallback ? !setHostProbeResultCallback((hMDNSHost)pHost, p_fnCallback) : false) || - (!pHost->setHostName(p_pcHostName)) || - (!pHost->restart())) - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _begin: FAILED for '%s'!\n"), _DH(), (p_pcHostName ? : "-"));); - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _begin: %s to init netif with hostname %s!\n"), _DH(), (pHost ? "Succeeded" : "FAILED"), (p_pcHostName ? : "-"));); - return pHost; -} - -/* - MDNSResponder::_close - - The announced host and services are unannounced (by multicasting a goodbye message) - All connected objects and finally the netif Responder is removed. - -*/ -bool MDNSResponder::_close(MDNSResponder::clsHost& p_rHost) -{ - _releaseHost(&p_rHost); // Will call 'delete' on the pHost object! - - return true; -} - - -/* - MISC -*/ - -#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER - -/* - MDNSResponder::_DH -*/ -const char* MDNSResponder::_DH(const hMDNSHost p_hMDNSHost /*= 0*/) const -{ - static char acBuffer[64]; - - *acBuffer = 0; - if (p_hMDNSHost) - { - sprintf_P(acBuffer, PSTR("[MDNSResponder %s]"), ((WIFI_STA == netif_get_index(&((clsHost*)p_hMDNSHost)->m_rNetIf)) - ? "STA" - : ((WIFI_AP == netif_get_index(&((clsHost*)p_hMDNSHost)->m_rNetIf)) - ? "AP" - : "??"))); - } - else - { - sprintf_P(acBuffer, PSTR("[MDNSResponder]")); - } - return acBuffer; -} - -#endif - - -} // namespace MDNSImplementation - -} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp new file mode 100644 index 0000000000..1f5f0422d4 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp @@ -0,0 +1,339 @@ +/* + LEAmDNS2_Backbone.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "LEAmDNS2Host.h" + + +namespace esp8266 +{ + + +namespace experimental +{ + + +/* + clsLEAmDNS2_Host::clsBackbone::clsBackbone constructor + +*/ +clsLEAMDNSHost::clsBackbone::clsBackbone(void) + : m_pUDPContext(0), + m_bDelayUDPProcessing(false), + m_u32DelayedDatagrams(0) +{ +} + +/* + clsLEAmDNS2_Host::clsBackbone::clsBackbone destructor + +*/ +clsLEAMDNSHost::clsBackbone::~clsBackbone(void) +{ + _releaseUDPContext(); +} + +/* + clsLEAmDNS2_Host::clsBackbone::init + +*/ +bool clsLEAMDNSHost::clsBackbone::init(void) +{ + return _allocUDPContext(); +} + +/* + clsLEAmDNS2_Host::clsBackbone::addHost + +*/ +UdpContext* clsLEAMDNSHost::clsBackbone::addHost(clsLEAMDNSHost* p_pHost) +{ + UdpContext* pUDPContext = 0; + + if ((m_pUDPContext) && + (p_pHost)) + { + m_HostList.push_back(p_pHost); + pUDPContext = m_pUDPContext; + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s addHost: %s to add host!\n"), _DH(), (pUDPContext ? "Succeeded" : "FAILED"));); + return pUDPContext; +} + +/* + clsLEAmDNS2_Host::clsBackbone::removeHost + +*/ +bool clsLEAMDNSHost::clsBackbone::removeHost(clsLEAMDNSHost* p_pHost) +{ + bool bResult = false; + + if ((p_pHost) && + (m_HostList.end() != std::find(m_HostList.begin(), m_HostList.end(), p_pHost))) + { + // Remove host object + m_HostList.remove(p_pHost); + bResult = true; + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s removeHost: %s to remove host!\n"), _DH(), (bResult ? "Succeeded" : "FAILED"));); + return bResult; +} + + +/* + clsLEAmDNS2_Host::clsBackbone::hostCount + +*/ +size_t clsLEAMDNSHost::clsBackbone::hostCount(void) const +{ + return m_HostList.size(); +} + +/* + clsLEAMDNSHost::clsBackbone::::setDelayUDPProcessing + + When executing _sendMessage, with multiple or larger messages, sometimes the ESP IP stack seems + to need a small delay to get the job done. To allow for this delay, a 'delay' was added after one + send operation. However, while 'taking' this delay, sometimes a UDP datagram is received and + processed (which might cause another send operation or change global states). + To avoid 're-entry-like' problems, UDP processing might be blocked for a short period of time. + +*/ +bool clsLEAMDNSHost::clsBackbone::setDelayUDPProcessing(bool p_bDelayUDPProcessing) +{ + if (m_bDelayUDPProcessing != p_bDelayUDPProcessing) + { + m_bDelayUDPProcessing = p_bDelayUDPProcessing; + + if ((!m_bDelayUDPProcessing) && + (m_u32DelayedDatagrams)) + { + DEBUG_EX_INFO2(if (6 <= m_u32DelayedDatagrams) DEBUG_OUTPUT.printf_P(PSTR("%s setDelayUDPProcessing: Processing %u delayed datagram(s)\n"), _DH(), m_u32DelayedDatagrams);); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s setDelayUDPProcessing: Processing %u delayed datagram(s)\n"), _DH(), m_u32DelayedDatagrams);); + _processUDPInput(); + } + m_u32DelayedDatagrams = 0; + } + return true; +} + +/* + clsLEAmDNS2_Host::clsBackbone::_allocUDPContext + +*/ +bool clsLEAMDNSHost::clsBackbone::_allocUDPContext(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext\n"), _DH());); + if (_releaseUDPContext()) + { + m_pUDPContext = new UdpContext; + if (m_pUDPContext) + { + m_pUDPContext->ref(); + + //ip_set_option(m_pUDPContext->pcb(), SOF_REUSEADDR); + //udp_bind_netif(m_pUDPContext->pcb(), m_pNetIf); + + if (m_pUDPContext->listen(IP_ANY_TYPE, DNS_MQUERY_PORT)) + { + // This is NOT the TTL (Time-To-Live) for MDNS records, but the subnet level distance MDNS records should travel. + // 1 sets the subnet distance to 'local', which is default for MDNS. + // (Btw.: 255 would set it to 'as far as possible' -> internet), however, RFC 3171 seems to force 255 instead + const uint8_t c_u8MulticastTTL = 255;//1;//255; + + m_pUDPContext->setMulticastTTL(c_u8MulticastTTL); + m_pUDPContext->onRx(std::bind(&clsLEAMDNSHost::clsBackbone::_processUDPInput, this)); + /* m_pUDPContext->onRx([&](void)->void + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext::onRx Received data!\n"), _DH());); + });*/ + m_pUDPContext->connect(IP_ANY_TYPE, DNS_MQUERY_PORT); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: Succeeded to alloc UDPContext!\n"), _DH());); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to make UDPContext listening!\n"), _DH());); + _releaseUDPContext(); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to alloc UDPContext!\n"), _DH());); + } + } + DEBUG_EX_ERR(if (!m_pUDPContext) DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED!\n"), _DH());); + return (0 != m_pUDPContext); +} + +/* + clsLEAmDNS2_Host::clsBackbone::_releaseUDPContext + +*/ +bool clsLEAMDNSHost::clsBackbone::_releaseUDPContext(void) +{ + if (m_pUDPContext) + { + m_pUDPContext->unref(); + m_pUDPContext = 0; + } + return true; +} + +/* + clsLEAmDNS2_Host::clsBackbone::_processUDPInput + + Called in SYS context! + +*/ +bool clsLEAMDNSHost::clsBackbone::_processUDPInput(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput\n"), _DH());); + + bool bResult = true; + + if (!m_bDelayUDPProcessing) + { + DEBUG_EX_INFO(uint32_t u32LoopCounter = 0; IPAddress remoteIPAddr;); + while ((m_pUDPContext) && + (m_pUDPContext->next())) + { + netif* pNetIf = m_pUDPContext->getInputNetif();//ip_current_input_netif(); // Probably changed inbetween!!!! + clsLEAMDNSHost* pHost = 0; + if ((pNetIf) && + ((pHost = _findHost(pNetIf)))) + { + DEBUG_EX_INFO( + if (u32LoopCounter++) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Multi-Loop (%u)!\n"), _DH(), u32LoopCounter); + if ((remoteIPAddr.isSet()) && + (remoteIPAddr != m_pUDPContext->getRemoteAddress())) + { + DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Changed IP address %s->%s!\n"), _DH(), remoteIPAddr.toString().c_str(), m_pUDPContext->getRemoteAddress().toString().c_str()); + } + } + remoteIPAddr = m_pUDPContext->getRemoteAddress(); + ); + bResult = pHost->_processUDPInput(); + DEBUG_EX_INFO2(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: FAILED to process UDP input!\n"), _DH());); + + DEBUG_EX_ERR(if ((-1) != m_pUDPContext->peek()) DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: !!!! CONTENT LEFT IN UDP BUFFER !!!!\n"), _DH());); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Received UDP datagramm for unused netif at index: %u\n"), _DH(), (pNetIf ? netif_get_index(pNetIf) : (-1)));); + } + m_pUDPContext->flush(); + } + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Delaying datagram!\n"), _DH());); + ++m_u32DelayedDatagrams; + } + return bResult; +} + +/* + clsLEAmDNS2_Host::clsBackbone::_findHost +*/ +const clsLEAMDNSHost* clsLEAMDNSHost::clsBackbone::_findHost(netif* p_pNetIf) const +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _findHost\n"), _DH());); + const clsLEAMDNSHost* pResult = 0; + for (const clsLEAMDNSHost* pHost : m_HostList) + { + if ((p_pNetIf) && + (pHost->m_pNetIf == p_pNetIf)) + { + pResult = pHost; + break; + } + } + return pResult; +} + +/* + MDNSResponder::_findHost +*/ +clsLEAMDNSHost* clsLEAMDNSHost::clsBackbone::_findHost(netif* p_pNetIf) +{ + return (clsLEAMDNSHost*)(((const clsLEAMDNSHost::clsBackbone*)this)->_findHost(p_pNetIf)); +} + + +/* + MISC +*/ + +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + +/* + clsLEAmDNS2_Host::clsBackbone::_DH +*/ +const char* clsLEAMDNSHost::clsBackbone::_DH(void) const +{ + static char acBuffer[24]; + + *acBuffer = 0; + sprintf_P(acBuffer, PSTR("[mDNS::backbone]")); + + return acBuffer; +} + +#endif + +#if LWIP_VERSION_MAJOR == 1 + +/* + netif_get_by_index + + Extracted (and slightly changed) from: https://github.com/yarrick/lwip/blob/master/src/core/netif.c +*/ +struct netif* netif_get_by_index(u8_t idx) +{ + struct netif *netif; + + //LWIP_ASSERT_CORE_LOCKED(); + + if (idx != 0) // <- NETIF_NO_INDEX + { + for ((netif) = netif_list; (netif) != NULL; (netif) = (netif)->next) // <- NETIF_FOREACH(netif) + { + if (idx == netif_get_index(netif)) + { + return netif; /* found! */ + } + } + } + + return NULL; +} + +#endif // LWIP_VERSION_MAJOR == 1 + + +} // namespace MDNSImplementation + + +} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp deleted file mode 100755 index b9df26ce8f..0000000000 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Host.cpp +++ /dev/null @@ -1,1336 +0,0 @@ -/* - LEAmDNS2_Host.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - ESP8266mDNS Control.cpp -*/ - -extern "C" { -#include "user_interface.h" -} - -#include "LEAmDNS2_lwIPdefs.h" -#include "LEAmDNS2_Priv.h" - -#ifdef MDNS_IPV4_SUPPORT -#include -#endif -#ifdef MDNS_IPV6_SUPPORT -#include -#endif - - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace experimental -{ - -/* - MDNSResponder::clsHost::clsHost constructor -*/ -MDNSResponder::clsHost::clsHost(netif& p_rNetIf, - UdpContext& p_rUDPContext) - : m_rNetIf(p_rNetIf), - m_NetIfState(static_cast(enuNetIfState::None)), - m_rUDPContext(p_rUDPContext), - m_pcHostName(0), - m_pcInstanceName(0), - m_pServices(0), - m_pQueries(0), - m_fnServiceTxtCallback(0), - m_HostProbeInformation() -{ -} - -/* - MDNSResponder::clsHost::~clsHost destructor -*/ -MDNSResponder::clsHost::~clsHost(void) -{ - _close(); -} - -/* - MDNSResponder::clsHost::init -*/ -bool MDNSResponder::clsHost::init(void) -{ - bool bResult = true; - - // Join multicast group(s) -#ifdef MDNS_IPV4_SUPPORT - ip_addr_t multicast_addr_V4 = DNS_MQUERY_IPV4_GROUP_INIT; - if (!(m_rNetIf.flags & NETIF_FLAG_IGMP)) - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: Setting flag: flags & NETIF_FLAG_IGMP\n"), _DH());); - m_rNetIf.flags |= NETIF_FLAG_IGMP; - - if (ERR_OK != igmp_start(&m_rNetIf)) - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: igmp_start FAILED!\n"), _DH());); - } - } - - bResult = ((bResult) && - (ERR_OK == igmp_joingroup_netif(&m_rNetIf, ip_2_ip4(&multicast_addr_V4)))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: igmp_joingroup_netif(%s) FAILED!\n"), _DH(), IPAddress(multicast_addr_V4).toString().c_str());); -#endif - -#ifdef MDNS_IPV6_SUPPORT - ip_addr_t multicast_addr_V6 = DNS_MQUERY_IPV6_GROUP_INIT; - bResult = ((bResult) && - (ERR_OK == mld6_joingroup_netif(&m_rNetIf, ip_2_ip6(&multicast_addr_V6)))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: mld6_joingroup_netif FAILED!\n"), _DH());); -#endif - return bResult; -} - -/* - MDNSResponder::clsHost::setHostName -*/ -bool MDNSResponder::clsHost::setHostName(const char* p_pcHostName) -{ - bool bResult; - if ((bResult = _allocHostName(p_pcHostName))) - { - m_HostProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart; - - // Replace 'auto-set' service names - for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if ((pService->m_bAutoName) && - (!m_pcInstanceName)) - { - bResult = pService->setName(p_pcHostName); - pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart; - } - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::setHostName -*/ -const char* MDNSResponder::clsHost::hostName(void) const -{ - return m_pcHostName; -} - -/* - MDNSResponder::clsHost::setHostProbeResultCallback -*/ -bool MDNSResponder::clsHost::setHostProbeResultCallback(HostProbeResultCallbackFn p_fnCallback) -{ - m_HostProbeInformation.m_fnProbeResultCallback = p_fnCallback; - return true; -} - -/* - MDNSResponder::clsHost::probeStatus -*/ -bool MDNSResponder::clsHost::probeStatus(void) const -{ - return (enuProbingStatus::Done == m_HostProbeInformation.m_ProbingStatus); -} - - -/* - SERVICE -*/ - -/* - MDNSResponder::clsHost::setInstanceName -*/ -bool MDNSResponder::clsHost::setInstanceName(const char* p_pcInstanceName) -{ - bool bResult; - if ((bResult = _allocInstanceName(p_pcInstanceName))) - { - // Replace 'auto-set' service names - for (stcService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if (pService->m_bAutoName) - { - bResult = pService->setName(p_pcInstanceName); - pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart; - } - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::instanceName -*/ -const char* MDNSResponder::clsHost::instanceName(void) const -{ - return m_pcInstanceName; -} - -/* - MDNSResponder::clsHost::addService -*/ -MDNSResponder::clsHost::stcService* MDNSResponder::clsHost::addService(const char* p_pcInstanceName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port) -{ - stcService* pService = 0; - - if (((!p_pcInstanceName) || // NO name OR - (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcInstanceName))) && // Fitting name - (p_pcServiceType) && - (MDNS_SERVICE_NAME_LENGTH >= os_strlen(p_pcServiceType)) && - (p_pcProtocol) && - ((MDNS_SERVICE_PROTOCOL_LENGTH - 1) != os_strlen(p_pcProtocol)) && - (p_u16Port)) - { - if (!((pService = findService((p_pcInstanceName ? : (m_pcInstanceName ? : m_pcHostName)), p_pcServiceType, p_pcProtocol, p_u16Port)))) // Not already used - { - if (0 != (pService = _allocService(p_pcInstanceName, p_pcServiceType, p_pcProtocol, p_u16Port))) - { - // Init probing - pService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart; - } - } - } // else: bad arguments - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s addService: %s to add service '%s.%s.%s.local'!\n"), _DH(pService), (pService ? "Succeeded" : "FAILED"), (p_pcInstanceName ? : (m_pcInstanceName ? : (m_pcHostName ? : "-"))), (p_pcServiceType ? : ""), (p_pcProtocol ? : ""));); - DEBUG_EX_ERR(if (!pService) DEBUG_OUTPUT.printf_P(PSTR("%s addService: FAILED to add service '%s.%s.%s.local'!\n"), _DH(pService), (p_pcInstanceName ? : (m_pcInstanceName ? : (m_pcHostName ? : "-"))), (p_pcServiceType ? : ""), (p_pcProtocol ? : ""));); - return pService; -} - -/* - MDNSResponder::clsHost::removeService -*/ -bool MDNSResponder::clsHost::removeService(MDNSResponder::clsHost::stcService* p_pMDNSService) -{ - bool bResult = ((p_pMDNSService) && - (_announceService(*p_pMDNSService, false)) && - (_releaseService(p_pMDNSService))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _removeService: FAILED!\n"), _DH(p_pMDNSService));); - return bResult; -} - -/* - MDNSResponder::clsHost::findService (const) -*/ -const MDNSResponder::clsHost::stcService* MDNSResponder::clsHost::findService(const char* p_pcInstanceName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port /*= 0*/) const -{ - stcService* pService = m_pServices; - while (pService) - { - if ((0 == strcmp(pService->m_pcName, p_pcInstanceName)) && - (0 == strcmp(pService->m_pcServiceType, p_pcServiceType)) && - (0 == strcmp(pService->m_pcProtocol, p_pcProtocol)) && - ((!p_u16Port) || - (p_u16Port == pService->m_u16Port))) - { - - break; - } - pService = pService->m_pNext; - } - return pService; -} - -/* - MDNSResponder::clsHost::findService -*/ -MDNSResponder::clsHost::stcService* MDNSResponder::clsHost::findService(const char* p_pcInstanceName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port /*= 0*/) -{ - return (stcService*)((const clsHost*)this)->findService(p_pcInstanceName, p_pcServiceType, p_pcProtocol, p_u16Port); -} - -/* - MDNSResponder::clsHost::validateService -*/ -bool MDNSResponder::clsHost::validateService(const MDNSResponder::clsHost::stcService* p_pService) const -{ - const stcService* pService = m_pServices; - while (pService) - { - if (pService == p_pService) - { - break; - } - pService = pService->m_pNext; - } - return (0 != pService); -} - -/* - MDNSResponder::clsHost::setServiceName -*/ -bool MDNSResponder::clsHost::setServiceName(MDNSResponder::clsHost::stcService* p_pMDNSService, - const char* p_pcInstanceName) -{ - p_pcInstanceName = p_pcInstanceName ? : m_pcInstanceName; - - bool bResult = ((p_pMDNSService) && - ((!p_pcInstanceName) || - (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcInstanceName))) && - (p_pMDNSService->setName(p_pcInstanceName)) && - ((p_pMDNSService->m_ProbeInformation.m_ProbingStatus = enuProbingStatus::ReadyToStart), true)); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _setServiceName: FAILED for '%s'!\n"), _DH(p_pMDNSService), (p_pcInstanceName ? : "-"));); - return bResult; -} - -/* - MDNSResponder::clsHost::setServiceName -*/ -const char* MDNSResponder::clsHost::serviceName(const stcService* p_pMDNSService) const -{ - return ((p_pMDNSService) - ? (p_pMDNSService->m_pcName) - : 0); -} - -/* - MDNSResponder::clsHost::serviceType -*/ -const char* MDNSResponder::clsHost::serviceType(const stcService* p_pMDNSService) const -{ - return ((p_pMDNSService) - ? (p_pMDNSService->m_pcServiceType) - : 0); -} - -/* - MDNSResponder::clsHost::serviceProtocol -*/ -const char* MDNSResponder::clsHost::serviceProtocol(const stcService* p_pMDNSService) const -{ - return ((p_pMDNSService) - ? (p_pMDNSService->m_pcProtocol) - : 0); -} - -/* - MDNSResponder::clsHost::servicePort -*/ -uint16_t MDNSResponder::clsHost::servicePort(const stcService* p_pMDNSService) const -{ - return ((p_pMDNSService) - ? (p_pMDNSService->m_u16Port) - : 0); -} - - -/* - MDNSResponder::clsHost::setServiceProbeResultCallback -*/ -bool MDNSResponder::clsHost::setServiceProbeResultCallback(stcService* p_pMDNSService, - ServiceProbeResultCallbackFn p_fnCallback) -{ - return ((p_pMDNSService) - ? ((p_pMDNSService->m_ProbeInformation.m_fnProbeResultCallback = p_fnCallback), true) - : false); -} - -/* - MDNSResponder::clsHost::setServiceName -*/ -bool MDNSResponder::clsHost::serviceProbeStatus(const stcService* p_pMDNSService) const -{ - return ((p_pMDNSService) && - (enuProbingStatus::Done == p_pMDNSService->m_ProbeInformation.m_ProbingStatus)); -} - - -/* - SERVICE TXT -*/ - -/* - MDNSResponder::clsHost::addServiceTxt -*/ -MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::addServiceTxt(stcService* p_pMDNSService, - const char* p_pcKey, - const char* p_pcValue) -{ - return _addServiceTxt(p_pMDNSService, p_pcKey, p_pcValue, false); -} - -/* - MDNSResponder::clsHost::removeServiceTxt -*/ -bool MDNSResponder::clsHost::removeServiceTxt(stcService* p_pMDNSService, - stcServiceTxt* p_pTxt) -{ - bool bResult = ((p_pMDNSService) && - (p_pTxt) && - (_releaseServiceTxt(p_pMDNSService, p_pTxt))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeServiceTxt: FAILED!\n"), _DH(p_pMDNSService));); - return bResult; -} - -/* - MDNSResponder::clsHost::findServiceTxt (const) -*/ -const MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::findServiceTxt(MDNSResponder::clsHost::stcService* p_pMDNSService, - const char* p_pcKey) const -{ - return (const stcServiceTxt*)((const clsHost*)this)->findServiceTxt(p_pMDNSService, p_pcKey); -} - -/* - MDNSResponder::clsHost::findServiceTxt -*/ -MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::findServiceTxt(MDNSResponder::clsHost::stcService* p_pMDNSService, - const char* p_pcKey) -{ - return _findServiceTxt(p_pMDNSService, p_pcKey); -} - -/* - MDNSResponder::clsHost::setDynamicServiceTxtCallback -*/ -bool MDNSResponder::clsHost::setDynamicServiceTxtCallback(DynamicServiceTxtCallbackFn p_fnCallback) -{ - m_fnServiceTxtCallback = p_fnCallback; - return true; -} - -/* - MDNSResponder::clsHost::setDynamicServiceTxtCallback -*/ -bool MDNSResponder::clsHost::setDynamicServiceTxtCallback(stcService* p_pMDNSService, - DynamicServiceTxtCallbackFn p_fnCallback) -{ - return ((p_pMDNSService) - ? ((p_pMDNSService->m_fnTxtCallback = p_fnCallback), true) - : false); -} - -/* - MDNSResponder::clsHost::addDynamicServiceTxt - - Add a (dynamic) MDNS TXT item ('key' = 'value') to the service - Dynamic TXT items are removed right after one-time use. So they need to be added - every time the value s needed (via callback). -*/ -MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::addDynamicServiceTxt(stcService* p_pMDNSService, - const char* p_pcKey, - const char* p_pcValue) -{ - return _addServiceTxt(p_pMDNSService, p_pcKey, p_pcValue, true); -} - - -/* - QUERIES -*/ -/* - MDNSResponder::clsHost::queryService -*/ -uint32_t MDNSResponder::clsHost::queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local'\n"), _DH(), p_pcService, p_pcProtocol);); - - stcQuery* pMDNSQuery = 0; - if ((p_pcService) && (*p_pcService) && - (p_pcProtocol) && (*p_pcProtocol) && - (p_u16Timeout) && - ((pMDNSQuery = _allocQuery(stcQuery::enuQueryType::Service))) && - (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) - { - if ((_removeLegacyQuery()) && - ((pMDNSQuery->m_bLegacyQuery = true)) && - (_sendMDNSQuery(*pMDNSQuery))) - { - // Wait for answers to arrive - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); - delay(p_u16Timeout); - - // All answers should have arrived by now -> stop adding new answers - pMDNSQuery->m_bAwaitingAnswers = false; - } - else // FAILED to send query - { - _removeQuery(pMDNSQuery); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: INVALID input data!\n"), _DH());); - } - return ((pMDNSQuery) - ? pMDNSQuery->answerCount() - : 0); -} - -/* - MDNSResponder::clsHost::queryHost -*/ -uint32_t MDNSResponder::clsHost::queryHost(const char* p_pcHostName, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local'\n"), _DH(), p_pcHostName);); - - stcQuery* pMDNSQuery = 0; - if ((p_pcHostName) && (*p_pcHostName) && - (p_u16Timeout) && - ((pMDNSQuery = _allocQuery(stcQuery::enuQueryType::Host))) && - (_buildDomainForHost(p_pcHostName, pMDNSQuery->m_Domain))) - { - if ((_removeLegacyQuery()) && - ((pMDNSQuery->m_bLegacyQuery = true)) && - (_sendMDNSQuery(*pMDNSQuery))) - { - // Wait for answers to arrive - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); - delay(p_u16Timeout); - - // All answers should have arrived by now -> stop adding new answers - pMDNSQuery->m_bAwaitingAnswers = false; - } - else // FAILED to send query - { - _removeQuery(pMDNSQuery); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: INVALID input data!\n"), _DH());); - } - return ((pMDNSQuery) - ? pMDNSQuery->answerCount() - : 0); -} - -/* - MDNSResponder::clsHost::removeQuery -*/ -bool MDNSResponder::clsHost::removeQuery(void) -{ - return _removeLegacyQuery(); -} - -/* - MDNSResponder::clsHost::hasQuery -*/ -bool MDNSResponder::clsHost::hasQuery(void) -{ - return (0 != _findLegacyQuery()); -} - -/* - MDNSResponder::clsHost::getQuery -*/ -MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::getQuery(void) -{ - return _findLegacyQuery(); -} - -/* - MDNSResponder::clsHost::installServiceQuery -*/ -MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSResponder::clsHost::QueryCallbackFn p_fnCallback) -{ - stcQuery* pMDNSQuery = 0; - if ((p_pcService) && (*p_pcService) && - (p_pcProtocol) && (*p_pcProtocol) && - (p_fnCallback) && - ((pMDNSQuery = _allocQuery(stcQuery::enuQueryType::Service))) && - (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) - { - - pMDNSQuery->m_fnCallback = p_fnCallback; - pMDNSQuery->m_bLegacyQuery = false; - - if (_sendMDNSQuery(*pMDNSQuery)) - { - pMDNSQuery->m_u8SentCount = 1; - pMDNSQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); - } - else - { - _removeQuery(pMDNSQuery); - } - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: %s for '_%s._%s.local'!\n\n"), _DH(), (pMDNSQuery ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - DEBUG_EX_ERR(if (!pMDNSQuery) DEBUG_OUTPUT.printf_P(PSTR("%s installServiceQuery: FAILED for '_%s._%s.local'!\n\n"), _DH(), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - return pMDNSQuery; -} - -/* - MDNSResponder::clsHost::installHostQuery -*/ -MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::installHostQuery(const char* p_pcHostName, - MDNSResponder::clsHost::QueryCallbackFn p_fnCallback) -{ - stcQuery* pMDNSQuery = 0; - if ((p_pcHostName) && (*p_pcHostName)) - { - stcRRDomain domain; - pMDNSQuery = ((_buildDomainForHost(p_pcHostName, domain)) - ? _installDomainQuery(domain, stcQuery::enuQueryType::Host, p_fnCallback) - : 0); - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: %s for '%s.local'!\n\n"), _DH(), (pMDNSQuery ? "Succeeded" : "FAILED"), (p_pcHostName ? : "-"));); - DEBUG_EX_ERR(if (!pMDNSQuery) DEBUG_OUTPUT.printf_P(PSTR("%s installHostQuery: FAILED for '%s.local'!\n\n"), _DH(), (p_pcHostName ? : "-"));); - return pMDNSQuery; -} - -/* - MDNSResponder::clsHost::removeQuery -*/ -bool MDNSResponder::clsHost::removeQuery(MDNSResponder::clsHost::stcQuery* p_pMDNSQuery) -{ - bool bResult = ((p_pMDNSQuery) && - (_removeQuery(p_pMDNSQuery))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeQuery: FAILED!\n"), _DH());); - return bResult; -} - - -/* - PROCESSING -*/ - -/* - MDNSResponder::clsHost::processUDPInput -*/ -bool MDNSResponder::clsHost::processUDPInput() -{ - bool bResult = false; - - bResult = ((_checkNetIfState()) && // Any changes in the netif state? - (_parseMessage())); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR(""));); - - return bResult; -} - -/* - MDNSResponder::clsHost::update -*/ -bool MDNSResponder::clsHost::update(void) -{ - return ((_checkNetIfState()) && // Any changes in the netif state? - (_updateProbeStatus()) && // Probing - (_checkQueryCache())); -} - -/* - MDNSResponder::clsHost::restart -*/ -bool MDNSResponder::clsHost::restart(void) -{ - return (_resetProbeStatus(true)); // Stop and restart probing -} - - - - - -/* - P R O T E C T E D -*/ - -/* - MDNSResponder::clsHost::_close -*/ -bool MDNSResponder::clsHost::_close(void) -{ - /* _resetProbeStatus(false); // Stop probing - - _releaseQueries(); - _releaseServices(); - _releaseHostName();*/ - - // Leave multicast group(s) -#ifdef MDNS_IPV4_SUPPORT - ip_addr_t multicast_addr_V4 = DNS_MQUERY_IPV4_GROUP_INIT; - if (ERR_OK != igmp_leavegroup_netif(&m_rNetIf, ip_2_ip4(&multicast_addr_V4)/*(const struct ip4_addr *)&multicast_addr_V4.u_addr.ip4*/)) - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("\n"));); - } -#endif -#ifdef MDNS_IPV6_SUPPORT - ip_addr_t multicast_addr_V6 = DNS_MQUERY_IPV6_GROUP_INIT; - if (ERR_OK != mld6_leavegroup_netif(&m_rNetIf, ip_2_ip6(&multicast_addr_V6)/*&(multicast_addr_V6.u_addr.ip6)*/)) - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("\n"));); - } -#endif - return true; -} - - -/* - NETIF -*/ - -/* - MDNSResponder::clsHost::_getNetIfState - - Returns the current netif state. - -*/ -MDNSResponder::clsHost::typeNetIfState MDNSResponder::clsHost::_getNetIfState(void) const -{ - typeNetIfState curNetIfState = static_cast(enuNetIfState::None); - - if (netif_is_up(&m_rNetIf)) - { - curNetIfState |= static_cast(enuNetIfState::IsUp); - - // Check if netif link is up - if ((netif_is_link_up(&m_rNetIf)) && - ((&m_rNetIf != netif_get_by_index(WIFI_STA)) || - (STATION_GOT_IP == wifi_station_get_connect_status()))) - { - curNetIfState |= static_cast(enuNetIfState::LinkIsUp); - } - - // Check for IPv4 address - if (_getResponderIPAddress(enuIPProtocolType::V4).isSet()) - { - curNetIfState |= static_cast(enuNetIfState::IPv4); - } - // Check for IPv6 address - if (_getResponderIPAddress(enuIPProtocolType::V6).isSet()) - { - curNetIfState |= static_cast(enuNetIfState::IPv6); - } - } - return curNetIfState; -} - -/* - MDNSResponder::clsHost::_checkNetIfState - - Checks the netif state. - If eg. a new address appears, the announcing is restarted. - -*/ -bool MDNSResponder::clsHost::_checkNetIfState(void) -{ - typeNetIfState curNetIfState; - if (m_NetIfState != ((curNetIfState = _getNetIfState()))) - { - // Some state change happened - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: DID CHANGE NETIF STATE\n\n"), _DH());); - DEBUG_EX_INFO( - if ((curNetIfState & static_cast(enuNetIfState::IsUp)) != (m_NetIfState & static_cast(enuNetIfState::IsUp))) - { - DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Netif is up: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::IsUp)) ? "YES" : "NO")); - } - if ((curNetIfState & static_cast(enuNetIfState::LinkIsUp)) != (m_NetIfState & static_cast(enuNetIfState::LinkIsUp))) - { - DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Netif link is up: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::LinkIsUp)) ? "YES" : "NO")); - } - if ((curNetIfState & static_cast(enuNetIfState::IPv4)) != (m_NetIfState & static_cast(enuNetIfState::IPv4))) - { - DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv4 address is set: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::IPv4)) ? "YES" : "NO")); - if (curNetIfState & static_cast(enuNetIfState::IPv4)) - { - DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv4 address: %s\n"), _DH(), _getResponderIPAddress(enuIPProtocolType::V4).toString().c_str()); - } - } - if ((curNetIfState & static_cast(enuNetIfState::IPv6)) != (m_NetIfState & static_cast(enuNetIfState::IPv6))) - { - DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv6 address is set: %s\n"), _DH(), ((curNetIfState & static_cast(enuNetIfState::IPv6)) ? "YES" : "NO")); - if (curNetIfState & static_cast(enuNetIfState::IPv6)) - { - DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: IPv6 address: %s\n"), _DH(), _getResponderIPAddress(enuIPProtocolType::V6).toString().c_str()); - } - } - ); - - if ((curNetIfState & static_cast(enuNetIfState::LinkMask)) != (m_NetIfState & static_cast(enuNetIfState::LinkMask))) - { - // Link came up (restart() will alloc a m_pUDPContext, ...) or down (_restart() will remove an existing m_pUDPContext, ...) - restart(); - } - else if (curNetIfState & static_cast(enuNetIfState::LinkIsUp)) - { - // Link is up (unchanged) - if ((curNetIfState & static_cast(enuNetIfState::IPMask)) != (m_NetIfState & static_cast(enuNetIfState::IPMask))) - { - // IP state changed - // TODO: If just a new IP address was added, a simple re-announcement should be enough - restart(); - } - } - /* if (enuProbingStatus::Done == m_HostProbeInformation.m_ProbingStatus) { - // Probing is done, prepare to (re)announce host - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Preparing to (re)announce host.\n"));); - //m_HostProbeInformation.m_ProbingStatus = enuProbingStatus::Done; - m_HostProbeInformation.m_u8SentCount = 0; - m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); - }*/ - m_NetIfState = curNetIfState; - } - - bool bResult = ((curNetIfState & static_cast(enuNetIfState::LinkMask)) && // Continue if Link is UP - (curNetIfState & static_cast(enuNetIfState::IPMask))); // AND has any IP - //DEBUG_EX_INFO(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _checkNetIfState: Link is DOWN or NO IP address!\n"), _DH());); - return bResult; -} - - -/* - DOMAIN NAMES -*/ - -/* - MDNSResponder::clsHost::_allocDomainName -*/ -bool MDNSResponder::clsHost::_allocDomainName(const char* p_pcNewDomainName, - char*& p_rpcDomainName) -{ - bool bResult = false; - - _releaseDomainName(p_rpcDomainName); - - size_t stLength = 0; - if ((p_pcNewDomainName) && - (MDNS_DOMAIN_LABEL_MAXLENGTH >= (stLength = strlen(p_pcNewDomainName)))) // char max size for a single label - { - // Copy in hostname characters as lowercase - if ((bResult = (0 != (p_rpcDomainName = new char[stLength + 1])))) - { -#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME - size_t i = 0; - for (; i < stLength; ++i) - { - p_rpcDomainName[i] = (isupper(p_pcNewDomainName[i]) ? tolower(p_pcNewDomainName[i]) : p_pcNewDomainName[i]); - } - p_rpcDomainName[i] = 0; -#else - strncpy(p_rpcDomainName, p_pcNewDomainName, (stLength + 1)); -#endif - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::_releaseDomainName -*/ -bool MDNSResponder::clsHost::_releaseDomainName(char*& p_rpcDomainName) -{ - bool bResult; - if ((bResult = (0 != p_rpcDomainName))) - { - delete[] p_rpcDomainName; - p_rpcDomainName = 0; - } - return bResult; -} - -/* - MDNSResponder::clsHost::_allocHostName -*/ -bool MDNSResponder::clsHost::_allocHostName(const char* p_pcHostName) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocHostName (%s)\n"), _DH(), p_pcHostName);); - return _allocDomainName(p_pcHostName, m_pcHostName); -} - -/* - MDNSResponder::clsHost::_releaseHostName -*/ -bool MDNSResponder::clsHost::_releaseHostName(void) -{ - return _releaseDomainName(m_pcHostName); -} - -/* - MDNSResponder::clsHost::_allocInstanceName -*/ -bool MDNSResponder::clsHost::_allocInstanceName(const char* p_pcInstanceName) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocInstanceName (%s)\n"), _DH(), p_pcHostName);); - return _allocDomainName(p_pcInstanceName, m_pcInstanceName); -} - -/* - MDNSResponder::clsHost::_releaseInstanceName -*/ -bool MDNSResponder::clsHost::_releaseInstanceName(void) -{ - return _releaseDomainName(m_pcInstanceName); -} - - -/* - SERVICE -*/ - -/* - MDNSResponder::clsHost::_allocService -*/ -MDNSResponder::clsHost::stcService* MDNSResponder::clsHost::_allocService(const char* p_pcName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port) -{ - stcService* pService = 0; - if (((!p_pcName) || - (MDNS_DOMAIN_LABEL_MAXLENGTH >= strlen(p_pcName))) && - (p_pcServiceType) && - (MDNS_SERVICE_NAME_LENGTH >= strlen(p_pcServiceType)) && - (p_pcProtocol) && - (MDNS_SERVICE_PROTOCOL_LENGTH >= strlen(p_pcProtocol)) && - (p_u16Port) && - (0 != ((pService = new stcService))) && - (pService->setName(p_pcName ? : (m_pcInstanceName ? : m_pcHostName))) && - (pService->setServiceType(p_pcServiceType)) && - (pService->setProtocol(p_pcProtocol))) - { - pService->m_bAutoName = (0 == p_pcName); - pService->m_u16Port = p_u16Port; - - // Add to list (or start list) - pService->m_pNext = m_pServices; - m_pServices = pService; - } - return pService; -} - -/* - MDNSResponder::clsHost::_releaseService -*/ -bool MDNSResponder::clsHost::_releaseService(MDNSResponder::clsHost::stcService* p_pService) -{ - bool bResult = false; - - if (p_pService) - { - stcService* pPred = m_pServices; - while ((pPred) && - (pPred->m_pNext != p_pService)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pService->m_pNext; - delete p_pService; - bResult = true; - } - else // No predecesor - { - if (m_pServices == p_pService) - { - m_pServices = p_pService->m_pNext; - delete p_pService; - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseService: INVALID service!"), _DH(p_pService));); - } - } - } - return bResult; -} - - -/* - SERVICE TXT -*/ - -/* - MDNSResponder::clsHost::_allocServiceTxt -*/ -MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_allocServiceTxt(MDNSResponder::clsHost::stcService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp) -{ - stcServiceTxt* pTxt = 0; - - if ((p_pService) && - (p_pcKey) && - (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() + - 1 + // Length byte - (p_pcKey ? strlen(p_pcKey) : 0) + - 1 + // '=' - (p_pcValue ? strlen(p_pcValue) : 0)))) - { - - pTxt = new stcServiceTxt; - if (pTxt) - { - size_t stLength = (p_pcKey ? strlen(p_pcKey) : 0); - pTxt->m_pcKey = new char[stLength + 1]; - if (pTxt->m_pcKey) - { - strncpy(pTxt->m_pcKey, p_pcKey, stLength); pTxt->m_pcKey[stLength] = 0; - } - - if (p_pcValue) - { - stLength = (p_pcValue ? strlen(p_pcValue) : 0); - pTxt->m_pcValue = new char[stLength + 1]; - if (pTxt->m_pcValue) - { - strncpy(pTxt->m_pcValue, p_pcValue, stLength); pTxt->m_pcValue[stLength] = 0; - } - } - pTxt->m_bTemp = p_bTemp; - - // Add to list (or start list) - p_pService->m_Txts.add(pTxt); - } - } - return pTxt; -} - -/* - MDNSResponder::clsHost::_releaseServiceTxt -*/ -bool MDNSResponder::clsHost::_releaseServiceTxt(MDNSResponder::clsHost::stcService* p_pService, - MDNSResponder::clsHost::stcServiceTxt* p_pTxt) -{ - return ((p_pService) && - (p_pTxt) && - (p_pService->m_Txts.remove(p_pTxt))); -} - -/* - MDNSResponder::clsHost::_updateServiceTxt -*/ -MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_updateServiceTxt(MDNSResponder::clsHost::stcService* p_pService, - MDNSResponder::clsHost::stcServiceTxt* p_pTxt, - const char* p_pcValue, - bool p_bTemp) -{ - if ((p_pService) && - (p_pTxt) && - (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() - - (p_pTxt->m_pcValue ? strlen(p_pTxt->m_pcValue) : 0) + - (p_pcValue ? strlen(p_pcValue) : 0)))) - { - p_pTxt->update(p_pcValue); - p_pTxt->m_bTemp = p_bTemp; - } - return p_pTxt; -} - -/* - MDNSResponder::clsHost::_findServiceTxt -*/ -MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_findServiceTxt(MDNSResponder::clsHost::stcService* p_pService, - const char* p_pcKey) -{ - return (p_pService ? p_pService->m_Txts.find(p_pcKey) : 0); -} - -/* - MDNSResponder::clsHost::_addServiceTxt -*/ -MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_addServiceTxt(MDNSResponder::clsHost::stcService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp) -{ - stcServiceTxt* pResult = 0; - - if ((p_pService) && - (p_pcKey) && - (strlen(p_pcKey))) - { - - stcServiceTxt* pTxt = p_pService->m_Txts.find(p_pcKey); - if (pTxt) - { - pResult = _updateServiceTxt(p_pService, pTxt, p_pcValue, p_bTemp); - } - else - { - pResult = _allocServiceTxt(p_pService, p_pcKey, p_pcValue, p_bTemp); - } - } - return pResult; -} - -/* - MDNSResponder::clsHost::_answerKeyValue - / - MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::_answerKeyValue(const MDNSResponder::clsHost::stcQuery p_pQuery, - const uint32_t p_u32AnswerIndex) - { - stcQuery::stcAnswer* pSQAnswer = (p_pQuery ? p_pQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcTxts (if not already done) - return (pSQAnswer) ? pSQAnswer->m_Txts.m_pTxts : 0; - }*/ - -/* - MDNSResponder::clsHost::_collectServiceTxts -*/ -bool MDNSResponder::clsHost::_collectServiceTxts(MDNSResponder::clsHost::stcService& p_rService) -{ - if (m_fnServiceTxtCallback) - { - //m_fnServiceTxtCallback(*this, p_pService); - } - if (p_rService.m_fnTxtCallback) - { - //p_pService->m_fnTxtCallback(*this, p_pService); - } - return true; -} - -/* - MDNSResponder::clsHost::_releaseTempServiceTxts -*/ -bool MDNSResponder::clsHost::_releaseTempServiceTxts(MDNSResponder::clsHost::stcService& p_rService) -{ - return (p_rService.m_Txts.removeTempTxts()); -} - - -/* - QUERIES -*/ - -/* - MDNSResponder::_allocQuery -*/ -MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::_allocQuery(MDNSResponder::clsHost::stcQuery::enuQueryType p_QueryType) -{ - stcQuery* pQuery = new stcQuery(p_QueryType); - if (pQuery) - { - // Link to query list - pQuery->m_pNext = m_pQueries; - m_pQueries = pQuery; - } - return m_pQueries; -} - -/* - MDNSResponder:clsHost:::_removeQuery -*/ -bool MDNSResponder::clsHost::_removeQuery(MDNSResponder::clsHost::stcQuery* p_pQuery) -{ - bool bResult = false; - - if (p_pQuery) - { - stcQuery* pPred = m_pQueries; - while ((pPred) && - (pPred->m_pNext != p_pQuery)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pQuery->m_pNext; - delete p_pQuery; - bResult = true; - } - else // No predecesor - { - if (m_pQueries == p_pQuery) - { - m_pQueries = p_pQuery->m_pNext; - delete p_pQuery; - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseQuery: INVALID query!"), _DH());); - } - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::_removeLegacyQuery -*/ -bool MDNSResponder::clsHost::_removeLegacyQuery(void) -{ - stcQuery* pLegacyQuery = 0; - return (((pLegacyQuery = _findLegacyQuery())) - ? _removeQuery(pLegacyQuery) - : false); -} - -/* - MDNSResponder::clsHost::_findLegacyQuery -*/ -MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::_findLegacyQuery(void) -{ - stcQuery* pLegacyQuery = m_pQueries; - while (pLegacyQuery) - { - if (pLegacyQuery->m_bLegacyQuery) - { - break; - } - pLegacyQuery = pLegacyQuery->m_pNext; - } - return pLegacyQuery; -} - -/* - MDNSResponder::clsHost::_releaseQueries -*/ -bool MDNSResponder::clsHost::_releaseQueries(void) -{ - while (m_pQueries) - { - stcQuery* pNext = m_pQueries->m_pNext; - delete m_pQueries; - m_pQueries = pNext; - } - return true; -} - -/* - MDNSResponder::clsHost::_findNextQueryByDomain -*/ -MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::_findNextQueryByDomain(const MDNSResponder::clsHost::stcRRDomain& p_Domain, - const MDNSResponder::clsHost::stcQuery::enuQueryType p_QueryType, - const stcQuery* p_pPrevQuery) -{ - stcQuery* pMatchingQuery = 0; - - stcQuery* pQuery = (p_pPrevQuery ? p_pPrevQuery->m_pNext : m_pQueries); - while (pQuery) - { - if (((stcQuery::enuQueryType::None == p_QueryType) || - (pQuery->m_QueryType == p_QueryType)) && - (p_Domain == pQuery->m_Domain)) - { - - pMatchingQuery = pQuery; - break; - } - pQuery = pQuery->m_pNext; - } - return pMatchingQuery; -} - -/* - MDNSResponder::clsHost::_installDomainQuery -*/ -MDNSResponder::clsHost::stcQuery* MDNSResponder::clsHost::_installDomainQuery(MDNSResponder::clsHost::stcRRDomain& p_Domain, - MDNSResponder::clsHost::stcQuery::enuQueryType p_QueryType, - MDNSResponder::clsHost::QueryCallbackFn p_fnCallback) -{ - stcQuery* pQuery = 0; - - if ((p_fnCallback) && - ((pQuery = _allocQuery(p_QueryType)))) - { - pQuery->m_Domain = p_Domain; - pQuery->m_fnCallback = p_fnCallback; - pQuery->m_bLegacyQuery = false; - - if (_sendMDNSQuery(*pQuery)) - { - pQuery->m_u8SentCount = 1; - pQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); - } - else - { - _removeQuery(pQuery); - } - } - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("%s _installDomainQuery: %s for "), (pQuery ? "Succeeded" : "FAILED"), _DH()); - _printRRDomain(p_Domain); - DEBUG_OUTPUT.println(); - ); - DEBUG_EX_ERR( - if (!pQuery) -{ - DEBUG_OUTPUT.printf_P(PSTR("%s _installDomainQuery: FAILED for "), _DH()); - _printRRDomain(p_Domain); - DEBUG_OUTPUT.println(); - } - ); - return pQuery; -} - -/* - MDNSResponder::clsHost::_hasQueriesWaitingForAnswers -*/ -bool MDNSResponder::clsHost::_hasQueriesWaitingForAnswers(void) const -{ - bool bOpenQueries = false; - - for (stcQuery* pQuery = m_pQueries; pQuery; pQuery = pQuery->m_pNext) - { - if (pQuery->m_bAwaitingAnswers) - { - bOpenQueries = true; - break; - } - } - return bOpenQueries; -} - -/* - MDNSResponder::clsHost::_executeQueryCallback -*/ -bool MDNSResponder::clsHost::_executeQueryCallback(const stcQuery& p_Query, - const stcQuery::stcAnswer& p_Answer, - typeQueryAnswerType p_QueryAnswerTypeFlags, - bool p_bSetContent) -{ - if (p_Query.m_fnCallback) - { - p_Query.m_fnCallback(*this, p_Query, p_Answer, p_QueryAnswerTypeFlags, p_bSetContent); - } - return true; -} - - - -} // namespace MDNSImplementation - -} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp deleted file mode 100755 index 4a5ff6f39d..0000000000 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Host.hpp +++ /dev/null @@ -1,1177 +0,0 @@ -/* - LEAmDNS2_Host.hpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -/** - clsHost & clsHostList -*/ -class clsHost -{ -public: - - // File: ..._Host_Structs - /** - typeIPProtocolType & enuIPProtocolType - */ - using typeIPProtocolType = uint8_t; - enum class enuIPProtocolType : typeIPProtocolType - { -#ifdef MDNS_IPV4_SUPPORT - V4 = 0x01, -#endif -#ifdef MDNS_IPV6_SUPPORT - V6 = 0x02, -#endif - }; - - /** - typeNetIfState & enuNetIfState - */ - using typeNetIfState = uint8_t; - enum class enuNetIfState : typeNetIfState - { - None = 0x00, - - IsUp = 0x01, - UpMask = (IsUp), - - LinkIsUp = 0x02, - LinkMask = (LinkIsUp), - - IPv4 = 0x04, - IPv6 = 0x08, - IPMask = (IPv4 | IPv6), - }; - - /** - stcServiceTxt - */ - struct stcServiceTxt - { - stcServiceTxt* m_pNext; - char* m_pcKey; - char* m_pcValue; - bool m_bTemp; - - stcServiceTxt(const char* p_pcKey = 0, - const char* p_pcValue = 0, - bool p_bTemp = false); - stcServiceTxt(const stcServiceTxt& p_Other); - ~stcServiceTxt(void); - - stcServiceTxt& operator=(const stcServiceTxt& p_Other); - bool clear(void); - - char* allocKey(size_t p_stLength); - bool setKey(const char* p_pcKey, - size_t p_stLength); - bool setKey(const char* p_pcKey); - bool releaseKey(void); - - char* allocValue(size_t p_stLength); - bool setValue(const char* p_pcValue, - size_t p_stLength); - bool setValue(const char* p_pcValue); - bool releaseValue(void); - - bool set(const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp = false); - - bool update(const char* p_pcValue); - - size_t length(void) const; - }; - - /** - stcServiceTxts - */ - struct stcServiceTxts - { - stcServiceTxt* m_pTxts; - char* m_pcCache; - - stcServiceTxts(void); - stcServiceTxts(const stcServiceTxts& p_Other); - ~stcServiceTxts(void); - - stcServiceTxts& operator=(const stcServiceTxts& p_Other); - - bool clear(void); - bool clearCache(void); - - bool add(stcServiceTxt* p_pTxt); - bool remove(stcServiceTxt* p_pTxt); - - bool removeTempTxts(void); - - stcServiceTxt* find(const char* p_pcKey); - const stcServiceTxt* find(const char* p_pcKey) const; - stcServiceTxt* find(const stcServiceTxt* p_pTxt); - - uint16_t length(void) const; - - size_t c_strLength(void) const; - bool c_str(char* p_pcBuffer); - const char* c_str(void) const; - - size_t bufferLength(void) const; - bool buffer(char* p_pcBuffer); - - bool compare(const stcServiceTxts& p_Other) const; - bool operator==(const stcServiceTxts& p_Other) const; - bool operator!=(const stcServiceTxts& p_Other) const; - }; - - /** - typeProbingStatus & enuProbingStatus - */ - using typeProbingStatus = uint8_t; - enum class enuProbingStatus : typeProbingStatus - { - WaitingForData, - ReadyToStart, - InProgress, - Done - }; - - /** - stcProbeInformation_Base - */ - struct stcProbeInformation_Base - { - enuProbingStatus m_ProbingStatus; - uint8_t m_u8SentCount; // Used for probes and announcements - esp8266::polledTimeout::oneShot m_Timeout; // Used for probes and announcements - bool m_bConflict; - bool m_bTiebreakNeeded; - - stcProbeInformation_Base(void); - - bool clear(void); // No 'virtual' needed, no polymorphic use (save 4 bytes) - }; - - /** - HostProbeResultCallbackFn - Callback function for host domain probe results - */ - using HostProbeResultCallbackFn = std::function; - /** - MDNSServiceProbeResultCallbackFn - Callback function for service domain probe results - */ - struct stcService; - using ServiceProbeResultCallbackFn = std::function; - - /** - stcProbeInformation_Host - */ - struct stcProbeInformation_Host : public stcProbeInformation_Base - { - HostProbeResultCallbackFn m_fnProbeResultCallback; - - stcProbeInformation_Host(void); - - bool clear(bool p_bClearUserdata = false); - }; - - /** - stcProbeInformation_Service - */ - struct stcProbeInformation_Service : public stcProbeInformation_Base - { - ServiceProbeResultCallbackFn m_fnProbeResultCallback; - - stcProbeInformation_Service(void); - - bool clear(bool p_bClearUserdata = false); - }; - - /** - DynamicServiceTxtCallbackFn - Callback function for dynamic MDNS TXT items - */ - struct stcService; - using DynamicServiceTxtCallbackFn = std::function; - - /** - stcService - */ - struct stcService - { - stcService* m_pNext; - char* m_pcName; - bool m_bAutoName; // Name was set automatically to hostname (if no name was supplied) - char* m_pcServiceType; - char* m_pcProtocol; - uint16_t m_u16Port; - uint32_t m_u32ReplyMask; - stcServiceTxts m_Txts; - DynamicServiceTxtCallbackFn m_fnTxtCallback; - stcProbeInformation_Service m_ProbeInformation; - - stcService(const char* p_pcName = 0, - const char* p_pcServiceType = 0, - const char* p_pcProtocol = 0); - ~stcService(void); - - bool setName(const char* p_pcName); - bool releaseName(void); - - bool setServiceType(const char* p_pcService); - bool releaseServiceType(void); - - bool setProtocol(const char* p_pcProtocol); - bool releaseProtocol(void); - - bool probeStatus(void) const; - }; - - /** - typeContentFlag & enuContentFlag - */ - using typeContentFlag = uint16_t; - enum class enuContentFlag : typeContentFlag - { - // Host - A = 0x0001, - PTR_IPv4 = 0x0002, - PTR_IPv6 = 0x0004, - AAAA = 0x0008, - // Service - PTR_TYPE = 0x0010, - PTR_NAME = 0x0020, - TXT = 0x0040, - SRV = 0x0080, - // DNSSEC - NSEC = 0x0100, - - PTR = (PTR_IPv4 | PTR_IPv6 | PTR_TYPE | PTR_NAME) - }; - - /** - stcMsgHeader - */ - struct stcMsgHeader - { - uint16_t m_u16ID; // Identifier - bool m_1bQR : 1; // Query/Response flag - uint8_t m_4bOpcode : 4; // Operation code - bool m_1bAA : 1; // Authoritative Answer flag - bool m_1bTC : 1; // Truncation flag - bool m_1bRD : 1; // Recursion desired - bool m_1bRA : 1; // Recursion available - uint8_t m_3bZ : 3; // Zero - uint8_t m_4bRCode : 4; // Response code - uint16_t m_u16QDCount; // Question count - uint16_t m_u16ANCount; // Answer count - uint16_t m_u16NSCount; // Authority Record count - uint16_t m_u16ARCount; // Additional Record count - - stcMsgHeader(uint16_t p_u16ID = 0, - bool p_bQR = false, - uint8_t p_u8Opcode = 0, - bool p_bAA = false, - bool p_bTC = false, - bool p_bRD = false, - bool p_bRA = false, - uint8_t p_u8RCode = 0, - uint16_t p_u16QDCount = 0, - uint16_t p_u16ANCount = 0, - uint16_t p_u16NSCount = 0, - uint16_t p_u16ARCount = 0); - }; - - /** - stcRRDomain - */ - struct stcRRDomain - { - char m_acName[MDNS_DOMAIN_MAXLENGTH]; // Encoded domain name - uint16_t m_u16NameLength; // Length (incl. '\0') - char* m_pcDecodedName; - - stcRRDomain(void); - stcRRDomain(const stcRRDomain& p_Other); - ~stcRRDomain(void); - - stcRRDomain& operator=(const stcRRDomain& p_Other); - - bool clear(void); - bool clearNameCache(void); - - bool addLabel(const char* p_pcLabel, - bool p_bPrependUnderline = false); - - bool compare(const stcRRDomain& p_Other) const; - bool operator==(const stcRRDomain& p_Other) const; - bool operator!=(const stcRRDomain& p_Other) const; - bool operator>(const stcRRDomain& p_Other) const; - - size_t c_strLength(void) const; - bool c_str(char* p_pcBuffer) const; - const char* c_str(void) const; - }; - - /** - stcRRAttributes - */ - struct stcRRAttributes - { - uint16_t m_u16Type; // Type - uint16_t m_u16Class; // Class, nearly always 'IN' - - stcRRAttributes(uint16_t p_u16Type = 0, - uint16_t p_u16Class = 1 /*DNS_RRCLASS_IN Internet*/); - stcRRAttributes(const stcRRAttributes& p_Other); - - stcRRAttributes& operator=(const stcRRAttributes& p_Other); - }; - - /** - stcRRHeader - */ - struct stcRRHeader - { - stcRRDomain m_Domain; - stcRRAttributes m_Attributes; - - stcRRHeader(void); - stcRRHeader(const stcRRHeader& p_Other); - - stcRRHeader& operator=(const stcRRHeader& p_Other); - - bool clear(void); - }; - - /** - stcRRQuestion - */ - struct stcRRQuestion - { - stcRRQuestion* m_pNext; - stcRRHeader m_Header; - bool m_bUnicast; // Unicast reply requested - - stcRRQuestion(void); - }; - - /** - stcNSECBitmap - */ - struct stcNSECBitmap - { - uint8_t m_au8BitmapData[6]; // 6 bytes data - - stcNSECBitmap(void); - - bool clear(void); - uint16_t length(void) const; - bool setBit(uint16_t p_u16Bit); - bool getBit(uint16_t p_u16Bit) const; - }; - - /** - typeAnswerType & enuAnswerType - */ - using typeAnswerType = uint8_t; - enum class enuAnswerType : typeAnswerType - { - A, - PTR, - TXT, - AAAA, - SRV, - //NSEC, - Generic - }; - - /** - stcRRAnswer - */ - struct stcRRAnswer - { - stcRRAnswer* m_pNext; - const enuAnswerType m_AnswerType; - stcRRHeader m_Header; - bool m_bCacheFlush; // Cache flush command bit - uint32_t m_u32TTL; // Validity time in seconds - - virtual ~stcRRAnswer(void); - - enuAnswerType answerType(void) const; - - bool clear(void); - - protected: - stcRRAnswer(enuAnswerType p_AnswerType, - const stcRRHeader& p_Header, - uint32_t p_u32TTL); - }; - -#ifdef MDNS_IPV4_SUPPORT - /** - stcRRAnswerA - */ - struct stcRRAnswerA : public stcRRAnswer - { - IPAddress m_IPAddress; - - stcRRAnswerA(const stcRRHeader& p_Header, - uint32_t p_u32TTL); - ~stcRRAnswerA(void); - - bool clear(void); - }; -#endif - - /** - stcRRAnswerPTR - */ - struct stcRRAnswerPTR : public stcRRAnswer - { - stcRRDomain m_PTRDomain; - - stcRRAnswerPTR(const stcRRHeader& p_Header, - uint32_t p_u32TTL); - ~stcRRAnswerPTR(void); - - bool clear(void); - }; - - /** - stcRRAnswerTXT - */ - struct stcRRAnswerTXT : public stcRRAnswer - { - stcServiceTxts m_Txts; - - stcRRAnswerTXT(const stcRRHeader& p_Header, - uint32_t p_u32TTL); - ~stcRRAnswerTXT(void); - - bool clear(void); - }; - -#ifdef MDNS_IPV6_SUPPORT - /** - stcRRAnswerAAAA - */ - struct stcRRAnswerAAAA : public stcRRAnswer - { - IPAddress m_IPAddress; - - stcRRAnswerAAAA(const stcRRHeader& p_Header, - uint32_t p_u32TTL); - ~stcRRAnswerAAAA(void); - - bool clear(void); - }; -#endif - - /** - stcRRAnswerSRV - */ - struct stcRRAnswerSRV : public stcRRAnswer - { - uint16_t m_u16Priority; - uint16_t m_u16Weight; - uint16_t m_u16Port; - stcRRDomain m_SRVDomain; - - stcRRAnswerSRV(const stcRRHeader& p_Header, - uint32_t p_u32TTL); - ~stcRRAnswerSRV(void); - - bool clear(void); - }; - - /** - stcRRAnswerGeneric - */ - struct stcRRAnswerGeneric : public stcRRAnswer - { - uint16_t m_u16RDLength; // Length of variable answer - uint8_t* m_pu8RDData; // Offset of start of variable answer in packet - - stcRRAnswerGeneric(const stcRRHeader& p_Header, - uint32_t p_u32TTL); - ~stcRRAnswerGeneric(void); - - bool clear(void); - }; - - - /** - stcSendParameter - */ - struct stcSendParameter - { - protected: - /** - stcDomainCacheItem - */ - struct stcDomainCacheItem - { - stcDomainCacheItem* m_pNext; - const void* m_pHostNameOrService; // Opaque id for host or service domain (pointer) - bool m_bAdditionalData; // Opaque flag for special info (service domain included) - uint16_t m_u16Offset; // Offset in UDP output buffer - - stcDomainCacheItem(const void* p_pHostNameOrService, - bool p_bAdditionalData, - uint32_t p_u16Offset); - }; - - public: - /** - typeResponseType & enuResponseType - */ - using typeResponseType = uint8_t; - enum class enuResponseType : typeResponseType - { - None, - Response, - Unsolicited - }; - - uint16_t m_u16ID; // Query ID (used only in lagacy queries) - stcRRQuestion* m_pQuestions; // A list of queries - uint32_t m_u32HostReplyMask; // Flags for reply components/answers - bool m_bLegacyQuery; // Flag: Legacy query - enuResponseType m_Response; // Enum: Response to a query - bool m_bAuthorative; // Flag: Authorative (owner) response - bool m_bCacheFlush; // Flag: Clients should flush their caches - bool m_bUnicast; // Flag: Unicast response - bool m_bUnannounce; // Flag: Unannounce service - - // Temp content; created while processing _prepareMessage - uint16_t m_u16Offset; // Current offset in UDP write buffer (mainly for domain cache) - stcDomainCacheItem* m_pDomainCacheItems; // Cached host and service domains - - stcSendParameter(void); - ~stcSendParameter(void); - - bool clear(void); - bool flushQuestions(void); - bool flushDomainCache(void); - bool flushTempContent(void); - - bool shiftOffset(uint16_t p_u16Shift); - - bool addDomainCacheItem(const void* p_pHostNameOrService, - bool p_bAdditionalData, - uint16_t p_u16Offset); - uint16_t findCachedDomainOffset(const void* p_pHostNameOrService, - bool p_bAdditionalData) const; - }; - - - // QUERIES & ANSWERS - /** - typeQueryAnswerType & enuQueryAnswerType - */ - using typeQueryAnswerType = uint8_t; - enum class enuQueryAnswerType : typeQueryAnswerType - { - Unknown = 0x00, - ServiceDomain = 0x01, // Service domain - HostDomain = 0x02, // Host domain - Port = 0x04, // Port - Txts = 0x08, // TXT items -#ifdef MDNS_IPV4_SUPPORT - IPv4Address = 0x10, // IPv4 address -#endif -#ifdef MDNS_IPV6_SUPPORT - IPv6Address = 0x20, // IPv6 address -#endif - }; - - /** - stcQuery - */ - struct stcQuery - { - /** - stcAnswer - */ - struct stcAnswer - { - /** - stcTTL - */ - struct stcTTL - { - /** - typeTimeoutLevel & enuTimeoutLevel - */ - using typeTimeoutLevel = uint8_t; - enum class enuTimeoutLevel : typeTimeoutLevel - { - None = 0, - Base = 80, - Interval = 5, - Final = 100 - }; - - uint32_t m_u32TTL; - esp8266::polledTimeout::oneShot m_TTLTimeout; - typeTimeoutLevel m_TimeoutLevel; - - stcTTL(void); - bool set(uint32_t p_u32TTL); - - bool flagged(void) const; - bool restart(void); - - bool prepareDeletion(void); - bool finalTimeoutLevel(void) const; - - unsigned long timeout(void) const; - }; - /** - stcIPAddress - */ - struct stcIPAddress - { - stcIPAddress* m_pNext; - IPAddress m_IPAddress; - stcTTL m_TTL; - - stcIPAddress(IPAddress p_IPAddress, - uint32_t p_u32TTL = 0); - }; - - stcAnswer* m_pNext; - // The service domain is the first 'answer' (from PTR answer, using service and protocol) to be set - // Defines the key for additional answer, like host domain, etc. - stcRRDomain m_ServiceDomain; // 1. level answer (PTR), eg. MyESP._http._tcp.local - stcTTL m_TTLServiceDomain; - stcRRDomain m_HostDomain; // 2. level answer (SRV, using service domain), eg. esp8266.local - uint16_t m_u16Port; // 2. level answer (SRV, using service domain), eg. 5000 - stcTTL m_TTLHostDomainAndPort; - stcServiceTxts m_Txts; // 2. level answer (TXT, using service domain), eg. c#=1 - stcTTL m_TTLTxts; -#ifdef MDNS_IPV4_SUPPORT - stcIPAddress* m_pIPv4Addresses; // 3. level answer (A, using host domain), eg. 123.456.789.012 -#endif -#ifdef MDNS_IPV6_SUPPORT - stcIPAddress* m_pIPv6Addresses; // 3. level answer (AAAA, using host domain), eg. 1234::09 -#endif - typeQueryAnswerType m_QueryAnswerFlags; // enuQueryAnswerType - - stcAnswer(void); - ~stcAnswer(void); - - bool clear(void); - -#ifdef MDNS_IPV4_SUPPORT - bool releaseIPv4Addresses(void); - bool addIPv4Address(stcIPAddress* p_pIPAddress); - bool removeIPv4Address(stcIPAddress* p_pIPAddress); - const stcIPAddress* findIPv4Address(const IPAddress& p_IPAddress) const; - stcIPAddress* findIPv4Address(const IPAddress& p_IPAddress); - uint32_t IPv4AddressCount(void) const; - const stcIPAddress* IPv4AddressAtIndex(uint32_t p_u32Index) const; - stcIPAddress* IPv4AddressAtIndex(uint32_t p_u32Index); -#endif -#ifdef MDNS_IPV6_SUPPORT - bool releaseIPv6Addresses(void); - bool addIPv6Address(stcIPAddress* p_pIPAddress); - bool removeIPv6Address(stcIPAddress* p_pIPAddress); - const stcIPAddress* findIPv6Address(const IPAddress& p_IPAddress) const; - stcIPAddress* findIPv6Address(const IPAddress& p_IPAddress); - uint32_t IPv6AddressCount(void) const; - const stcIPAddress* IPv6AddressAtIndex(uint32_t p_u32Index) const; - stcIPAddress* IPv6AddressAtIndex(uint32_t p_u32Index); -#endif - }; //stcAnswer - - /** - typeQueryType & enuQueryType - */ - using typeQueryType = uint8_t; - enum class enuQueryType : typeQueryType - { - None, - Service, - Host - }; - using _QueryCallbackFn = std::function; // true: Answer component set, false: component deleted - - stcQuery* m_pNext; - enuQueryType m_QueryType; - stcRRDomain m_Domain; // Type:Service -> _http._tcp.local; Type:Host -> esp8266.local - _QueryCallbackFn m_fnCallback; - bool m_bLegacyQuery; - uint8_t m_u8SentCount; - esp8266::polledTimeout::oneShot m_ResendTimeout; - bool m_bAwaitingAnswers; - stcAnswer* m_pAnswers; - - stcQuery(const enuQueryType p_QueryType); - ~stcQuery(void); - - bool clear(void); - - uint32_t answerCount(void) const; - const stcAnswer* answerAtIndex(uint32_t p_u32Index) const; - stcAnswer* answerAtIndex(uint32_t p_u32Index); - uint32_t indexOfAnswer(const stcAnswer* p_pAnswer) const; - - bool addAnswer(stcAnswer* p_pAnswer); - bool removeAnswer(stcAnswer* p_pAnswer); - - stcAnswer* findAnswerForServiceDomain(const stcRRDomain& p_ServiceDomain); - stcAnswer* findAnswerForHostDomain(const stcRRDomain& p_HostDomain); - }; - /** - QueryCallbackFn - - Callback function for received answers for dynamic queries - */ - using QueryCallbackFn = stcQuery::_QueryCallbackFn; - -public: - clsHost(netif& p_rNetIf, - UdpContext& p_rUDPContext); - ~clsHost(void); - - bool init(void); - - // HOST - bool setHostName(const char* p_pcHostName); - const char* hostName(void) const; - - bool setHostProbeResultCallback(HostProbeResultCallbackFn p_fnCallback); - - // Returns 'true' is host domain probing is done - bool probeStatus(void) const; - - // SERVICE - bool setInstanceName(const char* p_pcInstanceName); - const char* instanceName(void) const; - - stcService* addService(const char* p_pcInstanceName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port); - bool removeService(stcService* p_pMDNSService); - - const stcService* findService(const char* p_pcInstanceName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port = 0) const; - stcService* findService(const char* p_pcInstanceName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port = 0); - bool validateService(const stcService* p_pService) const; - - bool setServiceName(stcService* p_pMDNSService, - const char* p_pcInstanceName); - const char* serviceName(const stcService* p_pMDNSService) const; - const char* serviceType(const stcService* p_pMDNSService) const; - const char* serviceProtocol(const stcService* p_pMDNSService) const; - uint16_t servicePort(const stcService* p_pMDNSService) const; - - // Set a service specific probe result callcack - bool setServiceProbeResultCallback(stcService* p_pMDNSService, - ServiceProbeResultCallbackFn p_fnCallback); - - bool serviceProbeStatus(const stcService* p_pMDNSService) const; - - // SERVICE TXT - // Add a (static) MDNS TXT item ('key' = 'value') to the service - stcServiceTxt* addServiceTxt(stcService* p_pMDNSService, - const char* p_pcKey, - const char* p_pcValue); - bool removeServiceTxt(stcService* p_pMDNSService, - stcServiceTxt* p_pTxt); - const stcServiceTxt* findServiceTxt(stcService* p_pMDNSService, - const char* p_pcKey) const; - stcServiceTxt* findServiceTxt(stcService* p_pMDNSService, - const char* p_pcKey); - - bool setDynamicServiceTxtCallback(DynamicServiceTxtCallbackFn p_fnCallback); - bool setDynamicServiceTxtCallback(stcService* p_pMDNSService, - DynamicServiceTxtCallbackFn p_fnCallback); - - // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service - // Dynamic TXT items are removed right after one-time use. So they need to be added - // every time the value s needed (via callback). - stcServiceTxt* addDynamicServiceTxt(stcService* p_pMDNSService, - const char* p_pcKey, - const char* p_pcValue); - - // QUERIES - - // - STATIC - // Perform a (static) service/host query. The function returns after p_u16Timeout milliseconds - // The answers (the number of received answers is returned) can be retrieved by calling - // - answerHostName (or hostname) - // - answerIP (or IP) - // - answerPort (or port) - uint32_t queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - uint32_t queryHost(const char* p_pcHostName, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - bool removeQuery(void); - bool hasQuery(void); - stcQuery* getQuery(void); - - // - DYNAMIC - // Install a dynamic service/host query. For every received answer (part) the given callback - // function is called. The query will be updated every time, the TTL for an answer - // has timed-out. - // The answers can also be retrieved by calling - // - answerCount service/host (for host queries, this should never be >1) - // - answerServiceDomain service - // - hasAnswerHostDomain/answerHostDomain service/host - // - hasAnswerIPv4Address/answerIPv4Address service/host - // - hasAnswerIPv6Address/answerIPv6Address service/host - // - hasAnswerPort/answerPort service - // - hasAnswerTxts/answerTxts service - stcQuery* installServiceQuery(const char* p_pcServiceType, - const char* p_pcProtocol, - QueryCallbackFn p_fnCallback); - stcQuery* installHostQuery(const char* p_pcHostName, - QueryCallbackFn p_fnCallback); - // Remove a dynamic service query - bool removeQuery(stcQuery* p_pMDNSQuery); - - - - - - // PROCESSING - bool processUDPInput(void); - bool update(void); - - bool announce(bool p_bAnnounce, - bool p_bIncludeServices); - bool announceService(stcService* p_pService, - bool p_bAnnounce = true); - - bool restart(void); - -protected: - // File: ..._Host - bool _close(void); - - // NETIF - typeNetIfState _getNetIfState(void) const; - bool _checkNetIfState(void); - - // DOMAIN NAMES - bool _allocDomainName(const char* p_pcNewDomainName, - char*& p_rpcDomainName); - bool _releaseDomainName(char*& p_rpcDomainName); - bool _allocHostName(const char* p_pcHostName); - bool _releaseHostName(void); - bool _allocInstanceName(const char* p_pcInstanceName); - bool _releaseInstanceName(void); - - // SERVICE - stcService* _allocService(const char* p_pcName, - const char* p_pcServiceType, - const char* p_pcProtocol, - uint16_t p_u16Port); - bool _releaseService(stcService* p_pService); - - // SERVICE TXT - stcServiceTxt* _allocServiceTxt(stcService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp); - bool _releaseServiceTxt(stcService* p_pService, - stcServiceTxt* p_pTxt); - stcServiceTxt* _updateServiceTxt(stcService* p_pService, - stcServiceTxt* p_pTxt, - const char* p_pcValue, - bool p_bTemp); - stcServiceTxt* _findServiceTxt(stcService* p_pService, - const char* p_pcKey); - stcServiceTxt* _addServiceTxt(stcService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp); - stcServiceTxt* _answerKeyValue(const stcQuery p_pQuery, - const uint32_t p_u32AnswerIndex); - bool _collectServiceTxts(stcService& p_rService); - bool _releaseTempServiceTxts(stcService& p_rService); - - // QUERIES - stcQuery* _allocQuery(stcQuery::enuQueryType p_QueryType); - bool _removeQuery(stcQuery* p_pQuery); - bool _removeLegacyQuery(void); - stcQuery* _findLegacyQuery(void); - bool _releaseQueries(void); - stcQuery* _findNextQueryByDomain(const stcRRDomain& p_Domain, - const stcQuery::enuQueryType p_QueryType, - const stcQuery* p_pPrevQuery); - stcQuery* _installDomainQuery(stcRRDomain& p_Domain, - stcQuery::enuQueryType p_QueryType, - QueryCallbackFn p_fnCallback); - bool _hasQueriesWaitingForAnswers(void) const; - bool _executeQueryCallback(const stcQuery& p_Query, - const stcQuery::stcAnswer& p_Answer, - typeQueryAnswerType p_QueryAnswerTypeFlags, - bool p_SetContent); - - - // File: ..._Host_Control - // RECEIVING - bool _parseMessage(void); - bool _parseQuery(const stcMsgHeader& p_Header); - - bool _parseResponse(const stcMsgHeader& p_Header); - bool _processAnswers(const stcRRAnswer* p_pPTRAnswers); - bool _processPTRAnswer(const stcRRAnswerPTR* p_pPTRAnswer, - bool& p_rbFoundNewKeyAnswer); - bool _processSRVAnswer(const stcRRAnswerSRV* p_pSRVAnswer, - bool& p_rbFoundNewKeyAnswer); - bool _processTXTAnswer(const stcRRAnswerTXT* p_pTXTAnswer); -#ifdef MDNS_IPV4_SUPPORT - bool _processAAnswer(const stcRRAnswerA* p_pAAnswer); -#endif -#ifdef MDNS_IPV6_SUPPORT - bool _processAAAAAnswer(const stcRRAnswerAAAA* p_pAAAAAnswer); -#endif - - // PROBING - bool _updateProbeStatus(void); - bool _resetProbeStatus(bool p_bRestart = true); - bool _hasProbesWaitingForAnswers(void) const; - bool _sendHostProbe(void); - bool _sendServiceProbe(stcService& p_rService); - bool _cancelProbingForHost(void); - bool _cancelProbingForService(stcService& p_rService); - bool _callHostProbeResultCallback(bool p_bResult); - bool _callServiceProbeResultCallback(stcService& p_rService, - bool p_bResult); - - // ANNOUNCE - bool _announce(bool p_bAnnounce, - bool p_bIncludeServices); - bool _announceService(stcService& p_pService, - bool p_bAnnounce = true); - - // QUERY CACHE - bool _checkQueryCache(void); - - uint32_t _replyMaskForHost(const stcRRHeader& p_RRHeader, - bool* p_pbFullNameMatch = 0) const; - uint32_t _replyMaskForService(const stcRRHeader& p_RRHeader, - const stcService& p_Service, - bool* p_pbFullNameMatch = 0) const; - - - // File: ..._Host_Transfer - // SENDING - bool _sendMDNSMessage(stcSendParameter& p_SendParameter); - bool _sendMDNSMessage_Multicast(stcSendParameter& p_rSendParameter, - uint8_t p_IPProtocolTypes); - bool _prepareMDNSMessage(stcSendParameter& p_SendParameter); - bool _addMDNSQueryRecord(stcSendParameter& p_rSendParameter, - const stcRRDomain& p_QueryDomain, - uint16_t p_u16QueryType); - bool _sendMDNSQuery(const stcQuery& p_Query, - stcQuery::stcAnswer* p_pKnownAnswers = 0); - bool _sendMDNSQuery(const stcRRDomain& p_QueryDomain, - uint16_t p_u16RecordType, - stcQuery::stcAnswer* p_pKnownAnswers = 0); - - IPAddress _getResponderIPAddress(enuIPProtocolType p_IPProtocolType) const; - - // RESOURCE RECORD - bool _readRRQuestion(stcRRQuestion& p_rQuestion); - bool _readRRAnswer(stcRRAnswer*& p_rpAnswer); -#ifdef MDNS_IPV4_SUPPORT - bool _readRRAnswerA(stcRRAnswerA& p_rRRAnswerA, - uint16_t p_u16RDLength); -#endif - bool _readRRAnswerPTR(stcRRAnswerPTR& p_rRRAnswerPTR, - uint16_t p_u16RDLength); - bool _readRRAnswerTXT(stcRRAnswerTXT& p_rRRAnswerTXT, - uint16_t p_u16RDLength); -#ifdef MDNS_IPV6_SUPPORT - bool _readRRAnswerAAAA(stcRRAnswerAAAA& p_rRRAnswerAAAA, - uint16_t p_u16RDLength); -#endif - bool _readRRAnswerSRV(stcRRAnswerSRV& p_rRRAnswerSRV, - uint16_t p_u16RDLength); - bool _readRRAnswerGeneric(stcRRAnswerGeneric& p_rRRAnswerGeneric, - uint16_t p_u16RDLength); - - bool _readRRHeader(stcRRHeader& p_rHeader); - bool _readRRDomain(stcRRDomain& p_rRRDomain); - bool _readRRDomain_Loop(stcRRDomain& p_rRRDomain, - uint8_t p_u8Depth); - bool _readRRAttributes(stcRRAttributes& p_rAttributes); - - // DOMAIN NAMES - bool _buildDomainForHost(const char* p_pcHostName, - stcRRDomain& p_rHostDomain) const; - bool _buildDomainForDNSSD(stcRRDomain& p_rDNSSDDomain) const; - bool _buildDomainForService(const stcService& p_Service, - bool p_bIncludeName, - stcRRDomain& p_rServiceDomain) const; - bool _buildDomainForService(const char* p_pcService, - const char* p_pcProtocol, - stcRRDomain& p_rServiceDomain) const; -#ifdef MDNS_IPV4_SUPPORT - bool _buildDomainForReverseIPv4(IPAddress p_IPv4Address, - stcRRDomain& p_rReverseIPv4Domain) const; -#endif -#ifdef MDNS_IPV6_SUPPORT - bool _buildDomainForReverseIPv6(IPAddress p_IPv4Address, - stcRRDomain& p_rReverseIPv6Domain) const; -#endif - - // UDP - bool _udpReadBuffer(unsigned char* p_pBuffer, - size_t p_stLength); - bool _udpRead8(uint8_t& p_ru8Value); - bool _udpRead16(uint16_t& p_ru16Value); - bool _udpRead32(uint32_t& p_ru32Value); - - bool _udpAppendBuffer(const unsigned char* p_pcBuffer, - size_t p_stLength); - bool _udpAppend8(uint8_t p_u8Value); - bool _udpAppend16(uint16_t p_u16Value); - bool _udpAppend32(uint32_t p_u32Value); - -#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER - bool _udpDump(bool p_bMovePointer = false); - bool _udpDump(unsigned p_uOffset, - unsigned p_uLength); -#endif - - // READ/WRITE MDNS STRUCTS - bool _readMDNSMsgHeader(stcMsgHeader& p_rMsgHeader); - - bool _write8(uint8_t p_u8Value, - stcSendParameter& p_rSendParameter); - bool _write16(uint16_t p_u16Value, - stcSendParameter& p_rSendParameter); - bool _write32(uint32_t p_u32Value, - stcSendParameter& p_rSendParameter); - - bool _writeMDNSMsgHeader(const stcMsgHeader& p_MsgHeader, - stcSendParameter& p_rSendParameter); - bool _writeMDNSRRAttributes(const stcRRAttributes& p_Attributes, - stcSendParameter& p_rSendParameter); - bool _writeMDNSRRDomain(const stcRRDomain& p_Domain, - stcSendParameter& p_rSendParameter); - bool _writeMDNSHostDomain(const char* m_pcHostName, - bool p_bPrependRDLength, - uint16_t p_u16AdditionalLength, - stcSendParameter& p_rSendParameter); - bool _writeMDNSServiceDomain(const stcService& p_Service, - bool p_bIncludeName, - bool p_bPrependRDLength, - uint16_t p_u16AdditionalLength, - stcSendParameter& p_rSendParameter); - - bool _writeMDNSQuestion(stcRRQuestion& p_Question, - stcSendParameter& p_rSendParameter); - -#ifdef MDNS_IPV4_SUPPORT - bool _writeMDNSAnswer_A(IPAddress p_IPAddress, - stcSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, - stcSendParameter& p_rSendParameter); -#endif - bool _writeMDNSAnswer_PTR_TYPE(stcService& p_rService, - stcSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_PTR_NAME(stcService& p_rService, - stcSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_TXT(stcService& p_rService, - stcSendParameter& p_rSendParameter); -#ifdef MDNS_IPV6_SUPPORT - bool _writeMDNSAnswer_AAAA(IPAddress p_IPAddress, - stcSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, - stcSendParameter& p_rSendParameter); -#endif - bool _writeMDNSAnswer_SRV(stcService& p_rService, - stcSendParameter& p_rSendParameter); - stcNSECBitmap* _createNSECBitmap(uint32_t p_u32NSECContent); - bool _writeMDNSNSECBitmap(const stcNSECBitmap& p_NSECBitmap, - stcSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_NSEC(uint32_t p_u32NSECContent, - stcSendParameter& p_rSendParameter); -#ifdef MDNS_IPV4_SUPPORT - bool _writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddress, - stcSendParameter& p_rSendParameter); -#endif -#ifdef MDNS_IPV6_SUPPORT - bool _writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddress, - stcSendParameter& p_rSendParameter); -#endif - bool _writeMDNSAnswer_NSEC(stcService& p_rService, - uint32_t p_u32NSECContent, - stcSendParameter& p_rSendParameter); - - - // File: ..._Host_Debug -#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER - const char* _DH(const stcService* p_pMDNSService = 0) const; - const char* _service2String(const stcService* p_pMDNSService) const; - - bool _printRRDomain(const stcRRDomain& p_rRRDomain) const; - bool _printRRAnswer(const stcRRAnswer& p_RRAnswer) const; - const char* _RRType2Name(uint16_t p_u16RRType) const; - const char* _RRClass2String(uint16_t p_u16RRClass, - bool p_bIsQuery) const; - const char* _replyFlags2String(uint32_t p_u32ReplyFlags) const; - const char* _NSECBitmap2String(const stcNSECBitmap* p_pNSECBitmap) const; -#endif - - -public: - netif& m_rNetIf; - typeNetIfState m_NetIfState; - UdpContext& m_rUDPContext; - - char* m_pcHostName; - char* m_pcInstanceName; - stcService* m_pServices; - stcQuery* m_pQueries; - DynamicServiceTxtCallbackFn m_fnServiceTxtCallback; - stcProbeInformation_Host m_HostProbeInformation; -}; -using clsHostList = std::list; - diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp deleted file mode 100755 index 7121abcfca..0000000000 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Host_Structs.cpp +++ /dev/null @@ -1,2435 +0,0 @@ -/* - LEAmDNS2_Host_Structs.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include "LEAmDNS2_Priv.h" -#include "LEAmDNS2_lwIPdefs.h" - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace experimental -{ - -/** - Internal CLASSES & STRUCTS -*/ - -/** - MDNSResponder::clsHost::stcServiceTxt - - One MDNS TXT item. - m_pcValue may be '\0'. - Objects can be chained together (list, m_pNext). - A 'm_bTemp' flag differentiates between static and dynamic items. - Output as byte array 'c#=1' is supported. -*/ - -/* - MDNSResponder::clsHost::stcServiceTxt::stcServiceTxt constructor -*/ -MDNSResponder::clsHost::stcServiceTxt::stcServiceTxt(const char* p_pcKey /*= 0*/, - const char* p_pcValue /*= 0*/, - bool p_bTemp /*= false*/) - : m_pNext(0), - m_pcKey(0), - m_pcValue(0), - m_bTemp(p_bTemp) -{ - setKey(p_pcKey); - setValue(p_pcValue); -} - -/* - MDNSResponder::clsHost::stcServiceTxt::stcServiceTxt copy-constructor -*/ -MDNSResponder::clsHost::stcServiceTxt::stcServiceTxt(const MDNSResponder::clsHost::stcServiceTxt& p_Other) - : m_pNext(0), - m_pcKey(0), - m_pcValue(0), - m_bTemp(false) -{ - operator=(p_Other); -} - -/* - MDNSResponder::clsHost::stcServiceTxt::~stcServiceTxt destructor -*/ -MDNSResponder::clsHost::stcServiceTxt::~stcServiceTxt(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcServiceTxt::operator= -*/ -MDNSResponder::clsHost::stcServiceTxt& MDNSResponder::clsHost::stcServiceTxt::operator=(const MDNSResponder::clsHost::stcServiceTxt& p_Other) -{ - if (&p_Other != this) - { - clear(); - set(p_Other.m_pcKey, p_Other.m_pcValue, p_Other.m_bTemp); - } - return *this; -} - -/* - MDNSResponder::clsHost::stcServiceTxt::clear -*/ -bool MDNSResponder::clsHost::stcServiceTxt::clear(void) -{ - releaseKey(); - releaseValue(); - return true; -} - -/* - MDNSResponder::clsHost::stcServiceTxt::allocKey -*/ -char* MDNSResponder::clsHost::stcServiceTxt::allocKey(size_t p_stLength) -{ - releaseKey(); - if (p_stLength) - { - m_pcKey = new char[p_stLength + 1]; - } - return m_pcKey; -} - -/* - MDNSResponder::clsHost::stcServiceTxt::setKey -*/ -bool MDNSResponder::clsHost::stcServiceTxt::setKey(const char* p_pcKey, - size_t p_stLength) -{ - bool bResult = false; - - releaseKey(); - if (p_stLength) - { - if (allocKey(p_stLength)) - { - strncpy(m_pcKey, p_pcKey, p_stLength); - m_pcKey[p_stLength] = 0; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcServiceTxt::setKey -*/ -bool MDNSResponder::clsHost::stcServiceTxt::setKey(const char* p_pcKey) -{ - return setKey(p_pcKey, (p_pcKey ? strlen(p_pcKey) : 0)); -} - -/* - MDNSResponder::clsHost::stcServiceTxt::releaseKey -*/ -bool MDNSResponder::clsHost::stcServiceTxt::releaseKey(void) -{ - if (m_pcKey) - { - delete[] m_pcKey; - m_pcKey = 0; - } - return true; -} - -/* - MDNSResponder::clsHost::stcServiceTxt::allocValue -*/ -char* MDNSResponder::clsHost::stcServiceTxt::allocValue(size_t p_stLength) -{ - releaseValue(); - if (p_stLength) - { - m_pcValue = new char[p_stLength + 1]; - } - return m_pcValue; -} - -/* - MDNSResponder::clsHost::stcServiceTxt::setValue -*/ -bool MDNSResponder::clsHost::stcServiceTxt::setValue(const char* p_pcValue, - size_t p_stLength) -{ - bool bResult = false; - - releaseValue(); - if (p_stLength) - { - if (allocValue(p_stLength)) - { - strncpy(m_pcValue, p_pcValue, p_stLength); - m_pcValue[p_stLength] = 0; - bResult = true; - } - } - else // No value -> also OK - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcServiceTxt::setValue -*/ -bool MDNSResponder::clsHost::stcServiceTxt::setValue(const char* p_pcValue) -{ - return setValue(p_pcValue, (p_pcValue ? strlen(p_pcValue) : 0)); -} - -/* - MDNSResponder::clsHost::stcServiceTxt::releaseValue -*/ -bool MDNSResponder::clsHost::stcServiceTxt::releaseValue(void) -{ - if (m_pcValue) - { - delete[] m_pcValue; - m_pcValue = 0; - } - return true; -} - -/* - MDNSResponder::clsHost::stcServiceTxt::set -*/ -bool MDNSResponder::clsHost::stcServiceTxt::set(const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp /*= false*/) -{ - m_bTemp = p_bTemp; - return ((setKey(p_pcKey)) && - (setValue(p_pcValue))); -} - -/* - MDNSResponder::clsHost::stcServiceTxt::update -*/ -bool MDNSResponder::clsHost::stcServiceTxt::update(const char* p_pcValue) -{ - return setValue(p_pcValue); -} - -/* - MDNSResponder::clsHost::stcServiceTxt::length - - length of eg. 'c#=1' without any closing '\0' -*/ -size_t MDNSResponder::clsHost::stcServiceTxt::length(void) const -{ - size_t stLength = 0; - if (m_pcKey) - { - stLength += strlen(m_pcKey); // Key - stLength += 1; // '=' - stLength += (m_pcValue ? strlen(m_pcValue) : 0); // Value - } - return stLength; -} - - -/** - MDNSResponder::clsHost::stcServiceTxts - - A list of zero or more MDNS TXT items. - Dynamic TXT items can be removed by 'removeTempTxts'. - A TXT item can be looke up by its 'key' member. - Export as ';'-separated byte array is supported. - Export as 'length byte coded' byte array is supported. - Comparision ((all A TXT items in B and equal) AND (all B TXT items in A and equal)) is supported. - -*/ - -/* - MDNSResponder::clsHost::stcServiceTxts::stcServiceTxts contructor -*/ -MDNSResponder::clsHost::stcServiceTxts::stcServiceTxts(void) - : m_pTxts(0), - m_pcCache(0) -{ -} - -/* - MDNSResponder::clsHost::stcServiceTxts::stcServiceTxts copy-constructor -*/ -MDNSResponder::clsHost::stcServiceTxts::stcServiceTxts(const stcServiceTxts& p_Other) - : m_pTxts(0), - m_pcCache(0) -{ - operator=(p_Other); -} - -/* - MDNSResponder::clsHost::stcServiceTxts::~stcServiceTxts destructor -*/ -MDNSResponder::clsHost::stcServiceTxts::~stcServiceTxts(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcServiceTxts::operator= -*/ -MDNSResponder::clsHost::stcServiceTxts& MDNSResponder::clsHost::stcServiceTxts::operator=(const stcServiceTxts& p_Other) -{ - if (this != &p_Other) - { - clear(); - - for (stcServiceTxt* pOtherTxt = p_Other.m_pTxts; pOtherTxt; pOtherTxt = pOtherTxt->m_pNext) - { - add(new stcServiceTxt(*pOtherTxt)); - } - } - return *this; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::clear -*/ -bool MDNSResponder::clsHost::stcServiceTxts::clear(void) -{ - while (m_pTxts) - { - stcServiceTxt* pNext = m_pTxts->m_pNext; - delete m_pTxts; - m_pTxts = pNext; - } - return clearCache(); -} - -/* - MDNSResponder::clsHost::stcServiceTxts::clearCache -*/ -bool MDNSResponder::clsHost::stcServiceTxts::clearCache(void) -{ - if (m_pcCache) - { - delete[] m_pcCache; - m_pcCache = 0; - } - return true; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::add -*/ -bool MDNSResponder::clsHost::stcServiceTxts::add(MDNSResponder::clsHost::stcServiceTxt* p_pTxt) -{ - bool bResult = false; - - if (p_pTxt) - { - p_pTxt->m_pNext = m_pTxts; - m_pTxts = p_pTxt; - bResult = true; - } - return ((clearCache()) && - (bResult)); -} - -/* - MDNSResponder::clsHost::stcServiceTxts::remove -*/ -bool MDNSResponder::clsHost::stcServiceTxts::remove(stcServiceTxt* p_pTxt) -{ - bool bResult = false; - - if (p_pTxt) - { - stcServiceTxt* pPred = m_pTxts; - while ((pPred) && - (pPred->m_pNext != p_pTxt)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pTxt->m_pNext; - delete p_pTxt; - bResult = true; - } - else if (m_pTxts == p_pTxt) // No predecesor, but first item - { - m_pTxts = p_pTxt->m_pNext; - delete p_pTxt; - bResult = true; - } - } - return ((clearCache()) && - (bResult)); -} - -/* - MDNSResponder::clsHost::stcServiceTxts::removeTempTxts -*/ -bool MDNSResponder::clsHost::stcServiceTxts::removeTempTxts(void) -{ - bool bResult = true; - - stcServiceTxt* pTxt = m_pTxts; - while ((bResult) && - (pTxt)) - { - stcServiceTxt* pNext = pTxt->m_pNext; - if (pTxt->m_bTemp) - { - bResult = remove(pTxt); - } - pTxt = pNext; - } - return ((clearCache()) && - (bResult)); -} - -/* - MDNSResponder::clsHost::stcServiceTxts::find -*/ -MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::stcServiceTxts::find(const char* p_pcKey) -{ - stcServiceTxt* pResult = 0; - - for (stcServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if ((p_pcKey) && - (0 == strcmp(pTxt->m_pcKey, p_pcKey))) - { - pResult = pTxt; - break; - } - } - return pResult; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::find -*/ -const MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::stcServiceTxts::find(const char* p_pcKey) const -{ - const stcServiceTxt* pResult = 0; - - for (const stcServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if ((p_pcKey) && - (0 == strcmp(pTxt->m_pcKey, p_pcKey))) - { - - pResult = pTxt; - break; - } - } - return pResult; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::find -*/ -MDNSResponder::clsHost::stcServiceTxt* MDNSResponder::clsHost::stcServiceTxts::find(const stcServiceTxt* p_pTxt) -{ - stcServiceTxt* pResult = 0; - - for (stcServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if (p_pTxt == pTxt) - { - pResult = pTxt; - break; - } - } - return pResult; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::length -*/ -uint16_t MDNSResponder::clsHost::stcServiceTxts::length(void) const -{ - uint16_t u16Length = 0; - - stcServiceTxt* pTxt = m_pTxts; - while (pTxt) - { - u16Length += 1; // Length byte - u16Length += pTxt->length(); // Text - pTxt = pTxt->m_pNext; - } - return u16Length; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::c_strLength - - (incl. closing '\0'). Length bytes place is used for delimiting ';' and closing '\0' -*/ -size_t MDNSResponder::clsHost::stcServiceTxts::c_strLength(void) const -{ - return length(); -} - -/* - MDNSResponder::clsHost::stcServiceTxts::c_str -*/ -bool MDNSResponder::clsHost::stcServiceTxts::c_str(char* p_pcBuffer) -{ - bool bResult = false; - - if (p_pcBuffer) - { - bResult = true; - - *p_pcBuffer = 0; - for (stcServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - size_t stLength; - if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) - { - if (pTxt != m_pTxts) - { - *p_pcBuffer++ = ';'; - } - strncpy(p_pcBuffer, pTxt->m_pcKey, stLength); p_pcBuffer[stLength] = 0; - p_pcBuffer += stLength; - *p_pcBuffer++ = '='; - if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) - { - strncpy(p_pcBuffer, pTxt->m_pcValue, stLength); p_pcBuffer[stLength] = 0; - p_pcBuffer += stLength; - } - } - } - *p_pcBuffer++ = 0; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::c_str -*/ -const char* MDNSResponder::clsHost::stcServiceTxts::c_str(void) const -{ - - if ((!m_pcCache) && - (m_pTxts) && - ((((stcServiceTxts*)this)->m_pcCache = new char[c_strLength()]))) // TRANSPARENT caching - { - ((stcServiceTxts*)this)->c_str(m_pcCache); - } - return m_pcCache; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::bufferLength - - (incl. closing '\0'). -*/ -size_t MDNSResponder::clsHost::stcServiceTxts::bufferLength(void) const -{ - return (length() + 1); -} - -/* - MDNSResponder::clsHost::stcServiceTxts::toBuffer -*/ -bool MDNSResponder::clsHost::stcServiceTxts::buffer(char* p_pcBuffer) -{ - bool bResult = false; - - if (p_pcBuffer) - { - bResult = true; - - *p_pcBuffer = 0; - for (stcServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - *(unsigned char*)p_pcBuffer++ = pTxt->length(); - size_t stLength; - if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) - { - memcpy(p_pcBuffer, pTxt->m_pcKey, stLength); - p_pcBuffer += stLength; - *p_pcBuffer++ = '='; - if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) - { - memcpy(p_pcBuffer, pTxt->m_pcValue, stLength); - p_pcBuffer += stLength; - } - } - } - *p_pcBuffer++ = 0; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::compare -*/ -bool MDNSResponder::clsHost::stcServiceTxts::compare(const MDNSResponder::clsHost::stcServiceTxts& p_Other) const -{ - bool bResult = false; - - if ((bResult = (length() == p_Other.length()))) - { - // Compare A->B - for (const stcServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - const stcServiceTxt* pOtherTxt = p_Other.find(pTxt->m_pcKey); - bResult = ((pOtherTxt) && - (pTxt->m_pcValue) && - (pOtherTxt->m_pcValue) && - (strlen(pTxt->m_pcValue) == strlen(pOtherTxt->m_pcValue)) && - (0 == strcmp(pTxt->m_pcValue, pOtherTxt->m_pcValue))); - } - // Compare B->A - for (const stcServiceTxt* pOtherTxt = p_Other.m_pTxts; ((bResult) && (pOtherTxt)); pOtherTxt = pOtherTxt->m_pNext) - { - const stcServiceTxt* pTxt = find(pOtherTxt->m_pcKey); - bResult = ((pTxt) && - (pOtherTxt->m_pcValue) && - (pTxt->m_pcValue) && - (strlen(pOtherTxt->m_pcValue) == strlen(pTxt->m_pcValue)) && - (0 == strcmp(pOtherTxt->m_pcValue, pTxt->m_pcValue))); - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcServiceTxts::operator== -*/ -bool MDNSResponder::clsHost::stcServiceTxts::operator==(const stcServiceTxts& p_Other) const -{ - return compare(p_Other); -} - -/* - MDNSResponder::clsHost::stcServiceTxts::operator!= -*/ -bool MDNSResponder::clsHost::stcServiceTxts::operator!=(const stcServiceTxts& p_Other) const -{ - return !compare(p_Other); -} - - -/** - MDNSResponder::clsHost::stcProbeInformation_Base - - Probing status information for a host or service domain - -*/ - -/* - MDNSResponder::clsHost::stcProbeInformation_Base::stcProbeInformation_Base constructor -*/ -MDNSResponder::clsHost::stcProbeInformation_Base::stcProbeInformation_Base(void) - : m_ProbingStatus(enuProbingStatus::WaitingForData), - m_u8SentCount(0), - m_Timeout(std::numeric_limits::max()), - m_bConflict(false), - m_bTiebreakNeeded(false) -{ -} - -/* - MDNSResponder::clsHost::stcProbeInformation_Base::clear -*/ -bool MDNSResponder::clsHost::stcProbeInformation_Base::clear(void) -{ - m_ProbingStatus = enuProbingStatus::WaitingForData; - m_u8SentCount = 0; - m_Timeout.reset(std::numeric_limits::max()); - m_bConflict = false; - m_bTiebreakNeeded = false; - - return true; -} - - -/** - MDNSResponder::clsHost::stcProbeInformation_Host - - Probing status information for a host or service domain - -*/ - -/* - MDNSResponder::clsHost::stcProbeInformation_Host::stcProbeInformation_Host constructor -*/ -MDNSResponder::clsHost::stcProbeInformation_Host::stcProbeInformation_Host(void) - : m_fnProbeResultCallback(0) -{ -} - -/* - MDNSResponder::clsHost::stcProbeInformation_Host::clear -*/ -bool MDNSResponder::clsHost::stcProbeInformation_Host::clear(bool p_bClearUserdata /*= false*/) -{ - if (p_bClearUserdata) - { - m_fnProbeResultCallback = 0; - } - return stcProbeInformation_Base::clear(); -} - - -/** - MDNSResponder::clsHost::stcProbeInformation_Service - - Probing status information for a host or service domain - -*/ - -/* - MDNSResponder::clsHost::stcProbeInformation_Service::stcProbeInformation_Service constructor -*/ -MDNSResponder::clsHost::stcProbeInformation_Service::stcProbeInformation_Service(void) - : m_fnProbeResultCallback(0) -{ -} - -/* - MDNSResponder::clsHost::stcProbeInformation_Service::clear -*/ -bool MDNSResponder::clsHost::stcProbeInformation_Service::clear(bool p_bClearUserdata /*= false*/) -{ - if (p_bClearUserdata) - { - m_fnProbeResultCallback = 0; - } - return stcProbeInformation_Base::clear(); -} - - -/** - MDNSResponder::clsHost::stcService - - A MDNS service object (to be announced by the MDNS responder) - The service instance may be '\0'; in this case the hostname is used - and the flag m_bAutoName is set. If the hostname changes, all 'auto- - named' services are renamed also. - m_u8Replymask is used while preparing a response to a MDNS query. It is - resetted in '_sendMDNSMessage' afterwards. -*/ - -/* - MDNSResponder::clsHost::stcService::stcService constructor -*/ -MDNSResponder::clsHost::stcService::stcService(const char* p_pcName /*= 0*/, - const char* p_pcServiceType /*= 0*/, - const char* p_pcProtocol /*= 0*/) - : m_pNext(0), - m_pcName(0), - m_bAutoName(false), - m_pcServiceType(0), - m_pcProtocol(0), - m_u16Port(0), - m_u32ReplyMask(0), - m_fnTxtCallback(0) -{ - setName(p_pcName); - setServiceType(p_pcServiceType); - setProtocol(p_pcProtocol); -} - -/* - MDNSResponder::clsHost::stcService::~stcService destructor -*/ -MDNSResponder::clsHost::stcService::~stcService(void) -{ - releaseName(); - releaseServiceType(); - releaseProtocol(); -} - -/* - MDNSResponder::clsHost::stcService::setName -*/ -bool MDNSResponder::clsHost::stcService::setName(const char* p_pcName) -{ - bool bResult = false; - - releaseName(); - size_t stLength = (p_pcName ? strlen(p_pcName) : 0); - if (stLength) - { - if ((bResult = (0 != (m_pcName = new char[stLength + 1])))) - { - strncpy(m_pcName, p_pcName, stLength); - m_pcName[stLength] = 0; - } - } - else - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcService::releaseName -*/ -bool MDNSResponder::clsHost::stcService::releaseName(void) -{ - if (m_pcName) - { - delete[] m_pcName; - m_pcName = 0; - } - return true; -} - -/* - MDNSResponder::clsHost::stcService::setServiceType -*/ -bool MDNSResponder::clsHost::stcService::setServiceType(const char* p_pcServiceType) -{ - bool bResult = false; - - releaseServiceType(); - size_t stLength = (p_pcServiceType ? strlen(p_pcServiceType) : 0); - if (stLength) - { - if ((bResult = (0 != (m_pcServiceType = new char[stLength + 1])))) - { - strncpy(m_pcServiceType, p_pcServiceType, stLength); - m_pcServiceType[stLength] = 0; - } - } - else - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcService::releaseServiceType -*/ -bool MDNSResponder::clsHost::stcService::releaseServiceType(void) -{ - if (m_pcServiceType) - { - delete[] m_pcServiceType; - m_pcServiceType = 0; - } - return true; -} - -/* - MDNSResponder::clsHost::stcService::setProtocol -*/ -bool MDNSResponder::clsHost::stcService::setProtocol(const char* p_pcProtocol) -{ - bool bResult = false; - - releaseProtocol(); - size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); - if (stLength) - { - if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) - { - strncpy(m_pcProtocol, p_pcProtocol, stLength); - m_pcProtocol[stLength] = 0; - } - } - else - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcService::releaseProtocol -*/ -bool MDNSResponder::clsHost::stcService::releaseProtocol(void) -{ - if (m_pcProtocol) - { - delete[] m_pcProtocol; - m_pcProtocol = 0; - } - return true; -} - -/* - MDNSResponder::clsHost::stcService::probeStatus -*/ -bool MDNSResponder::clsHost::stcService::probeStatus(void) const -{ - return (enuProbingStatus::Done == m_ProbeInformation.m_ProbingStatus); -} - - -/** - MDNSResponder::clsHost::stcMsgHeader - - A MDNS message haeder. - -*/ - -/* - MDNSResponder::clsHost::stcMsgHeader::stcMsgHeader -*/ -MDNSResponder::clsHost::stcMsgHeader::stcMsgHeader(uint16_t p_u16ID /*= 0*/, - bool p_bQR /*= false*/, - uint8_t p_u8Opcode /*= 0*/, - bool p_bAA /*= false*/, - bool p_bTC /*= false*/, - bool p_bRD /*= false*/, - bool p_bRA /*= false*/, - uint8_t p_u8RCode /*= 0*/, - uint16_t p_u16QDCount /*= 0*/, - uint16_t p_u16ANCount /*= 0*/, - uint16_t p_u16NSCount /*= 0*/, - uint16_t p_u16ARCount /*= 0*/) - : m_u16ID(p_u16ID), - m_1bQR(p_bQR), m_4bOpcode(p_u8Opcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), - m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_u8RCode), - m_u16QDCount(p_u16QDCount), - m_u16ANCount(p_u16ANCount), - m_u16NSCount(p_u16NSCount), - m_u16ARCount(p_u16ARCount) -{ -} - - -/** - MDNSResponder::clsHost::stcRRDomain - - A MDNS domain object. - The labels of the domain are stored (DNS-like encoded) in 'm_acName': - [length byte]varlength label[length byte]varlength label[0] - 'm_u16NameLength' stores the used length of 'm_acName'. - Dynamic label addition is supported. - Comparison is supported. - Export as byte array 'esp8266.local' is supported. - -*/ - -/* - MDNSResponder::clsHost::stcRRDomain::stcRRDomain constructor -*/ -MDNSResponder::clsHost::stcRRDomain::stcRRDomain(void) - : m_u16NameLength(0), - m_pcDecodedName(0) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcRRDomain::stcRRDomain copy-constructor -*/ -MDNSResponder::clsHost::stcRRDomain::stcRRDomain(const stcRRDomain& p_Other) - : m_u16NameLength(0), - m_pcDecodedName(0) -{ - operator=(p_Other); -} - -/* - MDNSResponder::clsHost::stcRRDomain::stcRRDomain destructor -*/ -MDNSResponder::clsHost::stcRRDomain::~stcRRDomain(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcRRDomain::operator = -*/ -MDNSResponder::clsHost::stcRRDomain& MDNSResponder::clsHost::stcRRDomain::operator=(const stcRRDomain& p_Other) -{ - if (&p_Other != this) - { - clear(); - memcpy(m_acName, p_Other.m_acName, sizeof(m_acName)); - m_u16NameLength = p_Other.m_u16NameLength; - } - return *this; -} - -/* - MDNSResponder::clsHost::stcRRDomain::clear -*/ -bool MDNSResponder::clsHost::stcRRDomain::clear(void) -{ - memset(m_acName, 0, sizeof(m_acName)); - m_u16NameLength = 0; - return clearNameCache(); -} - -/* - MDNSResponder::clsHost::stcRRDomain::clearNameCache -*/ -bool MDNSResponder::clsHost::stcRRDomain::clearNameCache(void) -{ - if (m_pcDecodedName) - { - delete[] m_pcDecodedName; - m_pcDecodedName = 0; - } - return true; -} - -/* - MDNSResponder::clsHost::stcRRDomain::addLabel -*/ -bool MDNSResponder::clsHost::stcRRDomain::addLabel(const char* p_pcLabel, - bool p_bPrependUnderline /*= false*/) -{ - bool bResult = false; - - size_t stLength = (p_pcLabel - ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) - : 0); - if ((MDNS_DOMAIN_LABEL_MAXLENGTH >= stLength) && - (MDNS_DOMAIN_MAXLENGTH >= (m_u16NameLength + (1 + stLength)))) - { - // Length byte - m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! - ++m_u16NameLength; - // Label - if (stLength) - { - if (p_bPrependUnderline) - { - m_acName[m_u16NameLength++] = '_'; - --stLength; - } - strncpy(&(m_acName[m_u16NameLength]), p_pcLabel, stLength); m_acName[m_u16NameLength + stLength] = 0; - m_u16NameLength += stLength; - } - bResult = clearNameCache(); - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcRRDomain::compare -*/ -bool MDNSResponder::clsHost::stcRRDomain::compare(const stcRRDomain& p_Other) const -{ - bool bResult = false; - - if (m_u16NameLength == p_Other.m_u16NameLength) - { - const char* pT = m_acName; - const char* pO = p_Other.m_acName; - while ((pT) && - (pO) && - (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND - (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content - { - if (*((unsigned char*)pT)) // Not 0 - { - pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and lenght - pO += (1 + * ((unsigned char*)pO)); - } - else // Is 0 -> Successfully reached the end - { - bResult = true; - break; - } - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcRRDomain::operator == -*/ -bool MDNSResponder::clsHost::stcRRDomain::operator==(const stcRRDomain& p_Other) const -{ - return compare(p_Other); -} - -/* - MDNSResponder::clsHost::stcRRDomain::operator != -*/ -bool MDNSResponder::clsHost::stcRRDomain::operator!=(const stcRRDomain& p_Other) const -{ - return !compare(p_Other); -} - -/* - MDNSResponder::clsHost::stcRRDomain::operator > -*/ -bool MDNSResponder::clsHost::stcRRDomain::operator>(const stcRRDomain& p_Other) const -{ - // TODO: Check, if this is a good idea... - return !compare(p_Other); -} - -/* - MDNSResponder::clsHost::stcRRDomain::c_strLength -*/ -size_t MDNSResponder::clsHost::stcRRDomain::c_strLength(void) const -{ - size_t stLength = 0; - - unsigned char* pucLabelLength = (unsigned char*)m_acName; - while (*pucLabelLength) - { - stLength += (*pucLabelLength + 1 /* +1 for '.' or '\0'*/); - pucLabelLength += (*pucLabelLength + 1); - } - return stLength; -} - -/* - MDNSResponder::clsHost::stcRRDomain::c_str (const) -*/ -bool MDNSResponder::clsHost::stcRRDomain::c_str(char* p_pcBuffer) const -{ - bool bResult = false; - - if (p_pcBuffer) - { - *p_pcBuffer = 0; - unsigned char* pucLabelLength = (unsigned char*)m_acName; - while (*pucLabelLength) - { - memcpy(p_pcBuffer, (const char*)(pucLabelLength + 1), *pucLabelLength); - p_pcBuffer += *pucLabelLength; - pucLabelLength += (*pucLabelLength + 1); - *p_pcBuffer++ = (*pucLabelLength ? '.' : '\0'); - } - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcRRDomain::c_str -*/ -const char* MDNSResponder::clsHost::stcRRDomain::c_str(void) const -{ - if ((!m_pcDecodedName) && - (m_u16NameLength) && - ((((stcRRDomain*)this)->m_pcDecodedName = new char[c_strLength()]))) // TRANSPARENT caching - { - ((stcRRDomain*)this)->c_str(m_pcDecodedName); - } - return m_pcDecodedName; -} - - -/** - MDNSResponder::clsHost::stcRRAttributes - - A MDNS attributes object. - -*/ - -/* - MDNSResponder::clsHost::stcRRAttributes::stcRRAttributes constructor -*/ -MDNSResponder::clsHost::stcRRAttributes::stcRRAttributes(uint16_t p_u16Type /*= 0*/, - uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) - : m_u16Type(p_u16Type), - m_u16Class(p_u16Class) -{ -} - -/* - MDNSResponder::clsHost::stcRRAttributes::stcRRAttributes copy-constructor -*/ -MDNSResponder::clsHost::stcRRAttributes::stcRRAttributes(const MDNSResponder::clsHost::stcRRAttributes& p_Other) -{ - operator=(p_Other); -} - -/* - MDNSResponder::clsHost::stcRRAttributes::operator = -*/ -MDNSResponder::clsHost::stcRRAttributes& MDNSResponder::clsHost::stcRRAttributes::operator=(const MDNSResponder::clsHost::stcRRAttributes& p_Other) -{ - if (&p_Other != this) - { - m_u16Type = p_Other.m_u16Type; - m_u16Class = p_Other.m_u16Class; - } - return *this; -} - - -/** - MDNSResponder::clsHost::stcRRHeader - - A MDNS record header (domain and attributes) object. - -*/ - -/* - MDNSResponder::clsHost::stcRRHeader::stcRRHeader constructor -*/ -MDNSResponder::clsHost::stcRRHeader::stcRRHeader(void) -{ -} - -/* - MDNSResponder::clsHost::stcRRHeader::stcRRHeader copy-constructor -*/ -MDNSResponder::clsHost::stcRRHeader::stcRRHeader(const stcRRHeader& p_Other) -{ - operator=(p_Other); -} - -/* - MDNSResponder::clsHost::stcRRHeader::operator = -*/ -MDNSResponder::clsHost::stcRRHeader& MDNSResponder::clsHost::stcRRHeader::operator=(const MDNSResponder::clsHost::stcRRHeader& p_Other) -{ - if (&p_Other != this) - { - m_Domain = p_Other.m_Domain; - m_Attributes = p_Other.m_Attributes; - } - return *this; -} - -/* - MDNSResponder::clsHost::stcRRHeader::clear -*/ -bool MDNSResponder::clsHost::stcRRHeader::clear(void) -{ - m_Domain.clear(); - return true; -} - - -/** - MDNSResponder::clsHost::stcRRQuestion - - A MDNS question record object (header + question flags) - -*/ - -/* - MDNSResponder::clsHost::stcRRQuestion::stcRRQuestion constructor -*/ -MDNSResponder::clsHost::stcRRQuestion::stcRRQuestion(void) - : m_pNext(0), - m_bUnicast(false) -{ -} - - -/** - MDNSResponder::clsHost::stcNSECBitmap - - A MDNS question record object (header + question flags) - -*/ - -/* - MDNSResponder::clsHost::stcNSECBitmap::stcNSECBitmap constructor -*/ -MDNSResponder::clsHost::stcNSECBitmap::stcNSECBitmap(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcNSECBitmap::stcNSECBitmap destructor -*/ -bool MDNSResponder::clsHost::stcNSECBitmap::clear(void) -{ - memset(m_au8BitmapData, 0, sizeof(m_au8BitmapData)); - return true; -} - -/* - MDNSResponder::clsHost::stcNSECBitmap::length -*/ -uint16_t MDNSResponder::clsHost::stcNSECBitmap::length(void) const -{ - return sizeof(m_au8BitmapData); // 6 -} - -/* - MDNSResponder::clsHost::stcNSECBitmap::setBit -*/ -bool MDNSResponder::clsHost::stcNSECBitmap::setBit(uint16_t p_u16Bit) -{ - bool bResult = false; - - if ((p_u16Bit) && - (length() > (p_u16Bit / 8))) // bit between 0..47(2F) - { - - uint8_t& ru8Byte = m_au8BitmapData[p_u16Bit / 8]; - uint8_t u8Flag = 1 << (7 - (p_u16Bit % 8)); // (7 - (0..7)) = 7..0 - - ru8Byte |= u8Flag; - - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcNSECBitmap::getBit -*/ -bool MDNSResponder::clsHost::stcNSECBitmap::getBit(uint16_t p_u16Bit) const -{ - bool bResult = false; - - if ((p_u16Bit) && - (length() > (p_u16Bit / 8))) // bit between 0..47(2F) - { - - uint8_t u8Byte = m_au8BitmapData[p_u16Bit / 8]; - uint8_t u8Flag = 1 << (7 - (p_u16Bit % 8)); // (7 - (0..7)) = 7..0 - - bResult = (u8Byte & u8Flag); - } - return bResult; -} - - -/** - MDNSResponder::clsHost::stcRRAnswer - - A MDNS answer record object (header + answer content). - This is a 'virtual' base class for all other MDNS answer classes. - -*/ - -/* - MDNSResponder::clsHost::stcRRAnswer::stcRRAnswer constructor -*/ -MDNSResponder::clsHost::stcRRAnswer::stcRRAnswer(enuAnswerType p_AnswerType, - const MDNSResponder::clsHost::stcRRHeader& p_Header, - uint32_t p_u32TTL) - : m_pNext(0), - m_AnswerType(p_AnswerType), - m_Header(p_Header), - m_u32TTL(p_u32TTL) -{ - // Extract 'cache flush'-bit - m_bCacheFlush = (m_Header.m_Attributes.m_u16Class & 0x8000); - m_Header.m_Attributes.m_u16Class &= (~0x8000); -} - -/* - MDNSResponder::clsHost::stcRRAnswer::~stcRRAnswer destructor -*/ -MDNSResponder::clsHost::stcRRAnswer::~stcRRAnswer(void) -{ -} - -/* - MDNSResponder::clsHost::stcRRAnswer::answerType -*/ -MDNSResponder::clsHost::enuAnswerType MDNSResponder::clsHost::stcRRAnswer::answerType(void) const -{ - return m_AnswerType; -} - -/* - MDNSResponder::clsHost::stcRRAnswer::clear -*/ -bool MDNSResponder::clsHost::stcRRAnswer::clear(void) -{ - m_pNext = 0; - m_Header.clear(); - return true; -} - - -/** - MDNSResponder::clsHost::stcRRAnswerA - - A MDNS A answer object. - Extends the base class by an IPv4 address member. - -*/ - -#ifdef MDNS_IPV4_SUPPORT -/* - MDNSResponder::clsHost::stcRRAnswerA::stcRRAnswerA constructor -*/ -MDNSResponder::clsHost::stcRRAnswerA::stcRRAnswerA(const MDNSResponder::clsHost::stcRRHeader& p_Header, - uint32_t p_u32TTL) - : stcRRAnswer(enuAnswerType::A, p_Header, p_u32TTL), - m_IPAddress() -{ -} - -/* - MDNSResponder::clsHost::stcRRAnswerA::stcRRAnswerA destructor -*/ -MDNSResponder::clsHost::stcRRAnswerA::~stcRRAnswerA(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcRRAnswerA::clear -*/ -bool MDNSResponder::clsHost::stcRRAnswerA::clear(void) -{ - m_IPAddress = IPAddress(); - return true; -} -#endif - - -/** - MDNSResponder::clsHost::stcRRAnswerPTR - - A MDNS PTR answer object. - Extends the base class by a MDNS domain member. - -*/ - -/* - MDNSResponder::clsHost::stcRRAnswerPTR::stcRRAnswerPTR constructor -*/ -MDNSResponder::clsHost::stcRRAnswerPTR::stcRRAnswerPTR(const MDNSResponder::clsHost::stcRRHeader& p_Header, - uint32_t p_u32TTL) - : stcRRAnswer(enuAnswerType::PTR, p_Header, p_u32TTL) -{ -} - -/* - MDNSResponder::clsHost::stcRRAnswerPTR::~stcRRAnswerPTR destructor -*/ -MDNSResponder::clsHost::stcRRAnswerPTR::~stcRRAnswerPTR(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcRRAnswerPTR::clear -*/ -bool MDNSResponder::clsHost::stcRRAnswerPTR::clear(void) -{ - m_PTRDomain.clear(); - return true; -} - - -/** - MDNSResponder::clsHost::stcRRAnswerTXT - - A MDNS TXT answer object. - Extends the base class by a MDNS TXT items list member. - -*/ - -/* - MDNSResponder::clsHost::stcRRAnswerTXT::stcRRAnswerTXT constructor -*/ -MDNSResponder::clsHost::stcRRAnswerTXT::stcRRAnswerTXT(const MDNSResponder::clsHost::stcRRHeader& p_Header, - uint32_t p_u32TTL) - : stcRRAnswer(enuAnswerType::TXT, p_Header, p_u32TTL) -{ -} - -/* - MDNSResponder::clsHost::stcRRAnswerTXT::~stcRRAnswerTXT destructor -*/ -MDNSResponder::clsHost::stcRRAnswerTXT::~stcRRAnswerTXT(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcRRAnswerTXT::clear -*/ -bool MDNSResponder::clsHost::stcRRAnswerTXT::clear(void) -{ - m_Txts.clear(); - return true; -} - - -/** - MDNSResponder::clsHost::stcRRAnswerAAAA - - A MDNS AAAA answer object. - Extends the base class by an IPv6 address member. - -*/ - -#ifdef MDNS_IPV6_SUPPORT -/* - MDNSResponder::clsHost::stcRRAnswerAAAA::stcRRAnswerAAAA constructor -*/ -MDNSResponder::clsHost::stcRRAnswerAAAA::stcRRAnswerAAAA(const MDNSResponder::clsHost::stcRRHeader& p_Header, - uint32_t p_u32TTL) - : stcRRAnswer(enuAnswerType::AAAA, p_Header, p_u32TTL), - m_IPAddress() -{ -} - -/* - MDNSResponder::clsHost::stcRRAnswerAAAA::~stcRRAnswerAAAA destructor -*/ -MDNSResponder::clsHost::stcRRAnswerAAAA::~stcRRAnswerAAAA(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcRRAnswerAAAA::clear -*/ -bool MDNSResponder::clsHost::stcRRAnswerAAAA::clear(void) -{ - m_IPAddress = IPAddress(); - return true; -} -#endif - - -/** - MDNSResponder::clsHost::stcRRAnswerSRV - - A MDNS SRV answer object. - Extends the base class by a port member. - -*/ - -/* - MDNSResponder::clsHost::stcRRAnswerSRV::stcRRAnswerSRV constructor -*/ -MDNSResponder::clsHost::stcRRAnswerSRV::stcRRAnswerSRV(const MDNSResponder::clsHost::stcRRHeader& p_Header, - uint32_t p_u32TTL) - : stcRRAnswer(enuAnswerType::SRV, p_Header, p_u32TTL), - m_u16Priority(0), - m_u16Weight(0), - m_u16Port(0) -{ -} - -/* - MDNSResponder::clsHost::stcRRAnswerSRV::~stcRRAnswerSRV destructor -*/ -MDNSResponder::clsHost::stcRRAnswerSRV::~stcRRAnswerSRV(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcRRAnswerSRV::clear -*/ -bool MDNSResponder::clsHost::stcRRAnswerSRV::clear(void) -{ - m_u16Priority = 0; - m_u16Weight = 0; - m_u16Port = 0; - m_SRVDomain.clear(); - return true; -} - - -/** - MDNSResponder::clsHost::stcRRAnswerGeneric - - An unknown (generic) MDNS answer object. - Extends the base class by a RDATA buffer member. - -*/ - -/* - MDNSResponder::clsHost::stcRRAnswerGeneric::stcRRAnswerGeneric constructor -*/ -MDNSResponder::clsHost::stcRRAnswerGeneric::stcRRAnswerGeneric(const stcRRHeader& p_Header, - uint32_t p_u32TTL) - : stcRRAnswer(enuAnswerType::Generic, p_Header, p_u32TTL), - m_u16RDLength(0), - m_pu8RDData(0) -{ -} - -/* - MDNSResponder::clsHost::stcRRAnswerGeneric::~stcRRAnswerGeneric destructor -*/ -MDNSResponder::clsHost::stcRRAnswerGeneric::~stcRRAnswerGeneric(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcRRAnswerGeneric::clear -*/ -bool MDNSResponder::clsHost::stcRRAnswerGeneric::clear(void) -{ - if (m_pu8RDData) - { - delete[] m_pu8RDData; - m_pu8RDData = 0; - } - m_u16RDLength = 0; - - return true; -} - - -/** - MDNSResponder::clsHost::stcSendParameter - - A 'collection' of properties and flags for one MDNS query or response. - Mainly managed by the 'Control' functions. - The current offset in the UPD output buffer is tracked to be able to do - a simple host or service domain compression. - -*/ - -/** - MDNSResponder::clsHost::stcSendParameter::stcDomainCacheItem - - A cached host or service domain, incl. the offset in the UDP output buffer. - -*/ - -/* - MDNSResponder::clsHost::stcSendParameter::stcDomainCacheItem::stcDomainCacheItem constructor -*/ -MDNSResponder::clsHost::stcSendParameter::stcDomainCacheItem::stcDomainCacheItem(const void* p_pHostNameOrService, - bool p_bAdditionalData, - uint32_t p_u16Offset) - : m_pNext(0), - m_pHostNameOrService(p_pHostNameOrService), - m_bAdditionalData(p_bAdditionalData), - m_u16Offset(p_u16Offset) -{ -} - -/** - MDNSResponder::clsHost::stcSendParameter -*/ - -/* - MDNSResponder::clsHost::stcSendParameter::stcSendParameter constructor -*/ -MDNSResponder::clsHost::stcSendParameter::stcSendParameter(void) - : m_pQuestions(0), - m_Response(enuResponseType::None), - m_pDomainCacheItems(0) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcSendParameter::~stcSendParameter destructor -*/ -MDNSResponder::clsHost::stcSendParameter::~stcSendParameter(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcSendParameter::clear -*/ -bool MDNSResponder::clsHost::stcSendParameter::clear(void) -{ - m_u16ID = 0; - flushQuestions(); - m_u32HostReplyMask = 0; - - m_bLegacyQuery = false; - m_Response = enuResponseType::None; - m_bAuthorative = false; - m_bCacheFlush = true; - m_bUnicast = false; - m_bUnannounce = false; - - m_u16Offset = 0; - flushDomainCache(); - return true; -} - -/* - MDNSResponder::clsHost::stcSendParameter::flushQuestions -*/ -bool MDNSResponder::clsHost::stcSendParameter::flushQuestions(void) -{ - while (m_pQuestions) - { - stcRRQuestion* pNext = m_pQuestions->m_pNext; - delete m_pQuestions; - m_pQuestions = pNext; - } - return true; -} - -/* - MDNSResponder::clsHost::stcSendParameter::flushDomainCache -*/ -bool MDNSResponder::clsHost::stcSendParameter::flushDomainCache(void) -{ - while (m_pDomainCacheItems) - { - stcDomainCacheItem* pNext = m_pDomainCacheItems->m_pNext; - delete m_pDomainCacheItems; - m_pDomainCacheItems = pNext; - } - return true; -} - -/* - MDNSResponder::clsHost::stcSendParameter::flushTempContent -*/ -bool MDNSResponder::clsHost::stcSendParameter::flushTempContent(void) -{ - m_u16Offset = 0; - flushDomainCache(); - return true; -} - -/* - MDNSResponder::clsHost::stcSendParameter::shiftOffset -*/ -bool MDNSResponder::clsHost::stcSendParameter::shiftOffset(uint16_t p_u16Shift) -{ - m_u16Offset += p_u16Shift; - return true; -} - -/* - MDNSResponder::clsHost::stcSendParameter::addDomainCacheItem -*/ -bool MDNSResponder::clsHost::stcSendParameter::addDomainCacheItem(const void* p_pHostNameOrService, - bool p_bAdditionalData, - uint16_t p_u16Offset) -{ - bool bResult = false; - - stcDomainCacheItem* pNewItem = 0; - if ((p_pHostNameOrService) && - (p_u16Offset) && - ((pNewItem = new stcDomainCacheItem(p_pHostNameOrService, p_bAdditionalData, p_u16Offset)))) - { - - pNewItem->m_pNext = m_pDomainCacheItems; - bResult = ((m_pDomainCacheItems = pNewItem)); - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcSendParameter::findCachedDomainOffset -*/ -uint16_t MDNSResponder::clsHost::stcSendParameter::findCachedDomainOffset(const void* p_pHostNameOrService, - bool p_bAdditionalData) const -{ - const stcDomainCacheItem* pCacheItem = m_pDomainCacheItems; - - for (; pCacheItem; pCacheItem = pCacheItem->m_pNext) - { - if ((pCacheItem->m_pHostNameOrService == p_pHostNameOrService) && - (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item - { - break; - } - } - return (pCacheItem ? pCacheItem->m_u16Offset : 0); -} - - -/** - MDNSResponder::clsHost::stcQuery - - A MDNS service query object. - Service queries may be static or dynamic. - As the static service query is processed in the blocking function 'queryService', - only one static service service may exist. The processing of the answers is done - on the WiFi-stack side of the ESP stack structure (via 'UDPContext.onRx(_update)'). - -*/ - -/** - MDNSResponder::clsHost::stcQuery::stcAnswer - - One answer for a service query. - Every answer must contain - - a service instance entry (pivot), - and may contain - - a host domain, - - a port - - an IPv4 address - (- an IPv6 address) - - a MDNS TXTs - The existance of a component is flaged in 'm_u32ContentFlags'. - For every answer component a TTL value is maintained. - Answer objects can be connected to a linked list. - - For the host domain, service domain and TXTs components, a char array - representation can be retrieved (which is created on demand). - -*/ - -/** - MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL - - The TTL (Time-To-Live) for an specific answer content. - The 80% and outdated states are calculated based on the current time (millis) - and the 'set' time (also millis). - If the answer is scheduled for an update, the corresponding flag should be set. - -*/ - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::stcTTL constructor -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::stcTTL(void) - : m_u32TTL(0), - m_TTLTimeout(std::numeric_limits::max()), - m_TimeoutLevel(static_cast(enuTimeoutLevel::None)) -{ -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::set -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) -{ - m_u32TTL = p_u32TTL; - if (m_u32TTL) - { - m_TimeoutLevel = static_cast(enuTimeoutLevel::Base); // Set to 80% - m_TTLTimeout.reset(timeout()); - } - else - { - m_TimeoutLevel = static_cast(enuTimeoutLevel::None); // undef - m_TTLTimeout.reset(std::numeric_limits::max()); - } - return true; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::flagged -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::flagged(void) const -{ - return ((m_u32TTL) && - (static_cast(enuTimeoutLevel::None) != m_TimeoutLevel) && - (((esp8266::polledTimeout::timeoutTemplate*)&m_TTLTimeout)->expired())); // Cast-away the const; in case of oneShot-timer OK (but ugly...) -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::restart -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::restart(void) -{ - bool bResult = true; - - if ((static_cast(enuTimeoutLevel::Base) <= m_TimeoutLevel) && // >= 80% AND - (static_cast(enuTimeoutLevel::Final) > m_TimeoutLevel)) // < 100% - { - - m_TimeoutLevel += static_cast(enuTimeoutLevel::Interval); // increment by 5% - m_TTLTimeout.reset(timeout()); - } - else - { - bResult = false; - m_TTLTimeout.reset(std::numeric_limits::max()); - m_TimeoutLevel = static_cast(enuTimeoutLevel::None); - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::prepareDeletion -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::prepareDeletion(void) -{ - m_TimeoutLevel = static_cast(enuTimeoutLevel::Final); - m_TTLTimeout.reset(1 * 1000); // See RFC 6762, 10.1 - - return true; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::finalTimeoutLevel -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::finalTimeoutLevel(void) const -{ - return (static_cast(enuTimeoutLevel::Final) == m_TimeoutLevel); -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::timeout -*/ -unsigned long MDNSResponder::clsHost::stcQuery::stcAnswer::stcTTL::timeout(void) const -{ - uint32_t u32Timeout = std::numeric_limits::max(); - - if (static_cast(enuTimeoutLevel::Base) == m_TimeoutLevel) // 80% - { - u32Timeout = (m_u32TTL * 800); // to milliseconds - } - else if ((static_cast(enuTimeoutLevel::Base) < m_TimeoutLevel) && // >80% AND - (static_cast(enuTimeoutLevel::Final) >= m_TimeoutLevel)) // <= 100% - { - - u32Timeout = (m_u32TTL * 50); - } // else: invalid - return u32Timeout; -} - - -/** - MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress - -*/ - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress::stcIPAddress constructor -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress::stcIPAddress(IPAddress p_IPAddress, - uint32_t p_u32TTL /*= 0*/) - : m_pNext(0), - m_IPAddress(p_IPAddress) -{ - m_TTL.set(p_u32TTL); -} - - -/** - MDNSResponder::clsHost::stcQuery::stcAnswer -*/ - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::stcAnswer constructor -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer::stcAnswer(void) - : m_pNext(0), - m_u16Port(0), -#ifdef MDNS_IPV4_SUPPORT - m_pIPv4Addresses(0), -#endif -#ifdef MDNS_IPV6_SUPPORT - m_pIPv6Addresses(0), -#endif - m_QueryAnswerFlags(0) -{ -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::~stcAnswer destructor -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer::~stcAnswer(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::clear -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::clear(void) -{ - return ( -#ifdef MDNS_IPV4_SUPPORT - (releaseIPv4Addresses()) && -#endif -#ifdef MDNS_IPV6_SUPPORT - (releaseIPv6Addresses()) -#endif - ); -} - -#ifdef MDNS_IPV4_SUPPORT -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::releaseIPv4Addresses -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::releaseIPv4Addresses(void) -{ - while (m_pIPv4Addresses) - { - stcIPAddress* pNext = m_pIPv4Addresses->m_pNext; - delete m_pIPv4Addresses; - m_pIPv4Addresses = pNext; - } - return true; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::addIPv4Address -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::addIPv4Address(MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* p_pIPv4Address) -{ - bool bResult = false; - - if (p_pIPv4Address) - { - p_pIPv4Address->m_pNext = m_pIPv4Addresses; - m_pIPv4Addresses = p_pIPv4Address; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::removeIPv4Address -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::removeIPv4Address(MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* p_pIPv4Address) -{ - bool bResult = false; - - if (p_pIPv4Address) - { - stcIPAddress* pPred = m_pIPv4Addresses; - while ((pPred) && - (pPred->m_pNext != p_pIPv4Address)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pIPv4Address->m_pNext; - delete p_pIPv4Address; - bResult = true; - } - else if (m_pIPv4Addresses == p_pIPv4Address) // No predecesor, but first item - { - m_pIPv4Addresses = p_pIPv4Address->m_pNext; - delete p_pIPv4Address; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv4Address (const) -*/ -const MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv4Address(const IPAddress& p_IPAddress) const -{ - return (stcIPAddress*)(((const stcAnswer*)this)->findIPv4Address(p_IPAddress)); -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv4Address -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv4Address(const IPAddress& p_IPAddress) -{ - stcIPAddress* pIPv4Address = m_pIPv4Addresses; - while (pIPv4Address) - { - if (pIPv4Address->m_IPAddress == p_IPAddress) - { - break; - } - pIPv4Address = pIPv4Address->m_pNext; - } - return pIPv4Address; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressCount -*/ -uint32_t MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressCount(void) const -{ - uint32_t u32Count = 0; - - stcIPAddress* pIPv4Address = m_pIPv4Addresses; - while (pIPv4Address) - { - ++u32Count; - pIPv4Address = pIPv4Address->m_pNext; - } - return u32Count; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressAtIndex -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressAtIndex(uint32_t p_u32Index) -{ - return (stcIPAddress*)(((const stcAnswer*)this)->IPv4AddressAtIndex(p_u32Index)); -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressAtIndex (const) -*/ -const MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::IPv4AddressAtIndex(uint32_t p_u32Index) const -{ - const stcIPAddress* pIPv4Address = 0; - - if (((uint32_t)(-1) != p_u32Index) && - (m_pIPv4Addresses)) - { - - uint32_t u32Index; - for (pIPv4Address = m_pIPv4Addresses, u32Index = 0; ((pIPv4Address) && (u32Index < p_u32Index)); pIPv4Address = pIPv4Address->m_pNext, ++u32Index); - } - return pIPv4Address; -} -#endif - -#ifdef MDNS_IPV6_SUPPORT -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::releaseIPv6Addresses -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::releaseIPv6Addresses(void) -{ - while (m_pIPv6Addresses) - { - stcIPAddress* pNext = m_pIPv6Addresses->m_pNext; - delete m_pIPv6Addresses; - m_pIPv6Addresses = pNext; - } - return true; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::addIPv6Address -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::addIPv6Address(MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* p_pIPv6Address) -{ - bool bResult = false; - - if (p_pIPv6Address) - { - p_pIPv6Address->m_pNext = m_pIPv6Addresses; - m_pIPv6Addresses = p_pIPv6Address; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::removeIPv6Address -*/ -bool MDNSResponder::clsHost::stcQuery::stcAnswer::removeIPv6Address(MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* p_pIPv6Address) -{ - bool bResult = false; - - if (p_pIPv6Address) - { - stcIPAddress* pPred = m_pIPv6Addresses; - while ((pPred) && - (pPred->m_pNext != p_pIPv6Address)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pIPv6Address->m_pNext; - delete p_pIPv6Address; - bResult = true; - } - else if (m_pIPv6Addresses == p_pIPv6Address) // No predecesor, but first item - { - m_pIPv6Addresses = p_pIPv6Address->m_pNext; - delete p_pIPv6Address; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv6Address -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv6Address(const IPAddress& p_IPAddress) -{ - return (stcIPAddress*)(((const stcAnswer*)this)->findIPv6Address(p_IPAddress)); -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv6Address (const) -*/ -const MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::findIPv6Address(const IPAddress& p_IPAddress) const -{ - const stcIPAddress* pIPv6Address = m_pIPv6Addresses; - while (pIPv6Address) - { - if (pIPv6Address->m_IPAddress == p_IPAddress) - { - break; - } - pIPv6Address = pIPv6Address->m_pNext; - } - return pIPv6Address; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressCount -*/ -uint32_t MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressCount(void) const -{ - uint32_t u32Count = 0; - - stcIPAddress* pIPv6Address = m_pIPv6Addresses; - while (pIPv6Address) - { - ++u32Count; - pIPv6Address = pIPv6Address->m_pNext; - } - return u32Count; -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressAtIndex (const) -*/ -const MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressAtIndex(uint32_t p_u32Index) const -{ - return (stcIPAddress*)(((const stcAnswer*)this)->IPv6AddressAtIndex(p_u32Index)); -} - -/* - MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressAtIndex -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer::stcIPAddress* MDNSResponder::clsHost::stcQuery::stcAnswer::IPv6AddressAtIndex(uint32_t p_u32Index) -{ - stcIPAddress* pIPv6Address = 0; - - if (((uint32_t)(-1) != p_u32Index) && - (m_pIPv6Addresses)) - { - - uint32_t u32Index; - for (pIPv6Address = m_pIPv6Addresses, u32Index = 0; ((pIPv6Address) && (u32Index < p_u32Index)); pIPv6Address = pIPv6Address->m_pNext, ++u32Index); - } - return pIPv6Address; -} -#endif - - -/** - MDNSResponder::clsHost::stcQuery - - A service query object. - A static query is flaged via 'm_bLegacyQuery'; while the function 'queryService' - is waiting for answers, the internal flag 'm_bAwaitingAnswers' is set. When the - timeout is reached, the flag is removed. These two flags are only used for static - service queries. - All answers to the service query are stored in 'm_pAnswers' list. - Individual answers may be addressed by index (in the list of answers). - Every time a answer component is added (or changes) in a dynamic service query, - the callback 'm_fnCallback' is called. - The answer list may be searched by service and host domain. - - Service query object may be connected to a linked list. -*/ - -/* - MDNSResponder::clsHost::stcQuery::stcQuery constructor -*/ -MDNSResponder::clsHost::stcQuery::stcQuery(const enuQueryType p_QueryType) - : m_pNext(0), - m_QueryType(p_QueryType), - m_fnCallback(0), - m_bLegacyQuery(false), - m_u8SentCount(0), - m_ResendTimeout(std::numeric_limits::max()), - m_bAwaitingAnswers(true), - m_pAnswers(0) -{ - clear(); - m_QueryType = p_QueryType; -} - -/* - MDNSResponder::clsHost::stcQuery::~stcQuery destructor -*/ -MDNSResponder::clsHost::stcQuery::~stcQuery(void) -{ - clear(); -} - -/* - MDNSResponder::clsHost::stcQuery::clear -*/ -bool MDNSResponder::clsHost::stcQuery::clear(void) -{ - m_pNext = 0; - m_QueryType = enuQueryType::None; - m_fnCallback = 0; - m_bLegacyQuery = false; - m_u8SentCount = 0; - m_ResendTimeout.reset(std::numeric_limits::max()); - m_bAwaitingAnswers = true; - while (m_pAnswers) - { - stcAnswer* pNext = m_pAnswers->m_pNext; - delete m_pAnswers; - m_pAnswers = pNext; - } - return true; -} - -/* - MDNSResponder::clsHost::stcQuery::answerCount -*/ -uint32_t MDNSResponder::clsHost::stcQuery::answerCount(void) const -{ - uint32_t u32Count = 0; - - stcAnswer* pAnswer = m_pAnswers; - while (pAnswer) - { - ++u32Count; - pAnswer = pAnswer->m_pNext; - } - return u32Count; -} - -/* - MDNSResponder::clsHost::stcQuery::answerAtIndex -*/ -const MDNSResponder::clsHost::stcQuery::stcAnswer* MDNSResponder::clsHost::stcQuery::answerAtIndex(uint32_t p_u32Index) const -{ - const stcAnswer* pAnswer = 0; - - if (((uint32_t)(-1) != p_u32Index) && - (m_pAnswers)) - { - - uint32_t u32Index; - for (pAnswer = m_pAnswers, u32Index = 0; ((pAnswer) && (u32Index < p_u32Index)); pAnswer = pAnswer->m_pNext, ++u32Index); - } - return pAnswer; -} - -/* - MDNSResponder::clsHost::stcQuery::answerAtIndex -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer* MDNSResponder::clsHost::stcQuery::answerAtIndex(uint32_t p_u32Index) -{ - return (stcAnswer*)(((const stcQuery*)this)->answerAtIndex(p_u32Index)); -} - -/* - MDNSResponder::clsHost::stcQuery::indexOfAnswer -*/ -uint32_t MDNSResponder::clsHost::stcQuery::indexOfAnswer(const MDNSResponder::clsHost::stcQuery::stcAnswer* p_pAnswer) const -{ - uint32_t u32Index = 0; - - for (const stcAnswer* pAnswer = m_pAnswers; pAnswer; pAnswer = pAnswer->m_pNext, ++u32Index) - { - if (pAnswer == p_pAnswer) - { - return u32Index; - } - } - return ((uint32_t)(-1)); -} - -/* - MDNSResponder::clsHost::stcQuery::addAnswer -*/ -bool MDNSResponder::clsHost::stcQuery::addAnswer(MDNSResponder::clsHost::stcQuery::stcAnswer* p_pAnswer) -{ - bool bResult = false; - - if (p_pAnswer) - { - p_pAnswer->m_pNext = m_pAnswers; - m_pAnswers = p_pAnswer; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcQuery::removeAnswer -*/ -bool MDNSResponder::clsHost::stcQuery::removeAnswer(MDNSResponder::clsHost::stcQuery::stcAnswer* p_pAnswer) -{ - bool bResult = false; - - if (p_pAnswer) - { - stcAnswer* pPred = m_pAnswers; - while ((pPred) && - (pPred->m_pNext != p_pAnswer)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pAnswer->m_pNext; - delete p_pAnswer; - bResult = true; - } - else if (m_pAnswers == p_pAnswer) // No predecesor, but first item - { - m_pAnswers = p_pAnswer->m_pNext; - delete p_pAnswer; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::clsHost::stcQuery::findAnswerForServiceDomain -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer* MDNSResponder::clsHost::stcQuery::findAnswerForServiceDomain(const MDNSResponder::clsHost::stcRRDomain& p_ServiceDomain) -{ - stcAnswer* pAnswer = m_pAnswers; - while (pAnswer) - { - if (pAnswer->m_ServiceDomain == p_ServiceDomain) - { - break; - } - pAnswer = pAnswer->m_pNext; - } - return pAnswer; -} - -/* - MDNSResponder::clsHost::stcQuery::findAnswerForHostDomain -*/ -MDNSResponder::clsHost::stcQuery::stcAnswer* MDNSResponder::clsHost::stcQuery::findAnswerForHostDomain(const MDNSResponder::clsHost::stcRRDomain& p_HostDomain) -{ - stcAnswer* pAnswer = m_pAnswers; - while (pAnswer) - { - if (pAnswer->m_HostDomain == p_HostDomain) - { - break; - } - pAnswer = pAnswer->m_pNext; - } - return pAnswer; -} - - -} // namespace MDNSImplementation - -} // namespace esp8266 - - - diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp new file mode 100644 index 0000000000..040d915905 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp @@ -0,0 +1,1493 @@ +/* + * LEAmDNS2_Legacy.cpp + * + * + */ + +#include "LEAmDNS2_Legacy.h" + + +namespace esp8266 +{ + +/** + * LEAmDNS + */ +namespace MDNSImplementation +{ + +/** + STRINGIZE +*/ +#ifndef STRINGIZE +#define STRINGIZE(x) #x +#endif +#ifndef STRINGIZE_VALUE_OF +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) +#endif + + +/* + * clsLEAMDNSHost_Legacy::clsLEAMDNSHost_Legacy constructor + * + */ +clsLEAMDNSHost_Legacy::clsLEAMDNSHost_Legacy(void) +{ +} + +/* + * clsLEAMDNSHost_Legacy::clsLEAMDNSHost_Legacy destructor + * + */ +clsLEAMDNSHost_Legacy::~clsLEAMDNSHost_Legacy(void) +{ +} + +/* + * + * HOST SETUP + * + */ + +/* + * clsLEAMDNSHost_Legacy::begin + * + */ +bool clsLEAMDNSHost_Legacy::begin(const char* p_pcHostname) +{ + bool bResult = ( ( (!(WIFI_STA & (WiFiMode_t)wifi_get_opmode())) + || (addHostForNetIf(p_pcHostname, netif_get_by_index(WIFI_STA)))) + && ( (!(WIFI_AP & (WiFiMode_t)wifi_get_opmode())) + || (addHostForNetIf(p_pcHostname, netif_get_by_index(WIFI_AP))))); + return ( (bResult) + && (0 != m_HostInformations.size())); +} + +/* + * clsLEAMDNSHost_Legacy::begin (String) + * + */ +bool clsLEAMDNSHost_Legacy::begin(const String& p_strHostname) +{ + return begin(p_strHostname.c_str()); +} + +/* + * clsLEAMDNSHost_Legacy::begin (Ignored Options) + * + */ +bool clsLEAMDNSHost_Legacy::begin(const char* p_pcHostname, + IPAddress /*p_IPAddress = INADDR_ANY*/, // ignored + uint32_t /*p_u32TTL = 120*/) // ignored +{ + return begin(p_pcHostname); +} + +/* + * clsLEAMDNSHost_Legacy::begin (String & Ignored Options) + * + */ +bool clsLEAMDNSHost_Legacy::begin(const String& p_strHostname, + IPAddress /*p_IPAddress = INADDR_ANY*/, // ignored + uint32_t /*p_u32TTL = 120*/) // ignored +{ + return begin(p_strHostname.c_str()); +} + +/* + * clsLEAMDNSHost_Legacy::close + * + */ +bool clsLEAMDNSHost_Legacy::close(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + if ((bResult = (*it).m_pHost->close())) + { + delete (*it).m_pHost; + (*it).m_pHost = 0; + } + } + return ( (bResult) + && (m_HostInformations.clear(), true)); +} + +/* + * clsLEAMDNSHost_Legacy::end + * + */ +bool clsLEAMDNSHost_Legacy::end(void) +{ + return close(); +} + +/* + * clsLEAMDNSHost_Legacy::addHostForNetIf + * + * NEW! + * + */ +bool clsLEAMDNSHost_Legacy::addHostForNetIf(const char* p_pcHostname, + netif* p_pNetIf) +{ + clsLEAMDNSHost* pHost = 0; + + if ( ((pHost = new esp8266::experimental::clsLEAMDNSHost)) + && (!( (pHost->begin(p_pcHostname, p_pNetIf /*, default callback*/)) + && (m_HostInformations.push_back(stcHostInformation(pHost)), true)))) + { + delete pHost; + pHost = 0; + } + return (0 != pHost); +} + +/* + * clsLEAMDNSHost_Legacy::setHostname + * + */ +bool clsLEAMDNSHost_Legacy::setHostname(const char* p_pcHostname) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->setHostName(p_pcHostname); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::setHostname + * + */ +bool clsLEAMDNSHost_Legacy::setHostname(String p_strHostname) +{ + return setHostname(p_strHostname.c_str()); +} + +/* + * clsLEAMDNSHost_Legacy::hostname + * + */ +const char* clsLEAMDNSHost_Legacy::hostname(void) const +{ + return (m_HostInformations.empty() + ? 0 + : m_HostInformations.front().m_pHost->hostName()); +} + +/* + * clsLEAMDNSHost_Legacy::status + * + */ +bool clsLEAMDNSHost_Legacy::status(void) const +{ + bool bStatus = true; + + for (const stcHostInformation& hostInformation : m_HostInformations) + { + if (!((bStatus = hostInformation.m_pHost->probeStatus()))) + { + break; + } + } + return bStatus; +} + + +/* + * + * SERVICE MANAGEMENT + * + */ + +/* + * clsLEAMDNSHost_Legacy::addService + * + */ +clsLEAMDNSHost_Legacy::hMDNSService clsLEAMDNSHost_Legacy::addService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + hMDNSService hResult = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsService* pService = hostInformation.m_pHost->addService(p_pcName, p_pcService, p_pcProtocol, p_u16Port /*, default callback*/); + if (pService) + { + if (!hResult) + { // Store first service handle as result and key + hResult = (hMDNSService)pService; + } + hostInformation.m_HandleToPtr[hResult] = pService; + } + } + return hResult; +} + +/* + * clsLEAMDNSHost_Legacy::addService (String) + * + */ +bool clsLEAMDNSHost_Legacy::addService(String p_strServiceName, + String p_strProtocol, + uint16_t p_u16Port) +{ + return (0 != addService(0, p_strServiceName.c_str(), p_strProtocol.c_str(), p_u16Port)); +} + +/* + * clsLEAMDNSHost_Legacy::removeService (hService) + * + */ +bool clsLEAMDNSHost_Legacy::removeService(const hMDNSService p_hService) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; + if ((bResult = ( (pService) + && ((*it).m_pHost->removeService(pService))))) + { + (*it).m_HandleToPtr.erase(p_hService); + } + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::removeService (name) + * + */ +bool clsLEAMDNSHost_Legacy::removeService(const char* p_pcInstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol) +{ + hMDNSService hService = 0; + return ( ((hService = (m_HostInformations.empty() + ? 0 + : (hMDNSService)m_HostInformations.front().m_pHost->findService(p_pcInstanceName, p_pcServiceName, p_pcProtocol)))) + && (removeService(hService))); +} + +/* + * clsLEAMDNSHost_Legacy::setServiceName + * + */ +bool clsLEAMDNSHost_Legacy::setServiceName(const hMDNSService p_hService, + const char* p_pcInstanceName) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; + bResult = ( (pService) + && (pService->setInstanceName(p_pcInstanceName))); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::setInstanceName + * + */ +void clsLEAMDNSHost_Legacy::setInstanceName(const char* p_pcInstanceName) +{ + for (stcHostInformation& hostInformation : m_HostInformations) + { + hostInformation.m_pHost->setDefaultInstanceName(p_pcInstanceName); + } +} + +/* + * clsLEAMDNSHost_Legacy::setInstanceName (String) + * + */ +void clsLEAMDNSHost_Legacy::setInstanceName(const String& p_strHostname) +{ + setInstanceName(p_strHostname.c_str()); +} + +/* + * clsLEAMDNSHost_Legacy::serviceName + * + */ +const char* clsLEAMDNSHost_Legacy::serviceName(const hMDNSService p_hService) const +{ + const clsLEAMDNSHost::clsService* pService = 0; + return (m_HostInformations.empty() + ? 0 + : (((pService = (const clsLEAMDNSHost::clsService*)(m_HostInformations.front().m_HandleToPtr.at(p_hService)))) + ? pService->instanceName() + : 0)); +} + +/* + * clsLEAMDNSHost_Legacy::service + * + */ +const char* clsLEAMDNSHost_Legacy::service(const hMDNSService p_hService) const +{ + const clsLEAMDNSHost::clsService* pService = 0; + return (m_HostInformations.empty() + ? 0 + : (((pService = (const clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr.at(p_hService))) + ? pService->type() + : 0)); +} + +/* + * clsLEAMDNSHost_Legacy::serviceProtocol + * + */ +const char* clsLEAMDNSHost_Legacy::serviceProtocol(const hMDNSService p_hService) const +{ + const clsLEAMDNSHost::clsService* pService = 0; + return (m_HostInformations.empty() + ? 0 + : (((pService = (const clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr.at(p_hService))) + ? pService->protocol() + : 0)); +} + +/* + * clsLEAMDNSHost_Legacy::serviceStatus + * + */ +bool clsLEAMDNSHost_Legacy::serviceStatus(const hMDNSService p_hService) const +{ + const clsLEAMDNSHost::clsService* pService = 0; + return (m_HostInformations.empty() + ? false + : (((pService = (const clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr.at(p_hService))) + ? pService->probeStatus() + : false)); +} + + +/* + * + * SERVICE TXT MANAGEMENT + * + */ + +/* + * clsLEAMDNSHost_Legacy::addServiceTxt (char*) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_hService, p_pcKey, p_pcValue, false); +} + +/* + * clsLEAMDNSHost_Legacy::addServiceTxt (uint32_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u32Value, false); +} + +/* + * clsLEAMDNSHost_Legacy::addServiceTxt (uint16_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u16Value, false); +} + +/* + * clsLEAMDNSHost_Legacy::addServiceTxt (uint8_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u8Value, false); +} + +/* + * clsLEAMDNSHost_Legacy::addServiceTxt (int32_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i32Value, false); +} + +/* + * clsLEAMDNSHost_Legacy::addServiceTxt (int16_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i16Value, false); +} + +/* + * clsLEAMDNSHost_Legacy::addServiceTxt (int8_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i8Value, false); +} + +/* + * clsLEAMDNSHost_Legacy::addServiceTxt (legacy) + * + */ +bool clsLEAMDNSHost_Legacy::addServiceTxt(const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey, + const char* p_pcValue) +{ + hMDNSService hService = 0; + return ( ((hService = (m_HostInformations.empty() + ? 0 + : (hMDNSService)m_HostInformations.front().m_pHost->findService(0, p_pcService, p_pcProtocol)))) + && (_addServiceTxt(hService, p_pcKey, p_pcValue, false))); +} + +/* + * clsLEAMDNSHost_Legacy::addServiceTxt (legacy, String) + * + */ +bool clsLEAMDNSHost_Legacy::addServiceTxt(String p_strService, + String p_strProtocol, + String p_strKey, + String p_strValue) +{ + return addServiceTxt(p_strService.c_str(), p_strProtocol.c_str(), p_strKey.c_str(), p_strValue.c_str()); +} + +/* + * clsLEAMDNSHost_Legacy::removeServiceTxt (hTxt) + * + */ +bool clsLEAMDNSHost_Legacy::removeServiceTxt(const hMDNSService p_hService, + const hMDNSTxt p_hTxt) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; + clsLEAMDNSHost::clsServiceTxt* pTxt = (clsLEAMDNSHost::clsServiceTxt*)(*it).m_HandleToPtr[p_hTxt]; + if ((bResult = ( (pService) + && (pTxt) + && (pService->removeServiceTxt(pTxt))))) + { + (*it).m_HandleToPtr.erase(p_hTxt); + } + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::removeServiceTxt (char*) + * + */ +bool clsLEAMDNSHost_Legacy::removeServiceTxt(const hMDNSService p_hService, + const char* p_pcKey) +{ + clsLEAMDNSHost::clsService* pService = 0; + clsLEAMDNSHost::clsServiceTxt* pTxt = 0; + return ( ((pService = (m_HostInformations.empty() + ? 0 + : (clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr[p_hService]))) + && ((pTxt = pService->findServiceTxt(p_pcKey))) + && (removeServiceTxt(p_hService, (const hMDNSTxt)pTxt))); +} + +/* + * clsLEAMDNSHost_Legacy::removeServiceTxt (char*) + * + */ +bool clsLEAMDNSHost_Legacy::removeServiceTxt(const char* p_pcInstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol, + const char* p_pcKey) +{ + hMDNSService hService = 0; + return ( ((hService = (m_HostInformations.empty() + ? 0 + : (hMDNSService)m_HostInformations.front().m_pHost->findService(p_pcInstanceName, p_pcServiceName, p_pcProtocol)))) + && (removeServiceTxt(hService, p_pcKey))); +} + +/* + * clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback (global) + * + */ +bool clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn p_fnCallback) +{ + bool bResult = true; + + if ((bResult = m_HostInformations.empty())) + { + // The service handles of the first host are the keys in the HostInformations.HandleToPtr map + for (const clsLEAMDNSHost::clsService* pService : m_HostInformations.front().m_pHost->services()) + { + if (!((bResult = setDynamicServiceTxtCallback((hMDNSService)pService, p_fnCallback)))) + { + break; + } + } + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback (service) + * + */ +bool clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback(const hMDNSService p_hService, + MDNSDynamicServiceTxtCallbackFn p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; + bResult = pService->setDynamicServiceTxtCallback([p_hService, p_fnCallback](clsLEAMDNSHost::clsService& /*p_rMDNSService*/)->void + { + if (p_fnCallback) // void(const hMDNSService p_hService) + { + p_fnCallback(p_hService); + } + }); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (char*) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_hService, p_pcKey, p_pcValue, true); +} + +/* + * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (uint32) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u32Value, true); +} + +/* + * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (uint16) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u16Value, true); +} + +/* + * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (uint8) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u8Value, true); +} + +/* + * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (int32) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i32Value, true); +} + +/* + * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (int16) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i16Value, true); +} + +/* + * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (int8) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i8Value, true); +} + + +/* + * + * STATIC QUERY + * + */ + + /* + * clsLEAMDNSHost_Legacy::queryService + * + * This will take p_u16Timeout millisec for every host! + * + */ +uint32_t clsLEAMDNSHost_Legacy::queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + uint32_t u32Answers = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + u32Answers += (hostInformation.m_pHost->queryService(p_pcService, p_pcProtocol, p_u16Timeout)).size(); + } + return u32Answers; +} + +/* + * clsLEAMDNSHost_Legacy::removeQuery + * + */ +bool clsLEAMDNSHost_Legacy::removeQuery(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->removeQuery(); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::queryService + * + */ +uint32_t clsLEAMDNSHost_Legacy::queryService(String p_strService, + String p_strProtocol) +{ + return queryService(p_strService.c_str(), p_strProtocol.c_str()); +} + +/* + * clsLEAMDNSHost_Legacy::answerHostname + * + */ +const char* clsLEAMDNSHost_Legacy::answerHostname(const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_u32AnswerIndex); + return (answerAccessor.serviceDomainAvailable() + ? answerAccessor.serviceDomain() + : 0); +} + +/* + * clsLEAMDNSHost_Legacy::answerIP + * + */ +IPAddress clsLEAMDNSHost_Legacy::answerIP(const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_u32AnswerIndex); + return (answerAccessor.IPv4AddressAvailable() + ? answerAccessor.IPv4Addresses()[0] + : IPAddress()); +} + +/* + * clsLEAMDNSHost_Legacy::answerPort + * + */ +uint16_t clsLEAMDNSHost_Legacy::answerPort(const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_u32AnswerIndex); + return (answerAccessor.hostPortAvailable() + ? answerAccessor.hostPort() + : 0); +} + +/* + * clsLEAMDNSHost_Legacy::hostname + * + */ +String clsLEAMDNSHost_Legacy::hostname(const uint32_t p_u32AnswerIndex) +{ + return String(answerHostname(p_u32AnswerIndex)); +} + +/* + * clsLEAMDNSHost_Legacy::IP + * + */ +IPAddress clsLEAMDNSHost_Legacy::IP(const uint32_t p_u32AnswerIndex) +{ + return answerIP(p_u32AnswerIndex); +} + +/* + * clsLEAMDNSHost_Legacy::port + * + */ +uint16_t clsLEAMDNSHost_Legacy::port(const uint32_t p_u32AnswerIndex) +{ + return answerPort(p_u32AnswerIndex); +} + + +/* + * + * DYNAMIC QUERY + * + */ + +/* + * clsLEAMDNSHost_Legacy::installServiceQuery + * + */ +clsLEAMDNSHost_Legacy::hMDNSServiceQuery clsLEAMDNSHost_Legacy::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSServiceQueryCallbackFn p_fnCallback) +{ + hMDNSServiceQuery hResult = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = hostInformation.m_pHost->installServiceQuery(p_pcService, p_pcProtocol, [this, p_fnCallback](const clsLEAMDNSHost::clsQuery& /*p_Query*/, + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor& p_AnswerAccessor, + clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, // flags for the updated answer item + bool p_bSetContent)->void + { + if (p_fnCallback) // void(const stcMDNSServiceInfo& p_MDNSServiceInfo, MDNSResponder::AnswerType p_AnswerType, bool p_bSetContent) + { + p_fnCallback(stcMDNSServiceInfo(p_AnswerAccessor), _answerFlagsToAnswerType(p_QueryAnswerTypeFlags), p_bSetContent); + } + }); + if (pQuery) + { + if (!hResult) + { // Store first query as result and key + hResult = (hMDNSServiceQuery)pQuery; + } + hostInformation.m_HandleToPtr[hResult] = pQuery; + } + } + return hResult; +} + +/* + * clsLEAMDNSHost_Legacy::removeServiceQuery + * + */ +bool clsLEAMDNSHost_Legacy::removeServiceQuery(clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + if ((bResult = (*it).m_pHost->removeQuery((clsLEAMDNSHost::clsQuery*)(*it).m_HandleToPtr[p_hServiceQuery]))) + { + (*it).m_HandleToPtr.erase(p_hServiceQuery); + } + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::answerCount + * + */ +uint32_t clsLEAMDNSHost_Legacy::answerCount(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery) +{ + uint32_t u32AnswerCount = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = (clsLEAMDNSHost::clsQuery*)hostInformation.m_HandleToPtr[p_hServiceQuery]; + if (pQuery) + { + u32AnswerCount += pQuery->answerCount(); + } + else + { + u32AnswerCount = 0; + break; + } + } + return u32AnswerCount; +} + +/* + * clsLEAMDNSHost_Legacy::answerInfo + * + */ +std::vector clsLEAMDNSHost_Legacy::answerInfo(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery) +{ + std::vector serviceInfos; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = (clsLEAMDNSHost::clsQuery*)hostInformation.m_HandleToPtr[p_hServiceQuery]; + if (pQuery) + { + for (clsLEAMDNSHost::clsQuery::clsAnswerAccessor& answerAccessor : pQuery->answerAccessors()) + { + serviceInfos.push_back(stcMDNSServiceInfo(answerAccessor)); + } + } + else + { + serviceInfos.clear(); + break; + } + } + return serviceInfos; +} + +/* + * clsLEAMDNSHost_Legacy::answerServiceDomain + * + */ +const char* clsLEAMDNSHost_Legacy::answerServiceDomain(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.serviceDomainAvailable() + ? answerAccessor.serviceDomain() + : 0); +} + +/* + * clsLEAMDNSHost_Legacy::hasAnswerHostDomain + * + */ +bool clsLEAMDNSHost_Legacy::hasAnswerHostDomain(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).hostDomainAvailable(); +} + +/* + * clsLEAMDNSHost_Legacy::answerHostDomain + * + */ +const char* clsLEAMDNSHost_Legacy::answerHostDomain(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.hostDomainAvailable() + ? answerAccessor.hostDomain() + : 0); +} + +#ifdef MDNS_IP4_SUPPORT +/* + * clsLEAMDNSHost_Legacy::hasAnswerIP4Address + * + */ +bool clsLEAMDNSHost_Legacy::hasAnswerIP4Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).IPv4AddressAvailable(); +} + +/* + * clsLEAMDNSHost_Legacy::answerIP4AddressCount + * + */ +uint32_t clsLEAMDNSHost_Legacy::answerIP4AddressCount(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.IPv4AddressAvailable() + ? answerAccessor.IPv4Addresses().size() + : 0); +} + +/* + * clsLEAMDNSHost_Legacy::answerIP4Address + * + */ +IPAddress clsLEAMDNSHost_Legacy::answerIP4Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.IPv4AddressAvailable() + ? answerAccessor.IPv4Addresses()[p_u32AddressIndex] + : IPAddress()); +} +#endif +#ifdef MDNS_IP6_SUPPORT +/* + * clsLEAMDNSHost_Legacy::hasAnswerIP6Address + * + */ +bool clsLEAMDNSHost_Legacy::hasAnswerIP6Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).IPv6AddressAvailable(); +} + +/* + * clsLEAMDNSHost_Legacy::answerIP6AddressCount + * + */ +uint32_t clsLEAMDNSHost_Legacy::answerIP6AddressCount(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.IPv6AddressAvailable() + ? answerAccessor.IPv6Addresses().size() + : 0); +} + +/* + * clsLEAMDNSHost_Legacy::answerIP6Address + * + */ +IPAddress clsLEAMDNSHost_Legacy::answerIP6Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.IPv6AddressAvailable() + ? answerAccessor.IPv6Addresses()[p_u32AddressIndex] + : IPAddress()); +} +#endif + +/* + * clsLEAMDNSHost_Legacy::hasAnswerPort + * + */ +bool clsLEAMDNSHost_Legacy::hasAnswerPort(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).hostPortAvailable(); +} + +/* + * clsLEAMDNSHost_Legacy::answerPort + * + */ +uint16_t clsLEAMDNSHost_Legacy::answerPort(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.hostPortAvailable() + ? answerAccessor.hostPort() + : 0); +} + +/* + * clsLEAMDNSHost_Legacy::hasAnswerTxts + * + */ +bool clsLEAMDNSHost_Legacy::hasAnswerTxts(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).txtsAvailable(); +} + +/* + * clsLEAMDNSHost_Legacy::answerHostDomain + * + * Get the TXT items as a ';'-separated string + */ +const char* clsLEAMDNSHost_Legacy::answerTxts(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.txtsAvailable() + ? answerAccessor.txts() + : 0); +} + + +/* + * + * HOST/SERVICE PROBE CALLBACKS + * + */ + +/* + * clsLEAMDNSHost_Legacy::setHostProbeResultCallback + * + */ +bool clsLEAMDNSHost_Legacy::setHostProbeResultCallback(clsLEAMDNSHost_Legacy::MDNSHostProbeResultCallbackFn p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->setProbeResultCallback([p_fnCallback](clsLEAMDNSHost& /*p_rHost*/, + const char* p_pcDomainName, + bool p_bProbeResult)->void + { + if (p_fnCallback) // void(const char* p_pcDomainName, bool p_bProbeResult) + { + p_fnCallback(p_pcDomainName, p_bProbeResult); + } + }); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::setHostProbeResultCallback + * + */ +bool clsLEAMDNSHost_Legacy::setHostProbeResultCallback(clsLEAMDNSHost_Legacy::MDNSHostProbeResultCallbackFn2 p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->setProbeResultCallback([this, p_fnCallback](clsLEAMDNSHost& /*p_rHost*/, + const char* p_pcDomainName, + bool p_bProbeResult)->void + { + if (p_fnCallback) // void(clsLEAMDNSHost_Legacy* p_pMDNSResponder, const char* p_pcDomainName, bool p_bProbeResult) + { + p_fnCallback(this, p_pcDomainName, p_bProbeResult); + } + }); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::setServiceProbeResultCallback + * + */ +bool clsLEAMDNSHost_Legacy::setServiceProbeResultCallback(const clsLEAMDNSHost_Legacy::hMDNSService p_hService, + clsLEAMDNSHost_Legacy::MDNSServiceProbeResultCallbackFn p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = 0; + bResult = ( ((pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService])) + && (pService->setProbeResultCallback([this, p_hService, p_fnCallback](clsLEAMDNSHost::clsService& /*p_rMDNSService*/, + const char* p_pcInstanceName, + bool p_bProbeResult)->void + { + if (p_fnCallback) // void(const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) + { + p_fnCallback(p_pcInstanceName, p_hService, p_bProbeResult); + } + }))); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::setServiceProbeResultCallback + * + */ +bool clsLEAMDNSHost_Legacy::setServiceProbeResultCallback(const clsLEAMDNSHost_Legacy::hMDNSService p_hService, + clsLEAMDNSHost_Legacy::MDNSServiceProbeResultCallbackFn2 p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = 0; + bResult = ( ((pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService])) + && (pService->setProbeResultCallback([this, p_hService, p_fnCallback](clsLEAMDNSHost::clsService& /*p_rMDNSService*/, + const char* p_pcInstanceName, + bool p_bProbeResult)->void + { + if (p_fnCallback) // void((clsLEAMDNSHost_Legacy* p_pMDNSResponder, const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) + { + p_fnCallback(this, p_pcInstanceName, p_hService, p_bProbeResult); + } + }))); + } + return bResult; +} + + +/* + * + * PROCESS + * + */ + +/* + * clsLEAMDNSHost_Legacy::notifyAPChange + * + */ +bool clsLEAMDNSHost_Legacy::notifyAPChange(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->restart(); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::update + * + */ +bool clsLEAMDNSHost_Legacy::update(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->update(); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::announce + * + */ +bool clsLEAMDNSHost_Legacy::announce(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->announce(true, true); + } + return bResult; +} + +/* + * clsLEAMDNSHost_Legacy::enableArduino + * + */ +clsLEAMDNSHost_Legacy::hMDNSService clsLEAMDNSHost_Legacy::enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload /*= false*/) +{ + hMDNSService hService = addService(0, "arduino", "tcp", p_u16Port); + if (hService) + { + if ( (!addServiceTxt(hService, "tcp_check", "no")) + || (!addServiceTxt(hService, "ssh_upload", "no")) + || (!addServiceTxt(hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) + || (!addServiceTxt(hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) + { + removeService(hService); + hService = 0; + } + } + return hService; +} + +/* + * clsLEAMDNSHost_Legacy::indexDomain + * + */ +bool clsLEAMDNSHost_Legacy::indexDomain(char*& p_rpcDomain, + const char* p_pcDivider /*= "-"*/, + const char* p_pcDefaultDomain /*= 0*/) +{ + bool bResult = false; + + const char* cpcDomainName = clsLEAMDNSHost::indexDomainName(p_rpcDomain, p_pcDivider, p_pcDefaultDomain); + delete[] p_rpcDomain; + p_rpcDomain = 0; + if ( (cpcDomainName) + && ((p_rpcDomain = new char[strlen(cpcDomainName) + 1]))) + { + strcpy(p_rpcDomain, cpcDomainName); + bResult = true; + } + return bResult; +} + + +/* + * + * INTERNAL HELPERS + * + */ + +/* + * clsLEAMDNSHost_Legacy::_addServiceTxt (char*) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bDynamic) +{ + hMDNSTxt hResult = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsService* pService = 0; + clsLEAMDNSHost::clsServiceTxt* pTxt = 0; + if ( ((pService = (clsLEAMDNSHost::clsService*)hostInformation.m_HandleToPtr[p_hService])) + && ((pTxt = (p_bDynamic + ? pService->addDynamicServiceTxt(p_pcKey, p_pcValue) + : pService->addServiceTxt(p_pcKey, p_pcValue))))) + { + if (!hResult) + { + hResult = (hMDNSTxt)pTxt; + } + hostInformation.m_HandleToPtr[hResult] = pTxt; + } + } + return hResult; +} + +/* + * clsLEAMDNSHost_Legacy::_addServiceTxt (uint32_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value, + bool p_bDynamic) +{ + char acValueBuffer[16]; // 32-bit max 10 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%u", p_u32Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + * clsLEAMDNSHost_Legacy::_addServiceTxt (uint16_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value, + bool p_bDynamic) +{ + char acValueBuffer[8]; // 16-bit max 5 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hu", p_u16Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + * clsLEAMDNSHost_Legacy::_addServiceTxt (uint8_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value, + bool p_bDynamic) +{ + char acValueBuffer[8]; // 8-bit max 3 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hhu", p_u8Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + * clsLEAMDNSHost_Legacy::_addServiceTxt (int32_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value, + bool p_bDynamic) +{ + char acValueBuffer[16]; // 32-bit max 11 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%i", p_i32Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + * clsLEAMDNSHost_Legacy::_addServiceTxt (int16_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value, + bool p_bDynamic) +{ + char acValueBuffer[8]; // 16-bit max 6 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hi", p_i16Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + * clsLEAMDNSHost_Legacy::_addServiceTxt (int8_t) + * + */ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value, + bool p_bDynamic) +{ + char acValueBuffer[8]; // 8-bit max 4 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hhi", p_i8Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + * clsLEAMDNSHost_Legacy::_answerFlagsToAnswerType + * + */ +clsLEAMDNSHost_Legacy::AnswerType clsLEAMDNSHost_Legacy::_answerFlagsToAnswerType(clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags) const +{ + AnswerType answerType = AnswerType::Unknown; + + if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Unknown) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::Unknown; + } + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::ServiceDomain; + } + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::HostDomain) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::HostDomainAndPort; + } + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Port) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::HostDomainAndPort; + } + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Txts) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::Txt; + } +#ifdef MDNS_IP4_SUPPORT + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::IP4Address; + } +#endif +#ifdef MDNS_IP6_SUPPORT + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::IP6Address; + } +#endif + return answerType; +} + +/* + * clsLEAMDNSHost_Legacy::_getAnswerAccessor + * + */ +clsLEAMDNSHost_Legacy::clsLEAMDNSHost::clsQuery::clsAnswerAccessor clsLEAMDNSHost_Legacy::_getAnswerAccessor(const uint32_t p_u32AnswerIndex) +{ + uint32_t u32AnswerIndexWithoutOffset = p_u32AnswerIndex; + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = hostInformation.m_pHost->getQuery(); + if (pQuery) + { + if (pQuery->answerCount() > u32AnswerIndexWithoutOffset) + { + return pQuery->answerAccessor(u32AnswerIndexWithoutOffset); + } + else + { + u32AnswerIndexWithoutOffset -= pQuery->answerCount(); + } + } + else + { + break; + } + } + return clsLEAMDNSHost::clsQuery::clsAnswerAccessor(0); +} + +/* + * clsLEAMDNSHost_Legacy::_getAnswerAccessor + * + */ +clsLEAMDNSHost_Legacy::clsLEAMDNSHost::clsQuery::clsAnswerAccessor clsLEAMDNSHost_Legacy::_getAnswerAccessor(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + uint32_t u32AnswerIndexWithoutOffset = p_u32AnswerIndex; + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = (clsLEAMDNSHost::clsQuery*)hostInformation.m_HandleToPtr[p_hServiceQuery]; + if (pQuery) + { + if (pQuery->answerCount() > u32AnswerIndexWithoutOffset) + { + return pQuery->answerAccessor(u32AnswerIndexWithoutOffset); + } + else + { + u32AnswerIndexWithoutOffset -= pQuery->answerCount(); + } + } + else + { + break; + } + } + return clsLEAMDNSHost::clsQuery::clsAnswerAccessor(0); +} + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + + + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h new file mode 100644 index 0000000000..3b37dd5451 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h @@ -0,0 +1,679 @@ +/* + * LEAmDNS2_Legacy.h + * (c) 2020, LaborEtArs + * + * Version 0.9 beta + * + * Some notes (from LaborEtArs, 2018): + * Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS). + * The target of this rewrite was to keep the existing interface as stable as possible while + * adding and extending the supported set of mDNS features. + * A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code. + * + * Supported mDNS features (in some cases somewhat limited): + * - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service + * - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented + * - Probing host and service domains for uniqueness in the local network + * - Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak) + * - Announcing available services after successful probing + * - Using fixed service TXT items or + * - Using dynamic service TXT items for presented services (via callback) + * - Remove services (and un-announcing them to the observers by sending goodbye-messages) + * - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) + * - Dynamic queries for DNS-SD services with cached and updated answers and user notifications + * + * + * Usage: + * In most cases, this implementation should work as a 'drop-in' replacement for the original + * ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some + * of the new features should be used. + * + * For presenting services: + * In 'setup()': + * Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);' + * Register DNS-SD services with 'clsLEAMDNSHost_Legacy::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);' + * (Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);') + * Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback + * using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific + * 'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);' + * Call MDNS.begin("MyHostname"); + * + * In 'probeResultCallback(clsLEAMDNSHost_Legacy* p_MDNSResponder, const char* p_pcDomain, clsLEAMDNSHost_Legacy:hMDNSService p_hService, bool p_bProbeResult, void* p_pUserdata)': + * Check the probe result and update the host or service domain name if the probe failed + * + * In 'dynamicServiceTxtCallback(clsLEAMDNSHost_Legacy* p_MDNSResponder, const hMDNSService p_hService, void* p_pUserdata)': + * Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hService, "c#", "1");' + * + * In loop(): + * Call 'MDNS.update();' + * + * + * For querying services: + * Static: + * Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");' + * Iterate answers by: 'for (uint32_t u=0; u MDNSDynamicServiceTxtCallbackFn; + + // Set a global callback for dynamic MDNS TXT items. The callback function is called + // every time, a TXT item is needed for one of the installed services. + bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn p_fnCallback); + + // Set a service specific callback for dynamic MDNS TXT items. The callback function + // is called every time, a TXT item is needed for the given service. + bool setDynamicServiceTxtCallback(const hMDNSService p_hService, + MDNSDynamicServiceTxtCallbackFn p_fnCallback); + + // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + // Dynamic TXT items are removed right after one-time use. So they need to be added + // every time the value s needed (via callback). + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value); + + // Perform a (static) service query. The function returns after p_u16Timeout milliseconds + // The answers (the number of received answers is returned) can be retrieved by calling + // - answerHostname (or hostname) + // - answerIP (or IP) + // - answerPort (or port) + uint32_t queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout = clsConsts::u16StaticQueryWaitTime); + bool removeQuery(void); + // for compatibility... + uint32_t queryService(String p_strService, + String p_strProtocol); + + const char* answerHostname(const uint32_t p_u32AnswerIndex); + IPAddress answerIP(const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const uint32_t p_u32AnswerIndex); + // for compatibility... + String hostname(const uint32_t p_u32AnswerIndex); + IPAddress IP(const uint32_t p_u32AnswerIndex); + uint16_t port(const uint32_t p_u32AnswerIndex); + + /** + * hMDNSServiceQuery (opaque handle to access dynamic service queries) + */ + typedef const void* hMDNSServiceQuery; + + /** + * enuServiceQueryAnswerType + */ + typedef enum _enuServiceQueryAnswerType { + ServiceQueryAnswerType_Unknown = 0, + ServiceQueryAnswerType_ServiceDomain = (1 << 0), // Service instance name + ServiceQueryAnswerType_HostDomainAndPort = (1 << 1), // Host domain and service port + ServiceQueryAnswerType_Txts = (1 << 2), // TXT items +#ifdef MDNS_IP4_SUPPORT + ServiceQueryAnswerType_IP4Address = (1 << 3), // IP4 address +#endif +#ifdef MDNS_IP6_SUPPORT + ServiceQueryAnswerType_IP6Address = (1 << 4), // IP6 address +#endif + } enuServiceQueryAnswerType; + + /** + * AnswerType (std::map compatible version) + */ + enum class AnswerType : uint32_t { + Unknown = ServiceQueryAnswerType_Unknown, + ServiceDomain = ServiceQueryAnswerType_ServiceDomain, + HostDomainAndPort = ServiceQueryAnswerType_HostDomainAndPort, + Txt = ServiceQueryAnswerType_Txts, +#ifdef MDNS_IP4_SUPPORT + IP4Address = ServiceQueryAnswerType_IP4Address, +#endif +#ifdef MDNS_IP6_SUPPORT + IP6Address = ServiceQueryAnswerType_IP6Address +#endif + }; + + /** + * stcMDNSServiceInfo + */ + struct stcMDNSServiceInfo { + stcMDNSServiceInfo(const clsLEAMDNSHost::clsQuery::clsAnswerAccessor& p_rAnswerAccessor) + : m_rAnswerAccessor(p_rAnswerAccessor) {}; + /** + * stcCompareKey + */ + struct stcCompareKey { + /* + * operator () + */ + bool operator()(char const* p_pA, char const* p_pB) const { + return (0 > strcmp(p_pA, p_pB)); + } + }; + /** + * clsKeyValueMap + */ + using clsKeyValueMap = std::map; + + protected: + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor& m_rAnswerAccessor; + clsKeyValueMap m_KeyValueMap; + + public: + /* + * serviceDomain + */ + const char* serviceDomain(void) const { + return (m_rAnswerAccessor.serviceDomainAvailable() + ? m_rAnswerAccessor.serviceDomain() + : nullptr); + } + /* + * hostDomainAvailable + */ + bool hostDomainAvailable(void) const { + return m_rAnswerAccessor.serviceDomainAvailable(); + } + /* + * hostDomain + */ + const char* hostDomain(void) const { + return (hostDomainAvailable() + ? m_rAnswerAccessor.hostDomain() + : nullptr); + } + /* + * hostPortAvailable + */ + bool hostPortAvailable(void) const { + return m_rAnswerAccessor.hostPortAvailable(); + } + /* + * hostPort + */ + uint16_t hostPort(void) const { + return (hostPortAvailable() + ? m_rAnswerAccessor.hostPort() + : 0); + } +#ifdef MDNS_IP4_SUPPORT + /* + * IP4AddressAvailable + */ + bool IP4AddressAvailable(void) const { + return m_rAnswerAccessor.IPv4AddressAvailable(); + } + /* + * IP4Addresses + */ + std::vector IP4Adresses(void) const { + return (IP4AddressAvailable() + ? m_rAnswerAccessor.IPv4Addresses() + : std::vector()); + } +#endif +#ifdef MDNS_IP6_SUPPORT + /* + * IP6AddressAvailable + */ + bool IP6AddressAvailable(void) const { + return m_rAnswerAccessor.IPv6AddressAvailable(); + } + /* + * IP6Addresses + */ + std::vector IP6Adresses(void) const { + return (IP6AddressAvailable() + ? m_rAnswerAccessor.IPv6Addresses() + : std::vector()); + } +#endif + /* + * txtAvailable + */ + bool txtAvailable(void) const { + return m_rAnswerAccessor.txtsAvailable(); + } + /* + * strKeyValue -> abc=def;hij=klm; + */ + const char* strKeyValue (void) const { + // TODO + return nullptr; + } + /* + * keyValues -> abc=def hij=klm ... + */ + const clsKeyValueMap& keyValues(void) { + if ((txtAvailable()) && + (0 == m_KeyValueMap.size())) { + for (auto kv : m_rAnswerAccessor.txtKeyValues()) + { + m_KeyValueMap.emplace(std::pair(kv.first, kv.second)); + } + //for (auto kv=m_rMDNSResponder._answerKeyValue(m_hServiceQuery, m_u32AnswerIndex); kv!=nullptr; kv=kv->m_pNext) { + // m_KeyValueMap.emplace(std::pair(kv->m_pcKey, kv->m_pcValue)); + //} + } + return m_KeyValueMap; + } + /* + * value (abc)->def + */ + const char* value(const char* p_pcKey) const { + return m_rAnswerAccessor.txtValue(p_pcKey); + } + }; + + /** + * MDNSServiceQueryCallbackFn + * + * Callback function for received answers for dynamic service queries + */ + typedef std::function MDNSServiceQueryCallbackFn; + + // Install a dynamic service query. For every received answer (part) the given callback + // function is called. The query will be updated every time, the TTL for an answer + // has timed-out. + // The answers can also be retrieved by calling + // - answerCount + // - answerServiceDomain + // - hasAnswerHostDomain/answerHostDomain + // - hasAnswerIP4Address/answerIP4Address + // - hasAnswerIP6Address/answerIP6Address + // - hasAnswerPort/answerPort + // - hasAnswerTxts/answerTxts + hMDNSServiceQuery installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSServiceQueryCallbackFn p_fnCallback); + // Remove a dynamic service query + bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery); + + uint32_t answerCount(const hMDNSServiceQuery p_hServiceQuery); + std::vector answerInfo(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery); + const char* answerServiceDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerHostDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + const char* answerHostDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); +#ifdef MDNS_IP4_SUPPORT + bool hasAnswerIP4Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIP4AddressCount(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIP4Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif +#ifdef MDNS_IP6_SUPPORT + bool hasAnswerIP6Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIP6AddressCount(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIP6Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif + bool hasAnswerPort(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerTxts(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + // Get the TXT items as a ';'-separated string + const char* answerTxts(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + + /** + * MDNSHostProbeResultCallbackFn/2 + * Callback function for host domain probe results + */ + typedef std::function MDNSHostProbeResultCallbackFn; + + typedef std::function MDNSHostProbeResultCallbackFn2; + + // Set a callback function for host probe results + // The callback function is called, when the probeing for the host domain + // succeededs or fails. + // In case of failure, the failed domain name should be changed. + bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn p_fnCallback); + bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn2 p_fnCallback); + + /** + * MDNSServiceProbeResultCallbackFn/2 + * Callback function for service domain probe results + */ + typedef std::function MDNSServiceProbeResultCallbackFn; + + typedef std::function MDNSServiceProbeResultCallbackFn2; + + // Set a service specific probe result callcack + bool setServiceProbeResultCallback(const hMDNSService p_hService, + MDNSServiceProbeResultCallbackFn p_fnCallback); + bool setServiceProbeResultCallback(const hMDNSService p_hService, + MDNSServiceProbeResultCallbackFn2 p_fnCallback); + + // Application should call this whenever AP is configured/disabled + bool notifyAPChange(void); + + // 'update' should be called in every 'loop' to run the MDNS processing + bool update(void); + + // 'announce' can be called every time, the configuration of some service + // changes. Mainly, this would be changed content of TXT items. + bool announce(void); + + // Enable OTA update + hMDNSService enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload = false); + + // Domain name helper + static bool indexDomain(char*& p_rpcDomain, + const char* p_pcDivider = "-", + const char* p_pcDefaultDomain = 0); + +protected: + /** + * stcHostInformation + */ + struct stcHostInformation + { + /** + * clsHandleToPtrMap + */ + using clsHandleToPtrMap = std::map; + + clsLEAMDNSHost* m_pHost; + clsHandleToPtrMap m_HandleToPtr; + + stcHostInformation(clsLEAMDNSHost* p_pHost) + : m_pHost(p_pHost) + {} + + /** + * list + */ + using list = std::list; + }; + + stcHostInformation::list m_HostInformations; + + // HELPERS + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value, + bool p_bDynamic); + + AnswerType _answerFlagsToAnswerType(clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags) const; + + clsLEAMDNSHost::clsQuery::clsAnswerAccessor _getAnswerAccessor(const uint32_t p_u32AnswerIndex); + clsLEAMDNSHost::clsQuery::clsAnswerAccessor _getAnswerAccessor(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + +}; + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + +#endif // __LEAMDNS2HOST_LEGACY_H__ + + + + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h b/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h deleted file mode 100755 index 240700b7cf..0000000000 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - LEAmDNS2_Priv.h - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#ifndef LEAMDNS2_PRIV_H -#define LEAMDNS2_PRIV_H - -namespace esp8266 -{ - -/* - LEAmDNS -*/ - -namespace experimental -{ - -// Enable class debug functions -#define ESP_8266_MDNS_INCLUDE -#define DEBUG_ESP_MDNS_RESPONDER - - -#ifndef LWIP_OPEN_SRC -#define LWIP_OPEN_SRC -#endif - -// -// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing -// This allows to drive the responder in a environment, where 'update()' isn't called in the loop -//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE - -// Enable/disable debug trace macros -#ifdef DEBUG_ESP_MDNS_RESPONDER -#define DEBUG_ESP_MDNS_INFO -#define DEBUG_ESP_MDNS_ERR -#define DEBUG_ESP_MDNS_TX -#define DEBUG_ESP_MDNS_RX -#endif - -#ifdef DEBUG_ESP_MDNS_RESPONDER -#ifdef DEBUG_ESP_MDNS_INFO -#define DEBUG_EX_INFO(A) A -#else -#define DEBUG_EX_INFO(A) -#endif -#ifdef DEBUG_ESP_MDNS_ERR -#define DEBUG_EX_ERR(A) A -#else -#define DEBUG_EX_ERR(A) -#endif -#ifdef DEBUG_ESP_MDNS_TX -#define DEBUG_EX_TX(A) A -#else -#define DEBUG_EX_TX(A) -#endif -#ifdef DEBUG_ESP_MDNS_RX -#define DEBUG_EX_RX(A) A -#else -#define DEBUG_EX_RX(A) -#endif - -#ifdef DEBUG_ESP_PORT -#define DEBUG_OUTPUT DEBUG_ESP_PORT -#else -#define DEBUG_OUTPUT Serial -#endif -#else -#define DEBUG_EX_INFO(A) -#define DEBUG_EX_ERR(A) -#define DEBUG_EX_TX(A) -#define DEBUG_EX_RX(A) -#endif - -/* - This is NOT the TTL (Time-To-Live) for MDNS records, but the - subnet level distance MDNS records should travel. - 1 sets the subnet distance to 'local', which is default for MDNS. - (Btw.: 255 would set it to 'as far as possible' -> internet) - - However, RFC 3171 seems to force 255 instead -*/ -#define MDNS_MULTICAST_TTL 255 /* some say 1 is right*/ - -/* - This is the MDNS record TTL - Host level records are set to 2min (120s) - service level records are set to 75min (4500s) -*/ -#define MDNS_LEGACY_TTL 10 -#define MDNS_HOST_TTL 120 -#define MDNS_SERVICE_TTL 4500 - -/* - Compressed labels are flaged by the two topmost bits of the length byte being set -*/ -#define MDNS_DOMAIN_COMPRESS_MARK 0xC0 -/* - Avoid endless recursion because of malformed compressed labels -*/ -#define MDNS_DOMAIN_MAX_REDIRCTION 6 - -/* - Default service priority and weight in SRV answers -*/ -#define MDNS_SRV_PRIORITY 0 -#define MDNS_SRV_WEIGHT 0 - -/* - Delay between and number of probes for host and service domains - Delay between and number of announces for host and service domains - Delay between and number of queries; the delay is multiplied by the resent number in '_checkQueryCache' -*/ -#define MDNS_PROBE_DELAY 250 -#define MDNS_PROBE_COUNT 3 -#define MDNS_ANNOUNCE_DELAY 1000 -#define MDNS_ANNOUNCE_COUNT 3 -#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 1000 - - -/* - Force host domain to use only lowercase letters -*/ -//#define MDNS_FORCE_LOWERCASE_HOSTNAME - -/* - Enable/disable the usage of the F() macro in debug trace printf calls. - There needs to be an PGM comptible printf function to use this. - - USE_PGM_PRINTF and F -*/ -#define USE_PGM_PRINTF - -#ifdef USE_PGM_PRINTF -#else -#ifdef F -#undef F -#endif -#define F(A) A -#endif - -} // namespace MDNSImplementation - -} // namespace esp8266 - -// Include the main header, so the submodlues only need to include this header -#include "LEAmDNS2.h" - - -#endif // LEAMDNS2_PRIV_H diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h b/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h old mode 100755 new mode 100644 From d47f6f07e412659da52396ed6435ab059390a206 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 8 May 2020 11:29:26 +0200 Subject: [PATCH 04/12] style --- .../LEAmDNS/TwoInterfaces/TwoInterfaces.ino | 246 +- libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp | 144 +- libraries/ESP8266mDNS/src/LEAmDNS2Host.h | 28 +- .../ESP8266mDNS/src/LEAmDNS2Host_Control.cpp | 260 +- .../ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp | 4 +- .../ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp | 192 +- .../ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp | 180 +- .../ESP8266mDNS/src/LEAmDNS2_Backbone.cpp | 14 +- libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp | 2988 +++++++++-------- libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h | 1377 ++++---- 10 files changed, 2729 insertions(+), 2704 deletions(-) diff --git a/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino b/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino index 3434454491..3f06f543b7 100644 --- a/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino +++ b/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino @@ -12,151 +12,123 @@ ESP8266WebServer server(80); void connectToWiFi(const char* p_pcSSID, const char* p_pcPWD, - uint32_t p_u32Timeout = 20) -{ - WiFi.begin(p_pcSSID, p_pcPWD); + uint32_t p_u32Timeout = 20) { + WiFi.begin(p_pcSSID, p_pcPWD); + Serial.println(""); + + // Wait for connection + uint8 u8Tries = p_u32Timeout; + while ((WiFi.status() != WL_CONNECTED) && + (u8Tries--)) { + delay(500); + Serial.print("."); + } + if (WiFi.status() == WL_CONNECTED) { Serial.println(""); - - // Wait for connection - uint8 u8Tries = p_u32Timeout; - while ((WiFi.status() != WL_CONNECTED) && - (u8Tries--)) { - delay(500); - Serial.print("."); - } - if (WiFi.status() == WL_CONNECTED) - { - Serial.println(""); - Serial.print("Connected to "); - Serial.println(p_pcSSID); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - } - else - { - Serial.printf("FAILED to connect to '%s'!\n", p_pcSSID); - } + Serial.print("Connected to "); + Serial.println(p_pcSSID); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + } else { + Serial.printf("FAILED to connect to '%s'!\n", p_pcSSID); + } } -void setup(void) -{ - Serial.begin(115200); - Serial.setDebugOutput(false); - delay(2000); - Serial.printf("\nStart\n"); - - // Setup WiFi and AP - WiFi.setAutoConnect(false); - WiFi.mode(WIFI_AP_STA); - WiFi.softAP("ESP8266", "12345678"); - Serial.print("Created AP "); - Serial.println("ESP8266"); - Serial.print("AP-IP address: "); - Serial.println(WiFi.softAPIP()); - - if (mDNSHost_AP.begin("ESP8266", WIFI_AP, [](clsMDNSHost& p_rMDNSHost, - const char* p_pcDomainName, - bool p_bProbeResult)->void - { - Serial.printf("mDNSHost_AP::ProbeResultCallback: '%s' is %s\n", p_pcDomainName, (p_bProbeResult ? "FREE" : "USED!")); - - // Unattended added service - p_rMDNSHost.addService(0, "http", "tcp", 80); - })) - { - Serial.println("mDNS-AP started"); - } - else - { - Serial.println("FAILED to start mDNS-AP"); - } - - // Connect to WiFi network, with WRONG password - connectToWiFi("AP8", "WRONG_PW", 5); - - if (mDNSHost_STA.begin("esp8266", WIFI_STA, [](clsMDNSHost& p_rMDNSHost, - const char* p_pcDomainName, - bool p_bProbeResult)->void - { - Serial.printf("mDNSHost_STA::ProbeResultCallback: '%s' is %s\n", p_pcDomainName, (p_bProbeResult ? "FREE" : "USED!")); - if (p_bProbeResult) - { - p_rMDNSHost.addService("LEA_Weather", "http", "tcp", 80, [](clsMDNSHost::clsService& p_rService, - const char* p_pcInstanceName, - bool p_bProbeResult)->void - { - Serial.printf("mDNSHost_STA::HTTP-Service::ProbeResultCallback: '%s' is %s\n", p_pcInstanceName, (p_bProbeResult ? "FREE" : "USED!")); - if (p_bProbeResult) - { - if (!p_rService.addServiceTxt("path", "/")) - { - Serial.println("FAILED to add service TXT item!"); - } - p_rService.setDynamicServiceTxtCallback([](clsMDNSHost::clsService& p_rService)->void - { - Serial.printf("mDNSHost_STA::HTTP-Service::DynamicTXTCallback\n"); - - p_rService.addDynamicServiceTxt("user", "admin"); - static uint32_t u32Counter = 0; - p_rService.addDynamicServiceTxt("cnt", ++u32Counter); - }); - } - else - { - if (p_rService.indexInstanceName()) - { - Serial.printf("Changed service instance name to '%s'\n", p_rService.instanceName()); - } - else - { - Serial.println("FAILED to index service instance name!"); - } - } - }); - - // Unattended added service - p_rMDNSHost.addService("MQTTInstance", "mqtt", "tcp", 1883); - } - else - { - p_rMDNSHost.indexHostName(); - } - })) - { - Serial.println("mDNS-STA started"); - } - else - { - Serial.println("FAILED to start mDNS-STA"); +void setup(void) { + Serial.begin(115200); + Serial.setDebugOutput(false); + delay(2000); + Serial.printf("\nStart\n"); + + // Setup WiFi and AP + WiFi.setAutoConnect(false); + WiFi.mode(WIFI_AP_STA); + WiFi.softAP("ESP8266", "12345678"); + Serial.print("Created AP "); + Serial.println("ESP8266"); + Serial.print("AP-IP address: "); + Serial.println(WiFi.softAPIP()); + + if (mDNSHost_AP.begin("ESP8266", WIFI_AP, [](clsMDNSHost & p_rMDNSHost, + const char* p_pcDomainName, + bool p_bProbeResult)->void { + Serial.printf("mDNSHost_AP::ProbeResultCallback: '%s' is %s\n", p_pcDomainName, (p_bProbeResult ? "FREE" : "USED!")); + + // Unattended added service + p_rMDNSHost.addService(0, "http", "tcp", 80); + })) { + Serial.println("mDNS-AP started"); + } else { + Serial.println("FAILED to start mDNS-AP"); + } + + // Connect to WiFi network, with WRONG password + connectToWiFi("AP8", "WRONG_PW", 5); + + if (mDNSHost_STA.begin("esp8266", WIFI_STA, [](clsMDNSHost & p_rMDNSHost, + const char* p_pcDomainName, + bool p_bProbeResult)->void { + Serial.printf("mDNSHost_STA::ProbeResultCallback: '%s' is %s\n", p_pcDomainName, (p_bProbeResult ? "FREE" : "USED!")); + if (p_bProbeResult) { + p_rMDNSHost.addService("LEA_Weather", "http", "tcp", 80, [](clsMDNSHost::clsService & p_rService, + const char* p_pcInstanceName, + bool p_bProbeResult)->void { + Serial.printf("mDNSHost_STA::HTTP-Service::ProbeResultCallback: '%s' is %s\n", p_pcInstanceName, (p_bProbeResult ? "FREE" : "USED!")); + if (p_bProbeResult) { + if (!p_rService.addServiceTxt("path", "/")) { + Serial.println("FAILED to add service TXT item!"); + } + p_rService.setDynamicServiceTxtCallback([](clsMDNSHost::clsService & p_rService)->void { + Serial.printf("mDNSHost_STA::HTTP-Service::DynamicTXTCallback\n"); + + p_rService.addDynamicServiceTxt("user", "admin"); + static uint32_t u32Counter = 0; + p_rService.addDynamicServiceTxt("cnt", ++u32Counter); + }); + } else { + if (p_rService.indexInstanceName()) { + Serial.printf("Changed service instance name to '%s'\n", p_rService.instanceName()); + } else { + Serial.println("FAILED to index service instance name!"); + } + } + }); + + // Unattended added service + p_rMDNSHost.addService("MQTTInstance", "mqtt", "tcp", 1883); + } else { + p_rMDNSHost.indexHostName(); } - - // Non-synchronized added service - mDNSHost_STA.addService(0, "test", "tcp", 999); - - // Setup HTTP server - server.on("/", [](void) - { - Serial.println("server.on"); - server.send(200, "text/plain", "test"); - }); - server.begin(); - Serial.println("HTTP server started"); + })) { + Serial.println("mDNS-STA started"); + } else { + Serial.println("FAILED to start mDNS-STA"); + } + + // Non-synchronized added service + mDNSHost_STA.addService(0, "test", "tcp", 999); + + // Setup HTTP server + server.on("/", [](void) { + Serial.println("server.on"); + server.send(200, "text/plain", "test"); + }); + server.begin(); + Serial.println("HTTP server started"); } -void loop(void) -{ - server.handleClient(); - mDNSHost_AP.update(); - mDNSHost_STA.update(); +void loop(void) { + server.handleClient(); + mDNSHost_AP.update(); + mDNSHost_STA.update(); - static esp8266::polledTimeout::oneShotMs timer2(esp8266::polledTimeout::oneShotMs::alwaysExpired); - if (timer2) - { - Serial.println("FIX PASSWORD"); - connectToWiFi("AP8", "_______"); + static esp8266::polledTimeout::oneShotMs timer2(esp8266::polledTimeout::oneShotMs::alwaysExpired); + if (timer2) { + Serial.println("FIX PASSWORD"); + connectToWiFi("AP8", "_______"); - timer2.reset(esp8266::polledTimeout::oneShotMs::neverExpires); - } + timer2.reset(esp8266::polledTimeout::oneShotMs::neverExpires); + } } diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp index dd46d09ad3..cee90c907c 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp @@ -51,8 +51,8 @@ const char* strrstr(const char*__restrict p_pcString, size_t stPatternLength = (p_pcPattern ? strlen(p_pcPattern) : 0); if ((stStringLength) && - (stPatternLength) && - (stPatternLength <= stStringLength)) + (stPatternLength) && + (stPatternLength <= stStringLength)) { // Pattern is shorter or has the same length than the string for (const char* s = (p_pcString + stStringLength - stPatternLength); s >= p_pcString; --s) @@ -99,8 +99,8 @@ namespace experimental */ //static const char* clsLEAMDNSHost::indexDomainName(const char* p_pcDomainName, - const char* p_pcDivider /*= "-"*/, - const char* p_pcDefaultDomainName /*= 0*/) + const char* p_pcDivider /*= "-"*/, + const char* p_pcDefaultDomainName /*= 0*/) { static char acResultDomainName[clsConsts::stDomainLabelMaxLength]; *acResultDomainName = 0; @@ -117,8 +117,8 @@ const char* clsLEAMDNSHost::indexDomainName(const char* p_pcDomainName, char* pEnd = 0; unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10); if ((ulIndex) && - ((pEnd - p_pcDomainName) == (ptrdiff_t)strlen(p_pcDomainName)) && - (!*pEnd)) + ((pEnd - p_pcDomainName) == (ptrdiff_t)strlen(p_pcDomainName)) && + (!*pEnd)) { // Valid (old) index found char acIndexBuffer[16]; @@ -165,7 +165,7 @@ bool clsLEAMDNSHost::setNetIfHostName(netif* p_pNetIf, const char* p_pcHostName) { if ((p_pNetIf) && - (p_pcHostName)) + (p_pcHostName)) { netif_set_hostname(p_pNetIf, (char*)p_pcHostName); // LWIP 1.x forces 'char*' instead of 'const char*' DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[mDNS] setNetIfHostName host name: %s!\n"), p_pcHostName);); @@ -332,7 +332,7 @@ bool clsLEAMDNSHost::setHostName(const char* p_pcHostName) for (clsService* pService : m_Services) { if ((pService->m_bAutoName) && - (!m_pcDefaultInstanceName)) + (!m_pcDefaultInstanceName)) { if (!((bResult = pService->setInstanceName(p_pcHostName)))) { @@ -426,10 +426,10 @@ const char* clsLEAMDNSHost::defaultInstanceName(void) const */ clsLEAMDNSHost::clsService* clsLEAMDNSHost::addService(const char* p_pcInstanceName, - const char* p_pcType, - const char* p_pcProtocol, - uint16_t p_u16Port, - clsLEAMDNSHost::clsService::fnProbeResultCallback p_fnCallback /*= 0*/) + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port, + clsLEAMDNSHost::clsService::fnProbeResultCallback p_fnCallback /*= 0*/) { clsService* pService = 0; @@ -439,10 +439,10 @@ clsLEAMDNSHost::clsService* clsLEAMDNSHost::addService(const char* p_pcInstanceN if ((pService = new clsService)) { if ((pService->setInstanceName(_instanceName(p_pcInstanceName))) && - (pService->setType(p_pcType)) && - (pService->setProtocol(p_pcProtocol)) && - (pService->setPort(p_u16Port)) && - (p_fnCallback ? pService->setProbeResultCallback(p_fnCallback) : true)) + (pService->setType(p_pcType)) && + (pService->setProtocol(p_pcProtocol)) && + (pService->setPort(p_u16Port)) && + (p_fnCallback ? pService->setProbeResultCallback(p_fnCallback) : true)) { m_Services.push_back(pService); } @@ -482,19 +482,19 @@ bool clsLEAMDNSHost::removeService(clsLEAMDNSHost::clsService* p_pService) */ const clsLEAMDNSHost::clsService* clsLEAMDNSHost::findService(const char* p_pcInstanceName, - const char* p_pcType, - const char* p_pcProtocol, - uint16_t p_u16Port/*= (uint16_t)(-1)*/) const + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port/*= (uint16_t)(-1)*/) const { clsService* pFoundService = 0; for (clsService* pService : m_Services) { if ((0 == strcmp(pService->instanceName(), _instanceName(p_pcInstanceName))) && - (0 == strcmp(pService->type(), p_pcType)) && - (0 == strcmp(pService->protocol(), p_pcProtocol)) && - (((uint16_t)(-1) == p_u16Port) || - (pService->port() == p_u16Port))) + (0 == strcmp(pService->type(), p_pcType)) && + (0 == strcmp(pService->protocol(), p_pcProtocol)) && + (((uint16_t)(-1) == p_u16Port) || + (pService->port() == p_u16Port))) { pFoundService = pService; break; @@ -508,20 +508,20 @@ const clsLEAMDNSHost::clsService* clsLEAMDNSHost::findService(const char* p_pcIn */ clsLEAMDNSHost::clsService* clsLEAMDNSHost::findService(const char* p_pcInstanceName, - const char* p_pcType, - const char* p_pcProtocol, - uint16_t p_u16Port /*= (uint16_t)(-1)*/) + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port /*= (uint16_t)(-1)*/) { return (clsService*)((const clsLEAMDNSHost*)this)->findService(p_pcInstanceName, p_pcType, p_pcProtocol, p_u16Port); } /* clsLEAMDNSHost::services - + */ const clsLEAMDNSHost::clsService::list& clsLEAMDNSHost::services(void) const { - return m_Services; + return m_Services; } @@ -536,21 +536,21 @@ const clsLEAMDNSHost::clsService::list& clsLEAMDNSHost::services(void) const */ clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector clsLEAMDNSHost::queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout) + const char* p_pcProtocol, + const uint16_t p_u16Timeout) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local'\n"), _DH(), p_pcService, p_pcProtocol);); clsQuery* pQuery = 0; if ((p_pcService) && (*p_pcService) && - (p_pcProtocol) && (*p_pcProtocol) && - (p_u16Timeout) && - ((pQuery = _allocQuery(clsQuery::enuQueryType::Service))) && - (_buildDomainForService(p_pcService, p_pcProtocol, pQuery->m_Domain))) + (p_pcProtocol) && (*p_pcProtocol) && + (p_u16Timeout) && + ((pQuery = _allocQuery(clsQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pQuery->m_Domain))) { if ((_removeLegacyQuery()) && - ((pQuery->m_bStaticQuery = true)) && - (_sendQuery(*pQuery))) + ((pQuery->m_bStaticQuery = true)) && + (_sendQuery(*pQuery))) { // Wait for answers to arrive DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); @@ -579,19 +579,19 @@ clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector clsLEAMDNSHost::queryService */ clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector clsLEAMDNSHost::queryHost(const char* p_pcHostName, - const uint16_t p_u16Timeout) + const uint16_t p_u16Timeout) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local'\n"), _DH(), p_pcHostName);); clsQuery* pQuery = 0; if ((p_pcHostName) && (*p_pcHostName) && - (p_u16Timeout) && - ((pQuery = _allocQuery(clsQuery::enuQueryType::Host))) && - (_buildDomainForHost(p_pcHostName, pQuery->m_Domain))) + (p_u16Timeout) && + ((pQuery = _allocQuery(clsQuery::enuQueryType::Host))) && + (_buildDomainForHost(p_pcHostName, pQuery->m_Domain))) { if ((_removeLegacyQuery()) && - ((pQuery->m_bStaticQuery = true)) && - (_sendQuery(*pQuery))) + ((pQuery->m_bStaticQuery = true)) && + (_sendQuery(*pQuery))) { // Wait for answers to arrive DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); @@ -647,8 +647,8 @@ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::getQuery(void) */ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - clsLEAMDNSHost::clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer) + const char* p_pcProtocol, + clsLEAMDNSHost::clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer) { clsQuery* pQuery = 0; if ((pQuery = _installServiceQuery(p_pcService, p_pcProtocol))) @@ -663,8 +663,8 @@ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installServiceQuery(const char* p_pcSe */ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - clsLEAMDNSHost::clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor) + const char* p_pcProtocol, + clsLEAMDNSHost::clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor) { clsQuery* pQuery = 0; if ((pQuery = _installServiceQuery(p_pcService, p_pcProtocol))) @@ -678,7 +678,7 @@ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installServiceQuery(const char* p_pcSe clsLEAmDNS2_Host::installHostQuery (answer) */ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installHostQuery(const char* p_pcHostName, - clsLEAMDNSHost::clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer) + clsLEAMDNSHost::clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer) { clsQuery* pQuery = 0; if ((p_pcHostName) && (*p_pcHostName)) @@ -698,7 +698,7 @@ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installHostQuery(const char* p_pcHostN clsLEAmDNS2_Host::installHostQuery (accessor) */ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installHostQuery(const char* p_pcHostName, - clsLEAMDNSHost::clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor) + clsLEAMDNSHost::clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor) { clsQuery* pQuery = 0; if ((p_pcHostName) && (*p_pcHostName)) @@ -803,7 +803,7 @@ UdpContext* clsLEAMDNSHost::_allocBackbone(void) DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocBackbone: Created backbone.\n"), _DH());); if ((clsBackbone::sm_pBackbone) && - (!clsBackbone::sm_pBackbone->init())) + (!clsBackbone::sm_pBackbone->init())) { DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocBackbone: FAILED to init backbone!\n"), _DH());); @@ -828,8 +828,8 @@ bool clsLEAMDNSHost::_releaseBackbone(void) bool bResult = false; if ((clsBackbone::sm_pBackbone) && - ((bResult = clsBackbone::sm_pBackbone->removeHost(this))) && - (0 == clsBackbone::sm_pBackbone->hostCount())) + ((bResult = clsBackbone::sm_pBackbone->removeHost(this))) && + (0 == clsBackbone::sm_pBackbone->hostCount())) { delete clsBackbone::sm_pBackbone; clsBackbone::sm_pBackbone = 0; @@ -945,14 +945,14 @@ clsLEAMDNSHost::typeNetIfState clsLEAMDNSHost::_getNetIfState(void) const typeNetIfState curNetIfState = static_cast(enuNetIfState::None); if ((m_pNetIf) && - (netif_is_up(m_pNetIf))) + (netif_is_up(m_pNetIf))) { curNetIfState |= static_cast(enuNetIfState::IsUp); // Check if netif link is up if ((netif_is_link_up(m_pNetIf)) && - ((m_pNetIf != netif_get_by_index(WIFI_STA)) || - (STATION_GOT_IP == wifi_station_get_connect_status()))) + ((m_pNetIf != netif_get_by_index(WIFI_STA)) || + (STATION_GOT_IP == wifi_station_get_connect_status()))) { curNetIfState |= static_cast(enuNetIfState::LinkIsUp); } @@ -1084,7 +1084,7 @@ bool clsLEAMDNSHost::_allocDomainName(const char* p_pcNewDomainName, size_t stLength = 0; if ((p_pcNewDomainName) && - (clsConsts::stDomainLabelMaxLength >= (stLength = strlen(p_pcNewDomainName)))) // char max size for a single label + (clsConsts::stDomainLabelMaxLength >= (stLength = strlen(p_pcNewDomainName)))) // char max size for a single label { // Copy in hostname characters as lowercase if ((bResult = (0 != (p_rpcDomainName = new char[stLength + 1])))) @@ -1156,7 +1156,7 @@ bool clsLEAMDNSHost::_releaseDefaultInstanceName(void) clsLEAmDNS2_Host::_instanceName */ const char* clsLEAMDNSHost::_instanceName(const char* p_pcInstanceName, - bool p_bReturnZero /*= true*/) const + bool p_bReturnZero /*= true*/) const { return (p_pcInstanceName ? : (m_pcDefaultInstanceName ? : (m_pcHostName ? : (p_bReturnZero ? 0 : "-")))); } @@ -1283,8 +1283,8 @@ bool clsLEAMDNSHost::_releaseQueries(void) */ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_findNextQueryByDomain(const clsLEAMDNSHost::clsRRDomain& p_Domain, - const clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType, - const clsQuery* p_pPrevQuery) + const clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType, + const clsQuery* p_pPrevQuery) { clsQuery* pMatchingQuery = 0; @@ -1292,17 +1292,21 @@ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_findNextQueryByDomain(const clsLEAMDN if (p_pPrevQuery) { if (m_Queries.end() != ((it = std::find(m_Queries.begin(), m_Queries.end(), p_pPrevQuery)))) - { // Found previous object + { + // Found previous object it++; } - DEBUG_EX_ERR(else DEBUG_OUTPUT.printf_P(PSTR("%s _findNextQueryByDomain: FAILED to find 'previous' object!\n"), _DH());); // if not prev was found -> 'cancel' + DEBUG_EX_ERR(else + { + DEBUG_OUTPUT.printf_P(PSTR("%s _findNextQueryByDomain: FAILED to find 'previous' object!\n"), _DH()); + }); // if not prev was found -> 'cancel' } for (; it != m_Queries.end(); it++) { if (((clsQuery::enuQueryType::None == p_QueryType) || - ((*it)->m_QueryType == p_QueryType)) && - (p_Domain == (*it)->m_Domain)) + ((*it)->m_QueryType == p_QueryType)) && + (p_Domain == (*it)->m_Domain)) { pMatchingQuery = *it; break; @@ -1316,14 +1320,14 @@ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_findNextQueryByDomain(const clsLEAMDN */ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_installServiceQuery(const char* p_pcService, - const char* p_pcProtocol) + const char* p_pcProtocol) { clsQuery* pMDNSQuery = 0; if ((p_pcService) && (*p_pcService) && - (p_pcProtocol) && (*p_pcProtocol) && - ((pMDNSQuery = _allocQuery(clsQuery::enuQueryType::Service))) && - (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) + (p_pcProtocol) && (*p_pcProtocol) && + ((pMDNSQuery = _allocQuery(clsQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) { pMDNSQuery->m_bStaticQuery = false; @@ -1346,7 +1350,7 @@ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_installServiceQuery(const char* p_pcS clsLEAmDNS2_Host::_installDomainQuery */ clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_installDomainQuery(clsLEAMDNSHost::clsRRDomain& p_Domain, - clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType) + clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType) { clsQuery* pQuery = 0; @@ -1402,9 +1406,9 @@ bool clsLEAMDNSHost::_hasQueriesWaitingForAnswers(void) const clsLEAmDNS2_Host::_executeQueryCallback */ bool clsLEAMDNSHost::_executeQueryCallback(const clsQuery& p_Query, - const clsQuery::clsAnswer& p_Answer, - clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, - bool p_bSetContent) + const clsQuery::clsAnswer& p_Answer, + clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_bSetContent) { if (p_Query.m_fnCallbackAnswer) { diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host.h b/libraries/ESP8266mDNS/src/LEAmDNS2Host.h index 5a63d1f59e..ff590473c7 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host.h @@ -465,8 +465,8 @@ class clsLEAMDNSHost Callback function for host domain probe results */ using fnProbeResultCallback = std::function; + const char* p_pcDomainName, + bool p_bProbeResult)>; protected: /** @@ -498,8 +498,8 @@ class clsLEAMDNSHost fnProbeResultCallback */ using fnProbeResultCallback = std::function; + const char* p_pcInstanceName, + bool p_bProbeResult)>; protected: friend clsLEAMDNSHost; @@ -1188,16 +1188,16 @@ class clsLEAMDNSHost QueryCallbackAnswerFn */ using QueryCallbackAnswerFn = std::function; // true: Answer component set, false: component deleted + const clsAnswer& p_Answer, + clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, // flags for the updated answer item + bool p_bSetContent)>; // true: Answer component set, false: component deleted /** QueryCallbackAccessorFn */ using QueryCallbackAccessorFn = std::function; // true: Answer component set, false: component deleted + const clsAnswerAccessor& p_AnswerAccessor, + clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, // flags for the updated answer item + bool p_bSetContent)>; // true: Answer component set, false: component deleted protected: friend clsLEAMDNSHost; @@ -1292,7 +1292,7 @@ class clsLEAMDNSHost const char* p_pcType, const char* p_pcProtocol, uint16_t p_u16Port = (uint16_t)(-1)); - const clsService::list& services(void) const; + const clsService::list& services(void) const; // QUERIES @@ -1303,10 +1303,10 @@ class clsLEAMDNSHost // - answerIP (or IP) // - answerPort (or port) clsQuery::clsAnswerAccessor::vector queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout); + const char* p_pcProtocol, + const uint16_t p_u16Timeout); clsQuery::clsAnswerAccessor::vector queryHost(const char* p_pcHostName, - const uint16_t p_u16Timeout); + const uint16_t p_u16Timeout); bool removeQuery(void); bool hasQuery(void); clsQuery* getQuery(void); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp index 11fece09c1..efc9d1879e 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp @@ -133,8 +133,8 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader // Define host replies, BUT only answer queries after probing is done u32HostOrServiceReplies = sendParameter.m_u32HostReplyMask |= ((probeStatus()) - ? _replyMaskForHost(questionRR.m_Header, 0) - : 0); + ? _replyMaskForHost(questionRR.m_Header, 0) + : 0); DEBUG_EX_INFO(if (u32HostOrServiceReplies) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Host reply needed %s\n"), _DH(), _replyFlags2String(u32HostOrServiceReplies));); // Check tiebreak need for host domain @@ -142,7 +142,7 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader { bool bFullNameMatch = false; if ((_replyMaskForHost(questionRR.m_Header, &bFullNameMatch)) && - (bFullNameMatch)) + (bFullNameMatch)) { // We're in 'probing' state and someone is asking for our host domain: this might be // a race-condition: Two hosts with the same domain names try simutanously to probe their domains @@ -172,7 +172,7 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader { bool bFullNameMatch = false; if ((_replyMaskForService(questionRR.m_Header, *pService, &bFullNameMatch)) && - (bFullNameMatch)) + (bFullNameMatch)) { // We're in 'probing' state and someone is asking for this service domain: this might be // a race-condition: Two services with the same domain names try simutanously to probe their domains @@ -189,8 +189,8 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader // Handle unicast and legacy specialities // If only one question asks for unicast reply, the whole reply packet is send unicast if (((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) || // Unicast (maybe legacy) query OR - (questionRR.m_bUnicast)) && // Expressivly unicast query - (!sendParameter.m_bUnicast)) + (questionRR.m_bUnicast)) && // Expressivly unicast query + (!sendParameter.m_bUnicast)) { sendParameter.m_bUnicast = true; //sendParameter.m_bCacheFlush = false; @@ -198,9 +198,9 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader //Serial.printf_P(PSTR("%s _parseQuery: Ignored Unicast response asked for by %s!\n"), _DH(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()); if ((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) && // Unicast (maybe legacy) query AND - (1 == p_MsgHeader.m_u16QDCount) && // Only one question AND - ((sendParameter.m_u32HostReplyMask) || // Host replies OR - (u32HostOrServiceReplies))) // Host or service replies available + (1 == p_MsgHeader.m_u16QDCount) && // Only one question AND + ((sendParameter.m_u32HostReplyMask) || // Host replies OR + (u32HostOrServiceReplies))) // Host or service replies available { // Local host check // We're a match for this legacy query, BUT @@ -209,20 +209,20 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader ip_info IPInfo_Local; #endif if ((m_pNetIf) && - (m_pUDPContext) && + (m_pUDPContext) && #ifdef MDNS_IPV4_SUPPORT - (m_pUDPContext->getRemoteAddress().isV4()) && - ((wifi_get_ip_info(netif_get_index(m_pNetIf), &IPInfo_Local))) && - (ip4_addr_netcmp(ip_2_ip4((const ip_addr_t*)m_pUDPContext->getRemoteAddress()), &IPInfo_Local.ip, &IPInfo_Local.netmask)) + (m_pUDPContext->getRemoteAddress().isV4()) && + ((wifi_get_ip_info(netif_get_index(m_pNetIf), &IPInfo_Local))) && + (ip4_addr_netcmp(ip_2_ip4((const ip_addr_t*)m_pUDPContext->getRemoteAddress()), &IPInfo_Local.ip, &IPInfo_Local.netmask)) #else - (true) + (true) #endif - && + && #ifdef MDNS_IPV6_SUPPORT - (m_pUDPContext->getRemoteAddress().isV6()) && - (ip6_addr_islinklocal(ip_2_ip6((const ip_addr_t*)m_pUDPContext->getRemoteAddress()))) + (m_pUDPContext->getRemoteAddress().isV6()) && + (ip6_addr_islinklocal(ip_2_ip6((const ip_addr_t*)m_pUDPContext->getRemoteAddress()))) #else - (true) + (true) #endif ) { @@ -275,8 +275,8 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader // Handle known answers uint32_t u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); if (((u32HostOrServiceReplies) || - (bHostOrServiceTiebreakNeeded)) && - (u32Answers)) + (bHostOrServiceTiebreakNeeded)) && + (u32Answers)) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Reading known answers(%u):\n"), _DH(), u32Answers);); @@ -284,10 +284,10 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader { clsRRAnswer* pKnownRRAnswer = 0; if (((bResult = _readRRAnswer(pKnownRRAnswer))) && - (pKnownRRAnswer)) + (pKnownRRAnswer)) { if ((DNS_RRTYPE_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Type) && // No ANY type answer - (DNS_RRCLASS_ANY != (pKnownRRAnswer->m_Header.m_Attributes.m_u16Class & (~0x8000)))) // No ANY class answer + (DNS_RRCLASS_ANY != (pKnownRRAnswer->m_Header.m_Attributes.m_u16Class & (~0x8000)))) // No ANY class answer { /* - RFC6762 7.1 Suppression only for 'Shared Records' - // Find match between planned answer (sendParameter.m_u8HostReplyMask) and this 'known answer' @@ -357,7 +357,7 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader { clsRRDomain hostDomain; if ((_buildDomainForHost(m_pcHostName, hostDomain)) && - (pKnownRRAnswer->m_Header.m_Domain == hostDomain)) + (pKnownRRAnswer->m_Header.m_Domain == hostDomain)) { // Host domain match #ifdef MDNS_IPV4_SUPPORT @@ -429,21 +429,21 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader uint32_t u32ServiceMatchMask = (pService->m_u32ReplyMask & _replyMaskForService(pKnownRRAnswer->m_Header, *pService)); if ((u32ServiceMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND - ((clsConsts::u32ServiceTTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) + ((clsConsts::u32ServiceTTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) { if (enuAnswerType::PTR == pKnownRRAnswer->answerType()) { clsRRDomain serviceDomain; if ((u32ServiceMatchMask & static_cast(enuContentFlag::PTR_TYPE)) && - (_buildDomainForService(*pService, false, serviceDomain)) && - (serviceDomain == ((clsRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + (_buildDomainForService(*pService, false, serviceDomain)) && + (serviceDomain == ((clsRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service type PTR already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::PTR_TYPE); } if ((u32ServiceMatchMask & static_cast(enuContentFlag::PTR_NAME)) && - (_buildDomainForService(*pService, true, serviceDomain)) && - (serviceDomain == ((clsRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + (_buildDomainForService(*pService, true, serviceDomain)) && + (serviceDomain == ((clsRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service name PTR already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::PTR_NAME); @@ -488,14 +488,14 @@ bool clsLEAMDNSHost::_parseQuery(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader { clsRRDomain serviceDomain; if ((_buildDomainForService(*pService, true, serviceDomain)) && - (pKnownRRAnswer->m_Header.m_Domain == serviceDomain)) + (pKnownRRAnswer->m_Header.m_Domain == serviceDomain)) { // Service domain match if (enuAnswerType::SRV == pKnownRRAnswer->answerType()) { clsRRDomain hostDomain; if ((_buildDomainForHost(m_pcHostName, hostDomain)) && - (hostDomain == ((clsRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + (hostDomain == ((clsRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match { // We've received an old message from ourselfs (same SRV) DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) won (was an old message)!\n"), _DH(pService));); @@ -626,7 +626,7 @@ bool clsLEAMDNSHost::_parseResponse(const clsLEAMDNSHost::clsMsgHeader& p_MsgHea // A response should be the result of a query or a probe if ((_hasQueriesWaitingForAnswers()) || // Waiting for query answers OR - (_hasProbesWaitingForAnswers())) // Probe responses + (_hasProbesWaitingForAnswers())) // Probe responses { DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received a response\n"), _DH()); @@ -651,7 +651,7 @@ bool clsLEAMDNSHost::_parseResponse(const clsLEAMDNSHost::clsMsgHeader& p_MsgHea { clsRRAnswer* pRRAnswer = 0; if (((bResult = _readRRAnswer(pRRAnswer))) && - (pRRAnswer)) + (pRRAnswer)) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: ADDING answer!\n"));); pRRAnswer->m_pNext = pCollectedRRAnswers; @@ -753,36 +753,41 @@ bool clsLEAMDNSHost::_processAnswers(const clsLEAMDNSHost::clsRRAnswer* p_pAnswe const clsRRAnswer* pRRAnswer = p_pAnswers; while ((pRRAnswer) && - (bResult)) + (bResult)) { // 1. level answer (PTR) if (enuAnswerType::PTR == pRRAnswer->answerType()) - { // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + { + // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local bResult = _processPTRAnswer((clsRRAnswerPTR*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new SRV or TXT answers to be linked to queries } // 2. level answers // SRV -> host domain and port else if (enuAnswerType::SRV == pRRAnswer->answerType()) - { // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + { + // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local bResult = _processSRVAnswer((clsRRAnswerSRV*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new A/AAAA answers to be linked to queries } // TXT -> Txts else if (enuAnswerType::TXT == pRRAnswer->answerType()) - { // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 + { + // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 bResult = _processTXTAnswer((clsRRAnswerTXT*)pRRAnswer); } // 3. level answers #ifdef MDNS_IPV4_SUPPORT // A -> IPv4Address else if (enuAnswerType::A == pRRAnswer->answerType()) - { // eg. esp8266.local A xxxx xx 192.168.2.120 + { + // eg. esp8266.local A xxxx xx 192.168.2.120 bResult = _processAAnswer((clsRRAnswerA*)pRRAnswer); } #endif #ifdef MDNS_IPV6_SUPPORT // AAAA -> IPv6Address else if (enuAnswerType::AAAA == pRRAnswer->answerType()) - { // eg. esp8266.local AAAA xxxx xx 09cf::0c + { + // eg. esp8266.local AAAA xxxx xx 09cf::0c bResult = _processAAAAAnswer((clsRRAnswerAAAA*)pRRAnswer); } #endif @@ -790,24 +795,24 @@ bool clsLEAMDNSHost::_processAnswers(const clsLEAMDNSHost::clsRRAnswer* p_pAnswe // Finally check for probing conflicts // Host domain if ((clsProbeInformation_Base::enuProbingStatus::InProgress == m_ProbeInformation.m_ProbingStatus) && - ((enuAnswerType::A == pRRAnswer->answerType()) || - (enuAnswerType::AAAA == pRRAnswer->answerType()))) + ((enuAnswerType::A == pRRAnswer->answerType()) || + (enuAnswerType::AAAA == pRRAnswer->answerType()))) { clsRRDomain hostDomain; if ((_buildDomainForHost(m_pcHostName, hostDomain)) && - (pRRAnswer->m_Header.m_Domain == hostDomain)) + (pRRAnswer->m_Header.m_Domain == hostDomain)) { bool bPossibleEcho = false; #ifdef MDNS_IPV4_SUPPORT if ((enuAnswerType::A == pRRAnswer->answerType()) && - (((clsRRAnswerA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V4))) + (((clsRRAnswerA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V4))) { bPossibleEcho = true; } #endif #ifdef MDNS_IPV6_SUPPORT if ((enuAnswerType::AAAA == pRRAnswer->answerType()) && - (((clsRRAnswerAAAA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V6))) + (((clsRRAnswerAAAA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(enuIPProtocolType::V6))) { bPossibleEcho = true; } @@ -828,12 +833,12 @@ bool clsLEAMDNSHost::_processAnswers(const clsLEAMDNSHost::clsRRAnswer* p_pAnswe for (clsService* pService : m_Services) { if ((clsProbeInformation_Base::enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && - ((enuAnswerType::TXT == pRRAnswer->answerType()) || - (enuAnswerType::SRV == pRRAnswer->answerType()))) + ((enuAnswerType::TXT == pRRAnswer->answerType()) || + (enuAnswerType::SRV == pRRAnswer->answerType()))) { clsRRDomain serviceDomain; if ((_buildDomainForService(*pService, true, serviceDomain)) && - (pRRAnswer->m_Header.m_Domain == serviceDomain)) + (pRRAnswer->m_Header.m_Domain == serviceDomain)) { // TODO: Echo management needed? DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s'\n"), _DH(), _service2String(pService));); @@ -870,12 +875,15 @@ bool clsLEAMDNSHost::_processPTRAnswer(const clsLEAMDNSHost::clsRRAnswerPTR* p_p while (pQuery) { if (pQuery->m_bAwaitingAnswers) - { // Find answer for service domain (eg. MyESP._http._tcp.local) + { + // Find answer for service domain (eg. MyESP._http._tcp.local) clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pPTRAnswer->m_PTRDomain); if (pSQAnswer) - { // existing answer + { + // existing answer if (p_pPTRAnswer->m_u32TTL) - { // Received update message + { + // Received update message pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); // Update TTL tag DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: Updated TTL(%lu) for "), _DH(), p_pPTRAnswer->m_u32TTL); @@ -884,7 +892,8 @@ bool clsLEAMDNSHost::_processPTRAnswer(const clsLEAMDNSHost::clsRRAnswerPTR* p_p ); } else - { // received goodbye-message + { + // received goodbye-message pSQAnswer->m_TTLServiceDomain.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: 'Goodbye' received for "), _DH()); @@ -942,7 +951,8 @@ bool clsLEAMDNSHost::_processSRVAnswer(const clsLEAMDNSHost::clsRRAnswerSRV* p_p { // Answer for this service domain (eg. MyESP._http._tcp.local) available if (p_pSRVAnswer->m_u32TTL) - { // First or update message (TTL != 0) + { + // First or update message (TTL != 0) pSQAnswer->m_TTLHostDomainAndPort.set(p_pSRVAnswer->m_u32TTL); // Update TTL tag DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: Updated TTL(%lu) for "), _DH(), p_pSRVAnswer->m_u32TTL); @@ -951,7 +961,7 @@ bool clsLEAMDNSHost::_processSRVAnswer(const clsLEAMDNSHost::clsRRAnswerSRV* p_p ); // Host domain & Port if ((pSQAnswer->m_HostDomain != p_pSRVAnswer->m_SRVDomain) || - (pSQAnswer->m_u16Port != p_pSRVAnswer->m_u16Port)) + (pSQAnswer->m_u16Port != p_pSRVAnswer->m_u16Port)) { pSQAnswer->m_HostDomain = p_pSRVAnswer->m_SRVDomain; @@ -972,7 +982,8 @@ bool clsLEAMDNSHost::_processSRVAnswer(const clsLEAMDNSHost::clsRRAnswerSRV* p_p } } else - { // Goodby message + { + // Goodby message pSQAnswer->m_TTLHostDomainAndPort.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: 'Goodbye' received for "), _DH()); @@ -1006,9 +1017,11 @@ bool clsLEAMDNSHost::_processTXTAnswer(const clsLEAMDNSHost::clsRRAnswerTXT* p_p { clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pTXTAnswer->m_Header.m_Domain); if (pSQAnswer) - { // Answer for this service domain (eg. MyESP._http._tcp.local) available + { + // Answer for this service domain (eg. MyESP._http._tcp.local) available if (p_pTXTAnswer->m_u32TTL) - { // First or update message + { + // First or update message pSQAnswer->m_TTLTxts.set(p_pTXTAnswer->m_u32TTL); // Update TTL tag DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: Updated TTL(%lu) for "), _DH(), p_pTXTAnswer->m_u32TTL); @@ -1031,7 +1044,8 @@ bool clsLEAMDNSHost::_processTXTAnswer(const clsLEAMDNSHost::clsRRAnswerTXT* p_p } } else - { // Goodby message + { + // Goodby message pSQAnswer->m_TTLTxts.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: 'Goodbye' received for "), _DH()); @@ -1063,15 +1077,17 @@ bool clsLEAMDNSHost::_processAAnswer(const clsLEAMDNSHost::clsRRAnswerA* p_pAAns clsQuery* pQuery = *it; if (pQuery->m_bAwaitingAnswers) - { // Look for answers to host queries + { + // Look for answers to host queries if ((p_pAAnswer->m_u32TTL) && // NOT just a goodbye message - (clsQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query - (pQuery->m_Domain == p_pAAnswer->m_Header.m_Domain)) // AND a matching host domain + (clsQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query + (pQuery->m_Domain == p_pAAnswer->m_Header.m_Domain)) // AND a matching host domain { clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); if ((!pSQAnswer) && - ((pSQAnswer = new clsQuery::clsAnswer))) - { // Add not yet included answer + ((pSQAnswer = new clsQuery::clsAnswer))) + { + // Add not yet included answer pSQAnswer->m_HostDomain = p_pAAnswer->m_Header.m_Domain; //pSQAnswer->releaseHostDomain(); @@ -1090,12 +1106,15 @@ bool clsLEAMDNSHost::_processAAnswer(const clsLEAMDNSHost::clsRRAnswerA* p_pAAns // Look for answers to service queries clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); if (pSQAnswer) - { // Answer for this host domain (eg. esp8266.local) available + { + // Answer for this host domain (eg. esp8266.local) available clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddress = pSQAnswer->findIPv4Address(p_pAAnswer->m_IPAddress); if (pIPAddress) - { // Already known IPv4 address + { + // Already known IPv4 address if (p_pAAnswer->m_u32TTL) - { // Valid TTL -> Update answers TTL + { + // Valid TTL -> Update answers TTL pIPAddress->m_TTL.set(p_pAAnswer->m_u32TTL); DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Updated TTL(%lu) for "), _DH(), p_pAAnswer->m_u32TTL); @@ -1104,7 +1123,8 @@ bool clsLEAMDNSHost::_processAAnswer(const clsLEAMDNSHost::clsRRAnswerA* p_pAAns ); } else - { // 'Goodbye' message for known IPv4 address + { + // 'Goodbye' message for known IPv4 address pIPAddress->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: 'Goodbye' received for "), _DH()); @@ -1114,12 +1134,14 @@ bool clsLEAMDNSHost::_processAAnswer(const clsLEAMDNSHost::clsRRAnswerA* p_pAAns } } else - { // Until now unknown IPv4 address -> Add (if the message isn't just a 'Goodbye' note) + { + // Until now unknown IPv4 address -> Add (if the message isn't just a 'Goodbye' note) if (p_pAAnswer->m_u32TTL) - { // NOT just a 'Goodbye' message + { + // NOT just a 'Goodbye' message pIPAddress = new clsQuery::clsAnswer::clsIPAddressWithTTL(p_pAAnswer->m_IPAddress, p_pAAnswer->m_u32TTL); if ((pIPAddress) && - (pSQAnswer->addIPv4Address(pIPAddress))) + (pSQAnswer->addIPv4Address(pIPAddress))) { DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Added IPv4 address to "), _DH()); @@ -1161,15 +1183,17 @@ bool clsLEAMDNSHost::_processAAAAAnswer(const clsLEAMDNSHost::clsRRAnswerAAAA* p clsQuery* pQuery = *it; if (pQuery->m_bAwaitingAnswers) - { // Look for answers to host queries + { + // Look for answers to host queries if ((p_pAAAAAnswer->m_u32TTL) && // NOT just a goodbye message - (clsQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query - (pQuery->m_Domain == p_pAAAAAnswer->m_Header.m_Domain)) // AND a matching host domain + (clsQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query + (pQuery->m_Domain == p_pAAAAAnswer->m_Header.m_Domain)) // AND a matching host domain { clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); if ((!pSQAnswer) && - ((pSQAnswer = new clsQuery::clsAnswer))) - { // Add not yet included answer + ((pSQAnswer = new clsQuery::clsAnswer))) + { + // Add not yet included answer pSQAnswer->m_HostDomain = p_pAAAAAnswer->m_Header.m_Domain; //pSQAnswer->releaseHostDomain(); @@ -1191,9 +1215,11 @@ bool clsLEAMDNSHost::_processAAAAAnswer(const clsLEAMDNSHost::clsRRAnswerAAAA* p { clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddress = pSQAnswer->findIPv6Address(p_pAAAAAnswer->m_IPAddress); if (pIPAddress) - { // Already known IPv6 address + { + // Already known IPv6 address if (p_pAAAAAnswer->m_u32TTL) - { // Valid TTL -> Update answers TTL + { + // Valid TTL -> Update answers TTL pIPAddress->m_TTL.set(p_pAAAAAnswer->m_u32TTL); DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Updated TTL(%lu) for "), _DH(), p_pAAAAAnswer->m_u32TTL); @@ -1202,7 +1228,8 @@ bool clsLEAMDNSHost::_processAAAAAnswer(const clsLEAMDNSHost::clsRRAnswerAAAA* p ); } else - { // 'Goodbye' message for known IPv6 address + { + // 'Goodbye' message for known IPv6 address pIPAddress->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: 'Goodbye' received for "), _DH()); @@ -1212,13 +1239,14 @@ bool clsLEAMDNSHost::_processAAAAAnswer(const clsLEAMDNSHost::clsRRAnswerAAAA* p } } else - { // Until now unknown IPv6 address -> Add (if the message isn't just a 'Goodbye' note) + { + // Until now unknown IPv6 address -> Add (if the message isn't just a 'Goodbye' note) if (p_pAAAAAnswer->m_u32TTL) { // NOT just a 'Goodbye' message pIPAddress = new clsQuery::clsAnswer::clsIPAddressWithTTL(p_pAAAAAnswer->m_IPAddress, p_pAAAAAnswer->m_u32TTL); if ((pIPAddress) && - (pSQAnswer->addIPv6Address(pIPAddress))) + (pSQAnswer->addIPv6Address(pIPAddress))) { DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Added IPv6 address to "), _DH()); @@ -1270,19 +1298,19 @@ bool clsLEAMDNSHost::_updateProbeStatus(void) // // Probe host domain if ((clsProbeInformation_Base::enuProbingStatus::ReadyToStart == m_ProbeInformation.m_ProbingStatus) && // Ready to get started AND - (( + (( #ifdef MDNS_IPV4_SUPPORT - _getResponderIPAddress(enuIPProtocolType::V4).isSet() // AND has IPv4 address + _getResponderIPAddress(enuIPProtocolType::V4).isSet() // AND has IPv4 address #else - true + true #endif - ) || ( + ) || ( #ifdef MDNS_IPV6_SUPPORT - _getResponderIPAddress(enuIPProtocolType::V6).isSet() // OR has IPv6 address + _getResponderIPAddress(enuIPProtocolType::V6).isSet() // OR has IPv6 address #else - true + true #endif - ))) // Has IP address + ))) // Has IP address { DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Starting host probing...\n"), _DH());); @@ -1476,7 +1504,7 @@ bool clsLEAMDNSHost::_sendHostProbe(void) clsRRQuestion* pNewRRQuestion = new clsRRQuestion; if (((bResult = (0 != pNewRRQuestion))) && - ((bResult = _buildDomainForHost(m_pcHostName, pNewRRQuestion->m_Header.m_Domain)))) + ((bResult = _buildDomainForHost(m_pcHostName, pNewRRQuestion->m_Header.m_Domain)))) { //sendParameter.m_pQuestions->m_bUnicast = true; pNewRRQuestion->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; @@ -1531,7 +1559,7 @@ bool clsLEAMDNSHost::_sendServiceProbe(clsService& p_rService) clsRRQuestion* pNewRRQuestion = new clsRRQuestion; if (((bResult = (0 != pNewRRQuestion))) && - ((bResult = _buildDomainForService(p_rService, true, pNewRRQuestion->m_Header.m_Domain)))) + ((bResult = _buildDomainForService(p_rService, true, pNewRRQuestion->m_Header.m_Domain)))) { pNewRRQuestion->m_bUnicast = true; pNewRRQuestion->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; @@ -1612,7 +1640,7 @@ bool clsLEAMDNSHost::_callHostProbeResultCallback(bool p_bResult) */ bool clsLEAMDNSHost::_callServiceProbeResultCallback(clsLEAMDNSHost::clsService& p_rService, - bool p_bResult) + bool p_bResult) { if (p_rService.m_ProbeInformation.m_fnProbeResultCallback) { @@ -1763,7 +1791,7 @@ bool clsLEAMDNSHost::_checkQueryCache(void) // // Resend dynamic queries, if not already done often enough if ((!pQuery->m_bStaticQuery) && - (pQuery->m_ResendTimeout.expired())) + (pQuery->m_ResendTimeout.expired())) { if ((bResult = _sendQuery(*pQuery))) { @@ -1794,7 +1822,7 @@ bool clsLEAMDNSHost::_checkQueryCache(void) // 1. level answer if ((bResult) && - (pQAnswer->m_TTLServiceDomain.flagged())) + (pQAnswer->m_TTLServiceDomain.flagged())) { if (!pQAnswer->m_TTLServiceDomain.finalTimeoutLevel()) { @@ -1826,7 +1854,7 @@ bool clsLEAMDNSHost::_checkQueryCache(void) // 2. level answers // HostDomain & Port (from SRV) if ((bResult) && - (pQAnswer->m_TTLHostDomainAndPort.flagged())) + (pQAnswer->m_TTLHostDomainAndPort.flagged())) { if (!pQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) { @@ -1872,7 +1900,7 @@ bool clsLEAMDNSHost::_checkQueryCache(void) // Txts (from TXT) if ((bResult) && - (pQAnswer->m_TTLTxts.flagged())) + (pQAnswer->m_TTLTxts.flagged())) { if (!pQAnswer->m_TTLTxts.finalTimeoutLevel()) { @@ -1919,7 +1947,7 @@ bool clsLEAMDNSHost::_checkQueryCache(void) { // Needs update if ((bAUpdateQuerySent) || - ((bResult = _sendQuery(pQAnswer->m_HostDomain, DNS_RRTYPE_A)))) + ((bResult = _sendQuery(pQAnswer->m_HostDomain, DNS_RRTYPE_A)))) { pIPv4Address->m_TTL.restart(); bAUpdateQuerySent = true; @@ -1972,7 +2000,7 @@ bool clsLEAMDNSHost::_checkQueryCache(void) { // Needs update if ((bAAAAUpdateQuerySent) || - ((bResult = _sendQuery(pQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) + ((bResult = _sendQuery(pQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) { pIPv6Address->m_TTL.restart(); bAAAAUpdateQuerySent = true; @@ -2036,7 +2064,7 @@ bool clsLEAMDNSHost::_checkQueryCache(void) In addition, a full name match (question domain == host domain) is marked. */ uint32_t clsLEAMDNSHost::_replyMaskForHost(const clsLEAMDNSHost::clsRRHeader& p_RRHeader, - bool* p_pbFullNameMatch /*= 0*/) const + bool* p_pbFullNameMatch /*= 0*/) const { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForHost\n"));); @@ -2044,18 +2072,18 @@ uint32_t clsLEAMDNSHost::_replyMaskForHost(const clsLEAMDNSHost::clsRRHeader& p_ (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); if ((DNS_RRCLASS_IN == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000))) || - (DNS_RRCLASS_ANY == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000)))) + (DNS_RRCLASS_ANY == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000)))) { if ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) { // PTR request #ifdef MDNS_IPV4_SUPPORT clsRRDomain reverseIPv4Domain; if ((_getResponderIPAddress(enuIPProtocolType::V4).isSet()) && - (_buildDomainForReverseIPv4(_getResponderIPAddress(enuIPProtocolType::V4), reverseIPv4Domain)) && - (p_RRHeader.m_Domain == reverseIPv4Domain)) + (_buildDomainForReverseIPv4(_getResponderIPAddress(enuIPProtocolType::V4), reverseIPv4Domain)) && + (p_RRHeader.m_Domain == reverseIPv4Domain)) { // Reverse domain match u32ReplyMask |= static_cast(enuContentFlag::PTR_IPv4); @@ -2064,8 +2092,8 @@ uint32_t clsLEAMDNSHost::_replyMaskForHost(const clsLEAMDNSHost::clsRRHeader& p_ #ifdef MDNS_IPV6_SUPPORT clsRRDomain reverseIPv6Domain; if ((_getResponderIPAddress(enuIPProtocolType::V6).isSet()) && - (_buildDomainForReverseIPv6(_getResponderIPAddress(enuIPProtocolType::V6), reverseIPv6Domain)) && - (p_RRHeader.m_Domain == reverseIPv6Domain)) + (_buildDomainForReverseIPv6(_getResponderIPAddress(enuIPProtocolType::V6), reverseIPv6Domain)) && + (p_RRHeader.m_Domain == reverseIPv6Domain)) { // Reverse domain match u32ReplyMask |= static_cast(enuContentFlag::PTR_IPv6); @@ -2075,13 +2103,13 @@ uint32_t clsLEAMDNSHost::_replyMaskForHost(const clsLEAMDNSHost::clsRRHeader& p_ clsRRDomain hostDomain; if ((_buildDomainForHost(m_pcHostName, hostDomain)) && - (p_RRHeader.m_Domain == hostDomain)) // Host domain match + (p_RRHeader.m_Domain == hostDomain)) // Host domain match { (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); #ifdef MDNS_IPV4_SUPPORT if ((DNS_RRTYPE_A == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) { // IPv4 address request u32ReplyMask |= static_cast(enuContentFlag::A); @@ -2089,7 +2117,7 @@ uint32_t clsLEAMDNSHost::_replyMaskForHost(const clsLEAMDNSHost::clsRRHeader& p_ #endif #ifdef MDNS_IPV6_SUPPORT if ((DNS_RRTYPE_AAAA == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) { // IPv6 address request u32ReplyMask |= static_cast(enuContentFlag::AAAA); @@ -2119,20 +2147,20 @@ uint32_t clsLEAMDNSHost::_replyMaskForHost(const clsLEAMDNSHost::clsRRHeader& p_ */ uint32_t clsLEAMDNSHost::_replyMaskForService(const clsLEAMDNSHost::clsRRHeader& p_RRHeader, - clsLEAMDNSHost::clsService& p_rService, - bool* p_pbFullNameMatch /*= 0*/) + clsLEAMDNSHost::clsService& p_rService, + bool* p_pbFullNameMatch /*= 0*/) { uint32_t u32ReplyMask = 0; (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); if ((DNS_RRCLASS_IN == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000))) || - (DNS_RRCLASS_ANY == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000)))) + (DNS_RRCLASS_ANY == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000)))) { clsRRDomain DNSSDDomain; if ((_buildDomainForDNSSD(DNSSDDomain)) && // _services._dns-sd._udp.local - (p_RRHeader.m_Domain == DNSSDDomain) && - ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + (p_RRHeader.m_Domain == DNSSDDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) { // Common service info requested u32ReplyMask |= static_cast(enuContentFlag::PTR_TYPE); @@ -2140,27 +2168,27 @@ uint32_t clsLEAMDNSHost::_replyMaskForService(const clsLEAMDNSHost::clsRRHeader& clsRRDomain serviceDomain; if ((_buildDomainForService(p_rService, false, serviceDomain)) && // eg. _http._tcp.local - (p_RRHeader.m_Domain == serviceDomain) && - ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + (p_RRHeader.m_Domain == serviceDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) { // Special service info requested u32ReplyMask |= static_cast(enuContentFlag::PTR_NAME); } if ((_buildDomainForService(p_rService, true, serviceDomain)) && // eg. MyESP._http._tcp.local - (p_RRHeader.m_Domain == serviceDomain)) + (p_RRHeader.m_Domain == serviceDomain)) { (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); if ((DNS_RRTYPE_SRV == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) { // Instance info SRV requested u32ReplyMask |= static_cast(enuContentFlag::SRV); } if ((DNS_RRTYPE_TXT == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) { // Instance info TXT requested u32ReplyMask |= static_cast(enuContentFlag::TXT); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp index 434f61a0ea..b449d1cd08 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp @@ -197,7 +197,7 @@ const char* clsLEAMDNSHost::_RRType2Name(uint16_t p_u16RRType) const */ const char* clsLEAMDNSHost::_RRClass2String(uint16_t p_u16RRClass, - bool p_bIsQuery) const + bool p_bIsQuery) const { static char acClassString[16]; *acClassString = 0; @@ -267,7 +267,7 @@ const char* clsLEAMDNSHost::_replyFlags2String(uint32_t p_u32ReplyFlags) const // Remove trailing spaces while ((*acFlagsString) && - (' ' == acFlagsString[strlen(acFlagsString) - 1])) + (' ' == acFlagsString[strlen(acFlagsString) - 1])) { acFlagsString[strlen(acFlagsString) - 1] = 0; } diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp index b4db3c0531..b2fe64072a 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp @@ -52,8 +52,8 @@ namespace experimental */ clsLEAMDNSHost::clsServiceTxt::clsServiceTxt(const char* p_pcKey /*= 0*/, - const char* p_pcValue /*= 0*/, - bool p_bTemp /*= false*/) + const char* p_pcValue /*= 0*/, + bool p_bTemp /*= false*/) : m_pcKey(0), m_pcValue(0), m_bTemp(p_bTemp) @@ -127,7 +127,7 @@ char* clsLEAMDNSHost::clsServiceTxt::allocKey(size_t p_stLength) */ bool clsLEAMDNSHost::clsServiceTxt::setKey(const char* p_pcKey, - size_t p_stLength) + size_t p_stLength) { bool bResult = false; @@ -186,7 +186,7 @@ char* clsLEAMDNSHost::clsServiceTxt::allocValue(size_t p_stLength) */ bool clsLEAMDNSHost::clsServiceTxt::setValue(const char* p_pcValue, - size_t p_stLength) + size_t p_stLength) { bool bResult = false; @@ -446,7 +446,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsServiceTxts::find(const char* for (clsServiceTxt* pTxt : m_Txts) { if ((p_pcKey) && - (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) { pResult = pTxt; break; @@ -466,7 +466,7 @@ const clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsServiceTxts::find(const for (const clsServiceTxt* pTxt : m_Txts) { if ((p_pcKey) && - (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) { pResult = pTxt; break; @@ -571,8 +571,8 @@ const char* clsLEAMDNSHost::clsServiceTxts::c_str(void) const { if ((!m_pcCache) && - (m_Txts.size()) && - ((((clsServiceTxts*)this)->m_pcCache = new char[c_strLength()]))) // TRANSPARENT caching + (m_Txts.size()) && + ((((clsServiceTxts*)this)->m_pcCache = new char[c_strLength()]))) // TRANSPARENT caching { ((clsServiceTxts*)this)->c_str(m_pcCache); } @@ -825,7 +825,7 @@ bool clsLEAMDNSHost::clsService::setInstanceName(const char* p_pcInstanceName) _releaseInstanceName(); size_t stLength = (p_pcInstanceName ? strlen(p_pcInstanceName) : 0); if ((stLength) && - (stLength <= clsConsts::stDomainLabelMaxLength)) + (stLength <= clsConsts::stDomainLabelMaxLength)) { if ((bResult = (0 != (m_pcInstanceName = new char[stLength + 1])))) { @@ -887,7 +887,7 @@ bool clsLEAMDNSHost::clsService::setType(const char* p_pcType) _releaseType(); size_t stLength = (p_pcType ? strlen(p_pcType) : 0); if ((stLength) && - (stLength <= clsConsts::stServiceTypeMaxLength)) + (stLength <= clsConsts::stServiceTypeMaxLength)) { if ((bResult = (0 != (m_pcType = new char[stLength + 1])))) { @@ -934,7 +934,7 @@ bool clsLEAMDNSHost::clsService::setProtocol(const char* p_pcProtocol) _releaseProtocol(); size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); if ((stLength) && - (stLength <= clsConsts::stServiceProtocolMaxLength)) + (stLength <= clsConsts::stServiceProtocolMaxLength)) { if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) { @@ -1030,7 +1030,7 @@ void clsLEAMDNSHost::clsService::_resetProbeStatus(void) */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, - const char* p_pcValue) + const char* p_pcValue) { return _addServiceTxt(p_pcKey, p_pcValue, false); } @@ -1040,7 +1040,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const c */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, - uint32_t p_u32Value) + uint32_t p_u32Value) { return _addServiceTxt(p_pcKey, p_u32Value, false); } @@ -1050,7 +1050,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const c */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, - uint16_t p_u16Value) + uint16_t p_u16Value) { return _addServiceTxt(p_pcKey, p_u16Value, false); } @@ -1060,7 +1060,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const c */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, - uint8_t p_u8Value) + uint8_t p_u8Value) { return _addServiceTxt(p_pcKey, p_u8Value, false); } @@ -1070,7 +1070,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const c */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, - int32_t p_i32Value) + int32_t p_i32Value) { return _addServiceTxt(p_pcKey, p_i32Value, false); } @@ -1080,7 +1080,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const c */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, - int16_t p_i16Value) + int16_t p_i16Value) { return _addServiceTxt(p_pcKey, p_i16Value, false); } @@ -1090,7 +1090,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const c */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, - int8_t p_i8Value) + int8_t p_i8Value) { return _addServiceTxt(p_pcKey, p_i8Value, false); } @@ -1100,7 +1100,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const c */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, - const char* p_pcValue) + const char* p_pcValue) { return _addServiceTxt(p_pcKey, p_pcValue, true); } @@ -1110,7 +1110,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt( */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, - uint32_t p_u32Value) + uint32_t p_u32Value) { return _addServiceTxt(p_pcKey, p_u32Value, true); } @@ -1120,7 +1120,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt( */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, - uint16_t p_u16Value) + uint16_t p_u16Value) { return _addServiceTxt(p_pcKey, p_u16Value, true); } @@ -1130,7 +1130,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt( */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, - uint8_t p_u8Value) + uint8_t p_u8Value) { return _addServiceTxt(p_pcKey, p_u8Value, true); } @@ -1140,7 +1140,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt( */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, - int32_t p_i32Value) + int32_t p_i32Value) { return _addServiceTxt(p_pcKey, p_i32Value, true); } @@ -1150,7 +1150,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt( */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, - int16_t p_i16Value) + int16_t p_i16Value) { return _addServiceTxt(p_pcKey, p_i16Value, true); } @@ -1160,7 +1160,7 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt( */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, - int8_t p_i8Value) + int8_t p_i8Value) { return _addServiceTxt(p_pcKey, p_i8Value, true); } @@ -1180,13 +1180,13 @@ bool clsLEAMDNSHost::clsService::setDynamicServiceTxtCallback(fnDynamicServiceTx */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp) + const char* p_pcValue, + bool p_bTemp) { clsServiceTxt* pServiceTxt = 0; if ((p_pcKey) && - (*p_pcKey)) + (*p_pcKey)) { if ((pServiceTxt = m_Txts.find(p_pcKey))) { @@ -1220,8 +1220,8 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const (p_pcValue ? strlen(p_pcValue) : 0))) { if (!(((pServiceTxt = new clsServiceTxt)) && - (pServiceTxt->set(p_pcKey, p_pcValue, p_bTemp)) && - (m_Txts.add(pServiceTxt)))) + (pServiceTxt->set(p_pcKey, p_pcValue, p_bTemp)) && + (m_Txts.add(pServiceTxt)))) { DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[LEAmDNS2_Host] clsService::_addServiceTxt: FAILED to add TXT item '%s'!\n"), p_pcKey)); if (pServiceTxt) @@ -1247,8 +1247,8 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, - uint32_t p_u32Value, - bool p_bTemp) + uint32_t p_u32Value, + bool p_bTemp) { char acValueBuffer[16]; // 32-bit max 10 digits *acValueBuffer = 0; @@ -1262,8 +1262,8 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, - uint16_t p_u16Value, - bool p_bTemp) + uint16_t p_u16Value, + bool p_bTemp) { char acValueBuffer[8]; // 16-bit max 5 digits *acValueBuffer = 0; @@ -1277,8 +1277,8 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, - uint8_t p_u8Value, - bool p_bTemp) + uint8_t p_u8Value, + bool p_bTemp) { char acValueBuffer[8]; // 8-bit max 3 digits *acValueBuffer = 0; @@ -1292,8 +1292,8 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, - int32_t p_i32Value, - bool p_bTemp) + int32_t p_i32Value, + bool p_bTemp) { char acValueBuffer[16]; // 32-bit max 10 digits *acValueBuffer = 0; @@ -1307,8 +1307,8 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, - int16_t p_i16Value, - bool p_bTemp) + int16_t p_i16Value, + bool p_bTemp) { char acValueBuffer[8]; // 16-bit max 5 digits *acValueBuffer = 0; @@ -1322,8 +1322,8 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const */ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, - int8_t p_i8Value, - bool p_bTemp) + int8_t p_i8Value, + bool p_bTemp) { char acValueBuffer[8]; // 8-bit max 3 digits *acValueBuffer = 0; @@ -1345,17 +1345,17 @@ clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const */ clsLEAMDNSHost::clsMsgHeader::clsMsgHeader(uint16_t p_u16ID /*= 0*/, - bool p_bQR /*= false*/, - uint8_t p_u8Opcode /*= 0*/, - bool p_bAA /*= false*/, - bool p_bTC /*= false*/, - bool p_bRD /*= false*/, - bool p_bRA /*= false*/, - uint8_t p_u8RCode /*= 0*/, - uint16_t p_u16QDCount /*= 0*/, - uint16_t p_u16ANCount /*= 0*/, - uint16_t p_u16NSCount /*= 0*/, - uint16_t p_u16ARCount /*= 0*/) + bool p_bQR /*= false*/, + uint8_t p_u8Opcode /*= 0*/, + bool p_bAA /*= false*/, + bool p_bTC /*= false*/, + bool p_bRD /*= false*/, + bool p_bRA /*= false*/, + uint8_t p_u8RCode /*= 0*/, + uint16_t p_u16QDCount /*= 0*/, + uint16_t p_u16ANCount /*= 0*/, + uint16_t p_u16NSCount /*= 0*/, + uint16_t p_u16ARCount /*= 0*/) : m_u16ID(p_u16ID), m_1bQR(p_bQR), m_4bOpcode(p_u8Opcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_u8RCode), @@ -1456,7 +1456,7 @@ bool clsLEAMDNSHost::clsRRDomain::clearNameCache(void) */ bool clsLEAMDNSHost::clsRRDomain::addLabel(const char* p_pcLabel, - bool p_bPrependUnderline /*= false*/) + bool p_bPrependUnderline /*= false*/) { bool bResult = false; @@ -1464,7 +1464,7 @@ bool clsLEAMDNSHost::clsRRDomain::addLabel(const char* p_pcLabel, ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) : 0); if ((clsConsts::stDomainLabelMaxLength >= stLength) && - (clsConsts::stDomainMaxLength >= (m_u16NameLength + (1 + stLength)))) + (clsConsts::stDomainMaxLength >= (m_u16NameLength + (1 + stLength)))) { // Length byte m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! @@ -1498,9 +1498,9 @@ bool clsLEAMDNSHost::clsRRDomain::compare(const clsRRDomain& p_Other) const const char* pT = m_acName; const char* pO = p_Other.m_acName; while ((pT) && - (pO) && - (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND - (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content + (pO) && + (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND + (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content { if (*((unsigned char*)pT)) // Not 0 { @@ -1593,8 +1593,8 @@ bool clsLEAMDNSHost::clsRRDomain::c_str(char* p_pcBuffer) const const char* clsLEAMDNSHost::clsRRDomain::c_str(void) const { if ((!m_pcDecodedName) && - (m_u16NameLength) && - ((((clsRRDomain*)this)->m_pcDecodedName = new char[c_strLength()]))) // TRANSPARENT caching + (m_u16NameLength) && + ((((clsRRDomain*)this)->m_pcDecodedName = new char[c_strLength()]))) // TRANSPARENT caching { ((clsRRDomain*)this)->c_str(m_pcDecodedName); } @@ -1614,7 +1614,7 @@ const char* clsLEAMDNSHost::clsRRDomain::c_str(void) const */ clsLEAMDNSHost::clsRRAttributes::clsRRAttributes(uint16_t p_u16Type /*= 0*/, - uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) + uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) : m_u16Type(p_u16Type), m_u16Class(p_u16Class) { @@ -1753,7 +1753,7 @@ bool clsLEAMDNSHost::clsNSECBitmap::setBit(uint16_t p_u16Bit) bool bResult = false; if ((p_u16Bit) && - (length() > (p_u16Bit / 8))) // bit between 0..47(2F) + (length() > (p_u16Bit / 8))) // bit between 0..47(2F) { uint8_t& ru8Byte = m_au8BitmapData[p_u16Bit / 8]; @@ -1775,7 +1775,7 @@ bool clsLEAMDNSHost::clsNSECBitmap::getBit(uint16_t p_u16Bit) const bool bResult = false; if ((p_u16Bit) && - (length() > (p_u16Bit / 8))) // bit between 0..47(2F) + (length() > (p_u16Bit / 8))) // bit between 0..47(2F) { uint8_t u8Byte = m_au8BitmapData[p_u16Bit / 8]; @@ -1800,8 +1800,8 @@ bool clsLEAMDNSHost::clsNSECBitmap::getBit(uint16_t p_u16Bit) const */ clsLEAMDNSHost::clsRRAnswer::clsRRAnswer(enuAnswerType p_AnswerType, - const clsLEAMDNSHost::clsRRHeader& p_Header, - uint32_t p_u32TTL) + const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) : m_pNext(0), m_AnswerType(p_AnswerType), m_Header(p_Header), @@ -1855,7 +1855,7 @@ bool clsLEAMDNSHost::clsRRAnswer::clear(void) */ clsLEAMDNSHost::clsRRAnswerA::clsRRAnswerA(const clsLEAMDNSHost::clsRRHeader& p_Header, - uint32_t p_u32TTL) + uint32_t p_u32TTL) : clsRRAnswer(enuAnswerType::A, p_Header, p_u32TTL), m_IPAddress() { @@ -1895,7 +1895,7 @@ bool clsLEAMDNSHost::clsRRAnswerA::clear(void) */ clsLEAMDNSHost::clsRRAnswerPTR::clsRRAnswerPTR(const clsLEAMDNSHost::clsRRHeader& p_Header, - uint32_t p_u32TTL) + uint32_t p_u32TTL) : clsRRAnswer(enuAnswerType::PTR, p_Header, p_u32TTL) { } @@ -1933,7 +1933,7 @@ bool clsLEAMDNSHost::clsRRAnswerPTR::clear(void) */ clsLEAMDNSHost::clsRRAnswerTXT::clsRRAnswerTXT(const clsLEAMDNSHost::clsRRHeader& p_Header, - uint32_t p_u32TTL) + uint32_t p_u32TTL) : clsRRAnswer(enuAnswerType::TXT, p_Header, p_u32TTL) { } @@ -1972,7 +1972,7 @@ bool clsLEAMDNSHost::clsRRAnswerTXT::clear(void) */ clsLEAMDNSHost::clsRRAnswerAAAA::clsRRAnswerAAAA(const clsLEAMDNSHost::clsRRHeader& p_Header, - uint32_t p_u32TTL) + uint32_t p_u32TTL) : clsRRAnswer(enuAnswerType::AAAA, p_Header, p_u32TTL), m_IPAddress() { @@ -2012,7 +2012,7 @@ bool clsLEAMDNSHost::clsRRAnswerAAAA::clear(void) */ clsLEAMDNSHost::clsRRAnswerSRV::clsRRAnswerSRV(const clsLEAMDNSHost::clsRRHeader& p_Header, - uint32_t p_u32TTL) + uint32_t p_u32TTL) : clsRRAnswer(enuAnswerType::SRV, p_Header, p_u32TTL), m_u16Priority(0), m_u16Weight(0), @@ -2056,7 +2056,7 @@ bool clsLEAMDNSHost::clsRRAnswerSRV::clear(void) */ clsLEAMDNSHost::clsRRAnswerGeneric::clsRRAnswerGeneric(const clsRRHeader& p_Header, - uint32_t p_u32TTL) + uint32_t p_u32TTL) : clsRRAnswer(enuAnswerType::Generic, p_Header, p_u32TTL), m_u16RDLength(0), m_pu8RDData(0) @@ -2111,8 +2111,8 @@ bool clsLEAMDNSHost::clsRRAnswerGeneric::clear(void) */ clsLEAMDNSHost::clsSendParameter::clsDomainCacheItem::clsDomainCacheItem(const void* p_pHostNameOrService, - bool p_bAdditionalData, - uint32_t p_u16Offset) + bool p_bAdditionalData, + uint32_t p_u16Offset) : m_pHostNameOrService(p_pHostNameOrService), m_bAdditionalData(p_bAdditionalData), m_u16Offset(p_u16Offset) @@ -2227,15 +2227,15 @@ bool clsLEAMDNSHost::clsSendParameter::shiftOffset(uint16_t p_u16Shift) */ bool clsLEAMDNSHost::clsSendParameter::addDomainCacheItem(const void* p_pHostNameOrService, - bool p_bAdditionalData, - uint16_t p_u16Offset) + bool p_bAdditionalData, + uint16_t p_u16Offset) { bool bResult = false; clsDomainCacheItem* pNewItem = 0; if ((p_pHostNameOrService) && - (p_u16Offset) && - ((pNewItem = new clsDomainCacheItem(p_pHostNameOrService, p_bAdditionalData, p_u16Offset)))) + (p_u16Offset) && + ((pNewItem = new clsDomainCacheItem(p_pHostNameOrService, p_bAdditionalData, p_u16Offset)))) { m_DomainCacheItems.push_back(pNewItem); bResult = true; @@ -2248,14 +2248,14 @@ bool clsLEAMDNSHost::clsSendParameter::addDomainCacheItem(const void* p_pHostNam */ uint16_t clsLEAMDNSHost::clsSendParameter::findCachedDomainOffset(const void* p_pHostNameOrService, - bool p_bAdditionalData) const + bool p_bAdditionalData) const { const clsDomainCacheItem* pMatchingCacheItem = 0; for (const clsDomainCacheItem* pCacheItem : m_DomainCacheItems) { if ((pCacheItem->m_pHostNameOrService == p_pHostNameOrService) && - (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item + (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item { pMatchingCacheItem = pCacheItem; break; @@ -2356,7 +2356,7 @@ bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::restart(void) bool bResult = true; if ((static_cast(enuTimeoutLevel::Base) <= m_TimeoutLevel) && // >= 80% AND - (static_cast(enuTimeoutLevel::Final) > m_TimeoutLevel)) // < 100% + (static_cast(enuTimeoutLevel::Final) > m_TimeoutLevel)) // < 100% { m_TimeoutLevel += static_cast(enuTimeoutLevel::Interval); // increment by 5% m_TTLTimeout.reset(timeout()); @@ -2422,7 +2422,7 @@ unsigned long clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::timeout(void) const */ clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL::clsIPAddressWithTTL(IPAddress p_IPAddress, - uint32_t p_u32TTL /*= 0*/) + uint32_t p_u32TTL /*= 0*/) : m_IPAddress(p_IPAddress) { m_TTL.set(p_u32TTL); @@ -2514,8 +2514,8 @@ bool clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv4Address(clsLEAMDNSHost::clsQ bool bResult = false; clsIPAddressWithTTL::list::iterator it(p_pIPv4Address - ? std::find(m_IPv4Addresses.begin(), m_IPv4Addresses.end(), p_pIPv4Address) - : m_IPv4Addresses.end()); + ? std::find(m_IPv4Addresses.begin(), m_IPv4Addresses.end(), p_pIPv4Address) + : m_IPv4Addresses.end()); if (m_IPv4Addresses.end() != it) { m_IPv4Addresses.erase(it); @@ -2583,8 +2583,8 @@ const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost:: uint32_t u32CurIndex = 0; for (clsIPAddressWithTTL::list::const_iterator it = m_IPv4Addresses.begin(); - (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_IPv4Addresses.end())); - it++, u32CurIndex++) + (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_IPv4Addresses.end())); + it++, u32CurIndex++) { if (p_u32Index == u32CurIndex++) { @@ -2636,8 +2636,8 @@ bool clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv6Address(clsLEAMDNSHost::clsQ bool bResult = false; clsIPAddressWithTTL::list::iterator it(p_pIPv6Address - ? std::find(m_IPv6Addresses.begin(), m_IPv6Addresses.end(), p_pIPv6Address) - : m_IPv6Addresses.end()); + ? std::find(m_IPv6Addresses.begin(), m_IPv6Addresses.end(), p_pIPv6Address) + : m_IPv6Addresses.end()); if (m_IPv6Addresses.end() != it) { m_IPv6Addresses.erase(it); @@ -2705,8 +2705,8 @@ const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost:: uint32_t u32CurIndex = 0; for (clsIPAddressWithTTL::list::const_iterator it = m_IPv6Addresses.begin(); - (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_IPv6Addresses.end())); - it++, u32CurIndex++) + (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_IPv6Addresses.end())); + it++, u32CurIndex++) { if (p_u32Index == u32CurIndex++) { @@ -2732,7 +2732,7 @@ clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsAnswerAccessor(const clsLEAMDNSH : m_pAnswer(p_pAnswer) { if ((m_pAnswer) && - (txtsAvailable())) + (txtsAvailable())) { // Prepare m_TxtKeyValueMap for (const clsLEAMDNSHost::clsServiceTxt* pTxt : m_pAnswer->m_Txts.m_Txts) @@ -2759,7 +2759,7 @@ clsLEAMDNSHost::clsQuery::clsAnswerAccessor::~clsAnswerAccessor(void) */ bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::stcCompareTxtKey::operator()(char const* p_pA, - char const* p_pB) const + char const* p_pB) const { return (0 > strcasecmp(p_pA, p_pB)); } @@ -2846,7 +2846,7 @@ clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsIPAddressVector clsLEAMDNSHost:: { clsIPAddressVector internalIP; if ((m_pAnswer) && - (IPv4AddressAvailable())) + (IPv4AddressAvailable())) { for (uint32_t u = 0; u < m_pAnswer->IPv4AddressCount(); ++u) { @@ -2880,7 +2880,7 @@ clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsIPAddressVector clsLEAMDNSHost:: { clsIPAddressVector internalIP; if ((m_pAnswer) && - (IPv6AddressAvailable())) + (IPv6AddressAvailable())) { for (uint32_t u = 0; u < m_pAnswer->IPv6AddressCount(); ++u) { @@ -2941,7 +2941,7 @@ const char* clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtValue(const char* p_ for (const clsLEAMDNSHost::clsServiceTxt* pTxt : m_pAnswer->m_Txts.m_Txts) { if ((p_pcKey) && - (0 == strcasecmp(pTxt->m_pcKey, p_pcKey))) + (0 == strcasecmp(pTxt->m_pcKey, p_pcKey))) { pcResult = pTxt->m_pcValue; break; @@ -3110,8 +3110,8 @@ const clsLEAMDNSHost::clsQuery::clsAnswer* clsLEAMDNSHost::clsQuery::answer(uint uint32_t u32CurIndex = 0; for (clsAnswer::list::const_iterator it = m_Answers.begin(); - (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_Answers.end())); - it++, u32CurIndex++) + (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_Answers.end())); + it++, u32CurIndex++) { if (p_u32Index == u32CurIndex++) { diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp index 50880585cc..f4a187b667 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp @@ -100,7 +100,7 @@ bool clsLEAMDNSHost::_sendMessage(clsLEAMDNSHost::clsSendParameter& p_rSendParam DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage (V4): FAILED!\n"), _DH());); if ((clsConsts::u32SendCooldown) && - (can_yield())) + (can_yield())) { delay(clsConsts::u32SendCooldown); } @@ -110,16 +110,16 @@ bool clsLEAMDNSHost::_sendMessage(clsLEAMDNSHost::clsSendParameter& p_rSendParam // Multicast response -> Send via the same network interface, that received the query #ifdef MDNS_IPV4_SUPPORT if (((!ipRemote.isSet()) || // NO remote IP - (ipRemote.isV4())) && // OR IPv4 - (u8AvailableProtocols & static_cast(enuIPProtocolType::V4))) // AND IPv4 protocol available + (ipRemote.isV4())) && // OR IPv4 + (u8AvailableProtocols & static_cast(enuIPProtocolType::V4))) // AND IPv4 protocol available { bResult = _sendMessage_Multicast(p_rSendParameter, static_cast(enuIPProtocolType::V4)); } #endif #ifdef MDNS_IPV6_SUPPORT if (((!ipRemote.isSet()) || // NO remote IP - (ipRemote.isV6())) && // OR IPv6 - (u8AvailableProtocols & static_cast(enuIPProtocolType::V6))) // AND IPv6 protocol available + (ipRemote.isV6())) && // OR IPv6 + (u8AvailableProtocols & static_cast(enuIPProtocolType::V6))) // AND IPv6 protocol available { bResult = _sendMessage_Multicast(p_rSendParameter, static_cast(enuIPProtocolType::V6)); } @@ -153,7 +153,7 @@ bool clsLEAMDNSHost::_sendMessage(clsLEAMDNSHost::clsSendParameter& p_rSendParam via the selected WiFi protocols */ bool clsLEAMDNSHost::_sendMessage_Multicast(clsLEAMDNSHost::clsSendParameter& p_rSendParameter, - uint8_t p_IPProtocolTypes) + uint8_t p_IPProtocolTypes) { bool bIPv4Result = true; bool bIPv6Result = true; @@ -173,7 +173,7 @@ bool clsLEAMDNSHost::_sendMessage_Multicast(clsLEAMDNSHost::clsSendParameter& p_ DEBUG_EX_ERR(if (!bIPv4Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast (V4): FAILED!\n"), _DH());); if ((clsConsts::u32SendCooldown) && - (can_yield())) + (can_yield())) { delay(clsConsts::u32SendCooldown); } @@ -199,7 +199,7 @@ bool clsLEAMDNSHost::_sendMessage_Multicast(clsLEAMDNSHost::clsSendParameter& p_ DEBUG_EX_ERR(if (!bIPv6Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast (IPv6): FAILED! (%s, %s, %s)\n"), _DH(), (_getResponderIPAddress(enuIPProtocolType::V6).isSet() ? "1" : "0"), (bPrepareMessage ? "1" : "0"), (bUDPContextSend ? "1" : "0"));); if ((clsConsts::u32SendCooldown) && - (can_yield())) + (can_yield())) { delay(clsConsts::u32SendCooldown); } @@ -287,8 +287,8 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa #ifdef MDNS_IPV4_SUPPORT // A if ((bResult) && - (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::A)) && - (_getResponderIPAddress(enuIPProtocolType::V4).isSet())) + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::A)) && + (_getResponderIPAddress(enuIPProtocolType::V4).isSet())) { u32NSECContent |= static_cast(enuContentFlag::A); @@ -299,8 +299,8 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa } // PTR_IPv4 if ((bResult) && - (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::PTR_IPv4)) && - (_getResponderIPAddress(enuIPProtocolType::V4).isSet())) + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::PTR_IPv4)) && + (_getResponderIPAddress(enuIPProtocolType::V4).isSet())) { u32NSECContent |= static_cast(enuContentFlag::PTR_IPv4); @@ -313,8 +313,8 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa #ifdef MDNS_IPV6_SUPPORT // AAAA if ((bResult) && - (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::AAAA)) && - (_getResponderIPAddress(enuIPProtocolType::V6).isSet())) + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::AAAA)) && + (_getResponderIPAddress(enuIPProtocolType::V6).isSet())) { u32NSECContent |= static_cast(enuContentFlag::AAAA); @@ -325,8 +325,8 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa } // PTR_IPv6 if ((bResult) && - (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::PTR_IPv6)) && - (_getResponderIPAddress(enuIPProtocolType::V6).isSet())) + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::PTR_IPv6)) && + (_getResponderIPAddress(enuIPProtocolType::V6).isSet())) { u32NSECContent |= static_cast(enuContentFlag::PTR_IPv6); @@ -343,7 +343,7 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa // PTR_TYPE if ((bResult) && - (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_TYPE))) + (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_TYPE))) { ((static_cast(enuSequence::Count) == sequence) ? ++ru16Answers @@ -352,7 +352,7 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa } // PTR_NAME if ((bResult) && - (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_NAME))) + (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_NAME))) { ((static_cast(enuSequence::Count) == sequence) ? ++ru16Answers @@ -361,7 +361,7 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa } // SRV if ((bResult) && - (pService->m_u32ReplyMask & static_cast(enuContentFlag::SRV))) + (pService->m_u32ReplyMask & static_cast(enuContentFlag::SRV))) { ((static_cast(enuSequence::Count) == sequence) ? ++ru16Answers @@ -370,7 +370,7 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa } // TXT if ((bResult) && - (pService->m_u32ReplyMask & static_cast(enuContentFlag::TXT))) + (pService->m_u32ReplyMask & static_cast(enuContentFlag::TXT))) { ((static_cast(enuSequence::Count) == sequence) ? ++ru16Answers @@ -393,8 +393,8 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa clsService* pService = *it; if ((bResult) && - (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_NAME)) && // If PTR_NAME is requested, AND - (!(pService->m_u32ReplyMask & static_cast(enuContentFlag::SRV)))) // NOT SRV -> add SRV as additional answer + (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_NAME)) && // If PTR_NAME is requested, AND + (!(pService->m_u32ReplyMask & static_cast(enuContentFlag::SRV)))) // NOT SRV -> add SRV as additional answer { ((static_cast(enuSequence::Count) == sequence) @@ -413,18 +413,18 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa } */ if ((pService->m_u32ReplyMask & (static_cast(enuContentFlag::PTR_NAME) | static_cast(enuContentFlag::SRV))) || // If service instance name or SRV OR - (p_rSendParameter.m_u32HostReplyMask & (static_cast(enuContentFlag::A) | static_cast(enuContentFlag::AAAA)))) // any host IP address is requested + (p_rSendParameter.m_u32HostReplyMask & (static_cast(enuContentFlag::A) | static_cast(enuContentFlag::AAAA)))) // any host IP address is requested { #ifdef MDNS_IPV4_SUPPORT if ((bResult) && - (!(p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::A)))) // Add IPv4 address + (!(p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::A)))) // Add IPv4 address { bNeedsAdditionalAnswerA = true; } #endif #ifdef MDNS_IPV6_SUPPORT if ((bResult) && - (!(p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::AAAA)))) // Add IPv6 address + (!(p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::AAAA)))) // Add IPv6 address { bNeedsAdditionalAnswerAAAA = true; } @@ -432,8 +432,8 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa } // NSEC record for service if ((bResult) && - (pService->m_u32ReplyMask) && - ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response))) + (pService->m_u32ReplyMask) && + ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response))) { ((static_cast(enuSequence::Count) == sequence) ? ++ru16AdditionalAnswers @@ -445,8 +445,8 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa #ifdef MDNS_IPV4_SUPPORT // Answer A needed? if ((bResult) && - (bNeedsAdditionalAnswerA) && - (_getResponderIPAddress(enuIPProtocolType::V4).isSet())) + (bNeedsAdditionalAnswerA) && + (_getResponderIPAddress(enuIPProtocolType::V4).isSet())) { // Additional A u32NSECContent |= static_cast(enuContentFlag::A); @@ -460,8 +460,8 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa #ifdef MDNS_IPV6_SUPPORT // Answer AAAA needed? if ((bResult) && - (bNeedsAdditionalAnswerAAAA) && - (_getResponderIPAddress(enuIPProtocolType::V6).isSet())) + (bNeedsAdditionalAnswerAAAA) && + (_getResponderIPAddress(enuIPProtocolType::V6).isSet())) { // Additional AAAA u32NSECContent |= static_cast(enuContentFlag::AAAA); @@ -475,8 +475,8 @@ bool clsLEAMDNSHost::_prepareMessage(clsLEAMDNSHost::clsSendParameter& p_rSendPa // NSEC host (part 2) if ((bResult) && - ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response)) && - (u32NSECContent)) + ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response)) && + (u32NSECContent)) { // NSEC PTR IPv4/IPv6 are separate answers; make sure, that this is counted for #ifdef MDNS_IPV4_SUPPORT @@ -640,8 +640,8 @@ IPAddress clsLEAMDNSHost::_getResponderIPAddress(enuIPProtocolType p_IPProtocolT { //DEBUG_EX_INFO(if ip6_addr_isvalid(netif_ip6_addr_state(&m_rNetIf, idx)) DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Checking IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(m_pNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); if ((ip6_addr_isvalid(netif_ip6_addr_state(m_pNetIf, idx))) && - (((!bCheckLinkLocal) || - (ip6_addr_islinklocal(netif_ip6_addr(m_pNetIf, idx)))))) + (((!bCheckLinkLocal) || + (ip6_addr_islinklocal(netif_ip6_addr(m_pNetIf, idx)))))) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Selected IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(m_pNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); ipResponder = netif_ip_addr6(m_pNetIf, idx); @@ -713,8 +713,8 @@ bool clsLEAMDNSHost::_readRRAnswer(clsLEAMDNSHost::clsRRAnswer*& p_rpRRAnswer) uint32_t u32TTL; uint16_t u16RDLength; if ((_readRRHeader(header)) && - (_udpRead32(u32TTL)) && - (_udpRead16(u16RDLength))) + (_udpRead32(u32TTL)) && + (_udpRead16(u16RDLength))) { /* DEBUG_EX_INFO( DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: Reading 0x%04X answer (class:0x%04X, TTL:%u, RDLength:%u) for "), header.m_Attributes.m_u16Type, header.m_Attributes.m_u16Class, u32TTL, u16RDLength); @@ -876,7 +876,7 @@ bool clsLEAMDNSHost::_readRRAnswerTXT(clsLEAMDNSHost::clsRRAnswerTXT& p_rRRAnswe const unsigned char* pucCursor = pucBuffer; while ((pucCursor < (pucBuffer + p_u16RDLength)) && - (bResult)) + (bResult)) { bResult = false; @@ -894,7 +894,7 @@ bool clsLEAMDNSHost::_readRRAnswerTXT(clsLEAMDNSHost::clsRRAnswerTXT& p_rRRAnswe unsigned char* pucEqualSign = (unsigned char*)os_strchr((const char*)pucCursor, '='); // Position of the '=' sign unsigned char ucKeyLength; if ((pucEqualSign) && - ((ucKeyLength = (pucEqualSign - pucCursor)))) + ((ucKeyLength = (pucEqualSign - pucCursor)))) { unsigned char ucValueLength = (ucLength - (pucEqualSign - pucCursor + 1)); bResult = (((pTxt = new clsServiceTxt)) && @@ -914,7 +914,7 @@ bool clsLEAMDNSHost::_readRRAnswerTXT(clsLEAMDNSHost::clsRRAnswerTXT& p_rRRAnswe } if ((bResult) && - (pTxt)) + (pTxt)) { // Everythings fine so far // Link TXT item to answer TXTs @@ -1012,13 +1012,13 @@ bool clsLEAMDNSHost::_readRRAnswerSRV(clsLEAMDNSHost::clsRRAnswerSRV& p_rRRAnswe MDNSResponder::_readRRAnswerGeneric */ bool clsLEAMDNSHost::_readRRAnswerGeneric(clsLEAMDNSHost::clsRRAnswerGeneric& p_rRRAnswerGeneric, - uint16_t p_u16RDLength) + uint16_t p_u16RDLength) { bool bResult = (0 == p_u16RDLength); p_rRRAnswerGeneric.clear(); if (((p_rRRAnswerGeneric.m_u16RDLength = p_u16RDLength)) && - ((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength]))) + ((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength]))) { bResult = _udpReadBuffer(p_rRRAnswerGeneric.m_pu8RDData, p_rRRAnswerGeneric.m_u16RDLength); } @@ -1178,7 +1178,7 @@ bool clsLEAMDNSHost::_readRRAttributes(clsLEAMDNSHost::clsRRAttributes& p_rRRAtt */ bool clsLEAMDNSHost::_buildDomainForHost(const char* p_pcHostName, - clsLEAMDNSHost::clsRRDomain& p_rHostDomain) const + clsLEAMDNSHost::clsRRDomain& p_rHostDomain) const { p_rHostDomain.clear(); @@ -1218,8 +1218,8 @@ bool clsLEAMDNSHost::_buildDomainForDNSSD(clsLEAMDNSHost::clsRRDomain& p_rDNSSDD */ bool clsLEAMDNSHost::_buildDomainForService(const clsLEAMDNSHost::clsService& p_Service, - bool p_bIncludeName, - clsLEAMDNSHost::clsRRDomain& p_rServiceDomain) const + bool p_bIncludeName, + clsLEAMDNSHost::clsRRDomain& p_rServiceDomain) const { p_rServiceDomain.clear(); bool bResult = (((!p_bIncludeName) || @@ -1240,8 +1240,8 @@ bool clsLEAMDNSHost::_buildDomainForService(const clsLEAMDNSHost::clsService& p_ */ bool clsLEAMDNSHost::_buildDomainForService(const char* p_pcServiceType, - const char* p_pcProtocol, - clsLEAMDNSHost::clsRRDomain& p_rServiceDomain) const + const char* p_pcProtocol, + clsLEAMDNSHost::clsRRDomain& p_rServiceDomain) const { p_rServiceDomain.clear(); bool bResult = ((p_pcServiceType) && @@ -1264,7 +1264,7 @@ bool clsLEAMDNSHost::_buildDomainForService(const char* p_pcServiceType, */ bool clsLEAMDNSHost::_buildDomainForReverseIPv4(IPAddress p_IPv4Address, - clsLEAMDNSHost::clsRRDomain& p_rReverseIPv4Domain) const + clsLEAMDNSHost::clsRRDomain& p_rReverseIPv4Domain) const { bool bResult = ((p_IPv4Address.isSet()) && (p_IPv4Address.isV4())); @@ -1296,7 +1296,7 @@ bool clsLEAMDNSHost::_buildDomainForReverseIPv4(IPAddress p_IPv4Address, */ bool clsLEAMDNSHost::_buildDomainForReverseIPv6(IPAddress p_IPv6Address, - clsLEAMDNSHost::clsRRDomain& p_rReverseIPv6Domain) const + clsLEAMDNSHost::clsRRDomain& p_rReverseIPv6Domain) const { bool bResult = ((p_IPv6Address.isSet()) && (p_IPv6Address.isV6())); @@ -1507,12 +1507,12 @@ bool clsLEAMDNSHost::_readMDNSMsgHeader(clsLEAMDNSHost::clsMsgHeader& p_rMsgHead uint8_t u8B1; uint8_t u8B2; if ((_udpRead16(p_rMsgHeader.m_u16ID)) && - (_udpRead8(u8B1)) && - (_udpRead8(u8B2)) && - (_udpRead16(p_rMsgHeader.m_u16QDCount)) && - (_udpRead16(p_rMsgHeader.m_u16ANCount)) && - (_udpRead16(p_rMsgHeader.m_u16NSCount)) && - (_udpRead16(p_rMsgHeader.m_u16ARCount))) + (_udpRead8(u8B1)) && + (_udpRead8(u8B2)) && + (_udpRead16(p_rMsgHeader.m_u16QDCount)) && + (_udpRead16(p_rMsgHeader.m_u16ANCount)) && + (_udpRead16(p_rMsgHeader.m_u16NSCount)) && + (_udpRead16(p_rMsgHeader.m_u16ARCount))) { p_rMsgHeader.m_1bQR = (u8B1 & 0x80); // Query/Responde flag @@ -1584,7 +1584,7 @@ bool clsLEAMDNSHost::_write32(uint32_t p_u32Value, */ bool clsLEAMDNSHost::_writeMDNSMsgHeader(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), _DH(), @@ -1615,7 +1615,7 @@ bool clsLEAMDNSHost::_writeMDNSMsgHeader(const clsLEAMDNSHost::clsMsgHeader& p_M */ bool clsLEAMDNSHost::_writeMDNSRRAttributes(const clsLEAMDNSHost::clsRRAttributes& p_Attributes, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { bool bResult = ((_write16(p_Attributes.m_u16Type, p_rSendParameter)) && (_write16(p_Attributes.m_u16Class, p_rSendParameter))); @@ -1654,9 +1654,9 @@ bool clsLEAMDNSHost::_writeMDNSRRDomain(const clsLEAMDNSHost::clsRRDomain& p_Dom */ bool clsLEAMDNSHost::_writeMDNSHostDomain(const char* p_pcHostName, - bool p_bPrependRDLength, - uint16_t p_u16AdditionalLength, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)p_pcHostName, false); @@ -1694,10 +1694,10 @@ bool clsLEAMDNSHost::_writeMDNSHostDomain(const char* p_pcHostName, */ bool clsLEAMDNSHost::_writeMDNSServiceDomain(const clsLEAMDNSHost::clsService& p_Service, - bool p_bIncludeName, - bool p_bPrependRDLength, - uint16_t p_u16AdditionalLength, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + bool p_bIncludeName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)&p_Service, p_bIncludeName); @@ -1815,7 +1815,7 @@ bool clsLEAMDNSHost::_writeMDNSAnswer_A(IPAddress p_IPAddress, */ bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv4 (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); @@ -1860,7 +1860,7 @@ bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, */ bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_TYPE(clsLEAMDNSHost::clsService& p_rService, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_TYPE\n"));); @@ -1903,7 +1903,7 @@ bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_TYPE(clsLEAMDNSHost::clsService& p_rSe */ bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_NAME(clsLEAMDNSHost::clsService& p_rService, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME\n"), _DH());); @@ -1947,7 +1947,7 @@ bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_NAME(clsLEAMDNSHost::clsService& p_rSe */ bool clsLEAMDNSHost::_writeMDNSAnswer_TXT(clsLEAMDNSHost::clsService& p_rService, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"), _DH());); @@ -1957,16 +1957,16 @@ bool clsLEAMDNSHost::_writeMDNSAnswer_TXT(clsLEAMDNSHost::clsService& p_rService ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet if ((_collectServiceTxts(p_rService)) && - (_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce - ? 0 - : (p_rSendParameter.m_bLegacyDNSQuery // TTL - ? clsConsts::u32LegacyTTL - : clsConsts::u32ServiceTTL)), p_rSendParameter)) && - (_write16((p_rService.m_Txts.count() // RDLength - ? p_rService.m_Txts.length() // default case - : 1), p_rSendParameter))) // If no TXT records exist, a single 0 byte is sent + (_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery // TTL + ? clsConsts::u32LegacyTTL + : clsConsts::u32ServiceTTL)), p_rSendParameter)) && + (_write16((p_rService.m_Txts.count() // RDLength + ? p_rService.m_Txts.length() // default case + : 1), p_rSendParameter))) // If no TXT records exist, a single 0 byte is sent { bResult = true; // RData Txts @@ -2035,7 +2035,7 @@ bool clsLEAMDNSHost::_writeMDNSAnswer_TXT(clsLEAMDNSHost::clsService& p_rService */ bool clsLEAMDNSHost::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); @@ -2077,7 +2077,7 @@ bool clsLEAMDNSHost::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, */ bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv6%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); @@ -2117,13 +2117,13 @@ bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, */ bool clsLEAMDNSHost::_writeMDNSAnswer_SRV(clsLEAMDNSHost::clsService& p_rService, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_SRV%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyDNSQuery - ? 0 - : p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostName, false)); + ? 0 + : p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostName, false)); clsRRAttributes attributes(DNS_RRTYPE_SRV, ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet @@ -2194,7 +2194,7 @@ clsLEAMDNSHost::clsNSECBitmap* clsLEAMDNSHost::_createNSECBitmap(uint32_t p_u32N } #endif if ((p_u32NSECContent & static_cast(enuContentFlag::PTR_IPv4)) || - (p_u32NSECContent & static_cast(enuContentFlag::PTR_IPv6))) + (p_u32NSECContent & static_cast(enuContentFlag::PTR_IPv6))) { pNSECBitmap->setBit(DNS_RRTYPE_PTR); // 12/0x0C } @@ -2225,7 +2225,7 @@ clsLEAMDNSHost::clsNSECBitmap* clsLEAMDNSHost::_createNSECBitmap(uint32_t p_u32N */ bool clsLEAMDNSHost::_writeMDNSNSECBitmap(const clsLEAMDNSHost::clsNSECBitmap& p_NSECBitmap, - clsLEAMDNSHost::clsSendParameter& p_rSendParameter) + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) { /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("_writeMDNSNSECBitmap: ")); for (uint16_t u=0; unext())) + (m_pUDPContext->next())) { netif* pNetIf = m_pUDPContext->getInputNetif();//ip_current_input_netif(); // Probably changed inbetween!!!! clsLEAMDNSHost* pHost = 0; if ((pNetIf) && - ((pHost = _findHost(pNetIf)))) + ((pHost = _findHost(pNetIf)))) { DEBUG_EX_INFO( if (u32LoopCounter++) { DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Multi-Loop (%u)!\n"), _DH(), u32LoopCounter); if ((remoteIPAddr.isSet()) && - (remoteIPAddr != m_pUDPContext->getRemoteAddress())) + (remoteIPAddr != m_pUDPContext->getRemoteAddress())) { DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Changed IP address %s->%s!\n"), _DH(), remoteIPAddr.toString().c_str(), m_pUDPContext->getRemoteAddress().toString().c_str()); } @@ -264,7 +264,7 @@ const clsLEAMDNSHost* clsLEAMDNSHost::clsBackbone::_findHost(netif* p_pNetIf) co for (const clsLEAMDNSHost* pHost : m_HostList) { if ((p_pNetIf) && - (pHost->m_pNetIf == p_pNetIf)) + (pHost->m_pNetIf == p_pNetIf)) { pResult = pHost; break; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp index 040d915905..896018f81d 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp @@ -1,1493 +1,1495 @@ -/* - * LEAmDNS2_Legacy.cpp - * - * - */ - -#include "LEAmDNS2_Legacy.h" - - -namespace esp8266 -{ - -/** - * LEAmDNS - */ -namespace MDNSImplementation -{ - -/** - STRINGIZE -*/ -#ifndef STRINGIZE -#define STRINGIZE(x) #x -#endif -#ifndef STRINGIZE_VALUE_OF -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) -#endif - - -/* - * clsLEAMDNSHost_Legacy::clsLEAMDNSHost_Legacy constructor - * - */ -clsLEAMDNSHost_Legacy::clsLEAMDNSHost_Legacy(void) -{ -} - -/* - * clsLEAMDNSHost_Legacy::clsLEAMDNSHost_Legacy destructor - * - */ -clsLEAMDNSHost_Legacy::~clsLEAMDNSHost_Legacy(void) -{ -} - -/* - * - * HOST SETUP - * - */ - -/* - * clsLEAMDNSHost_Legacy::begin - * - */ -bool clsLEAMDNSHost_Legacy::begin(const char* p_pcHostname) -{ - bool bResult = ( ( (!(WIFI_STA & (WiFiMode_t)wifi_get_opmode())) - || (addHostForNetIf(p_pcHostname, netif_get_by_index(WIFI_STA)))) - && ( (!(WIFI_AP & (WiFiMode_t)wifi_get_opmode())) - || (addHostForNetIf(p_pcHostname, netif_get_by_index(WIFI_AP))))); - return ( (bResult) - && (0 != m_HostInformations.size())); -} - -/* - * clsLEAMDNSHost_Legacy::begin (String) - * - */ -bool clsLEAMDNSHost_Legacy::begin(const String& p_strHostname) -{ - return begin(p_strHostname.c_str()); -} - -/* - * clsLEAMDNSHost_Legacy::begin (Ignored Options) - * - */ -bool clsLEAMDNSHost_Legacy::begin(const char* p_pcHostname, - IPAddress /*p_IPAddress = INADDR_ANY*/, // ignored - uint32_t /*p_u32TTL = 120*/) // ignored -{ - return begin(p_pcHostname); -} - -/* - * clsLEAMDNSHost_Legacy::begin (String & Ignored Options) - * - */ -bool clsLEAMDNSHost_Legacy::begin(const String& p_strHostname, - IPAddress /*p_IPAddress = INADDR_ANY*/, // ignored - uint32_t /*p_u32TTL = 120*/) // ignored -{ - return begin(p_strHostname.c_str()); -} - -/* - * clsLEAMDNSHost_Legacy::close - * - */ -bool clsLEAMDNSHost_Legacy::close(void) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - if ((bResult = (*it).m_pHost->close())) - { - delete (*it).m_pHost; - (*it).m_pHost = 0; - } - } - return ( (bResult) - && (m_HostInformations.clear(), true)); -} - -/* - * clsLEAMDNSHost_Legacy::end - * - */ -bool clsLEAMDNSHost_Legacy::end(void) -{ - return close(); -} - -/* - * clsLEAMDNSHost_Legacy::addHostForNetIf - * - * NEW! - * - */ -bool clsLEAMDNSHost_Legacy::addHostForNetIf(const char* p_pcHostname, - netif* p_pNetIf) -{ - clsLEAMDNSHost* pHost = 0; - - if ( ((pHost = new esp8266::experimental::clsLEAMDNSHost)) - && (!( (pHost->begin(p_pcHostname, p_pNetIf /*, default callback*/)) - && (m_HostInformations.push_back(stcHostInformation(pHost)), true)))) - { - delete pHost; - pHost = 0; - } - return (0 != pHost); -} - -/* - * clsLEAMDNSHost_Legacy::setHostname - * - */ -bool clsLEAMDNSHost_Legacy::setHostname(const char* p_pcHostname) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - bResult = (*it).m_pHost->setHostName(p_pcHostname); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::setHostname - * - */ -bool clsLEAMDNSHost_Legacy::setHostname(String p_strHostname) -{ - return setHostname(p_strHostname.c_str()); -} - -/* - * clsLEAMDNSHost_Legacy::hostname - * - */ -const char* clsLEAMDNSHost_Legacy::hostname(void) const -{ - return (m_HostInformations.empty() - ? 0 - : m_HostInformations.front().m_pHost->hostName()); -} - -/* - * clsLEAMDNSHost_Legacy::status - * - */ -bool clsLEAMDNSHost_Legacy::status(void) const -{ - bool bStatus = true; - - for (const stcHostInformation& hostInformation : m_HostInformations) - { - if (!((bStatus = hostInformation.m_pHost->probeStatus()))) - { - break; - } - } - return bStatus; -} - - -/* - * - * SERVICE MANAGEMENT - * - */ - -/* - * clsLEAMDNSHost_Legacy::addService - * - */ -clsLEAMDNSHost_Legacy::hMDNSService clsLEAMDNSHost_Legacy::addService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port) -{ - hMDNSService hResult = 0; - - for (stcHostInformation& hostInformation : m_HostInformations) - { - clsLEAMDNSHost::clsService* pService = hostInformation.m_pHost->addService(p_pcName, p_pcService, p_pcProtocol, p_u16Port /*, default callback*/); - if (pService) - { - if (!hResult) - { // Store first service handle as result and key - hResult = (hMDNSService)pService; - } - hostInformation.m_HandleToPtr[hResult] = pService; - } - } - return hResult; -} - -/* - * clsLEAMDNSHost_Legacy::addService (String) - * - */ -bool clsLEAMDNSHost_Legacy::addService(String p_strServiceName, - String p_strProtocol, - uint16_t p_u16Port) -{ - return (0 != addService(0, p_strServiceName.c_str(), p_strProtocol.c_str(), p_u16Port)); -} - -/* - * clsLEAMDNSHost_Legacy::removeService (hService) - * - */ -bool clsLEAMDNSHost_Legacy::removeService(const hMDNSService p_hService) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; - if ((bResult = ( (pService) - && ((*it).m_pHost->removeService(pService))))) - { - (*it).m_HandleToPtr.erase(p_hService); - } - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::removeService (name) - * - */ -bool clsLEAMDNSHost_Legacy::removeService(const char* p_pcInstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol) -{ - hMDNSService hService = 0; - return ( ((hService = (m_HostInformations.empty() - ? 0 - : (hMDNSService)m_HostInformations.front().m_pHost->findService(p_pcInstanceName, p_pcServiceName, p_pcProtocol)))) - && (removeService(hService))); -} - -/* - * clsLEAMDNSHost_Legacy::setServiceName - * - */ -bool clsLEAMDNSHost_Legacy::setServiceName(const hMDNSService p_hService, - const char* p_pcInstanceName) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; - bResult = ( (pService) - && (pService->setInstanceName(p_pcInstanceName))); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::setInstanceName - * - */ -void clsLEAMDNSHost_Legacy::setInstanceName(const char* p_pcInstanceName) -{ - for (stcHostInformation& hostInformation : m_HostInformations) - { - hostInformation.m_pHost->setDefaultInstanceName(p_pcInstanceName); - } -} - -/* - * clsLEAMDNSHost_Legacy::setInstanceName (String) - * - */ -void clsLEAMDNSHost_Legacy::setInstanceName(const String& p_strHostname) -{ - setInstanceName(p_strHostname.c_str()); -} - -/* - * clsLEAMDNSHost_Legacy::serviceName - * - */ -const char* clsLEAMDNSHost_Legacy::serviceName(const hMDNSService p_hService) const -{ - const clsLEAMDNSHost::clsService* pService = 0; - return (m_HostInformations.empty() - ? 0 - : (((pService = (const clsLEAMDNSHost::clsService*)(m_HostInformations.front().m_HandleToPtr.at(p_hService)))) - ? pService->instanceName() - : 0)); -} - -/* - * clsLEAMDNSHost_Legacy::service - * - */ -const char* clsLEAMDNSHost_Legacy::service(const hMDNSService p_hService) const -{ - const clsLEAMDNSHost::clsService* pService = 0; - return (m_HostInformations.empty() - ? 0 - : (((pService = (const clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr.at(p_hService))) - ? pService->type() - : 0)); -} - -/* - * clsLEAMDNSHost_Legacy::serviceProtocol - * - */ -const char* clsLEAMDNSHost_Legacy::serviceProtocol(const hMDNSService p_hService) const -{ - const clsLEAMDNSHost::clsService* pService = 0; - return (m_HostInformations.empty() - ? 0 - : (((pService = (const clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr.at(p_hService))) - ? pService->protocol() - : 0)); -} - -/* - * clsLEAMDNSHost_Legacy::serviceStatus - * - */ -bool clsLEAMDNSHost_Legacy::serviceStatus(const hMDNSService p_hService) const -{ - const clsLEAMDNSHost::clsService* pService = 0; - return (m_HostInformations.empty() - ? false - : (((pService = (const clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr.at(p_hService))) - ? pService->probeStatus() - : false)); -} - - -/* - * - * SERVICE TXT MANAGEMENT - * - */ - -/* - * clsLEAMDNSHost_Legacy::addServiceTxt (char*) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue) -{ - return _addServiceTxt(p_hService, p_pcKey, p_pcValue, false); -} - -/* - * clsLEAMDNSHost_Legacy::addServiceTxt (uint32_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_u32Value, false); -} - -/* - * clsLEAMDNSHost_Legacy::addServiceTxt (uint16_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_u16Value, false); -} - -/* - * clsLEAMDNSHost_Legacy::addServiceTxt (uint8_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_u8Value, false); -} - -/* - * clsLEAMDNSHost_Legacy::addServiceTxt (int32_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_i32Value, false); -} - -/* - * clsLEAMDNSHost_Legacy::addServiceTxt (int16_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_i16Value, false); -} - -/* - * clsLEAMDNSHost_Legacy::addServiceTxt (int8_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_i8Value, false); -} - -/* - * clsLEAMDNSHost_Legacy::addServiceTxt (legacy) - * - */ -bool clsLEAMDNSHost_Legacy::addServiceTxt(const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey, - const char* p_pcValue) -{ - hMDNSService hService = 0; - return ( ((hService = (m_HostInformations.empty() - ? 0 - : (hMDNSService)m_HostInformations.front().m_pHost->findService(0, p_pcService, p_pcProtocol)))) - && (_addServiceTxt(hService, p_pcKey, p_pcValue, false))); -} - -/* - * clsLEAMDNSHost_Legacy::addServiceTxt (legacy, String) - * - */ -bool clsLEAMDNSHost_Legacy::addServiceTxt(String p_strService, - String p_strProtocol, - String p_strKey, - String p_strValue) -{ - return addServiceTxt(p_strService.c_str(), p_strProtocol.c_str(), p_strKey.c_str(), p_strValue.c_str()); -} - -/* - * clsLEAMDNSHost_Legacy::removeServiceTxt (hTxt) - * - */ -bool clsLEAMDNSHost_Legacy::removeServiceTxt(const hMDNSService p_hService, - const hMDNSTxt p_hTxt) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; - clsLEAMDNSHost::clsServiceTxt* pTxt = (clsLEAMDNSHost::clsServiceTxt*)(*it).m_HandleToPtr[p_hTxt]; - if ((bResult = ( (pService) - && (pTxt) - && (pService->removeServiceTxt(pTxt))))) - { - (*it).m_HandleToPtr.erase(p_hTxt); - } - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::removeServiceTxt (char*) - * - */ -bool clsLEAMDNSHost_Legacy::removeServiceTxt(const hMDNSService p_hService, - const char* p_pcKey) -{ - clsLEAMDNSHost::clsService* pService = 0; - clsLEAMDNSHost::clsServiceTxt* pTxt = 0; - return ( ((pService = (m_HostInformations.empty() - ? 0 - : (clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr[p_hService]))) - && ((pTxt = pService->findServiceTxt(p_pcKey))) - && (removeServiceTxt(p_hService, (const hMDNSTxt)pTxt))); -} - -/* - * clsLEAMDNSHost_Legacy::removeServiceTxt (char*) - * - */ -bool clsLEAMDNSHost_Legacy::removeServiceTxt(const char* p_pcInstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol, - const char* p_pcKey) -{ - hMDNSService hService = 0; - return ( ((hService = (m_HostInformations.empty() - ? 0 - : (hMDNSService)m_HostInformations.front().m_pHost->findService(p_pcInstanceName, p_pcServiceName, p_pcProtocol)))) - && (removeServiceTxt(hService, p_pcKey))); -} - -/* - * clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback (global) - * - */ -bool clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn p_fnCallback) -{ - bool bResult = true; - - if ((bResult = m_HostInformations.empty())) - { - // The service handles of the first host are the keys in the HostInformations.HandleToPtr map - for (const clsLEAMDNSHost::clsService* pService : m_HostInformations.front().m_pHost->services()) - { - if (!((bResult = setDynamicServiceTxtCallback((hMDNSService)pService, p_fnCallback)))) - { - break; - } - } - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback (service) - * - */ -bool clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback(const hMDNSService p_hService, - MDNSDynamicServiceTxtCallbackFn p_fnCallback) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; - bResult = pService->setDynamicServiceTxtCallback([p_hService, p_fnCallback](clsLEAMDNSHost::clsService& /*p_rMDNSService*/)->void - { - if (p_fnCallback) // void(const hMDNSService p_hService) - { - p_fnCallback(p_hService); - } - }); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (char*) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue) -{ - return _addServiceTxt(p_hService, p_pcKey, p_pcValue, true); -} - -/* - * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (uint32) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_u32Value, true); -} - -/* - * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (uint16) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_u16Value, true); -} - -/* - * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (uint8) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_u8Value, true); -} - -/* - * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (int32) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_i32Value, true); -} - -/* - * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (int16) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_i16Value, true); -} - -/* - * clsLEAMDNSHost_Legacy::addDynamicServiceTxt (int8) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value) -{ - return _addServiceTxt(p_hService, p_pcKey, p_i8Value, true); -} - - -/* - * - * STATIC QUERY - * - */ - - /* - * clsLEAMDNSHost_Legacy::queryService - * - * This will take p_u16Timeout millisec for every host! - * - */ -uint32_t clsLEAMDNSHost_Legacy::queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - uint32_t u32Answers = 0; - - for (stcHostInformation& hostInformation : m_HostInformations) - { - u32Answers += (hostInformation.m_pHost->queryService(p_pcService, p_pcProtocol, p_u16Timeout)).size(); - } - return u32Answers; -} - -/* - * clsLEAMDNSHost_Legacy::removeQuery - * - */ -bool clsLEAMDNSHost_Legacy::removeQuery(void) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - bResult = (*it).m_pHost->removeQuery(); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::queryService - * - */ -uint32_t clsLEAMDNSHost_Legacy::queryService(String p_strService, - String p_strProtocol) -{ - return queryService(p_strService.c_str(), p_strProtocol.c_str()); -} - -/* - * clsLEAMDNSHost_Legacy::answerHostname - * - */ -const char* clsLEAMDNSHost_Legacy::answerHostname(const uint32_t p_u32AnswerIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_u32AnswerIndex); - return (answerAccessor.serviceDomainAvailable() - ? answerAccessor.serviceDomain() - : 0); -} - -/* - * clsLEAMDNSHost_Legacy::answerIP - * - */ -IPAddress clsLEAMDNSHost_Legacy::answerIP(const uint32_t p_u32AnswerIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_u32AnswerIndex); - return (answerAccessor.IPv4AddressAvailable() - ? answerAccessor.IPv4Addresses()[0] - : IPAddress()); -} - -/* - * clsLEAMDNSHost_Legacy::answerPort - * - */ -uint16_t clsLEAMDNSHost_Legacy::answerPort(const uint32_t p_u32AnswerIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_u32AnswerIndex); - return (answerAccessor.hostPortAvailable() - ? answerAccessor.hostPort() - : 0); -} - -/* - * clsLEAMDNSHost_Legacy::hostname - * - */ -String clsLEAMDNSHost_Legacy::hostname(const uint32_t p_u32AnswerIndex) -{ - return String(answerHostname(p_u32AnswerIndex)); -} - -/* - * clsLEAMDNSHost_Legacy::IP - * - */ -IPAddress clsLEAMDNSHost_Legacy::IP(const uint32_t p_u32AnswerIndex) -{ - return answerIP(p_u32AnswerIndex); -} - -/* - * clsLEAMDNSHost_Legacy::port - * - */ -uint16_t clsLEAMDNSHost_Legacy::port(const uint32_t p_u32AnswerIndex) -{ - return answerPort(p_u32AnswerIndex); -} - - -/* - * - * DYNAMIC QUERY - * - */ - -/* - * clsLEAMDNSHost_Legacy::installServiceQuery - * - */ -clsLEAMDNSHost_Legacy::hMDNSServiceQuery clsLEAMDNSHost_Legacy::installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSServiceQueryCallbackFn p_fnCallback) -{ - hMDNSServiceQuery hResult = 0; - - for (stcHostInformation& hostInformation : m_HostInformations) - { - clsLEAMDNSHost::clsQuery* pQuery = hostInformation.m_pHost->installServiceQuery(p_pcService, p_pcProtocol, [this, p_fnCallback](const clsLEAMDNSHost::clsQuery& /*p_Query*/, - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor& p_AnswerAccessor, - clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, // flags for the updated answer item - bool p_bSetContent)->void - { - if (p_fnCallback) // void(const stcMDNSServiceInfo& p_MDNSServiceInfo, MDNSResponder::AnswerType p_AnswerType, bool p_bSetContent) - { - p_fnCallback(stcMDNSServiceInfo(p_AnswerAccessor), _answerFlagsToAnswerType(p_QueryAnswerTypeFlags), p_bSetContent); - } - }); - if (pQuery) - { - if (!hResult) - { // Store first query as result and key - hResult = (hMDNSServiceQuery)pQuery; - } - hostInformation.m_HandleToPtr[hResult] = pQuery; - } - } - return hResult; -} - -/* - * clsLEAMDNSHost_Legacy::removeServiceQuery - * - */ -bool clsLEAMDNSHost_Legacy::removeServiceQuery(clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - if ((bResult = (*it).m_pHost->removeQuery((clsLEAMDNSHost::clsQuery*)(*it).m_HandleToPtr[p_hServiceQuery]))) - { - (*it).m_HandleToPtr.erase(p_hServiceQuery); - } - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::answerCount - * - */ -uint32_t clsLEAMDNSHost_Legacy::answerCount(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery) -{ - uint32_t u32AnswerCount = 0; - - for (stcHostInformation& hostInformation : m_HostInformations) - { - clsLEAMDNSHost::clsQuery* pQuery = (clsLEAMDNSHost::clsQuery*)hostInformation.m_HandleToPtr[p_hServiceQuery]; - if (pQuery) - { - u32AnswerCount += pQuery->answerCount(); - } - else - { - u32AnswerCount = 0; - break; - } - } - return u32AnswerCount; -} - -/* - * clsLEAMDNSHost_Legacy::answerInfo - * - */ -std::vector clsLEAMDNSHost_Legacy::answerInfo(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery) -{ - std::vector serviceInfos; - - for (stcHostInformation& hostInformation : m_HostInformations) - { - clsLEAMDNSHost::clsQuery* pQuery = (clsLEAMDNSHost::clsQuery*)hostInformation.m_HandleToPtr[p_hServiceQuery]; - if (pQuery) - { - for (clsLEAMDNSHost::clsQuery::clsAnswerAccessor& answerAccessor : pQuery->answerAccessors()) - { - serviceInfos.push_back(stcMDNSServiceInfo(answerAccessor)); - } - } - else - { - serviceInfos.clear(); - break; - } - } - return serviceInfos; -} - -/* - * clsLEAMDNSHost_Legacy::answerServiceDomain - * - */ -const char* clsLEAMDNSHost_Legacy::answerServiceDomain(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); - return (answerAccessor.serviceDomainAvailable() - ? answerAccessor.serviceDomain() - : 0); -} - -/* - * clsLEAMDNSHost_Legacy::hasAnswerHostDomain - * - */ -bool clsLEAMDNSHost_Legacy::hasAnswerHostDomain(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).hostDomainAvailable(); -} - -/* - * clsLEAMDNSHost_Legacy::answerHostDomain - * - */ -const char* clsLEAMDNSHost_Legacy::answerHostDomain(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); - return (answerAccessor.hostDomainAvailable() - ? answerAccessor.hostDomain() - : 0); -} - -#ifdef MDNS_IP4_SUPPORT -/* - * clsLEAMDNSHost_Legacy::hasAnswerIP4Address - * - */ -bool clsLEAMDNSHost_Legacy::hasAnswerIP4Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).IPv4AddressAvailable(); -} - -/* - * clsLEAMDNSHost_Legacy::answerIP4AddressCount - * - */ -uint32_t clsLEAMDNSHost_Legacy::answerIP4AddressCount(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); - return (answerAccessor.IPv4AddressAvailable() - ? answerAccessor.IPv4Addresses().size() - : 0); -} - -/* - * clsLEAMDNSHost_Legacy::answerIP4Address - * - */ -IPAddress clsLEAMDNSHost_Legacy::answerIP4Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); - return (answerAccessor.IPv4AddressAvailable() - ? answerAccessor.IPv4Addresses()[p_u32AddressIndex] - : IPAddress()); -} -#endif -#ifdef MDNS_IP6_SUPPORT -/* - * clsLEAMDNSHost_Legacy::hasAnswerIP6Address - * - */ -bool clsLEAMDNSHost_Legacy::hasAnswerIP6Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).IPv6AddressAvailable(); -} - -/* - * clsLEAMDNSHost_Legacy::answerIP6AddressCount - * - */ -uint32_t clsLEAMDNSHost_Legacy::answerIP6AddressCount(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); - return (answerAccessor.IPv6AddressAvailable() - ? answerAccessor.IPv6Addresses().size() - : 0); -} - -/* - * clsLEAMDNSHost_Legacy::answerIP6Address - * - */ -IPAddress clsLEAMDNSHost_Legacy::answerIP6Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); - return (answerAccessor.IPv6AddressAvailable() - ? answerAccessor.IPv6Addresses()[p_u32AddressIndex] - : IPAddress()); -} -#endif - -/* - * clsLEAMDNSHost_Legacy::hasAnswerPort - * - */ -bool clsLEAMDNSHost_Legacy::hasAnswerPort(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).hostPortAvailable(); -} - -/* - * clsLEAMDNSHost_Legacy::answerPort - * - */ -uint16_t clsLEAMDNSHost_Legacy::answerPort(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); - return (answerAccessor.hostPortAvailable() - ? answerAccessor.hostPort() - : 0); -} - -/* - * clsLEAMDNSHost_Legacy::hasAnswerTxts - * - */ -bool clsLEAMDNSHost_Legacy::hasAnswerTxts(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).txtsAvailable(); -} - -/* - * clsLEAMDNSHost_Legacy::answerHostDomain - * - * Get the TXT items as a ';'-separated string - */ -const char* clsLEAMDNSHost_Legacy::answerTxts(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); - return (answerAccessor.txtsAvailable() - ? answerAccessor.txts() - : 0); -} - - -/* - * - * HOST/SERVICE PROBE CALLBACKS - * - */ - -/* - * clsLEAMDNSHost_Legacy::setHostProbeResultCallback - * - */ -bool clsLEAMDNSHost_Legacy::setHostProbeResultCallback(clsLEAMDNSHost_Legacy::MDNSHostProbeResultCallbackFn p_fnCallback) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - bResult = (*it).m_pHost->setProbeResultCallback([p_fnCallback](clsLEAMDNSHost& /*p_rHost*/, - const char* p_pcDomainName, - bool p_bProbeResult)->void - { - if (p_fnCallback) // void(const char* p_pcDomainName, bool p_bProbeResult) - { - p_fnCallback(p_pcDomainName, p_bProbeResult); - } - }); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::setHostProbeResultCallback - * - */ -bool clsLEAMDNSHost_Legacy::setHostProbeResultCallback(clsLEAMDNSHost_Legacy::MDNSHostProbeResultCallbackFn2 p_fnCallback) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - bResult = (*it).m_pHost->setProbeResultCallback([this, p_fnCallback](clsLEAMDNSHost& /*p_rHost*/, - const char* p_pcDomainName, - bool p_bProbeResult)->void - { - if (p_fnCallback) // void(clsLEAMDNSHost_Legacy* p_pMDNSResponder, const char* p_pcDomainName, bool p_bProbeResult) - { - p_fnCallback(this, p_pcDomainName, p_bProbeResult); - } - }); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::setServiceProbeResultCallback - * - */ -bool clsLEAMDNSHost_Legacy::setServiceProbeResultCallback(const clsLEAMDNSHost_Legacy::hMDNSService p_hService, - clsLEAMDNSHost_Legacy::MDNSServiceProbeResultCallbackFn p_fnCallback) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - clsLEAMDNSHost::clsService* pService = 0; - bResult = ( ((pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService])) - && (pService->setProbeResultCallback([this, p_hService, p_fnCallback](clsLEAMDNSHost::clsService& /*p_rMDNSService*/, - const char* p_pcInstanceName, - bool p_bProbeResult)->void - { - if (p_fnCallback) // void(const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) - { - p_fnCallback(p_pcInstanceName, p_hService, p_bProbeResult); - } - }))); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::setServiceProbeResultCallback - * - */ -bool clsLEAMDNSHost_Legacy::setServiceProbeResultCallback(const clsLEAMDNSHost_Legacy::hMDNSService p_hService, - clsLEAMDNSHost_Legacy::MDNSServiceProbeResultCallbackFn2 p_fnCallback) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - clsLEAMDNSHost::clsService* pService = 0; - bResult = ( ((pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService])) - && (pService->setProbeResultCallback([this, p_hService, p_fnCallback](clsLEAMDNSHost::clsService& /*p_rMDNSService*/, - const char* p_pcInstanceName, - bool p_bProbeResult)->void - { - if (p_fnCallback) // void((clsLEAMDNSHost_Legacy* p_pMDNSResponder, const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) - { - p_fnCallback(this, p_pcInstanceName, p_hService, p_bProbeResult); - } - }))); - } - return bResult; -} - - -/* - * - * PROCESS - * - */ - -/* - * clsLEAMDNSHost_Legacy::notifyAPChange - * - */ -bool clsLEAMDNSHost_Legacy::notifyAPChange(void) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - bResult = (*it).m_pHost->restart(); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::update - * - */ -bool clsLEAMDNSHost_Legacy::update(void) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - bResult = (*it).m_pHost->update(); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::announce - * - */ -bool clsLEAMDNSHost_Legacy::announce(void) -{ - bool bResult = true; - - for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) - { - bResult = (*it).m_pHost->announce(true, true); - } - return bResult; -} - -/* - * clsLEAMDNSHost_Legacy::enableArduino - * - */ -clsLEAMDNSHost_Legacy::hMDNSService clsLEAMDNSHost_Legacy::enableArduino(uint16_t p_u16Port, - bool p_bAuthUpload /*= false*/) -{ - hMDNSService hService = addService(0, "arduino", "tcp", p_u16Port); - if (hService) - { - if ( (!addServiceTxt(hService, "tcp_check", "no")) - || (!addServiceTxt(hService, "ssh_upload", "no")) - || (!addServiceTxt(hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) - || (!addServiceTxt(hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) - { - removeService(hService); - hService = 0; - } - } - return hService; -} - -/* - * clsLEAMDNSHost_Legacy::indexDomain - * - */ -bool clsLEAMDNSHost_Legacy::indexDomain(char*& p_rpcDomain, - const char* p_pcDivider /*= "-"*/, - const char* p_pcDefaultDomain /*= 0*/) -{ - bool bResult = false; - - const char* cpcDomainName = clsLEAMDNSHost::indexDomainName(p_rpcDomain, p_pcDivider, p_pcDefaultDomain); - delete[] p_rpcDomain; - p_rpcDomain = 0; - if ( (cpcDomainName) - && ((p_rpcDomain = new char[strlen(cpcDomainName) + 1]))) - { - strcpy(p_rpcDomain, cpcDomainName); - bResult = true; - } - return bResult; -} - - -/* - * - * INTERNAL HELPERS - * - */ - -/* - * clsLEAMDNSHost_Legacy::_addServiceTxt (char*) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bDynamic) -{ - hMDNSTxt hResult = 0; - - for (stcHostInformation& hostInformation : m_HostInformations) - { - clsLEAMDNSHost::clsService* pService = 0; - clsLEAMDNSHost::clsServiceTxt* pTxt = 0; - if ( ((pService = (clsLEAMDNSHost::clsService*)hostInformation.m_HandleToPtr[p_hService])) - && ((pTxt = (p_bDynamic - ? pService->addDynamicServiceTxt(p_pcKey, p_pcValue) - : pService->addServiceTxt(p_pcKey, p_pcValue))))) - { - if (!hResult) - { - hResult = (hMDNSTxt)pTxt; - } - hostInformation.m_HandleToPtr[hResult] = pTxt; - } - } - return hResult; -} - -/* - * clsLEAMDNSHost_Legacy::_addServiceTxt (uint32_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value, - bool p_bDynamic) -{ - char acValueBuffer[16]; // 32-bit max 10 digits - *acValueBuffer = 0; - sprintf(acValueBuffer, "%u", p_u32Value); - - return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); -} - -/* - * clsLEAMDNSHost_Legacy::_addServiceTxt (uint16_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value, - bool p_bDynamic) -{ - char acValueBuffer[8]; // 16-bit max 5 digits - *acValueBuffer = 0; - sprintf(acValueBuffer, "%hu", p_u16Value); - - return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); -} - -/* - * clsLEAMDNSHost_Legacy::_addServiceTxt (uint8_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value, - bool p_bDynamic) -{ - char acValueBuffer[8]; // 8-bit max 3 digits - *acValueBuffer = 0; - sprintf(acValueBuffer, "%hhu", p_u8Value); - - return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); -} - -/* - * clsLEAMDNSHost_Legacy::_addServiceTxt (int32_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value, - bool p_bDynamic) -{ - char acValueBuffer[16]; // 32-bit max 11 digits - *acValueBuffer = 0; - sprintf(acValueBuffer, "%i", p_i32Value); - - return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); -} - -/* - * clsLEAMDNSHost_Legacy::_addServiceTxt (int16_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value, - bool p_bDynamic) -{ - char acValueBuffer[8]; // 16-bit max 6 digits - *acValueBuffer = 0; - sprintf(acValueBuffer, "%hi", p_i16Value); - - return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); -} - -/* - * clsLEAMDNSHost_Legacy::_addServiceTxt (int8_t) - * - */ -clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value, - bool p_bDynamic) -{ - char acValueBuffer[8]; // 8-bit max 4 digits - *acValueBuffer = 0; - sprintf(acValueBuffer, "%hhi", p_i8Value); - - return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); -} - -/* - * clsLEAMDNSHost_Legacy::_answerFlagsToAnswerType - * - */ -clsLEAMDNSHost_Legacy::AnswerType clsLEAMDNSHost_Legacy::_answerFlagsToAnswerType(clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags) const -{ - AnswerType answerType = AnswerType::Unknown; - - if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Unknown) & p_QueryAnswerTypeFlags) - { - answerType = AnswerType::Unknown; - } - else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain) & p_QueryAnswerTypeFlags) - { - answerType = AnswerType::ServiceDomain; - } - else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::HostDomain) & p_QueryAnswerTypeFlags) - { - answerType = AnswerType::HostDomainAndPort; - } - else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Port) & p_QueryAnswerTypeFlags) - { - answerType = AnswerType::HostDomainAndPort; - } - else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Txts) & p_QueryAnswerTypeFlags) - { - answerType = AnswerType::Txt; - } -#ifdef MDNS_IP4_SUPPORT - else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address) & p_QueryAnswerTypeFlags) - { - answerType = AnswerType::IP4Address; - } -#endif -#ifdef MDNS_IP6_SUPPORT - else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address) & p_QueryAnswerTypeFlags) - { - answerType = AnswerType::IP6Address; - } -#endif - return answerType; -} - -/* - * clsLEAMDNSHost_Legacy::_getAnswerAccessor - * - */ -clsLEAMDNSHost_Legacy::clsLEAMDNSHost::clsQuery::clsAnswerAccessor clsLEAMDNSHost_Legacy::_getAnswerAccessor(const uint32_t p_u32AnswerIndex) -{ - uint32_t u32AnswerIndexWithoutOffset = p_u32AnswerIndex; - for (stcHostInformation& hostInformation : m_HostInformations) - { - clsLEAMDNSHost::clsQuery* pQuery = hostInformation.m_pHost->getQuery(); - if (pQuery) - { - if (pQuery->answerCount() > u32AnswerIndexWithoutOffset) - { - return pQuery->answerAccessor(u32AnswerIndexWithoutOffset); - } - else - { - u32AnswerIndexWithoutOffset -= pQuery->answerCount(); - } - } - else - { - break; - } - } - return clsLEAMDNSHost::clsQuery::clsAnswerAccessor(0); -} - -/* - * clsLEAMDNSHost_Legacy::_getAnswerAccessor - * - */ -clsLEAMDNSHost_Legacy::clsLEAMDNSHost::clsQuery::clsAnswerAccessor clsLEAMDNSHost_Legacy::_getAnswerAccessor(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - uint32_t u32AnswerIndexWithoutOffset = p_u32AnswerIndex; - for (stcHostInformation& hostInformation : m_HostInformations) - { - clsLEAMDNSHost::clsQuery* pQuery = (clsLEAMDNSHost::clsQuery*)hostInformation.m_HandleToPtr[p_hServiceQuery]; - if (pQuery) - { - if (pQuery->answerCount() > u32AnswerIndexWithoutOffset) - { - return pQuery->answerAccessor(u32AnswerIndexWithoutOffset); - } - else - { - u32AnswerIndexWithoutOffset -= pQuery->answerCount(); - } - } - else - { - break; - } - } - return clsLEAMDNSHost::clsQuery::clsAnswerAccessor(0); -} - - -} // namespace MDNSImplementation - - -} // namespace esp8266 - - - - - - +/* + LEAmDNS2_Legacy.cpp + + +*/ + +#include "LEAmDNS2_Legacy.h" + + +namespace esp8266 +{ + +/** + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + STRINGIZE +*/ +#ifndef STRINGIZE +#define STRINGIZE(x) #x +#endif +#ifndef STRINGIZE_VALUE_OF +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) +#endif + + +/* + clsLEAMDNSHost_Legacy::clsLEAMDNSHost_Legacy constructor + +*/ +clsLEAMDNSHost_Legacy::clsLEAMDNSHost_Legacy(void) +{ +} + +/* + clsLEAMDNSHost_Legacy::clsLEAMDNSHost_Legacy destructor + +*/ +clsLEAMDNSHost_Legacy::~clsLEAMDNSHost_Legacy(void) +{ +} + +/* + + HOST SETUP + +*/ + +/* + clsLEAMDNSHost_Legacy::begin + +*/ +bool clsLEAMDNSHost_Legacy::begin(const char* p_pcHostname) +{ + bool bResult = (((!(WIFI_STA & (WiFiMode_t)wifi_get_opmode())) + || (addHostForNetIf(p_pcHostname, netif_get_by_index(WIFI_STA)))) + && ((!(WIFI_AP & (WiFiMode_t)wifi_get_opmode())) + || (addHostForNetIf(p_pcHostname, netif_get_by_index(WIFI_AP))))); + return ((bResult) + && (0 != m_HostInformations.size())); +} + +/* + clsLEAMDNSHost_Legacy::begin (String) + +*/ +bool clsLEAMDNSHost_Legacy::begin(const String& p_strHostname) +{ + return begin(p_strHostname.c_str()); +} + +/* + clsLEAMDNSHost_Legacy::begin (Ignored Options) + +*/ +bool clsLEAMDNSHost_Legacy::begin(const char* p_pcHostname, + IPAddress /*p_IPAddress = INADDR_ANY*/, // ignored + uint32_t /*p_u32TTL = 120*/) // ignored +{ + return begin(p_pcHostname); +} + +/* + clsLEAMDNSHost_Legacy::begin (String & Ignored Options) + +*/ +bool clsLEAMDNSHost_Legacy::begin(const String& p_strHostname, + IPAddress /*p_IPAddress = INADDR_ANY*/, // ignored + uint32_t /*p_u32TTL = 120*/) // ignored +{ + return begin(p_strHostname.c_str()); +} + +/* + clsLEAMDNSHost_Legacy::close + +*/ +bool clsLEAMDNSHost_Legacy::close(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + if ((bResult = (*it).m_pHost->close())) + { + delete (*it).m_pHost; + (*it).m_pHost = 0; + } + } + return ((bResult) + && (m_HostInformations.clear(), true)); +} + +/* + clsLEAMDNSHost_Legacy::end + +*/ +bool clsLEAMDNSHost_Legacy::end(void) +{ + return close(); +} + +/* + clsLEAMDNSHost_Legacy::addHostForNetIf + + NEW! + +*/ +bool clsLEAMDNSHost_Legacy::addHostForNetIf(const char* p_pcHostname, + netif* p_pNetIf) +{ + clsLEAMDNSHost* pHost = 0; + + if (((pHost = new esp8266::experimental::clsLEAMDNSHost)) + && (!((pHost->begin(p_pcHostname, p_pNetIf /*, default callback*/)) + && (m_HostInformations.push_back(stcHostInformation(pHost)), true)))) + { + delete pHost; + pHost = 0; + } + return (0 != pHost); +} + +/* + clsLEAMDNSHost_Legacy::setHostname + +*/ +bool clsLEAMDNSHost_Legacy::setHostname(const char* p_pcHostname) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->setHostName(p_pcHostname); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::setHostname + +*/ +bool clsLEAMDNSHost_Legacy::setHostname(String p_strHostname) +{ + return setHostname(p_strHostname.c_str()); +} + +/* + clsLEAMDNSHost_Legacy::hostname + +*/ +const char* clsLEAMDNSHost_Legacy::hostname(void) const +{ + return (m_HostInformations.empty() + ? 0 + : m_HostInformations.front().m_pHost->hostName()); +} + +/* + clsLEAMDNSHost_Legacy::status + +*/ +bool clsLEAMDNSHost_Legacy::status(void) const +{ + bool bStatus = true; + + for (const stcHostInformation& hostInformation : m_HostInformations) + { + if (!((bStatus = hostInformation.m_pHost->probeStatus()))) + { + break; + } + } + return bStatus; +} + + +/* + + SERVICE MANAGEMENT + +*/ + +/* + clsLEAMDNSHost_Legacy::addService + +*/ +clsLEAMDNSHost_Legacy::hMDNSService clsLEAMDNSHost_Legacy::addService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + hMDNSService hResult = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsService* pService = hostInformation.m_pHost->addService(p_pcName, p_pcService, p_pcProtocol, p_u16Port /*, default callback*/); + if (pService) + { + if (!hResult) + { + // Store first service handle as result and key + hResult = (hMDNSService)pService; + } + hostInformation.m_HandleToPtr[hResult] = pService; + } + } + return hResult; +} + +/* + clsLEAMDNSHost_Legacy::addService (String) + +*/ +bool clsLEAMDNSHost_Legacy::addService(String p_strServiceName, + String p_strProtocol, + uint16_t p_u16Port) +{ + return (0 != addService(0, p_strServiceName.c_str(), p_strProtocol.c_str(), p_u16Port)); +} + +/* + clsLEAMDNSHost_Legacy::removeService (hService) + +*/ +bool clsLEAMDNSHost_Legacy::removeService(const hMDNSService p_hService) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; + if ((bResult = ((pService) + && ((*it).m_pHost->removeService(pService))))) + { + (*it).m_HandleToPtr.erase(p_hService); + } + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::removeService (name) + +*/ +bool clsLEAMDNSHost_Legacy::removeService(const char* p_pcInstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol) +{ + hMDNSService hService = 0; + return (((hService = (m_HostInformations.empty() + ? 0 + : (hMDNSService)m_HostInformations.front().m_pHost->findService(p_pcInstanceName, p_pcServiceName, p_pcProtocol)))) + && (removeService(hService))); +} + +/* + clsLEAMDNSHost_Legacy::setServiceName + +*/ +bool clsLEAMDNSHost_Legacy::setServiceName(const hMDNSService p_hService, + const char* p_pcInstanceName) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; + bResult = ((pService) + && (pService->setInstanceName(p_pcInstanceName))); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::setInstanceName + +*/ +void clsLEAMDNSHost_Legacy::setInstanceName(const char* p_pcInstanceName) +{ + for (stcHostInformation& hostInformation : m_HostInformations) + { + hostInformation.m_pHost->setDefaultInstanceName(p_pcInstanceName); + } +} + +/* + clsLEAMDNSHost_Legacy::setInstanceName (String) + +*/ +void clsLEAMDNSHost_Legacy::setInstanceName(const String& p_strHostname) +{ + setInstanceName(p_strHostname.c_str()); +} + +/* + clsLEAMDNSHost_Legacy::serviceName + +*/ +const char* clsLEAMDNSHost_Legacy::serviceName(const hMDNSService p_hService) const +{ + const clsLEAMDNSHost::clsService* pService = 0; + return (m_HostInformations.empty() + ? 0 + : (((pService = (const clsLEAMDNSHost::clsService*)(m_HostInformations.front().m_HandleToPtr.at(p_hService)))) + ? pService->instanceName() + : 0)); +} + +/* + clsLEAMDNSHost_Legacy::service + +*/ +const char* clsLEAMDNSHost_Legacy::service(const hMDNSService p_hService) const +{ + const clsLEAMDNSHost::clsService* pService = 0; + return (m_HostInformations.empty() + ? 0 + : (((pService = (const clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr.at(p_hService))) + ? pService->type() + : 0)); +} + +/* + clsLEAMDNSHost_Legacy::serviceProtocol + +*/ +const char* clsLEAMDNSHost_Legacy::serviceProtocol(const hMDNSService p_hService) const +{ + const clsLEAMDNSHost::clsService* pService = 0; + return (m_HostInformations.empty() + ? 0 + : (((pService = (const clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr.at(p_hService))) + ? pService->protocol() + : 0)); +} + +/* + clsLEAMDNSHost_Legacy::serviceStatus + +*/ +bool clsLEAMDNSHost_Legacy::serviceStatus(const hMDNSService p_hService) const +{ + const clsLEAMDNSHost::clsService* pService = 0; + return (m_HostInformations.empty() + ? false + : (((pService = (const clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr.at(p_hService))) + ? pService->probeStatus() + : false)); +} + + +/* + + SERVICE TXT MANAGEMENT + +*/ + +/* + clsLEAMDNSHost_Legacy::addServiceTxt (char*) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_hService, p_pcKey, p_pcValue, false); +} + +/* + clsLEAMDNSHost_Legacy::addServiceTxt (uint32_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u32Value, false); +} + +/* + clsLEAMDNSHost_Legacy::addServiceTxt (uint16_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u16Value, false); +} + +/* + clsLEAMDNSHost_Legacy::addServiceTxt (uint8_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u8Value, false); +} + +/* + clsLEAMDNSHost_Legacy::addServiceTxt (int32_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i32Value, false); +} + +/* + clsLEAMDNSHost_Legacy::addServiceTxt (int16_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i16Value, false); +} + +/* + clsLEAMDNSHost_Legacy::addServiceTxt (int8_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i8Value, false); +} + +/* + clsLEAMDNSHost_Legacy::addServiceTxt (legacy) + +*/ +bool clsLEAMDNSHost_Legacy::addServiceTxt(const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey, + const char* p_pcValue) +{ + hMDNSService hService = 0; + return (((hService = (m_HostInformations.empty() + ? 0 + : (hMDNSService)m_HostInformations.front().m_pHost->findService(0, p_pcService, p_pcProtocol)))) + && (_addServiceTxt(hService, p_pcKey, p_pcValue, false))); +} + +/* + clsLEAMDNSHost_Legacy::addServiceTxt (legacy, String) + +*/ +bool clsLEAMDNSHost_Legacy::addServiceTxt(String p_strService, + String p_strProtocol, + String p_strKey, + String p_strValue) +{ + return addServiceTxt(p_strService.c_str(), p_strProtocol.c_str(), p_strKey.c_str(), p_strValue.c_str()); +} + +/* + clsLEAMDNSHost_Legacy::removeServiceTxt (hTxt) + +*/ +bool clsLEAMDNSHost_Legacy::removeServiceTxt(const hMDNSService p_hService, + const hMDNSTxt p_hTxt) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; + clsLEAMDNSHost::clsServiceTxt* pTxt = (clsLEAMDNSHost::clsServiceTxt*)(*it).m_HandleToPtr[p_hTxt]; + if ((bResult = ((pService) + && (pTxt) + && (pService->removeServiceTxt(pTxt))))) + { + (*it).m_HandleToPtr.erase(p_hTxt); + } + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::removeServiceTxt (char*) + +*/ +bool clsLEAMDNSHost_Legacy::removeServiceTxt(const hMDNSService p_hService, + const char* p_pcKey) +{ + clsLEAMDNSHost::clsService* pService = 0; + clsLEAMDNSHost::clsServiceTxt* pTxt = 0; + return (((pService = (m_HostInformations.empty() + ? 0 + : (clsLEAMDNSHost::clsService*)m_HostInformations.front().m_HandleToPtr[p_hService]))) + && ((pTxt = pService->findServiceTxt(p_pcKey))) + && (removeServiceTxt(p_hService, (const hMDNSTxt)pTxt))); +} + +/* + clsLEAMDNSHost_Legacy::removeServiceTxt (char*) + +*/ +bool clsLEAMDNSHost_Legacy::removeServiceTxt(const char* p_pcInstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol, + const char* p_pcKey) +{ + hMDNSService hService = 0; + return (((hService = (m_HostInformations.empty() + ? 0 + : (hMDNSService)m_HostInformations.front().m_pHost->findService(p_pcInstanceName, p_pcServiceName, p_pcProtocol)))) + && (removeServiceTxt(hService, p_pcKey))); +} + +/* + clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback (global) + +*/ +bool clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn p_fnCallback) +{ + bool bResult = true; + + if ((bResult = m_HostInformations.empty())) + { + // The service handles of the first host are the keys in the HostInformations.HandleToPtr map + for (const clsLEAMDNSHost::clsService* pService : m_HostInformations.front().m_pHost->services()) + { + if (!((bResult = setDynamicServiceTxtCallback((hMDNSService)pService, p_fnCallback)))) + { + break; + } + } + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback (service) + +*/ +bool clsLEAMDNSHost_Legacy::setDynamicServiceTxtCallback(const hMDNSService p_hService, + MDNSDynamicServiceTxtCallbackFn p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService]; + bResult = pService->setDynamicServiceTxtCallback([p_hService, p_fnCallback](clsLEAMDNSHost::clsService& /*p_rMDNSService*/)->void + { + if (p_fnCallback) // void(const hMDNSService p_hService) + { + p_fnCallback(p_hService); + } + }); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::addDynamicServiceTxt (char*) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_hService, p_pcKey, p_pcValue, true); +} + +/* + clsLEAMDNSHost_Legacy::addDynamicServiceTxt (uint32) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u32Value, true); +} + +/* + clsLEAMDNSHost_Legacy::addDynamicServiceTxt (uint16) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u16Value, true); +} + +/* + clsLEAMDNSHost_Legacy::addDynamicServiceTxt (uint8) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_u8Value, true); +} + +/* + clsLEAMDNSHost_Legacy::addDynamicServiceTxt (int32) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i32Value, true); +} + +/* + clsLEAMDNSHost_Legacy::addDynamicServiceTxt (int16) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i16Value, true); +} + +/* + clsLEAMDNSHost_Legacy::addDynamicServiceTxt (int8) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value) +{ + return _addServiceTxt(p_hService, p_pcKey, p_i8Value, true); +} + + +/* + + STATIC QUERY + +*/ + +/* + clsLEAMDNSHost_Legacy::queryService + + This will take p_u16Timeout millisec for every host! + +*/ +uint32_t clsLEAMDNSHost_Legacy::queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + uint32_t u32Answers = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + u32Answers += (hostInformation.m_pHost->queryService(p_pcService, p_pcProtocol, p_u16Timeout)).size(); + } + return u32Answers; +} + +/* + clsLEAMDNSHost_Legacy::removeQuery + +*/ +bool clsLEAMDNSHost_Legacy::removeQuery(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->removeQuery(); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::queryService + +*/ +uint32_t clsLEAMDNSHost_Legacy::queryService(String p_strService, + String p_strProtocol) +{ + return queryService(p_strService.c_str(), p_strProtocol.c_str()); +} + +/* + clsLEAMDNSHost_Legacy::answerHostname + +*/ +const char* clsLEAMDNSHost_Legacy::answerHostname(const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_u32AnswerIndex); + return (answerAccessor.serviceDomainAvailable() + ? answerAccessor.serviceDomain() + : 0); +} + +/* + clsLEAMDNSHost_Legacy::answerIP + +*/ +IPAddress clsLEAMDNSHost_Legacy::answerIP(const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_u32AnswerIndex); + return (answerAccessor.IPv4AddressAvailable() + ? answerAccessor.IPv4Addresses()[0] + : IPAddress()); +} + +/* + clsLEAMDNSHost_Legacy::answerPort + +*/ +uint16_t clsLEAMDNSHost_Legacy::answerPort(const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_u32AnswerIndex); + return (answerAccessor.hostPortAvailable() + ? answerAccessor.hostPort() + : 0); +} + +/* + clsLEAMDNSHost_Legacy::hostname + +*/ +String clsLEAMDNSHost_Legacy::hostname(const uint32_t p_u32AnswerIndex) +{ + return String(answerHostname(p_u32AnswerIndex)); +} + +/* + clsLEAMDNSHost_Legacy::IP + +*/ +IPAddress clsLEAMDNSHost_Legacy::IP(const uint32_t p_u32AnswerIndex) +{ + return answerIP(p_u32AnswerIndex); +} + +/* + clsLEAMDNSHost_Legacy::port + +*/ +uint16_t clsLEAMDNSHost_Legacy::port(const uint32_t p_u32AnswerIndex) +{ + return answerPort(p_u32AnswerIndex); +} + + +/* + + DYNAMIC QUERY + +*/ + +/* + clsLEAMDNSHost_Legacy::installServiceQuery + +*/ +clsLEAMDNSHost_Legacy::hMDNSServiceQuery clsLEAMDNSHost_Legacy::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSServiceQueryCallbackFn p_fnCallback) +{ + hMDNSServiceQuery hResult = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = hostInformation.m_pHost->installServiceQuery(p_pcService, p_pcProtocol, [this, p_fnCallback](const clsLEAMDNSHost::clsQuery& /*p_Query*/, + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor & p_AnswerAccessor, + clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, // flags for the updated answer item + bool p_bSetContent)->void + { + if (p_fnCallback) // void(const stcMDNSServiceInfo& p_MDNSServiceInfo, MDNSResponder::AnswerType p_AnswerType, bool p_bSetContent) + { + p_fnCallback(stcMDNSServiceInfo(p_AnswerAccessor), _answerFlagsToAnswerType(p_QueryAnswerTypeFlags), p_bSetContent); + } + }); + if (pQuery) + { + if (!hResult) + { + // Store first query as result and key + hResult = (hMDNSServiceQuery)pQuery; + } + hostInformation.m_HandleToPtr[hResult] = pQuery; + } + } + return hResult; +} + +/* + clsLEAMDNSHost_Legacy::removeServiceQuery + +*/ +bool clsLEAMDNSHost_Legacy::removeServiceQuery(clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + if ((bResult = (*it).m_pHost->removeQuery((clsLEAMDNSHost::clsQuery*)(*it).m_HandleToPtr[p_hServiceQuery]))) + { + (*it).m_HandleToPtr.erase(p_hServiceQuery); + } + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::answerCount + +*/ +uint32_t clsLEAMDNSHost_Legacy::answerCount(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery) +{ + uint32_t u32AnswerCount = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = (clsLEAMDNSHost::clsQuery*)hostInformation.m_HandleToPtr[p_hServiceQuery]; + if (pQuery) + { + u32AnswerCount += pQuery->answerCount(); + } + else + { + u32AnswerCount = 0; + break; + } + } + return u32AnswerCount; +} + +/* + clsLEAMDNSHost_Legacy::answerInfo + +*/ +std::vector clsLEAMDNSHost_Legacy::answerInfo(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery) +{ + std::vector serviceInfos; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = (clsLEAMDNSHost::clsQuery*)hostInformation.m_HandleToPtr[p_hServiceQuery]; + if (pQuery) + { + for (clsLEAMDNSHost::clsQuery::clsAnswerAccessor& answerAccessor : pQuery->answerAccessors()) + { + serviceInfos.push_back(stcMDNSServiceInfo(answerAccessor)); + } + } + else + { + serviceInfos.clear(); + break; + } + } + return serviceInfos; +} + +/* + clsLEAMDNSHost_Legacy::answerServiceDomain + +*/ +const char* clsLEAMDNSHost_Legacy::answerServiceDomain(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.serviceDomainAvailable() + ? answerAccessor.serviceDomain() + : 0); +} + +/* + clsLEAMDNSHost_Legacy::hasAnswerHostDomain + +*/ +bool clsLEAMDNSHost_Legacy::hasAnswerHostDomain(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).hostDomainAvailable(); +} + +/* + clsLEAMDNSHost_Legacy::answerHostDomain + +*/ +const char* clsLEAMDNSHost_Legacy::answerHostDomain(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.hostDomainAvailable() + ? answerAccessor.hostDomain() + : 0); +} + +#ifdef MDNS_IP4_SUPPORT +/* + clsLEAMDNSHost_Legacy::hasAnswerIP4Address + +*/ +bool clsLEAMDNSHost_Legacy::hasAnswerIP4Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).IPv4AddressAvailable(); +} + +/* + clsLEAMDNSHost_Legacy::answerIP4AddressCount + +*/ +uint32_t clsLEAMDNSHost_Legacy::answerIP4AddressCount(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.IPv4AddressAvailable() + ? answerAccessor.IPv4Addresses().size() + : 0); +} + +/* + clsLEAMDNSHost_Legacy::answerIP4Address + +*/ +IPAddress clsLEAMDNSHost_Legacy::answerIP4Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.IPv4AddressAvailable() + ? answerAccessor.IPv4Addresses()[p_u32AddressIndex] + : IPAddress()); +} +#endif +#ifdef MDNS_IP6_SUPPORT +/* + clsLEAMDNSHost_Legacy::hasAnswerIP6Address + +*/ +bool clsLEAMDNSHost_Legacy::hasAnswerIP6Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).IPv6AddressAvailable(); +} + +/* + clsLEAMDNSHost_Legacy::answerIP6AddressCount + +*/ +uint32_t clsLEAMDNSHost_Legacy::answerIP6AddressCount(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.IPv6AddressAvailable() + ? answerAccessor.IPv6Addresses().size() + : 0); +} + +/* + clsLEAMDNSHost_Legacy::answerIP6Address + +*/ +IPAddress clsLEAMDNSHost_Legacy::answerIP6Address(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.IPv6AddressAvailable() + ? answerAccessor.IPv6Addresses()[p_u32AddressIndex] + : IPAddress()); +} +#endif + +/* + clsLEAMDNSHost_Legacy::hasAnswerPort + +*/ +bool clsLEAMDNSHost_Legacy::hasAnswerPort(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).hostPortAvailable(); +} + +/* + clsLEAMDNSHost_Legacy::answerPort + +*/ +uint16_t clsLEAMDNSHost_Legacy::answerPort(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.hostPortAvailable() + ? answerAccessor.hostPort() + : 0); +} + +/* + clsLEAMDNSHost_Legacy::hasAnswerTxts + +*/ +bool clsLEAMDNSHost_Legacy::hasAnswerTxts(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + return _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex).txtsAvailable(); +} + +/* + clsLEAMDNSHost_Legacy::answerHostDomain + + Get the TXT items as a ';'-separated string +*/ +const char* clsLEAMDNSHost_Legacy::answerTxts(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor answerAccessor = _getAnswerAccessor(p_hServiceQuery, p_u32AnswerIndex); + return (answerAccessor.txtsAvailable() + ? answerAccessor.txts() + : 0); +} + + +/* + + HOST/SERVICE PROBE CALLBACKS + +*/ + +/* + clsLEAMDNSHost_Legacy::setHostProbeResultCallback + +*/ +bool clsLEAMDNSHost_Legacy::setHostProbeResultCallback(clsLEAMDNSHost_Legacy::MDNSHostProbeResultCallbackFn p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->setProbeResultCallback([p_fnCallback](clsLEAMDNSHost& /*p_rHost*/, + const char* p_pcDomainName, + bool p_bProbeResult)->void + { + if (p_fnCallback) // void(const char* p_pcDomainName, bool p_bProbeResult) + { + p_fnCallback(p_pcDomainName, p_bProbeResult); + } + }); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::setHostProbeResultCallback + +*/ +bool clsLEAMDNSHost_Legacy::setHostProbeResultCallback(clsLEAMDNSHost_Legacy::MDNSHostProbeResultCallbackFn2 p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->setProbeResultCallback([this, p_fnCallback](clsLEAMDNSHost& /*p_rHost*/, + const char* p_pcDomainName, + bool p_bProbeResult)->void + { + if (p_fnCallback) // void(clsLEAMDNSHost_Legacy* p_pMDNSResponder, const char* p_pcDomainName, bool p_bProbeResult) + { + p_fnCallback(this, p_pcDomainName, p_bProbeResult); + } + }); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::setServiceProbeResultCallback + +*/ +bool clsLEAMDNSHost_Legacy::setServiceProbeResultCallback(const clsLEAMDNSHost_Legacy::hMDNSService p_hService, + clsLEAMDNSHost_Legacy::MDNSServiceProbeResultCallbackFn p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = 0; + bResult = (((pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService])) + && (pService->setProbeResultCallback([this, p_hService, p_fnCallback](clsLEAMDNSHost::clsService& /*p_rMDNSService*/, + const char* p_pcInstanceName, + bool p_bProbeResult)->void + { + if (p_fnCallback) // void(const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) + { + p_fnCallback(p_pcInstanceName, p_hService, p_bProbeResult); + } + }))); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::setServiceProbeResultCallback + +*/ +bool clsLEAMDNSHost_Legacy::setServiceProbeResultCallback(const clsLEAMDNSHost_Legacy::hMDNSService p_hService, + clsLEAMDNSHost_Legacy::MDNSServiceProbeResultCallbackFn2 p_fnCallback) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + clsLEAMDNSHost::clsService* pService = 0; + bResult = (((pService = (clsLEAMDNSHost::clsService*)(*it).m_HandleToPtr[p_hService])) + && (pService->setProbeResultCallback([this, p_hService, p_fnCallback](clsLEAMDNSHost::clsService& /*p_rMDNSService*/, + const char* p_pcInstanceName, + bool p_bProbeResult)->void + { + if (p_fnCallback) // void((clsLEAMDNSHost_Legacy* p_pMDNSResponder, const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) + { + p_fnCallback(this, p_pcInstanceName, p_hService, p_bProbeResult); + } + }))); + } + return bResult; +} + + +/* + + PROCESS + +*/ + +/* + clsLEAMDNSHost_Legacy::notifyAPChange + +*/ +bool clsLEAMDNSHost_Legacy::notifyAPChange(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->restart(); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::update + +*/ +bool clsLEAMDNSHost_Legacy::update(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->update(); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::announce + +*/ +bool clsLEAMDNSHost_Legacy::announce(void) +{ + bool bResult = true; + + for (stcHostInformation::list::iterator it = m_HostInformations.begin(); ((bResult) && (it != m_HostInformations.end())); ++it) + { + bResult = (*it).m_pHost->announce(true, true); + } + return bResult; +} + +/* + clsLEAMDNSHost_Legacy::enableArduino + +*/ +clsLEAMDNSHost_Legacy::hMDNSService clsLEAMDNSHost_Legacy::enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload /*= false*/) +{ + hMDNSService hService = addService(0, "arduino", "tcp", p_u16Port); + if (hService) + { + if ((!addServiceTxt(hService, "tcp_check", "no")) + || (!addServiceTxt(hService, "ssh_upload", "no")) + || (!addServiceTxt(hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) + || (!addServiceTxt(hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) + { + removeService(hService); + hService = 0; + } + } + return hService; +} + +/* + clsLEAMDNSHost_Legacy::indexDomain + +*/ +bool clsLEAMDNSHost_Legacy::indexDomain(char*& p_rpcDomain, + const char* p_pcDivider /*= "-"*/, + const char* p_pcDefaultDomain /*= 0*/) +{ + bool bResult = false; + + const char* cpcDomainName = clsLEAMDNSHost::indexDomainName(p_rpcDomain, p_pcDivider, p_pcDefaultDomain); + delete[] p_rpcDomain; + p_rpcDomain = 0; + if ((cpcDomainName) + && ((p_rpcDomain = new char[strlen(cpcDomainName) + 1]))) + { + strcpy(p_rpcDomain, cpcDomainName); + bResult = true; + } + return bResult; +} + + +/* + + INTERNAL HELPERS + +*/ + +/* + clsLEAMDNSHost_Legacy::_addServiceTxt (char*) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bDynamic) +{ + hMDNSTxt hResult = 0; + + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsService* pService = 0; + clsLEAMDNSHost::clsServiceTxt* pTxt = 0; + if (((pService = (clsLEAMDNSHost::clsService*)hostInformation.m_HandleToPtr[p_hService])) + && ((pTxt = (p_bDynamic + ? pService->addDynamicServiceTxt(p_pcKey, p_pcValue) + : pService->addServiceTxt(p_pcKey, p_pcValue))))) + { + if (!hResult) + { + hResult = (hMDNSTxt)pTxt; + } + hostInformation.m_HandleToPtr[hResult] = pTxt; + } + } + return hResult; +} + +/* + clsLEAMDNSHost_Legacy::_addServiceTxt (uint32_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value, + bool p_bDynamic) +{ + char acValueBuffer[16]; // 32-bit max 10 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%u", p_u32Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + clsLEAMDNSHost_Legacy::_addServiceTxt (uint16_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value, + bool p_bDynamic) +{ + char acValueBuffer[8]; // 16-bit max 5 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hu", p_u16Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + clsLEAMDNSHost_Legacy::_addServiceTxt (uint8_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value, + bool p_bDynamic) +{ + char acValueBuffer[8]; // 8-bit max 3 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hhu", p_u8Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + clsLEAMDNSHost_Legacy::_addServiceTxt (int32_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value, + bool p_bDynamic) +{ + char acValueBuffer[16]; // 32-bit max 11 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%i", p_i32Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + clsLEAMDNSHost_Legacy::_addServiceTxt (int16_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value, + bool p_bDynamic) +{ + char acValueBuffer[8]; // 16-bit max 6 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hi", p_i16Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + clsLEAMDNSHost_Legacy::_addServiceTxt (int8_t) + +*/ +clsLEAMDNSHost_Legacy::hMDNSTxt clsLEAMDNSHost_Legacy::_addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value, + bool p_bDynamic) +{ + char acValueBuffer[8]; // 8-bit max 4 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%hhi", p_i8Value); + + return _addServiceTxt(p_hService, p_pcKey, acValueBuffer, p_bDynamic); +} + +/* + clsLEAMDNSHost_Legacy::_answerFlagsToAnswerType + +*/ +clsLEAMDNSHost_Legacy::AnswerType clsLEAMDNSHost_Legacy::_answerFlagsToAnswerType(clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags) const +{ + AnswerType answerType = AnswerType::Unknown; + + if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Unknown) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::Unknown; + } + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::ServiceDomain; + } + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::HostDomain) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::HostDomainAndPort; + } + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Port) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::HostDomainAndPort; + } + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Txts) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::Txt; + } +#ifdef MDNS_IP4_SUPPORT + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::IP4Address; + } +#endif +#ifdef MDNS_IP6_SUPPORT + else if (static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address) & p_QueryAnswerTypeFlags) + { + answerType = AnswerType::IP6Address; + } +#endif + return answerType; +} + +/* + clsLEAMDNSHost_Legacy::_getAnswerAccessor + +*/ +clsLEAMDNSHost_Legacy::clsLEAMDNSHost::clsQuery::clsAnswerAccessor clsLEAMDNSHost_Legacy::_getAnswerAccessor(const uint32_t p_u32AnswerIndex) +{ + uint32_t u32AnswerIndexWithoutOffset = p_u32AnswerIndex; + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = hostInformation.m_pHost->getQuery(); + if (pQuery) + { + if (pQuery->answerCount() > u32AnswerIndexWithoutOffset) + { + return pQuery->answerAccessor(u32AnswerIndexWithoutOffset); + } + else + { + u32AnswerIndexWithoutOffset -= pQuery->answerCount(); + } + } + else + { + break; + } + } + return clsLEAMDNSHost::clsQuery::clsAnswerAccessor(0); +} + +/* + clsLEAMDNSHost_Legacy::_getAnswerAccessor + +*/ +clsLEAMDNSHost_Legacy::clsLEAMDNSHost::clsQuery::clsAnswerAccessor clsLEAMDNSHost_Legacy::_getAnswerAccessor(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + uint32_t u32AnswerIndexWithoutOffset = p_u32AnswerIndex; + for (stcHostInformation& hostInformation : m_HostInformations) + { + clsLEAMDNSHost::clsQuery* pQuery = (clsLEAMDNSHost::clsQuery*)hostInformation.m_HandleToPtr[p_hServiceQuery]; + if (pQuery) + { + if (pQuery->answerCount() > u32AnswerIndexWithoutOffset) + { + return pQuery->answerAccessor(u32AnswerIndexWithoutOffset); + } + else + { + u32AnswerIndexWithoutOffset -= pQuery->answerCount(); + } + } + else + { + break; + } + } + return clsLEAMDNSHost::clsQuery::clsAnswerAccessor(0); +} + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + + + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h index 3b37dd5451..be4a731216 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h @@ -1,679 +1,698 @@ -/* - * LEAmDNS2_Legacy.h - * (c) 2020, LaborEtArs - * - * Version 0.9 beta - * - * Some notes (from LaborEtArs, 2018): - * Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS). - * The target of this rewrite was to keep the existing interface as stable as possible while - * adding and extending the supported set of mDNS features. - * A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code. - * - * Supported mDNS features (in some cases somewhat limited): - * - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service - * - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented - * - Probing host and service domains for uniqueness in the local network - * - Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak) - * - Announcing available services after successful probing - * - Using fixed service TXT items or - * - Using dynamic service TXT items for presented services (via callback) - * - Remove services (and un-announcing them to the observers by sending goodbye-messages) - * - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) - * - Dynamic queries for DNS-SD services with cached and updated answers and user notifications - * - * - * Usage: - * In most cases, this implementation should work as a 'drop-in' replacement for the original - * ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some - * of the new features should be used. - * - * For presenting services: - * In 'setup()': - * Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);' - * Register DNS-SD services with 'clsLEAMDNSHost_Legacy::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);' - * (Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);') - * Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback - * using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific - * 'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);' - * Call MDNS.begin("MyHostname"); - * - * In 'probeResultCallback(clsLEAMDNSHost_Legacy* p_MDNSResponder, const char* p_pcDomain, clsLEAMDNSHost_Legacy:hMDNSService p_hService, bool p_bProbeResult, void* p_pUserdata)': - * Check the probe result and update the host or service domain name if the probe failed - * - * In 'dynamicServiceTxtCallback(clsLEAMDNSHost_Legacy* p_MDNSResponder, const hMDNSService p_hService, void* p_pUserdata)': - * Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hService, "c#", "1");' - * - * In loop(): - * Call 'MDNS.update();' - * - * - * For querying services: - * Static: - * Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");' - * Iterate answers by: 'for (uint32_t u=0; u MDNSDynamicServiceTxtCallbackFn; - - // Set a global callback for dynamic MDNS TXT items. The callback function is called - // every time, a TXT item is needed for one of the installed services. - bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn p_fnCallback); - - // Set a service specific callback for dynamic MDNS TXT items. The callback function - // is called every time, a TXT item is needed for the given service. - bool setDynamicServiceTxtCallback(const hMDNSService p_hService, - MDNSDynamicServiceTxtCallbackFn p_fnCallback); - - // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service - // Dynamic TXT items are removed right after one-time use. So they need to be added - // every time the value s needed (via callback). - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value); - - // Perform a (static) service query. The function returns after p_u16Timeout milliseconds - // The answers (the number of received answers is returned) can be retrieved by calling - // - answerHostname (or hostname) - // - answerIP (or IP) - // - answerPort (or port) - uint32_t queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout = clsConsts::u16StaticQueryWaitTime); - bool removeQuery(void); - // for compatibility... - uint32_t queryService(String p_strService, - String p_strProtocol); - - const char* answerHostname(const uint32_t p_u32AnswerIndex); - IPAddress answerIP(const uint32_t p_u32AnswerIndex); - uint16_t answerPort(const uint32_t p_u32AnswerIndex); - // for compatibility... - String hostname(const uint32_t p_u32AnswerIndex); - IPAddress IP(const uint32_t p_u32AnswerIndex); - uint16_t port(const uint32_t p_u32AnswerIndex); - - /** - * hMDNSServiceQuery (opaque handle to access dynamic service queries) - */ - typedef const void* hMDNSServiceQuery; - - /** - * enuServiceQueryAnswerType - */ - typedef enum _enuServiceQueryAnswerType { - ServiceQueryAnswerType_Unknown = 0, - ServiceQueryAnswerType_ServiceDomain = (1 << 0), // Service instance name - ServiceQueryAnswerType_HostDomainAndPort = (1 << 1), // Host domain and service port - ServiceQueryAnswerType_Txts = (1 << 2), // TXT items -#ifdef MDNS_IP4_SUPPORT - ServiceQueryAnswerType_IP4Address = (1 << 3), // IP4 address -#endif -#ifdef MDNS_IP6_SUPPORT - ServiceQueryAnswerType_IP6Address = (1 << 4), // IP6 address -#endif - } enuServiceQueryAnswerType; - - /** - * AnswerType (std::map compatible version) - */ - enum class AnswerType : uint32_t { - Unknown = ServiceQueryAnswerType_Unknown, - ServiceDomain = ServiceQueryAnswerType_ServiceDomain, - HostDomainAndPort = ServiceQueryAnswerType_HostDomainAndPort, - Txt = ServiceQueryAnswerType_Txts, -#ifdef MDNS_IP4_SUPPORT - IP4Address = ServiceQueryAnswerType_IP4Address, -#endif -#ifdef MDNS_IP6_SUPPORT - IP6Address = ServiceQueryAnswerType_IP6Address -#endif - }; - - /** - * stcMDNSServiceInfo - */ - struct stcMDNSServiceInfo { - stcMDNSServiceInfo(const clsLEAMDNSHost::clsQuery::clsAnswerAccessor& p_rAnswerAccessor) - : m_rAnswerAccessor(p_rAnswerAccessor) {}; - /** - * stcCompareKey - */ - struct stcCompareKey { - /* - * operator () - */ - bool operator()(char const* p_pA, char const* p_pB) const { - return (0 > strcmp(p_pA, p_pB)); - } - }; - /** - * clsKeyValueMap - */ - using clsKeyValueMap = std::map; - - protected: - const clsLEAMDNSHost::clsQuery::clsAnswerAccessor& m_rAnswerAccessor; - clsKeyValueMap m_KeyValueMap; - - public: - /* - * serviceDomain - */ - const char* serviceDomain(void) const { - return (m_rAnswerAccessor.serviceDomainAvailable() - ? m_rAnswerAccessor.serviceDomain() - : nullptr); - } - /* - * hostDomainAvailable - */ - bool hostDomainAvailable(void) const { - return m_rAnswerAccessor.serviceDomainAvailable(); - } - /* - * hostDomain - */ - const char* hostDomain(void) const { - return (hostDomainAvailable() - ? m_rAnswerAccessor.hostDomain() - : nullptr); - } - /* - * hostPortAvailable - */ - bool hostPortAvailable(void) const { - return m_rAnswerAccessor.hostPortAvailable(); - } - /* - * hostPort - */ - uint16_t hostPort(void) const { - return (hostPortAvailable() - ? m_rAnswerAccessor.hostPort() - : 0); - } -#ifdef MDNS_IP4_SUPPORT - /* - * IP4AddressAvailable - */ - bool IP4AddressAvailable(void) const { - return m_rAnswerAccessor.IPv4AddressAvailable(); - } - /* - * IP4Addresses - */ - std::vector IP4Adresses(void) const { - return (IP4AddressAvailable() - ? m_rAnswerAccessor.IPv4Addresses() - : std::vector()); - } -#endif -#ifdef MDNS_IP6_SUPPORT - /* - * IP6AddressAvailable - */ - bool IP6AddressAvailable(void) const { - return m_rAnswerAccessor.IPv6AddressAvailable(); - } - /* - * IP6Addresses - */ - std::vector IP6Adresses(void) const { - return (IP6AddressAvailable() - ? m_rAnswerAccessor.IPv6Addresses() - : std::vector()); - } -#endif - /* - * txtAvailable - */ - bool txtAvailable(void) const { - return m_rAnswerAccessor.txtsAvailable(); - } - /* - * strKeyValue -> abc=def;hij=klm; - */ - const char* strKeyValue (void) const { - // TODO - return nullptr; - } - /* - * keyValues -> abc=def hij=klm ... - */ - const clsKeyValueMap& keyValues(void) { - if ((txtAvailable()) && - (0 == m_KeyValueMap.size())) { - for (auto kv : m_rAnswerAccessor.txtKeyValues()) - { - m_KeyValueMap.emplace(std::pair(kv.first, kv.second)); - } - //for (auto kv=m_rMDNSResponder._answerKeyValue(m_hServiceQuery, m_u32AnswerIndex); kv!=nullptr; kv=kv->m_pNext) { - // m_KeyValueMap.emplace(std::pair(kv->m_pcKey, kv->m_pcValue)); - //} - } - return m_KeyValueMap; - } - /* - * value (abc)->def - */ - const char* value(const char* p_pcKey) const { - return m_rAnswerAccessor.txtValue(p_pcKey); - } - }; - - /** - * MDNSServiceQueryCallbackFn - * - * Callback function for received answers for dynamic service queries - */ - typedef std::function MDNSServiceQueryCallbackFn; - - // Install a dynamic service query. For every received answer (part) the given callback - // function is called. The query will be updated every time, the TTL for an answer - // has timed-out. - // The answers can also be retrieved by calling - // - answerCount - // - answerServiceDomain - // - hasAnswerHostDomain/answerHostDomain - // - hasAnswerIP4Address/answerIP4Address - // - hasAnswerIP6Address/answerIP6Address - // - hasAnswerPort/answerPort - // - hasAnswerTxts/answerTxts - hMDNSServiceQuery installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSServiceQueryCallbackFn p_fnCallback); - // Remove a dynamic service query - bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery); - - uint32_t answerCount(const hMDNSServiceQuery p_hServiceQuery); - std::vector answerInfo(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery); - const char* answerServiceDomain(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerHostDomain(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - const char* answerHostDomain(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); -#ifdef MDNS_IP4_SUPPORT - bool hasAnswerIP4Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIP4AddressCount(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIP4Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); -#endif -#ifdef MDNS_IP6_SUPPORT - bool hasAnswerIP6Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIP6AddressCount(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIP6Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); -#endif - bool hasAnswerPort(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - uint16_t answerPort(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerTxts(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - // Get the TXT items as a ';'-separated string - const char* answerTxts(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - - /** - * MDNSHostProbeResultCallbackFn/2 - * Callback function for host domain probe results - */ - typedef std::function MDNSHostProbeResultCallbackFn; - - typedef std::function MDNSHostProbeResultCallbackFn2; - - // Set a callback function for host probe results - // The callback function is called, when the probeing for the host domain - // succeededs or fails. - // In case of failure, the failed domain name should be changed. - bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn p_fnCallback); - bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn2 p_fnCallback); - - /** - * MDNSServiceProbeResultCallbackFn/2 - * Callback function for service domain probe results - */ - typedef std::function MDNSServiceProbeResultCallbackFn; - - typedef std::function MDNSServiceProbeResultCallbackFn2; - - // Set a service specific probe result callcack - bool setServiceProbeResultCallback(const hMDNSService p_hService, - MDNSServiceProbeResultCallbackFn p_fnCallback); - bool setServiceProbeResultCallback(const hMDNSService p_hService, - MDNSServiceProbeResultCallbackFn2 p_fnCallback); - - // Application should call this whenever AP is configured/disabled - bool notifyAPChange(void); - - // 'update' should be called in every 'loop' to run the MDNS processing - bool update(void); - - // 'announce' can be called every time, the configuration of some service - // changes. Mainly, this would be changed content of TXT items. - bool announce(void); - - // Enable OTA update - hMDNSService enableArduino(uint16_t p_u16Port, - bool p_bAuthUpload = false); - - // Domain name helper - static bool indexDomain(char*& p_rpcDomain, - const char* p_pcDivider = "-", - const char* p_pcDefaultDomain = 0); - -protected: - /** - * stcHostInformation - */ - struct stcHostInformation - { - /** - * clsHandleToPtrMap - */ - using clsHandleToPtrMap = std::map; - - clsLEAMDNSHost* m_pHost; - clsHandleToPtrMap m_HandleToPtr; - - stcHostInformation(clsLEAMDNSHost* p_pHost) - : m_pHost(p_pHost) - {} - - /** - * list - */ - using list = std::list; - }; - - stcHostInformation::list m_HostInformations; - - // HELPERS - hMDNSTxt _addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bDynamic); - hMDNSTxt _addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value, - bool p_bDynamic); - hMDNSTxt _addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value, - bool p_bDynamic); - hMDNSTxt _addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value, - bool p_bDynamic); - hMDNSTxt _addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value, - bool p_bDynamic); - hMDNSTxt _addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value, - bool p_bDynamic); - hMDNSTxt _addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value, - bool p_bDynamic); - - AnswerType _answerFlagsToAnswerType(clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags) const; - - clsLEAMDNSHost::clsQuery::clsAnswerAccessor _getAnswerAccessor(const uint32_t p_u32AnswerIndex); - clsLEAMDNSHost::clsQuery::clsAnswerAccessor _getAnswerAccessor(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - -}; - - -} // namespace MDNSImplementation - - -} // namespace esp8266 - - -#endif // __LEAMDNS2HOST_LEGACY_H__ - - - - - - +/* + LEAmDNS2_Legacy.h + (c) 2020, LaborEtArs + + Version 0.9 beta + + Some notes (from LaborEtArs, 2018): + Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS). + The target of this rewrite was to keep the existing interface as stable as possible while + adding and extending the supported set of mDNS features. + A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code. + + Supported mDNS features (in some cases somewhat limited): + - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service + - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented + - Probing host and service domains for uniqueness in the local network + - Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak) + - Announcing available services after successful probing + - Using fixed service TXT items or + - Using dynamic service TXT items for presented services (via callback) + - Remove services (and un-announcing them to the observers by sending goodbye-messages) + - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) + - Dynamic queries for DNS-SD services with cached and updated answers and user notifications + + + Usage: + In most cases, this implementation should work as a 'drop-in' replacement for the original + ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some + of the new features should be used. + + For presenting services: + In 'setup()': + Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);' + Register DNS-SD services with 'clsLEAMDNSHost_Legacy::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);' + (Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);') + Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback + using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific + 'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);' + Call MDNS.begin("MyHostname"); + + In 'probeResultCallback(clsLEAMDNSHost_Legacy* p_MDNSResponder, const char* p_pcDomain, clsLEAMDNSHost_Legacy:hMDNSService p_hService, bool p_bProbeResult, void* p_pUserdata)': + Check the probe result and update the host or service domain name if the probe failed + + In 'dynamicServiceTxtCallback(clsLEAMDNSHost_Legacy* p_MDNSResponder, const hMDNSService p_hService, void* p_pUserdata)': + Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hService, "c#", "1");' + + In loop(): + Call 'MDNS.update();' + + + For querying services: + Static: + Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");' + Iterate answers by: 'for (uint32_t u=0; u MDNSDynamicServiceTxtCallbackFn; + + // Set a global callback for dynamic MDNS TXT items. The callback function is called + // every time, a TXT item is needed for one of the installed services. + bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFn p_fnCallback); + + // Set a service specific callback for dynamic MDNS TXT items. The callback function + // is called every time, a TXT item is needed for the given service. + bool setDynamicServiceTxtCallback(const hMDNSService p_hService, + MDNSDynamicServiceTxtCallbackFn p_fnCallback); + + // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + // Dynamic TXT items are removed right after one-time use. So they need to be added + // every time the value s needed (via callback). + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value); + + // Perform a (static) service query. The function returns after p_u16Timeout milliseconds + // The answers (the number of received answers is returned) can be retrieved by calling + // - answerHostname (or hostname) + // - answerIP (or IP) + // - answerPort (or port) + uint32_t queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout = clsConsts::u16StaticQueryWaitTime); + bool removeQuery(void); + // for compatibility... + uint32_t queryService(String p_strService, + String p_strProtocol); + + const char* answerHostname(const uint32_t p_u32AnswerIndex); + IPAddress answerIP(const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const uint32_t p_u32AnswerIndex); + // for compatibility... + String hostname(const uint32_t p_u32AnswerIndex); + IPAddress IP(const uint32_t p_u32AnswerIndex); + uint16_t port(const uint32_t p_u32AnswerIndex); + + /** + hMDNSServiceQuery (opaque handle to access dynamic service queries) + */ + typedef const void* hMDNSServiceQuery; + + /** + enuServiceQueryAnswerType + */ + typedef enum _enuServiceQueryAnswerType + { + ServiceQueryAnswerType_Unknown = 0, + ServiceQueryAnswerType_ServiceDomain = (1 << 0), // Service instance name + ServiceQueryAnswerType_HostDomainAndPort = (1 << 1), // Host domain and service port + ServiceQueryAnswerType_Txts = (1 << 2), // TXT items +#ifdef MDNS_IP4_SUPPORT + ServiceQueryAnswerType_IP4Address = (1 << 3), // IP4 address +#endif +#ifdef MDNS_IP6_SUPPORT + ServiceQueryAnswerType_IP6Address = (1 << 4), // IP6 address +#endif + } enuServiceQueryAnswerType; + + /** + AnswerType (std::map compatible version) + */ + enum class AnswerType : uint32_t + { + Unknown = ServiceQueryAnswerType_Unknown, + ServiceDomain = ServiceQueryAnswerType_ServiceDomain, + HostDomainAndPort = ServiceQueryAnswerType_HostDomainAndPort, + Txt = ServiceQueryAnswerType_Txts, +#ifdef MDNS_IP4_SUPPORT + IP4Address = ServiceQueryAnswerType_IP4Address, +#endif +#ifdef MDNS_IP6_SUPPORT + IP6Address = ServiceQueryAnswerType_IP6Address +#endif + }; + + /** + stcMDNSServiceInfo + */ + struct stcMDNSServiceInfo + { + stcMDNSServiceInfo(const clsLEAMDNSHost::clsQuery::clsAnswerAccessor& p_rAnswerAccessor) + : m_rAnswerAccessor(p_rAnswerAccessor) {}; + /** + stcCompareKey + */ + struct stcCompareKey + { + /* + operator () + */ + bool operator()(char const* p_pA, char const* p_pB) const + { + return (0 > strcmp(p_pA, p_pB)); + } + }; + /** + clsKeyValueMap + */ + using clsKeyValueMap = std::map; + + protected: + const clsLEAMDNSHost::clsQuery::clsAnswerAccessor& m_rAnswerAccessor; + clsKeyValueMap m_KeyValueMap; + + public: + /* + serviceDomain + */ + const char* serviceDomain(void) const + { + return (m_rAnswerAccessor.serviceDomainAvailable() + ? m_rAnswerAccessor.serviceDomain() + : nullptr); + } + /* + hostDomainAvailable + */ + bool hostDomainAvailable(void) const + { + return m_rAnswerAccessor.serviceDomainAvailable(); + } + /* + hostDomain + */ + const char* hostDomain(void) const + { + return (hostDomainAvailable() + ? m_rAnswerAccessor.hostDomain() + : nullptr); + } + /* + hostPortAvailable + */ + bool hostPortAvailable(void) const + { + return m_rAnswerAccessor.hostPortAvailable(); + } + /* + hostPort + */ + uint16_t hostPort(void) const + { + return (hostPortAvailable() + ? m_rAnswerAccessor.hostPort() + : 0); + } +#ifdef MDNS_IP4_SUPPORT + /* + IP4AddressAvailable + */ + bool IP4AddressAvailable(void) const + { + return m_rAnswerAccessor.IPv4AddressAvailable(); + } + /* + IP4Addresses + */ + std::vector IP4Adresses(void) const + { + return (IP4AddressAvailable() + ? m_rAnswerAccessor.IPv4Addresses() + : std::vector()); + } +#endif +#ifdef MDNS_IP6_SUPPORT + /* + IP6AddressAvailable + */ + bool IP6AddressAvailable(void) const + { + return m_rAnswerAccessor.IPv6AddressAvailable(); + } + /* + IP6Addresses + */ + std::vector IP6Adresses(void) const + { + return (IP6AddressAvailable() + ? m_rAnswerAccessor.IPv6Addresses() + : std::vector()); + } +#endif + /* + txtAvailable + */ + bool txtAvailable(void) const + { + return m_rAnswerAccessor.txtsAvailable(); + } + /* + strKeyValue -> abc=def;hij=klm; + */ + const char* strKeyValue(void) const + { + // TODO + return nullptr; + } + /* + keyValues -> abc=def hij=klm ... + */ + const clsKeyValueMap& keyValues(void) + { + if ((txtAvailable()) && + (0 == m_KeyValueMap.size())) + { + for (auto kv : m_rAnswerAccessor.txtKeyValues()) + { + m_KeyValueMap.emplace(std::pair(kv.first, kv.second)); + } + //for (auto kv=m_rMDNSResponder._answerKeyValue(m_hServiceQuery, m_u32AnswerIndex); kv!=nullptr; kv=kv->m_pNext) { + // m_KeyValueMap.emplace(std::pair(kv->m_pcKey, kv->m_pcValue)); + //} + } + return m_KeyValueMap; + } + /* + value (abc)->def + */ + const char* value(const char* p_pcKey) const + { + return m_rAnswerAccessor.txtValue(p_pcKey); + } + }; + + /** + MDNSServiceQueryCallbackFn + + Callback function for received answers for dynamic service queries + */ + typedef std::function MDNSServiceQueryCallbackFn; + + // Install a dynamic service query. For every received answer (part) the given callback + // function is called. The query will be updated every time, the TTL for an answer + // has timed-out. + // The answers can also be retrieved by calling + // - answerCount + // - answerServiceDomain + // - hasAnswerHostDomain/answerHostDomain + // - hasAnswerIP4Address/answerIP4Address + // - hasAnswerIP6Address/answerIP6Address + // - hasAnswerPort/answerPort + // - hasAnswerTxts/answerTxts + hMDNSServiceQuery installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSServiceQueryCallbackFn p_fnCallback); + // Remove a dynamic service query + bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery); + + uint32_t answerCount(const hMDNSServiceQuery p_hServiceQuery); + std::vector answerInfo(const clsLEAMDNSHost_Legacy::hMDNSServiceQuery p_hServiceQuery); + const char* answerServiceDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerHostDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + const char* answerHostDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); +#ifdef MDNS_IP4_SUPPORT + bool hasAnswerIP4Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIP4AddressCount(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIP4Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif +#ifdef MDNS_IP6_SUPPORT + bool hasAnswerIP6Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIP6AddressCount(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIP6Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif + bool hasAnswerPort(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerTxts(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + // Get the TXT items as a ';'-separated string + const char* answerTxts(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + + /** + MDNSHostProbeResultCallbackFn/2 + Callback function for host domain probe results + */ + typedef std::function MDNSHostProbeResultCallbackFn; + + typedef std::function MDNSHostProbeResultCallbackFn2; + + // Set a callback function for host probe results + // The callback function is called, when the probeing for the host domain + // succeededs or fails. + // In case of failure, the failed domain name should be changed. + bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn p_fnCallback); + bool setHostProbeResultCallback(MDNSHostProbeResultCallbackFn2 p_fnCallback); + + /** + MDNSServiceProbeResultCallbackFn/2 + Callback function for service domain probe results + */ + typedef std::function MDNSServiceProbeResultCallbackFn; + + typedef std::function MDNSServiceProbeResultCallbackFn2; + + // Set a service specific probe result callcack + bool setServiceProbeResultCallback(const hMDNSService p_hService, + MDNSServiceProbeResultCallbackFn p_fnCallback); + bool setServiceProbeResultCallback(const hMDNSService p_hService, + MDNSServiceProbeResultCallbackFn2 p_fnCallback); + + // Application should call this whenever AP is configured/disabled + bool notifyAPChange(void); + + // 'update' should be called in every 'loop' to run the MDNS processing + bool update(void); + + // 'announce' can be called every time, the configuration of some service + // changes. Mainly, this would be changed content of TXT items. + bool announce(void); + + // Enable OTA update + hMDNSService enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload = false); + + // Domain name helper + static bool indexDomain(char*& p_rpcDomain, + const char* p_pcDivider = "-", + const char* p_pcDefaultDomain = 0); + +protected: + /** + stcHostInformation + */ + struct stcHostInformation + { + /** + clsHandleToPtrMap + */ + using clsHandleToPtrMap = std::map; + + clsLEAMDNSHost* m_pHost; + clsHandleToPtrMap m_HandleToPtr; + + stcHostInformation(clsLEAMDNSHost* p_pHost) + : m_pHost(p_pHost) + {} + + /** + list + */ + using list = std::list; + }; + + stcHostInformation::list m_HostInformations; + + // HELPERS + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value, + bool p_bDynamic); + hMDNSTxt _addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value, + bool p_bDynamic); + + AnswerType _answerFlagsToAnswerType(clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags) const; + + clsLEAMDNSHost::clsQuery::clsAnswerAccessor _getAnswerAccessor(const uint32_t p_u32AnswerIndex); + clsLEAMDNSHost::clsQuery::clsAnswerAccessor _getAnswerAccessor(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + +}; + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + +#endif // __LEAMDNS2HOST_LEGACY_H__ + + + + + + From 1910848a029db8b72994a95dd9b3e298b34741df Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 8 May 2020 15:49:38 +0200 Subject: [PATCH 05/12] two interface example is working (also with IPv6) --- .../{src => OLDmDNS}/ESP8266mDNS_Legacy.cpp | 0 .../{src => OLDmDNS}/ESP8266mDNS_Legacy.h | 0 .../ESP8266mDNS/{src => OLDmDNS}/LEAmDNS.cpp | 0 .../ESP8266mDNS/{src => OLDmDNS}/LEAmDNS.h | 0 .../{src => OLDmDNS}/LEAmDNS_Control.cpp | 0 .../{src => OLDmDNS}/LEAmDNS_Helpers.cpp | 0 .../{src => OLDmDNS}/LEAmDNS_Priv.h | 0 .../{src => OLDmDNS}/LEAmDNS_Structs.cpp | 0 .../{src => OLDmDNS}/LEAmDNS_Transfer.cpp | 0 .../{src => OLDmDNS}/LEAmDNS_lwIPdefs.h | 0 .../LEAmDNS/TwoInterfaces/TwoInterfaces.ino | 24 +++++++++++++------ libraries/ESP8266mDNS/src/ESP8266mDNS.h | 5 ++-- 12 files changed, 20 insertions(+), 9 deletions(-) rename libraries/ESP8266mDNS/{src => OLDmDNS}/ESP8266mDNS_Legacy.cpp (100%) rename libraries/ESP8266mDNS/{src => OLDmDNS}/ESP8266mDNS_Legacy.h (100%) rename libraries/ESP8266mDNS/{src => OLDmDNS}/LEAmDNS.cpp (100%) rename libraries/ESP8266mDNS/{src => OLDmDNS}/LEAmDNS.h (100%) rename libraries/ESP8266mDNS/{src => OLDmDNS}/LEAmDNS_Control.cpp (100%) rename libraries/ESP8266mDNS/{src => OLDmDNS}/LEAmDNS_Helpers.cpp (100%) rename libraries/ESP8266mDNS/{src => OLDmDNS}/LEAmDNS_Priv.h (100%) rename libraries/ESP8266mDNS/{src => OLDmDNS}/LEAmDNS_Structs.cpp (100%) rename libraries/ESP8266mDNS/{src => OLDmDNS}/LEAmDNS_Transfer.cpp (100%) rename libraries/ESP8266mDNS/{src => OLDmDNS}/LEAmDNS_lwIPdefs.h (100%) diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp b/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp similarity index 100% rename from libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp rename to libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.h b/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h similarity index 100% rename from libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.h rename to libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp similarity index 100% rename from libraries/ESP8266mDNS/src/LEAmDNS.cpp rename to libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.h b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h similarity index 100% rename from libraries/ESP8266mDNS/src/LEAmDNS.h rename to libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp similarity index 100% rename from libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp rename to libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp similarity index 100% rename from libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp rename to libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h similarity index 100% rename from libraries/ESP8266mDNS/src/LEAmDNS_Priv.h rename to libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp similarity index 100% rename from libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp rename to libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp similarity index 100% rename from libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp rename to libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h similarity index 100% rename from libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h rename to libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h diff --git a/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino b/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino index 3f06f543b7..4bbdbd157b 100644 --- a/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino +++ b/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino @@ -5,9 +5,18 @@ #include #include - -clsMDNSHost mDNSHost_AP; -clsMDNSHost mDNSHost_STA; +#ifndef STASSID +#define STASSID "ssid" +#define STAPSK "12345678" +#endif + +#ifndef APSSID +#define APSSID "espap" +#define APPSK "12345678" +#endif + +clsMDNSHost mDNSHost_AP; +clsMDNSHost mDNSHost_STA; ESP8266WebServer server(80); void connectToWiFi(const char* p_pcSSID, @@ -43,7 +52,7 @@ void setup(void) { // Setup WiFi and AP WiFi.setAutoConnect(false); WiFi.mode(WIFI_AP_STA); - WiFi.softAP("ESP8266", "12345678"); + WiFi.softAP(APSSID, APPSK); Serial.print("Created AP "); Serial.println("ESP8266"); Serial.print("AP-IP address: "); @@ -62,8 +71,9 @@ void setup(void) { Serial.println("FAILED to start mDNS-AP"); } - // Connect to WiFi network, with WRONG password - connectToWiFi("AP8", "WRONG_PW", 5); + // Connect to WiFi network, with WRONG password (timeout 5 seconds) + // (good password will be given in `loop()`) + connectToWiFi(STASSID, "WRONG_PW", 5); if (mDNSHost_STA.begin("esp8266", WIFI_STA, [](clsMDNSHost & p_rMDNSHost, const char* p_pcDomainName, @@ -125,7 +135,7 @@ void loop(void) { static esp8266::polledTimeout::oneShotMs timer2(esp8266::polledTimeout::oneShotMs::alwaysExpired); if (timer2) { Serial.println("FIX PASSWORD"); - connectToWiFi("AP8", "_______"); + connectToWiFi(STASSID, STAPSK); timer2.reset(esp8266::polledTimeout::oneShotMs::neverExpires); } diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS.h b/libraries/ESP8266mDNS/src/ESP8266mDNS.h index fdcf489fb0..467367b564 100644 --- a/libraries/ESP8266mDNS/src/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/src/ESP8266mDNS.h @@ -42,8 +42,8 @@ */ -#include "ESP8266mDNS_Legacy.h" -#include "LEAmDNS.h" +//#include "ESP8266mDNS_Legacy.h" +//#include "LEAmDNS.h" #include "LEAmDNS2Host.h" @@ -53,6 +53,7 @@ //using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new //using MDNSResponder = esp8266::experimental::MDNSResponder; //new^2 not compatible using clsMDNSHost = esp8266::experimental::clsLEAMDNSHost; +using MDNSResponder = esp8266::experimental::clsLEAMDNSHost; //extern MDNSResponder MDNS; #endif From c19266751dc14c6b402f5782157e02f3d1268d5d Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 8 May 2020 18:43:47 +0200 Subject: [PATCH 06/12] restored former versions (legacy, LEAv1), clock example for new API --- .../LEAmDNS/TwoInterfaces/TwoInterfaces.ino | 2 + .../LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino | 241 ++ libraries/ESP8266mDNS/src/ESP8266mDNS.h | 18 +- .../ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp | 1523 ++++++++++ .../ESP8266mDNS/src/ESP8266mDNS_Legacy.h | 169 ++ libraries/ESP8266mDNS/src/LEAmDNS.cpp | 1382 +++++++++ libraries/ESP8266mDNS/src/LEAmDNS.h | 1464 ++++++++++ libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp | 1 + libraries/ESP8266mDNS/src/LEAmDNS2Host.h | 12 +- .../ESP8266mDNS/src/LEAmDNS2Host_Control.cpp | 1 + .../ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp | 1 + .../ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp | 1 + .../ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp | 2 +- .../ESP8266mDNS/src/LEAmDNS2_Backbone.cpp | 1 + libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp | 1 + libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp | 2135 ++++++++++++++ libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp | 851 ++++++ libraries/ESP8266mDNS/src/LEAmDNS_Priv.h | 182 ++ libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp | 2477 +++++++++++++++++ .../ESP8266mDNS/src/LEAmDNS_Transfer.cpp | 1780 ++++++++++++ libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h | 44 + 21 files changed, 12274 insertions(+), 14 deletions(-) create mode 100644 libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino create mode 100644 libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp create mode 100644 libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.h create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS.cpp create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS.h create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS_Priv.h create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp create mode 100644 libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h diff --git a/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino b/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino index 4bbdbd157b..f561b867f6 100644 --- a/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino +++ b/libraries/ESP8266mDNS/examples/LEAmDNS/TwoInterfaces/TwoInterfaces.ino @@ -15,6 +15,8 @@ #define APPSK "12345678" #endif +// uses API MDNSApiVersion::LEAv2 + clsMDNSHost mDNSHost_AP; clsMDNSHost mDNSHost_STA; ESP8266WebServer server(80); diff --git a/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino b/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino new file mode 100644 index 0000000000..5c429226f4 --- /dev/null +++ b/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino @@ -0,0 +1,241 @@ +/* + ESP8266 mDNS responder clock + + This example demonstrates two features of the LEA clsMDNSHost: + 1. The host and service domain negotiation process that ensures + the uniqueness of the finally choosen host and service domain name. + 2. The dynamic MDNS service TXT feature + + A 'clock' service in announced via the MDNS responder and the current + time is set as a TXT item (eg. 'curtime=Mon Oct 15 19:54:35 2018'). + The time value is updated every second! + + The ESP is initially announced to clients as 'esp8266.local', if this host domain + is already used in the local network, another host domain is negociated. Keep an + eye to the serial output to learn the final host domain for the clock service. + The service itself is is announced as 'host domain'._espclk._tcp.local. + As the service uses port 80, a very simple HTTP server is installed also to deliver + a small web page containing a greeting and the current time (not updated). + The web server code is taken nearly 1:1 from the 'mDNS_Web_Server.ino' example. + Point your browser to 'host domain'.local to see this web page. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to the ESP8266 board + - Install host software: + - For Linux, install Avahi (http://avahi.org/). + - For Windows, install Bonjour (http://www.apple.com/support/bonjour/). + - For Mac OSX and iOS support is built in through Bonjour already. + - Use a MDNS/Bonjour browser like 'Discovery' to find the clock service in your local + network and see the current time updates. + +*/ + + +#include +#include +#include +#include + +// uses API MDNSApiVersion::LEAv2 + +/* + Include the clsMDNSHost (the library needs to be included also) + As LEA clsMDNSHost is experimantal in the ESP8266 environment currently, the + legacy clsMDNSHost is defaulted in th include file. + There are two ways to access LEA clsMDNSHost: + 1. Prepend every declaration and call to global declarations or functions with the namespace, like: + 'LEAmDNS::clsMDNSHost::hMDNSService hMDNSService;' + This way is used in the example. But be careful, if the namespace declaration is missing + somewhere, the call might go to the legacy implementation... + 2. Open 'ESP8266mDNS.h' and set LEAmDNS to default. + +*/ +#include +#include +/* + Global defines and vars +*/ + + +#define TIMEZONE_OFFSET 1 // CET +#define DST_OFFSET 1 // CEST +#define UPDATE_CYCLE (1 * 1000) // every second + +#define SERVICE_PORT 80 // HTTP port + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +clsMDNSHost responder; // MDNS responder +bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain +clsMDNSHost::clsService* hMDNSService = 0; // The handle of the clock service in the MDNS responder + +// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests +ESP8266WebServer server(SERVICE_PORT); + +/* + getTimeString +*/ +const char* getTimeString(void) { + + static char acTimeString[32]; + time_t now = time(nullptr); + ctime_r(&now, acTimeString); + size_t stLength; + while (((stLength = strlen(acTimeString))) && + ('\n' == acTimeString[stLength - 1])) { + acTimeString[stLength - 1] = 0; // Remove trailing line break... + } + return acTimeString; +} + + +/* + setClock + + Set time via NTP +*/ +void setClock(void) { + configTime((TIMEZONE_OFFSET * 3600), (DST_OFFSET * 3600), "pool.ntp.org", "time.nist.gov", "time.windows.com"); + + Serial.print("Waiting for NTP time sync: "); + time_t now = time(nullptr); // Secs since 01.01.1970 (when uninitalized starts with (8 * 3600 = 28800) + while (now < 8 * 3600 * 2) { // Wait for realistic value + delay(500); + Serial.print("."); + now = time(nullptr); + } + Serial.println(""); + Serial.printf("Current time: %s\n", getTimeString()); +} + + +/* + setStationHostname +*/ +bool setStationHostname(const char* p_pcHostname) { + + if (p_pcHostname) { + WiFi.hostname(p_pcHostname); + Serial.printf("setDeviceHostname: Station hostname is set to '%s'\n", p_pcHostname); + } + return true; +} + + +/* + MDNSDynamicServiceTxtCallback + + Add a dynamic MDNS TXT item 'ct' to the clock service. + The callback function is called every time, the TXT items for the clock service + are needed. + This can be triggered by calling responder.announce(). + +*/ +void MDNSDynamicServiceTxtCallback(const clsMDNSHost::hMDNSService& p_hService) { + Serial.println("MDNSDynamicServiceTxtCallback"); + + if (hMDNSService == &p_hService) { + Serial.printf("Updating curtime TXT item to: %s\n", getTimeString()); + hMDNSService->addDynamicServiceTxt("curtime", getTimeString()); + } +} + + +/* + handleHTTPClient +*/ + +void handleHTTPRequest() { + Serial.println(""); + Serial.println("HTTP Request"); + + // Get current time + time_t now = time(nullptr);; + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + + String s; + + s = "\r\nHello from "; + s += WiFi.hostname() + " at " + WiFi.localIP().toString(); + // Simple addition of the current time + s += "\r\nCurrent time is: "; + s += getTimeString(); + // done :-) + s += "\r\n\r\n"; + Serial.println("Sending 200"); + server.send(200, "text/html", s); +} + +/* + setup +*/ +void setup(void) { + Serial.begin(115200); + + // Connect to WiFi network + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // Sync clock + setClock(); + + // Setup MDNS responder + // Init the (currently empty) host domain string with 'esp8266' + if (responder.begin("ESP8266", WIFI_STA, [](clsMDNSHost & p_rMDNSHost, + const char* p_pcDomainName, + bool p_bProbeResult)->void { + Serial.printf("mDNSHost_AP::ProbeResultCallback: '%s' is %s\n", p_pcDomainName, (p_bProbeResult ? "FREE" : "USED!")); + // Unattended added service + p_rMDNSHost.addService(0, "http", "tcp", 80); + })) { + Serial.println("mDNS-AP started"); + } else { + Serial.println("FAILED to start mDNS-AP"); + } + + // Setup HTTP server + server.on("/", handleHTTPRequest); + server.begin(); + Serial.println("HTTP server started"); +} + +/* + loop +*/ +void loop(void) { + + // Check if a request has come in + server.handleClient(); + // Allow MDNS processing + responder.update(); + + static esp8266::polledTimeout::periodicMs timeout(UPDATE_CYCLE); + if (timeout.expired()) { + + if (hMDNSService) { + // Just trigger a new MDNS announcement, this will lead to a call to + // 'MDNSDynamicServiceTxtCallback', which will update the time TXT item + responder.announce(); + } + } +} diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS.h b/libraries/ESP8266mDNS/src/ESP8266mDNS.h index 467367b564..c3713c6689 100644 --- a/libraries/ESP8266mDNS/src/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/src/ESP8266mDNS.h @@ -42,19 +42,19 @@ */ -//#include "ESP8266mDNS_Legacy.h" -//#include "LEAmDNS.h" -#include "LEAmDNS2Host.h" +enum class MDNSApiVersion { Legacy, LEA, LEAv2 }; +#include "ESP8266mDNS_Legacy.h" +#include "LEAmDNS.h" +#include "LEAmDNS2Host.h" +using clsMDNSHost = esp8266::experimental::clsLEAMDNSHost; #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) // Maps the implementation to use to the global namespace type -//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; //legacy -//using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new -//using MDNSResponder = esp8266::experimental::MDNSResponder; //new^2 not compatible -using clsMDNSHost = esp8266::experimental::clsLEAMDNSHost; -using MDNSResponder = esp8266::experimental::clsLEAMDNSHost; +//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; // Legacy +using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; // LEA +//using MDNSResponder = clsMDNSHost; // LEAv2 -//extern MDNSResponder MDNS; +extern MDNSResponder MDNS; #endif diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp b/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp new file mode 100644 index 0000000000..8791195523 --- /dev/null +++ b/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp @@ -0,0 +1,1523 @@ +/* + + ESP8266 Multicast DNS (port of CC3000 Multicast DNS library) + Version 1.1 + Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) + ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com) + MDNS-SD Suport 2015 Hristo Gochkov + Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com) + + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +// Important RFC's for reference: +// - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt +// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt +// - MDNS-SD: https://tools.ietf.org/html/rfc6763 + +#ifndef LWIP_OPEN_SRC +#define LWIP_OPEN_SRC +#endif + +#include "ESP8266mDNS.h" +#include + +#include "debug.h" + +extern "C" { +#include "osapi.h" +#include "ets_sys.h" +#include "user_interface.h" +} + +#include "WiFiUdp.h" +#include "lwip/opt.h" +#include "lwip/udp.h" +#include "lwip/inet.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include "include/UdpContext.h" + + + +namespace Legacy_MDNSResponder +{ + + +#ifdef DEBUG_ESP_MDNS +#define DEBUG_ESP_MDNS_ERR +#define DEBUG_ESP_MDNS_TX +#define DEBUG_ESP_MDNS_RX +#endif + +#define MDNS_NAME_REF 0xC000 + +#define MDNS_TYPE_AAAA 0x001C +#define MDNS_TYPE_A 0x0001 +#define MDNS_TYPE_PTR 0x000C +#define MDNS_TYPE_SRV 0x0021 +#define MDNS_TYPE_TXT 0x0010 + +#define MDNS_CLASS_IN 0x0001 +#define MDNS_CLASS_IN_FLUSH_CACHE 0x8001 + +#define MDNS_ANSWERS_ALL 0x0F +#define MDNS_ANSWER_PTR 0x08 +#define MDNS_ANSWER_TXT 0x04 +#define MDNS_ANSWER_SRV 0x02 +#define MDNS_ANSWER_A 0x01 + +#define _conn_read32() (((uint32_t)_conn->read() << 24) | ((uint32_t)_conn->read() << 16) | ((uint32_t)_conn->read() << 8) | _conn->read()) +#define _conn_read16() (((uint16_t)_conn->read() << 8) | _conn->read()) +#define _conn_read8() _conn->read() +#define _conn_readS(b,l) _conn->read((char*)(b),l); + +static const IPAddress MDNS_MULTICAST_ADDR(224, 0, 0, 251); +static const int MDNS_MULTICAST_TTL = 1; +static const int MDNS_PORT = 5353; + +struct MDNSService +{ + MDNSService* _next; + char _name[32]; + char _proto[4]; + uint16_t _port; + uint16_t _txtLen; // length of all txts + struct MDNSTxt * _txts; +}; + +struct MDNSTxt +{ + MDNSTxt * _next; + String _txt; +}; + +struct MDNSAnswer +{ + MDNSAnswer* next; + uint8_t ip[4]; + uint16_t port; + char *hostname; +}; + +struct MDNSQuery +{ + char _service[32]; + char _proto[4]; +}; + + +MDNSResponder::MDNSResponder() : _conn(0) +{ + _services = 0; + _instanceName = ""; + _answers = 0; + _query = 0; + _newQuery = false; + _waitingForAnswers = false; +} +MDNSResponder::~MDNSResponder() +{ + if (_query != 0) + { + os_free(_query); + _query = 0; + } + + // Clear answer list + MDNSAnswer *answer; + int numAnswers = _getNumAnswers(); + for (int n = numAnswers - 1; n >= 0; n--) + { + answer = _getAnswerFromIdx(n); + os_free(answer->hostname); + os_free(answer); + answer = 0; + } + _answers = 0; + + if (_conn) + { + _conn->unref(); + } +} + +bool MDNSResponder::begin(const char* hostname) +{ + size_t n = strlen(hostname); + if (n > 63) // max size for a single label. + { + return false; + } + + // Copy in hostname characters as lowercase + _hostName = hostname; + _hostName.toLowerCase(); + + // If instance name is not already set copy hostname to instance name + if (_instanceName.equals("")) + { + _instanceName = hostname; + } + + _gotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & event) + { + (void) event; + _restart(); + }); + + _disconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & event) + { + (void) event; + _restart(); + }); + + return _listen(); +} + +void MDNSResponder::notifyAPChange() +{ + _restart(); +} + +void MDNSResponder::_restart() +{ + if (_conn) + { + _conn->unref(); + _conn = nullptr; + } + _listen(); +} + +bool MDNSResponder::_listen() +{ + // Open the MDNS socket if it isn't already open. + if (!_conn) + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.println("MDNS listening"); +#endif + + IPAddress mdns(MDNS_MULTICAST_ADDR); + + if (igmp_joingroup(IP4_ADDR_ANY4, mdns) != ERR_OK) + { + return false; + } + + _conn = new UdpContext; + _conn->ref(); + + if (!_conn->listen(IP_ADDR_ANY, MDNS_PORT)) + { + return false; + } + _conn->setMulticastTTL(MDNS_MULTICAST_TTL); + _conn->onRx(std::bind(&MDNSResponder::update, this)); + _conn->connect(mdns, MDNS_PORT); + } + return true; +} + +void MDNSResponder::update() +{ + if (!_conn || !_conn->next()) + { + return; + } + _parsePacket(); +} + + +void MDNSResponder::setInstanceName(String name) +{ + if (name.length() > 63) + { + return; + } + _instanceName = name; +} + + +bool MDNSResponder::addServiceTxt(char *name, char *proto, char *key, char *value) +{ + MDNSService* servicePtr; + + uint8_t txtLen = os_strlen(key) + os_strlen(value) + 1; // Add one for equals sign + txtLen += 1; //accounts for length byte added when building the txt responce + //Find the service + for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) + { + //Checking Service names + if (strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) + { + //found a service name match + if (servicePtr->_txtLen + txtLen > 1300) + { + return false; //max txt record size + } + MDNSTxt *newtxt = new MDNSTxt; + newtxt->_txt = String(key) + '=' + String(value); + newtxt->_next = 0; + if (servicePtr->_txts == 0) //no services have been added + { + //Adding First TXT to service + servicePtr->_txts = newtxt; + servicePtr->_txtLen += txtLen; + return true; + } + else + { + MDNSTxt * txtPtr = servicePtr->_txts; + while (txtPtr->_next != 0) + { + txtPtr = txtPtr->_next; + } + //adding another TXT to service + txtPtr->_next = newtxt; + servicePtr->_txtLen += txtLen; + return true; + } + } + } + return false; +} + +void MDNSResponder::addService(char *name, char *proto, uint16_t port) +{ + if (_getServicePort(name, proto) != 0) + { + return; + } + if (os_strlen(name) > 32 || os_strlen(proto) != 3) + { + return; //bad arguments + } + struct MDNSService *srv = (struct MDNSService*)(os_malloc(sizeof(struct MDNSService))); + os_strcpy(srv->_name, name); + os_strcpy(srv->_proto, proto); + srv->_port = port; + srv->_next = 0; + srv->_txts = 0; + srv->_txtLen = 0; + + if (_services == 0) + { + _services = srv; + } + else + { + MDNSService* servicePtr = _services; + while (servicePtr->_next != 0) + { + servicePtr = servicePtr->_next; + } + servicePtr->_next = srv; + } + +} + +int MDNSResponder::queryService(char *service, char *proto) +{ +#ifdef DEBUG_ESP_MDNS_TX + DEBUG_ESP_PORT.printf("queryService %s %s\n", service, proto); +#endif + while (_answers != 0) + { + MDNSAnswer *currAnswer = _answers; + _answers = _answers->next; + os_free(currAnswer->hostname); + os_free(currAnswer); + currAnswer = 0; + } + if (_query != 0) + { + os_free(_query); + _query = 0; + } + _query = (struct MDNSQuery*)(os_malloc(sizeof(struct MDNSQuery))); + os_strcpy(_query->_service, service); + os_strcpy(_query->_proto, proto); + _newQuery = true; + + char underscore[] = "_"; + + // build service name with _ + char serviceName[os_strlen(service) + 2]; + os_strcpy(serviceName, underscore); + os_strcat(serviceName, service); + size_t serviceNameLen = os_strlen(serviceName); + + //build proto name with _ + char protoName[5]; + os_strcpy(protoName, underscore); + os_strcat(protoName, proto); + size_t protoNameLen = 4; + + //local string + char localName[] = "local"; + size_t localNameLen = 5; + + //terminator + char terminator[] = "\0"; + + // Only supports sending one PTR query + uint8_t questionCount = 1; + + _waitingForAnswers = true; + for (int itfn = 0; itfn < 2; itfn++) + { + struct ip_info ip_info; + + wifi_get_ip_info((!itfn) ? SOFTAP_IF : STATION_IF, &ip_info); + if (!ip_info.ip.addr) + { + continue; + } + _conn->setMulticastInterface(IPAddress(ip_info.ip.addr)); + + // Write the header + _conn->flush(); + uint8_t head[12] = + { + 0x00, 0x00, //ID = 0 + 0x00, 0x00, //Flags = response + authoritative answer + 0x00, questionCount, //Question count + 0x00, 0x00, //Answer count + 0x00, 0x00, //Name server records + 0x00, 0x00 //Additional records + }; + _conn->append(reinterpret_cast(head), 12); + + // Only supports sending one PTR query + // Send the Name field (eg. "_http._tcp.local") + _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_" + service + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_" + service + _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_" + proto + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_" + proto + _conn->append(reinterpret_cast(&localNameLen), 1); // lenght of "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + //Send the type and class + uint8_t ptrAttrs[4] = + { + 0x00, 0x0c, //PTR record query + 0x00, 0x01 //Class IN + }; + _conn->append(reinterpret_cast(ptrAttrs), 4); + _conn->send(); + } + +#ifdef DEBUG_ESP_MDNS_TX + DEBUG_ESP_PORT.println("Waiting for answers.."); +#endif + delay(1000); + + _waitingForAnswers = false; + + return _getNumAnswers(); +} + +String MDNSResponder::hostname(int idx) +{ + MDNSAnswer *answer = _getAnswerFromIdx(idx); + if (answer == 0) + { + return String(); + } + return answer->hostname; +} + +IPAddress MDNSResponder::IP(int idx) +{ + MDNSAnswer *answer = _getAnswerFromIdx(idx); + if (answer == 0) + { + return IPAddress(); + } + return IPAddress(answer->ip); +} + +uint16_t MDNSResponder::port(int idx) +{ + MDNSAnswer *answer = _getAnswerFromIdx(idx); + if (answer == 0) + { + return 0; + } + return answer->port; +} + +MDNSAnswer* MDNSResponder::_getAnswerFromIdx(int idx) +{ + MDNSAnswer *answer = _answers; + while (answer != 0 && idx-- > 0) + { + answer = answer->next; + } + if (idx > 0) + { + return 0; + } + return answer; +} + +int MDNSResponder::_getNumAnswers() +{ + int numAnswers = 0; + MDNSAnswer *answer = _answers; + while (answer != 0) + { + numAnswers++; + answer = answer->next; + } + return numAnswers; +} + +MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto) +{ + MDNSService* servicePtr; + for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) + { + if (servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) + { + if (servicePtr->_txts == 0) + { + return nullptr; + } + return servicePtr->_txts; + } + } + return nullptr; +} + +uint16_t MDNSResponder::_getServiceTxtLen(char *name, char *proto) +{ + MDNSService* servicePtr; + for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) + { + if (servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) + { + if (servicePtr->_txts == 0) + { + return false; + } + return servicePtr->_txtLen; + } + } + return 0; +} + +uint16_t MDNSResponder::_getServicePort(char *name, char *proto) +{ + MDNSService* servicePtr; + for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) + { + if (servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) + { + return servicePtr->_port; + } + } + return 0; +} + +IPAddress MDNSResponder::_getRequestMulticastInterface() +{ + struct ip_info ip_info; + bool match_ap = false; + if (wifi_get_opmode() & SOFTAP_MODE) + { + const IPAddress& remote_ip = _conn->getRemoteAddress(); + wifi_get_ip_info(SOFTAP_IF, &ip_info); + IPAddress infoIp(ip_info.ip); + IPAddress infoMask(ip_info.netmask); + if (ip_info.ip.addr && ip_addr_netcmp((const ip_addr_t*)remote_ip, (const ip_addr_t*)infoIp, ip_2_ip4((const ip_addr_t*)infoMask))) + { + match_ap = true; + } + } + if (!match_ap) + { + wifi_get_ip_info(STATION_IF, &ip_info); + } + return IPAddress(ip_info.ip.addr); +} + +void MDNSResponder::_parsePacket() +{ + int i; + char tmp; + bool serviceParsed = false; + bool protoParsed = false; + bool localParsed = false; + + char hostName[255]; + uint8_t hostNameLen; + + char serviceName[32]; + uint8_t serviceNameLen; + uint16_t servicePort = 0; + + char protoName[32]; + protoName[0] = 0; + uint8_t protoNameLen = 0; + + uint16_t packetHeader[6]; + + for (i = 0; i < 6; i++) + { + packetHeader[i] = _conn_read16(); + } + + if ((packetHeader[1] & 0x8000) != 0) // Read answers + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("Reading answers RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]); +#endif + + if (!_waitingForAnswers) + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.println("Not expecting any answers right now, returning"); +#endif + _conn->flush(); + return; + } + + int numAnswers = packetHeader[3] + packetHeader[5]; + // Assume that the PTR answer always comes first and that it is always accompanied by a TXT, SRV, AAAA (optional) and A answer in the same packet. + if (numAnswers < 4) + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("Expected a packet with 4 or more answers, got %u\n", numAnswers); +#endif + _conn->flush(); + return; + } + + uint8_t tmp8; + uint16_t answerPort = 0; + uint8_t answerIp[4] = { 0, 0, 0, 0 }; + char answerHostName[255]; + bool serviceMatch = false; + MDNSAnswer *answer; + uint8_t partsCollected = 0; + uint8_t stringsRead = 0; + + answerHostName[0] = '\0'; + + // Clear answer list + if (_newQuery) + { + int oldAnswers = _getNumAnswers(); + for (int n = oldAnswers - 1; n >= 0; n--) + { + answer = _getAnswerFromIdx(n); + os_free(answer->hostname); + os_free(answer); + answer = 0; + } + _answers = 0; + _newQuery = false; + } + + while (numAnswers--) + { + // Read name + stringsRead = 0; + size_t last_bufferpos = 0; + do + { + tmp8 = _conn_read8(); + if (tmp8 == 0x00) // End of name + { + break; + } + if (tmp8 & 0xC0) // Compressed pointer + { + uint16_t offset = ((((uint16_t)tmp8) & ~0xC0) << 8) | _conn_read8(); + if (_conn->isValidOffset(offset)) + { + if (0 == last_bufferpos) + { + last_bufferpos = _conn->tell(); + } +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.print("Compressed pointer, jumping from "); + DEBUG_ESP_PORT.print(last_bufferpos); + DEBUG_ESP_PORT.print(" to "); + DEBUG_ESP_PORT.println(offset); +#endif + _conn->seek(offset); + tmp8 = _conn_read8(); + } + else + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.print("Skipping malformed compressed pointer"); +#endif + tmp8 = _conn_read8(); + break; + } + } + if (stringsRead > 3) + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.println("failed to read the response name"); +#endif + _conn->flush(); + return; + } + _conn_readS(serviceName, tmp8); + serviceName[tmp8] = '\0'; +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf(" %d ", tmp8); + for (int n = 0; n < tmp8; n++) + { + DEBUG_ESP_PORT.printf("%c", serviceName[n]); + } + DEBUG_ESP_PORT.println(); +#endif + if (serviceName[0] == '_') + { + if (strcmp(&serviceName[1], _query->_service) == 0) + { + serviceMatch = true; +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("found matching service: %s\n", _query->_service); +#endif + } + } + stringsRead++; + } while (true); + if (last_bufferpos > 0) + { + _conn->seek(last_bufferpos); +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.print("Compressed pointer, jumping back to "); + DEBUG_ESP_PORT.println(last_bufferpos); +#endif + } + + uint16_t answerType = _conn_read16(); // Read type + uint16_t answerClass = _conn_read16(); // Read class + uint32_t answerTtl = _conn_read32(); // Read ttl + uint16_t answerRdlength = _conn_read16(); // Read rdlength + + (void) answerClass; + (void) answerTtl; + + if (answerRdlength > 255) + { + if (answerType == MDNS_TYPE_TXT && answerRdlength < 1460) + { + while (--answerRdlength) + { + _conn->read(); + } + } + else + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("Data len too long! %u\n", answerRdlength); +#endif + _conn->flush(); + return; + } + } + +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("type: %04x rdlength: %d\n", answerType, answerRdlength); +#endif + + if (answerType == MDNS_TYPE_PTR) + { + partsCollected |= 0x01; + _conn_readS(hostName, answerRdlength); // Read rdata + if (hostName[answerRdlength - 2] & 0xc0) + { + memcpy(answerHostName, hostName + 1, answerRdlength - 3); + answerHostName[answerRdlength - 3] = '\0'; + } +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("PTR %d ", answerRdlength); + for (int n = 0; n < answerRdlength; n++) + { + DEBUG_ESP_PORT.printf("%c", hostName[n]); + } + DEBUG_ESP_PORT.println(); +#endif + } + + else if (answerType == MDNS_TYPE_TXT) + { + partsCollected |= 0x02; + _conn_readS(hostName, answerRdlength); // Read rdata +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("TXT %d ", answerRdlength); + for (int n = 0; n < answerRdlength; n++) + { + DEBUG_ESP_PORT.printf("%c", hostName[n]); + } + DEBUG_ESP_PORT.println(); +#endif + } + + else if (answerType == MDNS_TYPE_SRV) + { + partsCollected |= 0x04; + uint16_t answerPrio = _conn_read16(); // Read priority + uint16_t answerWeight = _conn_read16(); // Read weight + answerPort = _conn_read16(); // Read port + last_bufferpos = 0; + + (void) answerPrio; + (void) answerWeight; + + // Read hostname + tmp8 = _conn_read8(); + if (tmp8 & 0xC0) // Compressed pointer + { + uint16_t offset = ((((uint16_t)tmp8) & ~0xC0) << 8) | _conn_read8(); + if (_conn->isValidOffset(offset)) + { + last_bufferpos = _conn->tell(); +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.print("Compressed pointer, jumping from "); + DEBUG_ESP_PORT.print(last_bufferpos); + DEBUG_ESP_PORT.print(" to "); + DEBUG_ESP_PORT.println(offset); +#endif + _conn->seek(offset); + tmp8 = _conn_read8(); + } + else + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.print("Skipping malformed compressed pointer"); +#endif + tmp8 = _conn_read8(); + break; + } + } + _conn_readS(answerHostName, tmp8); + answerHostName[tmp8] = '\0'; +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("SRV %d ", tmp8); + for (int n = 0; n < tmp8; n++) + { + DEBUG_ESP_PORT.printf("%02x ", answerHostName[n]); + } + DEBUG_ESP_PORT.printf("\n%s\n", answerHostName); +#endif + if (last_bufferpos > 0) + { + _conn->seek(last_bufferpos); + tmp8 = 2; // Size of compression octets +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.print("Compressed pointer, jumping back to "); + DEBUG_ESP_PORT.println(last_bufferpos); +#endif + } + if (answerRdlength - (6 + 1 + tmp8) > 0) // Skip any remaining rdata + { + _conn_readS(hostName, answerRdlength - (6 + 1 + tmp8)); + } + } + + else if (answerType == MDNS_TYPE_A) + { + partsCollected |= 0x08; + for (int i = 0; i < 4; i++) + { + answerIp[i] = _conn_read8(); + } + } + else + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("Ignoring unsupported type %02x\n", tmp8); +#endif + for (int n = 0; n < answerRdlength; n++) + { + (void)_conn_read8(); + } + } + + if ((partsCollected == 0x0F) && serviceMatch) + { +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.println("All answers parsed, adding to _answers list.."); +#endif + // Add new answer to answer list + if (_answers == 0) + { + _answers = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer))); + answer = _answers; + } + else + { + answer = _answers; + while (answer->next != 0) + { + answer = answer->next; + } + answer->next = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer))); + answer = answer->next; + } + answer->next = 0; + answer->hostname = 0; + + // Populate new answer + answer->port = answerPort; + for (int i = 0; i < 4; i++) + { + answer->ip[i] = answerIp[i]; + } + answer->hostname = (char *)os_malloc(strlen(answerHostName) + 1); + os_strcpy(answer->hostname, answerHostName); + _conn->flush(); + return; + } + } + + _conn->flush(); + return; + } + + // PARSE REQUEST NAME + + hostNameLen = _conn_read8() % 255; + _conn_readS(hostName, hostNameLen); + hostName[hostNameLen] = '\0'; + + if (hostName[0] == '_') + { + serviceParsed = true; + memcpy(serviceName, hostName + 1, hostNameLen); + serviceNameLen = hostNameLen - 1; + hostNameLen = 0; + } + + if (hostNameLen > 0 && !_hostName.equals(hostName) && !_instanceName.equals(hostName)) + { +#ifdef DEBUG_ESP_MDNS_ERR + DEBUG_ESP_PORT.printf("ERR_NO_HOST: %s\n", hostName); + DEBUG_ESP_PORT.printf("hostname: %s\n", _hostName.c_str()); + DEBUG_ESP_PORT.printf("instance: %s\n", _instanceName.c_str()); +#endif + _conn->flush(); + return; + } + + if (!serviceParsed) + { + serviceNameLen = _conn_read8() % 255; + _conn_readS(serviceName, serviceNameLen); + serviceName[serviceNameLen] = '\0'; + + if (serviceName[0] == '_') + { + memmove(serviceName, serviceName + 1, serviceNameLen); + serviceNameLen--; + serviceParsed = true; + } + else if (serviceNameLen == 5 && strcmp("local", serviceName) == 0) + { + tmp = _conn_read8(); + if (tmp == 0) + { + serviceParsed = true; + serviceNameLen = 0; + protoParsed = true; + protoNameLen = 0; + localParsed = true; + } + else + { +#ifdef DEBUG_ESP_MDNS_ERR + DEBUG_ESP_PORT.printf("ERR_FQDN: %s\n", serviceName); +#endif + _conn->flush(); + return; + } + } + else + { +#ifdef DEBUG_ESP_MDNS_ERR + DEBUG_ESP_PORT.printf("ERR_SERVICE: %s\n", serviceName); +#endif + _conn->flush(); + return; + } + } + + if (!protoParsed) + { + protoNameLen = _conn_read8() % 255; + _conn_readS(protoName, protoNameLen); + protoName[protoNameLen] = '\0'; + if (protoNameLen == 4 && protoName[0] == '_') + { + memmove(protoName, protoName + 1, protoNameLen); + protoNameLen--; + protoParsed = true; + } + else if (strcmp("services", serviceName) == 0 && strcmp("_dns-sd", protoName) == 0) + { + _conn->flush(); + IPAddress interface = _getRequestMulticastInterface(); + _replyToTypeEnumRequest(interface); + return; + } + else + { +#ifdef DEBUG_ESP_MDNS_ERR + DEBUG_ESP_PORT.printf("ERR_PROTO: %s\n", protoName); +#endif + _conn->flush(); + return; + } + } + + if (!localParsed) + { + char localName[32]; + uint8_t localNameLen = _conn_read8() % 31; + _conn_readS(localName, localNameLen); + localName[localNameLen] = '\0'; + tmp = _conn_read8(); + if (localNameLen == 5 && strcmp("local", localName) == 0 && tmp == 0) + { + localParsed = true; + } + else + { +#ifdef DEBUG_ESP_MDNS_ERR + DEBUG_ESP_PORT.printf("ERR_FQDN: %s\n", localName); +#endif + _conn->flush(); + return; + } + } + + if (serviceNameLen > 0 && protoNameLen > 0) + { + servicePort = _getServicePort(serviceName, protoName); + if (servicePort == 0) + { +#ifdef DEBUG_ESP_MDNS_ERR + DEBUG_ESP_PORT.printf("ERR_NO_SERVICE: %s\n", serviceName); +#endif + _conn->flush(); + return; + } + } + else if (serviceNameLen > 0 || protoNameLen > 0) + { +#ifdef DEBUG_ESP_MDNS_ERR + DEBUG_ESP_PORT.printf("ERR_SERVICE_PROTO: %s\n", serviceName); +#endif + _conn->flush(); + return; + } + + // RESPOND + +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]); +#endif + + uint16_t currentType; + uint16_t currentClass; + + int numQuestions = packetHeader[2]; + if (numQuestions > 4) + { + numQuestions = 4; + } + uint16_t questions[4]; + int question = 0; + + while (numQuestions--) + { + currentType = _conn_read16(); + if (currentType & MDNS_NAME_REF) //new header handle it better! + { + currentType = _conn_read16(); + } + currentClass = _conn_read16(); + if (currentClass & MDNS_CLASS_IN) + { + questions[question++] = currentType; + } + + if (numQuestions > 0) + { + if (_conn_read16() != 0xC00C) //new question but for another host/service + { + _conn->flush(); + numQuestions = 0; + } + } + +#ifdef DEBUG_ESP_MDNS_RX + DEBUG_ESP_PORT.printf("REQ: "); + if (hostNameLen > 0) + { + DEBUG_ESP_PORT.printf("%s.", hostName); + } + if (serviceNameLen > 0) + { + DEBUG_ESP_PORT.printf("_%s.", serviceName); + } + if (protoNameLen > 0) + { + DEBUG_ESP_PORT.printf("_%s.", protoName); + } + DEBUG_ESP_PORT.printf("local. "); + + if (currentType == MDNS_TYPE_AAAA) + { + DEBUG_ESP_PORT.printf(" AAAA "); + } + else if (currentType == MDNS_TYPE_A) + { + DEBUG_ESP_PORT.printf(" A "); + } + else if (currentType == MDNS_TYPE_PTR) + { + DEBUG_ESP_PORT.printf(" PTR "); + } + else if (currentType == MDNS_TYPE_SRV) + { + DEBUG_ESP_PORT.printf(" SRV "); + } + else if (currentType == MDNS_TYPE_TXT) + { + DEBUG_ESP_PORT.printf(" TXT "); + } + else + { + DEBUG_ESP_PORT.printf(" 0x%04X ", currentType); + } + + if (currentClass == MDNS_CLASS_IN) + { + DEBUG_ESP_PORT.printf(" IN "); + } + else if (currentClass == MDNS_CLASS_IN_FLUSH_CACHE) + { + DEBUG_ESP_PORT.printf(" IN[F] "); + } + else + { + DEBUG_ESP_PORT.printf(" 0x%04X ", currentClass); + } + + DEBUG_ESP_PORT.printf("\n"); +#endif + } + uint8_t questionMask = 0; + uint8_t responseMask = 0; + for (i = 0; i < question; i++) + { + if (questions[i] == MDNS_TYPE_A) + { + questionMask |= 0x1; + responseMask |= 0x1; + } + else if (questions[i] == MDNS_TYPE_SRV) + { + questionMask |= 0x2; + responseMask |= 0x3; + } + else if (questions[i] == MDNS_TYPE_TXT) + { + questionMask |= 0x4; + responseMask |= 0x4; + } + else if (questions[i] == MDNS_TYPE_PTR) + { + questionMask |= 0x8; + responseMask |= 0xF; + } + } + + IPAddress interface = _getRequestMulticastInterface(); + return _replyToInstanceRequest(questionMask, responseMask, serviceName, protoName, servicePort, interface); +} + + +/** + STRINGIZE +*/ +#ifndef STRINGIZE +#define STRINGIZE(x) #x +#endif +#ifndef STRINGIZE_VALUE_OF +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) +#endif + + +void MDNSResponder::enableArduino(uint16_t port, bool auth) +{ + + addService("arduino", "tcp", port); + addServiceTxt("arduino", "tcp", "tcp_check", "no"); + addServiceTxt("arduino", "tcp", "ssh_upload", "no"); + addServiceTxt("arduino", "tcp", "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD)); + addServiceTxt("arduino", "tcp", "auth_upload", (auth) ? "yes" : "no"); +} + +void MDNSResponder::_replyToTypeEnumRequest(IPAddress multicastInterface) +{ + MDNSService* servicePtr; + for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) + { + if (servicePtr->_port > 0) + { + char *service = servicePtr->_name; + char *proto = servicePtr->_proto; + //uint16_t port = servicePtr->_port; + +#ifdef DEBUG_ESP_MDNS_TX + DEBUG_ESP_PORT.printf("TX: service:%s, proto:%s\n", service, proto); +#endif + + char sdHostName[] = "_services"; + size_t sdHostNameLen = 9; + char sdServiceName[] = "_dns-sd"; + size_t sdServiceNameLen = 7; + char sdProtoName[] = "_udp"; + size_t sdProtoNameLen = 4; + + char underscore[] = "_"; + + // build service name with _ + char serviceName[os_strlen(service) + 2]; + os_strcpy(serviceName, underscore); + os_strcat(serviceName, service); + size_t serviceNameLen = os_strlen(serviceName); + + //build proto name with _ + char protoName[5]; + os_strcpy(protoName, underscore); + os_strcat(protoName, proto); + size_t protoNameLen = 4; + + //local string + char localName[] = "local"; + size_t localNameLen = 5; + + //terminator + char terminator[] = "\0"; + + //Write the header + _conn->flush(); + uint8_t head[12] = + { + 0x00, 0x00, //ID = 0 + 0x84, 0x00, //Flags = response + authoritative answer + 0x00, 0x00, //Question count + 0x00, 0x01, //Answer count + 0x00, 0x00, //Name server records + 0x00, 0x00, //Additional records + }; + _conn->append(reinterpret_cast(head), 12); + + // Send the Name field (ie. "_services._dns-sd._udp.local") + _conn->append(reinterpret_cast(&sdHostNameLen), 1); // length of "_services" + _conn->append(reinterpret_cast(sdHostName), sdHostNameLen); // "_services" + _conn->append(reinterpret_cast(&sdServiceNameLen), 1); // length of "_dns-sd" + _conn->append(reinterpret_cast(sdServiceName), sdServiceNameLen);// "_dns-sd" + _conn->append(reinterpret_cast(&sdProtoNameLen), 1); // length of "_udp" + _conn->append(reinterpret_cast(sdProtoName), sdProtoNameLen); // "_udp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + //Send the type, class, ttl and rdata length + uint8_t ptrDataLen = serviceNameLen + protoNameLen + localNameLen + 4; // 4 is three label sizes and the terminator + uint8_t ptrAttrs[10] = + { + 0x00, 0x0c, //PTR record query + 0x00, 0x01, //Class IN + 0x00, 0x00, 0x11, 0x94, //TTL 4500 + 0x00, ptrDataLen, //RData length + }; + _conn->append(reinterpret_cast(ptrAttrs), 10); + + //Send the RData (ie. "_http._tcp.local") + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + _conn->setMulticastInterface(multicastInterface); + _conn->send(); + } + } +} + +void MDNSResponder::_replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface) +{ + int i; + if (questionMask == 0) + { + return; + } + if (responseMask == 0) + { + return; + } + +#ifdef DEBUG_ESP_MDNS_TX + DEBUG_ESP_PORT.printf("TX: qmask:%01X, rmask:%01X, service:%s, proto:%s, port:%u\n", questionMask, responseMask, service, proto, port); +#endif + + + String instanceName = _instanceName; + size_t instanceNameLen = instanceName.length(); + + String hostName = _hostName; + size_t hostNameLen = hostName.length(); + + char underscore[] = "_"; + + // build service name with _ + char serviceName[os_strlen(service) + 2]; + os_strcpy(serviceName, underscore); + os_strcat(serviceName, service); + size_t serviceNameLen = os_strlen(serviceName); + + //build proto name with _ + char protoName[5]; + os_strcpy(protoName, underscore); + os_strcat(protoName, proto); + size_t protoNameLen = 4; + + //local string + char localName[] = "local"; + size_t localNameLen = 5; + + //terminator + char terminator[] = "\0"; + + uint8_t answerMask = responseMask & questionMask; + uint8_t answerCount = 0; + uint8_t additionalMask = responseMask & ~questionMask; + uint8_t additionalCount = 0; + for (i = 0; i < 4; i++) + { + if (answerMask & (1 << i)) + { + answerCount++; + } + if (additionalMask & (1 << i)) + { + additionalCount++; + } + } + + + //Write the header + _conn->flush(); + uint8_t head[12] = + { + 0x00, 0x00, //ID = 0 + 0x84, 0x00, //Flags = response + authoritative answer + 0x00, 0x00, //Question count + 0x00, answerCount, //Answer count + 0x00, 0x00, //Name server records + 0x00, additionalCount, //Additional records + }; + _conn->append(reinterpret_cast(head), 12); + + for (int responseSection = 0; responseSection < 2; ++responseSection) + { + + // PTR Response + if ((responseSection == 0 ? answerMask : additionalMask) & 0x8) + { + // Send the Name field (ie. "_http._tcp.local") + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + //Send the type, class, ttl and rdata length + uint8_t ptrDataLen = instanceNameLen + serviceNameLen + protoNameLen + localNameLen + 5; // 5 is four label sizes and the terminator + uint8_t ptrAttrs[10] = + { + 0x00, 0x0c, //PTR record query + 0x00, 0x01, //Class IN + 0x00, 0x00, 0x00, 0x78, //TTL 120 + 0x00, ptrDataLen, //RData length + }; + _conn->append(reinterpret_cast(ptrAttrs), 10); + + //Send the RData (ie. "My IOT device._http._tcp.local") + _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" + _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + } + + //TXT Responce + if ((responseSection == 0 ? answerMask : additionalMask) & 0x4) + { + //Send the name field (ie. "My IOT device._http._tcp.local") + _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" + _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + //Send the type, class, ttl and rdata length + uint8_t txtDataLen = _getServiceTxtLen(service, proto); + uint8_t txtAttrs[10] = + { + 0x00, 0x10, //TXT record query + 0x80, 0x01, //Class IN, with cache flush + 0x00, 0x00, 0x11, 0x94, //TTL 4500 + 0x00, txtDataLen, //RData length + }; + _conn->append(reinterpret_cast(txtAttrs), 10); + + //Send the RData + MDNSTxt * txtPtr = _getServiceTxt(service, proto); + while (txtPtr != 0) + { + uint8_t txtLen = txtPtr->_txt.length(); + _conn->append(reinterpret_cast(&txtLen), 1); // length of txt + _conn->append(reinterpret_cast(txtPtr->_txt.c_str()), txtLen);// the txt + txtPtr = txtPtr->_next; + } + } + + + //SRV Responce + if ((responseSection == 0 ? answerMask : additionalMask) & 0x2) + { + //Send the name field (ie. "My IOT device._http._tcp.local") + _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" + _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + //Send the type, class, ttl, rdata length, priority and weight + uint8_t srvDataSize = hostNameLen + localNameLen + 3; // 3 is 2 lable size bytes and the terminator + srvDataSize += 6; // Size of Priority, weight and port + uint8_t srvAttrs[10] = + { + 0x00, 0x21, //Type SRV + 0x80, 0x01, //Class IN, with cache flush + 0x00, 0x00, 0x00, 0x78, //TTL 120 + 0x00, srvDataSize, //RData length + }; + _conn->append(reinterpret_cast(srvAttrs), 10); + + //Send the RData Priority weight and port + uint8_t srvRData[6] = + { + 0x00, 0x00, //Priority 0 + 0x00, 0x00, //Weight 0 + (uint8_t)((port >> 8) & 0xFF), (uint8_t)(port & 0xFF) + }; + _conn->append(reinterpret_cast(srvRData), 6); + //Send the RData (ie. "esp8266.local") + _conn->append(reinterpret_cast(&hostNameLen), 1); // length of "esp8266" + _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + } + + // A Response + if ((responseSection == 0 ? answerMask : additionalMask) & 0x1) + { + //Send the RData (ie. "esp8266.local") + _conn->append(reinterpret_cast(&hostNameLen), 1); // length of "esp8266" + _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + uint8_t aaaAttrs[10] = + { + 0x00, 0x01, //TYPE A + 0x80, 0x01, //Class IN, with cache flush + 0x00, 0x00, 0x00, 0x78, //TTL 120 + 0x00, 0x04, //DATA LEN + }; + _conn->append(reinterpret_cast(aaaAttrs), 10); + + // Send RData + uint32_t ip = multicastInterface; + uint8_t aaaRData[4] = + { + (uint8_t)(ip & 0xFF), //IP first octet + (uint8_t)((ip >> 8) & 0xFF), //IP second octet + (uint8_t)((ip >> 16) & 0xFF), //IP third octet + (uint8_t)((ip >> 24) & 0xFF) //IP fourth octet + }; + _conn->append(reinterpret_cast(aaaRData), 4); + } + } + + _conn->setMulticastInterface(multicastInterface); + _conn->send(); +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) +MDNSResponder MDNS; +#endif + +} // namespace Legacy_MDNSResponder + + + + diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.h b/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.h new file mode 100644 index 0000000000..0a66a7fd32 --- /dev/null +++ b/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.h @@ -0,0 +1,169 @@ +/* + ESP8266 Multicast DNS (port of CC3000 Multicast DNS library) + Version 1.1 + Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) + ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com) + Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com) + + This is a simple implementation of multicast DNS query support for an Arduino + running on ESP8266 chip. Only support for resolving address queries is currently + implemented. + + Requirements: + - ESP8266WiFi library + + Usage: + - Include the ESP8266 Multicast DNS library in the sketch. + - Call the begin method in the sketch's setup and provide a domain name (without + the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the + Adafruit CC3000 class instance. Optionally provide a time to live (in seconds) + for the DNS record--the default is 1 hour. + - Call the update method in each iteration of the sketch's loop function. + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ +#ifndef ESP8266MDNS_LEGACY_H +#define ESP8266MDNS_LEGACY_H + +#include "ESP8266WiFi.h" +#include "WiFiUdp.h" + +//this should be defined at build time +#ifndef ARDUINO_BOARD +#define ARDUINO_BOARD "generic" +#endif + +class UdpContext; + + +namespace Legacy_MDNSResponder +{ + + +struct MDNSService; +struct MDNSTxt; +struct MDNSAnswer; + +class MDNSResponder +{ +public: + + static constexpr auto ApiVersion = MDNSApiVersion::Legacy; + + MDNSResponder(); + ~MDNSResponder(); + bool begin(const char* hostName); + bool begin(const String& hostName) + { + return begin(hostName.c_str()); + } + //for compatibility + bool begin(const char* hostName, IPAddress ip, uint32_t ttl = 120) + { + (void) ip; + (void) ttl; + return begin(hostName); + } + bool begin(const String& hostName, IPAddress ip, uint32_t ttl = 120) + { + return begin(hostName.c_str(), ip, ttl); + } + /* Application should call this whenever AP is configured/disabled */ + void notifyAPChange(); + void update(); + + void addService(char *service, char *proto, uint16_t port); + void addService(const char *service, const char *proto, uint16_t port) + { + addService((char *)service, (char *)proto, port); + } + void addService(const String& service, const String& proto, uint16_t port) + { + addService(service.c_str(), proto.c_str(), port); + } + + bool addServiceTxt(char *name, char *proto, char * key, char * value); + bool addServiceTxt(const char *name, const char *proto, const char *key, const char * value) + { + return addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value); + } + bool addServiceTxt(const String& name, const String& proto, const String& key, const String& value) + { + return addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str()); + } + + int queryService(char *service, char *proto); + int queryService(const char *service, const char *proto) + { + return queryService((char *)service, (char *)proto); + } + int queryService(const String& service, const String& proto) + { + return queryService(service.c_str(), proto.c_str()); + } + String hostname(int idx); + IPAddress IP(int idx); + uint16_t port(int idx); + + void enableArduino(uint16_t port, bool auth = false); + + void setInstanceName(String name); + void setInstanceName(const char * name) + { + setInstanceName(String(name)); + } + void setInstanceName(char * name) + { + setInstanceName(String(name)); + } + +private: + struct MDNSService * _services; + UdpContext* _conn; + String _hostName; + String _instanceName; + struct MDNSAnswer * _answers; + struct MDNSQuery * _query; + bool _newQuery; + bool _waitingForAnswers; + WiFiEventHandler _disconnectedHandler; + WiFiEventHandler _gotIPHandler; + + + uint16_t _getServicePort(char *service, char *proto); + MDNSTxt * _getServiceTxt(char *name, char *proto); + uint16_t _getServiceTxtLen(char *name, char *proto); + IPAddress _getRequestMulticastInterface(); + void _parsePacket(); + void _replyToTypeEnumRequest(IPAddress multicastInterface); + void _replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface); + MDNSAnswer* _getAnswerFromIdx(int idx); + int _getNumAnswers(); + bool _listen(); + void _restart(); +}; + +} // namespace Legacy_MDNSResponder + +#endif //ESP8266MDNS_H + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.cpp b/libraries/ESP8266mDNS/src/LEAmDNS.cpp new file mode 100644 index 0000000000..9e784bfe97 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS.cpp @@ -0,0 +1,1382 @@ +/* + LEAmDNS.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include + +#include "ESP8266mDNS.h" +#include "LEAmDNS_Priv.h" + + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + STRINGIZE +*/ +#ifndef STRINGIZE +#define STRINGIZE(x) #x +#endif +#ifndef STRINGIZE_VALUE_OF +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) +#endif + + +/** + INTERFACE +*/ + +/** + MDNSResponder::MDNSResponder +*/ +MDNSResponder::MDNSResponder(void) + : m_pServices(0), + m_pUDPContext(0), + m_pcHostname(0), + m_pServiceQueries(0), + m_fnServiceTxtCallback(0), +#ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE + m_bPassivModeEnabled(true), +#else + m_bPassivModeEnabled(false), +#endif + m_netif(nullptr) +{ +} + +/* + MDNSResponder::~MDNSResponder +*/ +MDNSResponder::~MDNSResponder(void) +{ + + _resetProbeStatus(false); + _releaseServiceQueries(); + _releaseHostname(); + _releaseUDPContext(); + _releaseServices(); +} + +/* + MDNSResponder::begin + + Set the host domain (for probing) and install WiFi event handlers for + IP assignment and disconnection management. In both cases, the MDNS responder + is restarted (reset and restart probe status) + Finally the responder is (re)started + +*/ +bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress, uint32_t p_u32TTL) +{ + + (void)p_u32TTL; // ignored + bool bResult = false; + + if (0 == m_pUDPContext) + { + if (_setHostname(p_pcHostname)) + { + + //// select interface + + m_netif = nullptr; + IPAddress ipAddress = p_IPAddress; + + if (!ipAddress.isSet()) + { + + IPAddress sta = WiFi.localIP(); + IPAddress ap = WiFi.softAPIP(); + + if (sta.isSet()) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] STA interface selected\n"))); + ipAddress = sta; + } + else if (ap.isSet()) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] AP interface selected\n"))); + ipAddress = ap; + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] standard interfaces are not up, please specify one in ::begin()\n"))); + return false; + } + + // continue to ensure interface is UP + } + + // check existence of this IP address in the interface list + bool found = false; + m_netif = nullptr; + for (auto a : addrList) + if (ipAddress == a.addr()) + { + if (a.ifUp()) + { + found = true; + m_netif = a.interface(); + break; + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] found interface for IP '%s' but it is not UP\n"), ipAddress.toString().c_str());); + } + if (!found) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] interface defined by IP '%s' not found\n"), ipAddress.toString().c_str());); + return false; + } + + //// done selecting the interface + + if (m_netif->num == STATION_IF) + { + + m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & pEvent) + { + (void) pEvent; + // Ensure that _restart() runs in USER context + schedule_function([this]() + { + MDNSResponder::_restart(); + }); + }); + + m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & pEvent) + { + (void) pEvent; + // Ensure that _restart() runs in USER context + schedule_function([this]() + { + MDNSResponder::_restart(); + }); + }); + } + + bResult = _restart(); + } + DEBUG_EX_ERR(if (!bResult) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: FAILED for '%s'!\n"), (p_pcHostname ? : "-")); + }); + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: Ignoring multiple calls to begin (Ignored host domain: '%s')!\n"), (p_pcHostname ? : "-"));); + } + return bResult; +} + +/* + MDNSResponder::close + + Ends the MDNS responder. + Announced services are unannounced (by multicasting a goodbye message) + +*/ +bool MDNSResponder::close(void) +{ + bool bResult = false; + + if (0 != m_pUDPContext) + { + m_GotIPHandler.reset(); // reset WiFi event callbacks. + m_DisconnectedHandler.reset(); + + _announce(false, true); + _resetProbeStatus(false); // Stop probing + _releaseServiceQueries(); + _releaseUDPContext(); + _releaseHostname(); + + bResult = true; + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] close: Ignoring call to close!\n"));); + } + return bResult; +} + +/* + MDNSResponder::end + + Ends the MDNS responder. + for compatibility with esp32 + +*/ + +bool MDNSResponder::end(void) +{ + return close(); +} + +/* + MDNSResponder::setHostname + + Replaces the current hostname and restarts probing. + For services without own instance name (when the host name was used a instance + name), the instance names are replaced also (and the probing is restarted). + +*/ +bool MDNSResponder::setHostname(const char* p_pcHostname) +{ + + bool bResult = false; + + if (_setHostname(p_pcHostname)) + { + m_HostProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; + + // Replace 'auto-set' service names + bResult = true; + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if (pService->m_bAutoName) + { + bResult = pService->setName(p_pcHostname); + pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; + } + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setHostname: FAILED for '%s'!\n"), (p_pcHostname ? : "-")); + }); + return bResult; +} + +/* + MDNSResponder::setHostname (LEGACY) +*/ +bool MDNSResponder::setHostname(const String& p_strHostname) +{ + + return setHostname(p_strHostname.c_str()); +} + + +/* + SERVICES +*/ + +/* + MDNSResponder::addService + + Add service; using hostname if no name is explicitly provided for the service + The usual '_' underline, which is prepended to service and protocol, eg. _http, + may be given. If not, it is added automatically. + +*/ +MDNSResponder::hMDNSService MDNSResponder::addService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + + hMDNSService hResult = 0; + + if (((!p_pcName) || // NO name OR + (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcName))) && // Fitting name + (p_pcService) && + (MDNS_SERVICE_NAME_LENGTH >= os_strlen(p_pcService)) && + (p_pcProtocol) && + ((MDNS_SERVICE_PROTOCOL_LENGTH - 1) != os_strlen(p_pcProtocol)) && + (p_u16Port)) + { + + if (!_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol)) // Not already used + { + if (0 != (hResult = (hMDNSService)_allocService(p_pcName, p_pcService, p_pcProtocol, p_u16Port))) + { + + // Start probing + ((stcMDNSService*)hResult)->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; + } + } + } // else: bad arguments + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: %s to add '%s.%s.%s'!\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcName ? : "-"), p_pcService, p_pcProtocol);); + DEBUG_EX_ERR(if (!hResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: FAILED to add '%s.%s.%s'!\n"), (p_pcName ? : "-"), p_pcService, p_pcProtocol); + }); + return hResult; +} + +/* + MDNSResponder::removeService + + Unanounce a service (by sending a goodbye message) and remove it + from the MDNS responder + +*/ +bool MDNSResponder::removeService(const MDNSResponder::hMDNSService p_hService) +{ + + stcMDNSService* pService = 0; + bool bResult = (((pService = _findService(p_hService))) && + (_announceService(*pService, false)) && + (_releaseService(pService))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeService: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::removeService +*/ +bool MDNSResponder::removeService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol) +{ + + return removeService((hMDNSService)_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol)); +} + +/* + MDNSResponder::addService (LEGACY) +*/ +bool MDNSResponder::addService(const String& p_strService, + const String& p_strProtocol, + uint16_t p_u16Port) +{ + + return (0 != addService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str(), p_u16Port)); +} + +/* + MDNSResponder::setServiceName +*/ +bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSService p_hService, + const char* p_pcInstanceName) +{ + + stcMDNSService* pService = 0; + bool bResult = (((!p_pcInstanceName) || + (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcInstanceName))) && + ((pService = _findService(p_hService))) && + (pService->setName(p_pcInstanceName)) && + ((pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setServiceName: FAILED for '%s'!\n"), (p_pcInstanceName ? : "-")); + }); + return bResult; +} + +/* + SERVICE TXT +*/ + +/* + MDNSResponder::addServiceTxt + + Add a static service TXT item ('Key'='Value') to a service. + +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue) +{ + + hMDNSTxt hTxt = 0; + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + hTxt = (hMDNSTxt)_addServiceTxt(pService, p_pcKey, p_pcValue, false); + } + DEBUG_EX_ERR(if (!hTxt) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-")); + }); + return hTxt; +} + +/* + MDNSResponder::addServiceTxt (uint32_t) + + Formats: http://www.cplusplus.com/reference/cstdio/printf/ +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + char acBuffer[32]; *acBuffer = 0; + sprintf(acBuffer, "%u", p_u32Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (uint16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + char acBuffer[16]; *acBuffer = 0; + sprintf(acBuffer, "%hu", p_u16Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (uint8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + char acBuffer[8]; *acBuffer = 0; + sprintf(acBuffer, "%hhu", p_u8Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (int32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value) +{ + char acBuffer[32]; *acBuffer = 0; + sprintf(acBuffer, "%i", p_i32Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (int16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value) +{ + char acBuffer[16]; *acBuffer = 0; + sprintf(acBuffer, "%hi", p_i16Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (int8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value) +{ + char acBuffer[8]; *acBuffer = 0; + sprintf(acBuffer, "%hhi", p_i8Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::removeServiceTxt + + Remove a static service TXT item from a service. +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService, + const MDNSResponder::hMDNSTxt p_hTxt) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_hTxt); + if (pTxt) + { + bResult = _releaseServiceTxt(pService, pTxt); + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::removeServiceTxt +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey); + if (pTxt) + { + bResult = _releaseServiceTxt(pService, pTxt); + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED for '%s'!\n"), (p_pcKey ? : "-")); + }); + return bResult; +} + +/* + MDNSResponder::removeServiceTxt +*/ +bool MDNSResponder::removeServiceTxt(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol); + if (pService) + { + stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey); + if (pTxt) + { + bResult = _releaseServiceTxt(pService, pTxt); + } + } + return bResult; +} + +/* + MDNSResponder::addServiceTxt (LEGACY) +*/ +bool MDNSResponder::addServiceTxt(const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey, + const char* p_pcValue) +{ + + return (0 != _addServiceTxt(_findService(m_pcHostname, p_pcService, p_pcProtocol), p_pcKey, p_pcValue, false)); +} + +/* + MDNSResponder::addServiceTxt (LEGACY) +*/ +bool MDNSResponder::addServiceTxt(const String& p_strService, + const String& p_strProtocol, + const String& p_strKey, + const String& p_strValue) +{ + + return (0 != _addServiceTxt(_findService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str()), p_strKey.c_str(), p_strValue.c_str(), false)); +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (global) + + Set a global callback for dynamic service TXT items. The callback is called, whenever + service TXT items are needed. + +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback) +{ + + m_fnServiceTxtCallback = p_fnCallback; + + return true; +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (service specific) + + Set a service specific callback for dynamic service TXT items. The callback is called, whenever + service TXT items are needed for the given service. + +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::hMDNSService p_hService, + MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + pService->m_fnTxtCallback = p_fnCallback; + + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setDynamicServiceTxtCallback: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::addDynamicServiceTxt +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt (%s=%s)\n"), p_pcKey, p_pcValue);); + + hMDNSTxt hTxt = 0; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + hTxt = _addServiceTxt(pService, p_pcKey, p_pcValue, true); + } + DEBUG_EX_ERR(if (!hTxt) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-")); + }); + return hTxt; +} + +/* + MDNSResponder::addDynamicServiceTxt (uint32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + + char acBuffer[32]; *acBuffer = 0; + sprintf(acBuffer, "%u", p_u32Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (uint16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + + char acBuffer[16]; *acBuffer = 0; + sprintf(acBuffer, "%hu", p_u16Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (uint8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + + char acBuffer[8]; *acBuffer = 0; + sprintf(acBuffer, "%hhu", p_u8Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (int32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value) +{ + + char acBuffer[32]; *acBuffer = 0; + sprintf(acBuffer, "%i", p_i32Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (int16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value) +{ + + char acBuffer[16]; *acBuffer = 0; + sprintf(acBuffer, "%hi", p_i16Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (int8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value) +{ + + char acBuffer[8]; *acBuffer = 0; + sprintf(acBuffer, "%hhi", p_i8Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + + +/** + STATIC SERVICE QUERY (LEGACY) +*/ + +/* + MDNSResponder::queryService + + Perform a (blocking) static service query. + The arrived answers can be queried by calling: + - answerHostname (or 'hostname') + - answerIP (or 'IP') + - answerPort (or 'port') + +*/ +uint32_t MDNSResponder::queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + if (0 == m_pUDPContext) + { + // safeguard against misuse + return 0; + } + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService '%s.%s'\n"), p_pcService, p_pcProtocol);); + + uint32_t u32Result = 0; + + stcMDNSServiceQuery* pServiceQuery = 0; + if ((p_pcService) && + (os_strlen(p_pcService)) && + (p_pcProtocol) && + (os_strlen(p_pcProtocol)) && + (p_u16Timeout) && + (_removeLegacyServiceQuery()) && + ((pServiceQuery = _allocServiceQuery())) && + (_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain))) + { + + pServiceQuery->m_bLegacyQuery = true; + + if (_sendMDNSServiceQuery(*pServiceQuery)) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: Waiting %u ms for answers...\n"), p_u16Timeout);); + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + pServiceQuery->m_bAwaitingAnswers = false; + u32Result = pServiceQuery->answerCount(); + } + else // FAILED to send query + { + _removeServiceQuery(pServiceQuery); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: INVALID input data!\n"));); + } + return u32Result; +} + +/* + MDNSResponder::removeQuery + + Remove the last static service query (and all answers). + +*/ +bool MDNSResponder::removeQuery(void) +{ + + return _removeLegacyServiceQuery(); +} + +/* + MDNSResponder::queryService (LEGACY) +*/ +uint32_t MDNSResponder::queryService(const String& p_strService, + const String& p_strProtocol) +{ + + return queryService(p_strService.c_str(), p_strProtocol.c_str()); +} + +/* + MDNSResponder::answerHostname +*/ +const char* MDNSResponder::answerHostname(const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + + if ((pSQAnswer) && + (pSQAnswer->m_HostDomain.m_u16NameLength) && + (!pSQAnswer->m_pcHostDomain)) + { + + char* pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); + if (pcHostDomain) + { + pSQAnswer->m_HostDomain.c_str(pcHostDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::answerIP +*/ +IPAddress MDNSResponder::answerIP(const uint32_t p_u32AnswerIndex) +{ + + const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); + const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + const stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (((pSQAnswer) && (pSQAnswer->m_pIP4Addresses)) ? pSQAnswer->IP4AddressAtIndex(0) : 0); + return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress()); +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::answerIP6 +*/ +IPAddress MDNSResponder::answerIP6(const uint32_t p_u32AnswerIndex) +{ + + const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); + const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + const stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (((pSQAnswer) && (pSQAnswer->m_pIP6Addresses)) ? pSQAnswer->IP6AddressAtIndex(0) : 0); + return (pIP6Address ? pIP6Address->m_IPAddress : IP6Address()); +} +#endif + +/* + MDNSResponder::answerPort +*/ +uint16_t MDNSResponder::answerPort(const uint32_t p_u32AnswerIndex) +{ + + const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); + const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->m_u16Port : 0); +} + +/* + MDNSResponder::hostname (LEGACY) +*/ +String MDNSResponder::hostname(const uint32_t p_u32AnswerIndex) +{ + + return String(answerHostname(p_u32AnswerIndex)); +} + +/* + MDNSResponder::IP (LEGACY) +*/ +IPAddress MDNSResponder::IP(const uint32_t p_u32AnswerIndex) +{ + + return answerIP(p_u32AnswerIndex); +} + +/* + MDNSResponder::port (LEGACY) +*/ +uint16_t MDNSResponder::port(const uint32_t p_u32AnswerIndex) +{ + + return answerPort(p_u32AnswerIndex); +} + + +/** + DYNAMIC SERVICE QUERY +*/ + +/* + MDNSResponder::installServiceQuery + + Add a dynamic service query and a corresponding callback to the MDNS responder. + The callback will be called for every answer update. + The answers can also be queried by calling: + - answerServiceDomain + - answerHostDomain + - answerIP4Address/answerIP6Address + - answerPort + - answerTxts + +*/ +MDNSResponder::hMDNSServiceQuery MDNSResponder::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSResponder::MDNSServiceQueryCallbackFunc p_fnCallback) +{ + hMDNSServiceQuery hResult = 0; + + stcMDNSServiceQuery* pServiceQuery = 0; + if ((p_pcService) && + (os_strlen(p_pcService)) && + (p_pcProtocol) && + (os_strlen(p_pcProtocol)) && + (p_fnCallback) && + ((pServiceQuery = _allocServiceQuery())) && + (_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain))) + { + + pServiceQuery->m_fnCallback = p_fnCallback; + pServiceQuery->m_bLegacyQuery = false; + + if (_sendMDNSServiceQuery(*pServiceQuery)) + { + pServiceQuery->m_u8SentCount = 1; + pServiceQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); + + hResult = (hMDNSServiceQuery)pServiceQuery; + } + else + { + _removeServiceQuery(pServiceQuery); + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: %s for '%s.%s'!\n\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + DEBUG_EX_ERR(if (!hResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: FAILED for '%s.%s'!\n\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-")); + }); + return hResult; +} + +/* + MDNSResponder::removeServiceQuery + + Remove a dynamic service query (and all collected answers) from the MDNS responder + +*/ +bool MDNSResponder::removeServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) +{ + + stcMDNSServiceQuery* pServiceQuery = 0; + bool bResult = (((pServiceQuery = _findServiceQuery(p_hServiceQuery))) && + (_removeServiceQuery(pServiceQuery))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceQuery: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::answerCount +*/ +uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + return (pServiceQuery ? pServiceQuery->answerCount() : 0); +} + +std::vector MDNSResponder::answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery) +{ + std::vector tempVector; + for (uint32_t i = 0; i < answerCount(p_hServiceQuery); i++) + { + tempVector.emplace_back(*this, p_hServiceQuery, i); + } + return tempVector; +} + +/* + MDNSResponder::answerServiceDomain + + Returns the domain for the given service. + If not already existing, the string is allocated, filled and attached to the answer. + +*/ +const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcServiceDomain (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_ServiceDomain.m_u16NameLength) && + (!pSQAnswer->m_pcServiceDomain)) + { + + pSQAnswer->m_pcServiceDomain = pSQAnswer->allocServiceDomain(pSQAnswer->m_ServiceDomain.c_strLength()); + if (pSQAnswer->m_pcServiceDomain) + { + pSQAnswer->m_ServiceDomain.c_str(pSQAnswer->m_pcServiceDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcServiceDomain : 0); +} + +/* + MDNSResponder::hasAnswerHostDomain +*/ +bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort)); +} + +/* + MDNSResponder::answerHostDomain + + Returns the host domain for the given service. + If not already existing, the string is allocated, filled and attached to the answer. + +*/ +const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcHostDomain (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_HostDomain.m_u16NameLength) && + (!pSQAnswer->m_pcHostDomain)) + { + + pSQAnswer->m_pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); + if (pSQAnswer->m_pcHostDomain) + { + pSQAnswer->m_HostDomain.c_str(pSQAnswer->m_pcHostDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::hasAnswerIP4Address +*/ +bool MDNSResponder::hasAnswerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_IP4Address)); +} + +/* + MDNSResponder::answerIP4AddressCount +*/ +uint32_t MDNSResponder::answerIP4AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->IP4AddressCount() : 0); +} + +/* + MDNSResponder::answerIP4Address +*/ +IPAddress MDNSResponder::answerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (pSQAnswer ? pSQAnswer->IP4AddressAtIndex(p_u32AddressIndex) : 0); + return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress()); +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::hasAnswerIP6Address +*/ +bool MDNSResponder::hasAnswerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostIP6Address)); +} + +/* + MDNSResponder::answerIP6AddressCount +*/ +uint32_t MDNSResponder::answerIP6AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->IP6AddressCount() : 0); +} + +/* + MDNSResponder::answerIP6Address +*/ +IPAddress MDNSResponder::answerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (pSQAnswer ? pSQAnswer->IP6AddressAtIndex(p_u32AddressIndex) : 0); + return (pIP6Address ? pIP6Address->m_IPAddress : IPAddress()); +} +#endif + +/* + MDNSResponder::hasAnswerPort +*/ +bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort)); +} + +/* + MDNSResponder::answerPort +*/ +uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->m_u16Port : 0); +} + +/* + MDNSResponder::hasAnswerTxts +*/ +bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_Txts)); +} + +/* + MDNSResponder::answerTxts + + Returns all TXT items for the given service as a ';'-separated string. + If not already existing; the string is alloced, filled and attached to the answer. + +*/ +const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcTxts (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_Txts.m_pTxts) && + (!pSQAnswer->m_pcTxts)) + { + + pSQAnswer->m_pcTxts = pSQAnswer->allocTxts(pSQAnswer->m_Txts.c_strLength()); + if (pSQAnswer->m_pcTxts) + { + pSQAnswer->m_Txts.c_str(pSQAnswer->m_pcTxts); + } + } + return (pSQAnswer ? pSQAnswer->m_pcTxts : 0); +} + +/* + PROBING +*/ + +/* + MDNSResponder::setProbeResultCallback + + Set a global callback for probe results. The callback is called, when probing + for the host domain (or a service domain, without specific probe result callback) + failes or succeedes. + In the case of failure, the domain name should be changed via 'setHostname' or 'setServiceName'. + When succeeded, the host or service domain will be announced by the MDNS responder. + +*/ +bool MDNSResponder::setHostProbeResultCallback(MDNSResponder::MDNSHostProbeFn p_fnCallback) +{ + + m_HostProbeInformation.m_fnHostProbeResultCallback = p_fnCallback; + + return true; +} + +bool MDNSResponder::setHostProbeResultCallback(MDNSHostProbeFn1 pfn) +{ + using namespace std::placeholders; + return setHostProbeResultCallback([this, pfn](const char* p_pcDomainName, bool p_bProbeResult) + { + pfn(*this, p_pcDomainName, p_bProbeResult); + }); +} + +/* + MDNSResponder::setServiceProbeResultCallback + + Set a service specific callback for probe results. The callback is called, when probing + for the service domain failes or succeedes. + In the case of failure, the service name should be changed via 'setServiceName'. + When succeeded, the service domain will be announced by the MDNS responder. + +*/ +bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, + MDNSResponder::MDNSServiceProbeFn p_fnCallback) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + pService->m_ProbeInformation.m_fnServiceProbeResultCallback = p_fnCallback; + + bResult = true; + } + return bResult; +} + +bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, + MDNSResponder::MDNSServiceProbeFn1 p_fnCallback) +{ + using namespace std::placeholders; + return setServiceProbeResultCallback(p_hService, [this, p_fnCallback](const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) + { + p_fnCallback(*this, p_pcServiceName, p_hMDNSService, p_bProbeResult); + }); +} + + +/* + MISC +*/ + +/* + MDNSResponder::notifyAPChange + + Should be called, whenever the AP for the MDNS responder changes. + A bit of this is caught by the event callbacks installed in the constructor. + +*/ +bool MDNSResponder::notifyAPChange(void) +{ + + return _restart(); +} + +/* + MDNSResponder::update + + Should be called in every 'loop'. + +*/ +bool MDNSResponder::update(void) +{ + + if (m_bPassivModeEnabled) + { + m_bPassivModeEnabled = false; + } + return _process(true); +} + +/* + MDNSResponder::announce + + Should be called, if the 'configuration' changes. Mainly this will be changes in the TXT items... +*/ +bool MDNSResponder::announce(void) +{ + + return (_announce(true, true)); +} + +/* + MDNSResponder::enableArduino + + Enable the OTA update service. + +*/ +MDNSResponder::hMDNSService MDNSResponder::enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload /*= false*/) +{ + + hMDNSService hService = addService(0, "arduino", "tcp", p_u16Port); + if (hService) + { + if ((!addServiceTxt(hService, "tcp_check", "no")) || + (!addServiceTxt(hService, "ssh_upload", "no")) || + (!addServiceTxt(hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) || + (!addServiceTxt(hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) + { + + removeService(hService); + hService = 0; + } + } + return hService; +} + + +} //namespace MDNSImplementation + +} //namespace esp8266 + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.h b/libraries/ESP8266mDNS/src/LEAmDNS.h new file mode 100644 index 0000000000..e10080adf3 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS.h @@ -0,0 +1,1464 @@ +/* + LEAmDNS.h + (c) 2018, LaborEtArs + + Version 0.9 beta + + Some notes (from LaborEtArs, 2018): + Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS). + The target of this rewrite was to keep the existing interface as stable as possible while + adding and extending the supported set of mDNS features. + A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code. + + Supported mDNS features (in some cases somewhat limited): + - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service + - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented + - Probing host and service domains for uniqueness in the local network + - Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak) + - Announcing available services after successful probing + - Using fixed service TXT items or + - Using dynamic service TXT items for presented services (via callback) + - Remove services (and un-announcing them to the observers by sending goodbye-messages) + - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) + - Dynamic queries for DNS-SD services with cached and updated answers and user notifications + + + Usage: + In most cases, this implementation should work as a 'drop-in' replacement for the original + ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some + of the new features should be used. + + For presenting services: + In 'setup()': + Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);' + Register DNS-SD services with 'MDNSResponder::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);' + (Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);') + Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback + using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific + 'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);' + Call MDNS.begin("MyHostname"); + + In 'probeResultCallback(MDNSResponder* p_MDNSResponder, const char* p_pcDomain, MDNSResponder:hMDNSService p_hService, bool p_bProbeResult, void* p_pUserdata)': + Check the probe result and update the host or service domain name if the probe failed + + In 'dynamicServiceTxtCallback(MDNSResponder* p_MDNSResponder, const hMDNSService p_hService, void* p_pUserdata)': + Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hService, "c#", "1");' + + In loop(): + Call 'MDNS.update();' + + + For querying services: + Static: + Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");' + Iterate answers by: 'for (uint32_t u=0; u // for UdpContext.h +#include "WiFiUdp.h" +#include "lwip/udp.h" +#include "debug.h" +#include "include/UdpContext.h" +#include +#include +#include + + +#include "ESP8266WiFi.h" + + +namespace esp8266 +{ + +/** + LEAmDNS +*/ +namespace MDNSImplementation +{ + +//this should be defined at build time +#ifndef ARDUINO_BOARD +#define ARDUINO_BOARD "generic" +#endif + +#define MDNS_IP4_SUPPORT +//#define MDNS_IP6_SUPPORT + + +#ifdef MDNS_IP4_SUPPORT +#define MDNS_IP4_SIZE 4 +#endif +#ifdef MDNS_IP6_SUPPORT +#define MDNS_IP6_SIZE 16 +#endif +/* + Maximum length for all service txts for one service +*/ +#define MDNS_SERVICE_TXT_MAXLENGTH 1300 +/* + Maximum length for a full domain name eg. MyESP._http._tcp.local +*/ +#define MDNS_DOMAIN_MAXLENGTH 256 +/* + Maximum length of on label in a domain name (length info fits into 6 bits) +*/ +#define MDNS_DOMAIN_LABEL_MAXLENGTH 63 +/* + Maximum length of a service name eg. http +*/ +#define MDNS_SERVICE_NAME_LENGTH 15 +/* + Maximum length of a service protocol name eg. tcp +*/ +#define MDNS_SERVICE_PROTOCOL_LENGTH 3 +/* + Default timeout for static service queries +*/ +#define MDNS_QUERYSERVICES_WAIT_TIME 1000 + + +/** + MDNSResponder +*/ +class MDNSResponder +{ +public: + /* INTERFACE */ + + static constexpr auto ApiVersion = MDNSApiVersion::LEA; + + MDNSResponder(void); + virtual ~MDNSResponder(void); + + // Start the MDNS responder by setting the default hostname + // Later call MDNS::update() in every 'loop' to run the process loop + // (probing, announcing, responding, ...) + // if interfaceAddress is not specified, default interface is STA, or AP when STA is not set + bool begin(const char* p_pcHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/); + bool begin(const String& p_strHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/) + { + return begin(p_strHostname.c_str(), p_IPAddress, p_u32TTL); + } + + // Finish MDNS processing + bool close(void); + // for esp32 compatability + bool end(void); + // Change hostname (probing is restarted) + bool setHostname(const char* p_pcHostname); + // for compatibility... + bool setHostname(const String& p_strHostname); + + bool isRunning(void) + { + return (m_pUDPContext != 0); + } + + /** + hMDNSService (opaque handle to access the service) + */ + typedef const void* hMDNSService; + + // Add a new service to the MDNS responder. If no name (instance name) is given (p_pcName = 0) + // the current hostname is used. If the hostname is changed later, the instance names for + // these 'auto-named' services are changed to the new name also (and probing is restarted). + // The usual '_' before p_pcService (eg. http) and protocol (eg. tcp) may be given. + hMDNSService addService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port); + // Removes a service from the MDNS responder + bool removeService(const hMDNSService p_hService); + bool removeService(const char* p_pcInstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol); + // for compatibility... + bool addService(const String& p_strServiceName, + const String& p_strProtocol, + uint16_t p_u16Port); + + + // Change the services instance name (and restart probing). + bool setServiceName(const hMDNSService p_hService, + const char* p_pcInstanceName); + //for compatibility + //Warning: this has the side effect of changing the hostname. + //TODO: implement instancename different from hostname + void setInstanceName(const char* p_pcHostname) + { + setHostname(p_pcHostname); + } + // for esp32 compatibilty + void setInstanceName(const String& s_pcHostname) + { + setInstanceName(s_pcHostname.c_str()); + } + + /** + hMDNSTxt (opaque handle to access the TXT items) + */ + typedef void* hMDNSTxt; + + // Add a (static) MDNS TXT item ('key' = 'value') to the service + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value); + + // Remove an existing (static) MDNS TXT item from the service + bool removeServiceTxt(const hMDNSService p_hService, + const hMDNSTxt p_hTxt); + bool removeServiceTxt(const hMDNSService p_hService, + const char* p_pcKey); + bool removeServiceTxt(const char* p_pcinstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol, + const char* p_pcKey); + // for compatibility... + bool addServiceTxt(const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey, + const char* p_pcValue); + bool addServiceTxt(const String& p_strService, + const String& p_strProtocol, + const String& p_strKey, + const String& p_strValue); + + /** + MDNSDynamicServiceTxtCallbackFn + Callback function for dynamic MDNS TXT items + */ + + typedef std::function MDNSDynamicServiceTxtCallbackFunc; + + // Set a global callback for dynamic MDNS TXT items. The callback function is called + // every time, a TXT item is needed for one of the installed services. + bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFunc p_fnCallback); + // Set a service specific callback for dynamic MDNS TXT items. The callback function + // is called every time, a TXT item is needed for the given service. + bool setDynamicServiceTxtCallback(const hMDNSService p_hService, + MDNSDynamicServiceTxtCallbackFunc p_fnCallback); + + // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + // Dynamic TXT items are removed right after one-time use. So they need to be added + // every time the value s needed (via callback). + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value); + + // Perform a (static) service query. The function returns after p_u16Timeout milliseconds + // The answers (the number of received answers is returned) can be retrieved by calling + // - answerHostname (or hostname) + // - answerIP (or IP) + // - answerPort (or port) + uint32_t queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + bool removeQuery(void); + // for compatibility... + uint32_t queryService(const String& p_strService, + const String& p_strProtocol); + + const char* answerHostname(const uint32_t p_u32AnswerIndex); + IPAddress answerIP(const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const uint32_t p_u32AnswerIndex); + // for compatibility... + String hostname(const uint32_t p_u32AnswerIndex); + IPAddress IP(const uint32_t p_u32AnswerIndex); + uint16_t port(const uint32_t p_u32AnswerIndex); + + /** + hMDNSServiceQuery (opaque handle to access dynamic service queries) + */ + typedef const void* hMDNSServiceQuery; + + /** + enuServiceQueryAnswerType + */ + typedef enum _enuServiceQueryAnswerType + { + ServiceQueryAnswerType_ServiceDomain = (1 << 0), // Service instance name + ServiceQueryAnswerType_HostDomainAndPort = (1 << 1), // Host domain and service port + ServiceQueryAnswerType_Txts = (1 << 2), // TXT items +#ifdef MDNS_IP4_SUPPORT + ServiceQueryAnswerType_IP4Address = (1 << 3), // IP4 address +#endif +#ifdef MDNS_IP6_SUPPORT + ServiceQueryAnswerType_IP6Address = (1 << 4), // IP6 address +#endif + } enuServiceQueryAnswerType; + + enum class AnswerType : uint32_t + { + Unknown = 0, + ServiceDomain = ServiceQueryAnswerType_ServiceDomain, + HostDomainAndPort = ServiceQueryAnswerType_HostDomainAndPort, + Txt = ServiceQueryAnswerType_Txts, +#ifdef MDNS_IP4_SUPPORT + IP4Address = ServiceQueryAnswerType_IP4Address, +#endif +#ifdef MDNS_IP6_SUPPORT + IP6Address = ServiceQueryAnswerType_IP6Address, +#endif + }; + + /** + MDNSServiceQueryCallbackFn + Callback function for received answers for dynamic service queries + */ + struct MDNSServiceInfo; // forward declaration + typedef std::function MDNSServiceQueryCallbackFunc; + + // Install a dynamic service query. For every received answer (part) the given callback + // function is called. The query will be updated every time, the TTL for an answer + // has timed-out. + // The answers can also be retrieved by calling + // - answerCount + // - answerServiceDomain + // - hasAnswerHostDomain/answerHostDomain + // - hasAnswerIP4Address/answerIP4Address + // - hasAnswerIP6Address/answerIP6Address + // - hasAnswerPort/answerPort + // - hasAnswerTxts/answerTxts + hMDNSServiceQuery installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSServiceQueryCallbackFunc p_fnCallback); + // Remove a dynamic service query + bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery); + + uint32_t answerCount(const hMDNSServiceQuery p_hServiceQuery); + std::vector answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery); + + const char* answerServiceDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerHostDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + const char* answerHostDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); +#ifdef MDNS_IP4_SUPPORT + bool hasAnswerIP4Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIP4AddressCount(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIP4Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif +#ifdef MDNS_IP6_SUPPORT + bool hasAnswerIP6Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIP6AddressCount(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIP6Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif + bool hasAnswerPort(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerTxts(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + // Get the TXT items as a ';'-separated string + const char* answerTxts(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + + /** + MDNSProbeResultCallbackFn + Callback function for (host and service domain) probe results + */ + typedef std::function MDNSHostProbeFn; + + typedef std::function MDNSHostProbeFn1; + + typedef std::function MDNSServiceProbeFn; + + typedef std::function MDNSServiceProbeFn1; + + // Set a global callback function for host and service probe results + // The callback function is called, when the probing for the host domain + // (or a service domain, which hasn't got a service specific callback) + // Succeeds or fails. + // In case of failure, the failed domain name should be changed. + bool setHostProbeResultCallback(MDNSHostProbeFn p_fnCallback); + bool setHostProbeResultCallback(MDNSHostProbeFn1 p_fnCallback); + + // Set a service specific probe result callback + bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, + MDNSServiceProbeFn p_fnCallback); + bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, + MDNSServiceProbeFn1 p_fnCallback); + + // Application should call this whenever AP is configured/disabled + bool notifyAPChange(void); + + // 'update' should be called in every 'loop' to run the MDNS processing + bool update(void); + + // 'announce' can be called every time, the configuration of some service + // changes. Mainly, this would be changed content of TXT items. + bool announce(void); + + // Enable OTA update + hMDNSService enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload = false); + + // Domain name helper + static bool indexDomain(char*& p_rpcDomain, + const char* p_pcDivider = "-", + const char* p_pcDefaultDomain = 0); + + /** STRUCTS **/ + +public: + /** + MDNSServiceInfo, used in application callbacks + */ + struct MDNSServiceInfo + { + MDNSServiceInfo(MDNSResponder& p_pM, MDNSResponder::hMDNSServiceQuery p_hS, uint32_t p_u32A) + : p_pMDNSResponder(p_pM), + p_hServiceQuery(p_hS), + p_u32AnswerIndex(p_u32A) + {}; + struct CompareKey + { + bool operator()(char const *a, char const *b) const + { + return strcmp(a, b) < 0; + } + }; + using KeyValueMap = std::map; + protected: + MDNSResponder& p_pMDNSResponder; + MDNSResponder::hMDNSServiceQuery p_hServiceQuery; + uint32_t p_u32AnswerIndex; + KeyValueMap keyValueMap; + public: + const char* serviceDomain() + { + return p_pMDNSResponder.answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex); + }; + bool hostDomainAvailable() + { + return (p_pMDNSResponder.hasAnswerHostDomain(p_hServiceQuery, p_u32AnswerIndex)); + } + const char* hostDomain() + { + return (hostDomainAvailable()) ? + p_pMDNSResponder.answerHostDomain(p_hServiceQuery, p_u32AnswerIndex) : nullptr; + }; + bool hostPortAvailable() + { + return (p_pMDNSResponder.hasAnswerPort(p_hServiceQuery, p_u32AnswerIndex)); + } + uint16_t hostPort() + { + return (hostPortAvailable()) ? + p_pMDNSResponder.answerPort(p_hServiceQuery, p_u32AnswerIndex) : 0; + }; + bool IP4AddressAvailable() + { + return (p_pMDNSResponder.hasAnswerIP4Address(p_hServiceQuery, p_u32AnswerIndex)); + } + std::vector IP4Adresses() + { + std::vector internalIP; + if (IP4AddressAvailable()) + { + uint16_t cntIP4Adress = p_pMDNSResponder.answerIP4AddressCount(p_hServiceQuery, p_u32AnswerIndex); + for (uint32_t u2 = 0; u2 < cntIP4Adress; ++u2) + { + internalIP.emplace_back(p_pMDNSResponder.answerIP4Address(p_hServiceQuery, p_u32AnswerIndex, u2)); + } + } + return internalIP; + }; + bool txtAvailable() + { + return (p_pMDNSResponder.hasAnswerTxts(p_hServiceQuery, p_u32AnswerIndex)); + } + const char* strKeyValue() + { + return (txtAvailable()) ? + p_pMDNSResponder.answerTxts(p_hServiceQuery, p_u32AnswerIndex) : nullptr; + }; + const KeyValueMap& keyValues() + { + if (txtAvailable() && keyValueMap.size() == 0) + { + for (auto kv = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); kv != nullptr; kv = kv->m_pNext) + { + keyValueMap.emplace(std::pair(kv->m_pcKey, kv->m_pcValue)); + } + } + return keyValueMap; + } + const char* value(const char* key) + { + char* result = nullptr; + + for (stcMDNSServiceTxt* pTxt = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); pTxt; pTxt = pTxt->m_pNext) + { + if ((key) && + (0 == strcmp(pTxt->m_pcKey, key))) + { + result = pTxt->m_pcValue; + break; + } + } + return result; + } + }; +protected: + + /** + stcMDNSServiceTxt + */ + struct stcMDNSServiceTxt + { + stcMDNSServiceTxt* m_pNext; + char* m_pcKey; + char* m_pcValue; + bool m_bTemp; + + stcMDNSServiceTxt(const char* p_pcKey = 0, + const char* p_pcValue = 0, + bool p_bTemp = false); + stcMDNSServiceTxt(const stcMDNSServiceTxt& p_Other); + ~stcMDNSServiceTxt(void); + + stcMDNSServiceTxt& operator=(const stcMDNSServiceTxt& p_Other); + bool clear(void); + + char* allocKey(size_t p_stLength); + bool setKey(const char* p_pcKey, + size_t p_stLength); + bool setKey(const char* p_pcKey); + bool releaseKey(void); + + char* allocValue(size_t p_stLength); + bool setValue(const char* p_pcValue, + size_t p_stLength); + bool setValue(const char* p_pcValue); + bool releaseValue(void); + + bool set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp = false); + + bool update(const char* p_pcValue); + + size_t length(void) const; + }; + + /** + stcMDNSTxts + */ + struct stcMDNSServiceTxts + { + stcMDNSServiceTxt* m_pTxts; + + stcMDNSServiceTxts(void); + stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other); + ~stcMDNSServiceTxts(void); + + stcMDNSServiceTxts& operator=(const stcMDNSServiceTxts& p_Other); + + bool clear(void); + + bool add(stcMDNSServiceTxt* p_pTxt); + bool remove(stcMDNSServiceTxt* p_pTxt); + + bool removeTempTxts(void); + + stcMDNSServiceTxt* find(const char* p_pcKey); + const stcMDNSServiceTxt* find(const char* p_pcKey) const; + stcMDNSServiceTxt* find(const stcMDNSServiceTxt* p_pTxt); + + uint16_t length(void) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer); + + size_t bufferLength(void) const; + bool buffer(char* p_pcBuffer); + + bool compare(const stcMDNSServiceTxts& p_Other) const; + bool operator==(const stcMDNSServiceTxts& p_Other) const; + bool operator!=(const stcMDNSServiceTxts& p_Other) const; + }; + + /** + enuContentFlags + */ + typedef enum _enuContentFlags + { + // Host + ContentFlag_A = 0x01, + ContentFlag_PTR_IP4 = 0x02, + ContentFlag_PTR_IP6 = 0x04, + ContentFlag_AAAA = 0x08, + // Service + ContentFlag_PTR_TYPE = 0x10, + ContentFlag_PTR_NAME = 0x20, + ContentFlag_TXT = 0x40, + ContentFlag_SRV = 0x80, + } enuContentFlags; + + /** + stcMDNS_MsgHeader + */ + struct stcMDNS_MsgHeader + { + uint16_t m_u16ID; // Identifier + bool m_1bQR : 1; // Query/Response flag + unsigned char m_4bOpcode : 4; // Operation code + bool m_1bAA : 1; // Authoritative Answer flag + bool m_1bTC : 1; // Truncation flag + bool m_1bRD : 1; // Recursion desired + bool m_1bRA : 1; // Recursion available + unsigned char m_3bZ : 3; // Zero + unsigned char m_4bRCode : 4; // Response code + uint16_t m_u16QDCount; // Question count + uint16_t m_u16ANCount; // Answer count + uint16_t m_u16NSCount; // Authority Record count + uint16_t m_u16ARCount; // Additional Record count + + stcMDNS_MsgHeader(uint16_t p_u16ID = 0, + bool p_bQR = false, + unsigned char p_ucOpcode = 0, + bool p_bAA = false, + bool p_bTC = false, + bool p_bRD = false, + bool p_bRA = false, + unsigned char p_ucRCode = 0, + uint16_t p_u16QDCount = 0, + uint16_t p_u16ANCount = 0, + uint16_t p_u16NSCount = 0, + uint16_t p_u16ARCount = 0); + }; + + /** + stcMDNS_RRDomain + */ + struct stcMDNS_RRDomain + { + char m_acName[MDNS_DOMAIN_MAXLENGTH]; // Encoded domain name + uint16_t m_u16NameLength; // Length (incl. '\0') + + stcMDNS_RRDomain(void); + stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other); + + stcMDNS_RRDomain& operator=(const stcMDNS_RRDomain& p_Other); + + bool clear(void); + + bool addLabel(const char* p_pcLabel, + bool p_bPrependUnderline = false); + + bool compare(const stcMDNS_RRDomain& p_Other) const; + bool operator==(const stcMDNS_RRDomain& p_Other) const; + bool operator!=(const stcMDNS_RRDomain& p_Other) const; + bool operator>(const stcMDNS_RRDomain& p_Other) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer); + }; + + /** + stcMDNS_RRAttributes + */ + struct stcMDNS_RRAttributes + { + uint16_t m_u16Type; // Type + uint16_t m_u16Class; // Class, nearly always 'IN' + + stcMDNS_RRAttributes(uint16_t p_u16Type = 0, + uint16_t p_u16Class = 1 /*DNS_RRCLASS_IN Internet*/); + stcMDNS_RRAttributes(const stcMDNS_RRAttributes& p_Other); + + stcMDNS_RRAttributes& operator=(const stcMDNS_RRAttributes& p_Other); + }; + + /** + stcMDNS_RRHeader + */ + struct stcMDNS_RRHeader + { + stcMDNS_RRDomain m_Domain; + stcMDNS_RRAttributes m_Attributes; + + stcMDNS_RRHeader(void); + stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other); + + stcMDNS_RRHeader& operator=(const stcMDNS_RRHeader& p_Other); + + bool clear(void); + }; + + /** + stcMDNS_RRQuestion + */ + struct stcMDNS_RRQuestion + { + stcMDNS_RRQuestion* m_pNext; + stcMDNS_RRHeader m_Header; + bool m_bUnicast; // Unicast reply requested + + stcMDNS_RRQuestion(void); + }; + + /** + enuAnswerType + */ + typedef enum _enuAnswerType + { + AnswerType_A, + AnswerType_PTR, + AnswerType_TXT, + AnswerType_AAAA, + AnswerType_SRV, + AnswerType_Generic + } enuAnswerType; + + /** + stcMDNS_RRAnswer + */ + struct stcMDNS_RRAnswer + { + stcMDNS_RRAnswer* m_pNext; + const enuAnswerType m_AnswerType; + stcMDNS_RRHeader m_Header; + bool m_bCacheFlush; // Cache flush command bit + uint32_t m_u32TTL; // Validity time in seconds + + virtual ~stcMDNS_RRAnswer(void); + + enuAnswerType answerType(void) const; + + bool clear(void); + + protected: + stcMDNS_RRAnswer(enuAnswerType p_AnswerType, + const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + }; + +#ifdef MDNS_IP4_SUPPORT + /** + stcMDNS_RRAnswerA + */ + struct stcMDNS_RRAnswerA : public stcMDNS_RRAnswer + { + IPAddress m_IPAddress; + + stcMDNS_RRAnswerA(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerA(void); + + bool clear(void); + }; +#endif + + /** + stcMDNS_RRAnswerPTR + */ + struct stcMDNS_RRAnswerPTR : public stcMDNS_RRAnswer + { + stcMDNS_RRDomain m_PTRDomain; + + stcMDNS_RRAnswerPTR(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerPTR(void); + + bool clear(void); + }; + + /** + stcMDNS_RRAnswerTXT + */ + struct stcMDNS_RRAnswerTXT : public stcMDNS_RRAnswer + { + stcMDNSServiceTxts m_Txts; + + stcMDNS_RRAnswerTXT(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerTXT(void); + + bool clear(void); + }; + +#ifdef MDNS_IP6_SUPPORT + /** + stcMDNS_RRAnswerAAAA + */ + struct stcMDNS_RRAnswerAAAA : public stcMDNS_RRAnswer + { + //TODO: IP6Address m_IPAddress; + + stcMDNS_RRAnswerAAAA(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerAAAA(void); + + bool clear(void); + }; +#endif + + /** + stcMDNS_RRAnswerSRV + */ + struct stcMDNS_RRAnswerSRV : public stcMDNS_RRAnswer + { + uint16_t m_u16Priority; + uint16_t m_u16Weight; + uint16_t m_u16Port; + stcMDNS_RRDomain m_SRVDomain; + + stcMDNS_RRAnswerSRV(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerSRV(void); + + bool clear(void); + }; + + /** + stcMDNS_RRAnswerGeneric + */ + struct stcMDNS_RRAnswerGeneric : public stcMDNS_RRAnswer + { + uint16_t m_u16RDLength; // Length of variable answer + uint8_t* m_pu8RDData; // Offset of start of variable answer in packet + + stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerGeneric(void); + + bool clear(void); + }; + + + /** + enuProbingStatus + */ + typedef enum _enuProbingStatus + { + ProbingStatus_WaitingForData, + ProbingStatus_ReadyToStart, + ProbingStatus_InProgress, + ProbingStatus_Done + } enuProbingStatus; + + /** + stcProbeInformation + */ + struct stcProbeInformation + { + enuProbingStatus m_ProbingStatus; + uint8_t m_u8SentCount; // Used for probes and announcements + esp8266::polledTimeout::oneShotMs m_Timeout; // Used for probes and announcements + //clsMDNSTimeFlag m_TimeFlag; // Used for probes and announcements + bool m_bConflict; + bool m_bTiebreakNeeded; + MDNSHostProbeFn m_fnHostProbeResultCallback; + MDNSServiceProbeFn m_fnServiceProbeResultCallback; + + stcProbeInformation(void); + + bool clear(bool p_bClearUserdata = false); + }; + + + /** + stcMDNSService + */ + struct stcMDNSService + { + stcMDNSService* m_pNext; + char* m_pcName; + bool m_bAutoName; // Name was set automatically to hostname (if no name was supplied) + char* m_pcService; + char* m_pcProtocol; + uint16_t m_u16Port; + uint8_t m_u8ReplyMask; + stcMDNSServiceTxts m_Txts; + MDNSDynamicServiceTxtCallbackFunc m_fnTxtCallback; + stcProbeInformation m_ProbeInformation; + + stcMDNSService(const char* p_pcName = 0, + const char* p_pcService = 0, + const char* p_pcProtocol = 0); + ~stcMDNSService(void); + + bool setName(const char* p_pcName); + bool releaseName(void); + + bool setService(const char* p_pcService); + bool releaseService(void); + + bool setProtocol(const char* p_pcProtocol); + bool releaseProtocol(void); + }; + + /** + stcMDNSServiceQuery + */ + struct stcMDNSServiceQuery + { + /** + stcAnswer + */ + struct stcAnswer + { + /** + stcTTL + */ + struct stcTTL + { + /** + timeoutLevel_t + */ + typedef uint8_t timeoutLevel_t; + /** + TIMEOUTLEVELs + */ + const timeoutLevel_t TIMEOUTLEVEL_UNSET = 0; + const timeoutLevel_t TIMEOUTLEVEL_BASE = 80; + const timeoutLevel_t TIMEOUTLEVEL_INTERVAL = 5; + const timeoutLevel_t TIMEOUTLEVEL_FINAL = 100; + + uint32_t m_u32TTL; + esp8266::polledTimeout::oneShotMs m_TTLTimeout; + timeoutLevel_t m_timeoutLevel; + + stcTTL(void); + bool set(uint32_t p_u32TTL); + + bool flagged(void); + bool restart(void); + + bool prepareDeletion(void); + bool finalTimeoutLevel(void) const; + + unsigned long timeout(void) const; + }; +#ifdef MDNS_IP4_SUPPORT + /** + stcIP4Address + */ + struct stcIP4Address + { + stcIP4Address* m_pNext; + IPAddress m_IPAddress; + stcTTL m_TTL; + + stcIP4Address(IPAddress p_IPAddress, + uint32_t p_u32TTL = 0); + }; +#endif +#ifdef MDNS_IP6_SUPPORT + /** + stcIP6Address + */ + struct stcIP6Address + { + stcIP6Address* m_pNext; + IP6Address m_IPAddress; + stcTTL m_TTL; + + stcIP6Address(IPAddress p_IPAddress, + uint32_t p_u32TTL = 0); + }; +#endif + + stcAnswer* m_pNext; + // The service domain is the first 'answer' (from PTR answer, using service and protocol) to be set + // Defines the key for additional answer, like host domain, etc. + stcMDNS_RRDomain m_ServiceDomain; // 1. level answer (PTR), eg. MyESP._http._tcp.local + char* m_pcServiceDomain; + stcTTL m_TTLServiceDomain; + stcMDNS_RRDomain m_HostDomain; // 2. level answer (SRV, using service domain), eg. esp8266.local + char* m_pcHostDomain; + uint16_t m_u16Port; // 2. level answer (SRV, using service domain), eg. 5000 + stcTTL m_TTLHostDomainAndPort; + stcMDNSServiceTxts m_Txts; // 2. level answer (TXT, using service domain), eg. c#=1 + char* m_pcTxts; + stcTTL m_TTLTxts; +#ifdef MDNS_IP4_SUPPORT + stcIP4Address* m_pIP4Addresses; // 3. level answer (A, using host domain), eg. 123.456.789.012 +#endif +#ifdef MDNS_IP6_SUPPORT + stcIP6Address* m_pIP6Addresses; // 3. level answer (AAAA, using host domain), eg. 1234::09 +#endif + uint32_t m_u32ContentFlags; + + stcAnswer(void); + ~stcAnswer(void); + + bool clear(void); + + char* allocServiceDomain(size_t p_stLength); + bool releaseServiceDomain(void); + + char* allocHostDomain(size_t p_stLength); + bool releaseHostDomain(void); + + char* allocTxts(size_t p_stLength); + bool releaseTxts(void); + +#ifdef MDNS_IP4_SUPPORT + bool releaseIP4Addresses(void); + bool addIP4Address(stcIP4Address* p_pIP4Address); + bool removeIP4Address(stcIP4Address* p_pIP4Address); + const stcIP4Address* findIP4Address(const IPAddress& p_IPAddress) const; + stcIP4Address* findIP4Address(const IPAddress& p_IPAddress); + uint32_t IP4AddressCount(void) const; + const stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index) const; + stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index); +#endif +#ifdef MDNS_IP6_SUPPORT + bool releaseIP6Addresses(void); + bool addIP6Address(stcIP6Address* p_pIP6Address); + bool removeIP6Address(stcIP6Address* p_pIP6Address); + const stcIP6Address* findIP6Address(const IPAddress& p_IPAddress) const; + stcIP6Address* findIP6Address(const IPAddress& p_IPAddress); + uint32_t IP6AddressCount(void) const; + const stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index) const; + stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index); +#endif + }; + + stcMDNSServiceQuery* m_pNext; + stcMDNS_RRDomain m_ServiceTypeDomain; // eg. _http._tcp.local + MDNSServiceQueryCallbackFunc m_fnCallback; + bool m_bLegacyQuery; + uint8_t m_u8SentCount; + esp8266::polledTimeout::oneShotMs m_ResendTimeout; + bool m_bAwaitingAnswers; + stcAnswer* m_pAnswers; + + stcMDNSServiceQuery(void); + ~stcMDNSServiceQuery(void); + + bool clear(void); + + uint32_t answerCount(void) const; + const stcAnswer* answerAtIndex(uint32_t p_u32Index) const; + stcAnswer* answerAtIndex(uint32_t p_u32Index); + uint32_t indexOfAnswer(const stcAnswer* p_pAnswer) const; + + bool addAnswer(stcAnswer* p_pAnswer); + bool removeAnswer(stcAnswer* p_pAnswer); + + stcAnswer* findAnswerForServiceDomain(const stcMDNS_RRDomain& p_ServiceDomain); + stcAnswer* findAnswerForHostDomain(const stcMDNS_RRDomain& p_HostDomain); + }; + + /** + stcMDNSSendParameter + */ + struct stcMDNSSendParameter + { + protected: + /** + stcDomainCacheItem + */ + struct stcDomainCacheItem + { + stcDomainCacheItem* m_pNext; + const void* m_pHostnameOrService; // Opaque id for host or service domain (pointer) + bool m_bAdditionalData; // Opaque flag for special info (service domain included) + uint16_t m_u16Offset; // Offset in UDP output buffer + + stcDomainCacheItem(const void* p_pHostnameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset); + }; + + public: + uint16_t m_u16ID; // Query ID (used only in lagacy queries) + stcMDNS_RRQuestion* m_pQuestions; // A list of queries + uint8_t m_u8HostReplyMask; // Flags for reply components/answers + bool m_bLegacyQuery; // Flag: Legacy query + bool m_bResponse; // Flag: Response to a query + bool m_bAuthorative; // Flag: Authorative (owner) response + bool m_bCacheFlush; // Flag: Clients should flush their caches + bool m_bUnicast; // Flag: Unicast response + bool m_bUnannounce; // Flag: Unannounce service + uint16_t m_u16Offset; // Current offset in UDP write buffer (mainly for domain cache) + stcDomainCacheItem* m_pDomainCacheItems; // Cached host and service domains + + stcMDNSSendParameter(void); + ~stcMDNSSendParameter(void); + + bool clear(void); + + bool shiftOffset(uint16_t p_u16Shift); + + bool addDomainCacheItem(const void* p_pHostnameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset); + uint16_t findCachedDomainOffset(const void* p_pHostnameOrService, + bool p_bAdditionalData) const; + }; + + // Instance variables + stcMDNSService* m_pServices; + UdpContext* m_pUDPContext; + char* m_pcHostname; + stcMDNSServiceQuery* m_pServiceQueries; + WiFiEventHandler m_DisconnectedHandler; + WiFiEventHandler m_GotIPHandler; + MDNSDynamicServiceTxtCallbackFunc m_fnServiceTxtCallback; + bool m_bPassivModeEnabled; + stcProbeInformation m_HostProbeInformation; + CONST netif* m_netif; // network interface to run on + + /** CONTROL **/ + /* MAINTENANCE */ + bool _process(bool p_bUserContext); + bool _restart(void); + + /* RECEIVING */ + bool _parseMessage(void); + bool _parseQuery(const stcMDNS_MsgHeader& p_Header); + + bool _parseResponse(const stcMDNS_MsgHeader& p_Header); + bool _processAnswers(const stcMDNS_RRAnswer* p_pPTRAnswers); + bool _processPTRAnswer(const stcMDNS_RRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processSRVAnswer(const stcMDNS_RRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processTXTAnswer(const stcMDNS_RRAnswerTXT* p_pTXTAnswer); +#ifdef MDNS_IP4_SUPPORT + bool _processAAnswer(const stcMDNS_RRAnswerA* p_pAAnswer); +#endif +#ifdef MDNS_IP6_SUPPORT + bool _processAAAAAnswer(const stcMDNS_RRAnswerAAAA* p_pAAAAAnswer); +#endif + + /* PROBING */ + bool _updateProbeStatus(void); + bool _resetProbeStatus(bool p_bRestart = true); + bool _hasProbesWaitingForAnswers(void) const; + bool _sendHostProbe(void); + bool _sendServiceProbe(stcMDNSService& p_rService); + bool _cancelProbingForHost(void); + bool _cancelProbingForService(stcMDNSService& p_rService); + + /* ANNOUNCE */ + bool _announce(bool p_bAnnounce, + bool p_bIncludeServices); + bool _announceService(stcMDNSService& p_rService, + bool p_bAnnounce = true); + + /* SERVICE QUERY CACHE */ + bool _hasServiceQueriesWaitingForAnswers(void) const; + bool _checkServiceQueryCache(void); + + /** TRANSFER **/ + /* SENDING */ + bool _sendMDNSMessage(stcMDNSSendParameter& p_SendParameter); + bool _sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter); + bool _prepareMDNSMessage(stcMDNSSendParameter& p_SendParameter, + IPAddress p_IPAddress); + bool _sendMDNSServiceQuery(const stcMDNSServiceQuery& p_ServiceQuery); + bool _sendMDNSQuery(const stcMDNS_RRDomain& p_QueryDomain, + uint16_t p_u16QueryType, + stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers = 0); + + const IPAddress _getResponseMulticastInterface() const + { + return IPAddress(m_netif->ip_addr); + } + + uint8_t _replyMaskForHost(const stcMDNS_RRHeader& p_RRHeader, + bool* p_pbFullNameMatch = 0) const; + uint8_t _replyMaskForService(const stcMDNS_RRHeader& p_RRHeader, + const stcMDNSService& p_Service, + bool* p_pbFullNameMatch = 0) const; + + /* RESOURCE RECORD */ + bool _readRRQuestion(stcMDNS_RRQuestion& p_rQuestion); + bool _readRRAnswer(stcMDNS_RRAnswer*& p_rpAnswer); +#ifdef MDNS_IP4_SUPPORT + bool _readRRAnswerA(stcMDNS_RRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerPTR(stcMDNS_RRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength); + bool _readRRAnswerTXT(stcMDNS_RRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength); +#ifdef MDNS_IP6_SUPPORT + bool _readRRAnswerAAAA(stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerSRV(stcMDNS_RRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength); + bool _readRRAnswerGeneric(stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength); + + bool _readRRHeader(stcMDNS_RRHeader& p_rHeader); + bool _readRRDomain(stcMDNS_RRDomain& p_rRRDomain); + bool _readRRDomain_Loop(stcMDNS_RRDomain& p_rRRDomain, + uint8_t p_u8Depth); + bool _readRRAttributes(stcMDNS_RRAttributes& p_rAttributes); + + /* DOMAIN NAMES */ + bool _buildDomainForHost(const char* p_pcHostname, + stcMDNS_RRDomain& p_rHostDomain) const; + bool _buildDomainForDNSSD(stcMDNS_RRDomain& p_rDNSSDDomain) const; + bool _buildDomainForService(const stcMDNSService& p_Service, + bool p_bIncludeName, + stcMDNS_RRDomain& p_rServiceDomain) const; + bool _buildDomainForService(const char* p_pcService, + const char* p_pcProtocol, + stcMDNS_RRDomain& p_rServiceDomain) const; +#ifdef MDNS_IP4_SUPPORT + bool _buildDomainForReverseIP4(IPAddress p_IP4Address, + stcMDNS_RRDomain& p_rReverseIP4Domain) const; +#endif +#ifdef MDNS_IP6_SUPPORT + bool _buildDomainForReverseIP6(IPAddress p_IP4Address, + stcMDNS_RRDomain& p_rReverseIP6Domain) const; +#endif + + /* UDP */ + bool _udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength); + bool _udpRead8(uint8_t& p_ru8Value); + bool _udpRead16(uint16_t& p_ru16Value); + bool _udpRead32(uint32_t& p_ru32Value); + + bool _udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength); + bool _udpAppend8(uint8_t p_u8Value); + bool _udpAppend16(uint16_t p_u16Value); + bool _udpAppend32(uint32_t p_u32Value); + +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + bool _udpDump(bool p_bMovePointer = false); + bool _udpDump(unsigned p_uOffset, + unsigned p_uLength); +#endif + + /* READ/WRITE MDNS STRUCTS */ + bool _readMDNSMsgHeader(stcMDNS_MsgHeader& p_rMsgHeader); + + bool _write8(uint8_t p_u8Value, + stcMDNSSendParameter& p_rSendParameter); + bool _write16(uint16_t p_u16Value, + stcMDNSSendParameter& p_rSendParameter); + bool _write32(uint32_t p_u32Value, + stcMDNSSendParameter& p_rSendParameter); + + bool _writeMDNSMsgHeader(const stcMDNS_MsgHeader& p_MsgHeader, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSRRAttributes(const stcMDNS_RRAttributes& p_Attributes, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSRRDomain(const stcMDNS_RRDomain& p_Domain, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSHostDomain(const char* m_pcHostname, + bool p_bPrependRDLength, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSServiceDomain(const stcMDNSService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + stcMDNSSendParameter& p_rSendParameter); + + bool _writeMDNSQuestion(stcMDNS_RRQuestion& p_Question, + stcMDNSSendParameter& p_rSendParameter); + +#ifdef MDNS_IP4_SUPPORT + bool _writeMDNSAnswer_A(IPAddress p_IPAddress, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress, + stcMDNSSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_PTR_TYPE(stcMDNSService& p_rService, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_NAME(stcMDNSService& p_rService, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_TXT(stcMDNSService& p_rService, + stcMDNSSendParameter& p_rSendParameter); +#ifdef MDNS_IP6_SUPPORT + bool _writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress, + stcMDNSSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_SRV(stcMDNSService& p_rService, + stcMDNSSendParameter& p_rSendParameter); + + /** HELPERS **/ + /* UDP CONTEXT */ + bool _callProcess(void); + bool _allocUDPContext(void); + bool _releaseUDPContext(void); + + /* SERVICE QUERY */ + stcMDNSServiceQuery* _allocServiceQuery(void); + bool _removeServiceQuery(stcMDNSServiceQuery* p_pServiceQuery); + bool _removeLegacyServiceQuery(void); + stcMDNSServiceQuery* _findServiceQuery(hMDNSServiceQuery p_hServiceQuery); + stcMDNSServiceQuery* _findLegacyServiceQuery(void); + bool _releaseServiceQueries(void); + stcMDNSServiceQuery* _findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceDomain, + const stcMDNSServiceQuery* p_pPrevServiceQuery); + + /* HOSTNAME */ + bool _setHostname(const char* p_pcHostname); + bool _releaseHostname(void); + + /* SERVICE */ + stcMDNSService* _allocService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port); + bool _releaseService(stcMDNSService* p_pService); + bool _releaseServices(void); + + stcMDNSService* _findService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol); + stcMDNSService* _findService(const hMDNSService p_hService); + + size_t _countServices(void) const; + + /* SERVICE TXT */ + stcMDNSServiceTxt* _allocServiceTxt(stcMDNSService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + bool _releaseServiceTxt(stcMDNSService* p_pService, + stcMDNSServiceTxt* p_pTxt); + stcMDNSServiceTxt* _updateServiceTxt(stcMDNSService* p_pService, + stcMDNSServiceTxt* p_pTxt, + const char* p_pcValue, + bool p_bTemp); + + stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService, + const char* p_pcKey); + stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService, + const hMDNSTxt p_hTxt); + + stcMDNSServiceTxt* _addServiceTxt(stcMDNSService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + + stcMDNSServiceTxt* _answerKeyValue(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + + bool _collectServiceTxts(stcMDNSService& p_rService); + bool _releaseTempServiceTxts(stcMDNSService& p_rService); + const stcMDNSServiceTxt* _serviceTxts(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol); + + /* MISC */ +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + bool _printRRDomain(const stcMDNS_RRDomain& p_rRRDomain) const; + bool _printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const; +#endif +}; + +}// namespace MDNSImplementation + +}// namespace esp8266 + +#endif // MDNS_H diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp index cee90c907c..740b77db6f 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp @@ -22,6 +22,7 @@ */ +#include "ESP8266mDNS.h" #include "LEAmDNS2Host.h" #ifdef MDNS_IPV4_SUPPORT diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host.h b/libraries/ESP8266mDNS/src/LEAmDNS2Host.h index ff590473c7..ceee11834a 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host.h @@ -129,9 +129,9 @@ /* Enable/disable debug trace macros */ -#ifdef DEBUG_ESP_MDNS_RESPONDER -//#define DEBUG_ESP_MDNS_INFO -//#define DEBUG_ESP_MDNS_INFO2 +#if defined(DEBUG_ESP_PORT) && defined(DEBUG_ESP_MDNS_RESPONDER) +#define DEBUG_ESP_MDNS_INFO +#define DEBUG_ESP_MDNS_INFO2 #define DEBUG_ESP_MDNS_ERR #define DEBUG_ESP_MDNS_TX #define DEBUG_ESP_MDNS_RX @@ -144,7 +144,7 @@ #define DEBUG_EX_INFO(A) #endif #ifdef DEBUG_ESP_MDNS_INFO2 -#define DEBUG_EX_INFO2(A) A +#define DEBUG_EX_INFO2(A) A #else #define DEBUG_EX_INFO2(A) #endif @@ -340,6 +340,9 @@ class clsLEAMDNSHost }; public: + + static constexpr auto ApiVersion = MDNSApiVersion::LEAv2; + /** clsServiceTxt */ @@ -621,6 +624,7 @@ class clsLEAMDNSHost */ using list = std::list; }; + using hMDNSService = clsService; // backward compatibility with LEAmDNS protected: /** diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp index efc9d1879e..a061d77da8 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp @@ -22,6 +22,7 @@ */ +#include "ESP8266mDNS.h" #include "LEAmDNS2Host.h" diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp index b449d1cd08..bc7316be88 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp @@ -22,6 +22,7 @@ */ +#include "ESP8266mDNS.h" #include "LEAmDNS2Host.h" diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp index b2fe64072a..e027f494ac 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp @@ -22,6 +22,7 @@ */ +#include "ESP8266mDNS.h" #include "LEAmDNS2Host.h" diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp index f4a187b667..36b5ece554 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp @@ -23,7 +23,7 @@ */ #include // for can_yield() - +#include "ESP8266mDNS.h" #include "LEAmDNS2Host.h" diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp index 83ecf0c8a4..d3d4849a54 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp @@ -22,6 +22,7 @@ */ +#include "ESP8266mDNS.h" #include "LEAmDNS2Host.h" diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp index 896018f81d..151555d15c 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.cpp @@ -4,6 +4,7 @@ */ +#include "ESP8266mDNS.h" #include "LEAmDNS2_Legacy.h" diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp new file mode 100644 index 0000000000..0e46651d5f --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp @@ -0,0 +1,2135 @@ +/* + LEAmDNS_Control.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include +#include +#include +#include +#include + +/* + ESP8266mDNS Control.cpp +*/ + +extern "C" { +#include "user_interface.h" +} + +#include "ESP8266mDNS.h" +#include "LEAmDNS_lwIPdefs.h" +#include "LEAmDNS_Priv.h" + +namespace esp8266 +{ +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + CONTROL +*/ + + +/** + MAINTENANCE +*/ + +/* + MDNSResponder::_process + + Run the MDNS process. + Is called, every time the UDPContext receives data AND + should be called in every 'loop' by calling 'MDNS::update()'. + +*/ +bool MDNSResponder::_process(bool p_bUserContext) +{ + + bool bResult = true; + + if (!p_bUserContext) + { + + if ((m_pUDPContext) && // UDPContext available AND + (m_pUDPContext->next())) // has content + { + + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _update: Calling _parseMessage\n"));); + bResult = _parseMessage(); + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parsePacket %s\n"), (bResult ? "succeeded" : "FAILED"));); + } + } + else + { + bResult = (m_netif != nullptr) && + (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running + _updateProbeStatus() && // Probing + _checkServiceQueryCache(); // Service query cache check + } + return bResult; +} + +/* + MDNSResponder::_restart +*/ +bool MDNSResponder::_restart(void) +{ + + return ((m_netif != nullptr) && + (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running + (_resetProbeStatus(true)) && // Stop and restart probing + (_allocUDPContext())); // Restart UDP +} + + +/** + RECEIVING +*/ + +/* + MDNSResponder::_parseMessage +*/ +bool MDNSResponder::_parseMessage(void) +{ + DEBUG_EX_INFO( + unsigned long ulStartTime = millis(); + unsigned uStartMemory = ESP.getFreeHeap(); + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage (Time: %lu ms, heap: %u bytes, from %s(%u), to %s(%u))\n"), ulStartTime, uStartMemory, + IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), m_pUDPContext->getRemotePort(), + IPAddress(m_pUDPContext->getDestAddress()).toString().c_str(), m_pUDPContext->getLocalPort()); + ); + //DEBUG_EX_INFO(_udpDump();); + + bool bResult = false; + + stcMDNS_MsgHeader header; + if (_readMDNSMsgHeader(header)) + { + if (0 == header.m_4bOpcode) // A standard query + { + if (header.m_1bQR) // Received a response -> answers to a query + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Reading answers: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); + bResult = _parseResponse(header); + } + else // Received a query (Questions) + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Reading query: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); + bResult = _parseQuery(header); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Received UNEXPECTED opcode:%u. Ignoring message!\n"), header.m_4bOpcode);); + m_pUDPContext->flush(); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: FAILED to read header\n"));); + m_pUDPContext->flush(); + } + DEBUG_EX_INFO( + unsigned uFreeHeap = ESP.getFreeHeap(); + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Done (%s after %lu ms, ate %i bytes, remaining %u)\n\n"), (bResult ? "Succeeded" : "FAILED"), (millis() - ulStartTime), (uStartMemory - uFreeHeap), uFreeHeap); + ); + return bResult; +} + +/* + MDNSResponder::_parseQuery + + Queries are of interest in two cases: + 1. allow for tiebreaking while probing in the case of a race condition between two instances probing for + the same name at the same time + 2. provide answers to questions for our host domain or any presented service + + When reading the questions, a set of (planned) responses is created, eg. a reverse PTR question for the host domain + gets an A (IP address) response, a PTR question for the _services._dns-sd domain gets a PTR (type) response for any + registered service, ... + + As any mDNS responder should be able to handle 'legacy' queries (from DNS clients), this case is handled here also. + Legacy queries have got only one (unicast) question and are directed to the local DNS port (not the multicast port). + + 1. +*/ +bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader) +{ + + bool bResult = true; + + stcMDNSSendParameter sendParameter; + uint8_t u8HostOrServiceReplies = 0; + for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) + { + + stcMDNS_RRQuestion questionRR; + if ((bResult = _readRRQuestion(questionRR))) + { + // Define host replies, BUT only answer queries after probing is done + u8HostOrServiceReplies = + sendParameter.m_u8HostReplyMask |= (((m_bPassivModeEnabled) || + (ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus)) + ? _replyMaskForHost(questionRR.m_Header, 0) + : 0); + DEBUG_EX_INFO(if (u8HostOrServiceReplies) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Host reply needed 0x%X\n"), u8HostOrServiceReplies); + }); + + // Check tiebreak need for host domain + if (ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) + { + bool bFullNameMatch = false; + if ((_replyMaskForHost(questionRR.m_Header, &bFullNameMatch)) && + (bFullNameMatch)) + { + // We're in 'probing' state and someone is asking for our host domain: this might be + // a race-condition: Two host with the same domain names try simutanously to probe their domains + // See: RFC 6762, 8.2 (Tiebraking) + // However, we're using a max. reduced approach for tiebreaking here: The higher IP-address wins! + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Possible race-condition for host domain detected while probing.\n"));); + + m_HostProbeInformation.m_bTiebreakNeeded = true; + } + } + + // Define service replies + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + // Define service replies, BUT only answer queries after probing is done + uint8_t u8ReplyMaskForQuestion = (((m_bPassivModeEnabled) || + (ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus)) + ? _replyMaskForService(questionRR.m_Header, *pService, 0) + : 0); + u8HostOrServiceReplies |= (pService->m_u8ReplyMask |= u8ReplyMaskForQuestion); + DEBUG_EX_INFO(if (u8ReplyMaskForQuestion) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service reply needed for (%s.%s.%s): 0x%X (%s)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, u8ReplyMaskForQuestion, IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()); + }); + + // Check tiebreak need for service domain + if (ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) + { + bool bFullNameMatch = false; + if ((_replyMaskForService(questionRR.m_Header, *pService, &bFullNameMatch)) && + (bFullNameMatch)) + { + // We're in 'probing' state and someone is asking for this service domain: this might be + // a race-condition: Two services with the same domain names try simutanously to probe their domains + // See: RFC 6762, 8.2 (Tiebraking) + // However, we're using a max. reduced approach for tiebreaking here: The 'higher' SRV host wins! + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Possible race-condition for service domain %s.%s.%s detected while probing.\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + + pService->m_ProbeInformation.m_bTiebreakNeeded = true; + } + } + } + + // Handle unicast and legacy specialities + // If only one question asks for unicast reply, the whole reply packet is send unicast + if (((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) || // Unicast (maybe legacy) query OR + (questionRR.m_bUnicast)) && // Expressivly unicast query + (!sendParameter.m_bUnicast)) + { + + sendParameter.m_bUnicast = true; + sendParameter.m_bCacheFlush = false; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Unicast response for %s!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str());); + + if ((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) && // Unicast (maybe legacy) query AND + (1 == p_MsgHeader.m_u16QDCount) && // Only one question AND + ((sendParameter.m_u8HostReplyMask) || // Host replies OR + (u8HostOrServiceReplies))) // Host or service replies available + { + // We're a match for this legacy query, BUT + // make sure, that the query comes from a local host + ip_info IPInfo_Local; + ip_info IPInfo_Remote; + if (((IPInfo_Remote.ip.addr = m_pUDPContext->getRemoteAddress())) && + (((wifi_get_ip_info(SOFTAP_IF, &IPInfo_Local)) && + (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))) || // Remote IP in SOFTAP's subnet OR + ((wifi_get_ip_info(STATION_IF, &IPInfo_Local)) && + (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))))) // Remote IP in STATION's subnet + { + + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Legacy query from local host %s, id %u!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), p_MsgHeader.m_u16ID);); + + sendParameter.m_u16ID = p_MsgHeader.m_u16ID; + sendParameter.m_bLegacyQuery = true; + sendParameter.m_pQuestions = new stcMDNS_RRQuestion; + if ((bResult = (0 != sendParameter.m_pQuestions))) + { + sendParameter.m_pQuestions->m_Header.m_Domain = questionRR.m_Header.m_Domain; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = questionRR.m_Header.m_Attributes.m_u16Type; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = questionRR.m_Header.m_Attributes.m_u16Class; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to add legacy question!\n"));); + } + } + else + { + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Legacy query from NON-LOCAL host!\n"));); + bResult = false; + } + } + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to read question!\n"));); + } + } // for questions + + //DEBUG_EX_INFO(if (u8HostOrServiceReplies) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Reply needed: %u (%s: %s->%s)\n"), u8HostOrServiceReplies, clsTimeSyncer::timestr(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), IPAddress(m_pUDPContext->getDestAddress()).toString().c_str()); } ); + + // Handle known answers + uint32_t u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); + DEBUG_EX_INFO(if ((u8HostOrServiceReplies) && (u32Answers)) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Known answers(%u):\n"), u32Answers); + }); + + for (uint32_t an = 0; ((bResult) && (an < u32Answers)); ++an) + { + stcMDNS_RRAnswer* pKnownRRAnswer = 0; + if (((bResult = _readRRAnswer(pKnownRRAnswer))) && + (pKnownRRAnswer)) + { + + if ((DNS_RRTYPE_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Type) && // No ANY type answer + (DNS_RRCLASS_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Class)) // No ANY class answer + { + + // Find match between planned answer (sendParameter.m_u8HostReplyMask) and this 'known answer' + uint8_t u8HostMatchMask = (sendParameter.m_u8HostReplyMask & _replyMaskForHost(pKnownRRAnswer->m_Header)); + if ((u8HostMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND + ((MDNS_HOST_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new host TTL (120s) + { + + // Compare contents + if (AnswerType_PTR == pKnownRRAnswer->answerType()) + { + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain == hostDomain)) + { + // Host domain match +#ifdef MDNS_IP4_SUPPORT + if (u8HostMatchMask & ContentFlag_PTR_IP4) + { + // IP4 PTR was asked for, but is already known -> skipping + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP4 PTR already known... skipping!\n"));); + sendParameter.m_u8HostReplyMask &= ~ContentFlag_PTR_IP4; + } +#endif +#ifdef MDNS_IP6_SUPPORT + if (u8HostMatchMask & ContentFlag_PTR_IP6) + { + // IP6 PTR was asked for, but is already known -> skipping + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP6 PTR already known... skipping!\n"));); + sendParameter.m_u8HostReplyMask &= ~ContentFlag_PTR_IP6; + } +#endif + } + } + else if (u8HostMatchMask & ContentFlag_A) + { + // IP4 address was asked for +#ifdef MDNS_IP4_SUPPORT + if ((AnswerType_A == pKnownRRAnswer->answerType()) && + (((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress == _getResponseMulticastInterface())) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP4 address already known... skipping!\n"));); + sendParameter.m_u8HostReplyMask &= ~ContentFlag_A; + } // else: RData NOT IP4 length !! +#endif + } + else if (u8HostMatchMask & ContentFlag_AAAA) + { + // IP6 address was asked for +#ifdef MDNS_IP6_SUPPORT + if ((AnswerType_AAAA == pAnswerRR->answerType()) && + (((stcMDNS_RRAnswerAAAA*)pAnswerRR)->m_IPAddress == _getResponseMulticastInterface())) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP6 address already known... skipping!\n"));); + sendParameter.m_u8HostReplyMask &= ~ContentFlag_AAAA; + } // else: RData NOT IP6 length !! +#endif + } + } // Host match /*and TTL*/ + + // + // Check host tiebreak possibility + if (m_HostProbeInformation.m_bTiebreakNeeded) + { + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (pKnownRRAnswer->m_Header.m_Domain == hostDomain)) + { + // Host domain match +#ifdef MDNS_IP4_SUPPORT + if (AnswerType_A == pKnownRRAnswer->answerType()) + { + IPAddress localIPAddress(_getResponseMulticastInterface()); + if (((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) + { + // SAME IP address -> We've received an old message from ourselfs (same IP) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) WON (was an old message)!\n"));); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + else + { + if ((uint32_t)(((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) LOST (lower)!\n"));); + _cancelProbingForHost(); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + else // WON tiebreak + { + //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) WON (higher IP)!\n"));); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + } + } +#endif +#ifdef MDNS_IP6_SUPPORT + if (AnswerType_AAAA == pAnswerRR->answerType()) + { + // TODO + } +#endif + } + } // Host tiebreak possibility + + // Check service answers + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + + uint8_t u8ServiceMatchMask = (pService->m_u8ReplyMask & _replyMaskForService(pKnownRRAnswer->m_Header, *pService)); + + if ((u8ServiceMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND + ((MDNS_SERVICE_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) + { + + if (AnswerType_PTR == pKnownRRAnswer->answerType()) + { + stcMDNS_RRDomain serviceDomain; + if ((u8ServiceMatchMask & ContentFlag_PTR_TYPE) && + (_buildDomainForService(*pService, false, serviceDomain)) && + (serviceDomain == ((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service type PTR already known... skipping!\n"));); + pService->m_u8ReplyMask &= ~ContentFlag_PTR_TYPE; + } + if ((u8ServiceMatchMask & ContentFlag_PTR_NAME) && + (_buildDomainForService(*pService, true, serviceDomain)) && + (serviceDomain == ((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service name PTR already known... skipping!\n"));); + pService->m_u8ReplyMask &= ~ContentFlag_PTR_NAME; + } + } + else if (u8ServiceMatchMask & ContentFlag_SRV) + { + DEBUG_EX_ERR(if (AnswerType_SRV != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: ERROR! INVALID answer type (SRV)!\n"));); + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (hostDomain == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + { + + if ((MDNS_SRV_PRIORITY == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Priority) && + (MDNS_SRV_WEIGHT == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Weight) && + (pService->m_u16Port == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Port)) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service SRV answer already known... skipping!\n"));); + pService->m_u8ReplyMask &= ~ContentFlag_SRV; + } // else: Small differences -> send update message + } + } + else if (u8ServiceMatchMask & ContentFlag_TXT) + { + DEBUG_EX_ERR(if (AnswerType_TXT != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: ERROR! INVALID answer type (TXT)!\n"));); + _collectServiceTxts(*pService); + if (pService->m_Txts == ((stcMDNS_RRAnswerTXT*)pKnownRRAnswer)->m_Txts) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service TXT answer already known... skipping!\n"));); + pService->m_u8ReplyMask &= ~ContentFlag_TXT; + } + _releaseTempServiceTxts(*pService); + } + } // Service match and enough TTL + + // + // Check service tiebreak possibility + if (pService->m_ProbeInformation.m_bTiebreakNeeded) + { + stcMDNS_RRDomain serviceDomain; + if ((_buildDomainForService(*pService, true, serviceDomain)) && + (pKnownRRAnswer->m_Header.m_Domain == serviceDomain)) + { + // Service domain match + if (AnswerType_SRV == pKnownRRAnswer->answerType()) + { + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (hostDomain == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + { + + // We've received an old message from ourselfs (same SRV) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) won (was an old message)!\n"));); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + else + { + if (((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain > hostDomain) // The OTHER domain is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) LOST (lower)!\n"));); + _cancelProbingForService(*pService); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + else // WON tiebreak + { + //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) won (higher)!\n"));); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + } + } + } // service tiebreak possibility + } // for services + } // ANY answers + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to read known answer!\n"));); + } + + if (pKnownRRAnswer) + { + delete pKnownRRAnswer; + pKnownRRAnswer = 0; + } + } // for answers + + if (bResult) + { + // Check, if a reply is needed + uint8_t u8ReplyNeeded = sendParameter.m_u8HostReplyMask; + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + u8ReplyNeeded |= pService->m_u8ReplyMask; + } + + if (u8ReplyNeeded) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Sending answer(0x%X)...\n"), u8ReplyNeeded);); + + sendParameter.m_bResponse = true; + sendParameter.m_bAuthorative = true; + + bResult = _sendMDNSMessage(sendParameter); + } + DEBUG_EX_INFO( + else + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: No reply needed\n")); + } + ); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Something FAILED!\n"));); + m_pUDPContext->flush(); + } + + // + // Check and reset tiebreak-states + if (m_HostProbeInformation.m_bTiebreakNeeded) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: UNSOLVED tiebreak-need for host domain!\n"));); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + if (pService->m_ProbeInformation.m_bTiebreakNeeded) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: UNSOLVED tiebreak-need for service domain (%s.%s.%s)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_parseResponse + + Responses are of interest in two cases: + 1. find domain name conflicts while probing + 2. get answers to service queries + + In both cases any included questions are ignored + + 1. If any answer has a domain name similar to one of the domain names we're planning to use (and are probing for), + then we've got a 'probing conflict'. The conflict has to be solved on our side of the conflict (eg. by + setting a new hostname and restart probing). The callback 'm_fnProbeResultCallback' is called with + 'p_bProbeResult=false' in this case. + + 2. Service queries like '_http._tcp.local' will (if available) produce PTR, SRV, TXT and A/AAAA answers. + All stored answers are pivoted by the service instance name (from the PTR record). Other answer parts, + like host domain or IP address are than attached to this element. + Any answer part carries a TTL, this is also stored (incl. the reception time); if the TTL is '0' the + answer (part) is withdrawn by the sender and should be removed from any cache. RFC 6762, 10.1 proposes to + set the caches TTL-value to 1 second in such a case and to delete the item only, if no update has + has taken place in this second. + Answer parts may arrive in 'unsorted' order, so they are grouped into three levels: + Level 1: PRT - names the service instance (and is used as pivot), voids all other parts if is withdrawn or outdates + Level 2: SRV - links the instance name to a host domain and port, voids A/AAAA parts if is withdrawn or outdates + TXT - links the instance name to services TXTs + Level 3: A/AAAA - links the host domain to an IP address +*/ +bool MDNSResponder::_parseResponse(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse\n"));); + //DEBUG_EX_INFO(_udpDump();); + + bool bResult = false; + + // A response should be the result of a query or a probe + if ((_hasServiceQueriesWaitingForAnswers()) || // Waiting for query answers OR + (_hasProbesWaitingForAnswers())) // Probe responses + { + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received a response\n")); + //_udpDump(); + ); + + bResult = true; + // + // Ignore questions here + stcMDNS_RRQuestion dummyRRQ; + for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received a response containing a question... ignoring!\n"));); + bResult = _readRRQuestion(dummyRRQ); + } // for queries + + // + // Read and collect answers + stcMDNS_RRAnswer* pCollectedRRAnswers = 0; + uint32_t u32NumberOfAnswerRRs = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); + for (uint32_t an = 0; ((bResult) && (an < u32NumberOfAnswerRRs)); ++an) + { + stcMDNS_RRAnswer* pRRAnswer = 0; + if (((bResult = _readRRAnswer(pRRAnswer))) && + (pRRAnswer)) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: ADDING answer!\n"));); + pRRAnswer->m_pNext = pCollectedRRAnswers; + pCollectedRRAnswers = pRRAnswer; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED to read answer!\n"));); + if (pRRAnswer) + { + delete pRRAnswer; + pRRAnswer = 0; + } + bResult = false; + } + } // for answers + + // + // Process answers + if (bResult) + { + bResult = ((!pCollectedRRAnswers) || + (_processAnswers(pCollectedRRAnswers))); + } + else // Some failure while reading answers + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED to read answers!\n"));); + m_pUDPContext->flush(); + } + + // Delete collected answers + while (pCollectedRRAnswers) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: DELETING answer!\n"));); + stcMDNS_RRAnswer* pNextAnswer = pCollectedRRAnswers->m_pNext; + delete pCollectedRRAnswers; + pCollectedRRAnswers = pNextAnswer; + } + } + else // Received an unexpected response -> ignore + { + /* DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received an unexpected response... ignoring!\nDUMP:\n")); + bool bDumpResult = true; + for (uint16_t qd=0; ((bDumpResult) && (qdflush(); + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_processAnswers + Host: + A (0x01): eg. esp8266.local A OP TTL 123.456.789.012 + AAAA (01Cx): eg. esp8266.local AAAA OP TTL 1234:5678::90 + PTR (0x0C, IP4): eg. 012.789.456.123.in-addr.arpa PTR OP TTL esp8266.local + PTR (0x0C, IP6): eg. 90.0.0.0.0.0.0.0.0.0.0.0.78.56.34.12.ip6.arpa PTR OP TTL esp8266.local + Service: + PTR (0x0C, srv name): eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local + PTR (0x0C, srv type): eg. _services._dns-sd._udp.local PTR OP TTL _http._tcp.local + SRV (0x21): eg. MyESP._http._tcp.local SRV OP TTL PRIORITY WEIGHT PORT esp8266.local + TXT (0x10): eg. MyESP._http._tcp.local TXT OP TTL c#=1 + +*/ +bool MDNSResponder::_processAnswers(const MDNSResponder::stcMDNS_RRAnswer* p_pAnswers) +{ + + bool bResult = false; + + if (p_pAnswers) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Processing answers...\n"));); + bResult = true; + + // Answers may arrive in an unexpected order. So we loop our answers as long, as we + // can connect new information to service queries + bool bFoundNewKeyAnswer; + do + { + bFoundNewKeyAnswer = false; + + const stcMDNS_RRAnswer* pRRAnswer = p_pAnswers; + while ((pRRAnswer) && + (bResult)) + { + // 1. level answer (PTR) + if (AnswerType_PTR == pRRAnswer->answerType()) + { + // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + bResult = _processPTRAnswer((stcMDNS_RRAnswerPTR*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new SRV or TXT answers to be linked to queries + } + // 2. level answers + // SRV -> host domain and port + else if (AnswerType_SRV == pRRAnswer->answerType()) + { + // eg. MyESP_http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + bResult = _processSRVAnswer((stcMDNS_RRAnswerSRV*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new A/AAAA answers to be linked to queries + } + // TXT -> Txts + else if (AnswerType_TXT == pRRAnswer->answerType()) + { + // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 + bResult = _processTXTAnswer((stcMDNS_RRAnswerTXT*)pRRAnswer); + } + // 3. level answers +#ifdef MDNS_IP4_SUPPORT + // A -> IP4Address + else if (AnswerType_A == pRRAnswer->answerType()) + { + // eg. esp8266.local A xxxx xx 192.168.2.120 + bResult = _processAAnswer((stcMDNS_RRAnswerA*)pRRAnswer); + } +#endif +#ifdef MDNS_IP6_SUPPORT + // AAAA -> IP6Address + else if (AnswerType_AAAA == pRRAnswer->answerType()) + { + // eg. esp8266.local AAAA xxxx xx 09cf::0c + bResult = _processAAAAAnswer((stcMDNS_RRAnswerAAAA*)pRRAnswer); + } +#endif + + // Finally check for probing conflicts + // Host domain + if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && + ((AnswerType_A == pRRAnswer->answerType()) || + (AnswerType_AAAA == pRRAnswer->answerType()))) + { + + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (pRRAnswer->m_Header.m_Domain == hostDomain)) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Probing CONFLICT found with: %s.local\n"), m_pcHostname);); + _cancelProbingForHost(); + } + } + // Service domains + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && + ((AnswerType_TXT == pRRAnswer->answerType()) || + (AnswerType_SRV == pRRAnswer->answerType()))) + { + + stcMDNS_RRDomain serviceDomain; + if ((_buildDomainForService(*pService, true, serviceDomain)) && + (pRRAnswer->m_Header.m_Domain == serviceDomain)) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Probing CONFLICT found with: %s.%s.%s\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + _cancelProbingForService(*pService); + } + } + } + + pRRAnswer = pRRAnswer->m_pNext; // Next collected answer + } // while (answers) + } while ((bFoundNewKeyAnswer) && + (bResult)); + } // else: No answers provided + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_processPTRAnswer +*/ +bool MDNSResponder::_processPTRAnswer(const MDNSResponder::stcMDNS_RRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pPTRAnswer))) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Processing PTR answers...\n"));); + // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + // Check pending service queries for eg. '_http._tcp' + + stcMDNSServiceQuery* pServiceQuery = _findNextServiceQueryByServiceType(p_pPTRAnswer->m_Header.m_Domain, 0); + while (pServiceQuery) + { + if (pServiceQuery->m_bAwaitingAnswers) + { + // Find answer for service domain (eg. MyESP._http._tcp.local) + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pPTRAnswer->m_PTRDomain); + if (pSQAnswer) // existing answer + { + if (p_pPTRAnswer->m_u32TTL) // Received update message + { + pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Updated TTL(%d) for "), (int)p_pPTRAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + else // received goodbye-message + { + pSQAnswer->m_TTLServiceDomain.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + } + else if ((p_pPTRAnswer->m_u32TTL) && // Not just a goodbye-message + ((pSQAnswer = new stcMDNSServiceQuery::stcAnswer))) // Not yet included -> add answer + { + pSQAnswer->m_ServiceDomain = p_pPTRAnswer->m_PTRDomain; + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_ServiceDomain; + pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); + pSQAnswer->releaseServiceDomain(); + + bResult = pServiceQuery->addAnswer(pSQAnswer); + p_rbFoundNewKeyAnswer = true; + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_ServiceDomain), true); + } + } + } + pServiceQuery = _findNextServiceQueryByServiceType(p_pPTRAnswer->m_Header.m_Domain, pServiceQuery); + } + } // else: No p_pPTRAnswer + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_processSRVAnswer +*/ +bool MDNSResponder::_processSRVAnswer(const MDNSResponder::stcMDNS_RRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pSRVAnswer))) + { + // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pSRVAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available + { + if (p_pSRVAnswer->m_u32TTL) // First or update message (TTL != 0) + { + pSQAnswer->m_TTLHostDomainAndPort.set(p_pSRVAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: Updated TTL(%d) for "), (int)p_pSRVAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + ); + // Host domain & Port + if ((pSQAnswer->m_HostDomain != p_pSRVAnswer->m_SRVDomain) || + (pSQAnswer->m_u16Port != p_pSRVAnswer->m_u16Port)) + { + + pSQAnswer->m_HostDomain = p_pSRVAnswer->m_SRVDomain; + pSQAnswer->releaseHostDomain(); + pSQAnswer->m_u16Port = p_pSRVAnswer->m_u16Port; + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_HostDomainAndPort; + + p_rbFoundNewKeyAnswer = true; + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_HostDomainAndPort), true); + } + } + } + else // Goodby message + { + pSQAnswer->m_TTLHostDomainAndPort.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + ); + } + } + pServiceQuery = pServiceQuery->m_pNext; + } // while(service query) + } // else: No p_pSRVAnswer + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_processTXTAnswer +*/ +bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT* p_pTXTAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pTXTAnswer))) + { + // eg. MyESP._http._tcp.local TXT xxxx xx c#=1 + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pTXTAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available + { + if (p_pTXTAnswer->m_u32TTL) // First or update message + { + pSQAnswer->m_TTLTxts.set(p_pTXTAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: Updated TTL(%d) for "), (int)p_pTXTAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + ); + if (!pSQAnswer->m_Txts.compare(p_pTXTAnswer->m_Txts)) + { + pSQAnswer->m_Txts = p_pTXTAnswer->m_Txts; + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_Txts; + pSQAnswer->releaseTxts(); + + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_Txts), true); + } + } + } + else // Goodby message + { + pSQAnswer->m_TTLTxts.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + ); + } + } + pServiceQuery = pServiceQuery->m_pNext; + } // while(service query) + } // else: No p_pTXTAnswer + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: FAILED!\n")); + }); + return bResult; +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::_processAAnswer +*/ +bool MDNSResponder::_processAAnswer(const MDNSResponder::stcMDNS_RRAnswerA* p_pAAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pAAnswer))) + { + // eg. esp8266.local A xxxx xx 192.168.2.120 + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available + { + stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = pSQAnswer->findIP4Address(p_pAAnswer->m_IPAddress); + if (pIP4Address) + { + // Already known IP4 address + if (p_pAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL + { + pIP4Address->m_TTL.set(p_pAAnswer->m_u32TTL); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%d) for "), (int)p_pAAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP4Address (%s)\n"), pIP4Address->m_IPAddress.toString().c_str()); + ); + } + else // 'Goodbye' message for known IP4 address + { + pIP4Address->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP4 address (%s)\n"), pIP4Address->m_IPAddress.toString().c_str()); + ); + } + } + else + { + // Until now unknown IP4 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAnswer->m_u32TTL) // NOT just a 'Goodbye' message + { + pIP4Address = new stcMDNSServiceQuery::stcAnswer::stcIP4Address(p_pAAnswer->m_IPAddress, p_pAAnswer->m_u32TTL); + if ((pIP4Address) && + (pSQAnswer->addIP4Address(pIP4Address))) + { + + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_IP4Address; + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_IP4Address), true); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED to add IP4 address (%s)!\n"), p_pAAnswer->m_IPAddress.toString().c_str());); + } + } + } + } + pServiceQuery = pServiceQuery->m_pNext; + } // while(service query) + } // else: No p_pAAnswer + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED!\n")); + }); + return bResult; +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::_processAAAAAnswer +*/ +bool MDNSResponder::_processAAAAAnswer(const MDNSResponder::stcMDNS_RRAnswerAAAA* p_pAAAAAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pAAAAAnswer))) + { + // eg. esp8266.local AAAA xxxx xx 0bf3::0c + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available + { + stcIP6Address* pIP6Address = pSQAnswer->findIP6Address(p_pAAAAAnswer->m_IPAddress); + if (pIP6Address) + { + // Already known IP6 address + if (p_pAAAAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL + { + pIP6Address->m_TTL.set(p_pAAAAAnswer->m_u32TTL); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%lu) for "), p_pAAAAAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), pIP6Address->m_IPAddress.toString().c_str()); + ); + } + else // 'Goodbye' message for known IP6 address + { + pIP6Address->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), pIP6Address->m_IPAddress.toString().c_str()); + ); + } + } + else + { + // Until now unknown IP6 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAAAAnswer->m_u32TTL) // NOT just a 'Goodbye' message + { + pIP6Address = new stcIP6Address(p_pAAAAAnswer->m_IPAddress, p_pAAAAAnswer->m_u32TTL); + if ((pIP6Address) && + (pSQAnswer->addIP6Address(pIP6Address))) + { + + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_IP6Address; + + if (pServiceQuery->m_fnCallback) + { + pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP6Address, true, pServiceQuery->m_pUserdata); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED to add IP6 address (%s)!\n"), p_pAAAAAnswer->m_IPAddress.toString().c_str());); + } + } + } + } + pServiceQuery = pServiceQuery->m_pNext; + } // while(service query) + } // else: No p_pAAAAAnswer + + return bResult; +} +#endif + + +/* + PROBING +*/ + +/* + MDNSResponder::_updateProbeStatus + + Manages the (outgoing) probing process. + - If probing has not been started yet (ProbingStatus_NotStarted), the initial delay (see RFC 6762) is determined and + the process is started + - After timeout (of initial or subsequential delay) a probe message is send out for three times. If the message has + already been sent out three times, the probing has been successful and is finished. + + Conflict management is handled in '_parseResponse ff.' + Tiebraking is handled in 'parseQuery ff.' +*/ +bool MDNSResponder::_updateProbeStatus(void) +{ + + bool bResult = true; + + // + // Probe host domain + if ((ProbingStatus_ReadyToStart == m_HostProbeInformation.m_ProbingStatus) && // Ready to get started AND + //TODO: Fix the following to allow Ethernet shield or other interfaces + (_getResponseMulticastInterface() != IPAddress())) // Has IP address + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Starting host probing...\n"));); + + // First probe delay SHOULD be random 0-250 ms + m_HostProbeInformation.m_Timeout.reset(rand() % MDNS_PROBE_DELAY); + m_HostProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; + } + else if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing AND + (m_HostProbeInformation.m_Timeout.expired())) // Time for next probe + { + + if (MDNS_PROBE_COUNT > m_HostProbeInformation.m_u8SentCount) // Send next probe + { + if ((bResult = _sendHostProbe())) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Did sent host probe\n\n"));); + m_HostProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); + ++m_HostProbeInformation.m_u8SentCount; + } + } + else // Probing finished + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host probing.\n"));); + m_HostProbeInformation.m_ProbingStatus = ProbingStatus_Done; + m_HostProbeInformation.m_Timeout.resetToNeverExpires(); + if (m_HostProbeInformation.m_fnHostProbeResultCallback) + { + m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, true); + } + + // Prepare to announce host + m_HostProbeInformation.m_u8SentCount = 0; + m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Prepared host announcing.\n\n"));); + } + } // else: Probing already finished OR waiting for next time slot + else if ((ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) && + (m_HostProbeInformation.m_Timeout.expired())) + { + + if ((bResult = _announce(true, false))) // Don't announce services here + { + ++m_HostProbeInformation.m_u8SentCount; + + if (MDNS_ANNOUNCE_COUNT > m_HostProbeInformation.m_u8SentCount) + { + m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%d).\n\n"), m_HostProbeInformation.m_u8SentCount);); + } + else + { + m_HostProbeInformation.m_Timeout.resetToNeverExpires(); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host announcing.\n\n"));); + } + } + } + + // + // Probe services + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if (ProbingStatus_ReadyToStart == pService->m_ProbeInformation.m_ProbingStatus) // Ready to get started + { + + pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); // More or equal than first probe for host domain + pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; + } + else if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND + (pService->m_ProbeInformation.m_Timeout.expired())) // Time for next probe + { + + if (MDNS_PROBE_COUNT > pService->m_ProbeInformation.m_u8SentCount) // Send next probe + { + if ((bResult = _sendServiceProbe(*pService))) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Did sent service probe (%u)\n\n"), (pService->m_ProbeInformation.m_u8SentCount + 1));); + pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); + ++pService->m_ProbeInformation.m_u8SentCount; + } + } + else // Probing finished + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service probing %s.%s.%s\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_Done; + pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); + if (pService->m_ProbeInformation.m_fnServiceProbeResultCallback) + { + pService->m_ProbeInformation.m_fnServiceProbeResultCallback(pService->m_pcName, pService, true); + } + // Prepare to announce service + pService->m_ProbeInformation.m_u8SentCount = 0; + pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Prepared service announcing.\n\n"));); + } + } // else: Probing already finished OR waiting for next time slot + else if ((ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) && + (pService->m_ProbeInformation.m_Timeout.expired())) + { + + if ((bResult = _announceService(*pService))) // Announce service + { + ++pService->m_ProbeInformation.m_u8SentCount; + + if (MDNS_ANNOUNCE_COUNT > pService->m_ProbeInformation.m_u8SentCount) + { + pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing service %s.%s.%s (%d)\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount);); + } + else + { + pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service announcing for %s.%s.%s\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + } + } + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: FAILED!\n\n")); + }); + return bResult; +} + +/* + MDNSResponder::_resetProbeStatus + + Resets the probe status. + If 'p_bRestart' is set, the status is set to ProbingStatus_NotStarted. Consequently, + when running 'updateProbeStatus' (which is done in every '_update' loop), the probing + process is restarted. +*/ +bool MDNSResponder::_resetProbeStatus(bool p_bRestart /*= true*/) +{ + + m_HostProbeInformation.clear(false); + m_HostProbeInformation.m_ProbingStatus = (p_bRestart ? ProbingStatus_ReadyToStart : ProbingStatus_Done); + + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + pService->m_ProbeInformation.clear(false); + pService->m_ProbeInformation.m_ProbingStatus = (p_bRestart ? ProbingStatus_ReadyToStart : ProbingStatus_Done); + } + return true; +} + +/* + MDNSResponder::_hasProbesWaitingForAnswers +*/ +bool MDNSResponder::_hasProbesWaitingForAnswers(void) const +{ + + bool bResult = ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing + (0 < m_HostProbeInformation.m_u8SentCount)); // And really probing + + for (stcMDNSService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) + { + bResult = ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing + (0 < pService->m_ProbeInformation.m_u8SentCount)); // And really probing + } + return bResult; +} + +/* + MDNSResponder::_sendHostProbe + + Asks (probes) in the local network for the planned host domain + - (eg. esp8266.local) + + To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in + the 'knwon answers' section of the query. + Host domain: + - A/AAAA (eg. esp8266.esp -> 192.168.2.120) +*/ +bool MDNSResponder::_sendHostProbe(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe (%s, %lu)\n"), m_pcHostname, millis());); + + bool bResult = true; + + // Requests for host domain + stcMDNSSendParameter sendParameter; + sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 + + sendParameter.m_pQuestions = new stcMDNS_RRQuestion; + if (((bResult = (0 != sendParameter.m_pQuestions))) && + ((bResult = _buildDomainForHost(m_pcHostname, sendParameter.m_pQuestions->m_Header.m_Domain)))) + { + + //sendParameter.m_pQuestions->m_bUnicast = true; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + + // Add known answers +#ifdef MDNS_IP4_SUPPORT + sendParameter.m_u8HostReplyMask |= ContentFlag_A; // Add A answer +#endif +#ifdef MDNS_IP6_SUPPORT + sendParameter.m_u8HostReplyMask |= ContentFlag_AAAA; // Add AAAA answer +#endif + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe: FAILED to create host question!\n"));); + if (sendParameter.m_pQuestions) + { + delete sendParameter.m_pQuestions; + sendParameter.m_pQuestions = 0; + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe: FAILED!\n")); + }); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + +/* + MDNSResponder::_sendServiceProbe + + Asks (probes) in the local network for the planned service instance domain + - (eg. MyESP._http._tcp.local). + + To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in + the 'knwon answers' section of the query. + Service domain: + - SRV (eg. MyESP._http._tcp.local -> 5000 esp8266.local) + - PTR NAME (eg. _http._tcp.local -> MyESP._http._tcp.local) (TODO: Check if needed, maybe TXT is better) +*/ +bool MDNSResponder::_sendServiceProbe(stcMDNSService& p_rService) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe (%s.%s.%s, %lu)\n"), (p_rService.m_pcName ? : m_pcHostname), p_rService.m_pcService, p_rService.m_pcProtocol, millis());); + + bool bResult = true; + + // Requests for service instance domain + stcMDNSSendParameter sendParameter; + sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 + + sendParameter.m_pQuestions = new stcMDNS_RRQuestion; + if (((bResult = (0 != sendParameter.m_pQuestions))) && + ((bResult = _buildDomainForService(p_rService, true, sendParameter.m_pQuestions->m_Header.m_Domain)))) + { + + sendParameter.m_pQuestions->m_bUnicast = true; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + + // Add known answers + p_rService.m_u8ReplyMask = (ContentFlag_SRV | ContentFlag_PTR_NAME); // Add SRV and PTR NAME answers + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe: FAILED to create service question!\n"));); + if (sendParameter.m_pQuestions) + { + delete sendParameter.m_pQuestions; + sendParameter.m_pQuestions = 0; + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe: FAILED!\n")); + }); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + +/* + MDNSResponder::_cancelProbingForHost +*/ +bool MDNSResponder::_cancelProbingForHost(void) +{ + + bool bResult = false; + + m_HostProbeInformation.clear(false); + // Send host notification + if (m_HostProbeInformation.m_fnHostProbeResultCallback) + { + m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, false); + + bResult = true; + } + + for (stcMDNSService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) + { + bResult = _cancelProbingForService(*pService); + } + return bResult; +} + +/* + MDNSResponder::_cancelProbingForService +*/ +bool MDNSResponder::_cancelProbingForService(stcMDNSService& p_rService) +{ + + bool bResult = false; + + p_rService.m_ProbeInformation.clear(false); + // Send notification + if (p_rService.m_ProbeInformation.m_fnServiceProbeResultCallback) + { + p_rService.m_ProbeInformation.m_fnServiceProbeResultCallback(p_rService.m_pcName, &p_rService, false); + bResult = true; + } + return bResult; +} + + + +/** + ANNOUNCING +*/ + +/* + MDNSResponder::_announce + + Announces the host domain: + - A/AAAA (eg. esp8266.local -> 192.168.2.120) + - PTR (eg. 192.168.2.120.in-addr.arpa -> esp8266.local) + + and all presented services: + - PTR_TYPE (_services._dns-sd._udp.local -> _http._tcp.local) + - PTR_NAME (eg. _http._tcp.local -> MyESP8266._http._tcp.local) + - SRV (eg. MyESP8266._http._tcp.local -> 5000 esp8266.local) + - TXT (eg. MyESP8266._http._tcp.local -> c#=1) + + Goodbye (Un-Announcing) for the host domain and all services is also handled here. + Goodbye messages are created by setting the TTL for the answer to 0, this happens + inside the '_writeXXXAnswer' procs via 'sendParameter.m_bUnannounce = true' +*/ +bool MDNSResponder::_announce(bool p_bAnnounce, + bool p_bIncludeServices) +{ + + bool bResult = false; + + stcMDNSSendParameter sendParameter; + if (ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) + { + + bResult = true; + + sendParameter.m_bResponse = true; // Announces are 'Unsolicited authorative responses' + sendParameter.m_bAuthorative = true; + sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers + + // Announce host + sendParameter.m_u8HostReplyMask = 0; +#ifdef MDNS_IP4_SUPPORT + sendParameter.m_u8HostReplyMask |= ContentFlag_A; // A answer + sendParameter.m_u8HostReplyMask |= ContentFlag_PTR_IP4; // PTR_IP4 answer +#endif +#ifdef MDNS_IP6_SUPPORT + sendParameter.m_u8HostReplyMask |= ContentFlag_AAAA; // AAAA answer + sendParameter.m_u8HostReplyMask |= ContentFlag_PTR_IP6; // PTR_IP6 answer +#endif + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing host %s (content 0x%X)\n"), m_pcHostname, sendParameter.m_u8HostReplyMask);); + + if (p_bIncludeServices) + { + // Announce services (service type, name, SRV (location) and TXTs) + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if (ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) + { + pService->m_u8ReplyMask = (ContentFlag_PTR_TYPE | ContentFlag_PTR_NAME | ContentFlag_SRV | ContentFlag_TXT); + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing service %s.%s.%s (content %u)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_u8ReplyMask);); + } + } + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: FAILED!\n")); + }); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + +/* + MDNSResponder::_announceService +*/ +bool MDNSResponder::_announceService(stcMDNSService& p_rService, + bool p_bAnnounce /*= true*/) +{ + + bool bResult = false; + + stcMDNSSendParameter sendParameter; + if (ProbingStatus_Done == p_rService.m_ProbeInformation.m_ProbingStatus) + { + + sendParameter.m_bResponse = true; // Announces are 'Unsolicited authorative responses' + sendParameter.m_bAuthorative = true; + sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers + + // DON'T announce host + sendParameter.m_u8HostReplyMask = 0; + + // Announce services (service type, name, SRV (location) and TXTs) + p_rService.m_u8ReplyMask = (ContentFlag_PTR_TYPE | ContentFlag_PTR_NAME | ContentFlag_SRV | ContentFlag_TXT); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: Announcing service %s.%s.%s (content 0x%X)\n"), (p_rService.m_pcName ? : m_pcHostname), p_rService.m_pcService, p_rService.m_pcProtocol, p_rService.m_u8ReplyMask);); + + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: FAILED!\n")); + }); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + + +/** + SERVICE QUERY CACHE +*/ + +/* + MDNSResponder::_hasServiceQueriesWaitingForAnswers +*/ +bool MDNSResponder::_hasServiceQueriesWaitingForAnswers(void) const +{ + + bool bOpenQueries = false; + + for (stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; pServiceQuery; pServiceQuery = pServiceQuery->m_pNext) + { + if (pServiceQuery->m_bAwaitingAnswers) + { + bOpenQueries = true; + break; + } + } + return bOpenQueries; +} + +/* + MDNSResponder::_checkServiceQueryCache + + For any 'living' service query (m_bAwaitingAnswers == true) all available answers (their components) + are checked for topicality based on the stored reception time and the answers TTL. + When the components TTL is outlasted by more than 80%, a new question is generated, to get updated information. + When no update arrived (in time), the component is removed from the answer (cache). + +*/ +bool MDNSResponder::_checkServiceQueryCache(void) +{ + + bool bResult = true; + + DEBUG_EX_INFO( + bool printedInfo = false; + ); + for (stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; ((bResult) && (pServiceQuery)); pServiceQuery = pServiceQuery->m_pNext) + { + + // + // Resend dynamic service queries, if not already done often enough + if ((!pServiceQuery->m_bLegacyQuery) && + (MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) && + (pServiceQuery->m_ResendTimeout.expired())) + { + + if ((bResult = _sendMDNSServiceQuery(*pServiceQuery))) + { + ++pServiceQuery->m_u8SentCount; + pServiceQuery->m_ResendTimeout.reset((MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) + ? (MDNS_DYNAMIC_QUERY_RESEND_DELAY * (pServiceQuery->m_u8SentCount - 1)) + : esp8266::polledTimeout::oneShotMs::neverExpires); + } + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: %s to resend service query!"), (bResult ? "Succeeded" : "FAILED")); + printedInfo = true; + ); + } + + // + // Schedule updates for cached answers + if (pServiceQuery->m_bAwaitingAnswers) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->m_pAnswers; + while ((bResult) && + (pSQAnswer)) + { + stcMDNSServiceQuery::stcAnswer* pNextSQAnswer = pSQAnswer->m_pNext; + + // 1. level answer + if ((bResult) && + (pSQAnswer->m_TTLServiceDomain.flagged())) + { + + if (!pSQAnswer->m_TTLServiceDomain.finalTimeoutLevel()) + { + + bResult = ((_sendMDNSServiceQuery(*pServiceQuery)) && + (pSQAnswer->m_TTLServiceDomain.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: PTR update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_ServiceDomain), false); + } + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove PTR answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + printedInfo = true; + ); + + bResult = pServiceQuery->removeAnswer(pSQAnswer); + pSQAnswer = 0; + continue; // Don't use this answer anymore + } + } // ServiceDomain flagged + + // 2. level answers + // HostDomain & Port (from SRV) + if ((bResult) && + (pSQAnswer->m_TTLHostDomainAndPort.flagged())) + { + + if (!pSQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) + { + + bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_SRV)) && + (pSQAnswer->m_TTLHostDomainAndPort.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: SRV update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove SRV answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + printedInfo = true; + ); + // Delete + pSQAnswer->m_HostDomain.clear(); + pSQAnswer->releaseHostDomain(); + pSQAnswer->m_u16Port = 0; + pSQAnswer->m_TTLHostDomainAndPort.set(0); + uint32_t u32ContentFlags = ServiceQueryAnswerType_HostDomainAndPort; + // As the host domain is the base for the IP4- and IP6Address, remove these too +#ifdef MDNS_IP4_SUPPORT + pSQAnswer->releaseIP4Addresses(); + u32ContentFlags |= ServiceQueryAnswerType_IP4Address; +#endif +#ifdef MDNS_IP6_SUPPORT + pSQAnswer->releaseIP6Addresses(); + u32ContentFlags |= ServiceQueryAnswerType_IP6Address; +#endif + + // Remove content flags for deleted answer parts + pSQAnswer->m_u32ContentFlags &= ~u32ContentFlags; + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(u32ContentFlags), false); + } + } + } // HostDomainAndPort flagged + + // Txts (from TXT) + if ((bResult) && + (pSQAnswer->m_TTLTxts.flagged())) + { + + if (!pSQAnswer->m_TTLTxts.finalTimeoutLevel()) + { + + bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_TXT)) && + (pSQAnswer->m_TTLTxts.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: TXT update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove TXT answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + printedInfo = true; + ); + // Delete + pSQAnswer->m_Txts.clear(); + pSQAnswer->m_TTLTxts.set(0); + + // Remove content flags for deleted answer parts + pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_Txts; + + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_Txts), false); + } + } + } // TXTs flagged + + // 3. level answers +#ifdef MDNS_IP4_SUPPORT + // IP4Address (from A) + stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = pSQAnswer->m_pIP4Addresses; + bool bAUpdateQuerySent = false; + while ((pIP4Address) && + (bResult)) + { + + stcMDNSServiceQuery::stcAnswer::stcIP4Address* pNextIP4Address = pIP4Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... + + if (pIP4Address->m_TTL.flagged()) + { + + if (!pIP4Address->m_TTL.finalTimeoutLevel()) // Needs update + { + + if ((bAUpdateQuerySent) || + ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_A)))) + { + + pIP4Address->m_TTL.restart(); + bAUpdateQuerySent = true; + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: IP4 update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP4 address (%s)\n"), (pIP4Address->m_IPAddress.toString().c_str())); + printedInfo = true; + ); + } + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove IP4 answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP4 address\n")); + printedInfo = true; + ); + pSQAnswer->removeIP4Address(pIP4Address); + if (!pSQAnswer->m_pIP4Addresses) // NO IP4 address left -> remove content flag + { + pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_IP4Address; + } + // Notify client + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_IP4Address), false); + } + } + } // IP4 flagged + + pIP4Address = pNextIP4Address; // Next + } // while +#endif +#ifdef MDNS_IP6_SUPPORT + // IP6Address (from AAAA) + stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = pSQAnswer->m_pIP6Addresses; + bool bAAAAUpdateQuerySent = false; + while ((pIP6Address) && + (bResult)) + { + + stcMDNSServiceQuery::stcAnswer::stcIP6Address* pNextIP6Address = pIP6Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... + + if (pIP6Address->m_TTL.flagged()) + { + + if (!pIP6Address->m_TTL.finalTimeoutLevel()) // Needs update + { + + if ((bAAAAUpdateQuerySent) || + ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) + { + + pIP6Address->m_TTL.restart(); + bAAAAUpdateQuerySent = true; + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: IP6 update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), (pIP6Address->m_IPAddress.toString().c_str())); + printedInfo = true; + ); + } + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP6Address\n")); + printedInfo = true; + ); + pSQAnswer->removeIP6Address(pIP6Address); + if (!pSQAnswer->m_pIP6Addresses) // NO IP6 address left -> remove content flag + { + pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_IP6Address; + } + // Notify client + if (pServiceQuery->m_fnCallback) + { + pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP6Address, false, pServiceQuery->m_pUserdata); + } + } + } // IP6 flagged + + pIP6Address = pNextIP6Address; // Next + } // while +#endif + pSQAnswer = pNextSQAnswer; + } + } + } + DEBUG_EX_INFO( + if (printedInfo) +{ + DEBUG_OUTPUT.printf_P(PSTR("\n")); + } + ); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: FAILED!\n")); + }); + return bResult; +} + + +/* + MDNSResponder::_replyMaskForHost + + Determines the relavant host answers for the given question. + - A question for the hostname (eg. esp8266.local) will result in an A/AAAA (eg. 192.168.2.129) reply. + - A question for the reverse IP address (eg. 192-168.2.120.inarpa.arpa) will result in an PTR_IP4 (eg. esp8266.local) reply. + + In addition, a full name match (question domain == host domain) is marked. +*/ +uint8_t MDNSResponder::_replyMaskForHost(const MDNSResponder::stcMDNS_RRHeader& p_RRHeader, + bool* p_pbFullNameMatch /*= 0*/) const +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost\n"));); + + uint8_t u8ReplyMask = 0; + (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); + + if ((DNS_RRCLASS_IN == p_RRHeader.m_Attributes.m_u16Class) || + (DNS_RRCLASS_ANY == p_RRHeader.m_Attributes.m_u16Class)) + { + + if ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // PTR request +#ifdef MDNS_IP4_SUPPORT + stcMDNS_RRDomain reverseIP4Domain; + if ((_buildDomainForReverseIP4(_getResponseMulticastInterface(), reverseIP4Domain)) && + (p_RRHeader.m_Domain == reverseIP4Domain)) + { + // Reverse domain match + u8ReplyMask |= ContentFlag_PTR_IP4; + } +#endif +#ifdef MDNS_IP6_SUPPORT + // TODO +#endif + } // Address qeuest + + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (p_RRHeader.m_Domain == hostDomain)) // Host domain match + { + + (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); + +#ifdef MDNS_IP4_SUPPORT + if ((DNS_RRTYPE_A == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // IP4 address request + u8ReplyMask |= ContentFlag_A; + } +#endif +#ifdef MDNS_IP6_SUPPORT + if ((DNS_RRTYPE_AAAA == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // IP6 address request + u8ReplyMask |= ContentFlag_AAAA; + } +#endif + } + } + else + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); + } + DEBUG_EX_INFO(if (u8ReplyMask) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: 0x%X\n"), u8ReplyMask); + }); + return u8ReplyMask; +} + +/* + MDNSResponder::_replyMaskForService + + Determines the relevant service answers for the given question + - A PTR dns-sd service enum question (_services.dns-sd._udp.local) will result into an PTR_TYPE (eg. _http._tcp.local) answer + - A PTR service type question (eg. _http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer + - A PTR service name question (eg. MyESP._http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer + - A SRV service name question (eg. MyESP._http._tcp.local) will result into an SRV (eg. 5000 MyESP.local) answer + - A TXT service name question (eg. MyESP._http._tcp.local) will result into an TXT (eg. c#=1) answer + + In addition, a full name match (question domain == service instance domain) is marked. +*/ +uint8_t MDNSResponder::_replyMaskForService(const MDNSResponder::stcMDNS_RRHeader& p_RRHeader, + const MDNSResponder::stcMDNSService& p_Service, + bool* p_pbFullNameMatch /*= 0*/) const +{ + + uint8_t u8ReplyMask = 0; + (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); + + if ((DNS_RRCLASS_IN == p_RRHeader.m_Attributes.m_u16Class) || + (DNS_RRCLASS_ANY == p_RRHeader.m_Attributes.m_u16Class)) + { + + stcMDNS_RRDomain DNSSDDomain; + if ((_buildDomainForDNSSD(DNSSDDomain)) && // _services._dns-sd._udp.local + (p_RRHeader.m_Domain == DNSSDDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + { + // Common service info requested + u8ReplyMask |= ContentFlag_PTR_TYPE; + } + + stcMDNS_RRDomain serviceDomain; + if ((_buildDomainForService(p_Service, false, serviceDomain)) && // eg. _http._tcp.local + (p_RRHeader.m_Domain == serviceDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + { + // Special service info requested + u8ReplyMask |= ContentFlag_PTR_NAME; + } + + if ((_buildDomainForService(p_Service, true, serviceDomain)) && // eg. MyESP._http._tcp.local + (p_RRHeader.m_Domain == serviceDomain)) + { + + (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); + + if ((DNS_RRTYPE_SRV == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // Instance info SRV requested + u8ReplyMask |= ContentFlag_SRV; + } + if ((DNS_RRTYPE_TXT == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // Instance info TXT requested + u8ReplyMask |= ContentFlag_TXT; + } + } + } + else + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForService: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); + } + DEBUG_EX_INFO(if (u8ReplyMask) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForService(%s.%s.%s): 0x%X\n"), p_Service.m_pcName, p_Service.m_pcService, p_Service.m_pcProtocol, u8ReplyMask); + }); + return u8ReplyMask; +} + +} // namespace MDNSImplementation + +} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp new file mode 100644 index 0000000000..d5a0ccd762 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp @@ -0,0 +1,851 @@ +/* + LEAmDNS_Helpers.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include + +#include "ESP8266mDNS.h" +#include "LEAmDNS_lwIPdefs.h" +#include "LEAmDNS_Priv.h" + + +namespace +{ + +/* + strrstr (static) + + Backwards search for p_pcPattern in p_pcString + Based on: https://stackoverflow.com/a/1634398/2778898 + +*/ +const char* strrstr(const char*__restrict p_pcString, const char*__restrict p_pcPattern) +{ + + const char* pcResult = 0; + + size_t stStringLength = (p_pcString ? strlen(p_pcString) : 0); + size_t stPatternLength = (p_pcPattern ? strlen(p_pcPattern) : 0); + + if ((stStringLength) && + (stPatternLength) && + (stPatternLength <= stStringLength)) + { + // Pattern is shorter or has the same length tham the string + + for (const char* s = (p_pcString + stStringLength - stPatternLength); s >= p_pcString; --s) + { + if (0 == strncmp(s, p_pcPattern, stPatternLength)) + { + pcResult = s; + break; + } + } + } + return pcResult; +} + + +} // anonymous + + + + + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + HELPERS +*/ + +/* + MDNSResponder::indexDomain (static) + + Updates the given domain 'p_rpcHostname' by appending a delimiter and an index number. + + If the given domain already hasa numeric index (after the given delimiter), this index + incremented. If not, the delimiter and index '2' is added. + + If 'p_rpcHostname' is empty (==0), the given default name 'p_pcDefaultHostname' is used, + if no default is given, 'esp8266' is used. + +*/ +/*static*/ bool MDNSResponder::indexDomain(char*& p_rpcDomain, + const char* p_pcDivider /*= "-"*/, + const char* p_pcDefaultDomain /*= 0*/) +{ + + bool bResult = false; + + // Ensure a divider exists; use '-' as default + const char* pcDivider = (p_pcDivider ? : "-"); + + if (p_rpcDomain) + { + const char* pFoundDivider = strrstr(p_rpcDomain, pcDivider); + if (pFoundDivider) // maybe already extended + { + char* pEnd = 0; + unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10); + if ((ulIndex) && + ((pEnd - p_rpcDomain) == (ptrdiff_t)strlen(p_rpcDomain)) && + (!*pEnd)) // Valid (old) index found + { + + char acIndexBuffer[16]; + sprintf(acIndexBuffer, "%lu", (++ulIndex)); + size_t stLength = ((pFoundDivider - p_rpcDomain + strlen(pcDivider)) + strlen(acIndexBuffer) + 1); + char* pNewHostname = new char[stLength]; + if (pNewHostname) + { + memcpy(pNewHostname, p_rpcDomain, (pFoundDivider - p_rpcDomain + strlen(pcDivider))); + pNewHostname[pFoundDivider - p_rpcDomain + strlen(pcDivider)] = 0; + strcat(pNewHostname, acIndexBuffer); + + delete[] p_rpcDomain; + p_rpcDomain = pNewHostname; + + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); + } + } + else + { + pFoundDivider = 0; // Flag the need to (base) extend the hostname + } + } + + if (!pFoundDivider) // not yet extended (or failed to increment extension) -> start indexing + { + size_t stLength = strlen(p_rpcDomain) + (strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0' + char* pNewHostname = new char[stLength]; + if (pNewHostname) + { + sprintf(pNewHostname, "%s%s2", p_rpcDomain, pcDivider); + + delete[] p_rpcDomain; + p_rpcDomain = pNewHostname; + + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); + } + } + } + else + { + // No given host domain, use base or default + const char* cpcDefaultName = (p_pcDefaultDomain ? : "esp8266"); + + size_t stLength = strlen(cpcDefaultName) + 1; // '\0' + p_rpcDomain = new char[stLength]; + if (p_rpcDomain) + { + strncpy(p_rpcDomain, cpcDefaultName, stLength); + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: %s\n"), p_rpcDomain);); + return bResult; +} + + +/* + UDP CONTEXT +*/ + +bool MDNSResponder::_callProcess(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf("[MDNSResponder] _callProcess (%lu, triggered by: %s)\n", millis(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str());); + + return _process(false); +} + +/* + MDNSResponder::_allocUDPContext + + (Re-)Creates the one-and-only UDP context for the MDNS responder. + The context is added to the 'multicast'-group and listens to the MDNS port (5353). + The travel-distance for multicast messages is set to 1 (local, via MDNS_MULTICAST_TTL). + Messages are received via the MDNSResponder '_update' function. CAUTION: This function + is called from the WiFi stack side of the ESP stack system. + +*/ +bool MDNSResponder::_allocUDPContext(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.println("[MDNSResponder] _allocUDPContext");); + + bool bResult = false; + + _releaseUDPContext(); + +#ifdef MDNS_IP4_SUPPORT + ip_addr_t multicast_addr = DNS_MQUERY_IPV4_GROUP_INIT; +#endif +#ifdef MDNS_IP6_SUPPORT + //TODO: set multicast address (lwip_joingroup() is IPv4 only at the time of writing) + multicast_addr.addr = DNS_MQUERY_IPV6_GROUP_INIT; +#endif + if (ERR_OK == igmp_joingroup(ip_2_ip4(&m_netif->ip_addr), ip_2_ip4(&multicast_addr))) + { + m_pUDPContext = new UdpContext; + m_pUDPContext->ref(); + + if (m_pUDPContext->listen(IP4_ADDR_ANY, DNS_MQUERY_PORT)) + { + m_pUDPContext->setMulticastTTL(MDNS_MULTICAST_TTL); + m_pUDPContext->onRx(std::bind(&MDNSResponder::_callProcess, this)); + + bResult = m_pUDPContext->connect(&multicast_addr, DNS_MQUERY_PORT); + } + } + return bResult; +} + +/* + MDNSResponder::_releaseUDPContext +*/ +bool MDNSResponder::_releaseUDPContext(void) +{ + + if (m_pUDPContext) + { + m_pUDPContext->unref(); + m_pUDPContext = 0; + } + return true; +} + + +/* + SERVICE QUERY +*/ + +/* + MDNSResponder::_allocServiceQuery +*/ +MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_allocServiceQuery(void) +{ + + stcMDNSServiceQuery* pServiceQuery = new stcMDNSServiceQuery; + if (pServiceQuery) + { + // Link to query list + pServiceQuery->m_pNext = m_pServiceQueries; + m_pServiceQueries = pServiceQuery; + } + return m_pServiceQueries; +} + +/* + MDNSResponder::_removeServiceQuery +*/ +bool MDNSResponder::_removeServiceQuery(MDNSResponder::stcMDNSServiceQuery* p_pServiceQuery) +{ + + bool bResult = false; + + if (p_pServiceQuery) + { + stcMDNSServiceQuery* pPred = m_pServiceQueries; + while ((pPred) && + (pPred->m_pNext != p_pServiceQuery)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pServiceQuery->m_pNext; + delete p_pServiceQuery; + bResult = true; + } + else // No predecesor + { + if (m_pServiceQueries == p_pServiceQuery) + { + m_pServiceQueries = p_pServiceQuery->m_pNext; + delete p_pServiceQuery; + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseServiceQuery: INVALID service query!");); + } + } + } + return bResult; +} + +/* + MDNSResponder::_removeLegacyServiceQuery +*/ +bool MDNSResponder::_removeLegacyServiceQuery(void) +{ + + stcMDNSServiceQuery* pLegacyServiceQuery = _findLegacyServiceQuery(); + return (pLegacyServiceQuery ? _removeServiceQuery(pLegacyServiceQuery) : true); +} + +/* + MDNSResponder::_findServiceQuery + + 'Convert' hMDNSServiceQuery to stcMDNSServiceQuery* (ensure existance) + +*/ +MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) +{ + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + if ((hMDNSServiceQuery)pServiceQuery == p_hServiceQuery) + { + break; + } + pServiceQuery = pServiceQuery->m_pNext; + } + return pServiceQuery; +} + +/* + MDNSResponder::_findLegacyServiceQuery +*/ +MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findLegacyServiceQuery(void) +{ + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + if (pServiceQuery->m_bLegacyQuery) + { + break; + } + pServiceQuery = pServiceQuery->m_pNext; + } + return pServiceQuery; +} + +/* + MDNSResponder::_releaseServiceQueries +*/ +bool MDNSResponder::_releaseServiceQueries(void) +{ + while (m_pServiceQueries) + { + stcMDNSServiceQuery* pNext = m_pServiceQueries->m_pNext; + delete m_pServiceQueries; + m_pServiceQueries = pNext; + } + return true; +} + +/* + MDNSResponder::_findNextServiceQueryByServiceType +*/ +MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceTypeDomain, + const stcMDNSServiceQuery* p_pPrevServiceQuery) +{ + stcMDNSServiceQuery* pMatchingServiceQuery = 0; + + stcMDNSServiceQuery* pServiceQuery = (p_pPrevServiceQuery ? p_pPrevServiceQuery->m_pNext : m_pServiceQueries); + while (pServiceQuery) + { + if (p_ServiceTypeDomain == pServiceQuery->m_ServiceTypeDomain) + { + pMatchingServiceQuery = pServiceQuery; + break; + } + pServiceQuery = pServiceQuery->m_pNext; + } + return pMatchingServiceQuery; +} + + +/* + HOSTNAME +*/ + +/* + MDNSResponder::_setHostname +*/ +bool MDNSResponder::_setHostname(const char* p_pcHostname) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _allocHostname (%s)\n"), p_pcHostname);); + + bool bResult = false; + + _releaseHostname(); + + size_t stLength = 0; + if ((p_pcHostname) && + (MDNS_DOMAIN_LABEL_MAXLENGTH >= (stLength = strlen(p_pcHostname)))) // char max size for a single label + { + // Copy in hostname characters as lowercase + if ((bResult = (0 != (m_pcHostname = new char[stLength + 1])))) + { +#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME + size_t i = 0; + for (; i < stLength; ++i) + { + m_pcHostname[i] = (isupper(p_pcHostname[i]) ? tolower(p_pcHostname[i]) : p_pcHostname[i]); + } + m_pcHostname[i] = 0; +#else + strncpy(m_pcHostname, p_pcHostname, (stLength + 1)); +#endif + } + } + return bResult; +} + +/* + MDNSResponder::_releaseHostname +*/ +bool MDNSResponder::_releaseHostname(void) +{ + + if (m_pcHostname) + { + delete[] m_pcHostname; + m_pcHostname = 0; + } + return true; +} + + +/* + SERVICE +*/ + +/* + MDNSResponder::_allocService +*/ +MDNSResponder::stcMDNSService* MDNSResponder::_allocService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + + stcMDNSService* pService = 0; + if (((!p_pcName) || + (MDNS_DOMAIN_LABEL_MAXLENGTH >= strlen(p_pcName))) && + (p_pcService) && + (MDNS_SERVICE_NAME_LENGTH >= strlen(p_pcService)) && + (p_pcProtocol) && + (MDNS_SERVICE_PROTOCOL_LENGTH >= strlen(p_pcProtocol)) && + (p_u16Port) && + (0 != (pService = new stcMDNSService)) && + (pService->setName(p_pcName ? : m_pcHostname)) && + (pService->setService(p_pcService)) && + (pService->setProtocol(p_pcProtocol))) + { + + pService->m_bAutoName = (0 == p_pcName); + pService->m_u16Port = p_u16Port; + + // Add to list (or start list) + pService->m_pNext = m_pServices; + m_pServices = pService; + } + return pService; +} + +/* + MDNSResponder::_releaseService +*/ +bool MDNSResponder::_releaseService(MDNSResponder::stcMDNSService* p_pService) +{ + + bool bResult = false; + + if (p_pService) + { + stcMDNSService* pPred = m_pServices; + while ((pPred) && + (pPred->m_pNext != p_pService)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pService->m_pNext; + delete p_pService; + bResult = true; + } + else // No predecesor + { + if (m_pServices == p_pService) + { + m_pServices = p_pService->m_pNext; + delete p_pService; + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseService: INVALID service!");); + } + } + } + return bResult; +} + +/* + MDNSResponder::_releaseServices +*/ +bool MDNSResponder::_releaseServices(void) +{ + + stcMDNSService* pService = m_pServices; + while (pService) + { + _releaseService(pService); + pService = m_pServices; + } + return true; +} + +/* + MDNSResponder::_findService +*/ +MDNSResponder::stcMDNSService* MDNSResponder::_findService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol) +{ + + stcMDNSService* pService = m_pServices; + while (pService) + { + if ((0 == strcmp(pService->m_pcName, p_pcName)) && + (0 == strcmp(pService->m_pcService, p_pcService)) && + (0 == strcmp(pService->m_pcProtocol, p_pcProtocol))) + { + + break; + } + pService = pService->m_pNext; + } + return pService; +} + +/* + MDNSResponder::_findService +*/ +MDNSResponder::stcMDNSService* MDNSResponder::_findService(const MDNSResponder::hMDNSService p_hService) +{ + + stcMDNSService* pService = m_pServices; + while (pService) + { + if (p_hService == (hMDNSService)pService) + { + break; + } + pService = pService->m_pNext; + } + return pService; +} + + +/* + SERVICE TXT +*/ + +/* + MDNSResponder::_allocServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_allocServiceTxt(MDNSResponder::stcMDNSService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp) +{ + + stcMDNSServiceTxt* pTxt = 0; + + if ((p_pService) && + (p_pcKey) && + (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() + + 1 + // Length byte + (p_pcKey ? strlen(p_pcKey) : 0) + + 1 + // '=' + (p_pcValue ? strlen(p_pcValue) : 0)))) + { + + pTxt = new stcMDNSServiceTxt; + if (pTxt) + { + size_t stLength = (p_pcKey ? strlen(p_pcKey) : 0); + pTxt->m_pcKey = new char[stLength + 1]; + if (pTxt->m_pcKey) + { + strncpy(pTxt->m_pcKey, p_pcKey, stLength); pTxt->m_pcKey[stLength] = 0; + } + + if (p_pcValue) + { + stLength = (p_pcValue ? strlen(p_pcValue) : 0); + pTxt->m_pcValue = new char[stLength + 1]; + if (pTxt->m_pcValue) + { + strncpy(pTxt->m_pcValue, p_pcValue, stLength); pTxt->m_pcValue[stLength] = 0; + } + } + pTxt->m_bTemp = p_bTemp; + + // Add to list (or start list) + p_pService->m_Txts.add(pTxt); + } + } + return pTxt; +} + +/* + MDNSResponder::_releaseServiceTxt +*/ +bool MDNSResponder::_releaseServiceTxt(MDNSResponder::stcMDNSService* p_pService, + MDNSResponder::stcMDNSServiceTxt* p_pTxt) +{ + + return ((p_pService) && + (p_pTxt) && + (p_pService->m_Txts.remove(p_pTxt))); +} + +/* + MDNSResponder::_updateServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_updateServiceTxt(MDNSResponder::stcMDNSService* p_pService, + MDNSResponder::stcMDNSServiceTxt* p_pTxt, + const char* p_pcValue, + bool p_bTemp) +{ + + if ((p_pService) && + (p_pTxt) && + (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() - + (p_pTxt->m_pcValue ? strlen(p_pTxt->m_pcValue) : 0) + + (p_pcValue ? strlen(p_pcValue) : 0)))) + { + p_pTxt->update(p_pcValue); + p_pTxt->m_bTemp = p_bTemp; + } + return p_pTxt; +} + +/* + MDNSResponder::_findServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, + const char* p_pcKey) +{ + + return (p_pService ? p_pService->m_Txts.find(p_pcKey) : 0); +} + +/* + MDNSResponder::_findServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, + const hMDNSTxt p_hTxt) +{ + + return (((p_pService) && (p_hTxt)) ? p_pService->m_Txts.find((stcMDNSServiceTxt*)p_hTxt) : 0); +} + +/* + MDNSResponder::_addServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_addServiceTxt(MDNSResponder::stcMDNSService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp) +{ + stcMDNSServiceTxt* pResult = 0; + + if ((p_pService) && + (p_pcKey) && + (strlen(p_pcKey))) + { + + stcMDNSServiceTxt* pTxt = p_pService->m_Txts.find(p_pcKey); + if (pTxt) + { + pResult = _updateServiceTxt(p_pService, pTxt, p_pcValue, p_bTemp); + } + else + { + pResult = _allocServiceTxt(p_pService, p_pcKey, p_pcValue, p_bTemp); + } + } + return pResult; +} + +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_answerKeyValue(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcTxts (if not already done) + return (pSQAnswer) ? pSQAnswer->m_Txts.m_pTxts : 0; +} + +/* + MDNSResponder::_collectServiceTxts +*/ +bool MDNSResponder::_collectServiceTxts(MDNSResponder::stcMDNSService& p_rService) +{ + + // Call Dynamic service callbacks + if (m_fnServiceTxtCallback) + { + m_fnServiceTxtCallback((hMDNSService)&p_rService); + } + if (p_rService.m_fnTxtCallback) + { + p_rService.m_fnTxtCallback((hMDNSService)&p_rService); + } + return true; +} + +/* + MDNSResponder::_releaseTempServiceTxts +*/ +bool MDNSResponder::_releaseTempServiceTxts(MDNSResponder::stcMDNSService& p_rService) +{ + + return (p_rService.m_Txts.removeTempTxts()); +} + + +/* + MISC +*/ + +#ifdef DEBUG_ESP_MDNS_RESPONDER +/* + MDNSResponder::_printRRDomain +*/ +bool MDNSResponder::_printRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_RRDomain) const +{ + + //DEBUG_OUTPUT.printf_P(PSTR("Domain: ")); + + const char* pCursor = p_RRDomain.m_acName; + uint8_t u8Length = *pCursor++; + if (u8Length) + { + while (u8Length) + { + for (uint8_t u = 0; u < u8Length; ++u) + { + DEBUG_OUTPUT.printf_P(PSTR("%c"), *(pCursor++)); + } + u8Length = *pCursor++; + if (u8Length) + { + DEBUG_OUTPUT.printf_P(PSTR(".")); + } + } + } + else // empty domain + { + DEBUG_OUTPUT.printf_P(PSTR("-empty-")); + } + //DEBUG_OUTPUT.printf_P(PSTR("\n")); + + return true; +} + +/* + MDNSResponder::_printRRAnswer +*/ +bool MDNSResponder::_printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const +{ + + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] RRAnswer: ")); + _printRRDomain(p_RRAnswer.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, "), p_RRAnswer.m_Header.m_Attributes.m_u16Type, p_RRAnswer.m_Header.m_Attributes.m_u16Class, p_RRAnswer.m_u32TTL); + switch (p_RRAnswer.m_Header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IP4_SUPPORT + case DNS_RRTYPE_A: + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((const stcMDNS_RRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_PTR: + DEBUG_OUTPUT.printf_P(PSTR("PTR ")); + _printRRDomain(((const stcMDNS_RRAnswerPTR*)&p_RRAnswer)->m_PTRDomain); + break; + case DNS_RRTYPE_TXT: + { + size_t stTxtLength = ((const stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength(); + char* pTxts = new char[stTxtLength]; + if (pTxts) + { + ((/*const c_str()!!*/stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts); + DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); + delete[] pTxts; + } + break; + } +#ifdef MDNS_IP6_SUPPORT + case DNS_RRTYPE_AAAA: + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_SRV: + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_u16Port); + _printRRDomain(((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_SRVDomain); + break; + default: + DEBUG_OUTPUT.printf_P(PSTR("generic ")); + break; + } + DEBUG_OUTPUT.printf_P(PSTR("\n")); + + return true; +} +#endif + +} // namespace MDNSImplementation + +} // namespace esp8266 + + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h b/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h new file mode 100644 index 0000000000..4750669d38 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h @@ -0,0 +1,182 @@ +/* + LEAmDNS_Priv.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef MDNS_PRIV_H +#define MDNS_PRIV_H + +namespace esp8266 +{ + +/* + LEAmDNS +*/ + +namespace MDNSImplementation +{ + +// Enable class debug functions +#define ESP_8266_MDNS_INCLUDE +//#define DEBUG_ESP_MDNS_RESPONDER + +#if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS) +#define DEBUG_ESP_MDNS_RESPONDER +#endif + +#ifndef LWIP_OPEN_SRC +#define LWIP_OPEN_SRC +#endif + +// +// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing +// This allows to drive the responder in a environment, where 'update()' isn't called in the loop +//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE + +// Enable/disable debug trace macros +#if defined(DEBUG_ESP_PORT) && defined(DEBUG_ESP_MDNS_RESPONDER) +#define DEBUG_ESP_MDNS_INFO +#define DEBUG_ESP_MDNS_ERR +#define DEBUG_ESP_MDNS_TX +#define DEBUG_ESP_MDNS_RX +#endif + +#ifdef DEBUG_ESP_MDNS_RESPONDER +#ifdef DEBUG_ESP_MDNS_INFO +#define DEBUG_EX_INFO(A) A +#else +#define DEBUG_EX_INFO(A) +#endif +#ifdef DEBUG_ESP_MDNS_ERR +#define DEBUG_EX_ERR(A) A +#else +#define DEBUG_EX_ERR(A) +#endif +#ifdef DEBUG_ESP_MDNS_TX +#define DEBUG_EX_TX(A) A +#else +#define DEBUG_EX_TX(A) +#endif +#ifdef DEBUG_ESP_MDNS_RX +#define DEBUG_EX_RX(A) A +#else +#define DEBUG_EX_RX(A) +#endif + +#ifdef DEBUG_ESP_PORT +#define DEBUG_OUTPUT DEBUG_ESP_PORT +#else +#define DEBUG_OUTPUT Serial +#endif +#else +#define DEBUG_EX_INFO(A) do { (void)0; } while (0) +#define DEBUG_EX_ERR(A) do { (void)0; } while (0) +#define DEBUG_EX_TX(A) do { (void)0; } while (0) +#define DEBUG_EX_RX(A) do { (void)0; } while (0) +#endif + + +/* Replaced by 'lwip/prot/dns.h' definitions + #ifdef MDNS_IP4_SUPPORT + #define MDNS_MULTICAST_ADDR_IP4 (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT + #endif + #ifdef MDNS_IP6_SUPPORT + #define MDNS_MULTICAST_ADDR_IP6 (IPAddress("FF02::FB")) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT + #endif*/ +//#define MDNS_MULTICAST_PORT 5353 + +/* + This is NOT the TTL (Time-To-Live) for MDNS records, but the + subnet level distance MDNS records should travel. + 1 sets the subnet distance to 'local', which is default for MDNS. + (Btw.: 255 would set it to 'as far as possible' -> internet) + + However, RFC 3171 seems to force 255 instead +*/ +#define MDNS_MULTICAST_TTL 255/*1*/ + +/* + This is the MDNS record TTL + Host level records are set to 2min (120s) + service level records are set to 75min (4500s) +*/ +#define MDNS_HOST_TTL 120 +#define MDNS_SERVICE_TTL 4500 + +/* + Compressed labels are flaged by the two topmost bits of the length byte being set +*/ +#define MDNS_DOMAIN_COMPRESS_MARK 0xC0 +/* + Avoid endless recursion because of malformed compressed labels +*/ +#define MDNS_DOMAIN_MAX_REDIRCTION 6 + +/* + Default service priority and weight in SRV answers +*/ +#define MDNS_SRV_PRIORITY 0 +#define MDNS_SRV_WEIGHT 0 + +/* + Delay between and number of probes for host and service domains + Delay between and number of announces for host and service domains + Delay between and number of service queries; the delay is multiplied by the resent number in '_checkServiceQueryCache' +*/ +#define MDNS_PROBE_DELAY 250 +#define MDNS_PROBE_COUNT 3 +#define MDNS_ANNOUNCE_DELAY 1000 +#define MDNS_ANNOUNCE_COUNT 8 +#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5 +#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000 + + +/* + Force host domain to use only lowercase letters +*/ +//#define MDNS_FORCE_LOWERCASE_HOSTNAME + +/* + Enable/disable the usage of the F() macro in debug trace printf calls. + There needs to be an PGM comptible printf function to use this. + + USE_PGM_PRINTF and F +*/ +#define USE_PGM_PRINTF + +#ifdef USE_PGM_PRINTF +#else +#ifdef F +#undef F +#endif +#define F(A) A +#endif + +} // namespace MDNSImplementation + +} // namespace esp8266 + +// Include the main header, so the submodlues only need to include this header +#include "LEAmDNS.h" + + +#endif // MDNS_PRIV_H diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp new file mode 100644 index 0000000000..18c4a95eb3 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp @@ -0,0 +1,2477 @@ +/* + LEAmDNS_Structs.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "ESP8266mDNS.h" +#include "LEAmDNS_Priv.h" +#include "LEAmDNS_lwIPdefs.h" + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + STRUCTS +*/ + +/** + MDNSResponder::stcMDNSServiceTxt + + One MDNS TXT item. + m_pcValue may be '\0'. + Objects can be chained together (list, m_pNext). + A 'm_bTemp' flag differentiates between static and dynamic items. + Output as byte array 'c#=1' is supported. +*/ + +/* + MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt constructor +*/ +MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const char* p_pcKey /*= 0*/, + const char* p_pcValue /*= 0*/, + bool p_bTemp /*= false*/) + : m_pNext(0), + m_pcKey(0), + m_pcValue(0), + m_bTemp(p_bTemp) +{ + + setKey(p_pcKey); + setValue(p_pcValue); +} + +/* + MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt copy-constructor +*/ +MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const MDNSResponder::stcMDNSServiceTxt& p_Other) + : m_pNext(0), + m_pcKey(0), + m_pcValue(0), + m_bTemp(false) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt destructor +*/ +MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceTxt::operator= +*/ +MDNSResponder::stcMDNSServiceTxt& MDNSResponder::stcMDNSServiceTxt::operator=(const MDNSResponder::stcMDNSServiceTxt& p_Other) +{ + + if (&p_Other != this) + { + clear(); + set(p_Other.m_pcKey, p_Other.m_pcValue, p_Other.m_bTemp); + } + return *this; +} + +/* + MDNSResponder::stcMDNSServiceTxt::clear +*/ +bool MDNSResponder::stcMDNSServiceTxt::clear(void) +{ + + releaseKey(); + releaseValue(); + return true; +} + +/* + MDNSResponder::stcMDNSServiceTxt::allocKey +*/ +char* MDNSResponder::stcMDNSServiceTxt::allocKey(size_t p_stLength) +{ + + releaseKey(); + if (p_stLength) + { + m_pcKey = new char[p_stLength + 1]; + } + return m_pcKey; +} + +/* + MDNSResponder::stcMDNSServiceTxt::setKey +*/ +bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey, + size_t p_stLength) +{ + + bool bResult = false; + + releaseKey(); + if (p_stLength) + { + if (allocKey(p_stLength)) + { + strncpy(m_pcKey, p_pcKey, p_stLength); + m_pcKey[p_stLength] = 0; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxt::setKey +*/ +bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey) +{ + + return setKey(p_pcKey, (p_pcKey ? strlen(p_pcKey) : 0)); +} + +/* + MDNSResponder::stcMDNSServiceTxt::releaseKey +*/ +bool MDNSResponder::stcMDNSServiceTxt::releaseKey(void) +{ + + if (m_pcKey) + { + delete[] m_pcKey; + m_pcKey = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceTxt::allocValue +*/ +char* MDNSResponder::stcMDNSServiceTxt::allocValue(size_t p_stLength) +{ + + releaseValue(); + if (p_stLength) + { + m_pcValue = new char[p_stLength + 1]; + } + return m_pcValue; +} + +/* + MDNSResponder::stcMDNSServiceTxt::setValue +*/ +bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue, + size_t p_stLength) +{ + + bool bResult = false; + + releaseValue(); + if (p_stLength) + { + if (allocValue(p_stLength)) + { + strncpy(m_pcValue, p_pcValue, p_stLength); + m_pcValue[p_stLength] = 0; + bResult = true; + } + } + else // No value -> also OK + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxt::setValue +*/ +bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue) +{ + + return setValue(p_pcValue, (p_pcValue ? strlen(p_pcValue) : 0)); +} + +/* + MDNSResponder::stcMDNSServiceTxt::releaseValue +*/ +bool MDNSResponder::stcMDNSServiceTxt::releaseValue(void) +{ + + if (m_pcValue) + { + delete[] m_pcValue; + m_pcValue = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceTxt::set +*/ +bool MDNSResponder::stcMDNSServiceTxt::set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp /*= false*/) +{ + + m_bTemp = p_bTemp; + return ((setKey(p_pcKey)) && + (setValue(p_pcValue))); +} + +/* + MDNSResponder::stcMDNSServiceTxt::update +*/ +bool MDNSResponder::stcMDNSServiceTxt::update(const char* p_pcValue) +{ + + return setValue(p_pcValue); +} + +/* + MDNSResponder::stcMDNSServiceTxt::length + + length of eg. 'c#=1' without any closing '\0' +*/ +size_t MDNSResponder::stcMDNSServiceTxt::length(void) const +{ + + size_t stLength = 0; + if (m_pcKey) + { + stLength += strlen(m_pcKey); // Key + stLength += 1; // '=' + stLength += (m_pcValue ? strlen(m_pcValue) : 0); // Value + } + return stLength; +} + + +/** + MDNSResponder::stcMDNSServiceTxts + + A list of zero or more MDNS TXT items. + Dynamic TXT items can be removed by 'removeTempTxts'. + A TXT item can be looke up by its 'key' member. + Export as ';'-separated byte array is supported. + Export as 'length byte coded' byte array is supported. + Comparision ((all A TXT items in B and equal) AND (all B TXT items in A and equal)) is supported. + +*/ + +/* + MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts contructor +*/ +MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(void) + : m_pTxts(0) +{ + +} + +/* + MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts copy-constructor +*/ +MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other) + : m_pTxts(0) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts destructor +*/ +MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceTxts::operator= +*/ +MDNSResponder::stcMDNSServiceTxts& MDNSResponder::stcMDNSServiceTxts::operator=(const stcMDNSServiceTxts& p_Other) +{ + + if (this != &p_Other) + { + clear(); + + for (stcMDNSServiceTxt* pOtherTxt = p_Other.m_pTxts; pOtherTxt; pOtherTxt = pOtherTxt->m_pNext) + { + add(new stcMDNSServiceTxt(*pOtherTxt)); + } + } + return *this; +} + +/* + MDNSResponder::stcMDNSServiceTxts::clear +*/ +bool MDNSResponder::stcMDNSServiceTxts::clear(void) +{ + + while (m_pTxts) + { + stcMDNSServiceTxt* pNext = m_pTxts->m_pNext; + delete m_pTxts; + m_pTxts = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceTxts::add +*/ +bool MDNSResponder::stcMDNSServiceTxts::add(MDNSResponder::stcMDNSServiceTxt* p_pTxt) +{ + + bool bResult = false; + + if (p_pTxt) + { + p_pTxt->m_pNext = m_pTxts; + m_pTxts = p_pTxt; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::remove +*/ +bool MDNSResponder::stcMDNSServiceTxts::remove(stcMDNSServiceTxt* p_pTxt) +{ + + bool bResult = false; + + if (p_pTxt) + { + stcMDNSServiceTxt* pPred = m_pTxts; + while ((pPred) && + (pPred->m_pNext != p_pTxt)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pTxt->m_pNext; + delete p_pTxt; + bResult = true; + } + else if (m_pTxts == p_pTxt) // No predecesor, but first item + { + m_pTxts = p_pTxt->m_pNext; + delete p_pTxt; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::removeTempTxts +*/ +bool MDNSResponder::stcMDNSServiceTxts::removeTempTxts(void) +{ + + bool bResult = true; + + stcMDNSServiceTxt* pTxt = m_pTxts; + while ((bResult) && + (pTxt)) + { + stcMDNSServiceTxt* pNext = pTxt->m_pNext; + if (pTxt->m_bTemp) + { + bResult = remove(pTxt); + } + pTxt = pNext; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::find +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) +{ + + stcMDNSServiceTxt* pResult = 0; + + for (stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::find +*/ +const MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) const +{ + + const stcMDNSServiceTxt* pResult = 0; + + for (const stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::find +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const stcMDNSServiceTxt* p_pTxt) +{ + + stcMDNSServiceTxt* pResult = 0; + + for (stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if (p_pTxt == pTxt) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::length +*/ +uint16_t MDNSResponder::stcMDNSServiceTxts::length(void) const +{ + + uint16_t u16Length = 0; + + stcMDNSServiceTxt* pTxt = m_pTxts; + while (pTxt) + { + u16Length += 1; // Length byte + u16Length += pTxt->length(); // Text + pTxt = pTxt->m_pNext; + } + return u16Length; +} + +/* + MDNSResponder::stcMDNSServiceTxts::c_strLength + + (incl. closing '\0'). Length bytes place is used for delimiting ';' and closing '\0' +*/ +size_t MDNSResponder::stcMDNSServiceTxts::c_strLength(void) const +{ + + return length(); +} + +/* + MDNSResponder::stcMDNSServiceTxts::c_str +*/ +bool MDNSResponder::stcMDNSServiceTxts::c_str(char* p_pcBuffer) +{ + + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + *p_pcBuffer = 0; + for (stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + if (pTxt != m_pTxts) + { + *p_pcBuffer++ = ';'; + } + strncpy(p_pcBuffer, pTxt->m_pcKey, stLength); p_pcBuffer[stLength] = 0; + p_pcBuffer += stLength; + *p_pcBuffer++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + strncpy(p_pcBuffer, pTxt->m_pcValue, stLength); p_pcBuffer[stLength] = 0; + p_pcBuffer += stLength; + } + } + } + *p_pcBuffer++ = 0; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::bufferLength + + (incl. closing '\0'). +*/ +size_t MDNSResponder::stcMDNSServiceTxts::bufferLength(void) const +{ + + return (length() + 1); +} + +/* + MDNSResponder::stcMDNSServiceTxts::toBuffer +*/ +bool MDNSResponder::stcMDNSServiceTxts::buffer(char* p_pcBuffer) +{ + + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + *p_pcBuffer = 0; + for (stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + *(unsigned char*)p_pcBuffer++ = pTxt->length(); + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + memcpy(p_pcBuffer, pTxt->m_pcKey, stLength); + p_pcBuffer += stLength; + *p_pcBuffer++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + memcpy(p_pcBuffer, pTxt->m_pcValue, stLength); + p_pcBuffer += stLength; + } + } + } + *p_pcBuffer++ = 0; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::compare +*/ +bool MDNSResponder::stcMDNSServiceTxts::compare(const MDNSResponder::stcMDNSServiceTxts& p_Other) const +{ + + bool bResult = false; + + if ((bResult = (length() == p_Other.length()))) + { + // Compare A->B + for (const stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + const stcMDNSServiceTxt* pOtherTxt = p_Other.find(pTxt->m_pcKey); + bResult = ((pOtherTxt) && + (pTxt->m_pcValue) && + (pOtherTxt->m_pcValue) && + (strlen(pTxt->m_pcValue) == strlen(pOtherTxt->m_pcValue)) && + (0 == strcmp(pTxt->m_pcValue, pOtherTxt->m_pcValue))); + } + // Compare B->A + for (const stcMDNSServiceTxt* pOtherTxt = p_Other.m_pTxts; ((bResult) && (pOtherTxt)); pOtherTxt = pOtherTxt->m_pNext) + { + const stcMDNSServiceTxt* pTxt = find(pOtherTxt->m_pcKey); + bResult = ((pTxt) && + (pOtherTxt->m_pcValue) && + (pTxt->m_pcValue) && + (strlen(pOtherTxt->m_pcValue) == strlen(pTxt->m_pcValue)) && + (0 == strcmp(pOtherTxt->m_pcValue, pTxt->m_pcValue))); + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::operator== +*/ +bool MDNSResponder::stcMDNSServiceTxts::operator==(const stcMDNSServiceTxts& p_Other) const +{ + + return compare(p_Other); +} + +/* + MDNSResponder::stcMDNSServiceTxts::operator!= +*/ +bool MDNSResponder::stcMDNSServiceTxts::operator!=(const stcMDNSServiceTxts& p_Other) const +{ + + return !compare(p_Other); +} + + +/** + MDNSResponder::stcMDNS_MsgHeader + + A MDNS message haeder. + +*/ + +/* + MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader +*/ +MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader(uint16_t p_u16ID /*= 0*/, + bool p_bQR /*= false*/, + unsigned char p_ucOpcode /*= 0*/, + bool p_bAA /*= false*/, + bool p_bTC /*= false*/, + bool p_bRD /*= false*/, + bool p_bRA /*= false*/, + unsigned char p_ucRCode /*= 0*/, + uint16_t p_u16QDCount /*= 0*/, + uint16_t p_u16ANCount /*= 0*/, + uint16_t p_u16NSCount /*= 0*/, + uint16_t p_u16ARCount /*= 0*/) + : m_u16ID(p_u16ID), + m_1bQR(p_bQR), m_4bOpcode(p_ucOpcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), + m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_ucRCode), + m_u16QDCount(p_u16QDCount), + m_u16ANCount(p_u16ANCount), + m_u16NSCount(p_u16NSCount), + m_u16ARCount(p_u16ARCount) +{ + +} + + +/** + MDNSResponder::stcMDNS_RRDomain + + A MDNS domain object. + The labels of the domain are stored (DNS-like encoded) in 'm_acName': + [length byte]varlength label[length byte]varlength label[0] + 'm_u16NameLength' stores the used length of 'm_acName'. + Dynamic label addition is supported. + Comparison is supported. + Export as byte array 'esp8266.local' is supported. + +*/ + +/* + MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain constructor +*/ +MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(void) + : m_u16NameLength(0) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain copy-constructor +*/ +MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other) + : m_u16NameLength(0) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRDomain::operator = +*/ +MDNSResponder::stcMDNS_RRDomain& MDNSResponder::stcMDNS_RRDomain::operator=(const stcMDNS_RRDomain& p_Other) +{ + + if (&p_Other != this) + { + memcpy(m_acName, p_Other.m_acName, sizeof(m_acName)); + m_u16NameLength = p_Other.m_u16NameLength; + } + return *this; +} + +/* + MDNSResponder::stcMDNS_RRDomain::clear +*/ +bool MDNSResponder::stcMDNS_RRDomain::clear(void) +{ + + memset(m_acName, 0, sizeof(m_acName)); + m_u16NameLength = 0; + return true; +} + +/* + MDNSResponder::stcMDNS_RRDomain::addLabel +*/ +bool MDNSResponder::stcMDNS_RRDomain::addLabel(const char* p_pcLabel, + bool p_bPrependUnderline /*= false*/) +{ + + bool bResult = false; + + size_t stLength = (p_pcLabel + ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) + : 0); + if ((MDNS_DOMAIN_LABEL_MAXLENGTH >= stLength) && + (MDNS_DOMAIN_MAXLENGTH >= (m_u16NameLength + (1 + stLength)))) + { + // Length byte + m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! + ++m_u16NameLength; + // Label + if (stLength) + { + if (p_bPrependUnderline) + { + m_acName[m_u16NameLength++] = '_'; + --stLength; + } + strncpy(&(m_acName[m_u16NameLength]), p_pcLabel, stLength); m_acName[m_u16NameLength + stLength] = 0; + m_u16NameLength += stLength; + } + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNS_RRDomain::compare +*/ +bool MDNSResponder::stcMDNS_RRDomain::compare(const stcMDNS_RRDomain& p_Other) const +{ + + bool bResult = false; + + if (m_u16NameLength == p_Other.m_u16NameLength) + { + const char* pT = m_acName; + const char* pO = p_Other.m_acName; + while ((pT) && + (pO) && + (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND + (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content + { + if (*((unsigned char*)pT)) // Not 0 + { + pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and lenght + pO += (1 + * ((unsigned char*)pO)); + } + else // Is 0 -> Successfully reached the end + { + bResult = true; + break; + } + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNS_RRDomain::operator == +*/ +bool MDNSResponder::stcMDNS_RRDomain::operator==(const stcMDNS_RRDomain& p_Other) const +{ + + return compare(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRDomain::operator != +*/ +bool MDNSResponder::stcMDNS_RRDomain::operator!=(const stcMDNS_RRDomain& p_Other) const +{ + + return !compare(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRDomain::operator > +*/ +bool MDNSResponder::stcMDNS_RRDomain::operator>(const stcMDNS_RRDomain& p_Other) const +{ + + // TODO: Check, if this is a good idea... + return !compare(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRDomain::c_strLength +*/ +size_t MDNSResponder::stcMDNS_RRDomain::c_strLength(void) const +{ + + size_t stLength = 0; + + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + stLength += (*pucLabelLength + 1 /* +1 for '.' or '\0'*/); + pucLabelLength += (*pucLabelLength + 1); + } + return stLength; +} + +/* + MDNSResponder::stcMDNS_RRDomain::c_str +*/ +bool MDNSResponder::stcMDNS_RRDomain::c_str(char* p_pcBuffer) +{ + + bool bResult = false; + + if (p_pcBuffer) + { + *p_pcBuffer = 0; + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + memcpy(p_pcBuffer, (const char*)(pucLabelLength + 1), *pucLabelLength); + p_pcBuffer += *pucLabelLength; + pucLabelLength += (*pucLabelLength + 1); + *p_pcBuffer++ = (*pucLabelLength ? '.' : '\0'); + } + bResult = true; + } + return bResult; +} + + +/** + MDNSResponder::stcMDNS_RRAttributes + + A MDNS attributes object. + +*/ + +/* + MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes constructor +*/ +MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(uint16_t p_u16Type /*= 0*/, + uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) + : m_u16Type(p_u16Type), + m_u16Class(p_u16Class) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes copy-constructor +*/ +MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Other) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRAttributes::operator = +*/ +MDNSResponder::stcMDNS_RRAttributes& MDNSResponder::stcMDNS_RRAttributes::operator=(const MDNSResponder::stcMDNS_RRAttributes& p_Other) +{ + + if (&p_Other != this) + { + m_u16Type = p_Other.m_u16Type; + m_u16Class = p_Other.m_u16Class; + } + return *this; +} + + +/** + MDNSResponder::stcMDNS_RRHeader + + A MDNS record header (domain and attributes) object. + +*/ + +/* + MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader constructor +*/ +MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(void) +{ + +} + +/* + MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader copy-constructor +*/ +MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRHeader::operator = +*/ +MDNSResponder::stcMDNS_RRHeader& MDNSResponder::stcMDNS_RRHeader::operator=(const MDNSResponder::stcMDNS_RRHeader& p_Other) +{ + + if (&p_Other != this) + { + m_Domain = p_Other.m_Domain; + m_Attributes = p_Other.m_Attributes; + } + return *this; +} + +/* + MDNSResponder::stcMDNS_RRHeader::clear +*/ +bool MDNSResponder::stcMDNS_RRHeader::clear(void) +{ + + m_Domain.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRQuestion + + A MDNS question record object (header + question flags) + +*/ + +/* + MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion constructor +*/ +MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion(void) + : m_pNext(0), + m_bUnicast(false) +{ + +} + + +/** + MDNSResponder::stcMDNS_RRAnswer + + A MDNS answer record object (header + answer content). + This is a 'virtual' base class for all other MDNS answer classes. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer constructor +*/ +MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer(enuAnswerType p_AnswerType, + const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : m_pNext(0), + m_AnswerType(p_AnswerType), + m_Header(p_Header), + m_u32TTL(p_u32TTL) +{ + + // Extract 'cache flush'-bit + m_bCacheFlush = (m_Header.m_Attributes.m_u16Class & 0x8000); + m_Header.m_Attributes.m_u16Class &= (~0x8000); +} + +/* + MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer destructor +*/ +MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer(void) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswer::answerType +*/ +MDNSResponder::enuAnswerType MDNSResponder::stcMDNS_RRAnswer::answerType(void) const +{ + + return m_AnswerType; +} + +/* + MDNSResponder::stcMDNS_RRAnswer::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswer::clear(void) +{ + + m_pNext = 0; + m_Header.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRAnswerA + + A MDNS A answer object. + Extends the base class by an IP4 address member. + +*/ + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA constructor +*/ +MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_A, p_Header, p_u32TTL), + m_IPAddress(0, 0, 0, 0) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA destructor +*/ +MDNSResponder::stcMDNS_RRAnswerA::~stcMDNS_RRAnswerA(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerA::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerA::clear(void) +{ + + m_IPAddress = IPAddress(0, 0, 0, 0); + return true; +} +#endif + + +/** + MDNSResponder::stcMDNS_RRAnswerPTR + + A MDNS PTR answer object. + Extends the base class by a MDNS domain member. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR constructor +*/ +MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_PTR, p_Header, p_u32TTL) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR destructor +*/ +MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerPTR::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerPTR::clear(void) +{ + + m_PTRDomain.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRAnswerTXT + + A MDNS TXT answer object. + Extends the base class by a MDNS TXT items list member. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT constructor +*/ +MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_TXT, p_Header, p_u32TTL) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT destructor +*/ +MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerTXT::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerTXT::clear(void) +{ + + m_Txts.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRAnswerAAAA + + A MDNS AAAA answer object. + (Should) extend the base class by an IP6 address member. + +*/ + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA constructor +*/ +MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_AAAA, p_Header, p_u32TTL) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA destructor +*/ +MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerAAAA::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerAAAA::clear(void) +{ + + return true; +} +#endif + + +/** + MDNSResponder::stcMDNS_RRAnswerSRV + + A MDNS SRV answer object. + Extends the base class by a port member. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV constructor +*/ +MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_SRV, p_Header, p_u32TTL), + m_u16Priority(0), + m_u16Weight(0), + m_u16Port(0) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV destructor +*/ +MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerSRV::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerSRV::clear(void) +{ + + m_u16Priority = 0; + m_u16Weight = 0; + m_u16Port = 0; + m_SRVDomain.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRAnswerGeneric + + An unknown (generic) MDNS answer object. + Extends the base class by a RDATA buffer member. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric constructor +*/ +MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_Generic, p_Header, p_u32TTL), + m_u16RDLength(0), + m_pu8RDData(0) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric destructor +*/ +MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerGeneric::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerGeneric::clear(void) +{ + + if (m_pu8RDData) + { + delete[] m_pu8RDData; + m_pu8RDData = 0; + } + m_u16RDLength = 0; + + return true; +} + + +/** + MDNSResponder::stcProbeInformation + + Probing status information for a host or service domain + +*/ + +/* + MDNSResponder::stcProbeInformation::stcProbeInformation constructor +*/ +MDNSResponder::stcProbeInformation::stcProbeInformation(void) + : m_ProbingStatus(ProbingStatus_WaitingForData), + m_u8SentCount(0), + m_Timeout(esp8266::polledTimeout::oneShotMs::neverExpires), + m_bConflict(false), + m_bTiebreakNeeded(false), + m_fnHostProbeResultCallback(0), + m_fnServiceProbeResultCallback(0) +{ +} + +/* + MDNSResponder::stcProbeInformation::clear +*/ +bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/) +{ + + m_ProbingStatus = ProbingStatus_WaitingForData; + m_u8SentCount = 0; + m_Timeout.resetToNeverExpires(); + m_bConflict = false; + m_bTiebreakNeeded = false; + if (p_bClearUserdata) + { + m_fnHostProbeResultCallback = 0; + m_fnServiceProbeResultCallback = 0; + } + return true; +} + +/** + MDNSResponder::stcMDNSService + + A MDNS service object (to be announced by the MDNS responder) + The service instance may be '\0'; in this case the hostname is used + and the flag m_bAutoName is set. If the hostname changes, all 'auto- + named' services are renamed also. + m_u8Replymask is used while preparing a response to a MDNS query. It is + resetted in '_sendMDNSMessage' afterwards. +*/ + +/* + MDNSResponder::stcMDNSService::stcMDNSService constructor +*/ +MDNSResponder::stcMDNSService::stcMDNSService(const char* p_pcName /*= 0*/, + const char* p_pcService /*= 0*/, + const char* p_pcProtocol /*= 0*/) + : m_pNext(0), + m_pcName(0), + m_bAutoName(false), + m_pcService(0), + m_pcProtocol(0), + m_u16Port(0), + m_u8ReplyMask(0), + m_fnTxtCallback(0) +{ + + setName(p_pcName); + setService(p_pcService); + setProtocol(p_pcProtocol); +} + +/* + MDNSResponder::stcMDNSService::~stcMDNSService destructor +*/ +MDNSResponder::stcMDNSService::~stcMDNSService(void) +{ + + releaseName(); + releaseService(); + releaseProtocol(); +} + +/* + MDNSResponder::stcMDNSService::setName +*/ +bool MDNSResponder::stcMDNSService::setName(const char* p_pcName) +{ + + bool bResult = false; + + releaseName(); + size_t stLength = (p_pcName ? strlen(p_pcName) : 0); + if (stLength) + { + if ((bResult = (0 != (m_pcName = new char[stLength + 1])))) + { + strncpy(m_pcName, p_pcName, stLength); + m_pcName[stLength] = 0; + } + } + else + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSService::releaseName +*/ +bool MDNSResponder::stcMDNSService::releaseName(void) +{ + + if (m_pcName) + { + delete[] m_pcName; + m_pcName = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSService::setService +*/ +bool MDNSResponder::stcMDNSService::setService(const char* p_pcService) +{ + + bool bResult = false; + + releaseService(); + size_t stLength = (p_pcService ? strlen(p_pcService) : 0); + if (stLength) + { + if ((bResult = (0 != (m_pcService = new char[stLength + 1])))) + { + strncpy(m_pcService, p_pcService, stLength); + m_pcService[stLength] = 0; + } + } + else + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSService::releaseService +*/ +bool MDNSResponder::stcMDNSService::releaseService(void) +{ + + if (m_pcService) + { + delete[] m_pcService; + m_pcService = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSService::setProtocol +*/ +bool MDNSResponder::stcMDNSService::setProtocol(const char* p_pcProtocol) +{ + + bool bResult = false; + + releaseProtocol(); + size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); + if (stLength) + { + if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) + { + strncpy(m_pcProtocol, p_pcProtocol, stLength); + m_pcProtocol[stLength] = 0; + } + } + else + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSService::releaseProtocol +*/ +bool MDNSResponder::stcMDNSService::releaseProtocol(void) +{ + + if (m_pcProtocol) + { + delete[] m_pcProtocol; + m_pcProtocol = 0; + } + return true; +} + + +/** + MDNSResponder::stcMDNSServiceQuery + + A MDNS service query object. + Service queries may be static or dynamic. + As the static service query is processed in the blocking function 'queryService', + only one static service service may exist. The processing of the answers is done + on the WiFi-stack side of the ESP stack structure (via 'UDPContext.onRx(_update)'). + +*/ + +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer + + One answer for a service query. + Every answer must contain + - a service instance entry (pivot), + and may contain + - a host domain, + - a port + - an IP4 address + (- an IP6 address) + - a MDNS TXTs + The existance of a component is flaged in 'm_u32ContentFlags'. + For every answer component a TTL value is maintained. + Answer objects can be connected to a linked list. + + For the host domain, service domain and TXTs components, a char array + representation can be retrieved (which is created on demand). + +*/ + +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL + + The TTL (Time-To-Live) for an specific answer content. + The 80% and outdated states are calculated based on the current time (millis) + and the 'set' time (also millis). + If the answer is scheduled for an update, the corresponding flag should be set. + + / + + / * + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor + / + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(uint32_t p_u32TTL / *= 0* /) + : m_bUpdateScheduled(false) { + + set(p_u32TTL * 1000); + } + + / * + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set + / + bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) { + + m_TTLTimeFlag.restart(p_u32TTL * 1000); + m_bUpdateScheduled = false; + + return true; + } + + / * + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent + / + bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent(void) const { + + return ((m_TTLTimeFlag.getTimeout()) && + (!m_bUpdateScheduled) && + (m_TTLTimeFlag.hypotheticalTimeout((m_TTLTimeFlag.getTimeout() * 800) / 1000))); + } + + / * + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated + / + bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated(void) const { + + return ((m_TTLTimeFlag.getTimeout()) && + (m_TTLTimeFlag.flagged())); + }*/ + + +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL + + The TTL (Time-To-Live) for an specific answer content. + The 80% and outdated states are calculated based on the current time (millis) + and the 'set' time (also millis). + If the answer is scheduled for an update, the corresponding flag should be set. + +*/ + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(void) + : m_u32TTL(0), + m_TTLTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), + m_timeoutLevel(TIMEOUTLEVEL_UNSET) +{ + +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) +{ + + m_u32TTL = p_u32TTL; + if (m_u32TTL) + { + m_timeoutLevel = TIMEOUTLEVEL_BASE; // Set to 80% + m_TTLTimeout.reset(timeout()); + } + else + { + m_timeoutLevel = TIMEOUTLEVEL_UNSET; // undef + m_TTLTimeout.resetToNeverExpires(); + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) +{ + + return ((m_u32TTL) && + (TIMEOUTLEVEL_UNSET != m_timeoutLevel) && + (m_TTLTimeout.expired())); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart(void) +{ + + bool bResult = true; + + if ((TIMEOUTLEVEL_BASE <= m_timeoutLevel) && // >= 80% AND + (TIMEOUTLEVEL_FINAL > m_timeoutLevel)) // < 100% + { + + m_timeoutLevel += TIMEOUTLEVEL_INTERVAL; // increment by 5% + m_TTLTimeout.reset(timeout()); + } + else + { + bResult = false; + m_TTLTimeout.resetToNeverExpires(); + m_timeoutLevel = TIMEOUTLEVEL_UNSET; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion(void) +{ + + m_timeoutLevel = TIMEOUTLEVEL_FINAL; + m_TTLTimeout.reset(1 * 1000); // See RFC 6762, 10.1 + + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel(void) const +{ + + return (TIMEOUTLEVEL_FINAL == m_timeoutLevel); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout +*/ +unsigned long MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout(void) const +{ + + uint32_t u32Timeout = esp8266::polledTimeout::oneShotMs::neverExpires; + + if (TIMEOUTLEVEL_BASE == m_timeoutLevel) // 80% + { + u32Timeout = (m_u32TTL * 800); // to milliseconds + } + else if ((TIMEOUTLEVEL_BASE < m_timeoutLevel) && // >80% AND + (TIMEOUTLEVEL_FINAL >= m_timeoutLevel)) // <= 100% + { + + u32Timeout = (m_u32TTL * 50); + } // else: invalid + return u32Timeout; +} + + +#ifdef MDNS_IP4_SUPPORT +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address + +*/ + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address constructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address(IPAddress p_IPAddress, + uint32_t p_u32TTL /*= 0*/) + : m_pNext(0), + m_IPAddress(p_IPAddress) +{ + + m_TTL.set(p_u32TTL); +} +#endif + + +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer +*/ + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer constructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer(void) + : m_pNext(0), + m_pcServiceDomain(0), + m_pcHostDomain(0), + m_u16Port(0), + m_pcTxts(0), +#ifdef MDNS_IP4_SUPPORT + m_pIP4Addresses(0), +#endif +#ifdef MDNS_IP6_SUPPORT + m_pIP6Addresses(0), +#endif + m_u32ContentFlags(0) +{ +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer destructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear(void) +{ + + return ((releaseTxts()) && +#ifdef MDNS_IP4_SUPPORT + (releaseIP4Addresses()) && +#endif +#ifdef MDNS_IP6_SUPPORT + (releaseIP6Addresses()) +#endif + (releaseHostDomain()) && + (releaseServiceDomain())); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain + + Alloc memory for the char array representation of the service domain. + +*/ +char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain(size_t p_stLength) +{ + + releaseServiceDomain(); + if (p_stLength) + { + m_pcServiceDomain = new char[p_stLength]; + } + return m_pcServiceDomain; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain(void) +{ + + if (m_pcServiceDomain) + { + delete[] m_pcServiceDomain; + m_pcServiceDomain = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain + + Alloc memory for the char array representation of the host domain. + +*/ +char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain(size_t p_stLength) +{ + + releaseHostDomain(); + if (p_stLength) + { + m_pcHostDomain = new char[p_stLength]; + } + return m_pcHostDomain; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain(void) +{ + + if (m_pcHostDomain) + { + delete[] m_pcHostDomain; + m_pcHostDomain = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts + + Alloc memory for the char array representation of the TXT items. + +*/ +char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts(size_t p_stLength) +{ + + releaseTxts(); + if (p_stLength) + { + m_pcTxts = new char[p_stLength]; + } + return m_pcTxts; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts(void) +{ + + if (m_pcTxts) + { + delete[] m_pcTxts; + m_pcTxts = 0; + } + return true; +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses(void) +{ + + while (m_pIP4Addresses) + { + stcIP4Address* pNext = m_pIP4Addresses->m_pNext; + delete m_pIP4Addresses; + m_pIP4Addresses = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) +{ + + bool bResult = false; + + if (p_pIP4Address) + { + p_pIP4Address->m_pNext = m_pIP4Addresses; + m_pIP4Addresses = p_pIP4Address; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) +{ + + bool bResult = false; + + if (p_pIP4Address) + { + stcIP4Address* pPred = m_pIP4Addresses; + while ((pPred) && + (pPred->m_pNext != p_pIP4Address)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pIP4Address->m_pNext; + delete p_pIP4Address; + bResult = true; + } + else if (m_pIP4Addresses == p_pIP4Address) // No predecesor, but first item + { + m_pIP4Addresses = p_pIP4Address->m_pNext; + delete p_pIP4Address; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address (const) +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) const +{ + + return (stcIP4Address*)(((const stcAnswer*)this)->findIP4Address(p_IPAddress)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) +{ + + stcIP4Address* pIP4Address = m_pIP4Addresses; + while (pIP4Address) + { + if (pIP4Address->m_IPAddress == p_IPAddress) + { + break; + } + pIP4Address = pIP4Address->m_pNext; + } + return pIP4Address; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount +*/ +uint32_t MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount(void) const +{ + + uint32_t u32Count = 0; + + stcIP4Address* pIP4Address = m_pIP4Addresses; + while (pIP4Address) + { + ++u32Count; + pIP4Address = pIP4Address->m_pNext; + } + return u32Count; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) +{ + + return (stcIP4Address*)(((const stcAnswer*)this)->IP4AddressAtIndex(p_u32Index)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex (const) +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) const +{ + + const stcIP4Address* pIP4Address = 0; + + if (((uint32_t)(-1) != p_u32Index) && + (m_pIP4Addresses)) + { + + uint32_t u32Index; + for (pIP4Address = m_pIP4Addresses, u32Index = 0; ((pIP4Address) && (u32Index < p_u32Index)); pIP4Address = pIP4Address->m_pNext, ++u32Index); + } + return pIP4Address; +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP6Addresses +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP6Addresses(void) +{ + + while (m_pIP6Addresses) + { + stcIP6Address* pNext = m_pIP6Addresses->m_pNext; + delete m_pIP6Addresses; + m_pIP6Addresses = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP6Address +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP6Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* p_pIP6Address) +{ + + bool bResult = false; + + if (p_pIP6Address) + { + p_pIP6Address->m_pNext = m_pIP6Addresses; + m_pIP6Addresses = p_pIP6Address; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP6Address +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP6Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* p_pIP6Address) +{ + + bool bResult = false; + + if (p_pIP6Address) + { + stcIP6Address* pPred = m_pIP6Addresses; + while ((pPred) && + (pPred->m_pNext != p_pIP6Address)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pIP6Address->m_pNext; + delete p_pIP6Address; + bResult = true; + } + else if (m_pIP6Addresses == p_pIP6Address) // No predecesor, but first item + { + m_pIP6Addresses = p_pIP6Address->m_pNext; + delete p_pIP6Address; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address(const IP6Address& p_IPAddress) +{ + + return (stcIP6Address*)(((const stcAnswer*)this)->findIP6Address(p_IPAddress)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address (const) +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address(const IPAddress& p_IPAddress) const +{ + + const stcIP6Address* pIP6Address = m_pIP6Addresses; + while (pIP6Address) + { + if (p_IP6Address->m_IPAddress == p_IPAddress) + { + break; + } + pIP6Address = pIP6Address->m_pNext; + } + return pIP6Address; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressCount +*/ +uint32_t MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressCount(void) const +{ + + uint32_t u32Count = 0; + + stcIP6Address* pIP6Address = m_pIP6Addresses; + while (pIP6Address) + { + ++u32Count; + pIP6Address = pIP6Address->m_pNext; + } + return u32Count; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex (const) +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex(uint32_t p_u32Index) const +{ + + return (stcIP6Address*)(((const stcAnswer*)this)->IP6AddressAtIndex(p_u32Index)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex(uint32_t p_u32Index) +{ + + stcIP6Address* pIP6Address = 0; + + if (((uint32_t)(-1) != p_u32Index) && + (m_pIP6Addresses)) + { + + uint32_t u32Index; + for (pIP6Address = m_pIP6Addresses, u32Index = 0; ((pIP6Address) && (u32Index < p_u32Index)); pIP6Address = pIP6Address->m_pNext, ++u32Index); + } + return pIP6Address; +} +#endif + + +/** + MDNSResponder::stcMDNSServiceQuery + + A service query object. + A static query is flaged via 'm_bLegacyQuery'; while the function 'queryService' + is waiting for answers, the internal flag 'm_bAwaitingAnswers' is set. When the + timeout is reached, the flag is removed. These two flags are only used for static + service queries. + All answers to the service query are stored in 'm_pAnswers' list. + Individual answers may be addressed by index (in the list of answers). + Every time a answer component is added (or changes) in a dynamic service query, + the callback 'm_fnCallback' is called. + The answer list may be searched by service and host domain. + + Service query object may be connected to a linked list. +*/ + +/* + MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery constructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery(void) + : m_pNext(0), + m_fnCallback(0), + m_bLegacyQuery(false), + m_u8SentCount(0), + m_ResendTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), + m_bAwaitingAnswers(true), + m_pAnswers(0) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery destructor +*/ +MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceQuery::clear +*/ +bool MDNSResponder::stcMDNSServiceQuery::clear(void) +{ + + m_fnCallback = 0; + m_bLegacyQuery = false; + m_u8SentCount = 0; + m_ResendTimeout.resetToNeverExpires(); + m_bAwaitingAnswers = true; + while (m_pAnswers) + { + stcAnswer* pNext = m_pAnswers->m_pNext; + delete m_pAnswers; + m_pAnswers = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::answerCount +*/ +uint32_t MDNSResponder::stcMDNSServiceQuery::answerCount(void) const +{ + + uint32_t u32Count = 0; + + stcAnswer* pAnswer = m_pAnswers; + while (pAnswer) + { + ++u32Count; + pAnswer = pAnswer->m_pNext; + } + return u32Count; +} + +/* + MDNSResponder::stcMDNSServiceQuery::answerAtIndex +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::answerAtIndex(uint32_t p_u32Index) const +{ + + const stcAnswer* pAnswer = 0; + + if (((uint32_t)(-1) != p_u32Index) && + (m_pAnswers)) + { + + uint32_t u32Index; + for (pAnswer = m_pAnswers, u32Index = 0; ((pAnswer) && (u32Index < p_u32Index)); pAnswer = pAnswer->m_pNext, ++u32Index); + } + return pAnswer; +} + +/* + MDNSResponder::stcMDNSServiceQuery::answerAtIndex +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::answerAtIndex(uint32_t p_u32Index) +{ + + return (stcAnswer*)(((const stcMDNSServiceQuery*)this)->answerAtIndex(p_u32Index)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::indexOfAnswer +*/ +uint32_t MDNSResponder::stcMDNSServiceQuery::indexOfAnswer(const MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) const +{ + + uint32_t u32Index = 0; + + for (const stcAnswer* pAnswer = m_pAnswers; pAnswer; pAnswer = pAnswer->m_pNext, ++u32Index) + { + if (pAnswer == p_pAnswer) + { + return u32Index; + } + } + return ((uint32_t)(-1)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::addAnswer +*/ +bool MDNSResponder::stcMDNSServiceQuery::addAnswer(MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) +{ + + bool bResult = false; + + if (p_pAnswer) + { + p_pAnswer->m_pNext = m_pAnswers; + m_pAnswers = p_pAnswer; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::removeAnswer +*/ +bool MDNSResponder::stcMDNSServiceQuery::removeAnswer(MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) +{ + + bool bResult = false; + + if (p_pAnswer) + { + stcAnswer* pPred = m_pAnswers; + while ((pPred) && + (pPred->m_pNext != p_pAnswer)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pAnswer->m_pNext; + delete p_pAnswer; + bResult = true; + } + else if (m_pAnswers == p_pAnswer) // No predecesor, but first item + { + m_pAnswers = p_pAnswer->m_pNext; + delete p_pAnswer; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::findAnswerForServiceDomain +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::findAnswerForServiceDomain(const MDNSResponder::stcMDNS_RRDomain& p_ServiceDomain) +{ + + stcAnswer* pAnswer = m_pAnswers; + while (pAnswer) + { + if (pAnswer->m_ServiceDomain == p_ServiceDomain) + { + break; + } + pAnswer = pAnswer->m_pNext; + } + return pAnswer; +} + +/* + MDNSResponder::stcMDNSServiceQuery::findAnswerForHostDomain +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::findAnswerForHostDomain(const MDNSResponder::stcMDNS_RRDomain& p_HostDomain) +{ + + stcAnswer* pAnswer = m_pAnswers; + while (pAnswer) + { + if (pAnswer->m_HostDomain == p_HostDomain) + { + break; + } + pAnswer = pAnswer->m_pNext; + } + return pAnswer; +} + + +/** + MDNSResponder::stcMDNSSendParameter + + A 'collection' of properties and flags for one MDNS query or response. + Mainly managed by the 'Control' functions. + The current offset in the UPD output buffer is tracked to be able to do + a simple host or service domain compression. + +*/ + +/** + MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem + + A cached host or service domain, incl. the offset in the UDP output buffer. + +*/ + +/* + MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem::stcDomainCacheItem constructor +*/ +MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem::stcDomainCacheItem(const void* p_pHostnameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset) + : m_pNext(0), + m_pHostnameOrService(p_pHostnameOrService), + m_bAdditionalData(p_bAdditionalData), + m_u16Offset(p_u16Offset) +{ + +} + +/** + MDNSResponder::stcMDNSSendParameter +*/ + +/* + MDNSResponder::stcMDNSSendParameter::stcMDNSSendParameter constructor +*/ +MDNSResponder::stcMDNSSendParameter::stcMDNSSendParameter(void) + : m_pQuestions(0), + m_pDomainCacheItems(0) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSSendParameter::~stcMDNSSendParameter destructor +*/ +MDNSResponder::stcMDNSSendParameter::~stcMDNSSendParameter(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSSendParameter::clear +*/ +bool MDNSResponder::stcMDNSSendParameter::clear(void) +{ + + m_u16ID = 0; + m_u8HostReplyMask = 0; + m_u16Offset = 0; + + m_bLegacyQuery = false; + m_bResponse = false; + m_bAuthorative = false; + m_bUnicast = false; + m_bUnannounce = false; + + m_bCacheFlush = true; + + while (m_pQuestions) + { + stcMDNS_RRQuestion* pNext = m_pQuestions->m_pNext; + delete m_pQuestions; + m_pQuestions = pNext; + } + while (m_pDomainCacheItems) + { + stcDomainCacheItem* pNext = m_pDomainCacheItems->m_pNext; + delete m_pDomainCacheItems; + m_pDomainCacheItems = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSSendParameter::shiftOffset +*/ +bool MDNSResponder::stcMDNSSendParameter::shiftOffset(uint16_t p_u16Shift) +{ + + m_u16Offset += p_u16Shift; + return true; +} + +/* + MDNSResponder::stcMDNSSendParameter::addDomainCacheItem +*/ +bool MDNSResponder::stcMDNSSendParameter::addDomainCacheItem(const void* p_pHostnameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset) +{ + + bool bResult = false; + + stcDomainCacheItem* pNewItem = 0; + if ((p_pHostnameOrService) && + (p_u16Offset) && + ((pNewItem = new stcDomainCacheItem(p_pHostnameOrService, p_bAdditionalData, p_u16Offset)))) + { + + pNewItem->m_pNext = m_pDomainCacheItems; + bResult = ((m_pDomainCacheItems = pNewItem)); + } + return bResult; +} + +/* + MDNSResponder::stcMDNSSendParameter::findCachedDomainOffset +*/ +uint16_t MDNSResponder::stcMDNSSendParameter::findCachedDomainOffset(const void* p_pHostnameOrService, + bool p_bAdditionalData) const +{ + + const stcDomainCacheItem* pCacheItem = m_pDomainCacheItems; + + for (; pCacheItem; pCacheItem = pCacheItem->m_pNext) + { + if ((pCacheItem->m_pHostnameOrService == p_pHostnameOrService) && + (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item + { + break; + } + } + return (pCacheItem ? pCacheItem->m_u16Offset : 0); +} + +} // namespace MDNSImplementation + +} // namespace esp8266 + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp new file mode 100644 index 0000000000..c5858690a5 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp @@ -0,0 +1,1780 @@ +/* + LEAmDNS_Transfer.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +extern "C" { +#include "user_interface.h" +} + +#include "ESP8266mDNS.h" +#include "LEAmDNS_lwIPdefs.h" +#include "LEAmDNS_Priv.h" + + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + CONST STRINGS +*/ +static const char* scpcLocal = "local"; +static const char* scpcServices = "services"; +static const char* scpcDNSSD = "dns-sd"; +static const char* scpcUDP = "udp"; +//static const char* scpcTCP = "tcp"; + +#ifdef MDNS_IP4_SUPPORT +static const char* scpcReverseIP4Domain = "in-addr"; +#endif +#ifdef MDNS_IP6_SUPPORT +static const char* scpcReverseIP6Domain = "ip6"; +#endif +static const char* scpcReverseTopDomain = "arpa"; + +/** + TRANSFER +*/ + + +/** + SENDING +*/ + +/* + MDNSResponder::_sendMDNSMessage + + Unicast responses are prepared and sent directly to the querier. + Multicast responses or queries are transferred to _sendMDNSMessage_Multicast + + Any reply flags in installed services are removed at the end! + +*/ +bool MDNSResponder::_sendMDNSMessage(MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + bool bResult = true; + + if (p_rSendParameter.m_bResponse && + p_rSendParameter.m_bUnicast) // Unicast response -> Send to querier + { + DEBUG_EX_ERR(if (!m_pUDPContext->getRemoteAddress()) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: MISSING remote address for response!\n")); + }); + IPAddress ipRemote; + ipRemote = m_pUDPContext->getRemoteAddress(); + bResult = ((_prepareMDNSMessage(p_rSendParameter, _getResponseMulticastInterface())) && + (m_pUDPContext->send(ipRemote, m_pUDPContext->getRemotePort()))); + } + else // Multicast response + { + bResult = _sendMDNSMessage_Multicast(p_rSendParameter); + } + + // Finally clear service reply masks + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + pService->m_u8ReplyMask = 0; + } + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_sendMDNSMessage_Multicast + + Fills the UDP output buffer (via _prepareMDNSMessage) and sends the buffer + via the selected WiFi interface (Station or AP) +*/ +bool MDNSResponder::_sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + bool bResult = false; + + IPAddress fromIPAddress; + fromIPAddress = _getResponseMulticastInterface(); + m_pUDPContext->setMulticastInterface(fromIPAddress); + +#ifdef MDNS_IP4_SUPPORT + IPAddress toMulticastAddress(DNS_MQUERY_IPV4_GROUP_INIT); +#endif +#ifdef MDNS_IP6_SUPPORT + //TODO: set multicast address + IPAddress toMulticastAddress(DNS_MQUERY_IPV6_GROUP_INIT); +#endif + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage_Multicast: Will send to '%s'.\n"), toMulticastAddress.toString().c_str());); + bResult = ((_prepareMDNSMessage(p_rSendParameter, fromIPAddress)) && + (m_pUDPContext->send(toMulticastAddress, DNS_MQUERY_PORT))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage_Multicast: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_prepareMDNSMessage + + The MDNS message is composed in a two-step process. + In the first loop 'only' the header informations (mainly number of answers) are collected, + while in the seconds loop, the header and all queries and answers are written to the UDP + output buffer. + +*/ +bool MDNSResponder::_prepareMDNSMessage(MDNSResponder::stcMDNSSendParameter& p_rSendParameter, + IPAddress p_IPAddress) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage\n"));); + bool bResult = true; + + // Prepare header; count answers + stcMDNS_MsgHeader msgHeader(p_rSendParameter.m_u16ID, p_rSendParameter.m_bResponse, 0, p_rSendParameter.m_bAuthorative); + // If this is a response, the answers are anwers, + // else this is a query or probe and the answers go into auth section + uint16_t& ru16Answers = (p_rSendParameter.m_bResponse + ? msgHeader.m_u16ANCount + : msgHeader.m_u16NSCount); + + /** + enuSequence + */ + enum enuSequence + { + Sequence_Count = 0, + Sequence_Send = 1 + }; + + // Two step sequence: 'Count' and 'Send' + for (uint32_t sequence = Sequence_Count; ((bResult) && (sequence <= Sequence_Send)); ++sequence) + { + DEBUG_EX_INFO( + if (Sequence_Send == sequence) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + (unsigned)msgHeader.m_u16ID, + (unsigned)msgHeader.m_1bQR, (unsigned)msgHeader.m_4bOpcode, (unsigned)msgHeader.m_1bAA, (unsigned)msgHeader.m_1bTC, (unsigned)msgHeader.m_1bRD, + (unsigned)msgHeader.m_1bRA, (unsigned)msgHeader.m_4bRCode, + (unsigned)msgHeader.m_u16QDCount, + (unsigned)msgHeader.m_u16ANCount, + (unsigned)msgHeader.m_u16NSCount, + (unsigned)msgHeader.m_u16ARCount); + } + ); + // Count/send + // Header + bResult = ((Sequence_Count == sequence) + ? true + : _writeMDNSMsgHeader(msgHeader, p_rSendParameter)); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSMsgHeader FAILED!\n"));); + // Questions + for (stcMDNS_RRQuestion* pQuestion = p_rSendParameter.m_pQuestions; ((bResult) && (pQuestion)); pQuestion = pQuestion->m_pNext) + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16QDCount + : (bResult = _writeMDNSQuestion(*pQuestion, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSQuestion FAILED!\n"));); + } + + // Answers and authorative answers +#ifdef MDNS_IP4_SUPPORT + if ((bResult) && + (p_rSendParameter.m_u8HostReplyMask & ContentFlag_A)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(A) FAILED!\n"));); + } + if ((bResult) && + (p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP4)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_IP4(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP4 FAILED!\n"));); + } +#endif +#ifdef MDNS_IP6_SUPPORT + if ((bResult) && + (p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(A) FAILED!\n"));); + } + if ((bResult) && + (p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP6)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_IP6(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP6 FAILED!\n"));); + } +#endif + + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_PTR_TYPE)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_TYPE(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_TYPE FAILED!\n"));); + } + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_PTR_NAME)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_NAME(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_NAME FAILED!\n"));); + } + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_SRV)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(A) FAILED!\n"));); + } + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_TXT)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(A) FAILED!\n"));); + } + } // for services + + // Additional answers +#ifdef MDNS_IP4_SUPPORT + bool bNeedsAdditionalAnswerA = false; +#endif +#ifdef MDNS_IP6_SUPPORT + bool bNeedsAdditionalAnswerAAAA = false; +#endif + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND + (!(pService->m_u8ReplyMask & ContentFlag_SRV))) // NOT SRV -> add SRV as additional answer + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16ARCount + : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(B) FAILED!\n"));); + } + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND + (!(pService->m_u8ReplyMask & ContentFlag_TXT))) // NOT TXT -> add TXT as additional answer + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16ARCount + : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(B) FAILED!\n"));); + } + if ((pService->m_u8ReplyMask & (ContentFlag_PTR_NAME | ContentFlag_SRV)) || // If service instance name or SRV OR + (p_rSendParameter.m_u8HostReplyMask & (ContentFlag_A | ContentFlag_AAAA))) // any host IP address is requested + { +#ifdef MDNS_IP4_SUPPORT + if ((bResult) && + (!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_A))) // Add IP4 address + { + bNeedsAdditionalAnswerA = true; + } +#endif +#ifdef MDNS_IP6_SUPPORT + if ((bResult) && + (!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA))) // Add IP6 address + { + bNeedsAdditionalAnswerAAAA = true; + } +#endif + } + } // for services + + // Answer A needed? +#ifdef MDNS_IP4_SUPPORT + if ((bResult) && + (bNeedsAdditionalAnswerA)) + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16ARCount + : (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(B) FAILED!\n"));); + } +#endif +#ifdef MDNS_IP6_SUPPORT + // Answer AAAA needed? + if ((bResult) && + (bNeedsAdditionalAnswerAAAA)) + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16ARCount + : (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(B) FAILED!\n"));); + } +#endif + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: Loop %i FAILED!\n"), sequence);); + } // for sequence + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_sendMDNSServiceQuery + + Creates and sends a PTR query for the given service domain. + +*/ +bool MDNSResponder::_sendMDNSServiceQuery(const MDNSResponder::stcMDNSServiceQuery& p_ServiceQuery) +{ + + return _sendMDNSQuery(p_ServiceQuery.m_ServiceTypeDomain, DNS_RRTYPE_PTR); +} + +/* + MDNSResponder::_sendMDNSQuery + + Creates and sends a query for the given domain and query type. + +*/ +bool MDNSResponder::_sendMDNSQuery(const MDNSResponder::stcMDNS_RRDomain& p_QueryDomain, + uint16_t p_u16QueryType, + stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers /*= 0*/) +{ + + bool bResult = false; + + stcMDNSSendParameter sendParameter; + if (0 != ((sendParameter.m_pQuestions = new stcMDNS_RRQuestion))) + { + sendParameter.m_pQuestions->m_Header.m_Domain = p_QueryDomain; + + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = p_u16QueryType; + // It seems, that some mDNS implementations don't support 'unicast response' questions... + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN); // /*Unicast &*/ INternet + + // TODO: Add knwon answer to the query + (void)p_pKnownAnswers; + + bResult = _sendMDNSMessage(sendParameter); + } // else: FAILED to alloc question + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSQuery: FAILED to alloc question!\n"));); + return bResult; +} + +/** + HELPERS +*/ + +/** + RESOURCE RECORDS +*/ + +/* + MDNSResponder::_readRRQuestion + + Reads a question (eg. MyESP._http._tcp.local ANY IN) from the UPD input buffer. + +*/ +bool MDNSResponder::_readRRQuestion(MDNSResponder::stcMDNS_RRQuestion& p_rRRQuestion) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion\n"));); + + bool bResult = false; + + if ((bResult = _readRRHeader(p_rRRQuestion.m_Header))) + { + // Extract unicast flag from class field + p_rRRQuestion.m_bUnicast = (p_rRRQuestion.m_Header.m_Attributes.m_u16Class & 0x8000); + p_rRRQuestion.m_Header.m_Attributes.m_u16Class &= (~0x8000); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion ")); + _printRRDomain(p_rRRQuestion.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X %s\n"), (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Type, (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Class, (p_rRRQuestion.m_bUnicast ? "Unicast" : "Multicast")); + ); + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_readRRAnswer + + Reads an answer (eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local) + from the UDP input buffer. + After reading the domain and type info, the further processing of the answer + is transferred the answer specific reading functions. + Unknown answer types are processed by the generic answer reader (to remove them + from the input buffer). + +*/ +bool MDNSResponder::_readRRAnswer(MDNSResponder::stcMDNS_RRAnswer*& p_rpRRAnswer) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer\n"));); + + bool bResult = false; + + stcMDNS_RRHeader header; + uint32_t u32TTL; + uint16_t u16RDLength; + if ((_readRRHeader(header)) && + (_udpRead32(u32TTL)) && + (_udpRead16(u16RDLength))) + { + + /* DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: Reading 0x%04X answer (class:0x%04X, TTL:%u, RDLength:%u) for "), header.m_Attributes.m_u16Type, header.m_Attributes.m_u16Class, u32TTL, u16RDLength); + _printRRDomain(header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + );*/ + + switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IP4_SUPPORT + case DNS_RRTYPE_A: + p_rpRRAnswer = new stcMDNS_RRAnswerA(header, u32TTL); + bResult = _readRRAnswerA(*(stcMDNS_RRAnswerA*&)p_rpRRAnswer, u16RDLength); + break; +#endif + case DNS_RRTYPE_PTR: + p_rpRRAnswer = new stcMDNS_RRAnswerPTR(header, u32TTL); + bResult = _readRRAnswerPTR(*(stcMDNS_RRAnswerPTR*&)p_rpRRAnswer, u16RDLength); + break; + case DNS_RRTYPE_TXT: + p_rpRRAnswer = new stcMDNS_RRAnswerTXT(header, u32TTL); + bResult = _readRRAnswerTXT(*(stcMDNS_RRAnswerTXT*&)p_rpRRAnswer, u16RDLength); + break; +#ifdef MDNS_IP6_SUPPORT + case DNS_RRTYPE_AAAA: + p_rpRRAnswer = new stcMDNS_RRAnswerAAAA(header, u32TTL); + bResult = _readRRAnswerAAAA(*(stcMDNS_RRAnswerAAAA*&)p_rpRRAnswer, u16RDLength); + break; +#endif + case DNS_RRTYPE_SRV: + p_rpRRAnswer = new stcMDNS_RRAnswerSRV(header, u32TTL); + bResult = _readRRAnswerSRV(*(stcMDNS_RRAnswerSRV*&)p_rpRRAnswer, u16RDLength); + break; + default: + p_rpRRAnswer = new stcMDNS_RRAnswerGeneric(header, u32TTL); + bResult = _readRRAnswerGeneric(*(stcMDNS_RRAnswerGeneric*&)p_rpRRAnswer, u16RDLength); + break; + } + DEBUG_EX_INFO( + if ((bResult) && + (p_rpRRAnswer)) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: ")); + _printRRDomain(p_rpRRAnswer->m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, RDLength:%u "), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type, p_rpRRAnswer->m_Header.m_Attributes.m_u16Class, p_rpRRAnswer->m_u32TTL, u16RDLength); + switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IP4_SUPPORT + case DNS_RRTYPE_A: + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_PTR: + DEBUG_OUTPUT.printf_P(PSTR("PTR ")); + _printRRDomain(((stcMDNS_RRAnswerPTR*&)p_rpRRAnswer)->m_PTRDomain); + break; + case DNS_RRTYPE_TXT: + { + size_t stTxtLength = ((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_strLength(); + char* pTxts = new char[stTxtLength]; + if (pTxts) + { + ((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_str(pTxts); + DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); + delete[] pTxts; + } + break; + } +#ifdef MDNS_IP6_SUPPORT + case DNS_RRTYPE_AAAA: + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_SRV: + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_u16Port); + _printRRDomain(((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_SRVDomain); + break; + default: + DEBUG_OUTPUT.printf_P(PSTR("generic ")); + break; + } + DEBUG_OUTPUT.printf_P(PSTR("\n")); + } + else + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED to read specific answer of type 0x%04X!\n"), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type); + } + ); // DEBUG_EX_INFO + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED!\n"));); + return bResult; +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::_readRRAnswerA +*/ +bool MDNSResponder::_readRRAnswerA(MDNSResponder::stcMDNS_RRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength) +{ + + uint32_t u32IP4Address; + bool bResult = ((MDNS_IP4_SIZE == p_u16RDLength) && + (_udpReadBuffer((unsigned char*)&u32IP4Address, MDNS_IP4_SIZE)) && + ((p_rRRAnswerA.m_IPAddress = IPAddress(u32IP4Address)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerA: FAILED!\n"));); + return bResult; +} +#endif + +/* + MDNSResponder::_readRRAnswerPTR +*/ +bool MDNSResponder::_readRRAnswerPTR(MDNSResponder::stcMDNS_RRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength) +{ + + bool bResult = ((p_u16RDLength) && + (_readRRDomain(p_rRRAnswerPTR.m_PTRDomain))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerPTR: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRAnswerTXT + + Read TXT items from a buffer like 4c#=15ff=20 +*/ +bool MDNSResponder::_readRRAnswerTXT(MDNSResponder::stcMDNS_RRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: RDLength:%u\n"), p_u16RDLength);); + bool bResult = true; + + p_rRRAnswerTXT.clear(); + if (p_u16RDLength) + { + bResult = false; + + unsigned char* pucBuffer = new unsigned char[p_u16RDLength]; + if (pucBuffer) + { + if (_udpReadBuffer(pucBuffer, p_u16RDLength)) + { + bResult = true; + + const unsigned char* pucCursor = pucBuffer; + while ((pucCursor < (pucBuffer + p_u16RDLength)) && + (bResult)) + { + bResult = false; + + stcMDNSServiceTxt* pTxt = 0; + unsigned char ucLength = *pucCursor++; // Length of the next txt item + if (ucLength) + { + DEBUG_EX_INFO( + static char sacBuffer[64]; *sacBuffer = 0; + uint8_t u8MaxLength = ((ucLength > (sizeof(sacBuffer) - 1)) ? (sizeof(sacBuffer) - 1) : ucLength); + os_strncpy(sacBuffer, (const char*)pucCursor, u8MaxLength); sacBuffer[u8MaxLength] = 0; + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: Item(%u): %s\n"), ucLength, sacBuffer); + ); + + unsigned char* pucEqualSign = (unsigned char*)os_strchr((const char*)pucCursor, '='); // Position of the '=' sign + unsigned char ucKeyLength; + if ((pucEqualSign) && + ((ucKeyLength = (pucEqualSign - pucCursor)))) + { + unsigned char ucValueLength = (ucLength - (pucEqualSign - pucCursor + 1)); + bResult = (((pTxt = new stcMDNSServiceTxt)) && + (pTxt->setKey((const char*)pucCursor, ucKeyLength)) && + (pTxt->setValue((const char*)(pucEqualSign + 1), ucValueLength))); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: INVALID TXT format (No '=')!\n"));); + } + pucCursor += ucLength; + } + else // no/zero length TXT + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: TXT answer contains no items.\n"));); + bResult = true; + } + + if ((bResult) && + (pTxt)) // Everythings fine so far + { + // Link TXT item to answer TXTs + pTxt->m_pNext = p_rRRAnswerTXT.m_Txts.m_pTxts; + p_rRRAnswerTXT.m_Txts.m_pTxts = pTxt; + } + else // At least no TXT (migth be OK, if length was 0) OR an error + { + if (!bResult) + { + DEBUG_EX_ERR( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT item!\n")); + DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); + _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + if (pTxt) + { + delete pTxt; + pTxt = 0; + } + p_rRRAnswerTXT.clear(); + } + } // while + + DEBUG_EX_ERR( + if (!bResult) // Some failure + { + DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); + _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + } + ); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT content!\n"));); + } + // Clean up + delete[] pucBuffer; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to alloc buffer for TXT content!\n"));); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: WARNING! No content!\n"));); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED!\n"));); + return bResult; +} + +#ifdef MDNS_IP6_SUPPORT +bool MDNSResponder::_readRRAnswerAAAA(MDNSResponder::stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength) +{ + bool bResult = false; + // TODO: Implement + return bResult; +} +#endif + +/* + MDNSResponder::_readRRAnswerSRV +*/ +bool MDNSResponder::_readRRAnswerSRV(MDNSResponder::stcMDNS_RRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength) +{ + + bool bResult = (((3 * sizeof(uint16_t)) < p_u16RDLength) && + (_udpRead16(p_rRRAnswerSRV.m_u16Priority)) && + (_udpRead16(p_rRRAnswerSRV.m_u16Weight)) && + (_udpRead16(p_rRRAnswerSRV.m_u16Port)) && + (_readRRDomain(p_rRRAnswerSRV.m_SRVDomain))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerSRV: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRAnswerGeneric +*/ +bool MDNSResponder::_readRRAnswerGeneric(MDNSResponder::stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength) +{ + bool bResult = (0 == p_u16RDLength); + + p_rRRAnswerGeneric.clear(); + if (((p_rRRAnswerGeneric.m_u16RDLength = p_u16RDLength)) && + ((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength]))) + { + + bResult = _udpReadBuffer(p_rRRAnswerGeneric.m_pu8RDData, p_rRRAnswerGeneric.m_u16RDLength); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerGeneric: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRHeader +*/ +bool MDNSResponder::_readRRHeader(MDNSResponder::stcMDNS_RRHeader& p_rRRHeader) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader\n"));); + + bool bResult = ((_readRRDomain(p_rRRHeader.m_Domain)) && + (_readRRAttributes(p_rRRHeader.m_Attributes))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRDomain + + Reads a (maybe multilevel compressed) domain from the UDP input buffer. + +*/ +bool MDNSResponder::_readRRDomain(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain\n"));); + + bool bResult = ((p_rRRDomain.clear()) && + (_readRRDomain_Loop(p_rRRDomain, 0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRDomain_Loop + + Reads a domain from the UDP input buffer. For every compression level, the functions + calls itself recursively. To avoid endless recursion because of malformed MDNS records, + the maximum recursion depth is set by MDNS_DOMAIN_MAX_REDIRCTION. + +*/ +bool MDNSResponder::_readRRDomain_Loop(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain, + uint8_t p_u8Depth) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u)\n"), p_u8Depth);); + + bool bResult = false; + + if (MDNS_DOMAIN_MAX_REDIRCTION >= p_u8Depth) + { + bResult = true; + + uint8_t u8Len = 0; + do + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Offset:%u p0:%02x\n"), p_u8Depth, m_pUDPContext->tell(), m_pUDPContext->peek());); + _udpRead8(u8Len); + + if (u8Len & MDNS_DOMAIN_COMPRESS_MARK) + { + // Compressed label(s) + uint16_t u16Offset = ((u8Len & ~MDNS_DOMAIN_COMPRESS_MARK) << 8); // Implicit BE to LE conversion! + _udpRead8(u8Len); + u16Offset |= u8Len; + + if (m_pUDPContext->isValidOffset(u16Offset)) + { + size_t stCurrentPosition = m_pUDPContext->tell(); // Prepare return from recursion + + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Redirecting from %u to %u!\n"), p_u8Depth, stCurrentPosition, u16Offset);); + m_pUDPContext->seek(u16Offset); + if (_readRRDomain_Loop(p_rRRDomain, p_u8Depth + 1)) // Do recursion + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Succeeded to read redirected label! Returning to %u\n"), p_u8Depth, stCurrentPosition);); + m_pUDPContext->seek(stCurrentPosition); // Restore after recursion + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): FAILED to read redirected label!\n"), p_u8Depth);); + bResult = false; + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): INVALID offset in redirection!\n"), p_u8Depth);); + bResult = false; + } + break; + } + else + { + // Normal (uncompressed) label (maybe '\0' only) + if (MDNS_DOMAIN_MAXLENGTH > (p_rRRDomain.m_u16NameLength + u8Len)) + { + // Add length byte + p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength] = u8Len; + ++(p_rRRDomain.m_u16NameLength); + if (u8Len) // Add name + { + if ((bResult = _udpReadBuffer((unsigned char*) & (p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength]), u8Len))) + { + /* DEBUG_EX_INFO( + p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength + u8Len] = 0; // Closing '\0' for printing + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Domain label (%u): %s\n"), p_u8Depth, (unsigned)(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength - 1]), &(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength])); + );*/ + + p_rRRDomain.m_u16NameLength += u8Len; + } + } + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(2) offset:%u p0:%x\n"), m_pUDPContext->tell(), m_pUDPContext->peek());); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Domain name too long (%u + %u)!\n"), p_u8Depth, p_rRRDomain.m_u16NameLength, u8Len);); + bResult = false; + break; + } + } + } while ((bResult) && + (0 != u8Len)); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Too many redirections!\n"), p_u8Depth);); + } + return bResult; +} + +/* + MDNSResponder::_readRRAttributes +*/ +bool MDNSResponder::_readRRAttributes(MDNSResponder::stcMDNS_RRAttributes& p_rRRAttributes) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes\n"));); + + bool bResult = ((_udpRead16(p_rRRAttributes.m_u16Type)) && + (_udpRead16(p_rRRAttributes.m_u16Class))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes: FAILED!\n"));); + return bResult; +} + + +/* + DOMAIN NAMES +*/ + +/* + MDNSResponder::_buildDomainForHost + + Builds a MDNS host domain (eg. esp8266.local) for the given hostname. + +*/ +bool MDNSResponder::_buildDomainForHost(const char* p_pcHostname, + MDNSResponder::stcMDNS_RRDomain& p_rHostDomain) const +{ + + p_rHostDomain.clear(); + bool bResult = ((p_pcHostname) && + (*p_pcHostname) && + (p_rHostDomain.addLabel(p_pcHostname)) && + (p_rHostDomain.addLabel(scpcLocal)) && + (p_rHostDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForHost: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_buildDomainForDNSSD + + Builds the '_services._dns-sd._udp.local' domain. + Used while detecting generic service enum question (DNS-SD) and answering these questions. + +*/ +bool MDNSResponder::_buildDomainForDNSSD(MDNSResponder::stcMDNS_RRDomain& p_rDNSSDDomain) const +{ + + p_rDNSSDDomain.clear(); + bool bResult = ((p_rDNSSDDomain.addLabel(scpcServices, true)) && + (p_rDNSSDDomain.addLabel(scpcDNSSD, true)) && + (p_rDNSSDDomain.addLabel(scpcUDP, true)) && + (p_rDNSSDDomain.addLabel(scpcLocal)) && + (p_rDNSSDDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForDNSSD: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_buildDomainForService + + Builds the domain for the given service (eg. _http._tcp.local or + MyESP._http._tcp.local (if p_bIncludeName is set)). + +*/ +bool MDNSResponder::_buildDomainForService(const MDNSResponder::stcMDNSService& p_Service, + bool p_bIncludeName, + MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const +{ + + p_rServiceDomain.clear(); + bool bResult = (((!p_bIncludeName) || + (p_rServiceDomain.addLabel(p_Service.m_pcName))) && + (p_rServiceDomain.addLabel(p_Service.m_pcService, true)) && + (p_rServiceDomain.addLabel(p_Service.m_pcProtocol, true)) && + (p_rServiceDomain.addLabel(scpcLocal)) && + (p_rServiceDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_buildDomainForService + + Builds the domain for the given service properties (eg. _http._tcp.local). + The usual prepended '_' are added, if missing in the input strings. + +*/ +bool MDNSResponder::_buildDomainForService(const char* p_pcService, + const char* p_pcProtocol, + MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const +{ + + p_rServiceDomain.clear(); + bool bResult = ((p_pcService) && + (p_pcProtocol) && + (p_rServiceDomain.addLabel(p_pcService, ('_' != *p_pcService))) && + (p_rServiceDomain.addLabel(p_pcProtocol, ('_' != *p_pcProtocol))) && + (p_rServiceDomain.addLabel(scpcLocal)) && + (p_rServiceDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED for (%s.%s)!\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + return bResult; +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::_buildDomainForReverseIP4 + + The IP4 address is stringized by printing the four address bytes into a char buffer in reverse order + and adding 'in-addr.arpa' (eg. 012.789.456.123.in-addr.arpa). + Used while detecting reverse IP4 questions and answering these +*/ +bool MDNSResponder::_buildDomainForReverseIP4(IPAddress p_IP4Address, + MDNSResponder::stcMDNS_RRDomain& p_rReverseIP4Domain) const +{ + + bool bResult = true; + + p_rReverseIP4Domain.clear(); + + char acBuffer[32]; + for (int i = MDNS_IP4_SIZE; ((bResult) && (i >= 1)); --i) + { + itoa(p_IP4Address[i - 1], acBuffer, 10); + bResult = p_rReverseIP4Domain.addLabel(acBuffer); + } + bResult = ((bResult) && + (p_rReverseIP4Domain.addLabel(scpcReverseIP4Domain)) && + (p_rReverseIP4Domain.addLabel(scpcReverseTopDomain)) && + (p_rReverseIP4Domain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForReverseIP4: FAILED!\n"));); + return bResult; +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::_buildDomainForReverseIP6 + + Used while detecting reverse IP6 questions and answering these +*/ +bool MDNSResponder::_buildDomainForReverseIP6(IPAddress p_IP4Address, + MDNSResponder::stcMDNS_RRDomain& p_rReverseIP6Domain) const +{ + // TODO: Implement + return false; +} +#endif + + +/* + UDP +*/ + +/* + MDNSResponder::_udpReadBuffer +*/ +bool MDNSResponder::_udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength) +{ + + bool bResult = ((m_pUDPContext) && + (true/*m_pUDPContext->getSize() > p_stLength*/) && + (p_pBuffer) && + (p_stLength) && + ((p_stLength == m_pUDPContext->read((char*)p_pBuffer, p_stLength)))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpReadBuffer: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_udpRead8 +*/ +bool MDNSResponder::_udpRead8(uint8_t& p_ru8Value) +{ + + return _udpReadBuffer((unsigned char*)&p_ru8Value, sizeof(p_ru8Value)); +} + +/* + MDNSResponder::_udpRead16 +*/ +bool MDNSResponder::_udpRead16(uint16_t& p_ru16Value) +{ + + bool bResult = false; + + if (_udpReadBuffer((unsigned char*)&p_ru16Value, sizeof(p_ru16Value))) + { + p_ru16Value = lwip_ntohs(p_ru16Value); + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::_udpRead32 +*/ +bool MDNSResponder::_udpRead32(uint32_t& p_ru32Value) +{ + + bool bResult = false; + + if (_udpReadBuffer((unsigned char*)&p_ru32Value, sizeof(p_ru32Value))) + { + p_ru32Value = lwip_ntohl(p_ru32Value); + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::_udpAppendBuffer +*/ +bool MDNSResponder::_udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength) +{ + + bool bResult = ((m_pUDPContext) && + (p_pcBuffer) && + (p_stLength) && + (p_stLength == m_pUDPContext->append((const char*)p_pcBuffer, p_stLength))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpAppendBuffer: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_udpAppend8 +*/ +bool MDNSResponder::_udpAppend8(uint8_t p_u8Value) +{ + + return (_udpAppendBuffer((unsigned char*)&p_u8Value, sizeof(p_u8Value))); +} + +/* + MDNSResponder::_udpAppend16 +*/ +bool MDNSResponder::_udpAppend16(uint16_t p_u16Value) +{ + + p_u16Value = lwip_htons(p_u16Value); + return (_udpAppendBuffer((unsigned char*)&p_u16Value, sizeof(p_u16Value))); +} + +/* + MDNSResponder::_udpAppend32 +*/ +bool MDNSResponder::_udpAppend32(uint32_t p_u32Value) +{ + + p_u32Value = lwip_htonl(p_u32Value); + return (_udpAppendBuffer((unsigned char*)&p_u32Value, sizeof(p_u32Value))); +} + +#ifdef DEBUG_ESP_MDNS_RESPONDER +/* + MDNSResponder::_udpDump +*/ +bool MDNSResponder::_udpDump(bool p_bMovePointer /*= false*/) +{ + + const uint8_t cu8BytesPerLine = 16; + + uint32_t u32StartPosition = m_pUDPContext->tell(); + DEBUG_OUTPUT.println("UDP Context Dump:"); + uint32_t u32Counter = 0; + uint8_t u8Byte = 0; + + while (_udpRead8(u8Byte)) + { + DEBUG_OUTPUT.printf_P(PSTR("%02x %s"), u8Byte, ((++u32Counter % cu8BytesPerLine) ? "" : "\n")); + } + DEBUG_OUTPUT.printf_P(PSTR("%sDone: %u bytes\n"), (((u32Counter) && (u32Counter % cu8BytesPerLine)) ? "\n" : ""), u32Counter); + + if (!p_bMovePointer) // Restore + { + m_pUDPContext->seek(u32StartPosition); + } + return true; +} + +/* + MDNSResponder::_udpDump +*/ +bool MDNSResponder::_udpDump(unsigned p_uOffset, + unsigned p_uLength) +{ + + if ((m_pUDPContext) && + (m_pUDPContext->isValidOffset(p_uOffset))) + { + unsigned uCurrentPosition = m_pUDPContext->tell(); // Remember start position + + m_pUDPContext->seek(p_uOffset); + uint8_t u8Byte; + for (unsigned u = 0; ((u < p_uLength) && (_udpRead8(u8Byte))); ++u) + { + DEBUG_OUTPUT.printf_P(PSTR("%02x "), u8Byte); + } + // Return to start position + m_pUDPContext->seek(uCurrentPosition); + } + return true; +} +#endif + + +/** + READ/WRITE MDNS STRUCTS +*/ + +/* + MDNSResponder::_readMDNSMsgHeader + + Read a MDNS header from the UDP input buffer. + | 8 | 8 | 8 | 8 | + 00| Identifier | Flags & Codes | + 01| Question count | Answer count | + 02| NS answer count | Ad answer count | + + All 16-bit and 32-bit elements need to be translated form network coding to host coding (done in _udpRead16 and _udpRead32) + In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they + need some mapping here +*/ +bool MDNSResponder::_readMDNSMsgHeader(MDNSResponder::stcMDNS_MsgHeader& p_rMsgHeader) +{ + + bool bResult = false; + + uint8_t u8B1; + uint8_t u8B2; + if ((_udpRead16(p_rMsgHeader.m_u16ID)) && + (_udpRead8(u8B1)) && + (_udpRead8(u8B2)) && + (_udpRead16(p_rMsgHeader.m_u16QDCount)) && + (_udpRead16(p_rMsgHeader.m_u16ANCount)) && + (_udpRead16(p_rMsgHeader.m_u16NSCount)) && + (_udpRead16(p_rMsgHeader.m_u16ARCount))) + { + + p_rMsgHeader.m_1bQR = (u8B1 & 0x80); // Query/Responde flag + p_rMsgHeader.m_4bOpcode = (u8B1 & 0x78); // Operation code (0: Standard query, others ignored) + p_rMsgHeader.m_1bAA = (u8B1 & 0x04); // Authorative answer + p_rMsgHeader.m_1bTC = (u8B1 & 0x02); // Truncation flag + p_rMsgHeader.m_1bRD = (u8B1 & 0x01); // Recursion desired + + p_rMsgHeader.m_1bRA = (u8B2 & 0x80); // Recursion available + p_rMsgHeader.m_3bZ = (u8B2 & 0x70); // Zero + p_rMsgHeader.m_4bRCode = (u8B2 & 0x0F); // Response code + + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + (unsigned)p_rMsgHeader.m_u16ID, + (unsigned)p_rMsgHeader.m_1bQR, (unsigned)p_rMsgHeader.m_4bOpcode, (unsigned)p_rMsgHeader.m_1bAA, (unsigned)p_rMsgHeader.m_1bTC, (unsigned)p_rMsgHeader.m_1bRD, + (unsigned)p_rMsgHeader.m_1bRA, (unsigned)p_rMsgHeader.m_4bRCode, + (unsigned)p_rMsgHeader.m_u16QDCount, + (unsigned)p_rMsgHeader.m_u16ANCount, + (unsigned)p_rMsgHeader.m_u16NSCount, + (unsigned)p_rMsgHeader.m_u16ARCount););*/ + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_write8 +*/ +bool MDNSResponder::_write8(uint8_t p_u8Value, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + return ((_udpAppend8(p_u8Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u8Value)))); +} + +/* + MDNSResponder::_write16 +*/ +bool MDNSResponder::_write16(uint16_t p_u16Value, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + return ((_udpAppend16(p_u16Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u16Value)))); +} + +/* + MDNSResponder::_write32 +*/ +bool MDNSResponder::_write32(uint32_t p_u32Value, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + return ((_udpAppend32(p_u32Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u32Value)))); +} + +/* + MDNSResponder::_writeMDNSMsgHeader + + Write MDNS header to the UDP output buffer. + + All 16-bit and 32-bit elements need to be translated form host coding to network coding (done in _udpAppend16 and _udpAppend32) + In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they + need some mapping here +*/ +bool MDNSResponder::_writeMDNSMsgHeader(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + (unsigned)p_MsgHeader.m_u16ID, + (unsigned)p_MsgHeader.m_1bQR, (unsigned)p_MsgHeader.m_4bOpcode, (unsigned)p_MsgHeader.m_1bAA, (unsigned)p_MsgHeader.m_1bTC, (unsigned)p_MsgHeader.m_1bRD, + (unsigned)p_MsgHeader.m_1bRA, (unsigned)p_MsgHeader.m_4bRCode, + (unsigned)p_MsgHeader.m_u16QDCount, + (unsigned)p_MsgHeader.m_u16ANCount, + (unsigned)p_MsgHeader.m_u16NSCount, + (unsigned)p_MsgHeader.m_u16ARCount););*/ + + uint8_t u8B1((p_MsgHeader.m_1bQR << 7) | (p_MsgHeader.m_4bOpcode << 3) | (p_MsgHeader.m_1bAA << 2) | (p_MsgHeader.m_1bTC << 1) | (p_MsgHeader.m_1bRD)); + uint8_t u8B2((p_MsgHeader.m_1bRA << 7) | (p_MsgHeader.m_3bZ << 4) | (p_MsgHeader.m_4bRCode)); + bool bResult = ((_write16(p_MsgHeader.m_u16ID, p_rSendParameter)) && + (_write8(u8B1, p_rSendParameter)) && + (_write8(u8B2, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16QDCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16ANCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16NSCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16ARCount, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeRRAttributes +*/ +bool MDNSResponder::_writeMDNSRRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Attributes, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + bool bResult = ((_write16(p_Attributes.m_u16Type, p_rSendParameter)) && + (_write16(p_Attributes.m_u16Class, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRAttributes: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeMDNSRRDomain +*/ +bool MDNSResponder::_writeMDNSRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_Domain, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + bool bResult = ((_udpAppendBuffer((const unsigned char*)p_Domain.m_acName, p_Domain.m_u16NameLength)) && + (p_rSendParameter.shiftOffset(p_Domain.m_u16NameLength))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRDomain: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeMDNSHostDomain + + Write a host domain to the UDP output buffer. + If the domain record is part of the answer, the records length is + prepended (p_bPrependRDLength is set). + + A very simple form of name compression is applied here: + If the domain is written to the UDP output buffer, the write offset is stored + together with a domain id (the pointer) in a p_rSendParameter substructure (cache). + If the same domain (pointer) should be written to the UDP output later again, + the old offset is retrieved from the cache, marked as a compressed domain offset + and written to the output buffer. + +*/ +bool MDNSResponder::_writeMDNSHostDomain(const char* p_pcHostname, + bool p_bPrependRDLength, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' + uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)p_pcHostname, false); + + stcMDNS_RRDomain hostDomain; + bool bResult = (u16CachedDomainOffset + // Found cached domain -> mark as compressed domain + ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + ((!p_bPrependRDLength) || + (_write16(2, p_rSendParameter))) && // Length of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) + // No cached domain -> add this domain to cache and write full domain name + : ((_buildDomainForHost(p_pcHostname, hostDomain)) && // eg. esp8266.local + ((!p_bPrependRDLength) || + (_write16(hostDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed) + (p_rSendParameter.addDomainCacheItem((const void*)p_pcHostname, false, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(hostDomain, p_rSendParameter)))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSHostDomain: FAILED!\n")); + }); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSServiceDomain + + Write a service domain to the UDP output buffer. + If the domain record is part of the answer, the records length is + prepended (p_bPrependRDLength is set). + + A very simple form of name compression is applied here: see '_writeMDNSHostDomain' + The cache differentiates of course between service domains which includes + the instance name (p_bIncludeName is set) and thoose who don't. + +*/ +bool MDNSResponder::_writeMDNSServiceDomain(const MDNSResponder::stcMDNSService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' + uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)&p_Service, p_bIncludeName); + + stcMDNS_RRDomain serviceDomain; + bool bResult = (u16CachedDomainOffset + // Found cached domain -> mark as compressed domain + ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + ((!p_bPrependRDLength) || + (_write16(2, p_rSendParameter))) && // Lenght of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) + // No cached domain -> add this domain to cache and write full domain name + : ((_buildDomainForService(p_Service, p_bIncludeName, serviceDomain)) && // eg. MyESP._http._tcp.local + ((!p_bPrependRDLength) || + (_write16(serviceDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed) + (p_rSendParameter.addDomainCacheItem((const void*)&p_Service, p_bIncludeName, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(serviceDomain, p_rSendParameter)))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSServiceDomain: FAILED!\n")); + }); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSQuestion + + Write a MDNS question to the UDP output buffer + + QNAME (host/service domain, eg. esp8266.local) + QTYPE (16bit, eg. ANY) + QCLASS (16bit, eg. IN) + +*/ +bool MDNSResponder::_writeMDNSQuestion(MDNSResponder::stcMDNS_RRQuestion& p_Question, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion\n"));); + + bool bResult = ((_writeMDNSRRDomain(p_Question.m_Header.m_Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(p_Question.m_Header.m_Attributes, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion: FAILED!\n")); + }); + return bResult; + +} + + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_A + + Write a MDNS A answer to the UDP output buffer. + + NAME (var, host/service domain, eg. esp8266.local + TYPE (16bit, eg. A) + CLASS (16bit, eg. IN) + TTL (32bit, eg. 120) + RDLENGTH (16bit, eg 4) + RDATA (var, eg. 123.456.789.012) + + eg. esp8266.local A 0x8001 120 4 123.456.789.012 + Ref: http://www.zytrax.com/books/dns/ch8/a.html +*/ +bool MDNSResponder::_writeMDNSAnswer_A(IPAddress p_IPAddress, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A (%s)\n"), p_IPAddress.toString().c_str());); + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_A, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + const unsigned char aucIPAddress[MDNS_IP4_SIZE] = { p_IPAddress[0], p_IPAddress[1], p_IPAddress[2], p_IPAddress[3] }; + bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL + (_write16(MDNS_IP4_SIZE, p_rSendParameter)) && // RDLength + (_udpAppendBuffer(aucIPAddress, MDNS_IP4_SIZE)) && // RData + (p_rSendParameter.shiftOffset(MDNS_IP4_SIZE))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A: FAILED!\n")); + }); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_IP4 + + Write a MDNS reverse IP4 PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + eg. 012.789.456.123.in-addr.arpa PTR 0x8001 120 15 esp8266.local + Used while answering reverse IP4 questions +*/ +bool MDNSResponder::_writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4 (%s)\n"), p_IPAddress.toString().c_str());); + + stcMDNS_RRDomain reverseIP4Domain; + stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + stcMDNS_RRDomain hostDomain; + bool bResult = ((_buildDomainForReverseIP4(p_IPAddress, reverseIP4Domain)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSRRDomain(reverseIP4Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL + (_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4: FAILED!\n")); + }); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_PTR_TYPE + + Write a MDNS PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + PTR all-services -> service type + eg. _services._dns-sd._udp.local PTR 0x8001 5400 xx _http._tcp.local + http://www.zytrax.com/books/dns/ch8/ptr.html +*/ +bool MDNSResponder::_writeMDNSAnswer_PTR_TYPE(MDNSResponder::stcMDNSService& p_rService, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE\n"));); + + stcMDNS_RRDomain dnssdDomain; + stcMDNS_RRDomain serviceDomain; + stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet + bool bResult = ((_buildDomainForDNSSD(dnssdDomain)) && // _services._dns-sd._udp.local + (_writeMDNSRRDomain(dnssdDomain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, false, true, p_rSendParameter))); // RDLength & RData (service domain, eg. _http._tcp.local) + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_NAME + + Write a MDNS PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + PTR service type -> service name + eg. _http.tcp.local PTR 0x8001 120 xx myESP._http._tcp.local + http://www.zytrax.com/books/dns/ch8/ptr.html +*/ +bool MDNSResponder::_writeMDNSAnswer_PTR_NAME(MDNSResponder::stcMDNSService& p_rService, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME\n"));); + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet + bool bResult = ((_writeMDNSServiceDomain(p_rService, false, false, p_rSendParameter)) && // _http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, true, true, p_rSendParameter))); // RDLength & RData (service domain, eg. MyESP._http._tcp.local) + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME: FAILED!\n")); + }); + return bResult; +} + + +/* + MDNSResponder::_writeMDNSAnswer_TXT + + Write a MDNS TXT answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + The TXT items in the RDATA block are 'length byte encoded': [len]vardata + + eg. myESP._http._tcp.local TXT 0x8001 120 4 c#=1 + http://www.zytrax.com/books/dns/ch8/txt.html +*/ +bool MDNSResponder::_writeMDNSAnswer_TXT(MDNSResponder::stcMDNSService& p_rService, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT\n"));); + + bool bResult = false; + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_TXT, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + + if ((_collectServiceTxts(p_rService)) && + (_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL + (_write16(p_rService.m_Txts.length(), p_rSendParameter))) // RDLength + { + + bResult = true; + // RData Txts + for (stcMDNSServiceTxt* pTxt = p_rService.m_Txts.m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + unsigned char ucLengthByte = pTxt->length(); + bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length + (p_rSendParameter.shiftOffset(sizeof(ucLengthByte))) && + ((size_t)os_strlen(pTxt->m_pcKey) == m_pUDPContext->append(pTxt->m_pcKey, os_strlen(pTxt->m_pcKey))) && // Key + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcKey))) && + (1 == m_pUDPContext->append("=", 1)) && // = + (p_rSendParameter.shiftOffset(1)) && + ((!pTxt->m_pcValue) || + (((size_t)os_strlen(pTxt->m_pcValue) == m_pUDPContext->append(pTxt->m_pcValue, os_strlen(pTxt->m_pcValue))) && // Value + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcValue)))))); + + DEBUG_EX_ERR(if (!bResult) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED to write %sTxt %s=%s!\n"), (pTxt->m_bTemp ? "temp. " : ""), (pTxt->m_pcKey ? : "?"), (pTxt->m_pcValue ? : "?")); + }); + } + } + _releaseTempServiceTxts(p_rService); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED!\n")); + }); + return bResult; +} + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_AAAA + + Write a MDNS AAAA answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + eg. esp8266.local AAAA 0x8001 120 16 xxxx::xx + http://www.zytrax.com/books/dns/ch8/aaaa.html +*/ +bool MDNSResponder::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA\n"));); + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_AAAA, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && // esp8266.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL + (_write16(MDNS_IP6_SIZE, p_rSendParameter)) && // RDLength + (false /*TODO: IP6 version of: _udpAppendBuffer((uint32_t)p_IPAddress, MDNS_IP4_SIZE)*/)); // RData + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_IP6 + + Write a MDNS reverse IP6 PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + eg. xxxx::xx.in6.arpa PTR 0x8001 120 15 esp8266.local + Used while answering reverse IP6 questions +*/ +bool MDNSResponder::_writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6\n"));); + + stcMDNS_RRDomain reverseIP6Domain; + stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + bool bResult = ((_buildDomainForReverseIP6(p_IPAddress, reverseIP6Domain)) && // xxxx::xx.ip6.arpa + (_writeMDNSRRDomain(reverseIP6Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL + (_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6: FAILED!\n")); + }); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_SRV + + eg. MyESP._http.tcp.local SRV 0x8001 120 0 0 60068 esp8266.local + http://www.zytrax.com/books/dns/ch8/srv.html ???? Include instance name ???? +*/ +bool MDNSResponder::_writeMDNSAnswer_SRV(MDNSResponder::stcMDNSService& p_rService, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV\n"));); + + uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyQuery + ? 0 + : p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostname, false)); + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_SRV, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + stcMDNS_RRDomain hostDomain; + bool bResult = ((_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL + (!u16CachedDomainOffset + // No cache for domain name (or no compression allowed) + ? ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (_write16((sizeof(uint16_t /*Prio*/) + // RDLength + sizeof(uint16_t /*Weight*/) + + sizeof(uint16_t /*Port*/) + + hostDomain.m_u16NameLength), p_rSendParameter)) && // Domain length + (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority + (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight + (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port + (p_rSendParameter.addDomainCacheItem((const void*)m_pcHostname, false, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(hostDomain, p_rSendParameter))) // Host, eg. esp8266.local + // Cache available for domain + : ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + (_write16((sizeof(uint16_t /*Prio*/) + // RDLength + sizeof(uint16_t /*Weight*/) + + sizeof(uint16_t /*Port*/) + + 2), p_rSendParameter)) && // Length of 'C0xx' + (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority + (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight + (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port + (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)u16CachedDomainOffset, p_rSendParameter))))); // Offset + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV: FAILED!\n")); + }); + return bResult; +} + +} // namespace MDNSImplementation + +} // namespace esp8266 + + + + + + diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h b/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h new file mode 100644 index 0000000000..a3bcc4b370 --- /dev/null +++ b/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h @@ -0,0 +1,44 @@ +/* + LEAmDNS_Priv.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef MDNS_LWIPDEFS_H +#define MDNS_LWIPDEFS_H + +#include +#if LWIP_VERSION_MAJOR == 1 + +#include // DNS_RRTYPE_xxx + +// cherry pick from lwip1 dns.c/mdns.c source files: +#define DNS_MQUERY_PORT 5353 +#define DNS_MQUERY_IPV4_GROUP_INIT IPAddress(224,0,0,251) /* resolver1.opendns.com */ +#define DNS_RRCLASS_ANY 255 /* any class */ + +#else // lwIP > 1 + +#include // DNS_RRTYPE_xxx, DNS_MQUERY_PORT + +#endif + +#endif // MDNS_LWIPDEFS_H From 0e692c3993ac222cd41bc2f33df63350ed2245ec Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 8 May 2020 21:45:55 +0200 Subject: [PATCH 07/12] add enableArduino() into LEAmDNSv2 --- .../OLDmDNS/ESP8266mDNS_Legacy.cpp | 1523 ---------- .../ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h | 166 -- libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp | 1381 --------- libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h | 1461 ---------- .../ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp | 2134 -------------- .../ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp | 850 ------ libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h | 182 -- .../ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp | 2476 ----------------- .../ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp | 1779 ------------ .../ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h | 44 - ...-mDNS-SPIFFS.ino => OTA-mDNS-LittleFS.ino} | 0 libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp | 30 + libraries/ESP8266mDNS/src/LEAmDNS2Host.h | 2 + 13 files changed, 32 insertions(+), 11996 deletions(-) delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h rename libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/{OTA-mDNS-SPIFFS.ino => OTA-mDNS-LittleFS.ino} (100%) diff --git a/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp b/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp deleted file mode 100644 index 8791195523..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp +++ /dev/null @@ -1,1523 +0,0 @@ -/* - - ESP8266 Multicast DNS (port of CC3000 Multicast DNS library) - Version 1.1 - Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) - ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com) - MDNS-SD Suport 2015 Hristo Gochkov - Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com) - - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -// Important RFC's for reference: -// - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt -// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt -// - MDNS-SD: https://tools.ietf.org/html/rfc6763 - -#ifndef LWIP_OPEN_SRC -#define LWIP_OPEN_SRC -#endif - -#include "ESP8266mDNS.h" -#include - -#include "debug.h" - -extern "C" { -#include "osapi.h" -#include "ets_sys.h" -#include "user_interface.h" -} - -#include "WiFiUdp.h" -#include "lwip/opt.h" -#include "lwip/udp.h" -#include "lwip/inet.h" -#include "lwip/igmp.h" -#include "lwip/mem.h" -#include "include/UdpContext.h" - - - -namespace Legacy_MDNSResponder -{ - - -#ifdef DEBUG_ESP_MDNS -#define DEBUG_ESP_MDNS_ERR -#define DEBUG_ESP_MDNS_TX -#define DEBUG_ESP_MDNS_RX -#endif - -#define MDNS_NAME_REF 0xC000 - -#define MDNS_TYPE_AAAA 0x001C -#define MDNS_TYPE_A 0x0001 -#define MDNS_TYPE_PTR 0x000C -#define MDNS_TYPE_SRV 0x0021 -#define MDNS_TYPE_TXT 0x0010 - -#define MDNS_CLASS_IN 0x0001 -#define MDNS_CLASS_IN_FLUSH_CACHE 0x8001 - -#define MDNS_ANSWERS_ALL 0x0F -#define MDNS_ANSWER_PTR 0x08 -#define MDNS_ANSWER_TXT 0x04 -#define MDNS_ANSWER_SRV 0x02 -#define MDNS_ANSWER_A 0x01 - -#define _conn_read32() (((uint32_t)_conn->read() << 24) | ((uint32_t)_conn->read() << 16) | ((uint32_t)_conn->read() << 8) | _conn->read()) -#define _conn_read16() (((uint16_t)_conn->read() << 8) | _conn->read()) -#define _conn_read8() _conn->read() -#define _conn_readS(b,l) _conn->read((char*)(b),l); - -static const IPAddress MDNS_MULTICAST_ADDR(224, 0, 0, 251); -static const int MDNS_MULTICAST_TTL = 1; -static const int MDNS_PORT = 5353; - -struct MDNSService -{ - MDNSService* _next; - char _name[32]; - char _proto[4]; - uint16_t _port; - uint16_t _txtLen; // length of all txts - struct MDNSTxt * _txts; -}; - -struct MDNSTxt -{ - MDNSTxt * _next; - String _txt; -}; - -struct MDNSAnswer -{ - MDNSAnswer* next; - uint8_t ip[4]; - uint16_t port; - char *hostname; -}; - -struct MDNSQuery -{ - char _service[32]; - char _proto[4]; -}; - - -MDNSResponder::MDNSResponder() : _conn(0) -{ - _services = 0; - _instanceName = ""; - _answers = 0; - _query = 0; - _newQuery = false; - _waitingForAnswers = false; -} -MDNSResponder::~MDNSResponder() -{ - if (_query != 0) - { - os_free(_query); - _query = 0; - } - - // Clear answer list - MDNSAnswer *answer; - int numAnswers = _getNumAnswers(); - for (int n = numAnswers - 1; n >= 0; n--) - { - answer = _getAnswerFromIdx(n); - os_free(answer->hostname); - os_free(answer); - answer = 0; - } - _answers = 0; - - if (_conn) - { - _conn->unref(); - } -} - -bool MDNSResponder::begin(const char* hostname) -{ - size_t n = strlen(hostname); - if (n > 63) // max size for a single label. - { - return false; - } - - // Copy in hostname characters as lowercase - _hostName = hostname; - _hostName.toLowerCase(); - - // If instance name is not already set copy hostname to instance name - if (_instanceName.equals("")) - { - _instanceName = hostname; - } - - _gotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & event) - { - (void) event; - _restart(); - }); - - _disconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & event) - { - (void) event; - _restart(); - }); - - return _listen(); -} - -void MDNSResponder::notifyAPChange() -{ - _restart(); -} - -void MDNSResponder::_restart() -{ - if (_conn) - { - _conn->unref(); - _conn = nullptr; - } - _listen(); -} - -bool MDNSResponder::_listen() -{ - // Open the MDNS socket if it isn't already open. - if (!_conn) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.println("MDNS listening"); -#endif - - IPAddress mdns(MDNS_MULTICAST_ADDR); - - if (igmp_joingroup(IP4_ADDR_ANY4, mdns) != ERR_OK) - { - return false; - } - - _conn = new UdpContext; - _conn->ref(); - - if (!_conn->listen(IP_ADDR_ANY, MDNS_PORT)) - { - return false; - } - _conn->setMulticastTTL(MDNS_MULTICAST_TTL); - _conn->onRx(std::bind(&MDNSResponder::update, this)); - _conn->connect(mdns, MDNS_PORT); - } - return true; -} - -void MDNSResponder::update() -{ - if (!_conn || !_conn->next()) - { - return; - } - _parsePacket(); -} - - -void MDNSResponder::setInstanceName(String name) -{ - if (name.length() > 63) - { - return; - } - _instanceName = name; -} - - -bool MDNSResponder::addServiceTxt(char *name, char *proto, char *key, char *value) -{ - MDNSService* servicePtr; - - uint8_t txtLen = os_strlen(key) + os_strlen(value) + 1; // Add one for equals sign - txtLen += 1; //accounts for length byte added when building the txt responce - //Find the service - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - //Checking Service names - if (strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) - { - //found a service name match - if (servicePtr->_txtLen + txtLen > 1300) - { - return false; //max txt record size - } - MDNSTxt *newtxt = new MDNSTxt; - newtxt->_txt = String(key) + '=' + String(value); - newtxt->_next = 0; - if (servicePtr->_txts == 0) //no services have been added - { - //Adding First TXT to service - servicePtr->_txts = newtxt; - servicePtr->_txtLen += txtLen; - return true; - } - else - { - MDNSTxt * txtPtr = servicePtr->_txts; - while (txtPtr->_next != 0) - { - txtPtr = txtPtr->_next; - } - //adding another TXT to service - txtPtr->_next = newtxt; - servicePtr->_txtLen += txtLen; - return true; - } - } - } - return false; -} - -void MDNSResponder::addService(char *name, char *proto, uint16_t port) -{ - if (_getServicePort(name, proto) != 0) - { - return; - } - if (os_strlen(name) > 32 || os_strlen(proto) != 3) - { - return; //bad arguments - } - struct MDNSService *srv = (struct MDNSService*)(os_malloc(sizeof(struct MDNSService))); - os_strcpy(srv->_name, name); - os_strcpy(srv->_proto, proto); - srv->_port = port; - srv->_next = 0; - srv->_txts = 0; - srv->_txtLen = 0; - - if (_services == 0) - { - _services = srv; - } - else - { - MDNSService* servicePtr = _services; - while (servicePtr->_next != 0) - { - servicePtr = servicePtr->_next; - } - servicePtr->_next = srv; - } - -} - -int MDNSResponder::queryService(char *service, char *proto) -{ -#ifdef DEBUG_ESP_MDNS_TX - DEBUG_ESP_PORT.printf("queryService %s %s\n", service, proto); -#endif - while (_answers != 0) - { - MDNSAnswer *currAnswer = _answers; - _answers = _answers->next; - os_free(currAnswer->hostname); - os_free(currAnswer); - currAnswer = 0; - } - if (_query != 0) - { - os_free(_query); - _query = 0; - } - _query = (struct MDNSQuery*)(os_malloc(sizeof(struct MDNSQuery))); - os_strcpy(_query->_service, service); - os_strcpy(_query->_proto, proto); - _newQuery = true; - - char underscore[] = "_"; - - // build service name with _ - char serviceName[os_strlen(service) + 2]; - os_strcpy(serviceName, underscore); - os_strcat(serviceName, service); - size_t serviceNameLen = os_strlen(serviceName); - - //build proto name with _ - char protoName[5]; - os_strcpy(protoName, underscore); - os_strcat(protoName, proto); - size_t protoNameLen = 4; - - //local string - char localName[] = "local"; - size_t localNameLen = 5; - - //terminator - char terminator[] = "\0"; - - // Only supports sending one PTR query - uint8_t questionCount = 1; - - _waitingForAnswers = true; - for (int itfn = 0; itfn < 2; itfn++) - { - struct ip_info ip_info; - - wifi_get_ip_info((!itfn) ? SOFTAP_IF : STATION_IF, &ip_info); - if (!ip_info.ip.addr) - { - continue; - } - _conn->setMulticastInterface(IPAddress(ip_info.ip.addr)); - - // Write the header - _conn->flush(); - uint8_t head[12] = - { - 0x00, 0x00, //ID = 0 - 0x00, 0x00, //Flags = response + authoritative answer - 0x00, questionCount, //Question count - 0x00, 0x00, //Answer count - 0x00, 0x00, //Name server records - 0x00, 0x00 //Additional records - }; - _conn->append(reinterpret_cast(head), 12); - - // Only supports sending one PTR query - // Send the Name field (eg. "_http._tcp.local") - _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_" + service - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_" + service - _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_" + proto - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_" + proto - _conn->append(reinterpret_cast(&localNameLen), 1); // lenght of "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type and class - uint8_t ptrAttrs[4] = - { - 0x00, 0x0c, //PTR record query - 0x00, 0x01 //Class IN - }; - _conn->append(reinterpret_cast(ptrAttrs), 4); - _conn->send(); - } - -#ifdef DEBUG_ESP_MDNS_TX - DEBUG_ESP_PORT.println("Waiting for answers.."); -#endif - delay(1000); - - _waitingForAnswers = false; - - return _getNumAnswers(); -} - -String MDNSResponder::hostname(int idx) -{ - MDNSAnswer *answer = _getAnswerFromIdx(idx); - if (answer == 0) - { - return String(); - } - return answer->hostname; -} - -IPAddress MDNSResponder::IP(int idx) -{ - MDNSAnswer *answer = _getAnswerFromIdx(idx); - if (answer == 0) - { - return IPAddress(); - } - return IPAddress(answer->ip); -} - -uint16_t MDNSResponder::port(int idx) -{ - MDNSAnswer *answer = _getAnswerFromIdx(idx); - if (answer == 0) - { - return 0; - } - return answer->port; -} - -MDNSAnswer* MDNSResponder::_getAnswerFromIdx(int idx) -{ - MDNSAnswer *answer = _answers; - while (answer != 0 && idx-- > 0) - { - answer = answer->next; - } - if (idx > 0) - { - return 0; - } - return answer; -} - -int MDNSResponder::_getNumAnswers() -{ - int numAnswers = 0; - MDNSAnswer *answer = _answers; - while (answer != 0) - { - numAnswers++; - answer = answer->next; - } - return numAnswers; -} - -MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto) -{ - MDNSService* servicePtr; - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - if (servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) - { - if (servicePtr->_txts == 0) - { - return nullptr; - } - return servicePtr->_txts; - } - } - return nullptr; -} - -uint16_t MDNSResponder::_getServiceTxtLen(char *name, char *proto) -{ - MDNSService* servicePtr; - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - if (servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) - { - if (servicePtr->_txts == 0) - { - return false; - } - return servicePtr->_txtLen; - } - } - return 0; -} - -uint16_t MDNSResponder::_getServicePort(char *name, char *proto) -{ - MDNSService* servicePtr; - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - if (servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) - { - return servicePtr->_port; - } - } - return 0; -} - -IPAddress MDNSResponder::_getRequestMulticastInterface() -{ - struct ip_info ip_info; - bool match_ap = false; - if (wifi_get_opmode() & SOFTAP_MODE) - { - const IPAddress& remote_ip = _conn->getRemoteAddress(); - wifi_get_ip_info(SOFTAP_IF, &ip_info); - IPAddress infoIp(ip_info.ip); - IPAddress infoMask(ip_info.netmask); - if (ip_info.ip.addr && ip_addr_netcmp((const ip_addr_t*)remote_ip, (const ip_addr_t*)infoIp, ip_2_ip4((const ip_addr_t*)infoMask))) - { - match_ap = true; - } - } - if (!match_ap) - { - wifi_get_ip_info(STATION_IF, &ip_info); - } - return IPAddress(ip_info.ip.addr); -} - -void MDNSResponder::_parsePacket() -{ - int i; - char tmp; - bool serviceParsed = false; - bool protoParsed = false; - bool localParsed = false; - - char hostName[255]; - uint8_t hostNameLen; - - char serviceName[32]; - uint8_t serviceNameLen; - uint16_t servicePort = 0; - - char protoName[32]; - protoName[0] = 0; - uint8_t protoNameLen = 0; - - uint16_t packetHeader[6]; - - for (i = 0; i < 6; i++) - { - packetHeader[i] = _conn_read16(); - } - - if ((packetHeader[1] & 0x8000) != 0) // Read answers - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("Reading answers RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]); -#endif - - if (!_waitingForAnswers) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.println("Not expecting any answers right now, returning"); -#endif - _conn->flush(); - return; - } - - int numAnswers = packetHeader[3] + packetHeader[5]; - // Assume that the PTR answer always comes first and that it is always accompanied by a TXT, SRV, AAAA (optional) and A answer in the same packet. - if (numAnswers < 4) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("Expected a packet with 4 or more answers, got %u\n", numAnswers); -#endif - _conn->flush(); - return; - } - - uint8_t tmp8; - uint16_t answerPort = 0; - uint8_t answerIp[4] = { 0, 0, 0, 0 }; - char answerHostName[255]; - bool serviceMatch = false; - MDNSAnswer *answer; - uint8_t partsCollected = 0; - uint8_t stringsRead = 0; - - answerHostName[0] = '\0'; - - // Clear answer list - if (_newQuery) - { - int oldAnswers = _getNumAnswers(); - for (int n = oldAnswers - 1; n >= 0; n--) - { - answer = _getAnswerFromIdx(n); - os_free(answer->hostname); - os_free(answer); - answer = 0; - } - _answers = 0; - _newQuery = false; - } - - while (numAnswers--) - { - // Read name - stringsRead = 0; - size_t last_bufferpos = 0; - do - { - tmp8 = _conn_read8(); - if (tmp8 == 0x00) // End of name - { - break; - } - if (tmp8 & 0xC0) // Compressed pointer - { - uint16_t offset = ((((uint16_t)tmp8) & ~0xC0) << 8) | _conn_read8(); - if (_conn->isValidOffset(offset)) - { - if (0 == last_bufferpos) - { - last_bufferpos = _conn->tell(); - } -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Compressed pointer, jumping from "); - DEBUG_ESP_PORT.print(last_bufferpos); - DEBUG_ESP_PORT.print(" to "); - DEBUG_ESP_PORT.println(offset); -#endif - _conn->seek(offset); - tmp8 = _conn_read8(); - } - else - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Skipping malformed compressed pointer"); -#endif - tmp8 = _conn_read8(); - break; - } - } - if (stringsRead > 3) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.println("failed to read the response name"); -#endif - _conn->flush(); - return; - } - _conn_readS(serviceName, tmp8); - serviceName[tmp8] = '\0'; -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf(" %d ", tmp8); - for (int n = 0; n < tmp8; n++) - { - DEBUG_ESP_PORT.printf("%c", serviceName[n]); - } - DEBUG_ESP_PORT.println(); -#endif - if (serviceName[0] == '_') - { - if (strcmp(&serviceName[1], _query->_service) == 0) - { - serviceMatch = true; -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("found matching service: %s\n", _query->_service); -#endif - } - } - stringsRead++; - } while (true); - if (last_bufferpos > 0) - { - _conn->seek(last_bufferpos); -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Compressed pointer, jumping back to "); - DEBUG_ESP_PORT.println(last_bufferpos); -#endif - } - - uint16_t answerType = _conn_read16(); // Read type - uint16_t answerClass = _conn_read16(); // Read class - uint32_t answerTtl = _conn_read32(); // Read ttl - uint16_t answerRdlength = _conn_read16(); // Read rdlength - - (void) answerClass; - (void) answerTtl; - - if (answerRdlength > 255) - { - if (answerType == MDNS_TYPE_TXT && answerRdlength < 1460) - { - while (--answerRdlength) - { - _conn->read(); - } - } - else - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("Data len too long! %u\n", answerRdlength); -#endif - _conn->flush(); - return; - } - } - -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("type: %04x rdlength: %d\n", answerType, answerRdlength); -#endif - - if (answerType == MDNS_TYPE_PTR) - { - partsCollected |= 0x01; - _conn_readS(hostName, answerRdlength); // Read rdata - if (hostName[answerRdlength - 2] & 0xc0) - { - memcpy(answerHostName, hostName + 1, answerRdlength - 3); - answerHostName[answerRdlength - 3] = '\0'; - } -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("PTR %d ", answerRdlength); - for (int n = 0; n < answerRdlength; n++) - { - DEBUG_ESP_PORT.printf("%c", hostName[n]); - } - DEBUG_ESP_PORT.println(); -#endif - } - - else if (answerType == MDNS_TYPE_TXT) - { - partsCollected |= 0x02; - _conn_readS(hostName, answerRdlength); // Read rdata -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("TXT %d ", answerRdlength); - for (int n = 0; n < answerRdlength; n++) - { - DEBUG_ESP_PORT.printf("%c", hostName[n]); - } - DEBUG_ESP_PORT.println(); -#endif - } - - else if (answerType == MDNS_TYPE_SRV) - { - partsCollected |= 0x04; - uint16_t answerPrio = _conn_read16(); // Read priority - uint16_t answerWeight = _conn_read16(); // Read weight - answerPort = _conn_read16(); // Read port - last_bufferpos = 0; - - (void) answerPrio; - (void) answerWeight; - - // Read hostname - tmp8 = _conn_read8(); - if (tmp8 & 0xC0) // Compressed pointer - { - uint16_t offset = ((((uint16_t)tmp8) & ~0xC0) << 8) | _conn_read8(); - if (_conn->isValidOffset(offset)) - { - last_bufferpos = _conn->tell(); -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Compressed pointer, jumping from "); - DEBUG_ESP_PORT.print(last_bufferpos); - DEBUG_ESP_PORT.print(" to "); - DEBUG_ESP_PORT.println(offset); -#endif - _conn->seek(offset); - tmp8 = _conn_read8(); - } - else - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Skipping malformed compressed pointer"); -#endif - tmp8 = _conn_read8(); - break; - } - } - _conn_readS(answerHostName, tmp8); - answerHostName[tmp8] = '\0'; -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("SRV %d ", tmp8); - for (int n = 0; n < tmp8; n++) - { - DEBUG_ESP_PORT.printf("%02x ", answerHostName[n]); - } - DEBUG_ESP_PORT.printf("\n%s\n", answerHostName); -#endif - if (last_bufferpos > 0) - { - _conn->seek(last_bufferpos); - tmp8 = 2; // Size of compression octets -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Compressed pointer, jumping back to "); - DEBUG_ESP_PORT.println(last_bufferpos); -#endif - } - if (answerRdlength - (6 + 1 + tmp8) > 0) // Skip any remaining rdata - { - _conn_readS(hostName, answerRdlength - (6 + 1 + tmp8)); - } - } - - else if (answerType == MDNS_TYPE_A) - { - partsCollected |= 0x08; - for (int i = 0; i < 4; i++) - { - answerIp[i] = _conn_read8(); - } - } - else - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("Ignoring unsupported type %02x\n", tmp8); -#endif - for (int n = 0; n < answerRdlength; n++) - { - (void)_conn_read8(); - } - } - - if ((partsCollected == 0x0F) && serviceMatch) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.println("All answers parsed, adding to _answers list.."); -#endif - // Add new answer to answer list - if (_answers == 0) - { - _answers = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer))); - answer = _answers; - } - else - { - answer = _answers; - while (answer->next != 0) - { - answer = answer->next; - } - answer->next = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer))); - answer = answer->next; - } - answer->next = 0; - answer->hostname = 0; - - // Populate new answer - answer->port = answerPort; - for (int i = 0; i < 4; i++) - { - answer->ip[i] = answerIp[i]; - } - answer->hostname = (char *)os_malloc(strlen(answerHostName) + 1); - os_strcpy(answer->hostname, answerHostName); - _conn->flush(); - return; - } - } - - _conn->flush(); - return; - } - - // PARSE REQUEST NAME - - hostNameLen = _conn_read8() % 255; - _conn_readS(hostName, hostNameLen); - hostName[hostNameLen] = '\0'; - - if (hostName[0] == '_') - { - serviceParsed = true; - memcpy(serviceName, hostName + 1, hostNameLen); - serviceNameLen = hostNameLen - 1; - hostNameLen = 0; - } - - if (hostNameLen > 0 && !_hostName.equals(hostName) && !_instanceName.equals(hostName)) - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_NO_HOST: %s\n", hostName); - DEBUG_ESP_PORT.printf("hostname: %s\n", _hostName.c_str()); - DEBUG_ESP_PORT.printf("instance: %s\n", _instanceName.c_str()); -#endif - _conn->flush(); - return; - } - - if (!serviceParsed) - { - serviceNameLen = _conn_read8() % 255; - _conn_readS(serviceName, serviceNameLen); - serviceName[serviceNameLen] = '\0'; - - if (serviceName[0] == '_') - { - memmove(serviceName, serviceName + 1, serviceNameLen); - serviceNameLen--; - serviceParsed = true; - } - else if (serviceNameLen == 5 && strcmp("local", serviceName) == 0) - { - tmp = _conn_read8(); - if (tmp == 0) - { - serviceParsed = true; - serviceNameLen = 0; - protoParsed = true; - protoNameLen = 0; - localParsed = true; - } - else - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_FQDN: %s\n", serviceName); -#endif - _conn->flush(); - return; - } - } - else - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_SERVICE: %s\n", serviceName); -#endif - _conn->flush(); - return; - } - } - - if (!protoParsed) - { - protoNameLen = _conn_read8() % 255; - _conn_readS(protoName, protoNameLen); - protoName[protoNameLen] = '\0'; - if (protoNameLen == 4 && protoName[0] == '_') - { - memmove(protoName, protoName + 1, protoNameLen); - protoNameLen--; - protoParsed = true; - } - else if (strcmp("services", serviceName) == 0 && strcmp("_dns-sd", protoName) == 0) - { - _conn->flush(); - IPAddress interface = _getRequestMulticastInterface(); - _replyToTypeEnumRequest(interface); - return; - } - else - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_PROTO: %s\n", protoName); -#endif - _conn->flush(); - return; - } - } - - if (!localParsed) - { - char localName[32]; - uint8_t localNameLen = _conn_read8() % 31; - _conn_readS(localName, localNameLen); - localName[localNameLen] = '\0'; - tmp = _conn_read8(); - if (localNameLen == 5 && strcmp("local", localName) == 0 && tmp == 0) - { - localParsed = true; - } - else - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_FQDN: %s\n", localName); -#endif - _conn->flush(); - return; - } - } - - if (serviceNameLen > 0 && protoNameLen > 0) - { - servicePort = _getServicePort(serviceName, protoName); - if (servicePort == 0) - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_NO_SERVICE: %s\n", serviceName); -#endif - _conn->flush(); - return; - } - } - else if (serviceNameLen > 0 || protoNameLen > 0) - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_SERVICE_PROTO: %s\n", serviceName); -#endif - _conn->flush(); - return; - } - - // RESPOND - -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]); -#endif - - uint16_t currentType; - uint16_t currentClass; - - int numQuestions = packetHeader[2]; - if (numQuestions > 4) - { - numQuestions = 4; - } - uint16_t questions[4]; - int question = 0; - - while (numQuestions--) - { - currentType = _conn_read16(); - if (currentType & MDNS_NAME_REF) //new header handle it better! - { - currentType = _conn_read16(); - } - currentClass = _conn_read16(); - if (currentClass & MDNS_CLASS_IN) - { - questions[question++] = currentType; - } - - if (numQuestions > 0) - { - if (_conn_read16() != 0xC00C) //new question but for another host/service - { - _conn->flush(); - numQuestions = 0; - } - } - -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("REQ: "); - if (hostNameLen > 0) - { - DEBUG_ESP_PORT.printf("%s.", hostName); - } - if (serviceNameLen > 0) - { - DEBUG_ESP_PORT.printf("_%s.", serviceName); - } - if (protoNameLen > 0) - { - DEBUG_ESP_PORT.printf("_%s.", protoName); - } - DEBUG_ESP_PORT.printf("local. "); - - if (currentType == MDNS_TYPE_AAAA) - { - DEBUG_ESP_PORT.printf(" AAAA "); - } - else if (currentType == MDNS_TYPE_A) - { - DEBUG_ESP_PORT.printf(" A "); - } - else if (currentType == MDNS_TYPE_PTR) - { - DEBUG_ESP_PORT.printf(" PTR "); - } - else if (currentType == MDNS_TYPE_SRV) - { - DEBUG_ESP_PORT.printf(" SRV "); - } - else if (currentType == MDNS_TYPE_TXT) - { - DEBUG_ESP_PORT.printf(" TXT "); - } - else - { - DEBUG_ESP_PORT.printf(" 0x%04X ", currentType); - } - - if (currentClass == MDNS_CLASS_IN) - { - DEBUG_ESP_PORT.printf(" IN "); - } - else if (currentClass == MDNS_CLASS_IN_FLUSH_CACHE) - { - DEBUG_ESP_PORT.printf(" IN[F] "); - } - else - { - DEBUG_ESP_PORT.printf(" 0x%04X ", currentClass); - } - - DEBUG_ESP_PORT.printf("\n"); -#endif - } - uint8_t questionMask = 0; - uint8_t responseMask = 0; - for (i = 0; i < question; i++) - { - if (questions[i] == MDNS_TYPE_A) - { - questionMask |= 0x1; - responseMask |= 0x1; - } - else if (questions[i] == MDNS_TYPE_SRV) - { - questionMask |= 0x2; - responseMask |= 0x3; - } - else if (questions[i] == MDNS_TYPE_TXT) - { - questionMask |= 0x4; - responseMask |= 0x4; - } - else if (questions[i] == MDNS_TYPE_PTR) - { - questionMask |= 0x8; - responseMask |= 0xF; - } - } - - IPAddress interface = _getRequestMulticastInterface(); - return _replyToInstanceRequest(questionMask, responseMask, serviceName, protoName, servicePort, interface); -} - - -/** - STRINGIZE -*/ -#ifndef STRINGIZE -#define STRINGIZE(x) #x -#endif -#ifndef STRINGIZE_VALUE_OF -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) -#endif - - -void MDNSResponder::enableArduino(uint16_t port, bool auth) -{ - - addService("arduino", "tcp", port); - addServiceTxt("arduino", "tcp", "tcp_check", "no"); - addServiceTxt("arduino", "tcp", "ssh_upload", "no"); - addServiceTxt("arduino", "tcp", "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD)); - addServiceTxt("arduino", "tcp", "auth_upload", (auth) ? "yes" : "no"); -} - -void MDNSResponder::_replyToTypeEnumRequest(IPAddress multicastInterface) -{ - MDNSService* servicePtr; - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - if (servicePtr->_port > 0) - { - char *service = servicePtr->_name; - char *proto = servicePtr->_proto; - //uint16_t port = servicePtr->_port; - -#ifdef DEBUG_ESP_MDNS_TX - DEBUG_ESP_PORT.printf("TX: service:%s, proto:%s\n", service, proto); -#endif - - char sdHostName[] = "_services"; - size_t sdHostNameLen = 9; - char sdServiceName[] = "_dns-sd"; - size_t sdServiceNameLen = 7; - char sdProtoName[] = "_udp"; - size_t sdProtoNameLen = 4; - - char underscore[] = "_"; - - // build service name with _ - char serviceName[os_strlen(service) + 2]; - os_strcpy(serviceName, underscore); - os_strcat(serviceName, service); - size_t serviceNameLen = os_strlen(serviceName); - - //build proto name with _ - char protoName[5]; - os_strcpy(protoName, underscore); - os_strcat(protoName, proto); - size_t protoNameLen = 4; - - //local string - char localName[] = "local"; - size_t localNameLen = 5; - - //terminator - char terminator[] = "\0"; - - //Write the header - _conn->flush(); - uint8_t head[12] = - { - 0x00, 0x00, //ID = 0 - 0x84, 0x00, //Flags = response + authoritative answer - 0x00, 0x00, //Question count - 0x00, 0x01, //Answer count - 0x00, 0x00, //Name server records - 0x00, 0x00, //Additional records - }; - _conn->append(reinterpret_cast(head), 12); - - // Send the Name field (ie. "_services._dns-sd._udp.local") - _conn->append(reinterpret_cast(&sdHostNameLen), 1); // length of "_services" - _conn->append(reinterpret_cast(sdHostName), sdHostNameLen); // "_services" - _conn->append(reinterpret_cast(&sdServiceNameLen), 1); // length of "_dns-sd" - _conn->append(reinterpret_cast(sdServiceName), sdServiceNameLen);// "_dns-sd" - _conn->append(reinterpret_cast(&sdProtoNameLen), 1); // length of "_udp" - _conn->append(reinterpret_cast(sdProtoName), sdProtoNameLen); // "_udp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type, class, ttl and rdata length - uint8_t ptrDataLen = serviceNameLen + protoNameLen + localNameLen + 4; // 4 is three label sizes and the terminator - uint8_t ptrAttrs[10] = - { - 0x00, 0x0c, //PTR record query - 0x00, 0x01, //Class IN - 0x00, 0x00, 0x11, 0x94, //TTL 4500 - 0x00, ptrDataLen, //RData length - }; - _conn->append(reinterpret_cast(ptrAttrs), 10); - - //Send the RData (ie. "_http._tcp.local") - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - _conn->setMulticastInterface(multicastInterface); - _conn->send(); - } - } -} - -void MDNSResponder::_replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface) -{ - int i; - if (questionMask == 0) - { - return; - } - if (responseMask == 0) - { - return; - } - -#ifdef DEBUG_ESP_MDNS_TX - DEBUG_ESP_PORT.printf("TX: qmask:%01X, rmask:%01X, service:%s, proto:%s, port:%u\n", questionMask, responseMask, service, proto, port); -#endif - - - String instanceName = _instanceName; - size_t instanceNameLen = instanceName.length(); - - String hostName = _hostName; - size_t hostNameLen = hostName.length(); - - char underscore[] = "_"; - - // build service name with _ - char serviceName[os_strlen(service) + 2]; - os_strcpy(serviceName, underscore); - os_strcat(serviceName, service); - size_t serviceNameLen = os_strlen(serviceName); - - //build proto name with _ - char protoName[5]; - os_strcpy(protoName, underscore); - os_strcat(protoName, proto); - size_t protoNameLen = 4; - - //local string - char localName[] = "local"; - size_t localNameLen = 5; - - //terminator - char terminator[] = "\0"; - - uint8_t answerMask = responseMask & questionMask; - uint8_t answerCount = 0; - uint8_t additionalMask = responseMask & ~questionMask; - uint8_t additionalCount = 0; - for (i = 0; i < 4; i++) - { - if (answerMask & (1 << i)) - { - answerCount++; - } - if (additionalMask & (1 << i)) - { - additionalCount++; - } - } - - - //Write the header - _conn->flush(); - uint8_t head[12] = - { - 0x00, 0x00, //ID = 0 - 0x84, 0x00, //Flags = response + authoritative answer - 0x00, 0x00, //Question count - 0x00, answerCount, //Answer count - 0x00, 0x00, //Name server records - 0x00, additionalCount, //Additional records - }; - _conn->append(reinterpret_cast(head), 12); - - for (int responseSection = 0; responseSection < 2; ++responseSection) - { - - // PTR Response - if ((responseSection == 0 ? answerMask : additionalMask) & 0x8) - { - // Send the Name field (ie. "_http._tcp.local") - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type, class, ttl and rdata length - uint8_t ptrDataLen = instanceNameLen + serviceNameLen + protoNameLen + localNameLen + 5; // 5 is four label sizes and the terminator - uint8_t ptrAttrs[10] = - { - 0x00, 0x0c, //PTR record query - 0x00, 0x01, //Class IN - 0x00, 0x00, 0x00, 0x78, //TTL 120 - 0x00, ptrDataLen, //RData length - }; - _conn->append(reinterpret_cast(ptrAttrs), 10); - - //Send the RData (ie. "My IOT device._http._tcp.local") - _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" - _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - } - - //TXT Responce - if ((responseSection == 0 ? answerMask : additionalMask) & 0x4) - { - //Send the name field (ie. "My IOT device._http._tcp.local") - _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" - _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type, class, ttl and rdata length - uint8_t txtDataLen = _getServiceTxtLen(service, proto); - uint8_t txtAttrs[10] = - { - 0x00, 0x10, //TXT record query - 0x80, 0x01, //Class IN, with cache flush - 0x00, 0x00, 0x11, 0x94, //TTL 4500 - 0x00, txtDataLen, //RData length - }; - _conn->append(reinterpret_cast(txtAttrs), 10); - - //Send the RData - MDNSTxt * txtPtr = _getServiceTxt(service, proto); - while (txtPtr != 0) - { - uint8_t txtLen = txtPtr->_txt.length(); - _conn->append(reinterpret_cast(&txtLen), 1); // length of txt - _conn->append(reinterpret_cast(txtPtr->_txt.c_str()), txtLen);// the txt - txtPtr = txtPtr->_next; - } - } - - - //SRV Responce - if ((responseSection == 0 ? answerMask : additionalMask) & 0x2) - { - //Send the name field (ie. "My IOT device._http._tcp.local") - _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" - _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type, class, ttl, rdata length, priority and weight - uint8_t srvDataSize = hostNameLen + localNameLen + 3; // 3 is 2 lable size bytes and the terminator - srvDataSize += 6; // Size of Priority, weight and port - uint8_t srvAttrs[10] = - { - 0x00, 0x21, //Type SRV - 0x80, 0x01, //Class IN, with cache flush - 0x00, 0x00, 0x00, 0x78, //TTL 120 - 0x00, srvDataSize, //RData length - }; - _conn->append(reinterpret_cast(srvAttrs), 10); - - //Send the RData Priority weight and port - uint8_t srvRData[6] = - { - 0x00, 0x00, //Priority 0 - 0x00, 0x00, //Weight 0 - (uint8_t)((port >> 8) & 0xFF), (uint8_t)(port & 0xFF) - }; - _conn->append(reinterpret_cast(srvRData), 6); - //Send the RData (ie. "esp8266.local") - _conn->append(reinterpret_cast(&hostNameLen), 1); // length of "esp8266" - _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - } - - // A Response - if ((responseSection == 0 ? answerMask : additionalMask) & 0x1) - { - //Send the RData (ie. "esp8266.local") - _conn->append(reinterpret_cast(&hostNameLen), 1); // length of "esp8266" - _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - uint8_t aaaAttrs[10] = - { - 0x00, 0x01, //TYPE A - 0x80, 0x01, //Class IN, with cache flush - 0x00, 0x00, 0x00, 0x78, //TTL 120 - 0x00, 0x04, //DATA LEN - }; - _conn->append(reinterpret_cast(aaaAttrs), 10); - - // Send RData - uint32_t ip = multicastInterface; - uint8_t aaaRData[4] = - { - (uint8_t)(ip & 0xFF), //IP first octet - (uint8_t)((ip >> 8) & 0xFF), //IP second octet - (uint8_t)((ip >> 16) & 0xFF), //IP third octet - (uint8_t)((ip >> 24) & 0xFF) //IP fourth octet - }; - _conn->append(reinterpret_cast(aaaRData), 4); - } - } - - _conn->setMulticastInterface(multicastInterface); - _conn->send(); -} - -#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) -MDNSResponder MDNS; -#endif - -} // namespace Legacy_MDNSResponder - - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h b/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h deleted file mode 100644 index 9d3cfd2f62..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - ESP8266 Multicast DNS (port of CC3000 Multicast DNS library) - Version 1.1 - Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) - ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com) - Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com) - - This is a simple implementation of multicast DNS query support for an Arduino - running on ESP8266 chip. Only support for resolving address queries is currently - implemented. - - Requirements: - - ESP8266WiFi library - - Usage: - - Include the ESP8266 Multicast DNS library in the sketch. - - Call the begin method in the sketch's setup and provide a domain name (without - the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the - Adafruit CC3000 class instance. Optionally provide a time to live (in seconds) - for the DNS record--the default is 1 hour. - - Call the update method in each iteration of the sketch's loop function. - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ -#ifndef ESP8266MDNS_LEGACY_H -#define ESP8266MDNS_LEGACY_H - -#include "ESP8266WiFi.h" -#include "WiFiUdp.h" - -//this should be defined at build time -#ifndef ARDUINO_BOARD -#define ARDUINO_BOARD "generic" -#endif - -class UdpContext; - - -namespace Legacy_MDNSResponder -{ - - -struct MDNSService; -struct MDNSTxt; -struct MDNSAnswer; - -class MDNSResponder -{ -public: - MDNSResponder(); - ~MDNSResponder(); - bool begin(const char* hostName); - bool begin(const String& hostName) - { - return begin(hostName.c_str()); - } - //for compatibility - bool begin(const char* hostName, IPAddress ip, uint32_t ttl = 120) - { - (void) ip; - (void) ttl; - return begin(hostName); - } - bool begin(const String& hostName, IPAddress ip, uint32_t ttl = 120) - { - return begin(hostName.c_str(), ip, ttl); - } - /* Application should call this whenever AP is configured/disabled */ - void notifyAPChange(); - void update(); - - void addService(char *service, char *proto, uint16_t port); - void addService(const char *service, const char *proto, uint16_t port) - { - addService((char *)service, (char *)proto, port); - } - void addService(const String& service, const String& proto, uint16_t port) - { - addService(service.c_str(), proto.c_str(), port); - } - - bool addServiceTxt(char *name, char *proto, char * key, char * value); - bool addServiceTxt(const char *name, const char *proto, const char *key, const char * value) - { - return addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value); - } - bool addServiceTxt(const String& name, const String& proto, const String& key, const String& value) - { - return addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str()); - } - - int queryService(char *service, char *proto); - int queryService(const char *service, const char *proto) - { - return queryService((char *)service, (char *)proto); - } - int queryService(const String& service, const String& proto) - { - return queryService(service.c_str(), proto.c_str()); - } - String hostname(int idx); - IPAddress IP(int idx); - uint16_t port(int idx); - - void enableArduino(uint16_t port, bool auth = false); - - void setInstanceName(String name); - void setInstanceName(const char * name) - { - setInstanceName(String(name)); - } - void setInstanceName(char * name) - { - setInstanceName(String(name)); - } - -private: - struct MDNSService * _services; - UdpContext* _conn; - String _hostName; - String _instanceName; - struct MDNSAnswer * _answers; - struct MDNSQuery * _query; - bool _newQuery; - bool _waitingForAnswers; - WiFiEventHandler _disconnectedHandler; - WiFiEventHandler _gotIPHandler; - - - uint16_t _getServicePort(char *service, char *proto); - MDNSTxt * _getServiceTxt(char *name, char *proto); - uint16_t _getServiceTxtLen(char *name, char *proto); - IPAddress _getRequestMulticastInterface(); - void _parsePacket(); - void _replyToTypeEnumRequest(IPAddress multicastInterface); - void _replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface); - MDNSAnswer* _getAnswerFromIdx(int idx); - int _getNumAnswers(); - bool _listen(); - void _restart(); -}; - -} // namespace Legacy_MDNSResponder - -#endif //ESP8266MDNS_H - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp deleted file mode 100644 index 87ff5167ff..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp +++ /dev/null @@ -1,1381 +0,0 @@ -/* - LEAmDNS.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include -#include - -#include "LEAmDNS_Priv.h" - - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - STRINGIZE -*/ -#ifndef STRINGIZE -#define STRINGIZE(x) #x -#endif -#ifndef STRINGIZE_VALUE_OF -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) -#endif - - -/** - INTERFACE -*/ - -/** - MDNSResponder::MDNSResponder -*/ -MDNSResponder::MDNSResponder(void) - : m_pServices(0), - m_pUDPContext(0), - m_pcHostname(0), - m_pServiceQueries(0), - m_fnServiceTxtCallback(0), -#ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE - m_bPassivModeEnabled(true), -#else - m_bPassivModeEnabled(false), -#endif - m_netif(nullptr) -{ -} - -/* - MDNSResponder::~MDNSResponder -*/ -MDNSResponder::~MDNSResponder(void) -{ - - _resetProbeStatus(false); - _releaseServiceQueries(); - _releaseHostname(); - _releaseUDPContext(); - _releaseServices(); -} - -/* - MDNSResponder::begin - - Set the host domain (for probing) and install WiFi event handlers for - IP assignment and disconnection management. In both cases, the MDNS responder - is restarted (reset and restart probe status) - Finally the responder is (re)started - -*/ -bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress, uint32_t p_u32TTL) -{ - - (void)p_u32TTL; // ignored - bool bResult = false; - - if (0 == m_pUDPContext) - { - if (_setHostname(p_pcHostname)) - { - - //// select interface - - m_netif = nullptr; - IPAddress ipAddress = p_IPAddress; - - if (!ipAddress.isSet()) - { - - IPAddress sta = WiFi.localIP(); - IPAddress ap = WiFi.softAPIP(); - - if (sta.isSet()) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] STA interface selected\n"))); - ipAddress = sta; - } - else if (ap.isSet()) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] AP interface selected\n"))); - ipAddress = ap; - } - else - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] standard interfaces are not up, please specify one in ::begin()\n"))); - return false; - } - - // continue to ensure interface is UP - } - - // check existence of this IP address in the interface list - bool found = false; - m_netif = nullptr; - for (auto a : addrList) - if (ipAddress == a.addr()) - { - if (a.ifUp()) - { - found = true; - m_netif = a.interface(); - break; - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] found interface for IP '%s' but it is not UP\n"), ipAddress.toString().c_str());); - } - if (!found) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] interface defined by IP '%s' not found\n"), ipAddress.toString().c_str());); - return false; - } - - //// done selecting the interface - - if (m_netif->num == STATION_IF) - { - - m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & pEvent) - { - (void) pEvent; - // Ensure that _restart() runs in USER context - schedule_function([this]() - { - MDNSResponder::_restart(); - }); - }); - - m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & pEvent) - { - (void) pEvent; - // Ensure that _restart() runs in USER context - schedule_function([this]() - { - MDNSResponder::_restart(); - }); - }); - } - - bResult = _restart(); - } - DEBUG_EX_ERR(if (!bResult) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: FAILED for '%s'!\n"), (p_pcHostname ? : "-")); - }); - } - else - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: Ignoring multiple calls to begin (Ignored host domain: '%s')!\n"), (p_pcHostname ? : "-"));); - } - return bResult; -} - -/* - MDNSResponder::close - - Ends the MDNS responder. - Announced services are unannounced (by multicasting a goodbye message) - -*/ -bool MDNSResponder::close(void) -{ - bool bResult = false; - - if (0 != m_pUDPContext) - { - m_GotIPHandler.reset(); // reset WiFi event callbacks. - m_DisconnectedHandler.reset(); - - _announce(false, true); - _resetProbeStatus(false); // Stop probing - _releaseServiceQueries(); - _releaseUDPContext(); - _releaseHostname(); - - bResult = true; - } - else - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] close: Ignoring call to close!\n"));); - } - return bResult; -} - -/* - MDNSResponder::end - - Ends the MDNS responder. - for compatibility with esp32 - -*/ - -bool MDNSResponder::end(void) -{ - return close(); -} - -/* - MDNSResponder::setHostname - - Replaces the current hostname and restarts probing. - For services without own instance name (when the host name was used a instance - name), the instance names are replaced also (and the probing is restarted). - -*/ -bool MDNSResponder::setHostname(const char* p_pcHostname) -{ - - bool bResult = false; - - if (_setHostname(p_pcHostname)) - { - m_HostProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; - - // Replace 'auto-set' service names - bResult = true; - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if (pService->m_bAutoName) - { - bResult = pService->setName(p_pcHostname); - pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; - } - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setHostname: FAILED for '%s'!\n"), (p_pcHostname ? : "-")); - }); - return bResult; -} - -/* - MDNSResponder::setHostname (LEGACY) -*/ -bool MDNSResponder::setHostname(const String& p_strHostname) -{ - - return setHostname(p_strHostname.c_str()); -} - - -/* - SERVICES -*/ - -/* - MDNSResponder::addService - - Add service; using hostname if no name is explicitly provided for the service - The usual '_' underline, which is prepended to service and protocol, eg. _http, - may be given. If not, it is added automatically. - -*/ -MDNSResponder::hMDNSService MDNSResponder::addService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port) -{ - - hMDNSService hResult = 0; - - if (((!p_pcName) || // NO name OR - (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcName))) && // Fitting name - (p_pcService) && - (MDNS_SERVICE_NAME_LENGTH >= os_strlen(p_pcService)) && - (p_pcProtocol) && - ((MDNS_SERVICE_PROTOCOL_LENGTH - 1) != os_strlen(p_pcProtocol)) && - (p_u16Port)) - { - - if (!_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol)) // Not already used - { - if (0 != (hResult = (hMDNSService)_allocService(p_pcName, p_pcService, p_pcProtocol, p_u16Port))) - { - - // Start probing - ((stcMDNSService*)hResult)->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; - } - } - } // else: bad arguments - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: %s to add '%s.%s.%s'!\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcName ? : "-"), p_pcService, p_pcProtocol);); - DEBUG_EX_ERR(if (!hResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: FAILED to add '%s.%s.%s'!\n"), (p_pcName ? : "-"), p_pcService, p_pcProtocol); - }); - return hResult; -} - -/* - MDNSResponder::removeService - - Unanounce a service (by sending a goodbye message) and remove it - from the MDNS responder - -*/ -bool MDNSResponder::removeService(const MDNSResponder::hMDNSService p_hService) -{ - - stcMDNSService* pService = 0; - bool bResult = (((pService = _findService(p_hService))) && - (_announceService(*pService, false)) && - (_releaseService(pService))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeService: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::removeService -*/ -bool MDNSResponder::removeService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol) -{ - - return removeService((hMDNSService)_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol)); -} - -/* - MDNSResponder::addService (LEGACY) -*/ -bool MDNSResponder::addService(const String& p_strService, - const String& p_strProtocol, - uint16_t p_u16Port) -{ - - return (0 != addService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str(), p_u16Port)); -} - -/* - MDNSResponder::setServiceName -*/ -bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSService p_hService, - const char* p_pcInstanceName) -{ - - stcMDNSService* pService = 0; - bool bResult = (((!p_pcInstanceName) || - (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcInstanceName))) && - ((pService = _findService(p_hService))) && - (pService->setName(p_pcInstanceName)) && - ((pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setServiceName: FAILED for '%s'!\n"), (p_pcInstanceName ? : "-")); - }); - return bResult; -} - -/* - SERVICE TXT -*/ - -/* - MDNSResponder::addServiceTxt - - Add a static service TXT item ('Key'='Value') to a service. - -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue) -{ - - hMDNSTxt hTxt = 0; - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - hTxt = (hMDNSTxt)_addServiceTxt(pService, p_pcKey, p_pcValue, false); - } - DEBUG_EX_ERR(if (!hTxt) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-")); - }); - return hTxt; -} - -/* - MDNSResponder::addServiceTxt (uint32_t) - - Formats: http://www.cplusplus.com/reference/cstdio/printf/ -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - char acBuffer[32]; *acBuffer = 0; - sprintf(acBuffer, "%u", p_u32Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (uint16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - char acBuffer[16]; *acBuffer = 0; - sprintf(acBuffer, "%hu", p_u16Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (uint8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - char acBuffer[8]; *acBuffer = 0; - sprintf(acBuffer, "%hhu", p_u8Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (int32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value) -{ - char acBuffer[32]; *acBuffer = 0; - sprintf(acBuffer, "%i", p_i32Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (int16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value) -{ - char acBuffer[16]; *acBuffer = 0; - sprintf(acBuffer, "%hi", p_i16Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (int8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value) -{ - char acBuffer[8]; *acBuffer = 0; - sprintf(acBuffer, "%hhi", p_i8Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::removeServiceTxt - - Remove a static service TXT item from a service. -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService, - const MDNSResponder::hMDNSTxt p_hTxt) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_hTxt); - if (pTxt) - { - bResult = _releaseServiceTxt(pService, pTxt); - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::removeServiceTxt -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey); - if (pTxt) - { - bResult = _releaseServiceTxt(pService, pTxt); - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED for '%s'!\n"), (p_pcKey ? : "-")); - }); - return bResult; -} - -/* - MDNSResponder::removeServiceTxt -*/ -bool MDNSResponder::removeServiceTxt(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol); - if (pService) - { - stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey); - if (pTxt) - { - bResult = _releaseServiceTxt(pService, pTxt); - } - } - return bResult; -} - -/* - MDNSResponder::addServiceTxt (LEGACY) -*/ -bool MDNSResponder::addServiceTxt(const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey, - const char* p_pcValue) -{ - - return (0 != _addServiceTxt(_findService(m_pcHostname, p_pcService, p_pcProtocol), p_pcKey, p_pcValue, false)); -} - -/* - MDNSResponder::addServiceTxt (LEGACY) -*/ -bool MDNSResponder::addServiceTxt(const String& p_strService, - const String& p_strProtocol, - const String& p_strKey, - const String& p_strValue) -{ - - return (0 != _addServiceTxt(_findService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str()), p_strKey.c_str(), p_strValue.c_str(), false)); -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (global) - - Set a global callback for dynamic service TXT items. The callback is called, whenever - service TXT items are needed. - -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback) -{ - - m_fnServiceTxtCallback = p_fnCallback; - - return true; -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (service specific) - - Set a service specific callback for dynamic service TXT items. The callback is called, whenever - service TXT items are needed for the given service. - -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::hMDNSService p_hService, - MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - pService->m_fnTxtCallback = p_fnCallback; - - bResult = true; - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setDynamicServiceTxtCallback: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::addDynamicServiceTxt -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt (%s=%s)\n"), p_pcKey, p_pcValue);); - - hMDNSTxt hTxt = 0; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - hTxt = _addServiceTxt(pService, p_pcKey, p_pcValue, true); - } - DEBUG_EX_ERR(if (!hTxt) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-")); - }); - return hTxt; -} - -/* - MDNSResponder::addDynamicServiceTxt (uint32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - - char acBuffer[32]; *acBuffer = 0; - sprintf(acBuffer, "%u", p_u32Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (uint16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - - char acBuffer[16]; *acBuffer = 0; - sprintf(acBuffer, "%hu", p_u16Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (uint8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - - char acBuffer[8]; *acBuffer = 0; - sprintf(acBuffer, "%hhu", p_u8Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (int32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value) -{ - - char acBuffer[32]; *acBuffer = 0; - sprintf(acBuffer, "%i", p_i32Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (int16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value) -{ - - char acBuffer[16]; *acBuffer = 0; - sprintf(acBuffer, "%hi", p_i16Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (int8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value) -{ - - char acBuffer[8]; *acBuffer = 0; - sprintf(acBuffer, "%hhi", p_i8Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - - -/** - STATIC SERVICE QUERY (LEGACY) -*/ - -/* - MDNSResponder::queryService - - Perform a (blocking) static service query. - The arrived answers can be queried by calling: - - answerHostname (or 'hostname') - - answerIP (or 'IP') - - answerPort (or 'port') - -*/ -uint32_t MDNSResponder::queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - if (0 == m_pUDPContext) - { - // safeguard against misuse - return 0; - } - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService '%s.%s'\n"), p_pcService, p_pcProtocol);); - - uint32_t u32Result = 0; - - stcMDNSServiceQuery* pServiceQuery = 0; - if ((p_pcService) && - (os_strlen(p_pcService)) && - (p_pcProtocol) && - (os_strlen(p_pcProtocol)) && - (p_u16Timeout) && - (_removeLegacyServiceQuery()) && - ((pServiceQuery = _allocServiceQuery())) && - (_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain))) - { - - pServiceQuery->m_bLegacyQuery = true; - - if (_sendMDNSServiceQuery(*pServiceQuery)) - { - // Wait for answers to arrive - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: Waiting %u ms for answers...\n"), p_u16Timeout);); - delay(p_u16Timeout); - - // All answers should have arrived by now -> stop adding new answers - pServiceQuery->m_bAwaitingAnswers = false; - u32Result = pServiceQuery->answerCount(); - } - else // FAILED to send query - { - _removeServiceQuery(pServiceQuery); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: INVALID input data!\n"));); - } - return u32Result; -} - -/* - MDNSResponder::removeQuery - - Remove the last static service query (and all answers). - -*/ -bool MDNSResponder::removeQuery(void) -{ - - return _removeLegacyServiceQuery(); -} - -/* - MDNSResponder::queryService (LEGACY) -*/ -uint32_t MDNSResponder::queryService(const String& p_strService, - const String& p_strProtocol) -{ - - return queryService(p_strService.c_str(), p_strProtocol.c_str()); -} - -/* - MDNSResponder::answerHostname -*/ -const char* MDNSResponder::answerHostname(const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - - if ((pSQAnswer) && - (pSQAnswer->m_HostDomain.m_u16NameLength) && - (!pSQAnswer->m_pcHostDomain)) - { - - char* pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); - if (pcHostDomain) - { - pSQAnswer->m_HostDomain.c_str(pcHostDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::answerIP -*/ -IPAddress MDNSResponder::answerIP(const uint32_t p_u32AnswerIndex) -{ - - const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); - const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - const stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (((pSQAnswer) && (pSQAnswer->m_pIP4Addresses)) ? pSQAnswer->IP4AddressAtIndex(0) : 0); - return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress()); -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::answerIP6 -*/ -IPAddress MDNSResponder::answerIP6(const uint32_t p_u32AnswerIndex) -{ - - const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); - const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - const stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (((pSQAnswer) && (pSQAnswer->m_pIP6Addresses)) ? pSQAnswer->IP6AddressAtIndex(0) : 0); - return (pIP6Address ? pIP6Address->m_IPAddress : IP6Address()); -} -#endif - -/* - MDNSResponder::answerPort -*/ -uint16_t MDNSResponder::answerPort(const uint32_t p_u32AnswerIndex) -{ - - const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); - const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->m_u16Port : 0); -} - -/* - MDNSResponder::hostname (LEGACY) -*/ -String MDNSResponder::hostname(const uint32_t p_u32AnswerIndex) -{ - - return String(answerHostname(p_u32AnswerIndex)); -} - -/* - MDNSResponder::IP (LEGACY) -*/ -IPAddress MDNSResponder::IP(const uint32_t p_u32AnswerIndex) -{ - - return answerIP(p_u32AnswerIndex); -} - -/* - MDNSResponder::port (LEGACY) -*/ -uint16_t MDNSResponder::port(const uint32_t p_u32AnswerIndex) -{ - - return answerPort(p_u32AnswerIndex); -} - - -/** - DYNAMIC SERVICE QUERY -*/ - -/* - MDNSResponder::installServiceQuery - - Add a dynamic service query and a corresponding callback to the MDNS responder. - The callback will be called for every answer update. - The answers can also be queried by calling: - - answerServiceDomain - - answerHostDomain - - answerIP4Address/answerIP6Address - - answerPort - - answerTxts - -*/ -MDNSResponder::hMDNSServiceQuery MDNSResponder::installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSResponder::MDNSServiceQueryCallbackFunc p_fnCallback) -{ - hMDNSServiceQuery hResult = 0; - - stcMDNSServiceQuery* pServiceQuery = 0; - if ((p_pcService) && - (os_strlen(p_pcService)) && - (p_pcProtocol) && - (os_strlen(p_pcProtocol)) && - (p_fnCallback) && - ((pServiceQuery = _allocServiceQuery())) && - (_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain))) - { - - pServiceQuery->m_fnCallback = p_fnCallback; - pServiceQuery->m_bLegacyQuery = false; - - if (_sendMDNSServiceQuery(*pServiceQuery)) - { - pServiceQuery->m_u8SentCount = 1; - pServiceQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); - - hResult = (hMDNSServiceQuery)pServiceQuery; - } - else - { - _removeServiceQuery(pServiceQuery); - } - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: %s for '%s.%s'!\n\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - DEBUG_EX_ERR(if (!hResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: FAILED for '%s.%s'!\n\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-")); - }); - return hResult; -} - -/* - MDNSResponder::removeServiceQuery - - Remove a dynamic service query (and all collected answers) from the MDNS responder - -*/ -bool MDNSResponder::removeServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) -{ - - stcMDNSServiceQuery* pServiceQuery = 0; - bool bResult = (((pServiceQuery = _findServiceQuery(p_hServiceQuery))) && - (_removeServiceQuery(pServiceQuery))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceQuery: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::answerCount -*/ -uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - return (pServiceQuery ? pServiceQuery->answerCount() : 0); -} - -std::vector MDNSResponder::answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery) -{ - std::vector tempVector; - for (uint32_t i = 0; i < answerCount(p_hServiceQuery); i++) - { - tempVector.emplace_back(*this, p_hServiceQuery, i); - } - return tempVector; -} - -/* - MDNSResponder::answerServiceDomain - - Returns the domain for the given service. - If not already existing, the string is allocated, filled and attached to the answer. - -*/ -const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcServiceDomain (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_ServiceDomain.m_u16NameLength) && - (!pSQAnswer->m_pcServiceDomain)) - { - - pSQAnswer->m_pcServiceDomain = pSQAnswer->allocServiceDomain(pSQAnswer->m_ServiceDomain.c_strLength()); - if (pSQAnswer->m_pcServiceDomain) - { - pSQAnswer->m_ServiceDomain.c_str(pSQAnswer->m_pcServiceDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcServiceDomain : 0); -} - -/* - MDNSResponder::hasAnswerHostDomain -*/ -bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort)); -} - -/* - MDNSResponder::answerHostDomain - - Returns the host domain for the given service. - If not already existing, the string is allocated, filled and attached to the answer. - -*/ -const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcHostDomain (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_HostDomain.m_u16NameLength) && - (!pSQAnswer->m_pcHostDomain)) - { - - pSQAnswer->m_pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); - if (pSQAnswer->m_pcHostDomain) - { - pSQAnswer->m_HostDomain.c_str(pSQAnswer->m_pcHostDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::hasAnswerIP4Address -*/ -bool MDNSResponder::hasAnswerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_IP4Address)); -} - -/* - MDNSResponder::answerIP4AddressCount -*/ -uint32_t MDNSResponder::answerIP4AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->IP4AddressCount() : 0); -} - -/* - MDNSResponder::answerIP4Address -*/ -IPAddress MDNSResponder::answerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (pSQAnswer ? pSQAnswer->IP4AddressAtIndex(p_u32AddressIndex) : 0); - return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress()); -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::hasAnswerIP6Address -*/ -bool MDNSResponder::hasAnswerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostIP6Address)); -} - -/* - MDNSResponder::answerIP6AddressCount -*/ -uint32_t MDNSResponder::answerIP6AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->IP6AddressCount() : 0); -} - -/* - MDNSResponder::answerIP6Address -*/ -IPAddress MDNSResponder::answerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (pSQAnswer ? pSQAnswer->IP6AddressAtIndex(p_u32AddressIndex) : 0); - return (pIP6Address ? pIP6Address->m_IPAddress : IPAddress()); -} -#endif - -/* - MDNSResponder::hasAnswerPort -*/ -bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort)); -} - -/* - MDNSResponder::answerPort -*/ -uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->m_u16Port : 0); -} - -/* - MDNSResponder::hasAnswerTxts -*/ -bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_Txts)); -} - -/* - MDNSResponder::answerTxts - - Returns all TXT items for the given service as a ';'-separated string. - If not already existing; the string is alloced, filled and attached to the answer. - -*/ -const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcTxts (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_Txts.m_pTxts) && - (!pSQAnswer->m_pcTxts)) - { - - pSQAnswer->m_pcTxts = pSQAnswer->allocTxts(pSQAnswer->m_Txts.c_strLength()); - if (pSQAnswer->m_pcTxts) - { - pSQAnswer->m_Txts.c_str(pSQAnswer->m_pcTxts); - } - } - return (pSQAnswer ? pSQAnswer->m_pcTxts : 0); -} - -/* - PROBING -*/ - -/* - MDNSResponder::setProbeResultCallback - - Set a global callback for probe results. The callback is called, when probing - for the host domain (or a service domain, without specific probe result callback) - failes or succeedes. - In the case of failure, the domain name should be changed via 'setHostname' or 'setServiceName'. - When succeeded, the host or service domain will be announced by the MDNS responder. - -*/ -bool MDNSResponder::setHostProbeResultCallback(MDNSResponder::MDNSHostProbeFn p_fnCallback) -{ - - m_HostProbeInformation.m_fnHostProbeResultCallback = p_fnCallback; - - return true; -} - -bool MDNSResponder::setHostProbeResultCallback(MDNSHostProbeFn1 pfn) -{ - using namespace std::placeholders; - return setHostProbeResultCallback([this, pfn](const char* p_pcDomainName, bool p_bProbeResult) - { - pfn(*this, p_pcDomainName, p_bProbeResult); - }); -} - -/* - MDNSResponder::setServiceProbeResultCallback - - Set a service specific callback for probe results. The callback is called, when probing - for the service domain failes or succeedes. - In the case of failure, the service name should be changed via 'setServiceName'. - When succeeded, the service domain will be announced by the MDNS responder. - -*/ -bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, - MDNSResponder::MDNSServiceProbeFn p_fnCallback) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - pService->m_ProbeInformation.m_fnServiceProbeResultCallback = p_fnCallback; - - bResult = true; - } - return bResult; -} - -bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, - MDNSResponder::MDNSServiceProbeFn1 p_fnCallback) -{ - using namespace std::placeholders; - return setServiceProbeResultCallback(p_hService, [this, p_fnCallback](const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) - { - p_fnCallback(*this, p_pcServiceName, p_hMDNSService, p_bProbeResult); - }); -} - - -/* - MISC -*/ - -/* - MDNSResponder::notifyAPChange - - Should be called, whenever the AP for the MDNS responder changes. - A bit of this is caught by the event callbacks installed in the constructor. - -*/ -bool MDNSResponder::notifyAPChange(void) -{ - - return _restart(); -} - -/* - MDNSResponder::update - - Should be called in every 'loop'. - -*/ -bool MDNSResponder::update(void) -{ - - if (m_bPassivModeEnabled) - { - m_bPassivModeEnabled = false; - } - return _process(true); -} - -/* - MDNSResponder::announce - - Should be called, if the 'configuration' changes. Mainly this will be changes in the TXT items... -*/ -bool MDNSResponder::announce(void) -{ - - return (_announce(true, true)); -} - -/* - MDNSResponder::enableArduino - - Enable the OTA update service. - -*/ -MDNSResponder::hMDNSService MDNSResponder::enableArduino(uint16_t p_u16Port, - bool p_bAuthUpload /*= false*/) -{ - - hMDNSService hService = addService(0, "arduino", "tcp", p_u16Port); - if (hService) - { - if ((!addServiceTxt(hService, "tcp_check", "no")) || - (!addServiceTxt(hService, "ssh_upload", "no")) || - (!addServiceTxt(hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) || - (!addServiceTxt(hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) - { - - removeService(hService); - hService = 0; - } - } - return hService; -} - - -} //namespace MDNSImplementation - -} //namespace esp8266 - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h deleted file mode 100644 index fe02560aec..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h +++ /dev/null @@ -1,1461 +0,0 @@ -/* - LEAmDNS.h - (c) 2018, LaborEtArs - - Version 0.9 beta - - Some notes (from LaborEtArs, 2018): - Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS). - The target of this rewrite was to keep the existing interface as stable as possible while - adding and extending the supported set of mDNS features. - A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code. - - Supported mDNS features (in some cases somewhat limited): - - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service - - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented - - Probing host and service domains for uniqueness in the local network - - Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak) - - Announcing available services after successful probing - - Using fixed service TXT items or - - Using dynamic service TXT items for presented services (via callback) - - Remove services (and un-announcing them to the observers by sending goodbye-messages) - - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) - - Dynamic queries for DNS-SD services with cached and updated answers and user notifications - - - Usage: - In most cases, this implementation should work as a 'drop-in' replacement for the original - ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some - of the new features should be used. - - For presenting services: - In 'setup()': - Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);' - Register DNS-SD services with 'MDNSResponder::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);' - (Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);') - Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback - using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific - 'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);' - Call MDNS.begin("MyHostname"); - - In 'probeResultCallback(MDNSResponder* p_MDNSResponder, const char* p_pcDomain, MDNSResponder:hMDNSService p_hService, bool p_bProbeResult, void* p_pUserdata)': - Check the probe result and update the host or service domain name if the probe failed - - In 'dynamicServiceTxtCallback(MDNSResponder* p_MDNSResponder, const hMDNSService p_hService, void* p_pUserdata)': - Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hService, "c#", "1");' - - In loop(): - Call 'MDNS.update();' - - - For querying services: - Static: - Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");' - Iterate answers by: 'for (uint32_t u=0; u // for UdpContext.h -#include "WiFiUdp.h" -#include "lwip/udp.h" -#include "debug.h" -#include "include/UdpContext.h" -#include -#include -#include - - -#include "ESP8266WiFi.h" - - -namespace esp8266 -{ - -/** - LEAmDNS -*/ -namespace MDNSImplementation -{ - -//this should be defined at build time -#ifndef ARDUINO_BOARD -#define ARDUINO_BOARD "generic" -#endif - -#define MDNS_IP4_SUPPORT -//#define MDNS_IP6_SUPPORT - - -#ifdef MDNS_IP4_SUPPORT -#define MDNS_IP4_SIZE 4 -#endif -#ifdef MDNS_IP6_SUPPORT -#define MDNS_IP6_SIZE 16 -#endif -/* - Maximum length for all service txts for one service -*/ -#define MDNS_SERVICE_TXT_MAXLENGTH 1300 -/* - Maximum length for a full domain name eg. MyESP._http._tcp.local -*/ -#define MDNS_DOMAIN_MAXLENGTH 256 -/* - Maximum length of on label in a domain name (length info fits into 6 bits) -*/ -#define MDNS_DOMAIN_LABEL_MAXLENGTH 63 -/* - Maximum length of a service name eg. http -*/ -#define MDNS_SERVICE_NAME_LENGTH 15 -/* - Maximum length of a service protocol name eg. tcp -*/ -#define MDNS_SERVICE_PROTOCOL_LENGTH 3 -/* - Default timeout for static service queries -*/ -#define MDNS_QUERYSERVICES_WAIT_TIME 1000 - - -/** - MDNSResponder -*/ -class MDNSResponder -{ -public: - /* INTERFACE */ - MDNSResponder(void); - virtual ~MDNSResponder(void); - - // Start the MDNS responder by setting the default hostname - // Later call MDNS::update() in every 'loop' to run the process loop - // (probing, announcing, responding, ...) - // if interfaceAddress is not specified, default interface is STA, or AP when STA is not set - bool begin(const char* p_pcHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/); - bool begin(const String& p_strHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/) - { - return begin(p_strHostname.c_str(), p_IPAddress, p_u32TTL); - } - - // Finish MDNS processing - bool close(void); - // for esp32 compatability - bool end(void); - // Change hostname (probing is restarted) - bool setHostname(const char* p_pcHostname); - // for compatibility... - bool setHostname(const String& p_strHostname); - - bool isRunning(void) - { - return (m_pUDPContext != 0); - } - - /** - hMDNSService (opaque handle to access the service) - */ - typedef const void* hMDNSService; - - // Add a new service to the MDNS responder. If no name (instance name) is given (p_pcName = 0) - // the current hostname is used. If the hostname is changed later, the instance names for - // these 'auto-named' services are changed to the new name also (and probing is restarted). - // The usual '_' before p_pcService (eg. http) and protocol (eg. tcp) may be given. - hMDNSService addService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port); - // Removes a service from the MDNS responder - bool removeService(const hMDNSService p_hService); - bool removeService(const char* p_pcInstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol); - // for compatibility... - bool addService(const String& p_strServiceName, - const String& p_strProtocol, - uint16_t p_u16Port); - - - // Change the services instance name (and restart probing). - bool setServiceName(const hMDNSService p_hService, - const char* p_pcInstanceName); - //for compatibility - //Warning: this has the side effect of changing the hostname. - //TODO: implement instancename different from hostname - void setInstanceName(const char* p_pcHostname) - { - setHostname(p_pcHostname); - } - // for esp32 compatibilty - void setInstanceName(const String& s_pcHostname) - { - setInstanceName(s_pcHostname.c_str()); - } - - /** - hMDNSTxt (opaque handle to access the TXT items) - */ - typedef void* hMDNSTxt; - - // Add a (static) MDNS TXT item ('key' = 'value') to the service - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value); - - // Remove an existing (static) MDNS TXT item from the service - bool removeServiceTxt(const hMDNSService p_hService, - const hMDNSTxt p_hTxt); - bool removeServiceTxt(const hMDNSService p_hService, - const char* p_pcKey); - bool removeServiceTxt(const char* p_pcinstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol, - const char* p_pcKey); - // for compatibility... - bool addServiceTxt(const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey, - const char* p_pcValue); - bool addServiceTxt(const String& p_strService, - const String& p_strProtocol, - const String& p_strKey, - const String& p_strValue); - - /** - MDNSDynamicServiceTxtCallbackFn - Callback function for dynamic MDNS TXT items - */ - - typedef std::function MDNSDynamicServiceTxtCallbackFunc; - - // Set a global callback for dynamic MDNS TXT items. The callback function is called - // every time, a TXT item is needed for one of the installed services. - bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFunc p_fnCallback); - // Set a service specific callback for dynamic MDNS TXT items. The callback function - // is called every time, a TXT item is needed for the given service. - bool setDynamicServiceTxtCallback(const hMDNSService p_hService, - MDNSDynamicServiceTxtCallbackFunc p_fnCallback); - - // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service - // Dynamic TXT items are removed right after one-time use. So they need to be added - // every time the value s needed (via callback). - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value); - - // Perform a (static) service query. The function returns after p_u16Timeout milliseconds - // The answers (the number of received answers is returned) can be retrieved by calling - // - answerHostname (or hostname) - // - answerIP (or IP) - // - answerPort (or port) - uint32_t queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - bool removeQuery(void); - // for compatibility... - uint32_t queryService(const String& p_strService, - const String& p_strProtocol); - - const char* answerHostname(const uint32_t p_u32AnswerIndex); - IPAddress answerIP(const uint32_t p_u32AnswerIndex); - uint16_t answerPort(const uint32_t p_u32AnswerIndex); - // for compatibility... - String hostname(const uint32_t p_u32AnswerIndex); - IPAddress IP(const uint32_t p_u32AnswerIndex); - uint16_t port(const uint32_t p_u32AnswerIndex); - - /** - hMDNSServiceQuery (opaque handle to access dynamic service queries) - */ - typedef const void* hMDNSServiceQuery; - - /** - enuServiceQueryAnswerType - */ - typedef enum _enuServiceQueryAnswerType - { - ServiceQueryAnswerType_ServiceDomain = (1 << 0), // Service instance name - ServiceQueryAnswerType_HostDomainAndPort = (1 << 1), // Host domain and service port - ServiceQueryAnswerType_Txts = (1 << 2), // TXT items -#ifdef MDNS_IP4_SUPPORT - ServiceQueryAnswerType_IP4Address = (1 << 3), // IP4 address -#endif -#ifdef MDNS_IP6_SUPPORT - ServiceQueryAnswerType_IP6Address = (1 << 4), // IP6 address -#endif - } enuServiceQueryAnswerType; - - enum class AnswerType : uint32_t - { - Unknown = 0, - ServiceDomain = ServiceQueryAnswerType_ServiceDomain, - HostDomainAndPort = ServiceQueryAnswerType_HostDomainAndPort, - Txt = ServiceQueryAnswerType_Txts, -#ifdef MDNS_IP4_SUPPORT - IP4Address = ServiceQueryAnswerType_IP4Address, -#endif -#ifdef MDNS_IP6_SUPPORT - IP6Address = ServiceQueryAnswerType_IP6Address, -#endif - }; - - /** - MDNSServiceQueryCallbackFn - Callback function for received answers for dynamic service queries - */ - struct MDNSServiceInfo; // forward declaration - typedef std::function MDNSServiceQueryCallbackFunc; - - // Install a dynamic service query. For every received answer (part) the given callback - // function is called. The query will be updated every time, the TTL for an answer - // has timed-out. - // The answers can also be retrieved by calling - // - answerCount - // - answerServiceDomain - // - hasAnswerHostDomain/answerHostDomain - // - hasAnswerIP4Address/answerIP4Address - // - hasAnswerIP6Address/answerIP6Address - // - hasAnswerPort/answerPort - // - hasAnswerTxts/answerTxts - hMDNSServiceQuery installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSServiceQueryCallbackFunc p_fnCallback); - // Remove a dynamic service query - bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery); - - uint32_t answerCount(const hMDNSServiceQuery p_hServiceQuery); - std::vector answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery); - - const char* answerServiceDomain(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerHostDomain(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - const char* answerHostDomain(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); -#ifdef MDNS_IP4_SUPPORT - bool hasAnswerIP4Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIP4AddressCount(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIP4Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); -#endif -#ifdef MDNS_IP6_SUPPORT - bool hasAnswerIP6Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIP6AddressCount(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIP6Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); -#endif - bool hasAnswerPort(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - uint16_t answerPort(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerTxts(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - // Get the TXT items as a ';'-separated string - const char* answerTxts(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - - /** - MDNSProbeResultCallbackFn - Callback function for (host and service domain) probe results - */ - typedef std::function MDNSHostProbeFn; - - typedef std::function MDNSHostProbeFn1; - - typedef std::function MDNSServiceProbeFn; - - typedef std::function MDNSServiceProbeFn1; - - // Set a global callback function for host and service probe results - // The callback function is called, when the probing for the host domain - // (or a service domain, which hasn't got a service specific callback) - // Succeeds or fails. - // In case of failure, the failed domain name should be changed. - bool setHostProbeResultCallback(MDNSHostProbeFn p_fnCallback); - bool setHostProbeResultCallback(MDNSHostProbeFn1 p_fnCallback); - - // Set a service specific probe result callback - bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, - MDNSServiceProbeFn p_fnCallback); - bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, - MDNSServiceProbeFn1 p_fnCallback); - - // Application should call this whenever AP is configured/disabled - bool notifyAPChange(void); - - // 'update' should be called in every 'loop' to run the MDNS processing - bool update(void); - - // 'announce' can be called every time, the configuration of some service - // changes. Mainly, this would be changed content of TXT items. - bool announce(void); - - // Enable OTA update - hMDNSService enableArduino(uint16_t p_u16Port, - bool p_bAuthUpload = false); - - // Domain name helper - static bool indexDomain(char*& p_rpcDomain, - const char* p_pcDivider = "-", - const char* p_pcDefaultDomain = 0); - - /** STRUCTS **/ - -public: - /** - MDNSServiceInfo, used in application callbacks - */ - struct MDNSServiceInfo - { - MDNSServiceInfo(MDNSResponder& p_pM, MDNSResponder::hMDNSServiceQuery p_hS, uint32_t p_u32A) - : p_pMDNSResponder(p_pM), - p_hServiceQuery(p_hS), - p_u32AnswerIndex(p_u32A) - {}; - struct CompareKey - { - bool operator()(char const *a, char const *b) const - { - return strcmp(a, b) < 0; - } - }; - using KeyValueMap = std::map; - protected: - MDNSResponder& p_pMDNSResponder; - MDNSResponder::hMDNSServiceQuery p_hServiceQuery; - uint32_t p_u32AnswerIndex; - KeyValueMap keyValueMap; - public: - const char* serviceDomain() - { - return p_pMDNSResponder.answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex); - }; - bool hostDomainAvailable() - { - return (p_pMDNSResponder.hasAnswerHostDomain(p_hServiceQuery, p_u32AnswerIndex)); - } - const char* hostDomain() - { - return (hostDomainAvailable()) ? - p_pMDNSResponder.answerHostDomain(p_hServiceQuery, p_u32AnswerIndex) : nullptr; - }; - bool hostPortAvailable() - { - return (p_pMDNSResponder.hasAnswerPort(p_hServiceQuery, p_u32AnswerIndex)); - } - uint16_t hostPort() - { - return (hostPortAvailable()) ? - p_pMDNSResponder.answerPort(p_hServiceQuery, p_u32AnswerIndex) : 0; - }; - bool IP4AddressAvailable() - { - return (p_pMDNSResponder.hasAnswerIP4Address(p_hServiceQuery, p_u32AnswerIndex)); - } - std::vector IP4Adresses() - { - std::vector internalIP; - if (IP4AddressAvailable()) - { - uint16_t cntIP4Adress = p_pMDNSResponder.answerIP4AddressCount(p_hServiceQuery, p_u32AnswerIndex); - for (uint32_t u2 = 0; u2 < cntIP4Adress; ++u2) - { - internalIP.emplace_back(p_pMDNSResponder.answerIP4Address(p_hServiceQuery, p_u32AnswerIndex, u2)); - } - } - return internalIP; - }; - bool txtAvailable() - { - return (p_pMDNSResponder.hasAnswerTxts(p_hServiceQuery, p_u32AnswerIndex)); - } - const char* strKeyValue() - { - return (txtAvailable()) ? - p_pMDNSResponder.answerTxts(p_hServiceQuery, p_u32AnswerIndex) : nullptr; - }; - const KeyValueMap& keyValues() - { - if (txtAvailable() && keyValueMap.size() == 0) - { - for (auto kv = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); kv != nullptr; kv = kv->m_pNext) - { - keyValueMap.emplace(std::pair(kv->m_pcKey, kv->m_pcValue)); - } - } - return keyValueMap; - } - const char* value(const char* key) - { - char* result = nullptr; - - for (stcMDNSServiceTxt* pTxt = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); pTxt; pTxt = pTxt->m_pNext) - { - if ((key) && - (0 == strcmp(pTxt->m_pcKey, key))) - { - result = pTxt->m_pcValue; - break; - } - } - return result; - } - }; -protected: - - /** - stcMDNSServiceTxt - */ - struct stcMDNSServiceTxt - { - stcMDNSServiceTxt* m_pNext; - char* m_pcKey; - char* m_pcValue; - bool m_bTemp; - - stcMDNSServiceTxt(const char* p_pcKey = 0, - const char* p_pcValue = 0, - bool p_bTemp = false); - stcMDNSServiceTxt(const stcMDNSServiceTxt& p_Other); - ~stcMDNSServiceTxt(void); - - stcMDNSServiceTxt& operator=(const stcMDNSServiceTxt& p_Other); - bool clear(void); - - char* allocKey(size_t p_stLength); - bool setKey(const char* p_pcKey, - size_t p_stLength); - bool setKey(const char* p_pcKey); - bool releaseKey(void); - - char* allocValue(size_t p_stLength); - bool setValue(const char* p_pcValue, - size_t p_stLength); - bool setValue(const char* p_pcValue); - bool releaseValue(void); - - bool set(const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp = false); - - bool update(const char* p_pcValue); - - size_t length(void) const; - }; - - /** - stcMDNSTxts - */ - struct stcMDNSServiceTxts - { - stcMDNSServiceTxt* m_pTxts; - - stcMDNSServiceTxts(void); - stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other); - ~stcMDNSServiceTxts(void); - - stcMDNSServiceTxts& operator=(const stcMDNSServiceTxts& p_Other); - - bool clear(void); - - bool add(stcMDNSServiceTxt* p_pTxt); - bool remove(stcMDNSServiceTxt* p_pTxt); - - bool removeTempTxts(void); - - stcMDNSServiceTxt* find(const char* p_pcKey); - const stcMDNSServiceTxt* find(const char* p_pcKey) const; - stcMDNSServiceTxt* find(const stcMDNSServiceTxt* p_pTxt); - - uint16_t length(void) const; - - size_t c_strLength(void) const; - bool c_str(char* p_pcBuffer); - - size_t bufferLength(void) const; - bool buffer(char* p_pcBuffer); - - bool compare(const stcMDNSServiceTxts& p_Other) const; - bool operator==(const stcMDNSServiceTxts& p_Other) const; - bool operator!=(const stcMDNSServiceTxts& p_Other) const; - }; - - /** - enuContentFlags - */ - typedef enum _enuContentFlags - { - // Host - ContentFlag_A = 0x01, - ContentFlag_PTR_IP4 = 0x02, - ContentFlag_PTR_IP6 = 0x04, - ContentFlag_AAAA = 0x08, - // Service - ContentFlag_PTR_TYPE = 0x10, - ContentFlag_PTR_NAME = 0x20, - ContentFlag_TXT = 0x40, - ContentFlag_SRV = 0x80, - } enuContentFlags; - - /** - stcMDNS_MsgHeader - */ - struct stcMDNS_MsgHeader - { - uint16_t m_u16ID; // Identifier - bool m_1bQR : 1; // Query/Response flag - unsigned char m_4bOpcode : 4; // Operation code - bool m_1bAA : 1; // Authoritative Answer flag - bool m_1bTC : 1; // Truncation flag - bool m_1bRD : 1; // Recursion desired - bool m_1bRA : 1; // Recursion available - unsigned char m_3bZ : 3; // Zero - unsigned char m_4bRCode : 4; // Response code - uint16_t m_u16QDCount; // Question count - uint16_t m_u16ANCount; // Answer count - uint16_t m_u16NSCount; // Authority Record count - uint16_t m_u16ARCount; // Additional Record count - - stcMDNS_MsgHeader(uint16_t p_u16ID = 0, - bool p_bQR = false, - unsigned char p_ucOpcode = 0, - bool p_bAA = false, - bool p_bTC = false, - bool p_bRD = false, - bool p_bRA = false, - unsigned char p_ucRCode = 0, - uint16_t p_u16QDCount = 0, - uint16_t p_u16ANCount = 0, - uint16_t p_u16NSCount = 0, - uint16_t p_u16ARCount = 0); - }; - - /** - stcMDNS_RRDomain - */ - struct stcMDNS_RRDomain - { - char m_acName[MDNS_DOMAIN_MAXLENGTH]; // Encoded domain name - uint16_t m_u16NameLength; // Length (incl. '\0') - - stcMDNS_RRDomain(void); - stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other); - - stcMDNS_RRDomain& operator=(const stcMDNS_RRDomain& p_Other); - - bool clear(void); - - bool addLabel(const char* p_pcLabel, - bool p_bPrependUnderline = false); - - bool compare(const stcMDNS_RRDomain& p_Other) const; - bool operator==(const stcMDNS_RRDomain& p_Other) const; - bool operator!=(const stcMDNS_RRDomain& p_Other) const; - bool operator>(const stcMDNS_RRDomain& p_Other) const; - - size_t c_strLength(void) const; - bool c_str(char* p_pcBuffer); - }; - - /** - stcMDNS_RRAttributes - */ - struct stcMDNS_RRAttributes - { - uint16_t m_u16Type; // Type - uint16_t m_u16Class; // Class, nearly always 'IN' - - stcMDNS_RRAttributes(uint16_t p_u16Type = 0, - uint16_t p_u16Class = 1 /*DNS_RRCLASS_IN Internet*/); - stcMDNS_RRAttributes(const stcMDNS_RRAttributes& p_Other); - - stcMDNS_RRAttributes& operator=(const stcMDNS_RRAttributes& p_Other); - }; - - /** - stcMDNS_RRHeader - */ - struct stcMDNS_RRHeader - { - stcMDNS_RRDomain m_Domain; - stcMDNS_RRAttributes m_Attributes; - - stcMDNS_RRHeader(void); - stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other); - - stcMDNS_RRHeader& operator=(const stcMDNS_RRHeader& p_Other); - - bool clear(void); - }; - - /** - stcMDNS_RRQuestion - */ - struct stcMDNS_RRQuestion - { - stcMDNS_RRQuestion* m_pNext; - stcMDNS_RRHeader m_Header; - bool m_bUnicast; // Unicast reply requested - - stcMDNS_RRQuestion(void); - }; - - /** - enuAnswerType - */ - typedef enum _enuAnswerType - { - AnswerType_A, - AnswerType_PTR, - AnswerType_TXT, - AnswerType_AAAA, - AnswerType_SRV, - AnswerType_Generic - } enuAnswerType; - - /** - stcMDNS_RRAnswer - */ - struct stcMDNS_RRAnswer - { - stcMDNS_RRAnswer* m_pNext; - const enuAnswerType m_AnswerType; - stcMDNS_RRHeader m_Header; - bool m_bCacheFlush; // Cache flush command bit - uint32_t m_u32TTL; // Validity time in seconds - - virtual ~stcMDNS_RRAnswer(void); - - enuAnswerType answerType(void) const; - - bool clear(void); - - protected: - stcMDNS_RRAnswer(enuAnswerType p_AnswerType, - const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - }; - -#ifdef MDNS_IP4_SUPPORT - /** - stcMDNS_RRAnswerA - */ - struct stcMDNS_RRAnswerA : public stcMDNS_RRAnswer - { - IPAddress m_IPAddress; - - stcMDNS_RRAnswerA(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerA(void); - - bool clear(void); - }; -#endif - - /** - stcMDNS_RRAnswerPTR - */ - struct stcMDNS_RRAnswerPTR : public stcMDNS_RRAnswer - { - stcMDNS_RRDomain m_PTRDomain; - - stcMDNS_RRAnswerPTR(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerPTR(void); - - bool clear(void); - }; - - /** - stcMDNS_RRAnswerTXT - */ - struct stcMDNS_RRAnswerTXT : public stcMDNS_RRAnswer - { - stcMDNSServiceTxts m_Txts; - - stcMDNS_RRAnswerTXT(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerTXT(void); - - bool clear(void); - }; - -#ifdef MDNS_IP6_SUPPORT - /** - stcMDNS_RRAnswerAAAA - */ - struct stcMDNS_RRAnswerAAAA : public stcMDNS_RRAnswer - { - //TODO: IP6Address m_IPAddress; - - stcMDNS_RRAnswerAAAA(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerAAAA(void); - - bool clear(void); - }; -#endif - - /** - stcMDNS_RRAnswerSRV - */ - struct stcMDNS_RRAnswerSRV : public stcMDNS_RRAnswer - { - uint16_t m_u16Priority; - uint16_t m_u16Weight; - uint16_t m_u16Port; - stcMDNS_RRDomain m_SRVDomain; - - stcMDNS_RRAnswerSRV(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerSRV(void); - - bool clear(void); - }; - - /** - stcMDNS_RRAnswerGeneric - */ - struct stcMDNS_RRAnswerGeneric : public stcMDNS_RRAnswer - { - uint16_t m_u16RDLength; // Length of variable answer - uint8_t* m_pu8RDData; // Offset of start of variable answer in packet - - stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerGeneric(void); - - bool clear(void); - }; - - - /** - enuProbingStatus - */ - typedef enum _enuProbingStatus - { - ProbingStatus_WaitingForData, - ProbingStatus_ReadyToStart, - ProbingStatus_InProgress, - ProbingStatus_Done - } enuProbingStatus; - - /** - stcProbeInformation - */ - struct stcProbeInformation - { - enuProbingStatus m_ProbingStatus; - uint8_t m_u8SentCount; // Used for probes and announcements - esp8266::polledTimeout::oneShotMs m_Timeout; // Used for probes and announcements - //clsMDNSTimeFlag m_TimeFlag; // Used for probes and announcements - bool m_bConflict; - bool m_bTiebreakNeeded; - MDNSHostProbeFn m_fnHostProbeResultCallback; - MDNSServiceProbeFn m_fnServiceProbeResultCallback; - - stcProbeInformation(void); - - bool clear(bool p_bClearUserdata = false); - }; - - - /** - stcMDNSService - */ - struct stcMDNSService - { - stcMDNSService* m_pNext; - char* m_pcName; - bool m_bAutoName; // Name was set automatically to hostname (if no name was supplied) - char* m_pcService; - char* m_pcProtocol; - uint16_t m_u16Port; - uint8_t m_u8ReplyMask; - stcMDNSServiceTxts m_Txts; - MDNSDynamicServiceTxtCallbackFunc m_fnTxtCallback; - stcProbeInformation m_ProbeInformation; - - stcMDNSService(const char* p_pcName = 0, - const char* p_pcService = 0, - const char* p_pcProtocol = 0); - ~stcMDNSService(void); - - bool setName(const char* p_pcName); - bool releaseName(void); - - bool setService(const char* p_pcService); - bool releaseService(void); - - bool setProtocol(const char* p_pcProtocol); - bool releaseProtocol(void); - }; - - /** - stcMDNSServiceQuery - */ - struct stcMDNSServiceQuery - { - /** - stcAnswer - */ - struct stcAnswer - { - /** - stcTTL - */ - struct stcTTL - { - /** - timeoutLevel_t - */ - typedef uint8_t timeoutLevel_t; - /** - TIMEOUTLEVELs - */ - const timeoutLevel_t TIMEOUTLEVEL_UNSET = 0; - const timeoutLevel_t TIMEOUTLEVEL_BASE = 80; - const timeoutLevel_t TIMEOUTLEVEL_INTERVAL = 5; - const timeoutLevel_t TIMEOUTLEVEL_FINAL = 100; - - uint32_t m_u32TTL; - esp8266::polledTimeout::oneShotMs m_TTLTimeout; - timeoutLevel_t m_timeoutLevel; - - stcTTL(void); - bool set(uint32_t p_u32TTL); - - bool flagged(void); - bool restart(void); - - bool prepareDeletion(void); - bool finalTimeoutLevel(void) const; - - unsigned long timeout(void) const; - }; -#ifdef MDNS_IP4_SUPPORT - /** - stcIP4Address - */ - struct stcIP4Address - { - stcIP4Address* m_pNext; - IPAddress m_IPAddress; - stcTTL m_TTL; - - stcIP4Address(IPAddress p_IPAddress, - uint32_t p_u32TTL = 0); - }; -#endif -#ifdef MDNS_IP6_SUPPORT - /** - stcIP6Address - */ - struct stcIP6Address - { - stcIP6Address* m_pNext; - IP6Address m_IPAddress; - stcTTL m_TTL; - - stcIP6Address(IPAddress p_IPAddress, - uint32_t p_u32TTL = 0); - }; -#endif - - stcAnswer* m_pNext; - // The service domain is the first 'answer' (from PTR answer, using service and protocol) to be set - // Defines the key for additional answer, like host domain, etc. - stcMDNS_RRDomain m_ServiceDomain; // 1. level answer (PTR), eg. MyESP._http._tcp.local - char* m_pcServiceDomain; - stcTTL m_TTLServiceDomain; - stcMDNS_RRDomain m_HostDomain; // 2. level answer (SRV, using service domain), eg. esp8266.local - char* m_pcHostDomain; - uint16_t m_u16Port; // 2. level answer (SRV, using service domain), eg. 5000 - stcTTL m_TTLHostDomainAndPort; - stcMDNSServiceTxts m_Txts; // 2. level answer (TXT, using service domain), eg. c#=1 - char* m_pcTxts; - stcTTL m_TTLTxts; -#ifdef MDNS_IP4_SUPPORT - stcIP4Address* m_pIP4Addresses; // 3. level answer (A, using host domain), eg. 123.456.789.012 -#endif -#ifdef MDNS_IP6_SUPPORT - stcIP6Address* m_pIP6Addresses; // 3. level answer (AAAA, using host domain), eg. 1234::09 -#endif - uint32_t m_u32ContentFlags; - - stcAnswer(void); - ~stcAnswer(void); - - bool clear(void); - - char* allocServiceDomain(size_t p_stLength); - bool releaseServiceDomain(void); - - char* allocHostDomain(size_t p_stLength); - bool releaseHostDomain(void); - - char* allocTxts(size_t p_stLength); - bool releaseTxts(void); - -#ifdef MDNS_IP4_SUPPORT - bool releaseIP4Addresses(void); - bool addIP4Address(stcIP4Address* p_pIP4Address); - bool removeIP4Address(stcIP4Address* p_pIP4Address); - const stcIP4Address* findIP4Address(const IPAddress& p_IPAddress) const; - stcIP4Address* findIP4Address(const IPAddress& p_IPAddress); - uint32_t IP4AddressCount(void) const; - const stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index) const; - stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index); -#endif -#ifdef MDNS_IP6_SUPPORT - bool releaseIP6Addresses(void); - bool addIP6Address(stcIP6Address* p_pIP6Address); - bool removeIP6Address(stcIP6Address* p_pIP6Address); - const stcIP6Address* findIP6Address(const IPAddress& p_IPAddress) const; - stcIP6Address* findIP6Address(const IPAddress& p_IPAddress); - uint32_t IP6AddressCount(void) const; - const stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index) const; - stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index); -#endif - }; - - stcMDNSServiceQuery* m_pNext; - stcMDNS_RRDomain m_ServiceTypeDomain; // eg. _http._tcp.local - MDNSServiceQueryCallbackFunc m_fnCallback; - bool m_bLegacyQuery; - uint8_t m_u8SentCount; - esp8266::polledTimeout::oneShotMs m_ResendTimeout; - bool m_bAwaitingAnswers; - stcAnswer* m_pAnswers; - - stcMDNSServiceQuery(void); - ~stcMDNSServiceQuery(void); - - bool clear(void); - - uint32_t answerCount(void) const; - const stcAnswer* answerAtIndex(uint32_t p_u32Index) const; - stcAnswer* answerAtIndex(uint32_t p_u32Index); - uint32_t indexOfAnswer(const stcAnswer* p_pAnswer) const; - - bool addAnswer(stcAnswer* p_pAnswer); - bool removeAnswer(stcAnswer* p_pAnswer); - - stcAnswer* findAnswerForServiceDomain(const stcMDNS_RRDomain& p_ServiceDomain); - stcAnswer* findAnswerForHostDomain(const stcMDNS_RRDomain& p_HostDomain); - }; - - /** - stcMDNSSendParameter - */ - struct stcMDNSSendParameter - { - protected: - /** - stcDomainCacheItem - */ - struct stcDomainCacheItem - { - stcDomainCacheItem* m_pNext; - const void* m_pHostnameOrService; // Opaque id for host or service domain (pointer) - bool m_bAdditionalData; // Opaque flag for special info (service domain included) - uint16_t m_u16Offset; // Offset in UDP output buffer - - stcDomainCacheItem(const void* p_pHostnameOrService, - bool p_bAdditionalData, - uint32_t p_u16Offset); - }; - - public: - uint16_t m_u16ID; // Query ID (used only in lagacy queries) - stcMDNS_RRQuestion* m_pQuestions; // A list of queries - uint8_t m_u8HostReplyMask; // Flags for reply components/answers - bool m_bLegacyQuery; // Flag: Legacy query - bool m_bResponse; // Flag: Response to a query - bool m_bAuthorative; // Flag: Authorative (owner) response - bool m_bCacheFlush; // Flag: Clients should flush their caches - bool m_bUnicast; // Flag: Unicast response - bool m_bUnannounce; // Flag: Unannounce service - uint16_t m_u16Offset; // Current offset in UDP write buffer (mainly for domain cache) - stcDomainCacheItem* m_pDomainCacheItems; // Cached host and service domains - - stcMDNSSendParameter(void); - ~stcMDNSSendParameter(void); - - bool clear(void); - - bool shiftOffset(uint16_t p_u16Shift); - - bool addDomainCacheItem(const void* p_pHostnameOrService, - bool p_bAdditionalData, - uint16_t p_u16Offset); - uint16_t findCachedDomainOffset(const void* p_pHostnameOrService, - bool p_bAdditionalData) const; - }; - - // Instance variables - stcMDNSService* m_pServices; - UdpContext* m_pUDPContext; - char* m_pcHostname; - stcMDNSServiceQuery* m_pServiceQueries; - WiFiEventHandler m_DisconnectedHandler; - WiFiEventHandler m_GotIPHandler; - MDNSDynamicServiceTxtCallbackFunc m_fnServiceTxtCallback; - bool m_bPassivModeEnabled; - stcProbeInformation m_HostProbeInformation; - CONST netif* m_netif; // network interface to run on - - /** CONTROL **/ - /* MAINTENANCE */ - bool _process(bool p_bUserContext); - bool _restart(void); - - /* RECEIVING */ - bool _parseMessage(void); - bool _parseQuery(const stcMDNS_MsgHeader& p_Header); - - bool _parseResponse(const stcMDNS_MsgHeader& p_Header); - bool _processAnswers(const stcMDNS_RRAnswer* p_pPTRAnswers); - bool _processPTRAnswer(const stcMDNS_RRAnswerPTR* p_pPTRAnswer, - bool& p_rbFoundNewKeyAnswer); - bool _processSRVAnswer(const stcMDNS_RRAnswerSRV* p_pSRVAnswer, - bool& p_rbFoundNewKeyAnswer); - bool _processTXTAnswer(const stcMDNS_RRAnswerTXT* p_pTXTAnswer); -#ifdef MDNS_IP4_SUPPORT - bool _processAAnswer(const stcMDNS_RRAnswerA* p_pAAnswer); -#endif -#ifdef MDNS_IP6_SUPPORT - bool _processAAAAAnswer(const stcMDNS_RRAnswerAAAA* p_pAAAAAnswer); -#endif - - /* PROBING */ - bool _updateProbeStatus(void); - bool _resetProbeStatus(bool p_bRestart = true); - bool _hasProbesWaitingForAnswers(void) const; - bool _sendHostProbe(void); - bool _sendServiceProbe(stcMDNSService& p_rService); - bool _cancelProbingForHost(void); - bool _cancelProbingForService(stcMDNSService& p_rService); - - /* ANNOUNCE */ - bool _announce(bool p_bAnnounce, - bool p_bIncludeServices); - bool _announceService(stcMDNSService& p_rService, - bool p_bAnnounce = true); - - /* SERVICE QUERY CACHE */ - bool _hasServiceQueriesWaitingForAnswers(void) const; - bool _checkServiceQueryCache(void); - - /** TRANSFER **/ - /* SENDING */ - bool _sendMDNSMessage(stcMDNSSendParameter& p_SendParameter); - bool _sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter); - bool _prepareMDNSMessage(stcMDNSSendParameter& p_SendParameter, - IPAddress p_IPAddress); - bool _sendMDNSServiceQuery(const stcMDNSServiceQuery& p_ServiceQuery); - bool _sendMDNSQuery(const stcMDNS_RRDomain& p_QueryDomain, - uint16_t p_u16QueryType, - stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers = 0); - - const IPAddress _getResponseMulticastInterface() const - { - return IPAddress(m_netif->ip_addr); - } - - uint8_t _replyMaskForHost(const stcMDNS_RRHeader& p_RRHeader, - bool* p_pbFullNameMatch = 0) const; - uint8_t _replyMaskForService(const stcMDNS_RRHeader& p_RRHeader, - const stcMDNSService& p_Service, - bool* p_pbFullNameMatch = 0) const; - - /* RESOURCE RECORD */ - bool _readRRQuestion(stcMDNS_RRQuestion& p_rQuestion); - bool _readRRAnswer(stcMDNS_RRAnswer*& p_rpAnswer); -#ifdef MDNS_IP4_SUPPORT - bool _readRRAnswerA(stcMDNS_RRAnswerA& p_rRRAnswerA, - uint16_t p_u16RDLength); -#endif - bool _readRRAnswerPTR(stcMDNS_RRAnswerPTR& p_rRRAnswerPTR, - uint16_t p_u16RDLength); - bool _readRRAnswerTXT(stcMDNS_RRAnswerTXT& p_rRRAnswerTXT, - uint16_t p_u16RDLength); -#ifdef MDNS_IP6_SUPPORT - bool _readRRAnswerAAAA(stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA, - uint16_t p_u16RDLength); -#endif - bool _readRRAnswerSRV(stcMDNS_RRAnswerSRV& p_rRRAnswerSRV, - uint16_t p_u16RDLength); - bool _readRRAnswerGeneric(stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric, - uint16_t p_u16RDLength); - - bool _readRRHeader(stcMDNS_RRHeader& p_rHeader); - bool _readRRDomain(stcMDNS_RRDomain& p_rRRDomain); - bool _readRRDomain_Loop(stcMDNS_RRDomain& p_rRRDomain, - uint8_t p_u8Depth); - bool _readRRAttributes(stcMDNS_RRAttributes& p_rAttributes); - - /* DOMAIN NAMES */ - bool _buildDomainForHost(const char* p_pcHostname, - stcMDNS_RRDomain& p_rHostDomain) const; - bool _buildDomainForDNSSD(stcMDNS_RRDomain& p_rDNSSDDomain) const; - bool _buildDomainForService(const stcMDNSService& p_Service, - bool p_bIncludeName, - stcMDNS_RRDomain& p_rServiceDomain) const; - bool _buildDomainForService(const char* p_pcService, - const char* p_pcProtocol, - stcMDNS_RRDomain& p_rServiceDomain) const; -#ifdef MDNS_IP4_SUPPORT - bool _buildDomainForReverseIP4(IPAddress p_IP4Address, - stcMDNS_RRDomain& p_rReverseIP4Domain) const; -#endif -#ifdef MDNS_IP6_SUPPORT - bool _buildDomainForReverseIP6(IPAddress p_IP4Address, - stcMDNS_RRDomain& p_rReverseIP6Domain) const; -#endif - - /* UDP */ - bool _udpReadBuffer(unsigned char* p_pBuffer, - size_t p_stLength); - bool _udpRead8(uint8_t& p_ru8Value); - bool _udpRead16(uint16_t& p_ru16Value); - bool _udpRead32(uint32_t& p_ru32Value); - - bool _udpAppendBuffer(const unsigned char* p_pcBuffer, - size_t p_stLength); - bool _udpAppend8(uint8_t p_u8Value); - bool _udpAppend16(uint16_t p_u16Value); - bool _udpAppend32(uint32_t p_u32Value); - -#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER - bool _udpDump(bool p_bMovePointer = false); - bool _udpDump(unsigned p_uOffset, - unsigned p_uLength); -#endif - - /* READ/WRITE MDNS STRUCTS */ - bool _readMDNSMsgHeader(stcMDNS_MsgHeader& p_rMsgHeader); - - bool _write8(uint8_t p_u8Value, - stcMDNSSendParameter& p_rSendParameter); - bool _write16(uint16_t p_u16Value, - stcMDNSSendParameter& p_rSendParameter); - bool _write32(uint32_t p_u32Value, - stcMDNSSendParameter& p_rSendParameter); - - bool _writeMDNSMsgHeader(const stcMDNS_MsgHeader& p_MsgHeader, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSRRAttributes(const stcMDNS_RRAttributes& p_Attributes, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSRRDomain(const stcMDNS_RRDomain& p_Domain, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSHostDomain(const char* m_pcHostname, - bool p_bPrependRDLength, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSServiceDomain(const stcMDNSService& p_Service, - bool p_bIncludeName, - bool p_bPrependRDLength, - stcMDNSSendParameter& p_rSendParameter); - - bool _writeMDNSQuestion(stcMDNS_RRQuestion& p_Question, - stcMDNSSendParameter& p_rSendParameter); - -#ifdef MDNS_IP4_SUPPORT - bool _writeMDNSAnswer_A(IPAddress p_IPAddress, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress, - stcMDNSSendParameter& p_rSendParameter); -#endif - bool _writeMDNSAnswer_PTR_TYPE(stcMDNSService& p_rService, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_PTR_NAME(stcMDNSService& p_rService, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_TXT(stcMDNSService& p_rService, - stcMDNSSendParameter& p_rSendParameter); -#ifdef MDNS_IP6_SUPPORT - bool _writeMDNSAnswer_AAAA(IPAddress p_IPAddress, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress, - stcMDNSSendParameter& p_rSendParameter); -#endif - bool _writeMDNSAnswer_SRV(stcMDNSService& p_rService, - stcMDNSSendParameter& p_rSendParameter); - - /** HELPERS **/ - /* UDP CONTEXT */ - bool _callProcess(void); - bool _allocUDPContext(void); - bool _releaseUDPContext(void); - - /* SERVICE QUERY */ - stcMDNSServiceQuery* _allocServiceQuery(void); - bool _removeServiceQuery(stcMDNSServiceQuery* p_pServiceQuery); - bool _removeLegacyServiceQuery(void); - stcMDNSServiceQuery* _findServiceQuery(hMDNSServiceQuery p_hServiceQuery); - stcMDNSServiceQuery* _findLegacyServiceQuery(void); - bool _releaseServiceQueries(void); - stcMDNSServiceQuery* _findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceDomain, - const stcMDNSServiceQuery* p_pPrevServiceQuery); - - /* HOSTNAME */ - bool _setHostname(const char* p_pcHostname); - bool _releaseHostname(void); - - /* SERVICE */ - stcMDNSService* _allocService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port); - bool _releaseService(stcMDNSService* p_pService); - bool _releaseServices(void); - - stcMDNSService* _findService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol); - stcMDNSService* _findService(const hMDNSService p_hService); - - size_t _countServices(void) const; - - /* SERVICE TXT */ - stcMDNSServiceTxt* _allocServiceTxt(stcMDNSService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp); - bool _releaseServiceTxt(stcMDNSService* p_pService, - stcMDNSServiceTxt* p_pTxt); - stcMDNSServiceTxt* _updateServiceTxt(stcMDNSService* p_pService, - stcMDNSServiceTxt* p_pTxt, - const char* p_pcValue, - bool p_bTemp); - - stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService, - const char* p_pcKey); - stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService, - const hMDNSTxt p_hTxt); - - stcMDNSServiceTxt* _addServiceTxt(stcMDNSService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp); - - stcMDNSServiceTxt* _answerKeyValue(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - - bool _collectServiceTxts(stcMDNSService& p_rService); - bool _releaseTempServiceTxts(stcMDNSService& p_rService); - const stcMDNSServiceTxt* _serviceTxts(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol); - - /* MISC */ -#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER - bool _printRRDomain(const stcMDNS_RRDomain& p_rRRDomain) const; - bool _printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const; -#endif -}; - -}// namespace MDNSImplementation - -}// namespace esp8266 - -#endif // MDNS_H diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp deleted file mode 100644 index 41e9524aba..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp +++ /dev/null @@ -1,2134 +0,0 @@ -/* - LEAmDNS_Control.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include -#include - -/* - ESP8266mDNS Control.cpp -*/ - -extern "C" { -#include "user_interface.h" -} - -#include "LEAmDNS_lwIPdefs.h" -#include "LEAmDNS_Priv.h" - -namespace esp8266 -{ -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - CONTROL -*/ - - -/** - MAINTENANCE -*/ - -/* - MDNSResponder::_process - - Run the MDNS process. - Is called, every time the UDPContext receives data AND - should be called in every 'loop' by calling 'MDNS::update()'. - -*/ -bool MDNSResponder::_process(bool p_bUserContext) -{ - - bool bResult = true; - - if (!p_bUserContext) - { - - if ((m_pUDPContext) && // UDPContext available AND - (m_pUDPContext->next())) // has content - { - - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _update: Calling _parseMessage\n"));); - bResult = _parseMessage(); - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parsePacket %s\n"), (bResult ? "succeeded" : "FAILED"));); - } - } - else - { - bResult = (m_netif != nullptr) && - (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running - _updateProbeStatus() && // Probing - _checkServiceQueryCache(); // Service query cache check - } - return bResult; -} - -/* - MDNSResponder::_restart -*/ -bool MDNSResponder::_restart(void) -{ - - return ((m_netif != nullptr) && - (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running - (_resetProbeStatus(true)) && // Stop and restart probing - (_allocUDPContext())); // Restart UDP -} - - -/** - RECEIVING -*/ - -/* - MDNSResponder::_parseMessage -*/ -bool MDNSResponder::_parseMessage(void) -{ - DEBUG_EX_INFO( - unsigned long ulStartTime = millis(); - unsigned uStartMemory = ESP.getFreeHeap(); - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage (Time: %lu ms, heap: %u bytes, from %s(%u), to %s(%u))\n"), ulStartTime, uStartMemory, - IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), m_pUDPContext->getRemotePort(), - IPAddress(m_pUDPContext->getDestAddress()).toString().c_str(), m_pUDPContext->getLocalPort()); - ); - //DEBUG_EX_INFO(_udpDump();); - - bool bResult = false; - - stcMDNS_MsgHeader header; - if (_readMDNSMsgHeader(header)) - { - if (0 == header.m_4bOpcode) // A standard query - { - if (header.m_1bQR) // Received a response -> answers to a query - { - //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Reading answers: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); - bResult = _parseResponse(header); - } - else // Received a query (Questions) - { - //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Reading query: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); - bResult = _parseQuery(header); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Received UNEXPECTED opcode:%u. Ignoring message!\n"), header.m_4bOpcode);); - m_pUDPContext->flush(); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: FAILED to read header\n"));); - m_pUDPContext->flush(); - } - DEBUG_EX_INFO( - unsigned uFreeHeap = ESP.getFreeHeap(); - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Done (%s after %lu ms, ate %i bytes, remaining %u)\n\n"), (bResult ? "Succeeded" : "FAILED"), (millis() - ulStartTime), (uStartMemory - uFreeHeap), uFreeHeap); - ); - return bResult; -} - -/* - MDNSResponder::_parseQuery - - Queries are of interest in two cases: - 1. allow for tiebreaking while probing in the case of a race condition between two instances probing for - the same name at the same time - 2. provide answers to questions for our host domain or any presented service - - When reading the questions, a set of (planned) responses is created, eg. a reverse PTR question for the host domain - gets an A (IP address) response, a PTR question for the _services._dns-sd domain gets a PTR (type) response for any - registered service, ... - - As any mDNS responder should be able to handle 'legacy' queries (from DNS clients), this case is handled here also. - Legacy queries have got only one (unicast) question and are directed to the local DNS port (not the multicast port). - - 1. -*/ -bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader) -{ - - bool bResult = true; - - stcMDNSSendParameter sendParameter; - uint8_t u8HostOrServiceReplies = 0; - for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) - { - - stcMDNS_RRQuestion questionRR; - if ((bResult = _readRRQuestion(questionRR))) - { - // Define host replies, BUT only answer queries after probing is done - u8HostOrServiceReplies = - sendParameter.m_u8HostReplyMask |= (((m_bPassivModeEnabled) || - (ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus)) - ? _replyMaskForHost(questionRR.m_Header, 0) - : 0); - DEBUG_EX_INFO(if (u8HostOrServiceReplies) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Host reply needed 0x%X\n"), u8HostOrServiceReplies); - }); - - // Check tiebreak need for host domain - if (ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) - { - bool bFullNameMatch = false; - if ((_replyMaskForHost(questionRR.m_Header, &bFullNameMatch)) && - (bFullNameMatch)) - { - // We're in 'probing' state and someone is asking for our host domain: this might be - // a race-condition: Two host with the same domain names try simutanously to probe their domains - // See: RFC 6762, 8.2 (Tiebraking) - // However, we're using a max. reduced approach for tiebreaking here: The higher IP-address wins! - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Possible race-condition for host domain detected while probing.\n"));); - - m_HostProbeInformation.m_bTiebreakNeeded = true; - } - } - - // Define service replies - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - // Define service replies, BUT only answer queries after probing is done - uint8_t u8ReplyMaskForQuestion = (((m_bPassivModeEnabled) || - (ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus)) - ? _replyMaskForService(questionRR.m_Header, *pService, 0) - : 0); - u8HostOrServiceReplies |= (pService->m_u8ReplyMask |= u8ReplyMaskForQuestion); - DEBUG_EX_INFO(if (u8ReplyMaskForQuestion) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service reply needed for (%s.%s.%s): 0x%X (%s)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, u8ReplyMaskForQuestion, IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()); - }); - - // Check tiebreak need for service domain - if (ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) - { - bool bFullNameMatch = false; - if ((_replyMaskForService(questionRR.m_Header, *pService, &bFullNameMatch)) && - (bFullNameMatch)) - { - // We're in 'probing' state and someone is asking for this service domain: this might be - // a race-condition: Two services with the same domain names try simutanously to probe their domains - // See: RFC 6762, 8.2 (Tiebraking) - // However, we're using a max. reduced approach for tiebreaking here: The 'higher' SRV host wins! - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Possible race-condition for service domain %s.%s.%s detected while probing.\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - - pService->m_ProbeInformation.m_bTiebreakNeeded = true; - } - } - } - - // Handle unicast and legacy specialities - // If only one question asks for unicast reply, the whole reply packet is send unicast - if (((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) || // Unicast (maybe legacy) query OR - (questionRR.m_bUnicast)) && // Expressivly unicast query - (!sendParameter.m_bUnicast)) - { - - sendParameter.m_bUnicast = true; - sendParameter.m_bCacheFlush = false; - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Unicast response for %s!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str());); - - if ((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) && // Unicast (maybe legacy) query AND - (1 == p_MsgHeader.m_u16QDCount) && // Only one question AND - ((sendParameter.m_u8HostReplyMask) || // Host replies OR - (u8HostOrServiceReplies))) // Host or service replies available - { - // We're a match for this legacy query, BUT - // make sure, that the query comes from a local host - ip_info IPInfo_Local; - ip_info IPInfo_Remote; - if (((IPInfo_Remote.ip.addr = m_pUDPContext->getRemoteAddress())) && - (((wifi_get_ip_info(SOFTAP_IF, &IPInfo_Local)) && - (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))) || // Remote IP in SOFTAP's subnet OR - ((wifi_get_ip_info(STATION_IF, &IPInfo_Local)) && - (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))))) // Remote IP in STATION's subnet - { - - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Legacy query from local host %s, id %u!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), p_MsgHeader.m_u16ID);); - - sendParameter.m_u16ID = p_MsgHeader.m_u16ID; - sendParameter.m_bLegacyQuery = true; - sendParameter.m_pQuestions = new stcMDNS_RRQuestion; - if ((bResult = (0 != sendParameter.m_pQuestions))) - { - sendParameter.m_pQuestions->m_Header.m_Domain = questionRR.m_Header.m_Domain; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = questionRR.m_Header.m_Attributes.m_u16Type; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = questionRR.m_Header.m_Attributes.m_u16Class; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to add legacy question!\n"));); - } - } - else - { - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Legacy query from NON-LOCAL host!\n"));); - bResult = false; - } - } - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to read question!\n"));); - } - } // for questions - - //DEBUG_EX_INFO(if (u8HostOrServiceReplies) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Reply needed: %u (%s: %s->%s)\n"), u8HostOrServiceReplies, clsTimeSyncer::timestr(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), IPAddress(m_pUDPContext->getDestAddress()).toString().c_str()); } ); - - // Handle known answers - uint32_t u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); - DEBUG_EX_INFO(if ((u8HostOrServiceReplies) && (u32Answers)) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Known answers(%u):\n"), u32Answers); - }); - - for (uint32_t an = 0; ((bResult) && (an < u32Answers)); ++an) - { - stcMDNS_RRAnswer* pKnownRRAnswer = 0; - if (((bResult = _readRRAnswer(pKnownRRAnswer))) && - (pKnownRRAnswer)) - { - - if ((DNS_RRTYPE_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Type) && // No ANY type answer - (DNS_RRCLASS_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Class)) // No ANY class answer - { - - // Find match between planned answer (sendParameter.m_u8HostReplyMask) and this 'known answer' - uint8_t u8HostMatchMask = (sendParameter.m_u8HostReplyMask & _replyMaskForHost(pKnownRRAnswer->m_Header)); - if ((u8HostMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND - ((MDNS_HOST_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new host TTL (120s) - { - - // Compare contents - if (AnswerType_PTR == pKnownRRAnswer->answerType()) - { - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain == hostDomain)) - { - // Host domain match -#ifdef MDNS_IP4_SUPPORT - if (u8HostMatchMask & ContentFlag_PTR_IP4) - { - // IP4 PTR was asked for, but is already known -> skipping - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP4 PTR already known... skipping!\n"));); - sendParameter.m_u8HostReplyMask &= ~ContentFlag_PTR_IP4; - } -#endif -#ifdef MDNS_IP6_SUPPORT - if (u8HostMatchMask & ContentFlag_PTR_IP6) - { - // IP6 PTR was asked for, but is already known -> skipping - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP6 PTR already known... skipping!\n"));); - sendParameter.m_u8HostReplyMask &= ~ContentFlag_PTR_IP6; - } -#endif - } - } - else if (u8HostMatchMask & ContentFlag_A) - { - // IP4 address was asked for -#ifdef MDNS_IP4_SUPPORT - if ((AnswerType_A == pKnownRRAnswer->answerType()) && - (((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress == _getResponseMulticastInterface())) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP4 address already known... skipping!\n"));); - sendParameter.m_u8HostReplyMask &= ~ContentFlag_A; - } // else: RData NOT IP4 length !! -#endif - } - else if (u8HostMatchMask & ContentFlag_AAAA) - { - // IP6 address was asked for -#ifdef MDNS_IP6_SUPPORT - if ((AnswerType_AAAA == pAnswerRR->answerType()) && - (((stcMDNS_RRAnswerAAAA*)pAnswerRR)->m_IPAddress == _getResponseMulticastInterface())) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP6 address already known... skipping!\n"));); - sendParameter.m_u8HostReplyMask &= ~ContentFlag_AAAA; - } // else: RData NOT IP6 length !! -#endif - } - } // Host match /*and TTL*/ - - // - // Check host tiebreak possibility - if (m_HostProbeInformation.m_bTiebreakNeeded) - { - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (pKnownRRAnswer->m_Header.m_Domain == hostDomain)) - { - // Host domain match -#ifdef MDNS_IP4_SUPPORT - if (AnswerType_A == pKnownRRAnswer->answerType()) - { - IPAddress localIPAddress(_getResponseMulticastInterface()); - if (((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) - { - // SAME IP address -> We've received an old message from ourselfs (same IP) - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) WON (was an old message)!\n"));); - m_HostProbeInformation.m_bTiebreakNeeded = false; - } - else - { - if ((uint32_t)(((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST - { - // LOST tiebreak - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) LOST (lower)!\n"));); - _cancelProbingForHost(); - m_HostProbeInformation.m_bTiebreakNeeded = false; - } - else // WON tiebreak - { - //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) WON (higher IP)!\n"));); - m_HostProbeInformation.m_bTiebreakNeeded = false; - } - } - } -#endif -#ifdef MDNS_IP6_SUPPORT - if (AnswerType_AAAA == pAnswerRR->answerType()) - { - // TODO - } -#endif - } - } // Host tiebreak possibility - - // Check service answers - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - - uint8_t u8ServiceMatchMask = (pService->m_u8ReplyMask & _replyMaskForService(pKnownRRAnswer->m_Header, *pService)); - - if ((u8ServiceMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND - ((MDNS_SERVICE_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) - { - - if (AnswerType_PTR == pKnownRRAnswer->answerType()) - { - stcMDNS_RRDomain serviceDomain; - if ((u8ServiceMatchMask & ContentFlag_PTR_TYPE) && - (_buildDomainForService(*pService, false, serviceDomain)) && - (serviceDomain == ((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service type PTR already known... skipping!\n"));); - pService->m_u8ReplyMask &= ~ContentFlag_PTR_TYPE; - } - if ((u8ServiceMatchMask & ContentFlag_PTR_NAME) && - (_buildDomainForService(*pService, true, serviceDomain)) && - (serviceDomain == ((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service name PTR already known... skipping!\n"));); - pService->m_u8ReplyMask &= ~ContentFlag_PTR_NAME; - } - } - else if (u8ServiceMatchMask & ContentFlag_SRV) - { - DEBUG_EX_ERR(if (AnswerType_SRV != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: ERROR! INVALID answer type (SRV)!\n"));); - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (hostDomain == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match - { - - if ((MDNS_SRV_PRIORITY == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Priority) && - (MDNS_SRV_WEIGHT == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Weight) && - (pService->m_u16Port == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Port)) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service SRV answer already known... skipping!\n"));); - pService->m_u8ReplyMask &= ~ContentFlag_SRV; - } // else: Small differences -> send update message - } - } - else if (u8ServiceMatchMask & ContentFlag_TXT) - { - DEBUG_EX_ERR(if (AnswerType_TXT != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: ERROR! INVALID answer type (TXT)!\n"));); - _collectServiceTxts(*pService); - if (pService->m_Txts == ((stcMDNS_RRAnswerTXT*)pKnownRRAnswer)->m_Txts) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service TXT answer already known... skipping!\n"));); - pService->m_u8ReplyMask &= ~ContentFlag_TXT; - } - _releaseTempServiceTxts(*pService); - } - } // Service match and enough TTL - - // - // Check service tiebreak possibility - if (pService->m_ProbeInformation.m_bTiebreakNeeded) - { - stcMDNS_RRDomain serviceDomain; - if ((_buildDomainForService(*pService, true, serviceDomain)) && - (pKnownRRAnswer->m_Header.m_Domain == serviceDomain)) - { - // Service domain match - if (AnswerType_SRV == pKnownRRAnswer->answerType()) - { - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (hostDomain == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match - { - - // We've received an old message from ourselfs (same SRV) - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) won (was an old message)!\n"));); - pService->m_ProbeInformation.m_bTiebreakNeeded = false; - } - else - { - if (((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain > hostDomain) // The OTHER domain is 'higher' -> LOST - { - // LOST tiebreak - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) LOST (lower)!\n"));); - _cancelProbingForService(*pService); - pService->m_ProbeInformation.m_bTiebreakNeeded = false; - } - else // WON tiebreak - { - //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) won (higher)!\n"));); - pService->m_ProbeInformation.m_bTiebreakNeeded = false; - } - } - } - } - } // service tiebreak possibility - } // for services - } // ANY answers - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to read known answer!\n"));); - } - - if (pKnownRRAnswer) - { - delete pKnownRRAnswer; - pKnownRRAnswer = 0; - } - } // for answers - - if (bResult) - { - // Check, if a reply is needed - uint8_t u8ReplyNeeded = sendParameter.m_u8HostReplyMask; - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - u8ReplyNeeded |= pService->m_u8ReplyMask; - } - - if (u8ReplyNeeded) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Sending answer(0x%X)...\n"), u8ReplyNeeded);); - - sendParameter.m_bResponse = true; - sendParameter.m_bAuthorative = true; - - bResult = _sendMDNSMessage(sendParameter); - } - DEBUG_EX_INFO( - else - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: No reply needed\n")); - } - ); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Something FAILED!\n"));); - m_pUDPContext->flush(); - } - - // - // Check and reset tiebreak-states - if (m_HostProbeInformation.m_bTiebreakNeeded) - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: UNSOLVED tiebreak-need for host domain!\n"));); - m_HostProbeInformation.m_bTiebreakNeeded = false; - } - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - if (pService->m_ProbeInformation.m_bTiebreakNeeded) - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: UNSOLVED tiebreak-need for service domain (%s.%s.%s)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - pService->m_ProbeInformation.m_bTiebreakNeeded = false; - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_parseResponse - - Responses are of interest in two cases: - 1. find domain name conflicts while probing - 2. get answers to service queries - - In both cases any included questions are ignored - - 1. If any answer has a domain name similar to one of the domain names we're planning to use (and are probing for), - then we've got a 'probing conflict'. The conflict has to be solved on our side of the conflict (eg. by - setting a new hostname and restart probing). The callback 'm_fnProbeResultCallback' is called with - 'p_bProbeResult=false' in this case. - - 2. Service queries like '_http._tcp.local' will (if available) produce PTR, SRV, TXT and A/AAAA answers. - All stored answers are pivoted by the service instance name (from the PTR record). Other answer parts, - like host domain or IP address are than attached to this element. - Any answer part carries a TTL, this is also stored (incl. the reception time); if the TTL is '0' the - answer (part) is withdrawn by the sender and should be removed from any cache. RFC 6762, 10.1 proposes to - set the caches TTL-value to 1 second in such a case and to delete the item only, if no update has - has taken place in this second. - Answer parts may arrive in 'unsorted' order, so they are grouped into three levels: - Level 1: PRT - names the service instance (and is used as pivot), voids all other parts if is withdrawn or outdates - Level 2: SRV - links the instance name to a host domain and port, voids A/AAAA parts if is withdrawn or outdates - TXT - links the instance name to services TXTs - Level 3: A/AAAA - links the host domain to an IP address -*/ -bool MDNSResponder::_parseResponse(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse\n"));); - //DEBUG_EX_INFO(_udpDump();); - - bool bResult = false; - - // A response should be the result of a query or a probe - if ((_hasServiceQueriesWaitingForAnswers()) || // Waiting for query answers OR - (_hasProbesWaitingForAnswers())) // Probe responses - { - - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received a response\n")); - //_udpDump(); - ); - - bResult = true; - // - // Ignore questions here - stcMDNS_RRQuestion dummyRRQ; - for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received a response containing a question... ignoring!\n"));); - bResult = _readRRQuestion(dummyRRQ); - } // for queries - - // - // Read and collect answers - stcMDNS_RRAnswer* pCollectedRRAnswers = 0; - uint32_t u32NumberOfAnswerRRs = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); - for (uint32_t an = 0; ((bResult) && (an < u32NumberOfAnswerRRs)); ++an) - { - stcMDNS_RRAnswer* pRRAnswer = 0; - if (((bResult = _readRRAnswer(pRRAnswer))) && - (pRRAnswer)) - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: ADDING answer!\n"));); - pRRAnswer->m_pNext = pCollectedRRAnswers; - pCollectedRRAnswers = pRRAnswer; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED to read answer!\n"));); - if (pRRAnswer) - { - delete pRRAnswer; - pRRAnswer = 0; - } - bResult = false; - } - } // for answers - - // - // Process answers - if (bResult) - { - bResult = ((!pCollectedRRAnswers) || - (_processAnswers(pCollectedRRAnswers))); - } - else // Some failure while reading answers - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED to read answers!\n"));); - m_pUDPContext->flush(); - } - - // Delete collected answers - while (pCollectedRRAnswers) - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: DELETING answer!\n"));); - stcMDNS_RRAnswer* pNextAnswer = pCollectedRRAnswers->m_pNext; - delete pCollectedRRAnswers; - pCollectedRRAnswers = pNextAnswer; - } - } - else // Received an unexpected response -> ignore - { - /* DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received an unexpected response... ignoring!\nDUMP:\n")); - bool bDumpResult = true; - for (uint16_t qd=0; ((bDumpResult) && (qdflush(); - bResult = true; - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_processAnswers - Host: - A (0x01): eg. esp8266.local A OP TTL 123.456.789.012 - AAAA (01Cx): eg. esp8266.local AAAA OP TTL 1234:5678::90 - PTR (0x0C, IP4): eg. 012.789.456.123.in-addr.arpa PTR OP TTL esp8266.local - PTR (0x0C, IP6): eg. 90.0.0.0.0.0.0.0.0.0.0.0.78.56.34.12.ip6.arpa PTR OP TTL esp8266.local - Service: - PTR (0x0C, srv name): eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local - PTR (0x0C, srv type): eg. _services._dns-sd._udp.local PTR OP TTL _http._tcp.local - SRV (0x21): eg. MyESP._http._tcp.local SRV OP TTL PRIORITY WEIGHT PORT esp8266.local - TXT (0x10): eg. MyESP._http._tcp.local TXT OP TTL c#=1 - -*/ -bool MDNSResponder::_processAnswers(const MDNSResponder::stcMDNS_RRAnswer* p_pAnswers) -{ - - bool bResult = false; - - if (p_pAnswers) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Processing answers...\n"));); - bResult = true; - - // Answers may arrive in an unexpected order. So we loop our answers as long, as we - // can connect new information to service queries - bool bFoundNewKeyAnswer; - do - { - bFoundNewKeyAnswer = false; - - const stcMDNS_RRAnswer* pRRAnswer = p_pAnswers; - while ((pRRAnswer) && - (bResult)) - { - // 1. level answer (PTR) - if (AnswerType_PTR == pRRAnswer->answerType()) - { - // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local - bResult = _processPTRAnswer((stcMDNS_RRAnswerPTR*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new SRV or TXT answers to be linked to queries - } - // 2. level answers - // SRV -> host domain and port - else if (AnswerType_SRV == pRRAnswer->answerType()) - { - // eg. MyESP_http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local - bResult = _processSRVAnswer((stcMDNS_RRAnswerSRV*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new A/AAAA answers to be linked to queries - } - // TXT -> Txts - else if (AnswerType_TXT == pRRAnswer->answerType()) - { - // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 - bResult = _processTXTAnswer((stcMDNS_RRAnswerTXT*)pRRAnswer); - } - // 3. level answers -#ifdef MDNS_IP4_SUPPORT - // A -> IP4Address - else if (AnswerType_A == pRRAnswer->answerType()) - { - // eg. esp8266.local A xxxx xx 192.168.2.120 - bResult = _processAAnswer((stcMDNS_RRAnswerA*)pRRAnswer); - } -#endif -#ifdef MDNS_IP6_SUPPORT - // AAAA -> IP6Address - else if (AnswerType_AAAA == pRRAnswer->answerType()) - { - // eg. esp8266.local AAAA xxxx xx 09cf::0c - bResult = _processAAAAAnswer((stcMDNS_RRAnswerAAAA*)pRRAnswer); - } -#endif - - // Finally check for probing conflicts - // Host domain - if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && - ((AnswerType_A == pRRAnswer->answerType()) || - (AnswerType_AAAA == pRRAnswer->answerType()))) - { - - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (pRRAnswer->m_Header.m_Domain == hostDomain)) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Probing CONFLICT found with: %s.local\n"), m_pcHostname);); - _cancelProbingForHost(); - } - } - // Service domains - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && - ((AnswerType_TXT == pRRAnswer->answerType()) || - (AnswerType_SRV == pRRAnswer->answerType()))) - { - - stcMDNS_RRDomain serviceDomain; - if ((_buildDomainForService(*pService, true, serviceDomain)) && - (pRRAnswer->m_Header.m_Domain == serviceDomain)) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Probing CONFLICT found with: %s.%s.%s\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - _cancelProbingForService(*pService); - } - } - } - - pRRAnswer = pRRAnswer->m_pNext; // Next collected answer - } // while (answers) - } while ((bFoundNewKeyAnswer) && - (bResult)); - } // else: No answers provided - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_processPTRAnswer -*/ -bool MDNSResponder::_processPTRAnswer(const MDNSResponder::stcMDNS_RRAnswerPTR* p_pPTRAnswer, - bool& p_rbFoundNewKeyAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pPTRAnswer))) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Processing PTR answers...\n"));); - // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local - // Check pending service queries for eg. '_http._tcp' - - stcMDNSServiceQuery* pServiceQuery = _findNextServiceQueryByServiceType(p_pPTRAnswer->m_Header.m_Domain, 0); - while (pServiceQuery) - { - if (pServiceQuery->m_bAwaitingAnswers) - { - // Find answer for service domain (eg. MyESP._http._tcp.local) - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pPTRAnswer->m_PTRDomain); - if (pSQAnswer) // existing answer - { - if (p_pPTRAnswer->m_u32TTL) // Received update message - { - pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); // Update TTL tag - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Updated TTL(%d) for "), (int)p_pPTRAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - ); - } - else // received goodbye-message - { - pSQAnswer->m_TTLServiceDomain.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - ); - } - } - else if ((p_pPTRAnswer->m_u32TTL) && // Not just a goodbye-message - ((pSQAnswer = new stcMDNSServiceQuery::stcAnswer))) // Not yet included -> add answer - { - pSQAnswer->m_ServiceDomain = p_pPTRAnswer->m_PTRDomain; - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_ServiceDomain; - pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); - pSQAnswer->releaseServiceDomain(); - - bResult = pServiceQuery->addAnswer(pSQAnswer); - p_rbFoundNewKeyAnswer = true; - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_ServiceDomain), true); - } - } - } - pServiceQuery = _findNextServiceQueryByServiceType(p_pPTRAnswer->m_Header.m_Domain, pServiceQuery); - } - } // else: No p_pPTRAnswer - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_processSRVAnswer -*/ -bool MDNSResponder::_processSRVAnswer(const MDNSResponder::stcMDNS_RRAnswerSRV* p_pSRVAnswer, - bool& p_rbFoundNewKeyAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pSRVAnswer))) - { - // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pSRVAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available - { - if (p_pSRVAnswer->m_u32TTL) // First or update message (TTL != 0) - { - pSQAnswer->m_TTLHostDomainAndPort.set(p_pSRVAnswer->m_u32TTL); // Update TTL tag - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: Updated TTL(%d) for "), (int)p_pSRVAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); - ); - // Host domain & Port - if ((pSQAnswer->m_HostDomain != p_pSRVAnswer->m_SRVDomain) || - (pSQAnswer->m_u16Port != p_pSRVAnswer->m_u16Port)) - { - - pSQAnswer->m_HostDomain = p_pSRVAnswer->m_SRVDomain; - pSQAnswer->releaseHostDomain(); - pSQAnswer->m_u16Port = p_pSRVAnswer->m_u16Port; - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_HostDomainAndPort; - - p_rbFoundNewKeyAnswer = true; - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_HostDomainAndPort), true); - } - } - } - else // Goodby message - { - pSQAnswer->m_TTLHostDomainAndPort.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); - ); - } - } - pServiceQuery = pServiceQuery->m_pNext; - } // while(service query) - } // else: No p_pSRVAnswer - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_processTXTAnswer -*/ -bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT* p_pTXTAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pTXTAnswer))) - { - // eg. MyESP._http._tcp.local TXT xxxx xx c#=1 - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pTXTAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available - { - if (p_pTXTAnswer->m_u32TTL) // First or update message - { - pSQAnswer->m_TTLTxts.set(p_pTXTAnswer->m_u32TTL); // Update TTL tag - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: Updated TTL(%d) for "), (int)p_pTXTAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); - ); - if (!pSQAnswer->m_Txts.compare(p_pTXTAnswer->m_Txts)) - { - pSQAnswer->m_Txts = p_pTXTAnswer->m_Txts; - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_Txts; - pSQAnswer->releaseTxts(); - - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_Txts), true); - } - } - } - else // Goodby message - { - pSQAnswer->m_TTLTxts.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); - ); - } - } - pServiceQuery = pServiceQuery->m_pNext; - } // while(service query) - } // else: No p_pTXTAnswer - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: FAILED!\n")); - }); - return bResult; -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::_processAAnswer -*/ -bool MDNSResponder::_processAAnswer(const MDNSResponder::stcMDNS_RRAnswerA* p_pAAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pAAnswer))) - { - // eg. esp8266.local A xxxx xx 192.168.2.120 - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available - { - stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = pSQAnswer->findIP4Address(p_pAAnswer->m_IPAddress); - if (pIP4Address) - { - // Already known IP4 address - if (p_pAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL - { - pIP4Address->m_TTL.set(p_pAAnswer->m_u32TTL); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%d) for "), (int)p_pAAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP4Address (%s)\n"), pIP4Address->m_IPAddress.toString().c_str()); - ); - } - else // 'Goodbye' message for known IP4 address - { - pIP4Address->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP4 address (%s)\n"), pIP4Address->m_IPAddress.toString().c_str()); - ); - } - } - else - { - // Until now unknown IP4 address -> Add (if the message isn't just a 'Goodbye' note) - if (p_pAAnswer->m_u32TTL) // NOT just a 'Goodbye' message - { - pIP4Address = new stcMDNSServiceQuery::stcAnswer::stcIP4Address(p_pAAnswer->m_IPAddress, p_pAAnswer->m_u32TTL); - if ((pIP4Address) && - (pSQAnswer->addIP4Address(pIP4Address))) - { - - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_IP4Address; - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_IP4Address), true); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED to add IP4 address (%s)!\n"), p_pAAnswer->m_IPAddress.toString().c_str());); - } - } - } - } - pServiceQuery = pServiceQuery->m_pNext; - } // while(service query) - } // else: No p_pAAnswer - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED!\n")); - }); - return bResult; -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::_processAAAAAnswer -*/ -bool MDNSResponder::_processAAAAAnswer(const MDNSResponder::stcMDNS_RRAnswerAAAA* p_pAAAAAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pAAAAAnswer))) - { - // eg. esp8266.local AAAA xxxx xx 0bf3::0c - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available - { - stcIP6Address* pIP6Address = pSQAnswer->findIP6Address(p_pAAAAAnswer->m_IPAddress); - if (pIP6Address) - { - // Already known IP6 address - if (p_pAAAAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL - { - pIP6Address->m_TTL.set(p_pAAAAAnswer->m_u32TTL); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%lu) for "), p_pAAAAAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), pIP6Address->m_IPAddress.toString().c_str()); - ); - } - else // 'Goodbye' message for known IP6 address - { - pIP6Address->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), pIP6Address->m_IPAddress.toString().c_str()); - ); - } - } - else - { - // Until now unknown IP6 address -> Add (if the message isn't just a 'Goodbye' note) - if (p_pAAAAAnswer->m_u32TTL) // NOT just a 'Goodbye' message - { - pIP6Address = new stcIP6Address(p_pAAAAAnswer->m_IPAddress, p_pAAAAAnswer->m_u32TTL); - if ((pIP6Address) && - (pSQAnswer->addIP6Address(pIP6Address))) - { - - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_IP6Address; - - if (pServiceQuery->m_fnCallback) - { - pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP6Address, true, pServiceQuery->m_pUserdata); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED to add IP6 address (%s)!\n"), p_pAAAAAnswer->m_IPAddress.toString().c_str());); - } - } - } - } - pServiceQuery = pServiceQuery->m_pNext; - } // while(service query) - } // else: No p_pAAAAAnswer - - return bResult; -} -#endif - - -/* - PROBING -*/ - -/* - MDNSResponder::_updateProbeStatus - - Manages the (outgoing) probing process. - - If probing has not been started yet (ProbingStatus_NotStarted), the initial delay (see RFC 6762) is determined and - the process is started - - After timeout (of initial or subsequential delay) a probe message is send out for three times. If the message has - already been sent out three times, the probing has been successful and is finished. - - Conflict management is handled in '_parseResponse ff.' - Tiebraking is handled in 'parseQuery ff.' -*/ -bool MDNSResponder::_updateProbeStatus(void) -{ - - bool bResult = true; - - // - // Probe host domain - if ((ProbingStatus_ReadyToStart == m_HostProbeInformation.m_ProbingStatus) && // Ready to get started AND - //TODO: Fix the following to allow Ethernet shield or other interfaces - (_getResponseMulticastInterface() != IPAddress())) // Has IP address - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Starting host probing...\n"));); - - // First probe delay SHOULD be random 0-250 ms - m_HostProbeInformation.m_Timeout.reset(rand() % MDNS_PROBE_DELAY); - m_HostProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; - } - else if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing AND - (m_HostProbeInformation.m_Timeout.expired())) // Time for next probe - { - - if (MDNS_PROBE_COUNT > m_HostProbeInformation.m_u8SentCount) // Send next probe - { - if ((bResult = _sendHostProbe())) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Did sent host probe\n\n"));); - m_HostProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); - ++m_HostProbeInformation.m_u8SentCount; - } - } - else // Probing finished - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host probing.\n"));); - m_HostProbeInformation.m_ProbingStatus = ProbingStatus_Done; - m_HostProbeInformation.m_Timeout.resetToNeverExpires(); - if (m_HostProbeInformation.m_fnHostProbeResultCallback) - { - m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, true); - } - - // Prepare to announce host - m_HostProbeInformation.m_u8SentCount = 0; - m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Prepared host announcing.\n\n"));); - } - } // else: Probing already finished OR waiting for next time slot - else if ((ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) && - (m_HostProbeInformation.m_Timeout.expired())) - { - - if ((bResult = _announce(true, false))) // Don't announce services here - { - ++m_HostProbeInformation.m_u8SentCount; - - if (MDNS_ANNOUNCE_COUNT > m_HostProbeInformation.m_u8SentCount) - { - m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%d).\n\n"), m_HostProbeInformation.m_u8SentCount);); - } - else - { - m_HostProbeInformation.m_Timeout.resetToNeverExpires(); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host announcing.\n\n"));); - } - } - } - - // - // Probe services - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if (ProbingStatus_ReadyToStart == pService->m_ProbeInformation.m_ProbingStatus) // Ready to get started - { - - pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); // More or equal than first probe for host domain - pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; - } - else if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND - (pService->m_ProbeInformation.m_Timeout.expired())) // Time for next probe - { - - if (MDNS_PROBE_COUNT > pService->m_ProbeInformation.m_u8SentCount) // Send next probe - { - if ((bResult = _sendServiceProbe(*pService))) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Did sent service probe (%u)\n\n"), (pService->m_ProbeInformation.m_u8SentCount + 1));); - pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); - ++pService->m_ProbeInformation.m_u8SentCount; - } - } - else // Probing finished - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service probing %s.%s.%s\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_Done; - pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); - if (pService->m_ProbeInformation.m_fnServiceProbeResultCallback) - { - pService->m_ProbeInformation.m_fnServiceProbeResultCallback(pService->m_pcName, pService, true); - } - // Prepare to announce service - pService->m_ProbeInformation.m_u8SentCount = 0; - pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Prepared service announcing.\n\n"));); - } - } // else: Probing already finished OR waiting for next time slot - else if ((ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) && - (pService->m_ProbeInformation.m_Timeout.expired())) - { - - if ((bResult = _announceService(*pService))) // Announce service - { - ++pService->m_ProbeInformation.m_u8SentCount; - - if (MDNS_ANNOUNCE_COUNT > pService->m_ProbeInformation.m_u8SentCount) - { - pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing service %s.%s.%s (%d)\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount);); - } - else - { - pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service announcing for %s.%s.%s\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - } - } - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: FAILED!\n\n")); - }); - return bResult; -} - -/* - MDNSResponder::_resetProbeStatus - - Resets the probe status. - If 'p_bRestart' is set, the status is set to ProbingStatus_NotStarted. Consequently, - when running 'updateProbeStatus' (which is done in every '_update' loop), the probing - process is restarted. -*/ -bool MDNSResponder::_resetProbeStatus(bool p_bRestart /*= true*/) -{ - - m_HostProbeInformation.clear(false); - m_HostProbeInformation.m_ProbingStatus = (p_bRestart ? ProbingStatus_ReadyToStart : ProbingStatus_Done); - - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - pService->m_ProbeInformation.clear(false); - pService->m_ProbeInformation.m_ProbingStatus = (p_bRestart ? ProbingStatus_ReadyToStart : ProbingStatus_Done); - } - return true; -} - -/* - MDNSResponder::_hasProbesWaitingForAnswers -*/ -bool MDNSResponder::_hasProbesWaitingForAnswers(void) const -{ - - bool bResult = ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing - (0 < m_HostProbeInformation.m_u8SentCount)); // And really probing - - for (stcMDNSService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) - { - bResult = ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing - (0 < pService->m_ProbeInformation.m_u8SentCount)); // And really probing - } - return bResult; -} - -/* - MDNSResponder::_sendHostProbe - - Asks (probes) in the local network for the planned host domain - - (eg. esp8266.local) - - To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in - the 'knwon answers' section of the query. - Host domain: - - A/AAAA (eg. esp8266.esp -> 192.168.2.120) -*/ -bool MDNSResponder::_sendHostProbe(void) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe (%s, %lu)\n"), m_pcHostname, millis());); - - bool bResult = true; - - // Requests for host domain - stcMDNSSendParameter sendParameter; - sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 - - sendParameter.m_pQuestions = new stcMDNS_RRQuestion; - if (((bResult = (0 != sendParameter.m_pQuestions))) && - ((bResult = _buildDomainForHost(m_pcHostname, sendParameter.m_pQuestions->m_Header.m_Domain)))) - { - - //sendParameter.m_pQuestions->m_bUnicast = true; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet - - // Add known answers -#ifdef MDNS_IP4_SUPPORT - sendParameter.m_u8HostReplyMask |= ContentFlag_A; // Add A answer -#endif -#ifdef MDNS_IP6_SUPPORT - sendParameter.m_u8HostReplyMask |= ContentFlag_AAAA; // Add AAAA answer -#endif - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe: FAILED to create host question!\n"));); - if (sendParameter.m_pQuestions) - { - delete sendParameter.m_pQuestions; - sendParameter.m_pQuestions = 0; - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe: FAILED!\n")); - }); - return ((bResult) && - (_sendMDNSMessage(sendParameter))); -} - -/* - MDNSResponder::_sendServiceProbe - - Asks (probes) in the local network for the planned service instance domain - - (eg. MyESP._http._tcp.local). - - To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in - the 'knwon answers' section of the query. - Service domain: - - SRV (eg. MyESP._http._tcp.local -> 5000 esp8266.local) - - PTR NAME (eg. _http._tcp.local -> MyESP._http._tcp.local) (TODO: Check if needed, maybe TXT is better) -*/ -bool MDNSResponder::_sendServiceProbe(stcMDNSService& p_rService) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe (%s.%s.%s, %lu)\n"), (p_rService.m_pcName ? : m_pcHostname), p_rService.m_pcService, p_rService.m_pcProtocol, millis());); - - bool bResult = true; - - // Requests for service instance domain - stcMDNSSendParameter sendParameter; - sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 - - sendParameter.m_pQuestions = new stcMDNS_RRQuestion; - if (((bResult = (0 != sendParameter.m_pQuestions))) && - ((bResult = _buildDomainForService(p_rService, true, sendParameter.m_pQuestions->m_Header.m_Domain)))) - { - - sendParameter.m_pQuestions->m_bUnicast = true; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet - - // Add known answers - p_rService.m_u8ReplyMask = (ContentFlag_SRV | ContentFlag_PTR_NAME); // Add SRV and PTR NAME answers - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe: FAILED to create service question!\n"));); - if (sendParameter.m_pQuestions) - { - delete sendParameter.m_pQuestions; - sendParameter.m_pQuestions = 0; - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe: FAILED!\n")); - }); - return ((bResult) && - (_sendMDNSMessage(sendParameter))); -} - -/* - MDNSResponder::_cancelProbingForHost -*/ -bool MDNSResponder::_cancelProbingForHost(void) -{ - - bool bResult = false; - - m_HostProbeInformation.clear(false); - // Send host notification - if (m_HostProbeInformation.m_fnHostProbeResultCallback) - { - m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, false); - - bResult = true; - } - - for (stcMDNSService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) - { - bResult = _cancelProbingForService(*pService); - } - return bResult; -} - -/* - MDNSResponder::_cancelProbingForService -*/ -bool MDNSResponder::_cancelProbingForService(stcMDNSService& p_rService) -{ - - bool bResult = false; - - p_rService.m_ProbeInformation.clear(false); - // Send notification - if (p_rService.m_ProbeInformation.m_fnServiceProbeResultCallback) - { - p_rService.m_ProbeInformation.m_fnServiceProbeResultCallback(p_rService.m_pcName, &p_rService, false); - bResult = true; - } - return bResult; -} - - - -/** - ANNOUNCING -*/ - -/* - MDNSResponder::_announce - - Announces the host domain: - - A/AAAA (eg. esp8266.local -> 192.168.2.120) - - PTR (eg. 192.168.2.120.in-addr.arpa -> esp8266.local) - - and all presented services: - - PTR_TYPE (_services._dns-sd._udp.local -> _http._tcp.local) - - PTR_NAME (eg. _http._tcp.local -> MyESP8266._http._tcp.local) - - SRV (eg. MyESP8266._http._tcp.local -> 5000 esp8266.local) - - TXT (eg. MyESP8266._http._tcp.local -> c#=1) - - Goodbye (Un-Announcing) for the host domain and all services is also handled here. - Goodbye messages are created by setting the TTL for the answer to 0, this happens - inside the '_writeXXXAnswer' procs via 'sendParameter.m_bUnannounce = true' -*/ -bool MDNSResponder::_announce(bool p_bAnnounce, - bool p_bIncludeServices) -{ - - bool bResult = false; - - stcMDNSSendParameter sendParameter; - if (ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) - { - - bResult = true; - - sendParameter.m_bResponse = true; // Announces are 'Unsolicited authorative responses' - sendParameter.m_bAuthorative = true; - sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers - - // Announce host - sendParameter.m_u8HostReplyMask = 0; -#ifdef MDNS_IP4_SUPPORT - sendParameter.m_u8HostReplyMask |= ContentFlag_A; // A answer - sendParameter.m_u8HostReplyMask |= ContentFlag_PTR_IP4; // PTR_IP4 answer -#endif -#ifdef MDNS_IP6_SUPPORT - sendParameter.m_u8HostReplyMask |= ContentFlag_AAAA; // AAAA answer - sendParameter.m_u8HostReplyMask |= ContentFlag_PTR_IP6; // PTR_IP6 answer -#endif - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing host %s (content 0x%X)\n"), m_pcHostname, sendParameter.m_u8HostReplyMask);); - - if (p_bIncludeServices) - { - // Announce services (service type, name, SRV (location) and TXTs) - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if (ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) - { - pService->m_u8ReplyMask = (ContentFlag_PTR_TYPE | ContentFlag_PTR_NAME | ContentFlag_SRV | ContentFlag_TXT); - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing service %s.%s.%s (content %u)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_u8ReplyMask);); - } - } - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: FAILED!\n")); - }); - return ((bResult) && - (_sendMDNSMessage(sendParameter))); -} - -/* - MDNSResponder::_announceService -*/ -bool MDNSResponder::_announceService(stcMDNSService& p_rService, - bool p_bAnnounce /*= true*/) -{ - - bool bResult = false; - - stcMDNSSendParameter sendParameter; - if (ProbingStatus_Done == p_rService.m_ProbeInformation.m_ProbingStatus) - { - - sendParameter.m_bResponse = true; // Announces are 'Unsolicited authorative responses' - sendParameter.m_bAuthorative = true; - sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers - - // DON'T announce host - sendParameter.m_u8HostReplyMask = 0; - - // Announce services (service type, name, SRV (location) and TXTs) - p_rService.m_u8ReplyMask = (ContentFlag_PTR_TYPE | ContentFlag_PTR_NAME | ContentFlag_SRV | ContentFlag_TXT); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: Announcing service %s.%s.%s (content 0x%X)\n"), (p_rService.m_pcName ? : m_pcHostname), p_rService.m_pcService, p_rService.m_pcProtocol, p_rService.m_u8ReplyMask);); - - bResult = true; - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: FAILED!\n")); - }); - return ((bResult) && - (_sendMDNSMessage(sendParameter))); -} - - -/** - SERVICE QUERY CACHE -*/ - -/* - MDNSResponder::_hasServiceQueriesWaitingForAnswers -*/ -bool MDNSResponder::_hasServiceQueriesWaitingForAnswers(void) const -{ - - bool bOpenQueries = false; - - for (stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; pServiceQuery; pServiceQuery = pServiceQuery->m_pNext) - { - if (pServiceQuery->m_bAwaitingAnswers) - { - bOpenQueries = true; - break; - } - } - return bOpenQueries; -} - -/* - MDNSResponder::_checkServiceQueryCache - - For any 'living' service query (m_bAwaitingAnswers == true) all available answers (their components) - are checked for topicality based on the stored reception time and the answers TTL. - When the components TTL is outlasted by more than 80%, a new question is generated, to get updated information. - When no update arrived (in time), the component is removed from the answer (cache). - -*/ -bool MDNSResponder::_checkServiceQueryCache(void) -{ - - bool bResult = true; - - DEBUG_EX_INFO( - bool printedInfo = false; - ); - for (stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; ((bResult) && (pServiceQuery)); pServiceQuery = pServiceQuery->m_pNext) - { - - // - // Resend dynamic service queries, if not already done often enough - if ((!pServiceQuery->m_bLegacyQuery) && - (MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) && - (pServiceQuery->m_ResendTimeout.expired())) - { - - if ((bResult = _sendMDNSServiceQuery(*pServiceQuery))) - { - ++pServiceQuery->m_u8SentCount; - pServiceQuery->m_ResendTimeout.reset((MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) - ? (MDNS_DYNAMIC_QUERY_RESEND_DELAY * (pServiceQuery->m_u8SentCount - 1)) - : esp8266::polledTimeout::oneShotMs::neverExpires); - } - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: %s to resend service query!"), (bResult ? "Succeeded" : "FAILED")); - printedInfo = true; - ); - } - - // - // Schedule updates for cached answers - if (pServiceQuery->m_bAwaitingAnswers) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->m_pAnswers; - while ((bResult) && - (pSQAnswer)) - { - stcMDNSServiceQuery::stcAnswer* pNextSQAnswer = pSQAnswer->m_pNext; - - // 1. level answer - if ((bResult) && - (pSQAnswer->m_TTLServiceDomain.flagged())) - { - - if (!pSQAnswer->m_TTLServiceDomain.finalTimeoutLevel()) - { - - bResult = ((_sendMDNSServiceQuery(*pServiceQuery)) && - (pSQAnswer->m_TTLServiceDomain.restart())); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: PTR update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), (bResult ? "OK" : "FAILURE")); - printedInfo = true; - ); - } - else - { - // Timed out! -> Delete - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_ServiceDomain), false); - } - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove PTR answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - printedInfo = true; - ); - - bResult = pServiceQuery->removeAnswer(pSQAnswer); - pSQAnswer = 0; - continue; // Don't use this answer anymore - } - } // ServiceDomain flagged - - // 2. level answers - // HostDomain & Port (from SRV) - if ((bResult) && - (pSQAnswer->m_TTLHostDomainAndPort.flagged())) - { - - if (!pSQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) - { - - bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_SRV)) && - (pSQAnswer->m_TTLHostDomainAndPort.restart())); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: SRV update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" host domain and port %s\n"), (bResult ? "OK" : "FAILURE")); - printedInfo = true; - ); - } - else - { - // Timed out! -> Delete - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove SRV answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); - printedInfo = true; - ); - // Delete - pSQAnswer->m_HostDomain.clear(); - pSQAnswer->releaseHostDomain(); - pSQAnswer->m_u16Port = 0; - pSQAnswer->m_TTLHostDomainAndPort.set(0); - uint32_t u32ContentFlags = ServiceQueryAnswerType_HostDomainAndPort; - // As the host domain is the base for the IP4- and IP6Address, remove these too -#ifdef MDNS_IP4_SUPPORT - pSQAnswer->releaseIP4Addresses(); - u32ContentFlags |= ServiceQueryAnswerType_IP4Address; -#endif -#ifdef MDNS_IP6_SUPPORT - pSQAnswer->releaseIP6Addresses(); - u32ContentFlags |= ServiceQueryAnswerType_IP6Address; -#endif - - // Remove content flags for deleted answer parts - pSQAnswer->m_u32ContentFlags &= ~u32ContentFlags; - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(u32ContentFlags), false); - } - } - } // HostDomainAndPort flagged - - // Txts (from TXT) - if ((bResult) && - (pSQAnswer->m_TTLTxts.flagged())) - { - - if (!pSQAnswer->m_TTLTxts.finalTimeoutLevel()) - { - - bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_TXT)) && - (pSQAnswer->m_TTLTxts.restart())); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: TXT update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" TXTs %s\n"), (bResult ? "OK" : "FAILURE")); - printedInfo = true; - ); - } - else - { - // Timed out! -> Delete - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove TXT answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); - printedInfo = true; - ); - // Delete - pSQAnswer->m_Txts.clear(); - pSQAnswer->m_TTLTxts.set(0); - - // Remove content flags for deleted answer parts - pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_Txts; - - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_Txts), false); - } - } - } // TXTs flagged - - // 3. level answers -#ifdef MDNS_IP4_SUPPORT - // IP4Address (from A) - stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = pSQAnswer->m_pIP4Addresses; - bool bAUpdateQuerySent = false; - while ((pIP4Address) && - (bResult)) - { - - stcMDNSServiceQuery::stcAnswer::stcIP4Address* pNextIP4Address = pIP4Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... - - if (pIP4Address->m_TTL.flagged()) - { - - if (!pIP4Address->m_TTL.finalTimeoutLevel()) // Needs update - { - - if ((bAUpdateQuerySent) || - ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_A)))) - { - - pIP4Address->m_TTL.restart(); - bAUpdateQuerySent = true; - - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: IP4 update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP4 address (%s)\n"), (pIP4Address->m_IPAddress.toString().c_str())); - printedInfo = true; - ); - } - } - else - { - // Timed out! -> Delete - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove IP4 answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP4 address\n")); - printedInfo = true; - ); - pSQAnswer->removeIP4Address(pIP4Address); - if (!pSQAnswer->m_pIP4Addresses) // NO IP4 address left -> remove content flag - { - pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_IP4Address; - } - // Notify client - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_IP4Address), false); - } - } - } // IP4 flagged - - pIP4Address = pNextIP4Address; // Next - } // while -#endif -#ifdef MDNS_IP6_SUPPORT - // IP6Address (from AAAA) - stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = pSQAnswer->m_pIP6Addresses; - bool bAAAAUpdateQuerySent = false; - while ((pIP6Address) && - (bResult)) - { - - stcMDNSServiceQuery::stcAnswer::stcIP6Address* pNextIP6Address = pIP6Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... - - if (pIP6Address->m_TTL.flagged()) - { - - if (!pIP6Address->m_TTL.finalTimeoutLevel()) // Needs update - { - - if ((bAAAAUpdateQuerySent) || - ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) - { - - pIP6Address->m_TTL.restart(); - bAAAAUpdateQuerySent = true; - - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: IP6 update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), (pIP6Address->m_IPAddress.toString().c_str())); - printedInfo = true; - ); - } - } - else - { - // Timed out! -> Delete - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP6Address\n")); - printedInfo = true; - ); - pSQAnswer->removeIP6Address(pIP6Address); - if (!pSQAnswer->m_pIP6Addresses) // NO IP6 address left -> remove content flag - { - pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_IP6Address; - } - // Notify client - if (pServiceQuery->m_fnCallback) - { - pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP6Address, false, pServiceQuery->m_pUserdata); - } - } - } // IP6 flagged - - pIP6Address = pNextIP6Address; // Next - } // while -#endif - pSQAnswer = pNextSQAnswer; - } - } - } - DEBUG_EX_INFO( - if (printedInfo) -{ - DEBUG_OUTPUT.printf_P(PSTR("\n")); - } - ); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: FAILED!\n")); - }); - return bResult; -} - - -/* - MDNSResponder::_replyMaskForHost - - Determines the relavant host answers for the given question. - - A question for the hostname (eg. esp8266.local) will result in an A/AAAA (eg. 192.168.2.129) reply. - - A question for the reverse IP address (eg. 192-168.2.120.inarpa.arpa) will result in an PTR_IP4 (eg. esp8266.local) reply. - - In addition, a full name match (question domain == host domain) is marked. -*/ -uint8_t MDNSResponder::_replyMaskForHost(const MDNSResponder::stcMDNS_RRHeader& p_RRHeader, - bool* p_pbFullNameMatch /*= 0*/) const -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost\n"));); - - uint8_t u8ReplyMask = 0; - (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); - - if ((DNS_RRCLASS_IN == p_RRHeader.m_Attributes.m_u16Class) || - (DNS_RRCLASS_ANY == p_RRHeader.m_Attributes.m_u16Class)) - { - - if ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // PTR request -#ifdef MDNS_IP4_SUPPORT - stcMDNS_RRDomain reverseIP4Domain; - if ((_buildDomainForReverseIP4(_getResponseMulticastInterface(), reverseIP4Domain)) && - (p_RRHeader.m_Domain == reverseIP4Domain)) - { - // Reverse domain match - u8ReplyMask |= ContentFlag_PTR_IP4; - } -#endif -#ifdef MDNS_IP6_SUPPORT - // TODO -#endif - } // Address qeuest - - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (p_RRHeader.m_Domain == hostDomain)) // Host domain match - { - - (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); - -#ifdef MDNS_IP4_SUPPORT - if ((DNS_RRTYPE_A == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // IP4 address request - u8ReplyMask |= ContentFlag_A; - } -#endif -#ifdef MDNS_IP6_SUPPORT - if ((DNS_RRTYPE_AAAA == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // IP6 address request - u8ReplyMask |= ContentFlag_AAAA; - } -#endif - } - } - else - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); - } - DEBUG_EX_INFO(if (u8ReplyMask) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: 0x%X\n"), u8ReplyMask); - }); - return u8ReplyMask; -} - -/* - MDNSResponder::_replyMaskForService - - Determines the relevant service answers for the given question - - A PTR dns-sd service enum question (_services.dns-sd._udp.local) will result into an PTR_TYPE (eg. _http._tcp.local) answer - - A PTR service type question (eg. _http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer - - A PTR service name question (eg. MyESP._http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer - - A SRV service name question (eg. MyESP._http._tcp.local) will result into an SRV (eg. 5000 MyESP.local) answer - - A TXT service name question (eg. MyESP._http._tcp.local) will result into an TXT (eg. c#=1) answer - - In addition, a full name match (question domain == service instance domain) is marked. -*/ -uint8_t MDNSResponder::_replyMaskForService(const MDNSResponder::stcMDNS_RRHeader& p_RRHeader, - const MDNSResponder::stcMDNSService& p_Service, - bool* p_pbFullNameMatch /*= 0*/) const -{ - - uint8_t u8ReplyMask = 0; - (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); - - if ((DNS_RRCLASS_IN == p_RRHeader.m_Attributes.m_u16Class) || - (DNS_RRCLASS_ANY == p_RRHeader.m_Attributes.m_u16Class)) - { - - stcMDNS_RRDomain DNSSDDomain; - if ((_buildDomainForDNSSD(DNSSDDomain)) && // _services._dns-sd._udp.local - (p_RRHeader.m_Domain == DNSSDDomain) && - ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) - { - // Common service info requested - u8ReplyMask |= ContentFlag_PTR_TYPE; - } - - stcMDNS_RRDomain serviceDomain; - if ((_buildDomainForService(p_Service, false, serviceDomain)) && // eg. _http._tcp.local - (p_RRHeader.m_Domain == serviceDomain) && - ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) - { - // Special service info requested - u8ReplyMask |= ContentFlag_PTR_NAME; - } - - if ((_buildDomainForService(p_Service, true, serviceDomain)) && // eg. MyESP._http._tcp.local - (p_RRHeader.m_Domain == serviceDomain)) - { - - (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); - - if ((DNS_RRTYPE_SRV == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // Instance info SRV requested - u8ReplyMask |= ContentFlag_SRV; - } - if ((DNS_RRTYPE_TXT == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // Instance info TXT requested - u8ReplyMask |= ContentFlag_TXT; - } - } - } - else - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForService: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); - } - DEBUG_EX_INFO(if (u8ReplyMask) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForService(%s.%s.%s): 0x%X\n"), p_Service.m_pcName, p_Service.m_pcService, p_Service.m_pcProtocol, u8ReplyMask); - }); - return u8ReplyMask; -} - -} // namespace MDNSImplementation - -} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp deleted file mode 100644 index d23941ce53..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp +++ /dev/null @@ -1,850 +0,0 @@ -/* - LEAmDNS_Helpers.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include "lwip/igmp.h" - -#include "LEAmDNS_lwIPdefs.h" -#include "LEAmDNS_Priv.h" - - -namespace -{ - -/* - strrstr (static) - - Backwards search for p_pcPattern in p_pcString - Based on: https://stackoverflow.com/a/1634398/2778898 - -*/ -const char* strrstr(const char*__restrict p_pcString, const char*__restrict p_pcPattern) -{ - - const char* pcResult = 0; - - size_t stStringLength = (p_pcString ? strlen(p_pcString) : 0); - size_t stPatternLength = (p_pcPattern ? strlen(p_pcPattern) : 0); - - if ((stStringLength) && - (stPatternLength) && - (stPatternLength <= stStringLength)) - { - // Pattern is shorter or has the same length tham the string - - for (const char* s = (p_pcString + stStringLength - stPatternLength); s >= p_pcString; --s) - { - if (0 == strncmp(s, p_pcPattern, stPatternLength)) - { - pcResult = s; - break; - } - } - } - return pcResult; -} - - -} // anonymous - - - - - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - HELPERS -*/ - -/* - MDNSResponder::indexDomain (static) - - Updates the given domain 'p_rpcHostname' by appending a delimiter and an index number. - - If the given domain already hasa numeric index (after the given delimiter), this index - incremented. If not, the delimiter and index '2' is added. - - If 'p_rpcHostname' is empty (==0), the given default name 'p_pcDefaultHostname' is used, - if no default is given, 'esp8266' is used. - -*/ -/*static*/ bool MDNSResponder::indexDomain(char*& p_rpcDomain, - const char* p_pcDivider /*= "-"*/, - const char* p_pcDefaultDomain /*= 0*/) -{ - - bool bResult = false; - - // Ensure a divider exists; use '-' as default - const char* pcDivider = (p_pcDivider ? : "-"); - - if (p_rpcDomain) - { - const char* pFoundDivider = strrstr(p_rpcDomain, pcDivider); - if (pFoundDivider) // maybe already extended - { - char* pEnd = 0; - unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10); - if ((ulIndex) && - ((pEnd - p_rpcDomain) == (ptrdiff_t)strlen(p_rpcDomain)) && - (!*pEnd)) // Valid (old) index found - { - - char acIndexBuffer[16]; - sprintf(acIndexBuffer, "%lu", (++ulIndex)); - size_t stLength = ((pFoundDivider - p_rpcDomain + strlen(pcDivider)) + strlen(acIndexBuffer) + 1); - char* pNewHostname = new char[stLength]; - if (pNewHostname) - { - memcpy(pNewHostname, p_rpcDomain, (pFoundDivider - p_rpcDomain + strlen(pcDivider))); - pNewHostname[pFoundDivider - p_rpcDomain + strlen(pcDivider)] = 0; - strcat(pNewHostname, acIndexBuffer); - - delete[] p_rpcDomain; - p_rpcDomain = pNewHostname; - - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); - } - } - else - { - pFoundDivider = 0; // Flag the need to (base) extend the hostname - } - } - - if (!pFoundDivider) // not yet extended (or failed to increment extension) -> start indexing - { - size_t stLength = strlen(p_rpcDomain) + (strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0' - char* pNewHostname = new char[stLength]; - if (pNewHostname) - { - sprintf(pNewHostname, "%s%s2", p_rpcDomain, pcDivider); - - delete[] p_rpcDomain; - p_rpcDomain = pNewHostname; - - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); - } - } - } - else - { - // No given host domain, use base or default - const char* cpcDefaultName = (p_pcDefaultDomain ? : "esp8266"); - - size_t stLength = strlen(cpcDefaultName) + 1; // '\0' - p_rpcDomain = new char[stLength]; - if (p_rpcDomain) - { - strncpy(p_rpcDomain, cpcDefaultName, stLength); - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); - } - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: %s\n"), p_rpcDomain);); - return bResult; -} - - -/* - UDP CONTEXT -*/ - -bool MDNSResponder::_callProcess(void) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf("[MDNSResponder] _callProcess (%lu, triggered by: %s)\n", millis(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str());); - - return _process(false); -} - -/* - MDNSResponder::_allocUDPContext - - (Re-)Creates the one-and-only UDP context for the MDNS responder. - The context is added to the 'multicast'-group and listens to the MDNS port (5353). - The travel-distance for multicast messages is set to 1 (local, via MDNS_MULTICAST_TTL). - Messages are received via the MDNSResponder '_update' function. CAUTION: This function - is called from the WiFi stack side of the ESP stack system. - -*/ -bool MDNSResponder::_allocUDPContext(void) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.println("[MDNSResponder] _allocUDPContext");); - - bool bResult = false; - - _releaseUDPContext(); - -#ifdef MDNS_IP4_SUPPORT - ip_addr_t multicast_addr = DNS_MQUERY_IPV4_GROUP_INIT; -#endif -#ifdef MDNS_IP6_SUPPORT - //TODO: set multicast address (lwip_joingroup() is IPv4 only at the time of writing) - multicast_addr.addr = DNS_MQUERY_IPV6_GROUP_INIT; -#endif - if (ERR_OK == igmp_joingroup(ip_2_ip4(&m_netif->ip_addr), ip_2_ip4(&multicast_addr))) - { - m_pUDPContext = new UdpContext; - m_pUDPContext->ref(); - - if (m_pUDPContext->listen(IP4_ADDR_ANY, DNS_MQUERY_PORT)) - { - m_pUDPContext->setMulticastTTL(MDNS_MULTICAST_TTL); - m_pUDPContext->onRx(std::bind(&MDNSResponder::_callProcess, this)); - - bResult = m_pUDPContext->connect(&multicast_addr, DNS_MQUERY_PORT); - } - } - return bResult; -} - -/* - MDNSResponder::_releaseUDPContext -*/ -bool MDNSResponder::_releaseUDPContext(void) -{ - - if (m_pUDPContext) - { - m_pUDPContext->unref(); - m_pUDPContext = 0; - } - return true; -} - - -/* - SERVICE QUERY -*/ - -/* - MDNSResponder::_allocServiceQuery -*/ -MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_allocServiceQuery(void) -{ - - stcMDNSServiceQuery* pServiceQuery = new stcMDNSServiceQuery; - if (pServiceQuery) - { - // Link to query list - pServiceQuery->m_pNext = m_pServiceQueries; - m_pServiceQueries = pServiceQuery; - } - return m_pServiceQueries; -} - -/* - MDNSResponder::_removeServiceQuery -*/ -bool MDNSResponder::_removeServiceQuery(MDNSResponder::stcMDNSServiceQuery* p_pServiceQuery) -{ - - bool bResult = false; - - if (p_pServiceQuery) - { - stcMDNSServiceQuery* pPred = m_pServiceQueries; - while ((pPred) && - (pPred->m_pNext != p_pServiceQuery)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pServiceQuery->m_pNext; - delete p_pServiceQuery; - bResult = true; - } - else // No predecesor - { - if (m_pServiceQueries == p_pServiceQuery) - { - m_pServiceQueries = p_pServiceQuery->m_pNext; - delete p_pServiceQuery; - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseServiceQuery: INVALID service query!");); - } - } - } - return bResult; -} - -/* - MDNSResponder::_removeLegacyServiceQuery -*/ -bool MDNSResponder::_removeLegacyServiceQuery(void) -{ - - stcMDNSServiceQuery* pLegacyServiceQuery = _findLegacyServiceQuery(); - return (pLegacyServiceQuery ? _removeServiceQuery(pLegacyServiceQuery) : true); -} - -/* - MDNSResponder::_findServiceQuery - - 'Convert' hMDNSServiceQuery to stcMDNSServiceQuery* (ensure existance) - -*/ -MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) -{ - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - if ((hMDNSServiceQuery)pServiceQuery == p_hServiceQuery) - { - break; - } - pServiceQuery = pServiceQuery->m_pNext; - } - return pServiceQuery; -} - -/* - MDNSResponder::_findLegacyServiceQuery -*/ -MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findLegacyServiceQuery(void) -{ - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - if (pServiceQuery->m_bLegacyQuery) - { - break; - } - pServiceQuery = pServiceQuery->m_pNext; - } - return pServiceQuery; -} - -/* - MDNSResponder::_releaseServiceQueries -*/ -bool MDNSResponder::_releaseServiceQueries(void) -{ - while (m_pServiceQueries) - { - stcMDNSServiceQuery* pNext = m_pServiceQueries->m_pNext; - delete m_pServiceQueries; - m_pServiceQueries = pNext; - } - return true; -} - -/* - MDNSResponder::_findNextServiceQueryByServiceType -*/ -MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceTypeDomain, - const stcMDNSServiceQuery* p_pPrevServiceQuery) -{ - stcMDNSServiceQuery* pMatchingServiceQuery = 0; - - stcMDNSServiceQuery* pServiceQuery = (p_pPrevServiceQuery ? p_pPrevServiceQuery->m_pNext : m_pServiceQueries); - while (pServiceQuery) - { - if (p_ServiceTypeDomain == pServiceQuery->m_ServiceTypeDomain) - { - pMatchingServiceQuery = pServiceQuery; - break; - } - pServiceQuery = pServiceQuery->m_pNext; - } - return pMatchingServiceQuery; -} - - -/* - HOSTNAME -*/ - -/* - MDNSResponder::_setHostname -*/ -bool MDNSResponder::_setHostname(const char* p_pcHostname) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _allocHostname (%s)\n"), p_pcHostname);); - - bool bResult = false; - - _releaseHostname(); - - size_t stLength = 0; - if ((p_pcHostname) && - (MDNS_DOMAIN_LABEL_MAXLENGTH >= (stLength = strlen(p_pcHostname)))) // char max size for a single label - { - // Copy in hostname characters as lowercase - if ((bResult = (0 != (m_pcHostname = new char[stLength + 1])))) - { -#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME - size_t i = 0; - for (; i < stLength; ++i) - { - m_pcHostname[i] = (isupper(p_pcHostname[i]) ? tolower(p_pcHostname[i]) : p_pcHostname[i]); - } - m_pcHostname[i] = 0; -#else - strncpy(m_pcHostname, p_pcHostname, (stLength + 1)); -#endif - } - } - return bResult; -} - -/* - MDNSResponder::_releaseHostname -*/ -bool MDNSResponder::_releaseHostname(void) -{ - - if (m_pcHostname) - { - delete[] m_pcHostname; - m_pcHostname = 0; - } - return true; -} - - -/* - SERVICE -*/ - -/* - MDNSResponder::_allocService -*/ -MDNSResponder::stcMDNSService* MDNSResponder::_allocService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port) -{ - - stcMDNSService* pService = 0; - if (((!p_pcName) || - (MDNS_DOMAIN_LABEL_MAXLENGTH >= strlen(p_pcName))) && - (p_pcService) && - (MDNS_SERVICE_NAME_LENGTH >= strlen(p_pcService)) && - (p_pcProtocol) && - (MDNS_SERVICE_PROTOCOL_LENGTH >= strlen(p_pcProtocol)) && - (p_u16Port) && - (0 != (pService = new stcMDNSService)) && - (pService->setName(p_pcName ? : m_pcHostname)) && - (pService->setService(p_pcService)) && - (pService->setProtocol(p_pcProtocol))) - { - - pService->m_bAutoName = (0 == p_pcName); - pService->m_u16Port = p_u16Port; - - // Add to list (or start list) - pService->m_pNext = m_pServices; - m_pServices = pService; - } - return pService; -} - -/* - MDNSResponder::_releaseService -*/ -bool MDNSResponder::_releaseService(MDNSResponder::stcMDNSService* p_pService) -{ - - bool bResult = false; - - if (p_pService) - { - stcMDNSService* pPred = m_pServices; - while ((pPred) && - (pPred->m_pNext != p_pService)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pService->m_pNext; - delete p_pService; - bResult = true; - } - else // No predecesor - { - if (m_pServices == p_pService) - { - m_pServices = p_pService->m_pNext; - delete p_pService; - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseService: INVALID service!");); - } - } - } - return bResult; -} - -/* - MDNSResponder::_releaseServices -*/ -bool MDNSResponder::_releaseServices(void) -{ - - stcMDNSService* pService = m_pServices; - while (pService) - { - _releaseService(pService); - pService = m_pServices; - } - return true; -} - -/* - MDNSResponder::_findService -*/ -MDNSResponder::stcMDNSService* MDNSResponder::_findService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol) -{ - - stcMDNSService* pService = m_pServices; - while (pService) - { - if ((0 == strcmp(pService->m_pcName, p_pcName)) && - (0 == strcmp(pService->m_pcService, p_pcService)) && - (0 == strcmp(pService->m_pcProtocol, p_pcProtocol))) - { - - break; - } - pService = pService->m_pNext; - } - return pService; -} - -/* - MDNSResponder::_findService -*/ -MDNSResponder::stcMDNSService* MDNSResponder::_findService(const MDNSResponder::hMDNSService p_hService) -{ - - stcMDNSService* pService = m_pServices; - while (pService) - { - if (p_hService == (hMDNSService)pService) - { - break; - } - pService = pService->m_pNext; - } - return pService; -} - - -/* - SERVICE TXT -*/ - -/* - MDNSResponder::_allocServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_allocServiceTxt(MDNSResponder::stcMDNSService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp) -{ - - stcMDNSServiceTxt* pTxt = 0; - - if ((p_pService) && - (p_pcKey) && - (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() + - 1 + // Length byte - (p_pcKey ? strlen(p_pcKey) : 0) + - 1 + // '=' - (p_pcValue ? strlen(p_pcValue) : 0)))) - { - - pTxt = new stcMDNSServiceTxt; - if (pTxt) - { - size_t stLength = (p_pcKey ? strlen(p_pcKey) : 0); - pTxt->m_pcKey = new char[stLength + 1]; - if (pTxt->m_pcKey) - { - strncpy(pTxt->m_pcKey, p_pcKey, stLength); pTxt->m_pcKey[stLength] = 0; - } - - if (p_pcValue) - { - stLength = (p_pcValue ? strlen(p_pcValue) : 0); - pTxt->m_pcValue = new char[stLength + 1]; - if (pTxt->m_pcValue) - { - strncpy(pTxt->m_pcValue, p_pcValue, stLength); pTxt->m_pcValue[stLength] = 0; - } - } - pTxt->m_bTemp = p_bTemp; - - // Add to list (or start list) - p_pService->m_Txts.add(pTxt); - } - } - return pTxt; -} - -/* - MDNSResponder::_releaseServiceTxt -*/ -bool MDNSResponder::_releaseServiceTxt(MDNSResponder::stcMDNSService* p_pService, - MDNSResponder::stcMDNSServiceTxt* p_pTxt) -{ - - return ((p_pService) && - (p_pTxt) && - (p_pService->m_Txts.remove(p_pTxt))); -} - -/* - MDNSResponder::_updateServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_updateServiceTxt(MDNSResponder::stcMDNSService* p_pService, - MDNSResponder::stcMDNSServiceTxt* p_pTxt, - const char* p_pcValue, - bool p_bTemp) -{ - - if ((p_pService) && - (p_pTxt) && - (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() - - (p_pTxt->m_pcValue ? strlen(p_pTxt->m_pcValue) : 0) + - (p_pcValue ? strlen(p_pcValue) : 0)))) - { - p_pTxt->update(p_pcValue); - p_pTxt->m_bTemp = p_bTemp; - } - return p_pTxt; -} - -/* - MDNSResponder::_findServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, - const char* p_pcKey) -{ - - return (p_pService ? p_pService->m_Txts.find(p_pcKey) : 0); -} - -/* - MDNSResponder::_findServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, - const hMDNSTxt p_hTxt) -{ - - return (((p_pService) && (p_hTxt)) ? p_pService->m_Txts.find((stcMDNSServiceTxt*)p_hTxt) : 0); -} - -/* - MDNSResponder::_addServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_addServiceTxt(MDNSResponder::stcMDNSService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp) -{ - stcMDNSServiceTxt* pResult = 0; - - if ((p_pService) && - (p_pcKey) && - (strlen(p_pcKey))) - { - - stcMDNSServiceTxt* pTxt = p_pService->m_Txts.find(p_pcKey); - if (pTxt) - { - pResult = _updateServiceTxt(p_pService, pTxt, p_pcValue, p_bTemp); - } - else - { - pResult = _allocServiceTxt(p_pService, p_pcKey, p_pcValue, p_bTemp); - } - } - return pResult; -} - -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_answerKeyValue(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcTxts (if not already done) - return (pSQAnswer) ? pSQAnswer->m_Txts.m_pTxts : 0; -} - -/* - MDNSResponder::_collectServiceTxts -*/ -bool MDNSResponder::_collectServiceTxts(MDNSResponder::stcMDNSService& p_rService) -{ - - // Call Dynamic service callbacks - if (m_fnServiceTxtCallback) - { - m_fnServiceTxtCallback((hMDNSService)&p_rService); - } - if (p_rService.m_fnTxtCallback) - { - p_rService.m_fnTxtCallback((hMDNSService)&p_rService); - } - return true; -} - -/* - MDNSResponder::_releaseTempServiceTxts -*/ -bool MDNSResponder::_releaseTempServiceTxts(MDNSResponder::stcMDNSService& p_rService) -{ - - return (p_rService.m_Txts.removeTempTxts()); -} - - -/* - MISC -*/ - -#ifdef DEBUG_ESP_MDNS_RESPONDER -/* - MDNSResponder::_printRRDomain -*/ -bool MDNSResponder::_printRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_RRDomain) const -{ - - //DEBUG_OUTPUT.printf_P(PSTR("Domain: ")); - - const char* pCursor = p_RRDomain.m_acName; - uint8_t u8Length = *pCursor++; - if (u8Length) - { - while (u8Length) - { - for (uint8_t u = 0; u < u8Length; ++u) - { - DEBUG_OUTPUT.printf_P(PSTR("%c"), *(pCursor++)); - } - u8Length = *pCursor++; - if (u8Length) - { - DEBUG_OUTPUT.printf_P(PSTR(".")); - } - } - } - else // empty domain - { - DEBUG_OUTPUT.printf_P(PSTR("-empty-")); - } - //DEBUG_OUTPUT.printf_P(PSTR("\n")); - - return true; -} - -/* - MDNSResponder::_printRRAnswer -*/ -bool MDNSResponder::_printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const -{ - - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] RRAnswer: ")); - _printRRDomain(p_RRAnswer.m_Header.m_Domain); - DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, "), p_RRAnswer.m_Header.m_Attributes.m_u16Type, p_RRAnswer.m_Header.m_Attributes.m_u16Class, p_RRAnswer.m_u32TTL); - switch (p_RRAnswer.m_Header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag - { -#ifdef MDNS_IP4_SUPPORT - case DNS_RRTYPE_A: - DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((const stcMDNS_RRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str()); - break; -#endif - case DNS_RRTYPE_PTR: - DEBUG_OUTPUT.printf_P(PSTR("PTR ")); - _printRRDomain(((const stcMDNS_RRAnswerPTR*)&p_RRAnswer)->m_PTRDomain); - break; - case DNS_RRTYPE_TXT: - { - size_t stTxtLength = ((const stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength(); - char* pTxts = new char[stTxtLength]; - if (pTxts) - { - ((/*const c_str()!!*/stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts); - DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); - delete[] pTxts; - } - break; - } -#ifdef MDNS_IP6_SUPPORT - case DNS_RRTYPE_AAAA: - DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); - break; -#endif - case DNS_RRTYPE_SRV: - DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_u16Port); - _printRRDomain(((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_SRVDomain); - break; - default: - DEBUG_OUTPUT.printf_P(PSTR("generic ")); - break; - } - DEBUG_OUTPUT.printf_P(PSTR("\n")); - - return true; -} -#endif - -} // namespace MDNSImplementation - -} // namespace esp8266 - - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h deleted file mode 100644 index cc56b133a9..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - LEAmDNS_Priv.h - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#ifndef MDNS_PRIV_H -#define MDNS_PRIV_H - -namespace esp8266 -{ - -/* - LEAmDNS -*/ - -namespace MDNSImplementation -{ - -// Enable class debug functions -#define ESP_8266_MDNS_INCLUDE -//#define DEBUG_ESP_MDNS_RESPONDER - -#if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS) -#define DEBUG_ESP_MDNS_RESPONDER -#endif - -#ifndef LWIP_OPEN_SRC -#define LWIP_OPEN_SRC -#endif - -// -// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing -// This allows to drive the responder in a environment, where 'update()' isn't called in the loop -//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE - -// Enable/disable debug trace macros -#ifdef DEBUG_ESP_MDNS_RESPONDER -#define DEBUG_ESP_MDNS_INFO -#define DEBUG_ESP_MDNS_ERR -#define DEBUG_ESP_MDNS_TX -#define DEBUG_ESP_MDNS_RX -#endif - -#ifdef DEBUG_ESP_MDNS_RESPONDER -#ifdef DEBUG_ESP_MDNS_INFO -#define DEBUG_EX_INFO(A) A -#else -#define DEBUG_EX_INFO(A) do { (void)0; } while (0) -#endif -#ifdef DEBUG_ESP_MDNS_ERR -#define DEBUG_EX_ERR(A) A -#else -#define DEBUG_EX_ERR(A) do { (void)0; } while (0) -#endif -#ifdef DEBUG_ESP_MDNS_TX -#define DEBUG_EX_TX(A) A -#else -#define DEBUG_EX_TX(A) do { (void)0; } while (0) -#endif -#ifdef DEBUG_ESP_MDNS_RX -#define DEBUG_EX_RX(A) A -#else -#define DEBUG_EX_RX(A) do { (void)0; } while (0) -#endif - -#ifdef DEBUG_ESP_PORT -#define DEBUG_OUTPUT DEBUG_ESP_PORT -#else -#define DEBUG_OUTPUT Serial -#endif -#else -#define DEBUG_EX_INFO(A) do { (void)0; } while (0) -#define DEBUG_EX_ERR(A) do { (void)0; } while (0) -#define DEBUG_EX_TX(A) do { (void)0; } while (0) -#define DEBUG_EX_RX(A) do { (void)0; } while (0) -#endif - - -/* Replaced by 'lwip/prot/dns.h' definitions - #ifdef MDNS_IP4_SUPPORT - #define MDNS_MULTICAST_ADDR_IP4 (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT - #endif - #ifdef MDNS_IP6_SUPPORT - #define MDNS_MULTICAST_ADDR_IP6 (IPAddress("FF02::FB")) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT - #endif*/ -//#define MDNS_MULTICAST_PORT 5353 - -/* - This is NOT the TTL (Time-To-Live) for MDNS records, but the - subnet level distance MDNS records should travel. - 1 sets the subnet distance to 'local', which is default for MDNS. - (Btw.: 255 would set it to 'as far as possible' -> internet) - - However, RFC 3171 seems to force 255 instead -*/ -#define MDNS_MULTICAST_TTL 255/*1*/ - -/* - This is the MDNS record TTL - Host level records are set to 2min (120s) - service level records are set to 75min (4500s) -*/ -#define MDNS_HOST_TTL 120 -#define MDNS_SERVICE_TTL 4500 - -/* - Compressed labels are flaged by the two topmost bits of the length byte being set -*/ -#define MDNS_DOMAIN_COMPRESS_MARK 0xC0 -/* - Avoid endless recursion because of malformed compressed labels -*/ -#define MDNS_DOMAIN_MAX_REDIRCTION 6 - -/* - Default service priority and weight in SRV answers -*/ -#define MDNS_SRV_PRIORITY 0 -#define MDNS_SRV_WEIGHT 0 - -/* - Delay between and number of probes for host and service domains - Delay between and number of announces for host and service domains - Delay between and number of service queries; the delay is multiplied by the resent number in '_checkServiceQueryCache' -*/ -#define MDNS_PROBE_DELAY 250 -#define MDNS_PROBE_COUNT 3 -#define MDNS_ANNOUNCE_DELAY 1000 -#define MDNS_ANNOUNCE_COUNT 8 -#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5 -#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000 - - -/* - Force host domain to use only lowercase letters -*/ -//#define MDNS_FORCE_LOWERCASE_HOSTNAME - -/* - Enable/disable the usage of the F() macro in debug trace printf calls. - There needs to be an PGM comptible printf function to use this. - - USE_PGM_PRINTF and F -*/ -#define USE_PGM_PRINTF - -#ifdef USE_PGM_PRINTF -#else -#ifdef F -#undef F -#endif -#define F(A) A -#endif - -} // namespace MDNSImplementation - -} // namespace esp8266 - -// Include the main header, so the submodlues only need to include this header -#include "LEAmDNS.h" - - -#endif // MDNS_PRIV_H diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp deleted file mode 100644 index ce475de3ba..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp +++ /dev/null @@ -1,2476 +0,0 @@ -/* - LEAmDNS_Structs.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include "LEAmDNS_Priv.h" -#include "LEAmDNS_lwIPdefs.h" - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - STRUCTS -*/ - -/** - MDNSResponder::stcMDNSServiceTxt - - One MDNS TXT item. - m_pcValue may be '\0'. - Objects can be chained together (list, m_pNext). - A 'm_bTemp' flag differentiates between static and dynamic items. - Output as byte array 'c#=1' is supported. -*/ - -/* - MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt constructor -*/ -MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const char* p_pcKey /*= 0*/, - const char* p_pcValue /*= 0*/, - bool p_bTemp /*= false*/) - : m_pNext(0), - m_pcKey(0), - m_pcValue(0), - m_bTemp(p_bTemp) -{ - - setKey(p_pcKey); - setValue(p_pcValue); -} - -/* - MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt copy-constructor -*/ -MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const MDNSResponder::stcMDNSServiceTxt& p_Other) - : m_pNext(0), - m_pcKey(0), - m_pcValue(0), - m_bTemp(false) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt destructor -*/ -MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceTxt::operator= -*/ -MDNSResponder::stcMDNSServiceTxt& MDNSResponder::stcMDNSServiceTxt::operator=(const MDNSResponder::stcMDNSServiceTxt& p_Other) -{ - - if (&p_Other != this) - { - clear(); - set(p_Other.m_pcKey, p_Other.m_pcValue, p_Other.m_bTemp); - } - return *this; -} - -/* - MDNSResponder::stcMDNSServiceTxt::clear -*/ -bool MDNSResponder::stcMDNSServiceTxt::clear(void) -{ - - releaseKey(); - releaseValue(); - return true; -} - -/* - MDNSResponder::stcMDNSServiceTxt::allocKey -*/ -char* MDNSResponder::stcMDNSServiceTxt::allocKey(size_t p_stLength) -{ - - releaseKey(); - if (p_stLength) - { - m_pcKey = new char[p_stLength + 1]; - } - return m_pcKey; -} - -/* - MDNSResponder::stcMDNSServiceTxt::setKey -*/ -bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey, - size_t p_stLength) -{ - - bool bResult = false; - - releaseKey(); - if (p_stLength) - { - if (allocKey(p_stLength)) - { - strncpy(m_pcKey, p_pcKey, p_stLength); - m_pcKey[p_stLength] = 0; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxt::setKey -*/ -bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey) -{ - - return setKey(p_pcKey, (p_pcKey ? strlen(p_pcKey) : 0)); -} - -/* - MDNSResponder::stcMDNSServiceTxt::releaseKey -*/ -bool MDNSResponder::stcMDNSServiceTxt::releaseKey(void) -{ - - if (m_pcKey) - { - delete[] m_pcKey; - m_pcKey = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceTxt::allocValue -*/ -char* MDNSResponder::stcMDNSServiceTxt::allocValue(size_t p_stLength) -{ - - releaseValue(); - if (p_stLength) - { - m_pcValue = new char[p_stLength + 1]; - } - return m_pcValue; -} - -/* - MDNSResponder::stcMDNSServiceTxt::setValue -*/ -bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue, - size_t p_stLength) -{ - - bool bResult = false; - - releaseValue(); - if (p_stLength) - { - if (allocValue(p_stLength)) - { - strncpy(m_pcValue, p_pcValue, p_stLength); - m_pcValue[p_stLength] = 0; - bResult = true; - } - } - else // No value -> also OK - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxt::setValue -*/ -bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue) -{ - - return setValue(p_pcValue, (p_pcValue ? strlen(p_pcValue) : 0)); -} - -/* - MDNSResponder::stcMDNSServiceTxt::releaseValue -*/ -bool MDNSResponder::stcMDNSServiceTxt::releaseValue(void) -{ - - if (m_pcValue) - { - delete[] m_pcValue; - m_pcValue = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceTxt::set -*/ -bool MDNSResponder::stcMDNSServiceTxt::set(const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp /*= false*/) -{ - - m_bTemp = p_bTemp; - return ((setKey(p_pcKey)) && - (setValue(p_pcValue))); -} - -/* - MDNSResponder::stcMDNSServiceTxt::update -*/ -bool MDNSResponder::stcMDNSServiceTxt::update(const char* p_pcValue) -{ - - return setValue(p_pcValue); -} - -/* - MDNSResponder::stcMDNSServiceTxt::length - - length of eg. 'c#=1' without any closing '\0' -*/ -size_t MDNSResponder::stcMDNSServiceTxt::length(void) const -{ - - size_t stLength = 0; - if (m_pcKey) - { - stLength += strlen(m_pcKey); // Key - stLength += 1; // '=' - stLength += (m_pcValue ? strlen(m_pcValue) : 0); // Value - } - return stLength; -} - - -/** - MDNSResponder::stcMDNSServiceTxts - - A list of zero or more MDNS TXT items. - Dynamic TXT items can be removed by 'removeTempTxts'. - A TXT item can be looke up by its 'key' member. - Export as ';'-separated byte array is supported. - Export as 'length byte coded' byte array is supported. - Comparision ((all A TXT items in B and equal) AND (all B TXT items in A and equal)) is supported. - -*/ - -/* - MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts contructor -*/ -MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(void) - : m_pTxts(0) -{ - -} - -/* - MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts copy-constructor -*/ -MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other) - : m_pTxts(0) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts destructor -*/ -MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceTxts::operator= -*/ -MDNSResponder::stcMDNSServiceTxts& MDNSResponder::stcMDNSServiceTxts::operator=(const stcMDNSServiceTxts& p_Other) -{ - - if (this != &p_Other) - { - clear(); - - for (stcMDNSServiceTxt* pOtherTxt = p_Other.m_pTxts; pOtherTxt; pOtherTxt = pOtherTxt->m_pNext) - { - add(new stcMDNSServiceTxt(*pOtherTxt)); - } - } - return *this; -} - -/* - MDNSResponder::stcMDNSServiceTxts::clear -*/ -bool MDNSResponder::stcMDNSServiceTxts::clear(void) -{ - - while (m_pTxts) - { - stcMDNSServiceTxt* pNext = m_pTxts->m_pNext; - delete m_pTxts; - m_pTxts = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceTxts::add -*/ -bool MDNSResponder::stcMDNSServiceTxts::add(MDNSResponder::stcMDNSServiceTxt* p_pTxt) -{ - - bool bResult = false; - - if (p_pTxt) - { - p_pTxt->m_pNext = m_pTxts; - m_pTxts = p_pTxt; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::remove -*/ -bool MDNSResponder::stcMDNSServiceTxts::remove(stcMDNSServiceTxt* p_pTxt) -{ - - bool bResult = false; - - if (p_pTxt) - { - stcMDNSServiceTxt* pPred = m_pTxts; - while ((pPred) && - (pPred->m_pNext != p_pTxt)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pTxt->m_pNext; - delete p_pTxt; - bResult = true; - } - else if (m_pTxts == p_pTxt) // No predecesor, but first item - { - m_pTxts = p_pTxt->m_pNext; - delete p_pTxt; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::removeTempTxts -*/ -bool MDNSResponder::stcMDNSServiceTxts::removeTempTxts(void) -{ - - bool bResult = true; - - stcMDNSServiceTxt* pTxt = m_pTxts; - while ((bResult) && - (pTxt)) - { - stcMDNSServiceTxt* pNext = pTxt->m_pNext; - if (pTxt->m_bTemp) - { - bResult = remove(pTxt); - } - pTxt = pNext; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::find -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) -{ - - stcMDNSServiceTxt* pResult = 0; - - for (stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if ((p_pcKey) && - (0 == strcmp(pTxt->m_pcKey, p_pcKey))) - { - pResult = pTxt; - break; - } - } - return pResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::find -*/ -const MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) const -{ - - const stcMDNSServiceTxt* pResult = 0; - - for (const stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if ((p_pcKey) && - (0 == strcmp(pTxt->m_pcKey, p_pcKey))) - { - - pResult = pTxt; - break; - } - } - return pResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::find -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const stcMDNSServiceTxt* p_pTxt) -{ - - stcMDNSServiceTxt* pResult = 0; - - for (stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if (p_pTxt == pTxt) - { - pResult = pTxt; - break; - } - } - return pResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::length -*/ -uint16_t MDNSResponder::stcMDNSServiceTxts::length(void) const -{ - - uint16_t u16Length = 0; - - stcMDNSServiceTxt* pTxt = m_pTxts; - while (pTxt) - { - u16Length += 1; // Length byte - u16Length += pTxt->length(); // Text - pTxt = pTxt->m_pNext; - } - return u16Length; -} - -/* - MDNSResponder::stcMDNSServiceTxts::c_strLength - - (incl. closing '\0'). Length bytes place is used for delimiting ';' and closing '\0' -*/ -size_t MDNSResponder::stcMDNSServiceTxts::c_strLength(void) const -{ - - return length(); -} - -/* - MDNSResponder::stcMDNSServiceTxts::c_str -*/ -bool MDNSResponder::stcMDNSServiceTxts::c_str(char* p_pcBuffer) -{ - - bool bResult = false; - - if (p_pcBuffer) - { - bResult = true; - - *p_pcBuffer = 0; - for (stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - size_t stLength; - if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) - { - if (pTxt != m_pTxts) - { - *p_pcBuffer++ = ';'; - } - strncpy(p_pcBuffer, pTxt->m_pcKey, stLength); p_pcBuffer[stLength] = 0; - p_pcBuffer += stLength; - *p_pcBuffer++ = '='; - if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) - { - strncpy(p_pcBuffer, pTxt->m_pcValue, stLength); p_pcBuffer[stLength] = 0; - p_pcBuffer += stLength; - } - } - } - *p_pcBuffer++ = 0; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::bufferLength - - (incl. closing '\0'). -*/ -size_t MDNSResponder::stcMDNSServiceTxts::bufferLength(void) const -{ - - return (length() + 1); -} - -/* - MDNSResponder::stcMDNSServiceTxts::toBuffer -*/ -bool MDNSResponder::stcMDNSServiceTxts::buffer(char* p_pcBuffer) -{ - - bool bResult = false; - - if (p_pcBuffer) - { - bResult = true; - - *p_pcBuffer = 0; - for (stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - *(unsigned char*)p_pcBuffer++ = pTxt->length(); - size_t stLength; - if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) - { - memcpy(p_pcBuffer, pTxt->m_pcKey, stLength); - p_pcBuffer += stLength; - *p_pcBuffer++ = '='; - if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) - { - memcpy(p_pcBuffer, pTxt->m_pcValue, stLength); - p_pcBuffer += stLength; - } - } - } - *p_pcBuffer++ = 0; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::compare -*/ -bool MDNSResponder::stcMDNSServiceTxts::compare(const MDNSResponder::stcMDNSServiceTxts& p_Other) const -{ - - bool bResult = false; - - if ((bResult = (length() == p_Other.length()))) - { - // Compare A->B - for (const stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - const stcMDNSServiceTxt* pOtherTxt = p_Other.find(pTxt->m_pcKey); - bResult = ((pOtherTxt) && - (pTxt->m_pcValue) && - (pOtherTxt->m_pcValue) && - (strlen(pTxt->m_pcValue) == strlen(pOtherTxt->m_pcValue)) && - (0 == strcmp(pTxt->m_pcValue, pOtherTxt->m_pcValue))); - } - // Compare B->A - for (const stcMDNSServiceTxt* pOtherTxt = p_Other.m_pTxts; ((bResult) && (pOtherTxt)); pOtherTxt = pOtherTxt->m_pNext) - { - const stcMDNSServiceTxt* pTxt = find(pOtherTxt->m_pcKey); - bResult = ((pTxt) && - (pOtherTxt->m_pcValue) && - (pTxt->m_pcValue) && - (strlen(pOtherTxt->m_pcValue) == strlen(pTxt->m_pcValue)) && - (0 == strcmp(pOtherTxt->m_pcValue, pTxt->m_pcValue))); - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::operator== -*/ -bool MDNSResponder::stcMDNSServiceTxts::operator==(const stcMDNSServiceTxts& p_Other) const -{ - - return compare(p_Other); -} - -/* - MDNSResponder::stcMDNSServiceTxts::operator!= -*/ -bool MDNSResponder::stcMDNSServiceTxts::operator!=(const stcMDNSServiceTxts& p_Other) const -{ - - return !compare(p_Other); -} - - -/** - MDNSResponder::stcMDNS_MsgHeader - - A MDNS message haeder. - -*/ - -/* - MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader -*/ -MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader(uint16_t p_u16ID /*= 0*/, - bool p_bQR /*= false*/, - unsigned char p_ucOpcode /*= 0*/, - bool p_bAA /*= false*/, - bool p_bTC /*= false*/, - bool p_bRD /*= false*/, - bool p_bRA /*= false*/, - unsigned char p_ucRCode /*= 0*/, - uint16_t p_u16QDCount /*= 0*/, - uint16_t p_u16ANCount /*= 0*/, - uint16_t p_u16NSCount /*= 0*/, - uint16_t p_u16ARCount /*= 0*/) - : m_u16ID(p_u16ID), - m_1bQR(p_bQR), m_4bOpcode(p_ucOpcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), - m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_ucRCode), - m_u16QDCount(p_u16QDCount), - m_u16ANCount(p_u16ANCount), - m_u16NSCount(p_u16NSCount), - m_u16ARCount(p_u16ARCount) -{ - -} - - -/** - MDNSResponder::stcMDNS_RRDomain - - A MDNS domain object. - The labels of the domain are stored (DNS-like encoded) in 'm_acName': - [length byte]varlength label[length byte]varlength label[0] - 'm_u16NameLength' stores the used length of 'm_acName'. - Dynamic label addition is supported. - Comparison is supported. - Export as byte array 'esp8266.local' is supported. - -*/ - -/* - MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain constructor -*/ -MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(void) - : m_u16NameLength(0) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain copy-constructor -*/ -MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other) - : m_u16NameLength(0) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRDomain::operator = -*/ -MDNSResponder::stcMDNS_RRDomain& MDNSResponder::stcMDNS_RRDomain::operator=(const stcMDNS_RRDomain& p_Other) -{ - - if (&p_Other != this) - { - memcpy(m_acName, p_Other.m_acName, sizeof(m_acName)); - m_u16NameLength = p_Other.m_u16NameLength; - } - return *this; -} - -/* - MDNSResponder::stcMDNS_RRDomain::clear -*/ -bool MDNSResponder::stcMDNS_RRDomain::clear(void) -{ - - memset(m_acName, 0, sizeof(m_acName)); - m_u16NameLength = 0; - return true; -} - -/* - MDNSResponder::stcMDNS_RRDomain::addLabel -*/ -bool MDNSResponder::stcMDNS_RRDomain::addLabel(const char* p_pcLabel, - bool p_bPrependUnderline /*= false*/) -{ - - bool bResult = false; - - size_t stLength = (p_pcLabel - ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) - : 0); - if ((MDNS_DOMAIN_LABEL_MAXLENGTH >= stLength) && - (MDNS_DOMAIN_MAXLENGTH >= (m_u16NameLength + (1 + stLength)))) - { - // Length byte - m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! - ++m_u16NameLength; - // Label - if (stLength) - { - if (p_bPrependUnderline) - { - m_acName[m_u16NameLength++] = '_'; - --stLength; - } - strncpy(&(m_acName[m_u16NameLength]), p_pcLabel, stLength); m_acName[m_u16NameLength + stLength] = 0; - m_u16NameLength += stLength; - } - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNS_RRDomain::compare -*/ -bool MDNSResponder::stcMDNS_RRDomain::compare(const stcMDNS_RRDomain& p_Other) const -{ - - bool bResult = false; - - if (m_u16NameLength == p_Other.m_u16NameLength) - { - const char* pT = m_acName; - const char* pO = p_Other.m_acName; - while ((pT) && - (pO) && - (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND - (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content - { - if (*((unsigned char*)pT)) // Not 0 - { - pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and lenght - pO += (1 + * ((unsigned char*)pO)); - } - else // Is 0 -> Successfully reached the end - { - bResult = true; - break; - } - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNS_RRDomain::operator == -*/ -bool MDNSResponder::stcMDNS_RRDomain::operator==(const stcMDNS_RRDomain& p_Other) const -{ - - return compare(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRDomain::operator != -*/ -bool MDNSResponder::stcMDNS_RRDomain::operator!=(const stcMDNS_RRDomain& p_Other) const -{ - - return !compare(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRDomain::operator > -*/ -bool MDNSResponder::stcMDNS_RRDomain::operator>(const stcMDNS_RRDomain& p_Other) const -{ - - // TODO: Check, if this is a good idea... - return !compare(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRDomain::c_strLength -*/ -size_t MDNSResponder::stcMDNS_RRDomain::c_strLength(void) const -{ - - size_t stLength = 0; - - unsigned char* pucLabelLength = (unsigned char*)m_acName; - while (*pucLabelLength) - { - stLength += (*pucLabelLength + 1 /* +1 for '.' or '\0'*/); - pucLabelLength += (*pucLabelLength + 1); - } - return stLength; -} - -/* - MDNSResponder::stcMDNS_RRDomain::c_str -*/ -bool MDNSResponder::stcMDNS_RRDomain::c_str(char* p_pcBuffer) -{ - - bool bResult = false; - - if (p_pcBuffer) - { - *p_pcBuffer = 0; - unsigned char* pucLabelLength = (unsigned char*)m_acName; - while (*pucLabelLength) - { - memcpy(p_pcBuffer, (const char*)(pucLabelLength + 1), *pucLabelLength); - p_pcBuffer += *pucLabelLength; - pucLabelLength += (*pucLabelLength + 1); - *p_pcBuffer++ = (*pucLabelLength ? '.' : '\0'); - } - bResult = true; - } - return bResult; -} - - -/** - MDNSResponder::stcMDNS_RRAttributes - - A MDNS attributes object. - -*/ - -/* - MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes constructor -*/ -MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(uint16_t p_u16Type /*= 0*/, - uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) - : m_u16Type(p_u16Type), - m_u16Class(p_u16Class) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes copy-constructor -*/ -MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Other) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRAttributes::operator = -*/ -MDNSResponder::stcMDNS_RRAttributes& MDNSResponder::stcMDNS_RRAttributes::operator=(const MDNSResponder::stcMDNS_RRAttributes& p_Other) -{ - - if (&p_Other != this) - { - m_u16Type = p_Other.m_u16Type; - m_u16Class = p_Other.m_u16Class; - } - return *this; -} - - -/** - MDNSResponder::stcMDNS_RRHeader - - A MDNS record header (domain and attributes) object. - -*/ - -/* - MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader constructor -*/ -MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(void) -{ - -} - -/* - MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader copy-constructor -*/ -MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRHeader::operator = -*/ -MDNSResponder::stcMDNS_RRHeader& MDNSResponder::stcMDNS_RRHeader::operator=(const MDNSResponder::stcMDNS_RRHeader& p_Other) -{ - - if (&p_Other != this) - { - m_Domain = p_Other.m_Domain; - m_Attributes = p_Other.m_Attributes; - } - return *this; -} - -/* - MDNSResponder::stcMDNS_RRHeader::clear -*/ -bool MDNSResponder::stcMDNS_RRHeader::clear(void) -{ - - m_Domain.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRQuestion - - A MDNS question record object (header + question flags) - -*/ - -/* - MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion constructor -*/ -MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion(void) - : m_pNext(0), - m_bUnicast(false) -{ - -} - - -/** - MDNSResponder::stcMDNS_RRAnswer - - A MDNS answer record object (header + answer content). - This is a 'virtual' base class for all other MDNS answer classes. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer constructor -*/ -MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer(enuAnswerType p_AnswerType, - const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : m_pNext(0), - m_AnswerType(p_AnswerType), - m_Header(p_Header), - m_u32TTL(p_u32TTL) -{ - - // Extract 'cache flush'-bit - m_bCacheFlush = (m_Header.m_Attributes.m_u16Class & 0x8000); - m_Header.m_Attributes.m_u16Class &= (~0x8000); -} - -/* - MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer destructor -*/ -MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer(void) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswer::answerType -*/ -MDNSResponder::enuAnswerType MDNSResponder::stcMDNS_RRAnswer::answerType(void) const -{ - - return m_AnswerType; -} - -/* - MDNSResponder::stcMDNS_RRAnswer::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswer::clear(void) -{ - - m_pNext = 0; - m_Header.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRAnswerA - - A MDNS A answer object. - Extends the base class by an IP4 address member. - -*/ - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA constructor -*/ -MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_A, p_Header, p_u32TTL), - m_IPAddress(0, 0, 0, 0) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA destructor -*/ -MDNSResponder::stcMDNS_RRAnswerA::~stcMDNS_RRAnswerA(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerA::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerA::clear(void) -{ - - m_IPAddress = IPAddress(0, 0, 0, 0); - return true; -} -#endif - - -/** - MDNSResponder::stcMDNS_RRAnswerPTR - - A MDNS PTR answer object. - Extends the base class by a MDNS domain member. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR constructor -*/ -MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_PTR, p_Header, p_u32TTL) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR destructor -*/ -MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerPTR::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerPTR::clear(void) -{ - - m_PTRDomain.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRAnswerTXT - - A MDNS TXT answer object. - Extends the base class by a MDNS TXT items list member. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT constructor -*/ -MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_TXT, p_Header, p_u32TTL) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT destructor -*/ -MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerTXT::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerTXT::clear(void) -{ - - m_Txts.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRAnswerAAAA - - A MDNS AAAA answer object. - (Should) extend the base class by an IP6 address member. - -*/ - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA constructor -*/ -MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_AAAA, p_Header, p_u32TTL) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA destructor -*/ -MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerAAAA::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerAAAA::clear(void) -{ - - return true; -} -#endif - - -/** - MDNSResponder::stcMDNS_RRAnswerSRV - - A MDNS SRV answer object. - Extends the base class by a port member. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV constructor -*/ -MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_SRV, p_Header, p_u32TTL), - m_u16Priority(0), - m_u16Weight(0), - m_u16Port(0) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV destructor -*/ -MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerSRV::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerSRV::clear(void) -{ - - m_u16Priority = 0; - m_u16Weight = 0; - m_u16Port = 0; - m_SRVDomain.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRAnswerGeneric - - An unknown (generic) MDNS answer object. - Extends the base class by a RDATA buffer member. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric constructor -*/ -MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_Generic, p_Header, p_u32TTL), - m_u16RDLength(0), - m_pu8RDData(0) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric destructor -*/ -MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerGeneric::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerGeneric::clear(void) -{ - - if (m_pu8RDData) - { - delete[] m_pu8RDData; - m_pu8RDData = 0; - } - m_u16RDLength = 0; - - return true; -} - - -/** - MDNSResponder::stcProbeInformation - - Probing status information for a host or service domain - -*/ - -/* - MDNSResponder::stcProbeInformation::stcProbeInformation constructor -*/ -MDNSResponder::stcProbeInformation::stcProbeInformation(void) - : m_ProbingStatus(ProbingStatus_WaitingForData), - m_u8SentCount(0), - m_Timeout(esp8266::polledTimeout::oneShotMs::neverExpires), - m_bConflict(false), - m_bTiebreakNeeded(false), - m_fnHostProbeResultCallback(0), - m_fnServiceProbeResultCallback(0) -{ -} - -/* - MDNSResponder::stcProbeInformation::clear -*/ -bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/) -{ - - m_ProbingStatus = ProbingStatus_WaitingForData; - m_u8SentCount = 0; - m_Timeout.resetToNeverExpires(); - m_bConflict = false; - m_bTiebreakNeeded = false; - if (p_bClearUserdata) - { - m_fnHostProbeResultCallback = 0; - m_fnServiceProbeResultCallback = 0; - } - return true; -} - -/** - MDNSResponder::stcMDNSService - - A MDNS service object (to be announced by the MDNS responder) - The service instance may be '\0'; in this case the hostname is used - and the flag m_bAutoName is set. If the hostname changes, all 'auto- - named' services are renamed also. - m_u8Replymask is used while preparing a response to a MDNS query. It is - resetted in '_sendMDNSMessage' afterwards. -*/ - -/* - MDNSResponder::stcMDNSService::stcMDNSService constructor -*/ -MDNSResponder::stcMDNSService::stcMDNSService(const char* p_pcName /*= 0*/, - const char* p_pcService /*= 0*/, - const char* p_pcProtocol /*= 0*/) - : m_pNext(0), - m_pcName(0), - m_bAutoName(false), - m_pcService(0), - m_pcProtocol(0), - m_u16Port(0), - m_u8ReplyMask(0), - m_fnTxtCallback(0) -{ - - setName(p_pcName); - setService(p_pcService); - setProtocol(p_pcProtocol); -} - -/* - MDNSResponder::stcMDNSService::~stcMDNSService destructor -*/ -MDNSResponder::stcMDNSService::~stcMDNSService(void) -{ - - releaseName(); - releaseService(); - releaseProtocol(); -} - -/* - MDNSResponder::stcMDNSService::setName -*/ -bool MDNSResponder::stcMDNSService::setName(const char* p_pcName) -{ - - bool bResult = false; - - releaseName(); - size_t stLength = (p_pcName ? strlen(p_pcName) : 0); - if (stLength) - { - if ((bResult = (0 != (m_pcName = new char[stLength + 1])))) - { - strncpy(m_pcName, p_pcName, stLength); - m_pcName[stLength] = 0; - } - } - else - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSService::releaseName -*/ -bool MDNSResponder::stcMDNSService::releaseName(void) -{ - - if (m_pcName) - { - delete[] m_pcName; - m_pcName = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSService::setService -*/ -bool MDNSResponder::stcMDNSService::setService(const char* p_pcService) -{ - - bool bResult = false; - - releaseService(); - size_t stLength = (p_pcService ? strlen(p_pcService) : 0); - if (stLength) - { - if ((bResult = (0 != (m_pcService = new char[stLength + 1])))) - { - strncpy(m_pcService, p_pcService, stLength); - m_pcService[stLength] = 0; - } - } - else - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSService::releaseService -*/ -bool MDNSResponder::stcMDNSService::releaseService(void) -{ - - if (m_pcService) - { - delete[] m_pcService; - m_pcService = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSService::setProtocol -*/ -bool MDNSResponder::stcMDNSService::setProtocol(const char* p_pcProtocol) -{ - - bool bResult = false; - - releaseProtocol(); - size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); - if (stLength) - { - if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) - { - strncpy(m_pcProtocol, p_pcProtocol, stLength); - m_pcProtocol[stLength] = 0; - } - } - else - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSService::releaseProtocol -*/ -bool MDNSResponder::stcMDNSService::releaseProtocol(void) -{ - - if (m_pcProtocol) - { - delete[] m_pcProtocol; - m_pcProtocol = 0; - } - return true; -} - - -/** - MDNSResponder::stcMDNSServiceQuery - - A MDNS service query object. - Service queries may be static or dynamic. - As the static service query is processed in the blocking function 'queryService', - only one static service service may exist. The processing of the answers is done - on the WiFi-stack side of the ESP stack structure (via 'UDPContext.onRx(_update)'). - -*/ - -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer - - One answer for a service query. - Every answer must contain - - a service instance entry (pivot), - and may contain - - a host domain, - - a port - - an IP4 address - (- an IP6 address) - - a MDNS TXTs - The existance of a component is flaged in 'm_u32ContentFlags'. - For every answer component a TTL value is maintained. - Answer objects can be connected to a linked list. - - For the host domain, service domain and TXTs components, a char array - representation can be retrieved (which is created on demand). - -*/ - -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL - - The TTL (Time-To-Live) for an specific answer content. - The 80% and outdated states are calculated based on the current time (millis) - and the 'set' time (also millis). - If the answer is scheduled for an update, the corresponding flag should be set. - - / - - / * - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor - / - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(uint32_t p_u32TTL / *= 0* /) - : m_bUpdateScheduled(false) { - - set(p_u32TTL * 1000); - } - - / * - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set - / - bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) { - - m_TTLTimeFlag.restart(p_u32TTL * 1000); - m_bUpdateScheduled = false; - - return true; - } - - / * - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent - / - bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent(void) const { - - return ((m_TTLTimeFlag.getTimeout()) && - (!m_bUpdateScheduled) && - (m_TTLTimeFlag.hypotheticalTimeout((m_TTLTimeFlag.getTimeout() * 800) / 1000))); - } - - / * - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated - / - bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated(void) const { - - return ((m_TTLTimeFlag.getTimeout()) && - (m_TTLTimeFlag.flagged())); - }*/ - - -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL - - The TTL (Time-To-Live) for an specific answer content. - The 80% and outdated states are calculated based on the current time (millis) - and the 'set' time (also millis). - If the answer is scheduled for an update, the corresponding flag should be set. - -*/ - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(void) - : m_u32TTL(0), - m_TTLTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), - m_timeoutLevel(TIMEOUTLEVEL_UNSET) -{ - -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) -{ - - m_u32TTL = p_u32TTL; - if (m_u32TTL) - { - m_timeoutLevel = TIMEOUTLEVEL_BASE; // Set to 80% - m_TTLTimeout.reset(timeout()); - } - else - { - m_timeoutLevel = TIMEOUTLEVEL_UNSET; // undef - m_TTLTimeout.resetToNeverExpires(); - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) -{ - - return ((m_u32TTL) && - (TIMEOUTLEVEL_UNSET != m_timeoutLevel) && - (m_TTLTimeout.expired())); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart(void) -{ - - bool bResult = true; - - if ((TIMEOUTLEVEL_BASE <= m_timeoutLevel) && // >= 80% AND - (TIMEOUTLEVEL_FINAL > m_timeoutLevel)) // < 100% - { - - m_timeoutLevel += TIMEOUTLEVEL_INTERVAL; // increment by 5% - m_TTLTimeout.reset(timeout()); - } - else - { - bResult = false; - m_TTLTimeout.resetToNeverExpires(); - m_timeoutLevel = TIMEOUTLEVEL_UNSET; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion(void) -{ - - m_timeoutLevel = TIMEOUTLEVEL_FINAL; - m_TTLTimeout.reset(1 * 1000); // See RFC 6762, 10.1 - - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel(void) const -{ - - return (TIMEOUTLEVEL_FINAL == m_timeoutLevel); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout -*/ -unsigned long MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout(void) const -{ - - uint32_t u32Timeout = esp8266::polledTimeout::oneShotMs::neverExpires; - - if (TIMEOUTLEVEL_BASE == m_timeoutLevel) // 80% - { - u32Timeout = (m_u32TTL * 800); // to milliseconds - } - else if ((TIMEOUTLEVEL_BASE < m_timeoutLevel) && // >80% AND - (TIMEOUTLEVEL_FINAL >= m_timeoutLevel)) // <= 100% - { - - u32Timeout = (m_u32TTL * 50); - } // else: invalid - return u32Timeout; -} - - -#ifdef MDNS_IP4_SUPPORT -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address - -*/ - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address constructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address(IPAddress p_IPAddress, - uint32_t p_u32TTL /*= 0*/) - : m_pNext(0), - m_IPAddress(p_IPAddress) -{ - - m_TTL.set(p_u32TTL); -} -#endif - - -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer -*/ - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer constructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer(void) - : m_pNext(0), - m_pcServiceDomain(0), - m_pcHostDomain(0), - m_u16Port(0), - m_pcTxts(0), -#ifdef MDNS_IP4_SUPPORT - m_pIP4Addresses(0), -#endif -#ifdef MDNS_IP6_SUPPORT - m_pIP6Addresses(0), -#endif - m_u32ContentFlags(0) -{ -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer destructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear(void) -{ - - return ((releaseTxts()) && -#ifdef MDNS_IP4_SUPPORT - (releaseIP4Addresses()) && -#endif -#ifdef MDNS_IP6_SUPPORT - (releaseIP6Addresses()) -#endif - (releaseHostDomain()) && - (releaseServiceDomain())); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain - - Alloc memory for the char array representation of the service domain. - -*/ -char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain(size_t p_stLength) -{ - - releaseServiceDomain(); - if (p_stLength) - { - m_pcServiceDomain = new char[p_stLength]; - } - return m_pcServiceDomain; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain(void) -{ - - if (m_pcServiceDomain) - { - delete[] m_pcServiceDomain; - m_pcServiceDomain = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain - - Alloc memory for the char array representation of the host domain. - -*/ -char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain(size_t p_stLength) -{ - - releaseHostDomain(); - if (p_stLength) - { - m_pcHostDomain = new char[p_stLength]; - } - return m_pcHostDomain; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain(void) -{ - - if (m_pcHostDomain) - { - delete[] m_pcHostDomain; - m_pcHostDomain = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts - - Alloc memory for the char array representation of the TXT items. - -*/ -char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts(size_t p_stLength) -{ - - releaseTxts(); - if (p_stLength) - { - m_pcTxts = new char[p_stLength]; - } - return m_pcTxts; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts(void) -{ - - if (m_pcTxts) - { - delete[] m_pcTxts; - m_pcTxts = 0; - } - return true; -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses(void) -{ - - while (m_pIP4Addresses) - { - stcIP4Address* pNext = m_pIP4Addresses->m_pNext; - delete m_pIP4Addresses; - m_pIP4Addresses = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) -{ - - bool bResult = false; - - if (p_pIP4Address) - { - p_pIP4Address->m_pNext = m_pIP4Addresses; - m_pIP4Addresses = p_pIP4Address; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) -{ - - bool bResult = false; - - if (p_pIP4Address) - { - stcIP4Address* pPred = m_pIP4Addresses; - while ((pPred) && - (pPred->m_pNext != p_pIP4Address)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pIP4Address->m_pNext; - delete p_pIP4Address; - bResult = true; - } - else if (m_pIP4Addresses == p_pIP4Address) // No predecesor, but first item - { - m_pIP4Addresses = p_pIP4Address->m_pNext; - delete p_pIP4Address; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address (const) -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) const -{ - - return (stcIP4Address*)(((const stcAnswer*)this)->findIP4Address(p_IPAddress)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) -{ - - stcIP4Address* pIP4Address = m_pIP4Addresses; - while (pIP4Address) - { - if (pIP4Address->m_IPAddress == p_IPAddress) - { - break; - } - pIP4Address = pIP4Address->m_pNext; - } - return pIP4Address; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount -*/ -uint32_t MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount(void) const -{ - - uint32_t u32Count = 0; - - stcIP4Address* pIP4Address = m_pIP4Addresses; - while (pIP4Address) - { - ++u32Count; - pIP4Address = pIP4Address->m_pNext; - } - return u32Count; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) -{ - - return (stcIP4Address*)(((const stcAnswer*)this)->IP4AddressAtIndex(p_u32Index)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex (const) -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) const -{ - - const stcIP4Address* pIP4Address = 0; - - if (((uint32_t)(-1) != p_u32Index) && - (m_pIP4Addresses)) - { - - uint32_t u32Index; - for (pIP4Address = m_pIP4Addresses, u32Index = 0; ((pIP4Address) && (u32Index < p_u32Index)); pIP4Address = pIP4Address->m_pNext, ++u32Index); - } - return pIP4Address; -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP6Addresses -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP6Addresses(void) -{ - - while (m_pIP6Addresses) - { - stcIP6Address* pNext = m_pIP6Addresses->m_pNext; - delete m_pIP6Addresses; - m_pIP6Addresses = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP6Address -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP6Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* p_pIP6Address) -{ - - bool bResult = false; - - if (p_pIP6Address) - { - p_pIP6Address->m_pNext = m_pIP6Addresses; - m_pIP6Addresses = p_pIP6Address; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP6Address -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP6Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* p_pIP6Address) -{ - - bool bResult = false; - - if (p_pIP6Address) - { - stcIP6Address* pPred = m_pIP6Addresses; - while ((pPred) && - (pPred->m_pNext != p_pIP6Address)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pIP6Address->m_pNext; - delete p_pIP6Address; - bResult = true; - } - else if (m_pIP6Addresses == p_pIP6Address) // No predecesor, but first item - { - m_pIP6Addresses = p_pIP6Address->m_pNext; - delete p_pIP6Address; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address(const IP6Address& p_IPAddress) -{ - - return (stcIP6Address*)(((const stcAnswer*)this)->findIP6Address(p_IPAddress)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address (const) -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address(const IPAddress& p_IPAddress) const -{ - - const stcIP6Address* pIP6Address = m_pIP6Addresses; - while (pIP6Address) - { - if (p_IP6Address->m_IPAddress == p_IPAddress) - { - break; - } - pIP6Address = pIP6Address->m_pNext; - } - return pIP6Address; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressCount -*/ -uint32_t MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressCount(void) const -{ - - uint32_t u32Count = 0; - - stcIP6Address* pIP6Address = m_pIP6Addresses; - while (pIP6Address) - { - ++u32Count; - pIP6Address = pIP6Address->m_pNext; - } - return u32Count; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex (const) -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex(uint32_t p_u32Index) const -{ - - return (stcIP6Address*)(((const stcAnswer*)this)->IP6AddressAtIndex(p_u32Index)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex(uint32_t p_u32Index) -{ - - stcIP6Address* pIP6Address = 0; - - if (((uint32_t)(-1) != p_u32Index) && - (m_pIP6Addresses)) - { - - uint32_t u32Index; - for (pIP6Address = m_pIP6Addresses, u32Index = 0; ((pIP6Address) && (u32Index < p_u32Index)); pIP6Address = pIP6Address->m_pNext, ++u32Index); - } - return pIP6Address; -} -#endif - - -/** - MDNSResponder::stcMDNSServiceQuery - - A service query object. - A static query is flaged via 'm_bLegacyQuery'; while the function 'queryService' - is waiting for answers, the internal flag 'm_bAwaitingAnswers' is set. When the - timeout is reached, the flag is removed. These two flags are only used for static - service queries. - All answers to the service query are stored in 'm_pAnswers' list. - Individual answers may be addressed by index (in the list of answers). - Every time a answer component is added (or changes) in a dynamic service query, - the callback 'm_fnCallback' is called. - The answer list may be searched by service and host domain. - - Service query object may be connected to a linked list. -*/ - -/* - MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery constructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery(void) - : m_pNext(0), - m_fnCallback(0), - m_bLegacyQuery(false), - m_u8SentCount(0), - m_ResendTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), - m_bAwaitingAnswers(true), - m_pAnswers(0) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery destructor -*/ -MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceQuery::clear -*/ -bool MDNSResponder::stcMDNSServiceQuery::clear(void) -{ - - m_fnCallback = 0; - m_bLegacyQuery = false; - m_u8SentCount = 0; - m_ResendTimeout.resetToNeverExpires(); - m_bAwaitingAnswers = true; - while (m_pAnswers) - { - stcAnswer* pNext = m_pAnswers->m_pNext; - delete m_pAnswers; - m_pAnswers = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::answerCount -*/ -uint32_t MDNSResponder::stcMDNSServiceQuery::answerCount(void) const -{ - - uint32_t u32Count = 0; - - stcAnswer* pAnswer = m_pAnswers; - while (pAnswer) - { - ++u32Count; - pAnswer = pAnswer->m_pNext; - } - return u32Count; -} - -/* - MDNSResponder::stcMDNSServiceQuery::answerAtIndex -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::answerAtIndex(uint32_t p_u32Index) const -{ - - const stcAnswer* pAnswer = 0; - - if (((uint32_t)(-1) != p_u32Index) && - (m_pAnswers)) - { - - uint32_t u32Index; - for (pAnswer = m_pAnswers, u32Index = 0; ((pAnswer) && (u32Index < p_u32Index)); pAnswer = pAnswer->m_pNext, ++u32Index); - } - return pAnswer; -} - -/* - MDNSResponder::stcMDNSServiceQuery::answerAtIndex -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::answerAtIndex(uint32_t p_u32Index) -{ - - return (stcAnswer*)(((const stcMDNSServiceQuery*)this)->answerAtIndex(p_u32Index)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::indexOfAnswer -*/ -uint32_t MDNSResponder::stcMDNSServiceQuery::indexOfAnswer(const MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) const -{ - - uint32_t u32Index = 0; - - for (const stcAnswer* pAnswer = m_pAnswers; pAnswer; pAnswer = pAnswer->m_pNext, ++u32Index) - { - if (pAnswer == p_pAnswer) - { - return u32Index; - } - } - return ((uint32_t)(-1)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::addAnswer -*/ -bool MDNSResponder::stcMDNSServiceQuery::addAnswer(MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) -{ - - bool bResult = false; - - if (p_pAnswer) - { - p_pAnswer->m_pNext = m_pAnswers; - m_pAnswers = p_pAnswer; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::removeAnswer -*/ -bool MDNSResponder::stcMDNSServiceQuery::removeAnswer(MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) -{ - - bool bResult = false; - - if (p_pAnswer) - { - stcAnswer* pPred = m_pAnswers; - while ((pPred) && - (pPred->m_pNext != p_pAnswer)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pAnswer->m_pNext; - delete p_pAnswer; - bResult = true; - } - else if (m_pAnswers == p_pAnswer) // No predecesor, but first item - { - m_pAnswers = p_pAnswer->m_pNext; - delete p_pAnswer; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::findAnswerForServiceDomain -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::findAnswerForServiceDomain(const MDNSResponder::stcMDNS_RRDomain& p_ServiceDomain) -{ - - stcAnswer* pAnswer = m_pAnswers; - while (pAnswer) - { - if (pAnswer->m_ServiceDomain == p_ServiceDomain) - { - break; - } - pAnswer = pAnswer->m_pNext; - } - return pAnswer; -} - -/* - MDNSResponder::stcMDNSServiceQuery::findAnswerForHostDomain -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::findAnswerForHostDomain(const MDNSResponder::stcMDNS_RRDomain& p_HostDomain) -{ - - stcAnswer* pAnswer = m_pAnswers; - while (pAnswer) - { - if (pAnswer->m_HostDomain == p_HostDomain) - { - break; - } - pAnswer = pAnswer->m_pNext; - } - return pAnswer; -} - - -/** - MDNSResponder::stcMDNSSendParameter - - A 'collection' of properties and flags for one MDNS query or response. - Mainly managed by the 'Control' functions. - The current offset in the UPD output buffer is tracked to be able to do - a simple host or service domain compression. - -*/ - -/** - MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem - - A cached host or service domain, incl. the offset in the UDP output buffer. - -*/ - -/* - MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem::stcDomainCacheItem constructor -*/ -MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem::stcDomainCacheItem(const void* p_pHostnameOrService, - bool p_bAdditionalData, - uint32_t p_u16Offset) - : m_pNext(0), - m_pHostnameOrService(p_pHostnameOrService), - m_bAdditionalData(p_bAdditionalData), - m_u16Offset(p_u16Offset) -{ - -} - -/** - MDNSResponder::stcMDNSSendParameter -*/ - -/* - MDNSResponder::stcMDNSSendParameter::stcMDNSSendParameter constructor -*/ -MDNSResponder::stcMDNSSendParameter::stcMDNSSendParameter(void) - : m_pQuestions(0), - m_pDomainCacheItems(0) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSSendParameter::~stcMDNSSendParameter destructor -*/ -MDNSResponder::stcMDNSSendParameter::~stcMDNSSendParameter(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSSendParameter::clear -*/ -bool MDNSResponder::stcMDNSSendParameter::clear(void) -{ - - m_u16ID = 0; - m_u8HostReplyMask = 0; - m_u16Offset = 0; - - m_bLegacyQuery = false; - m_bResponse = false; - m_bAuthorative = false; - m_bUnicast = false; - m_bUnannounce = false; - - m_bCacheFlush = true; - - while (m_pQuestions) - { - stcMDNS_RRQuestion* pNext = m_pQuestions->m_pNext; - delete m_pQuestions; - m_pQuestions = pNext; - } - while (m_pDomainCacheItems) - { - stcDomainCacheItem* pNext = m_pDomainCacheItems->m_pNext; - delete m_pDomainCacheItems; - m_pDomainCacheItems = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSSendParameter::shiftOffset -*/ -bool MDNSResponder::stcMDNSSendParameter::shiftOffset(uint16_t p_u16Shift) -{ - - m_u16Offset += p_u16Shift; - return true; -} - -/* - MDNSResponder::stcMDNSSendParameter::addDomainCacheItem -*/ -bool MDNSResponder::stcMDNSSendParameter::addDomainCacheItem(const void* p_pHostnameOrService, - bool p_bAdditionalData, - uint16_t p_u16Offset) -{ - - bool bResult = false; - - stcDomainCacheItem* pNewItem = 0; - if ((p_pHostnameOrService) && - (p_u16Offset) && - ((pNewItem = new stcDomainCacheItem(p_pHostnameOrService, p_bAdditionalData, p_u16Offset)))) - { - - pNewItem->m_pNext = m_pDomainCacheItems; - bResult = ((m_pDomainCacheItems = pNewItem)); - } - return bResult; -} - -/* - MDNSResponder::stcMDNSSendParameter::findCachedDomainOffset -*/ -uint16_t MDNSResponder::stcMDNSSendParameter::findCachedDomainOffset(const void* p_pHostnameOrService, - bool p_bAdditionalData) const -{ - - const stcDomainCacheItem* pCacheItem = m_pDomainCacheItems; - - for (; pCacheItem; pCacheItem = pCacheItem->m_pNext) - { - if ((pCacheItem->m_pHostnameOrService == p_pHostnameOrService) && - (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item - { - break; - } - } - return (pCacheItem ? pCacheItem->m_u16Offset : 0); -} - -} // namespace MDNSImplementation - -} // namespace esp8266 - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp deleted file mode 100644 index 7400abec42..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp +++ /dev/null @@ -1,1779 +0,0 @@ -/* - LEAmDNS_Transfer.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -extern "C" { -#include "user_interface.h" -} - -#include "LEAmDNS_lwIPdefs.h" -#include "LEAmDNS_Priv.h" - - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - CONST STRINGS -*/ -static const char* scpcLocal = "local"; -static const char* scpcServices = "services"; -static const char* scpcDNSSD = "dns-sd"; -static const char* scpcUDP = "udp"; -//static const char* scpcTCP = "tcp"; - -#ifdef MDNS_IP4_SUPPORT -static const char* scpcReverseIP4Domain = "in-addr"; -#endif -#ifdef MDNS_IP6_SUPPORT -static const char* scpcReverseIP6Domain = "ip6"; -#endif -static const char* scpcReverseTopDomain = "arpa"; - -/** - TRANSFER -*/ - - -/** - SENDING -*/ - -/* - MDNSResponder::_sendMDNSMessage - - Unicast responses are prepared and sent directly to the querier. - Multicast responses or queries are transferred to _sendMDNSMessage_Multicast - - Any reply flags in installed services are removed at the end! - -*/ -bool MDNSResponder::_sendMDNSMessage(MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - bool bResult = true; - - if (p_rSendParameter.m_bResponse && - p_rSendParameter.m_bUnicast) // Unicast response -> Send to querier - { - DEBUG_EX_ERR(if (!m_pUDPContext->getRemoteAddress()) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: MISSING remote address for response!\n")); - }); - IPAddress ipRemote; - ipRemote = m_pUDPContext->getRemoteAddress(); - bResult = ((_prepareMDNSMessage(p_rSendParameter, _getResponseMulticastInterface())) && - (m_pUDPContext->send(ipRemote, m_pUDPContext->getRemotePort()))); - } - else // Multicast response - { - bResult = _sendMDNSMessage_Multicast(p_rSendParameter); - } - - // Finally clear service reply masks - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - pService->m_u8ReplyMask = 0; - } - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_sendMDNSMessage_Multicast - - Fills the UDP output buffer (via _prepareMDNSMessage) and sends the buffer - via the selected WiFi interface (Station or AP) -*/ -bool MDNSResponder::_sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - bool bResult = false; - - IPAddress fromIPAddress; - fromIPAddress = _getResponseMulticastInterface(); - m_pUDPContext->setMulticastInterface(fromIPAddress); - -#ifdef MDNS_IP4_SUPPORT - IPAddress toMulticastAddress(DNS_MQUERY_IPV4_GROUP_INIT); -#endif -#ifdef MDNS_IP6_SUPPORT - //TODO: set multicast address - IPAddress toMulticastAddress(DNS_MQUERY_IPV6_GROUP_INIT); -#endif - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage_Multicast: Will send to '%s'.\n"), toMulticastAddress.toString().c_str());); - bResult = ((_prepareMDNSMessage(p_rSendParameter, fromIPAddress)) && - (m_pUDPContext->send(toMulticastAddress, DNS_MQUERY_PORT))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage_Multicast: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_prepareMDNSMessage - - The MDNS message is composed in a two-step process. - In the first loop 'only' the header informations (mainly number of answers) are collected, - while in the seconds loop, the header and all queries and answers are written to the UDP - output buffer. - -*/ -bool MDNSResponder::_prepareMDNSMessage(MDNSResponder::stcMDNSSendParameter& p_rSendParameter, - IPAddress p_IPAddress) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage\n"));); - bool bResult = true; - - // Prepare header; count answers - stcMDNS_MsgHeader msgHeader(p_rSendParameter.m_u16ID, p_rSendParameter.m_bResponse, 0, p_rSendParameter.m_bAuthorative); - // If this is a response, the answers are anwers, - // else this is a query or probe and the answers go into auth section - uint16_t& ru16Answers = (p_rSendParameter.m_bResponse - ? msgHeader.m_u16ANCount - : msgHeader.m_u16NSCount); - - /** - enuSequence - */ - enum enuSequence - { - Sequence_Count = 0, - Sequence_Send = 1 - }; - - // Two step sequence: 'Count' and 'Send' - for (uint32_t sequence = Sequence_Count; ((bResult) && (sequence <= Sequence_Send)); ++sequence) - { - DEBUG_EX_INFO( - if (Sequence_Send == sequence) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), - (unsigned)msgHeader.m_u16ID, - (unsigned)msgHeader.m_1bQR, (unsigned)msgHeader.m_4bOpcode, (unsigned)msgHeader.m_1bAA, (unsigned)msgHeader.m_1bTC, (unsigned)msgHeader.m_1bRD, - (unsigned)msgHeader.m_1bRA, (unsigned)msgHeader.m_4bRCode, - (unsigned)msgHeader.m_u16QDCount, - (unsigned)msgHeader.m_u16ANCount, - (unsigned)msgHeader.m_u16NSCount, - (unsigned)msgHeader.m_u16ARCount); - } - ); - // Count/send - // Header - bResult = ((Sequence_Count == sequence) - ? true - : _writeMDNSMsgHeader(msgHeader, p_rSendParameter)); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSMsgHeader FAILED!\n"));); - // Questions - for (stcMDNS_RRQuestion* pQuestion = p_rSendParameter.m_pQuestions; ((bResult) && (pQuestion)); pQuestion = pQuestion->m_pNext) - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16QDCount - : (bResult = _writeMDNSQuestion(*pQuestion, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSQuestion FAILED!\n"));); - } - - // Answers and authorative answers -#ifdef MDNS_IP4_SUPPORT - if ((bResult) && - (p_rSendParameter.m_u8HostReplyMask & ContentFlag_A)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(A) FAILED!\n"));); - } - if ((bResult) && - (p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP4)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_PTR_IP4(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP4 FAILED!\n"));); - } -#endif -#ifdef MDNS_IP6_SUPPORT - if ((bResult) && - (p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(A) FAILED!\n"));); - } - if ((bResult) && - (p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP6)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_PTR_IP6(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP6 FAILED!\n"));); - } -#endif - - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_PTR_TYPE)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_PTR_TYPE(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_TYPE FAILED!\n"));); - } - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_PTR_NAME)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_PTR_NAME(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_NAME FAILED!\n"));); - } - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_SRV)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(A) FAILED!\n"));); - } - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_TXT)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(A) FAILED!\n"));); - } - } // for services - - // Additional answers -#ifdef MDNS_IP4_SUPPORT - bool bNeedsAdditionalAnswerA = false; -#endif -#ifdef MDNS_IP6_SUPPORT - bool bNeedsAdditionalAnswerAAAA = false; -#endif - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND - (!(pService->m_u8ReplyMask & ContentFlag_SRV))) // NOT SRV -> add SRV as additional answer - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16ARCount - : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(B) FAILED!\n"));); - } - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND - (!(pService->m_u8ReplyMask & ContentFlag_TXT))) // NOT TXT -> add TXT as additional answer - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16ARCount - : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(B) FAILED!\n"));); - } - if ((pService->m_u8ReplyMask & (ContentFlag_PTR_NAME | ContentFlag_SRV)) || // If service instance name or SRV OR - (p_rSendParameter.m_u8HostReplyMask & (ContentFlag_A | ContentFlag_AAAA))) // any host IP address is requested - { -#ifdef MDNS_IP4_SUPPORT - if ((bResult) && - (!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_A))) // Add IP4 address - { - bNeedsAdditionalAnswerA = true; - } -#endif -#ifdef MDNS_IP6_SUPPORT - if ((bResult) && - (!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA))) // Add IP6 address - { - bNeedsAdditionalAnswerAAAA = true; - } -#endif - } - } // for services - - // Answer A needed? -#ifdef MDNS_IP4_SUPPORT - if ((bResult) && - (bNeedsAdditionalAnswerA)) - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16ARCount - : (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(B) FAILED!\n"));); - } -#endif -#ifdef MDNS_IP6_SUPPORT - // Answer AAAA needed? - if ((bResult) && - (bNeedsAdditionalAnswerAAAA)) - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16ARCount - : (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(B) FAILED!\n"));); - } -#endif - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: Loop %i FAILED!\n"), sequence);); - } // for sequence - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_sendMDNSServiceQuery - - Creates and sends a PTR query for the given service domain. - -*/ -bool MDNSResponder::_sendMDNSServiceQuery(const MDNSResponder::stcMDNSServiceQuery& p_ServiceQuery) -{ - - return _sendMDNSQuery(p_ServiceQuery.m_ServiceTypeDomain, DNS_RRTYPE_PTR); -} - -/* - MDNSResponder::_sendMDNSQuery - - Creates and sends a query for the given domain and query type. - -*/ -bool MDNSResponder::_sendMDNSQuery(const MDNSResponder::stcMDNS_RRDomain& p_QueryDomain, - uint16_t p_u16QueryType, - stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers /*= 0*/) -{ - - bool bResult = false; - - stcMDNSSendParameter sendParameter; - if (0 != ((sendParameter.m_pQuestions = new stcMDNS_RRQuestion))) - { - sendParameter.m_pQuestions->m_Header.m_Domain = p_QueryDomain; - - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = p_u16QueryType; - // It seems, that some mDNS implementations don't support 'unicast response' questions... - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN); // /*Unicast &*/ INternet - - // TODO: Add knwon answer to the query - (void)p_pKnownAnswers; - - bResult = _sendMDNSMessage(sendParameter); - } // else: FAILED to alloc question - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSQuery: FAILED to alloc question!\n"));); - return bResult; -} - -/** - HELPERS -*/ - -/** - RESOURCE RECORDS -*/ - -/* - MDNSResponder::_readRRQuestion - - Reads a question (eg. MyESP._http._tcp.local ANY IN) from the UPD input buffer. - -*/ -bool MDNSResponder::_readRRQuestion(MDNSResponder::stcMDNS_RRQuestion& p_rRRQuestion) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion\n"));); - - bool bResult = false; - - if ((bResult = _readRRHeader(p_rRRQuestion.m_Header))) - { - // Extract unicast flag from class field - p_rRRQuestion.m_bUnicast = (p_rRRQuestion.m_Header.m_Attributes.m_u16Class & 0x8000); - p_rRRQuestion.m_Header.m_Attributes.m_u16Class &= (~0x8000); - - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion ")); - _printRRDomain(p_rRRQuestion.m_Header.m_Domain); - DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X %s\n"), (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Type, (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Class, (p_rRRQuestion.m_bUnicast ? "Unicast" : "Multicast")); - ); - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_readRRAnswer - - Reads an answer (eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local) - from the UDP input buffer. - After reading the domain and type info, the further processing of the answer - is transferred the answer specific reading functions. - Unknown answer types are processed by the generic answer reader (to remove them - from the input buffer). - -*/ -bool MDNSResponder::_readRRAnswer(MDNSResponder::stcMDNS_RRAnswer*& p_rpRRAnswer) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer\n"));); - - bool bResult = false; - - stcMDNS_RRHeader header; - uint32_t u32TTL; - uint16_t u16RDLength; - if ((_readRRHeader(header)) && - (_udpRead32(u32TTL)) && - (_udpRead16(u16RDLength))) - { - - /* DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: Reading 0x%04X answer (class:0x%04X, TTL:%u, RDLength:%u) for "), header.m_Attributes.m_u16Type, header.m_Attributes.m_u16Class, u32TTL, u16RDLength); - _printRRDomain(header.m_Domain); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - );*/ - - switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag - { -#ifdef MDNS_IP4_SUPPORT - case DNS_RRTYPE_A: - p_rpRRAnswer = new stcMDNS_RRAnswerA(header, u32TTL); - bResult = _readRRAnswerA(*(stcMDNS_RRAnswerA*&)p_rpRRAnswer, u16RDLength); - break; -#endif - case DNS_RRTYPE_PTR: - p_rpRRAnswer = new stcMDNS_RRAnswerPTR(header, u32TTL); - bResult = _readRRAnswerPTR(*(stcMDNS_RRAnswerPTR*&)p_rpRRAnswer, u16RDLength); - break; - case DNS_RRTYPE_TXT: - p_rpRRAnswer = new stcMDNS_RRAnswerTXT(header, u32TTL); - bResult = _readRRAnswerTXT(*(stcMDNS_RRAnswerTXT*&)p_rpRRAnswer, u16RDLength); - break; -#ifdef MDNS_IP6_SUPPORT - case DNS_RRTYPE_AAAA: - p_rpRRAnswer = new stcMDNS_RRAnswerAAAA(header, u32TTL); - bResult = _readRRAnswerAAAA(*(stcMDNS_RRAnswerAAAA*&)p_rpRRAnswer, u16RDLength); - break; -#endif - case DNS_RRTYPE_SRV: - p_rpRRAnswer = new stcMDNS_RRAnswerSRV(header, u32TTL); - bResult = _readRRAnswerSRV(*(stcMDNS_RRAnswerSRV*&)p_rpRRAnswer, u16RDLength); - break; - default: - p_rpRRAnswer = new stcMDNS_RRAnswerGeneric(header, u32TTL); - bResult = _readRRAnswerGeneric(*(stcMDNS_RRAnswerGeneric*&)p_rpRRAnswer, u16RDLength); - break; - } - DEBUG_EX_INFO( - if ((bResult) && - (p_rpRRAnswer)) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: ")); - _printRRDomain(p_rpRRAnswer->m_Header.m_Domain); - DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, RDLength:%u "), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type, p_rpRRAnswer->m_Header.m_Attributes.m_u16Class, p_rpRRAnswer->m_u32TTL, u16RDLength); - switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag - { -#ifdef MDNS_IP4_SUPPORT - case DNS_RRTYPE_A: - DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); - break; -#endif - case DNS_RRTYPE_PTR: - DEBUG_OUTPUT.printf_P(PSTR("PTR ")); - _printRRDomain(((stcMDNS_RRAnswerPTR*&)p_rpRRAnswer)->m_PTRDomain); - break; - case DNS_RRTYPE_TXT: - { - size_t stTxtLength = ((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_strLength(); - char* pTxts = new char[stTxtLength]; - if (pTxts) - { - ((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_str(pTxts); - DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); - delete[] pTxts; - } - break; - } -#ifdef MDNS_IP6_SUPPORT - case DNS_RRTYPE_AAAA: - DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); - break; -#endif - case DNS_RRTYPE_SRV: - DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_u16Port); - _printRRDomain(((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_SRVDomain); - break; - default: - DEBUG_OUTPUT.printf_P(PSTR("generic ")); - break; - } - DEBUG_OUTPUT.printf_P(PSTR("\n")); - } - else - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED to read specific answer of type 0x%04X!\n"), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type); - } - ); // DEBUG_EX_INFO - } - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED!\n"));); - return bResult; -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::_readRRAnswerA -*/ -bool MDNSResponder::_readRRAnswerA(MDNSResponder::stcMDNS_RRAnswerA& p_rRRAnswerA, - uint16_t p_u16RDLength) -{ - - uint32_t u32IP4Address; - bool bResult = ((MDNS_IP4_SIZE == p_u16RDLength) && - (_udpReadBuffer((unsigned char*)&u32IP4Address, MDNS_IP4_SIZE)) && - ((p_rRRAnswerA.m_IPAddress = IPAddress(u32IP4Address)))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerA: FAILED!\n"));); - return bResult; -} -#endif - -/* - MDNSResponder::_readRRAnswerPTR -*/ -bool MDNSResponder::_readRRAnswerPTR(MDNSResponder::stcMDNS_RRAnswerPTR& p_rRRAnswerPTR, - uint16_t p_u16RDLength) -{ - - bool bResult = ((p_u16RDLength) && - (_readRRDomain(p_rRRAnswerPTR.m_PTRDomain))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerPTR: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRAnswerTXT - - Read TXT items from a buffer like 4c#=15ff=20 -*/ -bool MDNSResponder::_readRRAnswerTXT(MDNSResponder::stcMDNS_RRAnswerTXT& p_rRRAnswerTXT, - uint16_t p_u16RDLength) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: RDLength:%u\n"), p_u16RDLength);); - bool bResult = true; - - p_rRRAnswerTXT.clear(); - if (p_u16RDLength) - { - bResult = false; - - unsigned char* pucBuffer = new unsigned char[p_u16RDLength]; - if (pucBuffer) - { - if (_udpReadBuffer(pucBuffer, p_u16RDLength)) - { - bResult = true; - - const unsigned char* pucCursor = pucBuffer; - while ((pucCursor < (pucBuffer + p_u16RDLength)) && - (bResult)) - { - bResult = false; - - stcMDNSServiceTxt* pTxt = 0; - unsigned char ucLength = *pucCursor++; // Length of the next txt item - if (ucLength) - { - DEBUG_EX_INFO( - static char sacBuffer[64]; *sacBuffer = 0; - uint8_t u8MaxLength = ((ucLength > (sizeof(sacBuffer) - 1)) ? (sizeof(sacBuffer) - 1) : ucLength); - os_strncpy(sacBuffer, (const char*)pucCursor, u8MaxLength); sacBuffer[u8MaxLength] = 0; - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: Item(%u): %s\n"), ucLength, sacBuffer); - ); - - unsigned char* pucEqualSign = (unsigned char*)os_strchr((const char*)pucCursor, '='); // Position of the '=' sign - unsigned char ucKeyLength; - if ((pucEqualSign) && - ((ucKeyLength = (pucEqualSign - pucCursor)))) - { - unsigned char ucValueLength = (ucLength - (pucEqualSign - pucCursor + 1)); - bResult = (((pTxt = new stcMDNSServiceTxt)) && - (pTxt->setKey((const char*)pucCursor, ucKeyLength)) && - (pTxt->setValue((const char*)(pucEqualSign + 1), ucValueLength))); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: INVALID TXT format (No '=')!\n"));); - } - pucCursor += ucLength; - } - else // no/zero length TXT - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: TXT answer contains no items.\n"));); - bResult = true; - } - - if ((bResult) && - (pTxt)) // Everythings fine so far - { - // Link TXT item to answer TXTs - pTxt->m_pNext = p_rRRAnswerTXT.m_Txts.m_pTxts; - p_rRRAnswerTXT.m_Txts.m_pTxts = pTxt; - } - else // At least no TXT (migth be OK, if length was 0) OR an error - { - if (!bResult) - { - DEBUG_EX_ERR( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT item!\n")); - DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); - _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - ); - } - if (pTxt) - { - delete pTxt; - pTxt = 0; - } - p_rRRAnswerTXT.clear(); - } - } // while - - DEBUG_EX_ERR( - if (!bResult) // Some failure - { - DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); - _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - } - ); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT content!\n"));); - } - // Clean up - delete[] pucBuffer; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to alloc buffer for TXT content!\n"));); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: WARNING! No content!\n"));); - } - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED!\n"));); - return bResult; -} - -#ifdef MDNS_IP6_SUPPORT -bool MDNSResponder::_readRRAnswerAAAA(MDNSResponder::stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA, - uint16_t p_u16RDLength) -{ - bool bResult = false; - // TODO: Implement - return bResult; -} -#endif - -/* - MDNSResponder::_readRRAnswerSRV -*/ -bool MDNSResponder::_readRRAnswerSRV(MDNSResponder::stcMDNS_RRAnswerSRV& p_rRRAnswerSRV, - uint16_t p_u16RDLength) -{ - - bool bResult = (((3 * sizeof(uint16_t)) < p_u16RDLength) && - (_udpRead16(p_rRRAnswerSRV.m_u16Priority)) && - (_udpRead16(p_rRRAnswerSRV.m_u16Weight)) && - (_udpRead16(p_rRRAnswerSRV.m_u16Port)) && - (_readRRDomain(p_rRRAnswerSRV.m_SRVDomain))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerSRV: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRAnswerGeneric -*/ -bool MDNSResponder::_readRRAnswerGeneric(MDNSResponder::stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric, - uint16_t p_u16RDLength) -{ - bool bResult = (0 == p_u16RDLength); - - p_rRRAnswerGeneric.clear(); - if (((p_rRRAnswerGeneric.m_u16RDLength = p_u16RDLength)) && - ((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength]))) - { - - bResult = _udpReadBuffer(p_rRRAnswerGeneric.m_pu8RDData, p_rRRAnswerGeneric.m_u16RDLength); - } - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerGeneric: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRHeader -*/ -bool MDNSResponder::_readRRHeader(MDNSResponder::stcMDNS_RRHeader& p_rRRHeader) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader\n"));); - - bool bResult = ((_readRRDomain(p_rRRHeader.m_Domain)) && - (_readRRAttributes(p_rRRHeader.m_Attributes))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRDomain - - Reads a (maybe multilevel compressed) domain from the UDP input buffer. - -*/ -bool MDNSResponder::_readRRDomain(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain\n"));); - - bool bResult = ((p_rRRDomain.clear()) && - (_readRRDomain_Loop(p_rRRDomain, 0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRDomain_Loop - - Reads a domain from the UDP input buffer. For every compression level, the functions - calls itself recursively. To avoid endless recursion because of malformed MDNS records, - the maximum recursion depth is set by MDNS_DOMAIN_MAX_REDIRCTION. - -*/ -bool MDNSResponder::_readRRDomain_Loop(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain, - uint8_t p_u8Depth) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u)\n"), p_u8Depth);); - - bool bResult = false; - - if (MDNS_DOMAIN_MAX_REDIRCTION >= p_u8Depth) - { - bResult = true; - - uint8_t u8Len = 0; - do - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Offset:%u p0:%02x\n"), p_u8Depth, m_pUDPContext->tell(), m_pUDPContext->peek());); - _udpRead8(u8Len); - - if (u8Len & MDNS_DOMAIN_COMPRESS_MARK) - { - // Compressed label(s) - uint16_t u16Offset = ((u8Len & ~MDNS_DOMAIN_COMPRESS_MARK) << 8); // Implicit BE to LE conversion! - _udpRead8(u8Len); - u16Offset |= u8Len; - - if (m_pUDPContext->isValidOffset(u16Offset)) - { - size_t stCurrentPosition = m_pUDPContext->tell(); // Prepare return from recursion - - //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Redirecting from %u to %u!\n"), p_u8Depth, stCurrentPosition, u16Offset);); - m_pUDPContext->seek(u16Offset); - if (_readRRDomain_Loop(p_rRRDomain, p_u8Depth + 1)) // Do recursion - { - //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Succeeded to read redirected label! Returning to %u\n"), p_u8Depth, stCurrentPosition);); - m_pUDPContext->seek(stCurrentPosition); // Restore after recursion - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): FAILED to read redirected label!\n"), p_u8Depth);); - bResult = false; - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): INVALID offset in redirection!\n"), p_u8Depth);); - bResult = false; - } - break; - } - else - { - // Normal (uncompressed) label (maybe '\0' only) - if (MDNS_DOMAIN_MAXLENGTH > (p_rRRDomain.m_u16NameLength + u8Len)) - { - // Add length byte - p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength] = u8Len; - ++(p_rRRDomain.m_u16NameLength); - if (u8Len) // Add name - { - if ((bResult = _udpReadBuffer((unsigned char*) & (p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength]), u8Len))) - { - /* DEBUG_EX_INFO( - p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength + u8Len] = 0; // Closing '\0' for printing - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Domain label (%u): %s\n"), p_u8Depth, (unsigned)(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength - 1]), &(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength])); - );*/ - - p_rRRDomain.m_u16NameLength += u8Len; - } - } - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(2) offset:%u p0:%x\n"), m_pUDPContext->tell(), m_pUDPContext->peek());); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Domain name too long (%u + %u)!\n"), p_u8Depth, p_rRRDomain.m_u16NameLength, u8Len);); - bResult = false; - break; - } - } - } while ((bResult) && - (0 != u8Len)); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Too many redirections!\n"), p_u8Depth);); - } - return bResult; -} - -/* - MDNSResponder::_readRRAttributes -*/ -bool MDNSResponder::_readRRAttributes(MDNSResponder::stcMDNS_RRAttributes& p_rRRAttributes) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes\n"));); - - bool bResult = ((_udpRead16(p_rRRAttributes.m_u16Type)) && - (_udpRead16(p_rRRAttributes.m_u16Class))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes: FAILED!\n"));); - return bResult; -} - - -/* - DOMAIN NAMES -*/ - -/* - MDNSResponder::_buildDomainForHost - - Builds a MDNS host domain (eg. esp8266.local) for the given hostname. - -*/ -bool MDNSResponder::_buildDomainForHost(const char* p_pcHostname, - MDNSResponder::stcMDNS_RRDomain& p_rHostDomain) const -{ - - p_rHostDomain.clear(); - bool bResult = ((p_pcHostname) && - (*p_pcHostname) && - (p_rHostDomain.addLabel(p_pcHostname)) && - (p_rHostDomain.addLabel(scpcLocal)) && - (p_rHostDomain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForHost: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_buildDomainForDNSSD - - Builds the '_services._dns-sd._udp.local' domain. - Used while detecting generic service enum question (DNS-SD) and answering these questions. - -*/ -bool MDNSResponder::_buildDomainForDNSSD(MDNSResponder::stcMDNS_RRDomain& p_rDNSSDDomain) const -{ - - p_rDNSSDDomain.clear(); - bool bResult = ((p_rDNSSDDomain.addLabel(scpcServices, true)) && - (p_rDNSSDDomain.addLabel(scpcDNSSD, true)) && - (p_rDNSSDDomain.addLabel(scpcUDP, true)) && - (p_rDNSSDDomain.addLabel(scpcLocal)) && - (p_rDNSSDDomain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForDNSSD: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_buildDomainForService - - Builds the domain for the given service (eg. _http._tcp.local or - MyESP._http._tcp.local (if p_bIncludeName is set)). - -*/ -bool MDNSResponder::_buildDomainForService(const MDNSResponder::stcMDNSService& p_Service, - bool p_bIncludeName, - MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const -{ - - p_rServiceDomain.clear(); - bool bResult = (((!p_bIncludeName) || - (p_rServiceDomain.addLabel(p_Service.m_pcName))) && - (p_rServiceDomain.addLabel(p_Service.m_pcService, true)) && - (p_rServiceDomain.addLabel(p_Service.m_pcProtocol, true)) && - (p_rServiceDomain.addLabel(scpcLocal)) && - (p_rServiceDomain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_buildDomainForService - - Builds the domain for the given service properties (eg. _http._tcp.local). - The usual prepended '_' are added, if missing in the input strings. - -*/ -bool MDNSResponder::_buildDomainForService(const char* p_pcService, - const char* p_pcProtocol, - MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const -{ - - p_rServiceDomain.clear(); - bool bResult = ((p_pcService) && - (p_pcProtocol) && - (p_rServiceDomain.addLabel(p_pcService, ('_' != *p_pcService))) && - (p_rServiceDomain.addLabel(p_pcProtocol, ('_' != *p_pcProtocol))) && - (p_rServiceDomain.addLabel(scpcLocal)) && - (p_rServiceDomain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED for (%s.%s)!\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - return bResult; -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::_buildDomainForReverseIP4 - - The IP4 address is stringized by printing the four address bytes into a char buffer in reverse order - and adding 'in-addr.arpa' (eg. 012.789.456.123.in-addr.arpa). - Used while detecting reverse IP4 questions and answering these -*/ -bool MDNSResponder::_buildDomainForReverseIP4(IPAddress p_IP4Address, - MDNSResponder::stcMDNS_RRDomain& p_rReverseIP4Domain) const -{ - - bool bResult = true; - - p_rReverseIP4Domain.clear(); - - char acBuffer[32]; - for (int i = MDNS_IP4_SIZE; ((bResult) && (i >= 1)); --i) - { - itoa(p_IP4Address[i - 1], acBuffer, 10); - bResult = p_rReverseIP4Domain.addLabel(acBuffer); - } - bResult = ((bResult) && - (p_rReverseIP4Domain.addLabel(scpcReverseIP4Domain)) && - (p_rReverseIP4Domain.addLabel(scpcReverseTopDomain)) && - (p_rReverseIP4Domain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForReverseIP4: FAILED!\n"));); - return bResult; -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::_buildDomainForReverseIP6 - - Used while detecting reverse IP6 questions and answering these -*/ -bool MDNSResponder::_buildDomainForReverseIP6(IPAddress p_IP4Address, - MDNSResponder::stcMDNS_RRDomain& p_rReverseIP6Domain) const -{ - // TODO: Implement - return false; -} -#endif - - -/* - UDP -*/ - -/* - MDNSResponder::_udpReadBuffer -*/ -bool MDNSResponder::_udpReadBuffer(unsigned char* p_pBuffer, - size_t p_stLength) -{ - - bool bResult = ((m_pUDPContext) && - (true/*m_pUDPContext->getSize() > p_stLength*/) && - (p_pBuffer) && - (p_stLength) && - ((p_stLength == m_pUDPContext->read((char*)p_pBuffer, p_stLength)))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpReadBuffer: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_udpRead8 -*/ -bool MDNSResponder::_udpRead8(uint8_t& p_ru8Value) -{ - - return _udpReadBuffer((unsigned char*)&p_ru8Value, sizeof(p_ru8Value)); -} - -/* - MDNSResponder::_udpRead16 -*/ -bool MDNSResponder::_udpRead16(uint16_t& p_ru16Value) -{ - - bool bResult = false; - - if (_udpReadBuffer((unsigned char*)&p_ru16Value, sizeof(p_ru16Value))) - { - p_ru16Value = lwip_ntohs(p_ru16Value); - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::_udpRead32 -*/ -bool MDNSResponder::_udpRead32(uint32_t& p_ru32Value) -{ - - bool bResult = false; - - if (_udpReadBuffer((unsigned char*)&p_ru32Value, sizeof(p_ru32Value))) - { - p_ru32Value = lwip_ntohl(p_ru32Value); - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::_udpAppendBuffer -*/ -bool MDNSResponder::_udpAppendBuffer(const unsigned char* p_pcBuffer, - size_t p_stLength) -{ - - bool bResult = ((m_pUDPContext) && - (p_pcBuffer) && - (p_stLength) && - (p_stLength == m_pUDPContext->append((const char*)p_pcBuffer, p_stLength))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpAppendBuffer: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_udpAppend8 -*/ -bool MDNSResponder::_udpAppend8(uint8_t p_u8Value) -{ - - return (_udpAppendBuffer((unsigned char*)&p_u8Value, sizeof(p_u8Value))); -} - -/* - MDNSResponder::_udpAppend16 -*/ -bool MDNSResponder::_udpAppend16(uint16_t p_u16Value) -{ - - p_u16Value = lwip_htons(p_u16Value); - return (_udpAppendBuffer((unsigned char*)&p_u16Value, sizeof(p_u16Value))); -} - -/* - MDNSResponder::_udpAppend32 -*/ -bool MDNSResponder::_udpAppend32(uint32_t p_u32Value) -{ - - p_u32Value = lwip_htonl(p_u32Value); - return (_udpAppendBuffer((unsigned char*)&p_u32Value, sizeof(p_u32Value))); -} - -#ifdef DEBUG_ESP_MDNS_RESPONDER -/* - MDNSResponder::_udpDump -*/ -bool MDNSResponder::_udpDump(bool p_bMovePointer /*= false*/) -{ - - const uint8_t cu8BytesPerLine = 16; - - uint32_t u32StartPosition = m_pUDPContext->tell(); - DEBUG_OUTPUT.println("UDP Context Dump:"); - uint32_t u32Counter = 0; - uint8_t u8Byte = 0; - - while (_udpRead8(u8Byte)) - { - DEBUG_OUTPUT.printf_P(PSTR("%02x %s"), u8Byte, ((++u32Counter % cu8BytesPerLine) ? "" : "\n")); - } - DEBUG_OUTPUT.printf_P(PSTR("%sDone: %u bytes\n"), (((u32Counter) && (u32Counter % cu8BytesPerLine)) ? "\n" : ""), u32Counter); - - if (!p_bMovePointer) // Restore - { - m_pUDPContext->seek(u32StartPosition); - } - return true; -} - -/* - MDNSResponder::_udpDump -*/ -bool MDNSResponder::_udpDump(unsigned p_uOffset, - unsigned p_uLength) -{ - - if ((m_pUDPContext) && - (m_pUDPContext->isValidOffset(p_uOffset))) - { - unsigned uCurrentPosition = m_pUDPContext->tell(); // Remember start position - - m_pUDPContext->seek(p_uOffset); - uint8_t u8Byte; - for (unsigned u = 0; ((u < p_uLength) && (_udpRead8(u8Byte))); ++u) - { - DEBUG_OUTPUT.printf_P(PSTR("%02x "), u8Byte); - } - // Return to start position - m_pUDPContext->seek(uCurrentPosition); - } - return true; -} -#endif - - -/** - READ/WRITE MDNS STRUCTS -*/ - -/* - MDNSResponder::_readMDNSMsgHeader - - Read a MDNS header from the UDP input buffer. - | 8 | 8 | 8 | 8 | - 00| Identifier | Flags & Codes | - 01| Question count | Answer count | - 02| NS answer count | Ad answer count | - - All 16-bit and 32-bit elements need to be translated form network coding to host coding (done in _udpRead16 and _udpRead32) - In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they - need some mapping here -*/ -bool MDNSResponder::_readMDNSMsgHeader(MDNSResponder::stcMDNS_MsgHeader& p_rMsgHeader) -{ - - bool bResult = false; - - uint8_t u8B1; - uint8_t u8B2; - if ((_udpRead16(p_rMsgHeader.m_u16ID)) && - (_udpRead8(u8B1)) && - (_udpRead8(u8B2)) && - (_udpRead16(p_rMsgHeader.m_u16QDCount)) && - (_udpRead16(p_rMsgHeader.m_u16ANCount)) && - (_udpRead16(p_rMsgHeader.m_u16NSCount)) && - (_udpRead16(p_rMsgHeader.m_u16ARCount))) - { - - p_rMsgHeader.m_1bQR = (u8B1 & 0x80); // Query/Responde flag - p_rMsgHeader.m_4bOpcode = (u8B1 & 0x78); // Operation code (0: Standard query, others ignored) - p_rMsgHeader.m_1bAA = (u8B1 & 0x04); // Authorative answer - p_rMsgHeader.m_1bTC = (u8B1 & 0x02); // Truncation flag - p_rMsgHeader.m_1bRD = (u8B1 & 0x01); // Recursion desired - - p_rMsgHeader.m_1bRA = (u8B2 & 0x80); // Recursion available - p_rMsgHeader.m_3bZ = (u8B2 & 0x70); // Zero - p_rMsgHeader.m_4bRCode = (u8B2 & 0x0F); // Response code - - /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), - (unsigned)p_rMsgHeader.m_u16ID, - (unsigned)p_rMsgHeader.m_1bQR, (unsigned)p_rMsgHeader.m_4bOpcode, (unsigned)p_rMsgHeader.m_1bAA, (unsigned)p_rMsgHeader.m_1bTC, (unsigned)p_rMsgHeader.m_1bRD, - (unsigned)p_rMsgHeader.m_1bRA, (unsigned)p_rMsgHeader.m_4bRCode, - (unsigned)p_rMsgHeader.m_u16QDCount, - (unsigned)p_rMsgHeader.m_u16ANCount, - (unsigned)p_rMsgHeader.m_u16NSCount, - (unsigned)p_rMsgHeader.m_u16ARCount););*/ - bResult = true; - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_write8 -*/ -bool MDNSResponder::_write8(uint8_t p_u8Value, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - return ((_udpAppend8(p_u8Value)) && - (p_rSendParameter.shiftOffset(sizeof(p_u8Value)))); -} - -/* - MDNSResponder::_write16 -*/ -bool MDNSResponder::_write16(uint16_t p_u16Value, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - return ((_udpAppend16(p_u16Value)) && - (p_rSendParameter.shiftOffset(sizeof(p_u16Value)))); -} - -/* - MDNSResponder::_write32 -*/ -bool MDNSResponder::_write32(uint32_t p_u32Value, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - return ((_udpAppend32(p_u32Value)) && - (p_rSendParameter.shiftOffset(sizeof(p_u32Value)))); -} - -/* - MDNSResponder::_writeMDNSMsgHeader - - Write MDNS header to the UDP output buffer. - - All 16-bit and 32-bit elements need to be translated form host coding to network coding (done in _udpAppend16 and _udpAppend32) - In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they - need some mapping here -*/ -bool MDNSResponder::_writeMDNSMsgHeader(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), - (unsigned)p_MsgHeader.m_u16ID, - (unsigned)p_MsgHeader.m_1bQR, (unsigned)p_MsgHeader.m_4bOpcode, (unsigned)p_MsgHeader.m_1bAA, (unsigned)p_MsgHeader.m_1bTC, (unsigned)p_MsgHeader.m_1bRD, - (unsigned)p_MsgHeader.m_1bRA, (unsigned)p_MsgHeader.m_4bRCode, - (unsigned)p_MsgHeader.m_u16QDCount, - (unsigned)p_MsgHeader.m_u16ANCount, - (unsigned)p_MsgHeader.m_u16NSCount, - (unsigned)p_MsgHeader.m_u16ARCount););*/ - - uint8_t u8B1((p_MsgHeader.m_1bQR << 7) | (p_MsgHeader.m_4bOpcode << 3) | (p_MsgHeader.m_1bAA << 2) | (p_MsgHeader.m_1bTC << 1) | (p_MsgHeader.m_1bRD)); - uint8_t u8B2((p_MsgHeader.m_1bRA << 7) | (p_MsgHeader.m_3bZ << 4) | (p_MsgHeader.m_4bRCode)); - bool bResult = ((_write16(p_MsgHeader.m_u16ID, p_rSendParameter)) && - (_write8(u8B1, p_rSendParameter)) && - (_write8(u8B2, p_rSendParameter)) && - (_write16(p_MsgHeader.m_u16QDCount, p_rSendParameter)) && - (_write16(p_MsgHeader.m_u16ANCount, p_rSendParameter)) && - (_write16(p_MsgHeader.m_u16NSCount, p_rSendParameter)) && - (_write16(p_MsgHeader.m_u16ARCount, p_rSendParameter))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeRRAttributes -*/ -bool MDNSResponder::_writeMDNSRRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Attributes, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - bool bResult = ((_write16(p_Attributes.m_u16Type, p_rSendParameter)) && - (_write16(p_Attributes.m_u16Class, p_rSendParameter))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRAttributes: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeMDNSRRDomain -*/ -bool MDNSResponder::_writeMDNSRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_Domain, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - bool bResult = ((_udpAppendBuffer((const unsigned char*)p_Domain.m_acName, p_Domain.m_u16NameLength)) && - (p_rSendParameter.shiftOffset(p_Domain.m_u16NameLength))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRDomain: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeMDNSHostDomain - - Write a host domain to the UDP output buffer. - If the domain record is part of the answer, the records length is - prepended (p_bPrependRDLength is set). - - A very simple form of name compression is applied here: - If the domain is written to the UDP output buffer, the write offset is stored - together with a domain id (the pointer) in a p_rSendParameter substructure (cache). - If the same domain (pointer) should be written to the UDP output later again, - the old offset is retrieved from the cache, marked as a compressed domain offset - and written to the output buffer. - -*/ -bool MDNSResponder::_writeMDNSHostDomain(const char* p_pcHostname, - bool p_bPrependRDLength, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' - uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)p_pcHostname, false); - - stcMDNS_RRDomain hostDomain; - bool bResult = (u16CachedDomainOffset - // Found cached domain -> mark as compressed domain - ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset - ((!p_bPrependRDLength) || - (_write16(2, p_rSendParameter))) && // Length of 'Cxxx' - (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) - (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) - // No cached domain -> add this domain to cache and write full domain name - : ((_buildDomainForHost(p_pcHostname, hostDomain)) && // eg. esp8266.local - ((!p_bPrependRDLength) || - (_write16(hostDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed) - (p_rSendParameter.addDomainCacheItem((const void*)p_pcHostname, false, p_rSendParameter.m_u16Offset)) && - (_writeMDNSRRDomain(hostDomain, p_rSendParameter)))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSHostDomain: FAILED!\n")); - }); - return bResult; - -} - -/* - MDNSResponder::_writeMDNSServiceDomain - - Write a service domain to the UDP output buffer. - If the domain record is part of the answer, the records length is - prepended (p_bPrependRDLength is set). - - A very simple form of name compression is applied here: see '_writeMDNSHostDomain' - The cache differentiates of course between service domains which includes - the instance name (p_bIncludeName is set) and thoose who don't. - -*/ -bool MDNSResponder::_writeMDNSServiceDomain(const MDNSResponder::stcMDNSService& p_Service, - bool p_bIncludeName, - bool p_bPrependRDLength, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' - uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)&p_Service, p_bIncludeName); - - stcMDNS_RRDomain serviceDomain; - bool bResult = (u16CachedDomainOffset - // Found cached domain -> mark as compressed domain - ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset - ((!p_bPrependRDLength) || - (_write16(2, p_rSendParameter))) && // Lenght of 'Cxxx' - (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) - (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) - // No cached domain -> add this domain to cache and write full domain name - : ((_buildDomainForService(p_Service, p_bIncludeName, serviceDomain)) && // eg. MyESP._http._tcp.local - ((!p_bPrependRDLength) || - (_write16(serviceDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed) - (p_rSendParameter.addDomainCacheItem((const void*)&p_Service, p_bIncludeName, p_rSendParameter.m_u16Offset)) && - (_writeMDNSRRDomain(serviceDomain, p_rSendParameter)))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSServiceDomain: FAILED!\n")); - }); - return bResult; - -} - -/* - MDNSResponder::_writeMDNSQuestion - - Write a MDNS question to the UDP output buffer - - QNAME (host/service domain, eg. esp8266.local) - QTYPE (16bit, eg. ANY) - QCLASS (16bit, eg. IN) - -*/ -bool MDNSResponder::_writeMDNSQuestion(MDNSResponder::stcMDNS_RRQuestion& p_Question, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion\n"));); - - bool bResult = ((_writeMDNSRRDomain(p_Question.m_Header.m_Domain, p_rSendParameter)) && - (_writeMDNSRRAttributes(p_Question.m_Header.m_Attributes, p_rSendParameter))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion: FAILED!\n")); - }); - return bResult; - -} - - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::_writeMDNSAnswer_A - - Write a MDNS A answer to the UDP output buffer. - - NAME (var, host/service domain, eg. esp8266.local - TYPE (16bit, eg. A) - CLASS (16bit, eg. IN) - TTL (32bit, eg. 120) - RDLENGTH (16bit, eg 4) - RDATA (var, eg. 123.456.789.012) - - eg. esp8266.local A 0x8001 120 4 123.456.789.012 - Ref: http://www.zytrax.com/books/dns/ch8/a.html -*/ -bool MDNSResponder::_writeMDNSAnswer_A(IPAddress p_IPAddress, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A (%s)\n"), p_IPAddress.toString().c_str());); - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_A, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - const unsigned char aucIPAddress[MDNS_IP4_SIZE] = { p_IPAddress[0], p_IPAddress[1], p_IPAddress[2], p_IPAddress[3] }; - bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL - (_write16(MDNS_IP4_SIZE, p_rSendParameter)) && // RDLength - (_udpAppendBuffer(aucIPAddress, MDNS_IP4_SIZE)) && // RData - (p_rSendParameter.shiftOffset(MDNS_IP4_SIZE))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A: FAILED!\n")); - }); - return bResult; - -} - -/* - MDNSResponder::_writeMDNSAnswer_PTR_IP4 - - Write a MDNS reverse IP4 PTR answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - eg. 012.789.456.123.in-addr.arpa PTR 0x8001 120 15 esp8266.local - Used while answering reverse IP4 questions -*/ -bool MDNSResponder::_writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4 (%s)\n"), p_IPAddress.toString().c_str());); - - stcMDNS_RRDomain reverseIP4Domain; - stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - stcMDNS_RRDomain hostDomain; - bool bResult = ((_buildDomainForReverseIP4(p_IPAddress, reverseIP4Domain)) && // 012.789.456.123.in-addr.arpa - (_writeMDNSRRDomain(reverseIP4Domain, p_rSendParameter)) && - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL - (_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4: FAILED!\n")); - }); - return bResult; -} -#endif - -/* - MDNSResponder::_writeMDNSAnswer_PTR_TYPE - - Write a MDNS PTR answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - PTR all-services -> service type - eg. _services._dns-sd._udp.local PTR 0x8001 5400 xx _http._tcp.local - http://www.zytrax.com/books/dns/ch8/ptr.html -*/ -bool MDNSResponder::_writeMDNSAnswer_PTR_TYPE(MDNSResponder::stcMDNSService& p_rService, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE\n"));); - - stcMDNS_RRDomain dnssdDomain; - stcMDNS_RRDomain serviceDomain; - stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet - bool bResult = ((_buildDomainForDNSSD(dnssdDomain)) && // _services._dns-sd._udp.local - (_writeMDNSRRDomain(dnssdDomain, p_rSendParameter)) && - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL - (_writeMDNSServiceDomain(p_rService, false, true, p_rSendParameter))); // RDLength & RData (service domain, eg. _http._tcp.local) - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeMDNSAnswer_PTR_NAME - - Write a MDNS PTR answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - PTR service type -> service name - eg. _http.tcp.local PTR 0x8001 120 xx myESP._http._tcp.local - http://www.zytrax.com/books/dns/ch8/ptr.html -*/ -bool MDNSResponder::_writeMDNSAnswer_PTR_NAME(MDNSResponder::stcMDNSService& p_rService, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME\n"));); - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet - bool bResult = ((_writeMDNSServiceDomain(p_rService, false, false, p_rSendParameter)) && // _http._tcp.local - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL - (_writeMDNSServiceDomain(p_rService, true, true, p_rSendParameter))); // RDLength & RData (service domain, eg. MyESP._http._tcp.local) - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME: FAILED!\n")); - }); - return bResult; -} - - -/* - MDNSResponder::_writeMDNSAnswer_TXT - - Write a MDNS TXT answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - The TXT items in the RDATA block are 'length byte encoded': [len]vardata - - eg. myESP._http._tcp.local TXT 0x8001 120 4 c#=1 - http://www.zytrax.com/books/dns/ch8/txt.html -*/ -bool MDNSResponder::_writeMDNSAnswer_TXT(MDNSResponder::stcMDNSService& p_rService, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT\n"));); - - bool bResult = false; - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_TXT, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - - if ((_collectServiceTxts(p_rService)) && - (_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL - (_write16(p_rService.m_Txts.length(), p_rSendParameter))) // RDLength - { - - bResult = true; - // RData Txts - for (stcMDNSServiceTxt* pTxt = p_rService.m_Txts.m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - unsigned char ucLengthByte = pTxt->length(); - bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length - (p_rSendParameter.shiftOffset(sizeof(ucLengthByte))) && - ((size_t)os_strlen(pTxt->m_pcKey) == m_pUDPContext->append(pTxt->m_pcKey, os_strlen(pTxt->m_pcKey))) && // Key - (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcKey))) && - (1 == m_pUDPContext->append("=", 1)) && // = - (p_rSendParameter.shiftOffset(1)) && - ((!pTxt->m_pcValue) || - (((size_t)os_strlen(pTxt->m_pcValue) == m_pUDPContext->append(pTxt->m_pcValue, os_strlen(pTxt->m_pcValue))) && // Value - (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcValue)))))); - - DEBUG_EX_ERR(if (!bResult) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED to write %sTxt %s=%s!\n"), (pTxt->m_bTemp ? "temp. " : ""), (pTxt->m_pcKey ? : "?"), (pTxt->m_pcValue ? : "?")); - }); - } - } - _releaseTempServiceTxts(p_rService); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED!\n")); - }); - return bResult; -} - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::_writeMDNSAnswer_AAAA - - Write a MDNS AAAA answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - eg. esp8266.local AAAA 0x8001 120 16 xxxx::xx - http://www.zytrax.com/books/dns/ch8/aaaa.html -*/ -bool MDNSResponder::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA\n"));); - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_AAAA, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && // esp8266.local - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL - (_write16(MDNS_IP6_SIZE, p_rSendParameter)) && // RDLength - (false /*TODO: IP6 version of: _udpAppendBuffer((uint32_t)p_IPAddress, MDNS_IP4_SIZE)*/)); // RData - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeMDNSAnswer_PTR_IP6 - - Write a MDNS reverse IP6 PTR answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - eg. xxxx::xx.in6.arpa PTR 0x8001 120 15 esp8266.local - Used while answering reverse IP6 questions -*/ -bool MDNSResponder::_writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6\n"));); - - stcMDNS_RRDomain reverseIP6Domain; - stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - bool bResult = ((_buildDomainForReverseIP6(p_IPAddress, reverseIP6Domain)) && // xxxx::xx.ip6.arpa - (_writeMDNSRRDomain(reverseIP6Domain, p_rSendParameter)) && - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL - (_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6: FAILED!\n")); - }); - return bResult; -} -#endif - -/* - MDNSResponder::_writeMDNSAnswer_SRV - - eg. MyESP._http.tcp.local SRV 0x8001 120 0 0 60068 esp8266.local - http://www.zytrax.com/books/dns/ch8/srv.html ???? Include instance name ???? -*/ -bool MDNSResponder::_writeMDNSAnswer_SRV(MDNSResponder::stcMDNSService& p_rService, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV\n"));); - - uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyQuery - ? 0 - : p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostname, false)); - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_SRV, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - stcMDNS_RRDomain hostDomain; - bool bResult = ((_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL - (!u16CachedDomainOffset - // No cache for domain name (or no compression allowed) - ? ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (_write16((sizeof(uint16_t /*Prio*/) + // RDLength - sizeof(uint16_t /*Weight*/) + - sizeof(uint16_t /*Port*/) + - hostDomain.m_u16NameLength), p_rSendParameter)) && // Domain length - (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority - (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight - (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port - (p_rSendParameter.addDomainCacheItem((const void*)m_pcHostname, false, p_rSendParameter.m_u16Offset)) && - (_writeMDNSRRDomain(hostDomain, p_rSendParameter))) // Host, eg. esp8266.local - // Cache available for domain - : ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset - (_write16((sizeof(uint16_t /*Prio*/) + // RDLength - sizeof(uint16_t /*Weight*/) + - sizeof(uint16_t /*Port*/) + - 2), p_rSendParameter)) && // Length of 'C0xx' - (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority - (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight - (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port - (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) - (_write8((uint8_t)u16CachedDomainOffset, p_rSendParameter))))); // Offset - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV: FAILED!\n")); - }); - return bResult; -} - -} // namespace MDNSImplementation - -} // namespace esp8266 - - - - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h deleted file mode 100644 index a3bcc4b370..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - LEAmDNS_Priv.h - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#ifndef MDNS_LWIPDEFS_H -#define MDNS_LWIPDEFS_H - -#include -#if LWIP_VERSION_MAJOR == 1 - -#include // DNS_RRTYPE_xxx - -// cherry pick from lwip1 dns.c/mdns.c source files: -#define DNS_MQUERY_PORT 5353 -#define DNS_MQUERY_IPV4_GROUP_INIT IPAddress(224,0,0,251) /* resolver1.opendns.com */ -#define DNS_RRCLASS_ANY 255 /* any class */ - -#else // lwIP > 1 - -#include // DNS_RRTYPE_xxx, DNS_MQUERY_PORT - -#endif - -#endif // MDNS_LWIPDEFS_H diff --git a/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-SPIFFS.ino b/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino similarity index 100% rename from libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-SPIFFS.ino rename to libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp index 740b77db6f..c8c05082c5 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp @@ -32,6 +32,15 @@ #include #endif +/** + STRINGIZE +*/ +#ifndef STRINGIZE +#define STRINGIZE(x) #x +#endif +#ifndef STRINGIZE_VALUE_OF +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) +#endif namespace // anonymous { @@ -778,6 +787,27 @@ bool clsLEAMDNSHost::restart(void) } +/* + clsLEAMDNSHost_Legacy::enableArduino +*/ +clsLEAMDNSHost::clsService* clsLEAMDNSHost::enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload /*= false*/) +{ + clsLEAMDNSHost::clsService* svc = addService("arduino", "arduino", "tcp", p_u16Port); + if (svc) + { + if ((!svc->addServiceTxt("tcp_check", "no")) + || (!svc->addServiceTxt("ssh_upload", "no")) + || (!svc->addServiceTxt("board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) + || (!svc->addServiceTxt("auth_upload", (p_bAuthUpload) ? "yes" : "no"))) + { + removeService(svc); + svc = 0; + } + } + return svc; +} + /* P R O T E C T E D diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host.h b/libraries/ESP8266mDNS/src/LEAmDNS2Host.h index ceee11834a..bdcc05e21e 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host.h @@ -1350,6 +1350,8 @@ class clsLEAMDNSHost bool restart(void); + clsService* enableArduino(uint16_t p_u16Port, bool p_bAuthUpload = false); + protected: // File: ..._Host UdpContext* _allocBackbone(void); From 6d22b7073b879668ccdaf0213ec6bdc8252234d1 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 8 May 2020 22:09:05 +0200 Subject: [PATCH 08/12] still using current LEA --- .../OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino | 17 +++++++++++------ libraries/ESP8266mDNS/src/ESP8266mDNS.h | 19 +++++++++++-------- libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h | 3 +++ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino b/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino index 9d0d861474..34ffcc5c89 100644 --- a/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino +++ b/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino @@ -12,8 +12,13 @@ */ +#ifndef APSSID +#define APSSID "your-apssid" +#define APPSK "your-password" +#endif + #ifndef STASSID -#define STASSID "your-ssid" +#define STASSID "your-sta" #define STAPSK "your-password" #endif @@ -30,15 +35,15 @@ @brief mDNS and OTA Constants @{ */ -#define HOSTNAME "ESP8266-OTA-" ///< Hostename. The setup function adds the Chip ID at the end. +#define HOSTNAME "ESP8266-OTA-" ///< Hostname. The setup function adds the Chip ID at the end. /// @} /** @brief Default WiFi connection information. @{ */ -const char* ap_default_ssid = STASSID; ///< Default SSID. -const char* ap_default_psk = STAPSK; ///< Default PSK. +const char* ap_default_ssid = APSSID; ///< Default SSID. +const char* ap_default_psk = APPSK; ///< Default PSK. /// @} /// Uncomment the next line for verbose output over UART. @@ -166,8 +171,8 @@ void setup() { // Load wifi connection information. if (! loadConfig(&station_ssid, &station_psk)) { - station_ssid = ""; - station_psk = ""; + station_ssid = STASSID; + station_psk = STAPSK; Serial.println("No WiFi connection information available."); } diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS.h b/libraries/ESP8266mDNS/src/ESP8266mDNS.h index c3713c6689..7b921817e7 100644 --- a/libraries/ESP8266mDNS/src/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/src/ESP8266mDNS.h @@ -42,19 +42,22 @@ */ -enum class MDNSApiVersion { Legacy, LEA, LEAv2 }; +enum class MDNSApiVersion { Legacy, LEA, LEAv2Compat, LEAv2 }; -#include "ESP8266mDNS_Legacy.h" -#include "LEAmDNS.h" -#include "LEAmDNS2Host.h" +#include "ESP8266mDNS_Legacy.h" // Legacy +#include "LEAmDNS.h" // LEA +#include "LEAmDNS2_Legacy.h" // LEAv2Compat - replacement for LEA using v2 +#include "LEAmDNS2Host.h" // LEAv2 - API updated + +// clsMDNSHost replaces MDNSResponder in LEAv2 using clsMDNSHost = esp8266::experimental::clsLEAMDNSHost; #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) // Maps the implementation to use to the global namespace type -//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; // Legacy -using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; // LEA -//using MDNSResponder = clsMDNSHost; // LEAv2 +//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; // Legacy +using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; // LEA +//using MDNSResponder = esp8266::MDNSImplementation::clsLEAMDNSHost_Legacy; // LEAv2Compat +//using MDNSResponder = clsMDNSHost; // LEAv2 extern MDNSResponder MDNS; #endif - diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h index be4a731216..9ab1f14d0c 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Legacy.h @@ -128,6 +128,9 @@ class clsLEAMDNSHost_Legacy }; public: + + static constexpr auto ApiVersion = MDNSApiVersion::LEAv2Compat; + /* INTERFACE */ clsLEAMDNSHost_Legacy(void); virtual ~clsLEAMDNSHost_Legacy(void); From b7c35048c77a632352a35fbbe5f69c4e9ea080d9 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 8 May 2020 23:15:28 +0200 Subject: [PATCH 09/12] remove unwanted change --- libraries/ESP8266WebServer/src/detail/RequestHandler.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandler.h b/libraries/ESP8266WebServer/src/detail/RequestHandler.h index c939d573bd..9202f623b3 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandler.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandler.h @@ -7,9 +7,8 @@ template class RequestHandler { -public: using WebServerType = ESP8266WebServerTemplate; - +public: virtual ~RequestHandler() { } virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; } virtual bool canUpload(String uri) { (void) uri; return false; } From ff0b10035dca6812a1a24e63890a8c4c5335033b Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 8 May 2020 23:21:47 +0200 Subject: [PATCH 10/12] remove unwanted changes --- .../src/detail/RequestHandler.h | 3 +- .../OLDmDNS/ESP8266mDNS_Legacy.cpp | 1523 ---------- .../ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h | 166 -- libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp | 1381 --------- libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h | 1461 ---------- .../ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp | 2134 -------------- .../ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp | 850 ------ libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h | 182 -- .../ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp | 2476 ----------------- .../ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp | 1779 ------------ .../ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h | 44 - 11 files changed, 1 insertion(+), 11998 deletions(-) delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp delete mode 100644 libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandler.h b/libraries/ESP8266WebServer/src/detail/RequestHandler.h index c939d573bd..9202f623b3 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandler.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandler.h @@ -7,9 +7,8 @@ template class RequestHandler { -public: using WebServerType = ESP8266WebServerTemplate; - +public: virtual ~RequestHandler() { } virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; } virtual bool canUpload(String uri) { (void) uri; return false; } diff --git a/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp b/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp deleted file mode 100644 index 8791195523..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.cpp +++ /dev/null @@ -1,1523 +0,0 @@ -/* - - ESP8266 Multicast DNS (port of CC3000 Multicast DNS library) - Version 1.1 - Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) - ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com) - MDNS-SD Suport 2015 Hristo Gochkov - Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com) - - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -// Important RFC's for reference: -// - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt -// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt -// - MDNS-SD: https://tools.ietf.org/html/rfc6763 - -#ifndef LWIP_OPEN_SRC -#define LWIP_OPEN_SRC -#endif - -#include "ESP8266mDNS.h" -#include - -#include "debug.h" - -extern "C" { -#include "osapi.h" -#include "ets_sys.h" -#include "user_interface.h" -} - -#include "WiFiUdp.h" -#include "lwip/opt.h" -#include "lwip/udp.h" -#include "lwip/inet.h" -#include "lwip/igmp.h" -#include "lwip/mem.h" -#include "include/UdpContext.h" - - - -namespace Legacy_MDNSResponder -{ - - -#ifdef DEBUG_ESP_MDNS -#define DEBUG_ESP_MDNS_ERR -#define DEBUG_ESP_MDNS_TX -#define DEBUG_ESP_MDNS_RX -#endif - -#define MDNS_NAME_REF 0xC000 - -#define MDNS_TYPE_AAAA 0x001C -#define MDNS_TYPE_A 0x0001 -#define MDNS_TYPE_PTR 0x000C -#define MDNS_TYPE_SRV 0x0021 -#define MDNS_TYPE_TXT 0x0010 - -#define MDNS_CLASS_IN 0x0001 -#define MDNS_CLASS_IN_FLUSH_CACHE 0x8001 - -#define MDNS_ANSWERS_ALL 0x0F -#define MDNS_ANSWER_PTR 0x08 -#define MDNS_ANSWER_TXT 0x04 -#define MDNS_ANSWER_SRV 0x02 -#define MDNS_ANSWER_A 0x01 - -#define _conn_read32() (((uint32_t)_conn->read() << 24) | ((uint32_t)_conn->read() << 16) | ((uint32_t)_conn->read() << 8) | _conn->read()) -#define _conn_read16() (((uint16_t)_conn->read() << 8) | _conn->read()) -#define _conn_read8() _conn->read() -#define _conn_readS(b,l) _conn->read((char*)(b),l); - -static const IPAddress MDNS_MULTICAST_ADDR(224, 0, 0, 251); -static const int MDNS_MULTICAST_TTL = 1; -static const int MDNS_PORT = 5353; - -struct MDNSService -{ - MDNSService* _next; - char _name[32]; - char _proto[4]; - uint16_t _port; - uint16_t _txtLen; // length of all txts - struct MDNSTxt * _txts; -}; - -struct MDNSTxt -{ - MDNSTxt * _next; - String _txt; -}; - -struct MDNSAnswer -{ - MDNSAnswer* next; - uint8_t ip[4]; - uint16_t port; - char *hostname; -}; - -struct MDNSQuery -{ - char _service[32]; - char _proto[4]; -}; - - -MDNSResponder::MDNSResponder() : _conn(0) -{ - _services = 0; - _instanceName = ""; - _answers = 0; - _query = 0; - _newQuery = false; - _waitingForAnswers = false; -} -MDNSResponder::~MDNSResponder() -{ - if (_query != 0) - { - os_free(_query); - _query = 0; - } - - // Clear answer list - MDNSAnswer *answer; - int numAnswers = _getNumAnswers(); - for (int n = numAnswers - 1; n >= 0; n--) - { - answer = _getAnswerFromIdx(n); - os_free(answer->hostname); - os_free(answer); - answer = 0; - } - _answers = 0; - - if (_conn) - { - _conn->unref(); - } -} - -bool MDNSResponder::begin(const char* hostname) -{ - size_t n = strlen(hostname); - if (n > 63) // max size for a single label. - { - return false; - } - - // Copy in hostname characters as lowercase - _hostName = hostname; - _hostName.toLowerCase(); - - // If instance name is not already set copy hostname to instance name - if (_instanceName.equals("")) - { - _instanceName = hostname; - } - - _gotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & event) - { - (void) event; - _restart(); - }); - - _disconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & event) - { - (void) event; - _restart(); - }); - - return _listen(); -} - -void MDNSResponder::notifyAPChange() -{ - _restart(); -} - -void MDNSResponder::_restart() -{ - if (_conn) - { - _conn->unref(); - _conn = nullptr; - } - _listen(); -} - -bool MDNSResponder::_listen() -{ - // Open the MDNS socket if it isn't already open. - if (!_conn) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.println("MDNS listening"); -#endif - - IPAddress mdns(MDNS_MULTICAST_ADDR); - - if (igmp_joingroup(IP4_ADDR_ANY4, mdns) != ERR_OK) - { - return false; - } - - _conn = new UdpContext; - _conn->ref(); - - if (!_conn->listen(IP_ADDR_ANY, MDNS_PORT)) - { - return false; - } - _conn->setMulticastTTL(MDNS_MULTICAST_TTL); - _conn->onRx(std::bind(&MDNSResponder::update, this)); - _conn->connect(mdns, MDNS_PORT); - } - return true; -} - -void MDNSResponder::update() -{ - if (!_conn || !_conn->next()) - { - return; - } - _parsePacket(); -} - - -void MDNSResponder::setInstanceName(String name) -{ - if (name.length() > 63) - { - return; - } - _instanceName = name; -} - - -bool MDNSResponder::addServiceTxt(char *name, char *proto, char *key, char *value) -{ - MDNSService* servicePtr; - - uint8_t txtLen = os_strlen(key) + os_strlen(value) + 1; // Add one for equals sign - txtLen += 1; //accounts for length byte added when building the txt responce - //Find the service - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - //Checking Service names - if (strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) - { - //found a service name match - if (servicePtr->_txtLen + txtLen > 1300) - { - return false; //max txt record size - } - MDNSTxt *newtxt = new MDNSTxt; - newtxt->_txt = String(key) + '=' + String(value); - newtxt->_next = 0; - if (servicePtr->_txts == 0) //no services have been added - { - //Adding First TXT to service - servicePtr->_txts = newtxt; - servicePtr->_txtLen += txtLen; - return true; - } - else - { - MDNSTxt * txtPtr = servicePtr->_txts; - while (txtPtr->_next != 0) - { - txtPtr = txtPtr->_next; - } - //adding another TXT to service - txtPtr->_next = newtxt; - servicePtr->_txtLen += txtLen; - return true; - } - } - } - return false; -} - -void MDNSResponder::addService(char *name, char *proto, uint16_t port) -{ - if (_getServicePort(name, proto) != 0) - { - return; - } - if (os_strlen(name) > 32 || os_strlen(proto) != 3) - { - return; //bad arguments - } - struct MDNSService *srv = (struct MDNSService*)(os_malloc(sizeof(struct MDNSService))); - os_strcpy(srv->_name, name); - os_strcpy(srv->_proto, proto); - srv->_port = port; - srv->_next = 0; - srv->_txts = 0; - srv->_txtLen = 0; - - if (_services == 0) - { - _services = srv; - } - else - { - MDNSService* servicePtr = _services; - while (servicePtr->_next != 0) - { - servicePtr = servicePtr->_next; - } - servicePtr->_next = srv; - } - -} - -int MDNSResponder::queryService(char *service, char *proto) -{ -#ifdef DEBUG_ESP_MDNS_TX - DEBUG_ESP_PORT.printf("queryService %s %s\n", service, proto); -#endif - while (_answers != 0) - { - MDNSAnswer *currAnswer = _answers; - _answers = _answers->next; - os_free(currAnswer->hostname); - os_free(currAnswer); - currAnswer = 0; - } - if (_query != 0) - { - os_free(_query); - _query = 0; - } - _query = (struct MDNSQuery*)(os_malloc(sizeof(struct MDNSQuery))); - os_strcpy(_query->_service, service); - os_strcpy(_query->_proto, proto); - _newQuery = true; - - char underscore[] = "_"; - - // build service name with _ - char serviceName[os_strlen(service) + 2]; - os_strcpy(serviceName, underscore); - os_strcat(serviceName, service); - size_t serviceNameLen = os_strlen(serviceName); - - //build proto name with _ - char protoName[5]; - os_strcpy(protoName, underscore); - os_strcat(protoName, proto); - size_t protoNameLen = 4; - - //local string - char localName[] = "local"; - size_t localNameLen = 5; - - //terminator - char terminator[] = "\0"; - - // Only supports sending one PTR query - uint8_t questionCount = 1; - - _waitingForAnswers = true; - for (int itfn = 0; itfn < 2; itfn++) - { - struct ip_info ip_info; - - wifi_get_ip_info((!itfn) ? SOFTAP_IF : STATION_IF, &ip_info); - if (!ip_info.ip.addr) - { - continue; - } - _conn->setMulticastInterface(IPAddress(ip_info.ip.addr)); - - // Write the header - _conn->flush(); - uint8_t head[12] = - { - 0x00, 0x00, //ID = 0 - 0x00, 0x00, //Flags = response + authoritative answer - 0x00, questionCount, //Question count - 0x00, 0x00, //Answer count - 0x00, 0x00, //Name server records - 0x00, 0x00 //Additional records - }; - _conn->append(reinterpret_cast(head), 12); - - // Only supports sending one PTR query - // Send the Name field (eg. "_http._tcp.local") - _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_" + service - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_" + service - _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_" + proto - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_" + proto - _conn->append(reinterpret_cast(&localNameLen), 1); // lenght of "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type and class - uint8_t ptrAttrs[4] = - { - 0x00, 0x0c, //PTR record query - 0x00, 0x01 //Class IN - }; - _conn->append(reinterpret_cast(ptrAttrs), 4); - _conn->send(); - } - -#ifdef DEBUG_ESP_MDNS_TX - DEBUG_ESP_PORT.println("Waiting for answers.."); -#endif - delay(1000); - - _waitingForAnswers = false; - - return _getNumAnswers(); -} - -String MDNSResponder::hostname(int idx) -{ - MDNSAnswer *answer = _getAnswerFromIdx(idx); - if (answer == 0) - { - return String(); - } - return answer->hostname; -} - -IPAddress MDNSResponder::IP(int idx) -{ - MDNSAnswer *answer = _getAnswerFromIdx(idx); - if (answer == 0) - { - return IPAddress(); - } - return IPAddress(answer->ip); -} - -uint16_t MDNSResponder::port(int idx) -{ - MDNSAnswer *answer = _getAnswerFromIdx(idx); - if (answer == 0) - { - return 0; - } - return answer->port; -} - -MDNSAnswer* MDNSResponder::_getAnswerFromIdx(int idx) -{ - MDNSAnswer *answer = _answers; - while (answer != 0 && idx-- > 0) - { - answer = answer->next; - } - if (idx > 0) - { - return 0; - } - return answer; -} - -int MDNSResponder::_getNumAnswers() -{ - int numAnswers = 0; - MDNSAnswer *answer = _answers; - while (answer != 0) - { - numAnswers++; - answer = answer->next; - } - return numAnswers; -} - -MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto) -{ - MDNSService* servicePtr; - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - if (servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) - { - if (servicePtr->_txts == 0) - { - return nullptr; - } - return servicePtr->_txts; - } - } - return nullptr; -} - -uint16_t MDNSResponder::_getServiceTxtLen(char *name, char *proto) -{ - MDNSService* servicePtr; - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - if (servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) - { - if (servicePtr->_txts == 0) - { - return false; - } - return servicePtr->_txtLen; - } - } - return 0; -} - -uint16_t MDNSResponder::_getServicePort(char *name, char *proto) -{ - MDNSService* servicePtr; - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - if (servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0) - { - return servicePtr->_port; - } - } - return 0; -} - -IPAddress MDNSResponder::_getRequestMulticastInterface() -{ - struct ip_info ip_info; - bool match_ap = false; - if (wifi_get_opmode() & SOFTAP_MODE) - { - const IPAddress& remote_ip = _conn->getRemoteAddress(); - wifi_get_ip_info(SOFTAP_IF, &ip_info); - IPAddress infoIp(ip_info.ip); - IPAddress infoMask(ip_info.netmask); - if (ip_info.ip.addr && ip_addr_netcmp((const ip_addr_t*)remote_ip, (const ip_addr_t*)infoIp, ip_2_ip4((const ip_addr_t*)infoMask))) - { - match_ap = true; - } - } - if (!match_ap) - { - wifi_get_ip_info(STATION_IF, &ip_info); - } - return IPAddress(ip_info.ip.addr); -} - -void MDNSResponder::_parsePacket() -{ - int i; - char tmp; - bool serviceParsed = false; - bool protoParsed = false; - bool localParsed = false; - - char hostName[255]; - uint8_t hostNameLen; - - char serviceName[32]; - uint8_t serviceNameLen; - uint16_t servicePort = 0; - - char protoName[32]; - protoName[0] = 0; - uint8_t protoNameLen = 0; - - uint16_t packetHeader[6]; - - for (i = 0; i < 6; i++) - { - packetHeader[i] = _conn_read16(); - } - - if ((packetHeader[1] & 0x8000) != 0) // Read answers - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("Reading answers RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]); -#endif - - if (!_waitingForAnswers) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.println("Not expecting any answers right now, returning"); -#endif - _conn->flush(); - return; - } - - int numAnswers = packetHeader[3] + packetHeader[5]; - // Assume that the PTR answer always comes first and that it is always accompanied by a TXT, SRV, AAAA (optional) and A answer in the same packet. - if (numAnswers < 4) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("Expected a packet with 4 or more answers, got %u\n", numAnswers); -#endif - _conn->flush(); - return; - } - - uint8_t tmp8; - uint16_t answerPort = 0; - uint8_t answerIp[4] = { 0, 0, 0, 0 }; - char answerHostName[255]; - bool serviceMatch = false; - MDNSAnswer *answer; - uint8_t partsCollected = 0; - uint8_t stringsRead = 0; - - answerHostName[0] = '\0'; - - // Clear answer list - if (_newQuery) - { - int oldAnswers = _getNumAnswers(); - for (int n = oldAnswers - 1; n >= 0; n--) - { - answer = _getAnswerFromIdx(n); - os_free(answer->hostname); - os_free(answer); - answer = 0; - } - _answers = 0; - _newQuery = false; - } - - while (numAnswers--) - { - // Read name - stringsRead = 0; - size_t last_bufferpos = 0; - do - { - tmp8 = _conn_read8(); - if (tmp8 == 0x00) // End of name - { - break; - } - if (tmp8 & 0xC0) // Compressed pointer - { - uint16_t offset = ((((uint16_t)tmp8) & ~0xC0) << 8) | _conn_read8(); - if (_conn->isValidOffset(offset)) - { - if (0 == last_bufferpos) - { - last_bufferpos = _conn->tell(); - } -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Compressed pointer, jumping from "); - DEBUG_ESP_PORT.print(last_bufferpos); - DEBUG_ESP_PORT.print(" to "); - DEBUG_ESP_PORT.println(offset); -#endif - _conn->seek(offset); - tmp8 = _conn_read8(); - } - else - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Skipping malformed compressed pointer"); -#endif - tmp8 = _conn_read8(); - break; - } - } - if (stringsRead > 3) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.println("failed to read the response name"); -#endif - _conn->flush(); - return; - } - _conn_readS(serviceName, tmp8); - serviceName[tmp8] = '\0'; -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf(" %d ", tmp8); - for (int n = 0; n < tmp8; n++) - { - DEBUG_ESP_PORT.printf("%c", serviceName[n]); - } - DEBUG_ESP_PORT.println(); -#endif - if (serviceName[0] == '_') - { - if (strcmp(&serviceName[1], _query->_service) == 0) - { - serviceMatch = true; -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("found matching service: %s\n", _query->_service); -#endif - } - } - stringsRead++; - } while (true); - if (last_bufferpos > 0) - { - _conn->seek(last_bufferpos); -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Compressed pointer, jumping back to "); - DEBUG_ESP_PORT.println(last_bufferpos); -#endif - } - - uint16_t answerType = _conn_read16(); // Read type - uint16_t answerClass = _conn_read16(); // Read class - uint32_t answerTtl = _conn_read32(); // Read ttl - uint16_t answerRdlength = _conn_read16(); // Read rdlength - - (void) answerClass; - (void) answerTtl; - - if (answerRdlength > 255) - { - if (answerType == MDNS_TYPE_TXT && answerRdlength < 1460) - { - while (--answerRdlength) - { - _conn->read(); - } - } - else - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("Data len too long! %u\n", answerRdlength); -#endif - _conn->flush(); - return; - } - } - -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("type: %04x rdlength: %d\n", answerType, answerRdlength); -#endif - - if (answerType == MDNS_TYPE_PTR) - { - partsCollected |= 0x01; - _conn_readS(hostName, answerRdlength); // Read rdata - if (hostName[answerRdlength - 2] & 0xc0) - { - memcpy(answerHostName, hostName + 1, answerRdlength - 3); - answerHostName[answerRdlength - 3] = '\0'; - } -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("PTR %d ", answerRdlength); - for (int n = 0; n < answerRdlength; n++) - { - DEBUG_ESP_PORT.printf("%c", hostName[n]); - } - DEBUG_ESP_PORT.println(); -#endif - } - - else if (answerType == MDNS_TYPE_TXT) - { - partsCollected |= 0x02; - _conn_readS(hostName, answerRdlength); // Read rdata -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("TXT %d ", answerRdlength); - for (int n = 0; n < answerRdlength; n++) - { - DEBUG_ESP_PORT.printf("%c", hostName[n]); - } - DEBUG_ESP_PORT.println(); -#endif - } - - else if (answerType == MDNS_TYPE_SRV) - { - partsCollected |= 0x04; - uint16_t answerPrio = _conn_read16(); // Read priority - uint16_t answerWeight = _conn_read16(); // Read weight - answerPort = _conn_read16(); // Read port - last_bufferpos = 0; - - (void) answerPrio; - (void) answerWeight; - - // Read hostname - tmp8 = _conn_read8(); - if (tmp8 & 0xC0) // Compressed pointer - { - uint16_t offset = ((((uint16_t)tmp8) & ~0xC0) << 8) | _conn_read8(); - if (_conn->isValidOffset(offset)) - { - last_bufferpos = _conn->tell(); -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Compressed pointer, jumping from "); - DEBUG_ESP_PORT.print(last_bufferpos); - DEBUG_ESP_PORT.print(" to "); - DEBUG_ESP_PORT.println(offset); -#endif - _conn->seek(offset); - tmp8 = _conn_read8(); - } - else - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Skipping malformed compressed pointer"); -#endif - tmp8 = _conn_read8(); - break; - } - } - _conn_readS(answerHostName, tmp8); - answerHostName[tmp8] = '\0'; -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("SRV %d ", tmp8); - for (int n = 0; n < tmp8; n++) - { - DEBUG_ESP_PORT.printf("%02x ", answerHostName[n]); - } - DEBUG_ESP_PORT.printf("\n%s\n", answerHostName); -#endif - if (last_bufferpos > 0) - { - _conn->seek(last_bufferpos); - tmp8 = 2; // Size of compression octets -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.print("Compressed pointer, jumping back to "); - DEBUG_ESP_PORT.println(last_bufferpos); -#endif - } - if (answerRdlength - (6 + 1 + tmp8) > 0) // Skip any remaining rdata - { - _conn_readS(hostName, answerRdlength - (6 + 1 + tmp8)); - } - } - - else if (answerType == MDNS_TYPE_A) - { - partsCollected |= 0x08; - for (int i = 0; i < 4; i++) - { - answerIp[i] = _conn_read8(); - } - } - else - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("Ignoring unsupported type %02x\n", tmp8); -#endif - for (int n = 0; n < answerRdlength; n++) - { - (void)_conn_read8(); - } - } - - if ((partsCollected == 0x0F) && serviceMatch) - { -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.println("All answers parsed, adding to _answers list.."); -#endif - // Add new answer to answer list - if (_answers == 0) - { - _answers = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer))); - answer = _answers; - } - else - { - answer = _answers; - while (answer->next != 0) - { - answer = answer->next; - } - answer->next = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer))); - answer = answer->next; - } - answer->next = 0; - answer->hostname = 0; - - // Populate new answer - answer->port = answerPort; - for (int i = 0; i < 4; i++) - { - answer->ip[i] = answerIp[i]; - } - answer->hostname = (char *)os_malloc(strlen(answerHostName) + 1); - os_strcpy(answer->hostname, answerHostName); - _conn->flush(); - return; - } - } - - _conn->flush(); - return; - } - - // PARSE REQUEST NAME - - hostNameLen = _conn_read8() % 255; - _conn_readS(hostName, hostNameLen); - hostName[hostNameLen] = '\0'; - - if (hostName[0] == '_') - { - serviceParsed = true; - memcpy(serviceName, hostName + 1, hostNameLen); - serviceNameLen = hostNameLen - 1; - hostNameLen = 0; - } - - if (hostNameLen > 0 && !_hostName.equals(hostName) && !_instanceName.equals(hostName)) - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_NO_HOST: %s\n", hostName); - DEBUG_ESP_PORT.printf("hostname: %s\n", _hostName.c_str()); - DEBUG_ESP_PORT.printf("instance: %s\n", _instanceName.c_str()); -#endif - _conn->flush(); - return; - } - - if (!serviceParsed) - { - serviceNameLen = _conn_read8() % 255; - _conn_readS(serviceName, serviceNameLen); - serviceName[serviceNameLen] = '\0'; - - if (serviceName[0] == '_') - { - memmove(serviceName, serviceName + 1, serviceNameLen); - serviceNameLen--; - serviceParsed = true; - } - else if (serviceNameLen == 5 && strcmp("local", serviceName) == 0) - { - tmp = _conn_read8(); - if (tmp == 0) - { - serviceParsed = true; - serviceNameLen = 0; - protoParsed = true; - protoNameLen = 0; - localParsed = true; - } - else - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_FQDN: %s\n", serviceName); -#endif - _conn->flush(); - return; - } - } - else - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_SERVICE: %s\n", serviceName); -#endif - _conn->flush(); - return; - } - } - - if (!protoParsed) - { - protoNameLen = _conn_read8() % 255; - _conn_readS(protoName, protoNameLen); - protoName[protoNameLen] = '\0'; - if (protoNameLen == 4 && protoName[0] == '_') - { - memmove(protoName, protoName + 1, protoNameLen); - protoNameLen--; - protoParsed = true; - } - else if (strcmp("services", serviceName) == 0 && strcmp("_dns-sd", protoName) == 0) - { - _conn->flush(); - IPAddress interface = _getRequestMulticastInterface(); - _replyToTypeEnumRequest(interface); - return; - } - else - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_PROTO: %s\n", protoName); -#endif - _conn->flush(); - return; - } - } - - if (!localParsed) - { - char localName[32]; - uint8_t localNameLen = _conn_read8() % 31; - _conn_readS(localName, localNameLen); - localName[localNameLen] = '\0'; - tmp = _conn_read8(); - if (localNameLen == 5 && strcmp("local", localName) == 0 && tmp == 0) - { - localParsed = true; - } - else - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_FQDN: %s\n", localName); -#endif - _conn->flush(); - return; - } - } - - if (serviceNameLen > 0 && protoNameLen > 0) - { - servicePort = _getServicePort(serviceName, protoName); - if (servicePort == 0) - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_NO_SERVICE: %s\n", serviceName); -#endif - _conn->flush(); - return; - } - } - else if (serviceNameLen > 0 || protoNameLen > 0) - { -#ifdef DEBUG_ESP_MDNS_ERR - DEBUG_ESP_PORT.printf("ERR_SERVICE_PROTO: %s\n", serviceName); -#endif - _conn->flush(); - return; - } - - // RESPOND - -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]); -#endif - - uint16_t currentType; - uint16_t currentClass; - - int numQuestions = packetHeader[2]; - if (numQuestions > 4) - { - numQuestions = 4; - } - uint16_t questions[4]; - int question = 0; - - while (numQuestions--) - { - currentType = _conn_read16(); - if (currentType & MDNS_NAME_REF) //new header handle it better! - { - currentType = _conn_read16(); - } - currentClass = _conn_read16(); - if (currentClass & MDNS_CLASS_IN) - { - questions[question++] = currentType; - } - - if (numQuestions > 0) - { - if (_conn_read16() != 0xC00C) //new question but for another host/service - { - _conn->flush(); - numQuestions = 0; - } - } - -#ifdef DEBUG_ESP_MDNS_RX - DEBUG_ESP_PORT.printf("REQ: "); - if (hostNameLen > 0) - { - DEBUG_ESP_PORT.printf("%s.", hostName); - } - if (serviceNameLen > 0) - { - DEBUG_ESP_PORT.printf("_%s.", serviceName); - } - if (protoNameLen > 0) - { - DEBUG_ESP_PORT.printf("_%s.", protoName); - } - DEBUG_ESP_PORT.printf("local. "); - - if (currentType == MDNS_TYPE_AAAA) - { - DEBUG_ESP_PORT.printf(" AAAA "); - } - else if (currentType == MDNS_TYPE_A) - { - DEBUG_ESP_PORT.printf(" A "); - } - else if (currentType == MDNS_TYPE_PTR) - { - DEBUG_ESP_PORT.printf(" PTR "); - } - else if (currentType == MDNS_TYPE_SRV) - { - DEBUG_ESP_PORT.printf(" SRV "); - } - else if (currentType == MDNS_TYPE_TXT) - { - DEBUG_ESP_PORT.printf(" TXT "); - } - else - { - DEBUG_ESP_PORT.printf(" 0x%04X ", currentType); - } - - if (currentClass == MDNS_CLASS_IN) - { - DEBUG_ESP_PORT.printf(" IN "); - } - else if (currentClass == MDNS_CLASS_IN_FLUSH_CACHE) - { - DEBUG_ESP_PORT.printf(" IN[F] "); - } - else - { - DEBUG_ESP_PORT.printf(" 0x%04X ", currentClass); - } - - DEBUG_ESP_PORT.printf("\n"); -#endif - } - uint8_t questionMask = 0; - uint8_t responseMask = 0; - for (i = 0; i < question; i++) - { - if (questions[i] == MDNS_TYPE_A) - { - questionMask |= 0x1; - responseMask |= 0x1; - } - else if (questions[i] == MDNS_TYPE_SRV) - { - questionMask |= 0x2; - responseMask |= 0x3; - } - else if (questions[i] == MDNS_TYPE_TXT) - { - questionMask |= 0x4; - responseMask |= 0x4; - } - else if (questions[i] == MDNS_TYPE_PTR) - { - questionMask |= 0x8; - responseMask |= 0xF; - } - } - - IPAddress interface = _getRequestMulticastInterface(); - return _replyToInstanceRequest(questionMask, responseMask, serviceName, protoName, servicePort, interface); -} - - -/** - STRINGIZE -*/ -#ifndef STRINGIZE -#define STRINGIZE(x) #x -#endif -#ifndef STRINGIZE_VALUE_OF -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) -#endif - - -void MDNSResponder::enableArduino(uint16_t port, bool auth) -{ - - addService("arduino", "tcp", port); - addServiceTxt("arduino", "tcp", "tcp_check", "no"); - addServiceTxt("arduino", "tcp", "ssh_upload", "no"); - addServiceTxt("arduino", "tcp", "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD)); - addServiceTxt("arduino", "tcp", "auth_upload", (auth) ? "yes" : "no"); -} - -void MDNSResponder::_replyToTypeEnumRequest(IPAddress multicastInterface) -{ - MDNSService* servicePtr; - for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) - { - if (servicePtr->_port > 0) - { - char *service = servicePtr->_name; - char *proto = servicePtr->_proto; - //uint16_t port = servicePtr->_port; - -#ifdef DEBUG_ESP_MDNS_TX - DEBUG_ESP_PORT.printf("TX: service:%s, proto:%s\n", service, proto); -#endif - - char sdHostName[] = "_services"; - size_t sdHostNameLen = 9; - char sdServiceName[] = "_dns-sd"; - size_t sdServiceNameLen = 7; - char sdProtoName[] = "_udp"; - size_t sdProtoNameLen = 4; - - char underscore[] = "_"; - - // build service name with _ - char serviceName[os_strlen(service) + 2]; - os_strcpy(serviceName, underscore); - os_strcat(serviceName, service); - size_t serviceNameLen = os_strlen(serviceName); - - //build proto name with _ - char protoName[5]; - os_strcpy(protoName, underscore); - os_strcat(protoName, proto); - size_t protoNameLen = 4; - - //local string - char localName[] = "local"; - size_t localNameLen = 5; - - //terminator - char terminator[] = "\0"; - - //Write the header - _conn->flush(); - uint8_t head[12] = - { - 0x00, 0x00, //ID = 0 - 0x84, 0x00, //Flags = response + authoritative answer - 0x00, 0x00, //Question count - 0x00, 0x01, //Answer count - 0x00, 0x00, //Name server records - 0x00, 0x00, //Additional records - }; - _conn->append(reinterpret_cast(head), 12); - - // Send the Name field (ie. "_services._dns-sd._udp.local") - _conn->append(reinterpret_cast(&sdHostNameLen), 1); // length of "_services" - _conn->append(reinterpret_cast(sdHostName), sdHostNameLen); // "_services" - _conn->append(reinterpret_cast(&sdServiceNameLen), 1); // length of "_dns-sd" - _conn->append(reinterpret_cast(sdServiceName), sdServiceNameLen);// "_dns-sd" - _conn->append(reinterpret_cast(&sdProtoNameLen), 1); // length of "_udp" - _conn->append(reinterpret_cast(sdProtoName), sdProtoNameLen); // "_udp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type, class, ttl and rdata length - uint8_t ptrDataLen = serviceNameLen + protoNameLen + localNameLen + 4; // 4 is three label sizes and the terminator - uint8_t ptrAttrs[10] = - { - 0x00, 0x0c, //PTR record query - 0x00, 0x01, //Class IN - 0x00, 0x00, 0x11, 0x94, //TTL 4500 - 0x00, ptrDataLen, //RData length - }; - _conn->append(reinterpret_cast(ptrAttrs), 10); - - //Send the RData (ie. "_http._tcp.local") - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - _conn->setMulticastInterface(multicastInterface); - _conn->send(); - } - } -} - -void MDNSResponder::_replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface) -{ - int i; - if (questionMask == 0) - { - return; - } - if (responseMask == 0) - { - return; - } - -#ifdef DEBUG_ESP_MDNS_TX - DEBUG_ESP_PORT.printf("TX: qmask:%01X, rmask:%01X, service:%s, proto:%s, port:%u\n", questionMask, responseMask, service, proto, port); -#endif - - - String instanceName = _instanceName; - size_t instanceNameLen = instanceName.length(); - - String hostName = _hostName; - size_t hostNameLen = hostName.length(); - - char underscore[] = "_"; - - // build service name with _ - char serviceName[os_strlen(service) + 2]; - os_strcpy(serviceName, underscore); - os_strcat(serviceName, service); - size_t serviceNameLen = os_strlen(serviceName); - - //build proto name with _ - char protoName[5]; - os_strcpy(protoName, underscore); - os_strcat(protoName, proto); - size_t protoNameLen = 4; - - //local string - char localName[] = "local"; - size_t localNameLen = 5; - - //terminator - char terminator[] = "\0"; - - uint8_t answerMask = responseMask & questionMask; - uint8_t answerCount = 0; - uint8_t additionalMask = responseMask & ~questionMask; - uint8_t additionalCount = 0; - for (i = 0; i < 4; i++) - { - if (answerMask & (1 << i)) - { - answerCount++; - } - if (additionalMask & (1 << i)) - { - additionalCount++; - } - } - - - //Write the header - _conn->flush(); - uint8_t head[12] = - { - 0x00, 0x00, //ID = 0 - 0x84, 0x00, //Flags = response + authoritative answer - 0x00, 0x00, //Question count - 0x00, answerCount, //Answer count - 0x00, 0x00, //Name server records - 0x00, additionalCount, //Additional records - }; - _conn->append(reinterpret_cast(head), 12); - - for (int responseSection = 0; responseSection < 2; ++responseSection) - { - - // PTR Response - if ((responseSection == 0 ? answerMask : additionalMask) & 0x8) - { - // Send the Name field (ie. "_http._tcp.local") - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type, class, ttl and rdata length - uint8_t ptrDataLen = instanceNameLen + serviceNameLen + protoNameLen + localNameLen + 5; // 5 is four label sizes and the terminator - uint8_t ptrAttrs[10] = - { - 0x00, 0x0c, //PTR record query - 0x00, 0x01, //Class IN - 0x00, 0x00, 0x00, 0x78, //TTL 120 - 0x00, ptrDataLen, //RData length - }; - _conn->append(reinterpret_cast(ptrAttrs), 10); - - //Send the RData (ie. "My IOT device._http._tcp.local") - _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" - _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - } - - //TXT Responce - if ((responseSection == 0 ? answerMask : additionalMask) & 0x4) - { - //Send the name field (ie. "My IOT device._http._tcp.local") - _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" - _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type, class, ttl and rdata length - uint8_t txtDataLen = _getServiceTxtLen(service, proto); - uint8_t txtAttrs[10] = - { - 0x00, 0x10, //TXT record query - 0x80, 0x01, //Class IN, with cache flush - 0x00, 0x00, 0x11, 0x94, //TTL 4500 - 0x00, txtDataLen, //RData length - }; - _conn->append(reinterpret_cast(txtAttrs), 10); - - //Send the RData - MDNSTxt * txtPtr = _getServiceTxt(service, proto); - while (txtPtr != 0) - { - uint8_t txtLen = txtPtr->_txt.length(); - _conn->append(reinterpret_cast(&txtLen), 1); // length of txt - _conn->append(reinterpret_cast(txtPtr->_txt.c_str()), txtLen);// the txt - txtPtr = txtPtr->_next; - } - } - - - //SRV Responce - if ((responseSection == 0 ? answerMask : additionalMask) & 0x2) - { - //Send the name field (ie. "My IOT device._http._tcp.local") - _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" - _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" - _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - //Send the type, class, ttl, rdata length, priority and weight - uint8_t srvDataSize = hostNameLen + localNameLen + 3; // 3 is 2 lable size bytes and the terminator - srvDataSize += 6; // Size of Priority, weight and port - uint8_t srvAttrs[10] = - { - 0x00, 0x21, //Type SRV - 0x80, 0x01, //Class IN, with cache flush - 0x00, 0x00, 0x00, 0x78, //TTL 120 - 0x00, srvDataSize, //RData length - }; - _conn->append(reinterpret_cast(srvAttrs), 10); - - //Send the RData Priority weight and port - uint8_t srvRData[6] = - { - 0x00, 0x00, //Priority 0 - 0x00, 0x00, //Weight 0 - (uint8_t)((port >> 8) & 0xFF), (uint8_t)(port & 0xFF) - }; - _conn->append(reinterpret_cast(srvRData), 6); - //Send the RData (ie. "esp8266.local") - _conn->append(reinterpret_cast(&hostNameLen), 1); // length of "esp8266" - _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - } - - // A Response - if ((responseSection == 0 ? answerMask : additionalMask) & 0x1) - { - //Send the RData (ie. "esp8266.local") - _conn->append(reinterpret_cast(&hostNameLen), 1); // length of "esp8266" - _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" - _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - uint8_t aaaAttrs[10] = - { - 0x00, 0x01, //TYPE A - 0x80, 0x01, //Class IN, with cache flush - 0x00, 0x00, 0x00, 0x78, //TTL 120 - 0x00, 0x04, //DATA LEN - }; - _conn->append(reinterpret_cast(aaaAttrs), 10); - - // Send RData - uint32_t ip = multicastInterface; - uint8_t aaaRData[4] = - { - (uint8_t)(ip & 0xFF), //IP first octet - (uint8_t)((ip >> 8) & 0xFF), //IP second octet - (uint8_t)((ip >> 16) & 0xFF), //IP third octet - (uint8_t)((ip >> 24) & 0xFF) //IP fourth octet - }; - _conn->append(reinterpret_cast(aaaRData), 4); - } - } - - _conn->setMulticastInterface(multicastInterface); - _conn->send(); -} - -#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) -MDNSResponder MDNS; -#endif - -} // namespace Legacy_MDNSResponder - - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h b/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h deleted file mode 100644 index 9d3cfd2f62..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/ESP8266mDNS_Legacy.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - ESP8266 Multicast DNS (port of CC3000 Multicast DNS library) - Version 1.1 - Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) - ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com) - Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com) - - This is a simple implementation of multicast DNS query support for an Arduino - running on ESP8266 chip. Only support for resolving address queries is currently - implemented. - - Requirements: - - ESP8266WiFi library - - Usage: - - Include the ESP8266 Multicast DNS library in the sketch. - - Call the begin method in the sketch's setup and provide a domain name (without - the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the - Adafruit CC3000 class instance. Optionally provide a time to live (in seconds) - for the DNS record--the default is 1 hour. - - Call the update method in each iteration of the sketch's loop function. - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ -#ifndef ESP8266MDNS_LEGACY_H -#define ESP8266MDNS_LEGACY_H - -#include "ESP8266WiFi.h" -#include "WiFiUdp.h" - -//this should be defined at build time -#ifndef ARDUINO_BOARD -#define ARDUINO_BOARD "generic" -#endif - -class UdpContext; - - -namespace Legacy_MDNSResponder -{ - - -struct MDNSService; -struct MDNSTxt; -struct MDNSAnswer; - -class MDNSResponder -{ -public: - MDNSResponder(); - ~MDNSResponder(); - bool begin(const char* hostName); - bool begin(const String& hostName) - { - return begin(hostName.c_str()); - } - //for compatibility - bool begin(const char* hostName, IPAddress ip, uint32_t ttl = 120) - { - (void) ip; - (void) ttl; - return begin(hostName); - } - bool begin(const String& hostName, IPAddress ip, uint32_t ttl = 120) - { - return begin(hostName.c_str(), ip, ttl); - } - /* Application should call this whenever AP is configured/disabled */ - void notifyAPChange(); - void update(); - - void addService(char *service, char *proto, uint16_t port); - void addService(const char *service, const char *proto, uint16_t port) - { - addService((char *)service, (char *)proto, port); - } - void addService(const String& service, const String& proto, uint16_t port) - { - addService(service.c_str(), proto.c_str(), port); - } - - bool addServiceTxt(char *name, char *proto, char * key, char * value); - bool addServiceTxt(const char *name, const char *proto, const char *key, const char * value) - { - return addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value); - } - bool addServiceTxt(const String& name, const String& proto, const String& key, const String& value) - { - return addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str()); - } - - int queryService(char *service, char *proto); - int queryService(const char *service, const char *proto) - { - return queryService((char *)service, (char *)proto); - } - int queryService(const String& service, const String& proto) - { - return queryService(service.c_str(), proto.c_str()); - } - String hostname(int idx); - IPAddress IP(int idx); - uint16_t port(int idx); - - void enableArduino(uint16_t port, bool auth = false); - - void setInstanceName(String name); - void setInstanceName(const char * name) - { - setInstanceName(String(name)); - } - void setInstanceName(char * name) - { - setInstanceName(String(name)); - } - -private: - struct MDNSService * _services; - UdpContext* _conn; - String _hostName; - String _instanceName; - struct MDNSAnswer * _answers; - struct MDNSQuery * _query; - bool _newQuery; - bool _waitingForAnswers; - WiFiEventHandler _disconnectedHandler; - WiFiEventHandler _gotIPHandler; - - - uint16_t _getServicePort(char *service, char *proto); - MDNSTxt * _getServiceTxt(char *name, char *proto); - uint16_t _getServiceTxtLen(char *name, char *proto); - IPAddress _getRequestMulticastInterface(); - void _parsePacket(); - void _replyToTypeEnumRequest(IPAddress multicastInterface); - void _replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface); - MDNSAnswer* _getAnswerFromIdx(int idx); - int _getNumAnswers(); - bool _listen(); - void _restart(); -}; - -} // namespace Legacy_MDNSResponder - -#endif //ESP8266MDNS_H - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp deleted file mode 100644 index 87ff5167ff..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.cpp +++ /dev/null @@ -1,1381 +0,0 @@ -/* - LEAmDNS.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include -#include - -#include "LEAmDNS_Priv.h" - - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - STRINGIZE -*/ -#ifndef STRINGIZE -#define STRINGIZE(x) #x -#endif -#ifndef STRINGIZE_VALUE_OF -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) -#endif - - -/** - INTERFACE -*/ - -/** - MDNSResponder::MDNSResponder -*/ -MDNSResponder::MDNSResponder(void) - : m_pServices(0), - m_pUDPContext(0), - m_pcHostname(0), - m_pServiceQueries(0), - m_fnServiceTxtCallback(0), -#ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE - m_bPassivModeEnabled(true), -#else - m_bPassivModeEnabled(false), -#endif - m_netif(nullptr) -{ -} - -/* - MDNSResponder::~MDNSResponder -*/ -MDNSResponder::~MDNSResponder(void) -{ - - _resetProbeStatus(false); - _releaseServiceQueries(); - _releaseHostname(); - _releaseUDPContext(); - _releaseServices(); -} - -/* - MDNSResponder::begin - - Set the host domain (for probing) and install WiFi event handlers for - IP assignment and disconnection management. In both cases, the MDNS responder - is restarted (reset and restart probe status) - Finally the responder is (re)started - -*/ -bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress, uint32_t p_u32TTL) -{ - - (void)p_u32TTL; // ignored - bool bResult = false; - - if (0 == m_pUDPContext) - { - if (_setHostname(p_pcHostname)) - { - - //// select interface - - m_netif = nullptr; - IPAddress ipAddress = p_IPAddress; - - if (!ipAddress.isSet()) - { - - IPAddress sta = WiFi.localIP(); - IPAddress ap = WiFi.softAPIP(); - - if (sta.isSet()) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] STA interface selected\n"))); - ipAddress = sta; - } - else if (ap.isSet()) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] AP interface selected\n"))); - ipAddress = ap; - } - else - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] standard interfaces are not up, please specify one in ::begin()\n"))); - return false; - } - - // continue to ensure interface is UP - } - - // check existence of this IP address in the interface list - bool found = false; - m_netif = nullptr; - for (auto a : addrList) - if (ipAddress == a.addr()) - { - if (a.ifUp()) - { - found = true; - m_netif = a.interface(); - break; - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] found interface for IP '%s' but it is not UP\n"), ipAddress.toString().c_str());); - } - if (!found) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] interface defined by IP '%s' not found\n"), ipAddress.toString().c_str());); - return false; - } - - //// done selecting the interface - - if (m_netif->num == STATION_IF) - { - - m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & pEvent) - { - (void) pEvent; - // Ensure that _restart() runs in USER context - schedule_function([this]() - { - MDNSResponder::_restart(); - }); - }); - - m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & pEvent) - { - (void) pEvent; - // Ensure that _restart() runs in USER context - schedule_function([this]() - { - MDNSResponder::_restart(); - }); - }); - } - - bResult = _restart(); - } - DEBUG_EX_ERR(if (!bResult) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: FAILED for '%s'!\n"), (p_pcHostname ? : "-")); - }); - } - else - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: Ignoring multiple calls to begin (Ignored host domain: '%s')!\n"), (p_pcHostname ? : "-"));); - } - return bResult; -} - -/* - MDNSResponder::close - - Ends the MDNS responder. - Announced services are unannounced (by multicasting a goodbye message) - -*/ -bool MDNSResponder::close(void) -{ - bool bResult = false; - - if (0 != m_pUDPContext) - { - m_GotIPHandler.reset(); // reset WiFi event callbacks. - m_DisconnectedHandler.reset(); - - _announce(false, true); - _resetProbeStatus(false); // Stop probing - _releaseServiceQueries(); - _releaseUDPContext(); - _releaseHostname(); - - bResult = true; - } - else - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] close: Ignoring call to close!\n"));); - } - return bResult; -} - -/* - MDNSResponder::end - - Ends the MDNS responder. - for compatibility with esp32 - -*/ - -bool MDNSResponder::end(void) -{ - return close(); -} - -/* - MDNSResponder::setHostname - - Replaces the current hostname and restarts probing. - For services without own instance name (when the host name was used a instance - name), the instance names are replaced also (and the probing is restarted). - -*/ -bool MDNSResponder::setHostname(const char* p_pcHostname) -{ - - bool bResult = false; - - if (_setHostname(p_pcHostname)) - { - m_HostProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; - - // Replace 'auto-set' service names - bResult = true; - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if (pService->m_bAutoName) - { - bResult = pService->setName(p_pcHostname); - pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; - } - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setHostname: FAILED for '%s'!\n"), (p_pcHostname ? : "-")); - }); - return bResult; -} - -/* - MDNSResponder::setHostname (LEGACY) -*/ -bool MDNSResponder::setHostname(const String& p_strHostname) -{ - - return setHostname(p_strHostname.c_str()); -} - - -/* - SERVICES -*/ - -/* - MDNSResponder::addService - - Add service; using hostname if no name is explicitly provided for the service - The usual '_' underline, which is prepended to service and protocol, eg. _http, - may be given. If not, it is added automatically. - -*/ -MDNSResponder::hMDNSService MDNSResponder::addService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port) -{ - - hMDNSService hResult = 0; - - if (((!p_pcName) || // NO name OR - (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcName))) && // Fitting name - (p_pcService) && - (MDNS_SERVICE_NAME_LENGTH >= os_strlen(p_pcService)) && - (p_pcProtocol) && - ((MDNS_SERVICE_PROTOCOL_LENGTH - 1) != os_strlen(p_pcProtocol)) && - (p_u16Port)) - { - - if (!_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol)) // Not already used - { - if (0 != (hResult = (hMDNSService)_allocService(p_pcName, p_pcService, p_pcProtocol, p_u16Port))) - { - - // Start probing - ((stcMDNSService*)hResult)->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; - } - } - } // else: bad arguments - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: %s to add '%s.%s.%s'!\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcName ? : "-"), p_pcService, p_pcProtocol);); - DEBUG_EX_ERR(if (!hResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: FAILED to add '%s.%s.%s'!\n"), (p_pcName ? : "-"), p_pcService, p_pcProtocol); - }); - return hResult; -} - -/* - MDNSResponder::removeService - - Unanounce a service (by sending a goodbye message) and remove it - from the MDNS responder - -*/ -bool MDNSResponder::removeService(const MDNSResponder::hMDNSService p_hService) -{ - - stcMDNSService* pService = 0; - bool bResult = (((pService = _findService(p_hService))) && - (_announceService(*pService, false)) && - (_releaseService(pService))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeService: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::removeService -*/ -bool MDNSResponder::removeService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol) -{ - - return removeService((hMDNSService)_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol)); -} - -/* - MDNSResponder::addService (LEGACY) -*/ -bool MDNSResponder::addService(const String& p_strService, - const String& p_strProtocol, - uint16_t p_u16Port) -{ - - return (0 != addService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str(), p_u16Port)); -} - -/* - MDNSResponder::setServiceName -*/ -bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSService p_hService, - const char* p_pcInstanceName) -{ - - stcMDNSService* pService = 0; - bool bResult = (((!p_pcInstanceName) || - (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcInstanceName))) && - ((pService = _findService(p_hService))) && - (pService->setName(p_pcInstanceName)) && - ((pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setServiceName: FAILED for '%s'!\n"), (p_pcInstanceName ? : "-")); - }); - return bResult; -} - -/* - SERVICE TXT -*/ - -/* - MDNSResponder::addServiceTxt - - Add a static service TXT item ('Key'='Value') to a service. - -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue) -{ - - hMDNSTxt hTxt = 0; - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - hTxt = (hMDNSTxt)_addServiceTxt(pService, p_pcKey, p_pcValue, false); - } - DEBUG_EX_ERR(if (!hTxt) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-")); - }); - return hTxt; -} - -/* - MDNSResponder::addServiceTxt (uint32_t) - - Formats: http://www.cplusplus.com/reference/cstdio/printf/ -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - char acBuffer[32]; *acBuffer = 0; - sprintf(acBuffer, "%u", p_u32Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (uint16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - char acBuffer[16]; *acBuffer = 0; - sprintf(acBuffer, "%hu", p_u16Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (uint8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - char acBuffer[8]; *acBuffer = 0; - sprintf(acBuffer, "%hhu", p_u8Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (int32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value) -{ - char acBuffer[32]; *acBuffer = 0; - sprintf(acBuffer, "%i", p_i32Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (int16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value) -{ - char acBuffer[16]; *acBuffer = 0; - sprintf(acBuffer, "%hi", p_i16Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addServiceTxt (int8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value) -{ - char acBuffer[8]; *acBuffer = 0; - sprintf(acBuffer, "%hhi", p_i8Value); - - return addServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::removeServiceTxt - - Remove a static service TXT item from a service. -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService, - const MDNSResponder::hMDNSTxt p_hTxt) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_hTxt); - if (pTxt) - { - bResult = _releaseServiceTxt(pService, pTxt); - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::removeServiceTxt -*/ -bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService, - const char* p_pcKey) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey); - if (pTxt) - { - bResult = _releaseServiceTxt(pService, pTxt); - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED for '%s'!\n"), (p_pcKey ? : "-")); - }); - return bResult; -} - -/* - MDNSResponder::removeServiceTxt -*/ -bool MDNSResponder::removeServiceTxt(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol); - if (pService) - { - stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey); - if (pTxt) - { - bResult = _releaseServiceTxt(pService, pTxt); - } - } - return bResult; -} - -/* - MDNSResponder::addServiceTxt (LEGACY) -*/ -bool MDNSResponder::addServiceTxt(const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey, - const char* p_pcValue) -{ - - return (0 != _addServiceTxt(_findService(m_pcHostname, p_pcService, p_pcProtocol), p_pcKey, p_pcValue, false)); -} - -/* - MDNSResponder::addServiceTxt (LEGACY) -*/ -bool MDNSResponder::addServiceTxt(const String& p_strService, - const String& p_strProtocol, - const String& p_strKey, - const String& p_strValue) -{ - - return (0 != _addServiceTxt(_findService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str()), p_strKey.c_str(), p_strValue.c_str(), false)); -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (global) - - Set a global callback for dynamic service TXT items. The callback is called, whenever - service TXT items are needed. - -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback) -{ - - m_fnServiceTxtCallback = p_fnCallback; - - return true; -} - -/* - MDNSResponder::setDynamicServiceTxtCallback (service specific) - - Set a service specific callback for dynamic service TXT items. The callback is called, whenever - service TXT items are needed for the given service. - -*/ -bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::hMDNSService p_hService, - MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - pService->m_fnTxtCallback = p_fnCallback; - - bResult = true; - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setDynamicServiceTxtCallback: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::addDynamicServiceTxt -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt (%s=%s)\n"), p_pcKey, p_pcValue);); - - hMDNSTxt hTxt = 0; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - hTxt = _addServiceTxt(pService, p_pcKey, p_pcValue, true); - } - DEBUG_EX_ERR(if (!hTxt) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-")); - }); - return hTxt; -} - -/* - MDNSResponder::addDynamicServiceTxt (uint32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value) -{ - - char acBuffer[32]; *acBuffer = 0; - sprintf(acBuffer, "%u", p_u32Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (uint16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value) -{ - - char acBuffer[16]; *acBuffer = 0; - sprintf(acBuffer, "%hu", p_u16Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (uint8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value) -{ - - char acBuffer[8]; *acBuffer = 0; - sprintf(acBuffer, "%hhu", p_u8Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (int32_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value) -{ - - char acBuffer[32]; *acBuffer = 0; - sprintf(acBuffer, "%i", p_i32Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (int16_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value) -{ - - char acBuffer[16]; *acBuffer = 0; - sprintf(acBuffer, "%hi", p_i16Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - -/* - MDNSResponder::addDynamicServiceTxt (int8_t) -*/ -MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value) -{ - - char acBuffer[8]; *acBuffer = 0; - sprintf(acBuffer, "%hhi", p_i8Value); - - return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); -} - - -/** - STATIC SERVICE QUERY (LEGACY) -*/ - -/* - MDNSResponder::queryService - - Perform a (blocking) static service query. - The arrived answers can be queried by calling: - - answerHostname (or 'hostname') - - answerIP (or 'IP') - - answerPort (or 'port') - -*/ -uint32_t MDNSResponder::queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) -{ - if (0 == m_pUDPContext) - { - // safeguard against misuse - return 0; - } - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService '%s.%s'\n"), p_pcService, p_pcProtocol);); - - uint32_t u32Result = 0; - - stcMDNSServiceQuery* pServiceQuery = 0; - if ((p_pcService) && - (os_strlen(p_pcService)) && - (p_pcProtocol) && - (os_strlen(p_pcProtocol)) && - (p_u16Timeout) && - (_removeLegacyServiceQuery()) && - ((pServiceQuery = _allocServiceQuery())) && - (_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain))) - { - - pServiceQuery->m_bLegacyQuery = true; - - if (_sendMDNSServiceQuery(*pServiceQuery)) - { - // Wait for answers to arrive - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: Waiting %u ms for answers...\n"), p_u16Timeout);); - delay(p_u16Timeout); - - // All answers should have arrived by now -> stop adding new answers - pServiceQuery->m_bAwaitingAnswers = false; - u32Result = pServiceQuery->answerCount(); - } - else // FAILED to send query - { - _removeServiceQuery(pServiceQuery); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: INVALID input data!\n"));); - } - return u32Result; -} - -/* - MDNSResponder::removeQuery - - Remove the last static service query (and all answers). - -*/ -bool MDNSResponder::removeQuery(void) -{ - - return _removeLegacyServiceQuery(); -} - -/* - MDNSResponder::queryService (LEGACY) -*/ -uint32_t MDNSResponder::queryService(const String& p_strService, - const String& p_strProtocol) -{ - - return queryService(p_strService.c_str(), p_strProtocol.c_str()); -} - -/* - MDNSResponder::answerHostname -*/ -const char* MDNSResponder::answerHostname(const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - - if ((pSQAnswer) && - (pSQAnswer->m_HostDomain.m_u16NameLength) && - (!pSQAnswer->m_pcHostDomain)) - { - - char* pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); - if (pcHostDomain) - { - pSQAnswer->m_HostDomain.c_str(pcHostDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::answerIP -*/ -IPAddress MDNSResponder::answerIP(const uint32_t p_u32AnswerIndex) -{ - - const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); - const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - const stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (((pSQAnswer) && (pSQAnswer->m_pIP4Addresses)) ? pSQAnswer->IP4AddressAtIndex(0) : 0); - return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress()); -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::answerIP6 -*/ -IPAddress MDNSResponder::answerIP6(const uint32_t p_u32AnswerIndex) -{ - - const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); - const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - const stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (((pSQAnswer) && (pSQAnswer->m_pIP6Addresses)) ? pSQAnswer->IP6AddressAtIndex(0) : 0); - return (pIP6Address ? pIP6Address->m_IPAddress : IP6Address()); -} -#endif - -/* - MDNSResponder::answerPort -*/ -uint16_t MDNSResponder::answerPort(const uint32_t p_u32AnswerIndex) -{ - - const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); - const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->m_u16Port : 0); -} - -/* - MDNSResponder::hostname (LEGACY) -*/ -String MDNSResponder::hostname(const uint32_t p_u32AnswerIndex) -{ - - return String(answerHostname(p_u32AnswerIndex)); -} - -/* - MDNSResponder::IP (LEGACY) -*/ -IPAddress MDNSResponder::IP(const uint32_t p_u32AnswerIndex) -{ - - return answerIP(p_u32AnswerIndex); -} - -/* - MDNSResponder::port (LEGACY) -*/ -uint16_t MDNSResponder::port(const uint32_t p_u32AnswerIndex) -{ - - return answerPort(p_u32AnswerIndex); -} - - -/** - DYNAMIC SERVICE QUERY -*/ - -/* - MDNSResponder::installServiceQuery - - Add a dynamic service query and a corresponding callback to the MDNS responder. - The callback will be called for every answer update. - The answers can also be queried by calling: - - answerServiceDomain - - answerHostDomain - - answerIP4Address/answerIP6Address - - answerPort - - answerTxts - -*/ -MDNSResponder::hMDNSServiceQuery MDNSResponder::installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSResponder::MDNSServiceQueryCallbackFunc p_fnCallback) -{ - hMDNSServiceQuery hResult = 0; - - stcMDNSServiceQuery* pServiceQuery = 0; - if ((p_pcService) && - (os_strlen(p_pcService)) && - (p_pcProtocol) && - (os_strlen(p_pcProtocol)) && - (p_fnCallback) && - ((pServiceQuery = _allocServiceQuery())) && - (_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain))) - { - - pServiceQuery->m_fnCallback = p_fnCallback; - pServiceQuery->m_bLegacyQuery = false; - - if (_sendMDNSServiceQuery(*pServiceQuery)) - { - pServiceQuery->m_u8SentCount = 1; - pServiceQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); - - hResult = (hMDNSServiceQuery)pServiceQuery; - } - else - { - _removeServiceQuery(pServiceQuery); - } - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: %s for '%s.%s'!\n\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - DEBUG_EX_ERR(if (!hResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: FAILED for '%s.%s'!\n\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-")); - }); - return hResult; -} - -/* - MDNSResponder::removeServiceQuery - - Remove a dynamic service query (and all collected answers) from the MDNS responder - -*/ -bool MDNSResponder::removeServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) -{ - - stcMDNSServiceQuery* pServiceQuery = 0; - bool bResult = (((pServiceQuery = _findServiceQuery(p_hServiceQuery))) && - (_removeServiceQuery(pServiceQuery))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceQuery: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::answerCount -*/ -uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - return (pServiceQuery ? pServiceQuery->answerCount() : 0); -} - -std::vector MDNSResponder::answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery) -{ - std::vector tempVector; - for (uint32_t i = 0; i < answerCount(p_hServiceQuery); i++) - { - tempVector.emplace_back(*this, p_hServiceQuery, i); - } - return tempVector; -} - -/* - MDNSResponder::answerServiceDomain - - Returns the domain for the given service. - If not already existing, the string is allocated, filled and attached to the answer. - -*/ -const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcServiceDomain (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_ServiceDomain.m_u16NameLength) && - (!pSQAnswer->m_pcServiceDomain)) - { - - pSQAnswer->m_pcServiceDomain = pSQAnswer->allocServiceDomain(pSQAnswer->m_ServiceDomain.c_strLength()); - if (pSQAnswer->m_pcServiceDomain) - { - pSQAnswer->m_ServiceDomain.c_str(pSQAnswer->m_pcServiceDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcServiceDomain : 0); -} - -/* - MDNSResponder::hasAnswerHostDomain -*/ -bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort)); -} - -/* - MDNSResponder::answerHostDomain - - Returns the host domain for the given service. - If not already existing, the string is allocated, filled and attached to the answer. - -*/ -const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcHostDomain (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_HostDomain.m_u16NameLength) && - (!pSQAnswer->m_pcHostDomain)) - { - - pSQAnswer->m_pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); - if (pSQAnswer->m_pcHostDomain) - { - pSQAnswer->m_HostDomain.c_str(pSQAnswer->m_pcHostDomain); - } - } - return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::hasAnswerIP4Address -*/ -bool MDNSResponder::hasAnswerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_IP4Address)); -} - -/* - MDNSResponder::answerIP4AddressCount -*/ -uint32_t MDNSResponder::answerIP4AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->IP4AddressCount() : 0); -} - -/* - MDNSResponder::answerIP4Address -*/ -IPAddress MDNSResponder::answerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (pSQAnswer ? pSQAnswer->IP4AddressAtIndex(p_u32AddressIndex) : 0); - return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress()); -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::hasAnswerIP6Address -*/ -bool MDNSResponder::hasAnswerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostIP6Address)); -} - -/* - MDNSResponder::answerIP6AddressCount -*/ -uint32_t MDNSResponder::answerIP6AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->IP6AddressCount() : 0); -} - -/* - MDNSResponder::answerIP6Address -*/ -IPAddress MDNSResponder::answerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (pSQAnswer ? pSQAnswer->IP6AddressAtIndex(p_u32AddressIndex) : 0); - return (pIP6Address ? pIP6Address->m_IPAddress : IPAddress()); -} -#endif - -/* - MDNSResponder::hasAnswerPort -*/ -bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort)); -} - -/* - MDNSResponder::answerPort -*/ -uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return (pSQAnswer ? pSQAnswer->m_u16Port : 0); -} - -/* - MDNSResponder::hasAnswerTxts -*/ -bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - return ((pSQAnswer) && - (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_Txts)); -} - -/* - MDNSResponder::answerTxts - - Returns all TXT items for the given service as a ';'-separated string. - If not already existing; the string is alloced, filled and attached to the answer. - -*/ -const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcTxts (if not already done) - if ((pSQAnswer) && - (pSQAnswer->m_Txts.m_pTxts) && - (!pSQAnswer->m_pcTxts)) - { - - pSQAnswer->m_pcTxts = pSQAnswer->allocTxts(pSQAnswer->m_Txts.c_strLength()); - if (pSQAnswer->m_pcTxts) - { - pSQAnswer->m_Txts.c_str(pSQAnswer->m_pcTxts); - } - } - return (pSQAnswer ? pSQAnswer->m_pcTxts : 0); -} - -/* - PROBING -*/ - -/* - MDNSResponder::setProbeResultCallback - - Set a global callback for probe results. The callback is called, when probing - for the host domain (or a service domain, without specific probe result callback) - failes or succeedes. - In the case of failure, the domain name should be changed via 'setHostname' or 'setServiceName'. - When succeeded, the host or service domain will be announced by the MDNS responder. - -*/ -bool MDNSResponder::setHostProbeResultCallback(MDNSResponder::MDNSHostProbeFn p_fnCallback) -{ - - m_HostProbeInformation.m_fnHostProbeResultCallback = p_fnCallback; - - return true; -} - -bool MDNSResponder::setHostProbeResultCallback(MDNSHostProbeFn1 pfn) -{ - using namespace std::placeholders; - return setHostProbeResultCallback([this, pfn](const char* p_pcDomainName, bool p_bProbeResult) - { - pfn(*this, p_pcDomainName, p_bProbeResult); - }); -} - -/* - MDNSResponder::setServiceProbeResultCallback - - Set a service specific callback for probe results. The callback is called, when probing - for the service domain failes or succeedes. - In the case of failure, the service name should be changed via 'setServiceName'. - When succeeded, the service domain will be announced by the MDNS responder. - -*/ -bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, - MDNSResponder::MDNSServiceProbeFn p_fnCallback) -{ - - bool bResult = false; - - stcMDNSService* pService = _findService(p_hService); - if (pService) - { - pService->m_ProbeInformation.m_fnServiceProbeResultCallback = p_fnCallback; - - bResult = true; - } - return bResult; -} - -bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, - MDNSResponder::MDNSServiceProbeFn1 p_fnCallback) -{ - using namespace std::placeholders; - return setServiceProbeResultCallback(p_hService, [this, p_fnCallback](const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) - { - p_fnCallback(*this, p_pcServiceName, p_hMDNSService, p_bProbeResult); - }); -} - - -/* - MISC -*/ - -/* - MDNSResponder::notifyAPChange - - Should be called, whenever the AP for the MDNS responder changes. - A bit of this is caught by the event callbacks installed in the constructor. - -*/ -bool MDNSResponder::notifyAPChange(void) -{ - - return _restart(); -} - -/* - MDNSResponder::update - - Should be called in every 'loop'. - -*/ -bool MDNSResponder::update(void) -{ - - if (m_bPassivModeEnabled) - { - m_bPassivModeEnabled = false; - } - return _process(true); -} - -/* - MDNSResponder::announce - - Should be called, if the 'configuration' changes. Mainly this will be changes in the TXT items... -*/ -bool MDNSResponder::announce(void) -{ - - return (_announce(true, true)); -} - -/* - MDNSResponder::enableArduino - - Enable the OTA update service. - -*/ -MDNSResponder::hMDNSService MDNSResponder::enableArduino(uint16_t p_u16Port, - bool p_bAuthUpload /*= false*/) -{ - - hMDNSService hService = addService(0, "arduino", "tcp", p_u16Port); - if (hService) - { - if ((!addServiceTxt(hService, "tcp_check", "no")) || - (!addServiceTxt(hService, "ssh_upload", "no")) || - (!addServiceTxt(hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) || - (!addServiceTxt(hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) - { - - removeService(hService); - hService = 0; - } - } - return hService; -} - - -} //namespace MDNSImplementation - -} //namespace esp8266 - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h deleted file mode 100644 index fe02560aec..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS.h +++ /dev/null @@ -1,1461 +0,0 @@ -/* - LEAmDNS.h - (c) 2018, LaborEtArs - - Version 0.9 beta - - Some notes (from LaborEtArs, 2018): - Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS). - The target of this rewrite was to keep the existing interface as stable as possible while - adding and extending the supported set of mDNS features. - A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code. - - Supported mDNS features (in some cases somewhat limited): - - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service - - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented - - Probing host and service domains for uniqueness in the local network - - Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak) - - Announcing available services after successful probing - - Using fixed service TXT items or - - Using dynamic service TXT items for presented services (via callback) - - Remove services (and un-announcing them to the observers by sending goodbye-messages) - - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) - - Dynamic queries for DNS-SD services with cached and updated answers and user notifications - - - Usage: - In most cases, this implementation should work as a 'drop-in' replacement for the original - ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some - of the new features should be used. - - For presenting services: - In 'setup()': - Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);' - Register DNS-SD services with 'MDNSResponder::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);' - (Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);') - Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback - using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific - 'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);' - Call MDNS.begin("MyHostname"); - - In 'probeResultCallback(MDNSResponder* p_MDNSResponder, const char* p_pcDomain, MDNSResponder:hMDNSService p_hService, bool p_bProbeResult, void* p_pUserdata)': - Check the probe result and update the host or service domain name if the probe failed - - In 'dynamicServiceTxtCallback(MDNSResponder* p_MDNSResponder, const hMDNSService p_hService, void* p_pUserdata)': - Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hService, "c#", "1");' - - In loop(): - Call 'MDNS.update();' - - - For querying services: - Static: - Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");' - Iterate answers by: 'for (uint32_t u=0; u // for UdpContext.h -#include "WiFiUdp.h" -#include "lwip/udp.h" -#include "debug.h" -#include "include/UdpContext.h" -#include -#include -#include - - -#include "ESP8266WiFi.h" - - -namespace esp8266 -{ - -/** - LEAmDNS -*/ -namespace MDNSImplementation -{ - -//this should be defined at build time -#ifndef ARDUINO_BOARD -#define ARDUINO_BOARD "generic" -#endif - -#define MDNS_IP4_SUPPORT -//#define MDNS_IP6_SUPPORT - - -#ifdef MDNS_IP4_SUPPORT -#define MDNS_IP4_SIZE 4 -#endif -#ifdef MDNS_IP6_SUPPORT -#define MDNS_IP6_SIZE 16 -#endif -/* - Maximum length for all service txts for one service -*/ -#define MDNS_SERVICE_TXT_MAXLENGTH 1300 -/* - Maximum length for a full domain name eg. MyESP._http._tcp.local -*/ -#define MDNS_DOMAIN_MAXLENGTH 256 -/* - Maximum length of on label in a domain name (length info fits into 6 bits) -*/ -#define MDNS_DOMAIN_LABEL_MAXLENGTH 63 -/* - Maximum length of a service name eg. http -*/ -#define MDNS_SERVICE_NAME_LENGTH 15 -/* - Maximum length of a service protocol name eg. tcp -*/ -#define MDNS_SERVICE_PROTOCOL_LENGTH 3 -/* - Default timeout for static service queries -*/ -#define MDNS_QUERYSERVICES_WAIT_TIME 1000 - - -/** - MDNSResponder -*/ -class MDNSResponder -{ -public: - /* INTERFACE */ - MDNSResponder(void); - virtual ~MDNSResponder(void); - - // Start the MDNS responder by setting the default hostname - // Later call MDNS::update() in every 'loop' to run the process loop - // (probing, announcing, responding, ...) - // if interfaceAddress is not specified, default interface is STA, or AP when STA is not set - bool begin(const char* p_pcHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/); - bool begin(const String& p_strHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/) - { - return begin(p_strHostname.c_str(), p_IPAddress, p_u32TTL); - } - - // Finish MDNS processing - bool close(void); - // for esp32 compatability - bool end(void); - // Change hostname (probing is restarted) - bool setHostname(const char* p_pcHostname); - // for compatibility... - bool setHostname(const String& p_strHostname); - - bool isRunning(void) - { - return (m_pUDPContext != 0); - } - - /** - hMDNSService (opaque handle to access the service) - */ - typedef const void* hMDNSService; - - // Add a new service to the MDNS responder. If no name (instance name) is given (p_pcName = 0) - // the current hostname is used. If the hostname is changed later, the instance names for - // these 'auto-named' services are changed to the new name also (and probing is restarted). - // The usual '_' before p_pcService (eg. http) and protocol (eg. tcp) may be given. - hMDNSService addService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port); - // Removes a service from the MDNS responder - bool removeService(const hMDNSService p_hService); - bool removeService(const char* p_pcInstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol); - // for compatibility... - bool addService(const String& p_strServiceName, - const String& p_strProtocol, - uint16_t p_u16Port); - - - // Change the services instance name (and restart probing). - bool setServiceName(const hMDNSService p_hService, - const char* p_pcInstanceName); - //for compatibility - //Warning: this has the side effect of changing the hostname. - //TODO: implement instancename different from hostname - void setInstanceName(const char* p_pcHostname) - { - setHostname(p_pcHostname); - } - // for esp32 compatibilty - void setInstanceName(const String& s_pcHostname) - { - setInstanceName(s_pcHostname.c_str()); - } - - /** - hMDNSTxt (opaque handle to access the TXT items) - */ - typedef void* hMDNSTxt; - - // Add a (static) MDNS TXT item ('key' = 'value') to the service - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addServiceTxt(const hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value); - - // Remove an existing (static) MDNS TXT item from the service - bool removeServiceTxt(const hMDNSService p_hService, - const hMDNSTxt p_hTxt); - bool removeServiceTxt(const hMDNSService p_hService, - const char* p_pcKey); - bool removeServiceTxt(const char* p_pcinstanceName, - const char* p_pcServiceName, - const char* p_pcProtocol, - const char* p_pcKey); - // for compatibility... - bool addServiceTxt(const char* p_pcService, - const char* p_pcProtocol, - const char* p_pcKey, - const char* p_pcValue); - bool addServiceTxt(const String& p_strService, - const String& p_strProtocol, - const String& p_strKey, - const String& p_strValue); - - /** - MDNSDynamicServiceTxtCallbackFn - Callback function for dynamic MDNS TXT items - */ - - typedef std::function MDNSDynamicServiceTxtCallbackFunc; - - // Set a global callback for dynamic MDNS TXT items. The callback function is called - // every time, a TXT item is needed for one of the installed services. - bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFunc p_fnCallback); - // Set a service specific callback for dynamic MDNS TXT items. The callback function - // is called every time, a TXT item is needed for the given service. - bool setDynamicServiceTxtCallback(const hMDNSService p_hService, - MDNSDynamicServiceTxtCallbackFunc p_fnCallback); - - // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service - // Dynamic TXT items are removed right after one-time use. So they need to be added - // every time the value s needed (via callback). - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - const char* p_pcValue); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint32_t p_u32Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint16_t p_u16Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - uint8_t p_u8Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int32_t p_i32Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int16_t p_i16Value); - hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, - const char* p_pcKey, - int8_t p_i8Value); - - // Perform a (static) service query. The function returns after p_u16Timeout milliseconds - // The answers (the number of received answers is returned) can be retrieved by calling - // - answerHostname (or hostname) - // - answerIP (or IP) - // - answerPort (or port) - uint32_t queryService(const char* p_pcService, - const char* p_pcProtocol, - const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); - bool removeQuery(void); - // for compatibility... - uint32_t queryService(const String& p_strService, - const String& p_strProtocol); - - const char* answerHostname(const uint32_t p_u32AnswerIndex); - IPAddress answerIP(const uint32_t p_u32AnswerIndex); - uint16_t answerPort(const uint32_t p_u32AnswerIndex); - // for compatibility... - String hostname(const uint32_t p_u32AnswerIndex); - IPAddress IP(const uint32_t p_u32AnswerIndex); - uint16_t port(const uint32_t p_u32AnswerIndex); - - /** - hMDNSServiceQuery (opaque handle to access dynamic service queries) - */ - typedef const void* hMDNSServiceQuery; - - /** - enuServiceQueryAnswerType - */ - typedef enum _enuServiceQueryAnswerType - { - ServiceQueryAnswerType_ServiceDomain = (1 << 0), // Service instance name - ServiceQueryAnswerType_HostDomainAndPort = (1 << 1), // Host domain and service port - ServiceQueryAnswerType_Txts = (1 << 2), // TXT items -#ifdef MDNS_IP4_SUPPORT - ServiceQueryAnswerType_IP4Address = (1 << 3), // IP4 address -#endif -#ifdef MDNS_IP6_SUPPORT - ServiceQueryAnswerType_IP6Address = (1 << 4), // IP6 address -#endif - } enuServiceQueryAnswerType; - - enum class AnswerType : uint32_t - { - Unknown = 0, - ServiceDomain = ServiceQueryAnswerType_ServiceDomain, - HostDomainAndPort = ServiceQueryAnswerType_HostDomainAndPort, - Txt = ServiceQueryAnswerType_Txts, -#ifdef MDNS_IP4_SUPPORT - IP4Address = ServiceQueryAnswerType_IP4Address, -#endif -#ifdef MDNS_IP6_SUPPORT - IP6Address = ServiceQueryAnswerType_IP6Address, -#endif - }; - - /** - MDNSServiceQueryCallbackFn - Callback function for received answers for dynamic service queries - */ - struct MDNSServiceInfo; // forward declaration - typedef std::function MDNSServiceQueryCallbackFunc; - - // Install a dynamic service query. For every received answer (part) the given callback - // function is called. The query will be updated every time, the TTL for an answer - // has timed-out. - // The answers can also be retrieved by calling - // - answerCount - // - answerServiceDomain - // - hasAnswerHostDomain/answerHostDomain - // - hasAnswerIP4Address/answerIP4Address - // - hasAnswerIP6Address/answerIP6Address - // - hasAnswerPort/answerPort - // - hasAnswerTxts/answerTxts - hMDNSServiceQuery installServiceQuery(const char* p_pcService, - const char* p_pcProtocol, - MDNSServiceQueryCallbackFunc p_fnCallback); - // Remove a dynamic service query - bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery); - - uint32_t answerCount(const hMDNSServiceQuery p_hServiceQuery); - std::vector answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery); - - const char* answerServiceDomain(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerHostDomain(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - const char* answerHostDomain(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); -#ifdef MDNS_IP4_SUPPORT - bool hasAnswerIP4Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIP4AddressCount(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIP4Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); -#endif -#ifdef MDNS_IP6_SUPPORT - bool hasAnswerIP6Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - uint32_t answerIP6AddressCount(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - IPAddress answerIP6Address(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex, - const uint32_t p_u32AddressIndex); -#endif - bool hasAnswerPort(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - uint16_t answerPort(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - bool hasAnswerTxts(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - // Get the TXT items as a ';'-separated string - const char* answerTxts(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - - /** - MDNSProbeResultCallbackFn - Callback function for (host and service domain) probe results - */ - typedef std::function MDNSHostProbeFn; - - typedef std::function MDNSHostProbeFn1; - - typedef std::function MDNSServiceProbeFn; - - typedef std::function MDNSServiceProbeFn1; - - // Set a global callback function for host and service probe results - // The callback function is called, when the probing for the host domain - // (or a service domain, which hasn't got a service specific callback) - // Succeeds or fails. - // In case of failure, the failed domain name should be changed. - bool setHostProbeResultCallback(MDNSHostProbeFn p_fnCallback); - bool setHostProbeResultCallback(MDNSHostProbeFn1 p_fnCallback); - - // Set a service specific probe result callback - bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, - MDNSServiceProbeFn p_fnCallback); - bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, - MDNSServiceProbeFn1 p_fnCallback); - - // Application should call this whenever AP is configured/disabled - bool notifyAPChange(void); - - // 'update' should be called in every 'loop' to run the MDNS processing - bool update(void); - - // 'announce' can be called every time, the configuration of some service - // changes. Mainly, this would be changed content of TXT items. - bool announce(void); - - // Enable OTA update - hMDNSService enableArduino(uint16_t p_u16Port, - bool p_bAuthUpload = false); - - // Domain name helper - static bool indexDomain(char*& p_rpcDomain, - const char* p_pcDivider = "-", - const char* p_pcDefaultDomain = 0); - - /** STRUCTS **/ - -public: - /** - MDNSServiceInfo, used in application callbacks - */ - struct MDNSServiceInfo - { - MDNSServiceInfo(MDNSResponder& p_pM, MDNSResponder::hMDNSServiceQuery p_hS, uint32_t p_u32A) - : p_pMDNSResponder(p_pM), - p_hServiceQuery(p_hS), - p_u32AnswerIndex(p_u32A) - {}; - struct CompareKey - { - bool operator()(char const *a, char const *b) const - { - return strcmp(a, b) < 0; - } - }; - using KeyValueMap = std::map; - protected: - MDNSResponder& p_pMDNSResponder; - MDNSResponder::hMDNSServiceQuery p_hServiceQuery; - uint32_t p_u32AnswerIndex; - KeyValueMap keyValueMap; - public: - const char* serviceDomain() - { - return p_pMDNSResponder.answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex); - }; - bool hostDomainAvailable() - { - return (p_pMDNSResponder.hasAnswerHostDomain(p_hServiceQuery, p_u32AnswerIndex)); - } - const char* hostDomain() - { - return (hostDomainAvailable()) ? - p_pMDNSResponder.answerHostDomain(p_hServiceQuery, p_u32AnswerIndex) : nullptr; - }; - bool hostPortAvailable() - { - return (p_pMDNSResponder.hasAnswerPort(p_hServiceQuery, p_u32AnswerIndex)); - } - uint16_t hostPort() - { - return (hostPortAvailable()) ? - p_pMDNSResponder.answerPort(p_hServiceQuery, p_u32AnswerIndex) : 0; - }; - bool IP4AddressAvailable() - { - return (p_pMDNSResponder.hasAnswerIP4Address(p_hServiceQuery, p_u32AnswerIndex)); - } - std::vector IP4Adresses() - { - std::vector internalIP; - if (IP4AddressAvailable()) - { - uint16_t cntIP4Adress = p_pMDNSResponder.answerIP4AddressCount(p_hServiceQuery, p_u32AnswerIndex); - for (uint32_t u2 = 0; u2 < cntIP4Adress; ++u2) - { - internalIP.emplace_back(p_pMDNSResponder.answerIP4Address(p_hServiceQuery, p_u32AnswerIndex, u2)); - } - } - return internalIP; - }; - bool txtAvailable() - { - return (p_pMDNSResponder.hasAnswerTxts(p_hServiceQuery, p_u32AnswerIndex)); - } - const char* strKeyValue() - { - return (txtAvailable()) ? - p_pMDNSResponder.answerTxts(p_hServiceQuery, p_u32AnswerIndex) : nullptr; - }; - const KeyValueMap& keyValues() - { - if (txtAvailable() && keyValueMap.size() == 0) - { - for (auto kv = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); kv != nullptr; kv = kv->m_pNext) - { - keyValueMap.emplace(std::pair(kv->m_pcKey, kv->m_pcValue)); - } - } - return keyValueMap; - } - const char* value(const char* key) - { - char* result = nullptr; - - for (stcMDNSServiceTxt* pTxt = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); pTxt; pTxt = pTxt->m_pNext) - { - if ((key) && - (0 == strcmp(pTxt->m_pcKey, key))) - { - result = pTxt->m_pcValue; - break; - } - } - return result; - } - }; -protected: - - /** - stcMDNSServiceTxt - */ - struct stcMDNSServiceTxt - { - stcMDNSServiceTxt* m_pNext; - char* m_pcKey; - char* m_pcValue; - bool m_bTemp; - - stcMDNSServiceTxt(const char* p_pcKey = 0, - const char* p_pcValue = 0, - bool p_bTemp = false); - stcMDNSServiceTxt(const stcMDNSServiceTxt& p_Other); - ~stcMDNSServiceTxt(void); - - stcMDNSServiceTxt& operator=(const stcMDNSServiceTxt& p_Other); - bool clear(void); - - char* allocKey(size_t p_stLength); - bool setKey(const char* p_pcKey, - size_t p_stLength); - bool setKey(const char* p_pcKey); - bool releaseKey(void); - - char* allocValue(size_t p_stLength); - bool setValue(const char* p_pcValue, - size_t p_stLength); - bool setValue(const char* p_pcValue); - bool releaseValue(void); - - bool set(const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp = false); - - bool update(const char* p_pcValue); - - size_t length(void) const; - }; - - /** - stcMDNSTxts - */ - struct stcMDNSServiceTxts - { - stcMDNSServiceTxt* m_pTxts; - - stcMDNSServiceTxts(void); - stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other); - ~stcMDNSServiceTxts(void); - - stcMDNSServiceTxts& operator=(const stcMDNSServiceTxts& p_Other); - - bool clear(void); - - bool add(stcMDNSServiceTxt* p_pTxt); - bool remove(stcMDNSServiceTxt* p_pTxt); - - bool removeTempTxts(void); - - stcMDNSServiceTxt* find(const char* p_pcKey); - const stcMDNSServiceTxt* find(const char* p_pcKey) const; - stcMDNSServiceTxt* find(const stcMDNSServiceTxt* p_pTxt); - - uint16_t length(void) const; - - size_t c_strLength(void) const; - bool c_str(char* p_pcBuffer); - - size_t bufferLength(void) const; - bool buffer(char* p_pcBuffer); - - bool compare(const stcMDNSServiceTxts& p_Other) const; - bool operator==(const stcMDNSServiceTxts& p_Other) const; - bool operator!=(const stcMDNSServiceTxts& p_Other) const; - }; - - /** - enuContentFlags - */ - typedef enum _enuContentFlags - { - // Host - ContentFlag_A = 0x01, - ContentFlag_PTR_IP4 = 0x02, - ContentFlag_PTR_IP6 = 0x04, - ContentFlag_AAAA = 0x08, - // Service - ContentFlag_PTR_TYPE = 0x10, - ContentFlag_PTR_NAME = 0x20, - ContentFlag_TXT = 0x40, - ContentFlag_SRV = 0x80, - } enuContentFlags; - - /** - stcMDNS_MsgHeader - */ - struct stcMDNS_MsgHeader - { - uint16_t m_u16ID; // Identifier - bool m_1bQR : 1; // Query/Response flag - unsigned char m_4bOpcode : 4; // Operation code - bool m_1bAA : 1; // Authoritative Answer flag - bool m_1bTC : 1; // Truncation flag - bool m_1bRD : 1; // Recursion desired - bool m_1bRA : 1; // Recursion available - unsigned char m_3bZ : 3; // Zero - unsigned char m_4bRCode : 4; // Response code - uint16_t m_u16QDCount; // Question count - uint16_t m_u16ANCount; // Answer count - uint16_t m_u16NSCount; // Authority Record count - uint16_t m_u16ARCount; // Additional Record count - - stcMDNS_MsgHeader(uint16_t p_u16ID = 0, - bool p_bQR = false, - unsigned char p_ucOpcode = 0, - bool p_bAA = false, - bool p_bTC = false, - bool p_bRD = false, - bool p_bRA = false, - unsigned char p_ucRCode = 0, - uint16_t p_u16QDCount = 0, - uint16_t p_u16ANCount = 0, - uint16_t p_u16NSCount = 0, - uint16_t p_u16ARCount = 0); - }; - - /** - stcMDNS_RRDomain - */ - struct stcMDNS_RRDomain - { - char m_acName[MDNS_DOMAIN_MAXLENGTH]; // Encoded domain name - uint16_t m_u16NameLength; // Length (incl. '\0') - - stcMDNS_RRDomain(void); - stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other); - - stcMDNS_RRDomain& operator=(const stcMDNS_RRDomain& p_Other); - - bool clear(void); - - bool addLabel(const char* p_pcLabel, - bool p_bPrependUnderline = false); - - bool compare(const stcMDNS_RRDomain& p_Other) const; - bool operator==(const stcMDNS_RRDomain& p_Other) const; - bool operator!=(const stcMDNS_RRDomain& p_Other) const; - bool operator>(const stcMDNS_RRDomain& p_Other) const; - - size_t c_strLength(void) const; - bool c_str(char* p_pcBuffer); - }; - - /** - stcMDNS_RRAttributes - */ - struct stcMDNS_RRAttributes - { - uint16_t m_u16Type; // Type - uint16_t m_u16Class; // Class, nearly always 'IN' - - stcMDNS_RRAttributes(uint16_t p_u16Type = 0, - uint16_t p_u16Class = 1 /*DNS_RRCLASS_IN Internet*/); - stcMDNS_RRAttributes(const stcMDNS_RRAttributes& p_Other); - - stcMDNS_RRAttributes& operator=(const stcMDNS_RRAttributes& p_Other); - }; - - /** - stcMDNS_RRHeader - */ - struct stcMDNS_RRHeader - { - stcMDNS_RRDomain m_Domain; - stcMDNS_RRAttributes m_Attributes; - - stcMDNS_RRHeader(void); - stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other); - - stcMDNS_RRHeader& operator=(const stcMDNS_RRHeader& p_Other); - - bool clear(void); - }; - - /** - stcMDNS_RRQuestion - */ - struct stcMDNS_RRQuestion - { - stcMDNS_RRQuestion* m_pNext; - stcMDNS_RRHeader m_Header; - bool m_bUnicast; // Unicast reply requested - - stcMDNS_RRQuestion(void); - }; - - /** - enuAnswerType - */ - typedef enum _enuAnswerType - { - AnswerType_A, - AnswerType_PTR, - AnswerType_TXT, - AnswerType_AAAA, - AnswerType_SRV, - AnswerType_Generic - } enuAnswerType; - - /** - stcMDNS_RRAnswer - */ - struct stcMDNS_RRAnswer - { - stcMDNS_RRAnswer* m_pNext; - const enuAnswerType m_AnswerType; - stcMDNS_RRHeader m_Header; - bool m_bCacheFlush; // Cache flush command bit - uint32_t m_u32TTL; // Validity time in seconds - - virtual ~stcMDNS_RRAnswer(void); - - enuAnswerType answerType(void) const; - - bool clear(void); - - protected: - stcMDNS_RRAnswer(enuAnswerType p_AnswerType, - const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - }; - -#ifdef MDNS_IP4_SUPPORT - /** - stcMDNS_RRAnswerA - */ - struct stcMDNS_RRAnswerA : public stcMDNS_RRAnswer - { - IPAddress m_IPAddress; - - stcMDNS_RRAnswerA(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerA(void); - - bool clear(void); - }; -#endif - - /** - stcMDNS_RRAnswerPTR - */ - struct stcMDNS_RRAnswerPTR : public stcMDNS_RRAnswer - { - stcMDNS_RRDomain m_PTRDomain; - - stcMDNS_RRAnswerPTR(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerPTR(void); - - bool clear(void); - }; - - /** - stcMDNS_RRAnswerTXT - */ - struct stcMDNS_RRAnswerTXT : public stcMDNS_RRAnswer - { - stcMDNSServiceTxts m_Txts; - - stcMDNS_RRAnswerTXT(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerTXT(void); - - bool clear(void); - }; - -#ifdef MDNS_IP6_SUPPORT - /** - stcMDNS_RRAnswerAAAA - */ - struct stcMDNS_RRAnswerAAAA : public stcMDNS_RRAnswer - { - //TODO: IP6Address m_IPAddress; - - stcMDNS_RRAnswerAAAA(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerAAAA(void); - - bool clear(void); - }; -#endif - - /** - stcMDNS_RRAnswerSRV - */ - struct stcMDNS_RRAnswerSRV : public stcMDNS_RRAnswer - { - uint16_t m_u16Priority; - uint16_t m_u16Weight; - uint16_t m_u16Port; - stcMDNS_RRDomain m_SRVDomain; - - stcMDNS_RRAnswerSRV(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerSRV(void); - - bool clear(void); - }; - - /** - stcMDNS_RRAnswerGeneric - */ - struct stcMDNS_RRAnswerGeneric : public stcMDNS_RRAnswer - { - uint16_t m_u16RDLength; // Length of variable answer - uint8_t* m_pu8RDData; // Offset of start of variable answer in packet - - stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL); - ~stcMDNS_RRAnswerGeneric(void); - - bool clear(void); - }; - - - /** - enuProbingStatus - */ - typedef enum _enuProbingStatus - { - ProbingStatus_WaitingForData, - ProbingStatus_ReadyToStart, - ProbingStatus_InProgress, - ProbingStatus_Done - } enuProbingStatus; - - /** - stcProbeInformation - */ - struct stcProbeInformation - { - enuProbingStatus m_ProbingStatus; - uint8_t m_u8SentCount; // Used for probes and announcements - esp8266::polledTimeout::oneShotMs m_Timeout; // Used for probes and announcements - //clsMDNSTimeFlag m_TimeFlag; // Used for probes and announcements - bool m_bConflict; - bool m_bTiebreakNeeded; - MDNSHostProbeFn m_fnHostProbeResultCallback; - MDNSServiceProbeFn m_fnServiceProbeResultCallback; - - stcProbeInformation(void); - - bool clear(bool p_bClearUserdata = false); - }; - - - /** - stcMDNSService - */ - struct stcMDNSService - { - stcMDNSService* m_pNext; - char* m_pcName; - bool m_bAutoName; // Name was set automatically to hostname (if no name was supplied) - char* m_pcService; - char* m_pcProtocol; - uint16_t m_u16Port; - uint8_t m_u8ReplyMask; - stcMDNSServiceTxts m_Txts; - MDNSDynamicServiceTxtCallbackFunc m_fnTxtCallback; - stcProbeInformation m_ProbeInformation; - - stcMDNSService(const char* p_pcName = 0, - const char* p_pcService = 0, - const char* p_pcProtocol = 0); - ~stcMDNSService(void); - - bool setName(const char* p_pcName); - bool releaseName(void); - - bool setService(const char* p_pcService); - bool releaseService(void); - - bool setProtocol(const char* p_pcProtocol); - bool releaseProtocol(void); - }; - - /** - stcMDNSServiceQuery - */ - struct stcMDNSServiceQuery - { - /** - stcAnswer - */ - struct stcAnswer - { - /** - stcTTL - */ - struct stcTTL - { - /** - timeoutLevel_t - */ - typedef uint8_t timeoutLevel_t; - /** - TIMEOUTLEVELs - */ - const timeoutLevel_t TIMEOUTLEVEL_UNSET = 0; - const timeoutLevel_t TIMEOUTLEVEL_BASE = 80; - const timeoutLevel_t TIMEOUTLEVEL_INTERVAL = 5; - const timeoutLevel_t TIMEOUTLEVEL_FINAL = 100; - - uint32_t m_u32TTL; - esp8266::polledTimeout::oneShotMs m_TTLTimeout; - timeoutLevel_t m_timeoutLevel; - - stcTTL(void); - bool set(uint32_t p_u32TTL); - - bool flagged(void); - bool restart(void); - - bool prepareDeletion(void); - bool finalTimeoutLevel(void) const; - - unsigned long timeout(void) const; - }; -#ifdef MDNS_IP4_SUPPORT - /** - stcIP4Address - */ - struct stcIP4Address - { - stcIP4Address* m_pNext; - IPAddress m_IPAddress; - stcTTL m_TTL; - - stcIP4Address(IPAddress p_IPAddress, - uint32_t p_u32TTL = 0); - }; -#endif -#ifdef MDNS_IP6_SUPPORT - /** - stcIP6Address - */ - struct stcIP6Address - { - stcIP6Address* m_pNext; - IP6Address m_IPAddress; - stcTTL m_TTL; - - stcIP6Address(IPAddress p_IPAddress, - uint32_t p_u32TTL = 0); - }; -#endif - - stcAnswer* m_pNext; - // The service domain is the first 'answer' (from PTR answer, using service and protocol) to be set - // Defines the key for additional answer, like host domain, etc. - stcMDNS_RRDomain m_ServiceDomain; // 1. level answer (PTR), eg. MyESP._http._tcp.local - char* m_pcServiceDomain; - stcTTL m_TTLServiceDomain; - stcMDNS_RRDomain m_HostDomain; // 2. level answer (SRV, using service domain), eg. esp8266.local - char* m_pcHostDomain; - uint16_t m_u16Port; // 2. level answer (SRV, using service domain), eg. 5000 - stcTTL m_TTLHostDomainAndPort; - stcMDNSServiceTxts m_Txts; // 2. level answer (TXT, using service domain), eg. c#=1 - char* m_pcTxts; - stcTTL m_TTLTxts; -#ifdef MDNS_IP4_SUPPORT - stcIP4Address* m_pIP4Addresses; // 3. level answer (A, using host domain), eg. 123.456.789.012 -#endif -#ifdef MDNS_IP6_SUPPORT - stcIP6Address* m_pIP6Addresses; // 3. level answer (AAAA, using host domain), eg. 1234::09 -#endif - uint32_t m_u32ContentFlags; - - stcAnswer(void); - ~stcAnswer(void); - - bool clear(void); - - char* allocServiceDomain(size_t p_stLength); - bool releaseServiceDomain(void); - - char* allocHostDomain(size_t p_stLength); - bool releaseHostDomain(void); - - char* allocTxts(size_t p_stLength); - bool releaseTxts(void); - -#ifdef MDNS_IP4_SUPPORT - bool releaseIP4Addresses(void); - bool addIP4Address(stcIP4Address* p_pIP4Address); - bool removeIP4Address(stcIP4Address* p_pIP4Address); - const stcIP4Address* findIP4Address(const IPAddress& p_IPAddress) const; - stcIP4Address* findIP4Address(const IPAddress& p_IPAddress); - uint32_t IP4AddressCount(void) const; - const stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index) const; - stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index); -#endif -#ifdef MDNS_IP6_SUPPORT - bool releaseIP6Addresses(void); - bool addIP6Address(stcIP6Address* p_pIP6Address); - bool removeIP6Address(stcIP6Address* p_pIP6Address); - const stcIP6Address* findIP6Address(const IPAddress& p_IPAddress) const; - stcIP6Address* findIP6Address(const IPAddress& p_IPAddress); - uint32_t IP6AddressCount(void) const; - const stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index) const; - stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index); -#endif - }; - - stcMDNSServiceQuery* m_pNext; - stcMDNS_RRDomain m_ServiceTypeDomain; // eg. _http._tcp.local - MDNSServiceQueryCallbackFunc m_fnCallback; - bool m_bLegacyQuery; - uint8_t m_u8SentCount; - esp8266::polledTimeout::oneShotMs m_ResendTimeout; - bool m_bAwaitingAnswers; - stcAnswer* m_pAnswers; - - stcMDNSServiceQuery(void); - ~stcMDNSServiceQuery(void); - - bool clear(void); - - uint32_t answerCount(void) const; - const stcAnswer* answerAtIndex(uint32_t p_u32Index) const; - stcAnswer* answerAtIndex(uint32_t p_u32Index); - uint32_t indexOfAnswer(const stcAnswer* p_pAnswer) const; - - bool addAnswer(stcAnswer* p_pAnswer); - bool removeAnswer(stcAnswer* p_pAnswer); - - stcAnswer* findAnswerForServiceDomain(const stcMDNS_RRDomain& p_ServiceDomain); - stcAnswer* findAnswerForHostDomain(const stcMDNS_RRDomain& p_HostDomain); - }; - - /** - stcMDNSSendParameter - */ - struct stcMDNSSendParameter - { - protected: - /** - stcDomainCacheItem - */ - struct stcDomainCacheItem - { - stcDomainCacheItem* m_pNext; - const void* m_pHostnameOrService; // Opaque id for host or service domain (pointer) - bool m_bAdditionalData; // Opaque flag for special info (service domain included) - uint16_t m_u16Offset; // Offset in UDP output buffer - - stcDomainCacheItem(const void* p_pHostnameOrService, - bool p_bAdditionalData, - uint32_t p_u16Offset); - }; - - public: - uint16_t m_u16ID; // Query ID (used only in lagacy queries) - stcMDNS_RRQuestion* m_pQuestions; // A list of queries - uint8_t m_u8HostReplyMask; // Flags for reply components/answers - bool m_bLegacyQuery; // Flag: Legacy query - bool m_bResponse; // Flag: Response to a query - bool m_bAuthorative; // Flag: Authorative (owner) response - bool m_bCacheFlush; // Flag: Clients should flush their caches - bool m_bUnicast; // Flag: Unicast response - bool m_bUnannounce; // Flag: Unannounce service - uint16_t m_u16Offset; // Current offset in UDP write buffer (mainly for domain cache) - stcDomainCacheItem* m_pDomainCacheItems; // Cached host and service domains - - stcMDNSSendParameter(void); - ~stcMDNSSendParameter(void); - - bool clear(void); - - bool shiftOffset(uint16_t p_u16Shift); - - bool addDomainCacheItem(const void* p_pHostnameOrService, - bool p_bAdditionalData, - uint16_t p_u16Offset); - uint16_t findCachedDomainOffset(const void* p_pHostnameOrService, - bool p_bAdditionalData) const; - }; - - // Instance variables - stcMDNSService* m_pServices; - UdpContext* m_pUDPContext; - char* m_pcHostname; - stcMDNSServiceQuery* m_pServiceQueries; - WiFiEventHandler m_DisconnectedHandler; - WiFiEventHandler m_GotIPHandler; - MDNSDynamicServiceTxtCallbackFunc m_fnServiceTxtCallback; - bool m_bPassivModeEnabled; - stcProbeInformation m_HostProbeInformation; - CONST netif* m_netif; // network interface to run on - - /** CONTROL **/ - /* MAINTENANCE */ - bool _process(bool p_bUserContext); - bool _restart(void); - - /* RECEIVING */ - bool _parseMessage(void); - bool _parseQuery(const stcMDNS_MsgHeader& p_Header); - - bool _parseResponse(const stcMDNS_MsgHeader& p_Header); - bool _processAnswers(const stcMDNS_RRAnswer* p_pPTRAnswers); - bool _processPTRAnswer(const stcMDNS_RRAnswerPTR* p_pPTRAnswer, - bool& p_rbFoundNewKeyAnswer); - bool _processSRVAnswer(const stcMDNS_RRAnswerSRV* p_pSRVAnswer, - bool& p_rbFoundNewKeyAnswer); - bool _processTXTAnswer(const stcMDNS_RRAnswerTXT* p_pTXTAnswer); -#ifdef MDNS_IP4_SUPPORT - bool _processAAnswer(const stcMDNS_RRAnswerA* p_pAAnswer); -#endif -#ifdef MDNS_IP6_SUPPORT - bool _processAAAAAnswer(const stcMDNS_RRAnswerAAAA* p_pAAAAAnswer); -#endif - - /* PROBING */ - bool _updateProbeStatus(void); - bool _resetProbeStatus(bool p_bRestart = true); - bool _hasProbesWaitingForAnswers(void) const; - bool _sendHostProbe(void); - bool _sendServiceProbe(stcMDNSService& p_rService); - bool _cancelProbingForHost(void); - bool _cancelProbingForService(stcMDNSService& p_rService); - - /* ANNOUNCE */ - bool _announce(bool p_bAnnounce, - bool p_bIncludeServices); - bool _announceService(stcMDNSService& p_rService, - bool p_bAnnounce = true); - - /* SERVICE QUERY CACHE */ - bool _hasServiceQueriesWaitingForAnswers(void) const; - bool _checkServiceQueryCache(void); - - /** TRANSFER **/ - /* SENDING */ - bool _sendMDNSMessage(stcMDNSSendParameter& p_SendParameter); - bool _sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter); - bool _prepareMDNSMessage(stcMDNSSendParameter& p_SendParameter, - IPAddress p_IPAddress); - bool _sendMDNSServiceQuery(const stcMDNSServiceQuery& p_ServiceQuery); - bool _sendMDNSQuery(const stcMDNS_RRDomain& p_QueryDomain, - uint16_t p_u16QueryType, - stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers = 0); - - const IPAddress _getResponseMulticastInterface() const - { - return IPAddress(m_netif->ip_addr); - } - - uint8_t _replyMaskForHost(const stcMDNS_RRHeader& p_RRHeader, - bool* p_pbFullNameMatch = 0) const; - uint8_t _replyMaskForService(const stcMDNS_RRHeader& p_RRHeader, - const stcMDNSService& p_Service, - bool* p_pbFullNameMatch = 0) const; - - /* RESOURCE RECORD */ - bool _readRRQuestion(stcMDNS_RRQuestion& p_rQuestion); - bool _readRRAnswer(stcMDNS_RRAnswer*& p_rpAnswer); -#ifdef MDNS_IP4_SUPPORT - bool _readRRAnswerA(stcMDNS_RRAnswerA& p_rRRAnswerA, - uint16_t p_u16RDLength); -#endif - bool _readRRAnswerPTR(stcMDNS_RRAnswerPTR& p_rRRAnswerPTR, - uint16_t p_u16RDLength); - bool _readRRAnswerTXT(stcMDNS_RRAnswerTXT& p_rRRAnswerTXT, - uint16_t p_u16RDLength); -#ifdef MDNS_IP6_SUPPORT - bool _readRRAnswerAAAA(stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA, - uint16_t p_u16RDLength); -#endif - bool _readRRAnswerSRV(stcMDNS_RRAnswerSRV& p_rRRAnswerSRV, - uint16_t p_u16RDLength); - bool _readRRAnswerGeneric(stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric, - uint16_t p_u16RDLength); - - bool _readRRHeader(stcMDNS_RRHeader& p_rHeader); - bool _readRRDomain(stcMDNS_RRDomain& p_rRRDomain); - bool _readRRDomain_Loop(stcMDNS_RRDomain& p_rRRDomain, - uint8_t p_u8Depth); - bool _readRRAttributes(stcMDNS_RRAttributes& p_rAttributes); - - /* DOMAIN NAMES */ - bool _buildDomainForHost(const char* p_pcHostname, - stcMDNS_RRDomain& p_rHostDomain) const; - bool _buildDomainForDNSSD(stcMDNS_RRDomain& p_rDNSSDDomain) const; - bool _buildDomainForService(const stcMDNSService& p_Service, - bool p_bIncludeName, - stcMDNS_RRDomain& p_rServiceDomain) const; - bool _buildDomainForService(const char* p_pcService, - const char* p_pcProtocol, - stcMDNS_RRDomain& p_rServiceDomain) const; -#ifdef MDNS_IP4_SUPPORT - bool _buildDomainForReverseIP4(IPAddress p_IP4Address, - stcMDNS_RRDomain& p_rReverseIP4Domain) const; -#endif -#ifdef MDNS_IP6_SUPPORT - bool _buildDomainForReverseIP6(IPAddress p_IP4Address, - stcMDNS_RRDomain& p_rReverseIP6Domain) const; -#endif - - /* UDP */ - bool _udpReadBuffer(unsigned char* p_pBuffer, - size_t p_stLength); - bool _udpRead8(uint8_t& p_ru8Value); - bool _udpRead16(uint16_t& p_ru16Value); - bool _udpRead32(uint32_t& p_ru32Value); - - bool _udpAppendBuffer(const unsigned char* p_pcBuffer, - size_t p_stLength); - bool _udpAppend8(uint8_t p_u8Value); - bool _udpAppend16(uint16_t p_u16Value); - bool _udpAppend32(uint32_t p_u32Value); - -#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER - bool _udpDump(bool p_bMovePointer = false); - bool _udpDump(unsigned p_uOffset, - unsigned p_uLength); -#endif - - /* READ/WRITE MDNS STRUCTS */ - bool _readMDNSMsgHeader(stcMDNS_MsgHeader& p_rMsgHeader); - - bool _write8(uint8_t p_u8Value, - stcMDNSSendParameter& p_rSendParameter); - bool _write16(uint16_t p_u16Value, - stcMDNSSendParameter& p_rSendParameter); - bool _write32(uint32_t p_u32Value, - stcMDNSSendParameter& p_rSendParameter); - - bool _writeMDNSMsgHeader(const stcMDNS_MsgHeader& p_MsgHeader, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSRRAttributes(const stcMDNS_RRAttributes& p_Attributes, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSRRDomain(const stcMDNS_RRDomain& p_Domain, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSHostDomain(const char* m_pcHostname, - bool p_bPrependRDLength, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSServiceDomain(const stcMDNSService& p_Service, - bool p_bIncludeName, - bool p_bPrependRDLength, - stcMDNSSendParameter& p_rSendParameter); - - bool _writeMDNSQuestion(stcMDNS_RRQuestion& p_Question, - stcMDNSSendParameter& p_rSendParameter); - -#ifdef MDNS_IP4_SUPPORT - bool _writeMDNSAnswer_A(IPAddress p_IPAddress, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress, - stcMDNSSendParameter& p_rSendParameter); -#endif - bool _writeMDNSAnswer_PTR_TYPE(stcMDNSService& p_rService, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_PTR_NAME(stcMDNSService& p_rService, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_TXT(stcMDNSService& p_rService, - stcMDNSSendParameter& p_rSendParameter); -#ifdef MDNS_IP6_SUPPORT - bool _writeMDNSAnswer_AAAA(IPAddress p_IPAddress, - stcMDNSSendParameter& p_rSendParameter); - bool _writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress, - stcMDNSSendParameter& p_rSendParameter); -#endif - bool _writeMDNSAnswer_SRV(stcMDNSService& p_rService, - stcMDNSSendParameter& p_rSendParameter); - - /** HELPERS **/ - /* UDP CONTEXT */ - bool _callProcess(void); - bool _allocUDPContext(void); - bool _releaseUDPContext(void); - - /* SERVICE QUERY */ - stcMDNSServiceQuery* _allocServiceQuery(void); - bool _removeServiceQuery(stcMDNSServiceQuery* p_pServiceQuery); - bool _removeLegacyServiceQuery(void); - stcMDNSServiceQuery* _findServiceQuery(hMDNSServiceQuery p_hServiceQuery); - stcMDNSServiceQuery* _findLegacyServiceQuery(void); - bool _releaseServiceQueries(void); - stcMDNSServiceQuery* _findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceDomain, - const stcMDNSServiceQuery* p_pPrevServiceQuery); - - /* HOSTNAME */ - bool _setHostname(const char* p_pcHostname); - bool _releaseHostname(void); - - /* SERVICE */ - stcMDNSService* _allocService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port); - bool _releaseService(stcMDNSService* p_pService); - bool _releaseServices(void); - - stcMDNSService* _findService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol); - stcMDNSService* _findService(const hMDNSService p_hService); - - size_t _countServices(void) const; - - /* SERVICE TXT */ - stcMDNSServiceTxt* _allocServiceTxt(stcMDNSService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp); - bool _releaseServiceTxt(stcMDNSService* p_pService, - stcMDNSServiceTxt* p_pTxt); - stcMDNSServiceTxt* _updateServiceTxt(stcMDNSService* p_pService, - stcMDNSServiceTxt* p_pTxt, - const char* p_pcValue, - bool p_bTemp); - - stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService, - const char* p_pcKey); - stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService, - const hMDNSTxt p_hTxt); - - stcMDNSServiceTxt* _addServiceTxt(stcMDNSService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp); - - stcMDNSServiceTxt* _answerKeyValue(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex); - - bool _collectServiceTxts(stcMDNSService& p_rService); - bool _releaseTempServiceTxts(stcMDNSService& p_rService); - const stcMDNSServiceTxt* _serviceTxts(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol); - - /* MISC */ -#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER - bool _printRRDomain(const stcMDNS_RRDomain& p_rRRDomain) const; - bool _printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const; -#endif -}; - -}// namespace MDNSImplementation - -}// namespace esp8266 - -#endif // MDNS_H diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp deleted file mode 100644 index 41e9524aba..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Control.cpp +++ /dev/null @@ -1,2134 +0,0 @@ -/* - LEAmDNS_Control.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include -#include - -/* - ESP8266mDNS Control.cpp -*/ - -extern "C" { -#include "user_interface.h" -} - -#include "LEAmDNS_lwIPdefs.h" -#include "LEAmDNS_Priv.h" - -namespace esp8266 -{ -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - CONTROL -*/ - - -/** - MAINTENANCE -*/ - -/* - MDNSResponder::_process - - Run the MDNS process. - Is called, every time the UDPContext receives data AND - should be called in every 'loop' by calling 'MDNS::update()'. - -*/ -bool MDNSResponder::_process(bool p_bUserContext) -{ - - bool bResult = true; - - if (!p_bUserContext) - { - - if ((m_pUDPContext) && // UDPContext available AND - (m_pUDPContext->next())) // has content - { - - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _update: Calling _parseMessage\n"));); - bResult = _parseMessage(); - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parsePacket %s\n"), (bResult ? "succeeded" : "FAILED"));); - } - } - else - { - bResult = (m_netif != nullptr) && - (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running - _updateProbeStatus() && // Probing - _checkServiceQueryCache(); // Service query cache check - } - return bResult; -} - -/* - MDNSResponder::_restart -*/ -bool MDNSResponder::_restart(void) -{ - - return ((m_netif != nullptr) && - (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running - (_resetProbeStatus(true)) && // Stop and restart probing - (_allocUDPContext())); // Restart UDP -} - - -/** - RECEIVING -*/ - -/* - MDNSResponder::_parseMessage -*/ -bool MDNSResponder::_parseMessage(void) -{ - DEBUG_EX_INFO( - unsigned long ulStartTime = millis(); - unsigned uStartMemory = ESP.getFreeHeap(); - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage (Time: %lu ms, heap: %u bytes, from %s(%u), to %s(%u))\n"), ulStartTime, uStartMemory, - IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), m_pUDPContext->getRemotePort(), - IPAddress(m_pUDPContext->getDestAddress()).toString().c_str(), m_pUDPContext->getLocalPort()); - ); - //DEBUG_EX_INFO(_udpDump();); - - bool bResult = false; - - stcMDNS_MsgHeader header; - if (_readMDNSMsgHeader(header)) - { - if (0 == header.m_4bOpcode) // A standard query - { - if (header.m_1bQR) // Received a response -> answers to a query - { - //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Reading answers: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); - bResult = _parseResponse(header); - } - else // Received a query (Questions) - { - //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Reading query: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); - bResult = _parseQuery(header); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Received UNEXPECTED opcode:%u. Ignoring message!\n"), header.m_4bOpcode);); - m_pUDPContext->flush(); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: FAILED to read header\n"));); - m_pUDPContext->flush(); - } - DEBUG_EX_INFO( - unsigned uFreeHeap = ESP.getFreeHeap(); - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Done (%s after %lu ms, ate %i bytes, remaining %u)\n\n"), (bResult ? "Succeeded" : "FAILED"), (millis() - ulStartTime), (uStartMemory - uFreeHeap), uFreeHeap); - ); - return bResult; -} - -/* - MDNSResponder::_parseQuery - - Queries are of interest in two cases: - 1. allow for tiebreaking while probing in the case of a race condition between two instances probing for - the same name at the same time - 2. provide answers to questions for our host domain or any presented service - - When reading the questions, a set of (planned) responses is created, eg. a reverse PTR question for the host domain - gets an A (IP address) response, a PTR question for the _services._dns-sd domain gets a PTR (type) response for any - registered service, ... - - As any mDNS responder should be able to handle 'legacy' queries (from DNS clients), this case is handled here also. - Legacy queries have got only one (unicast) question and are directed to the local DNS port (not the multicast port). - - 1. -*/ -bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader) -{ - - bool bResult = true; - - stcMDNSSendParameter sendParameter; - uint8_t u8HostOrServiceReplies = 0; - for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) - { - - stcMDNS_RRQuestion questionRR; - if ((bResult = _readRRQuestion(questionRR))) - { - // Define host replies, BUT only answer queries after probing is done - u8HostOrServiceReplies = - sendParameter.m_u8HostReplyMask |= (((m_bPassivModeEnabled) || - (ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus)) - ? _replyMaskForHost(questionRR.m_Header, 0) - : 0); - DEBUG_EX_INFO(if (u8HostOrServiceReplies) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Host reply needed 0x%X\n"), u8HostOrServiceReplies); - }); - - // Check tiebreak need for host domain - if (ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) - { - bool bFullNameMatch = false; - if ((_replyMaskForHost(questionRR.m_Header, &bFullNameMatch)) && - (bFullNameMatch)) - { - // We're in 'probing' state and someone is asking for our host domain: this might be - // a race-condition: Two host with the same domain names try simutanously to probe their domains - // See: RFC 6762, 8.2 (Tiebraking) - // However, we're using a max. reduced approach for tiebreaking here: The higher IP-address wins! - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Possible race-condition for host domain detected while probing.\n"));); - - m_HostProbeInformation.m_bTiebreakNeeded = true; - } - } - - // Define service replies - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - // Define service replies, BUT only answer queries after probing is done - uint8_t u8ReplyMaskForQuestion = (((m_bPassivModeEnabled) || - (ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus)) - ? _replyMaskForService(questionRR.m_Header, *pService, 0) - : 0); - u8HostOrServiceReplies |= (pService->m_u8ReplyMask |= u8ReplyMaskForQuestion); - DEBUG_EX_INFO(if (u8ReplyMaskForQuestion) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service reply needed for (%s.%s.%s): 0x%X (%s)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, u8ReplyMaskForQuestion, IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()); - }); - - // Check tiebreak need for service domain - if (ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) - { - bool bFullNameMatch = false; - if ((_replyMaskForService(questionRR.m_Header, *pService, &bFullNameMatch)) && - (bFullNameMatch)) - { - // We're in 'probing' state and someone is asking for this service domain: this might be - // a race-condition: Two services with the same domain names try simutanously to probe their domains - // See: RFC 6762, 8.2 (Tiebraking) - // However, we're using a max. reduced approach for tiebreaking here: The 'higher' SRV host wins! - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Possible race-condition for service domain %s.%s.%s detected while probing.\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - - pService->m_ProbeInformation.m_bTiebreakNeeded = true; - } - } - } - - // Handle unicast and legacy specialities - // If only one question asks for unicast reply, the whole reply packet is send unicast - if (((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) || // Unicast (maybe legacy) query OR - (questionRR.m_bUnicast)) && // Expressivly unicast query - (!sendParameter.m_bUnicast)) - { - - sendParameter.m_bUnicast = true; - sendParameter.m_bCacheFlush = false; - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Unicast response for %s!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str());); - - if ((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) && // Unicast (maybe legacy) query AND - (1 == p_MsgHeader.m_u16QDCount) && // Only one question AND - ((sendParameter.m_u8HostReplyMask) || // Host replies OR - (u8HostOrServiceReplies))) // Host or service replies available - { - // We're a match for this legacy query, BUT - // make sure, that the query comes from a local host - ip_info IPInfo_Local; - ip_info IPInfo_Remote; - if (((IPInfo_Remote.ip.addr = m_pUDPContext->getRemoteAddress())) && - (((wifi_get_ip_info(SOFTAP_IF, &IPInfo_Local)) && - (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))) || // Remote IP in SOFTAP's subnet OR - ((wifi_get_ip_info(STATION_IF, &IPInfo_Local)) && - (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))))) // Remote IP in STATION's subnet - { - - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Legacy query from local host %s, id %u!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), p_MsgHeader.m_u16ID);); - - sendParameter.m_u16ID = p_MsgHeader.m_u16ID; - sendParameter.m_bLegacyQuery = true; - sendParameter.m_pQuestions = new stcMDNS_RRQuestion; - if ((bResult = (0 != sendParameter.m_pQuestions))) - { - sendParameter.m_pQuestions->m_Header.m_Domain = questionRR.m_Header.m_Domain; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = questionRR.m_Header.m_Attributes.m_u16Type; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = questionRR.m_Header.m_Attributes.m_u16Class; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to add legacy question!\n"));); - } - } - else - { - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Legacy query from NON-LOCAL host!\n"));); - bResult = false; - } - } - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to read question!\n"));); - } - } // for questions - - //DEBUG_EX_INFO(if (u8HostOrServiceReplies) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Reply needed: %u (%s: %s->%s)\n"), u8HostOrServiceReplies, clsTimeSyncer::timestr(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), IPAddress(m_pUDPContext->getDestAddress()).toString().c_str()); } ); - - // Handle known answers - uint32_t u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); - DEBUG_EX_INFO(if ((u8HostOrServiceReplies) && (u32Answers)) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Known answers(%u):\n"), u32Answers); - }); - - for (uint32_t an = 0; ((bResult) && (an < u32Answers)); ++an) - { - stcMDNS_RRAnswer* pKnownRRAnswer = 0; - if (((bResult = _readRRAnswer(pKnownRRAnswer))) && - (pKnownRRAnswer)) - { - - if ((DNS_RRTYPE_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Type) && // No ANY type answer - (DNS_RRCLASS_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Class)) // No ANY class answer - { - - // Find match between planned answer (sendParameter.m_u8HostReplyMask) and this 'known answer' - uint8_t u8HostMatchMask = (sendParameter.m_u8HostReplyMask & _replyMaskForHost(pKnownRRAnswer->m_Header)); - if ((u8HostMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND - ((MDNS_HOST_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new host TTL (120s) - { - - // Compare contents - if (AnswerType_PTR == pKnownRRAnswer->answerType()) - { - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain == hostDomain)) - { - // Host domain match -#ifdef MDNS_IP4_SUPPORT - if (u8HostMatchMask & ContentFlag_PTR_IP4) - { - // IP4 PTR was asked for, but is already known -> skipping - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP4 PTR already known... skipping!\n"));); - sendParameter.m_u8HostReplyMask &= ~ContentFlag_PTR_IP4; - } -#endif -#ifdef MDNS_IP6_SUPPORT - if (u8HostMatchMask & ContentFlag_PTR_IP6) - { - // IP6 PTR was asked for, but is already known -> skipping - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP6 PTR already known... skipping!\n"));); - sendParameter.m_u8HostReplyMask &= ~ContentFlag_PTR_IP6; - } -#endif - } - } - else if (u8HostMatchMask & ContentFlag_A) - { - // IP4 address was asked for -#ifdef MDNS_IP4_SUPPORT - if ((AnswerType_A == pKnownRRAnswer->answerType()) && - (((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress == _getResponseMulticastInterface())) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP4 address already known... skipping!\n"));); - sendParameter.m_u8HostReplyMask &= ~ContentFlag_A; - } // else: RData NOT IP4 length !! -#endif - } - else if (u8HostMatchMask & ContentFlag_AAAA) - { - // IP6 address was asked for -#ifdef MDNS_IP6_SUPPORT - if ((AnswerType_AAAA == pAnswerRR->answerType()) && - (((stcMDNS_RRAnswerAAAA*)pAnswerRR)->m_IPAddress == _getResponseMulticastInterface())) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP6 address already known... skipping!\n"));); - sendParameter.m_u8HostReplyMask &= ~ContentFlag_AAAA; - } // else: RData NOT IP6 length !! -#endif - } - } // Host match /*and TTL*/ - - // - // Check host tiebreak possibility - if (m_HostProbeInformation.m_bTiebreakNeeded) - { - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (pKnownRRAnswer->m_Header.m_Domain == hostDomain)) - { - // Host domain match -#ifdef MDNS_IP4_SUPPORT - if (AnswerType_A == pKnownRRAnswer->answerType()) - { - IPAddress localIPAddress(_getResponseMulticastInterface()); - if (((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) - { - // SAME IP address -> We've received an old message from ourselfs (same IP) - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) WON (was an old message)!\n"));); - m_HostProbeInformation.m_bTiebreakNeeded = false; - } - else - { - if ((uint32_t)(((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST - { - // LOST tiebreak - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) LOST (lower)!\n"));); - _cancelProbingForHost(); - m_HostProbeInformation.m_bTiebreakNeeded = false; - } - else // WON tiebreak - { - //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) WON (higher IP)!\n"));); - m_HostProbeInformation.m_bTiebreakNeeded = false; - } - } - } -#endif -#ifdef MDNS_IP6_SUPPORT - if (AnswerType_AAAA == pAnswerRR->answerType()) - { - // TODO - } -#endif - } - } // Host tiebreak possibility - - // Check service answers - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - - uint8_t u8ServiceMatchMask = (pService->m_u8ReplyMask & _replyMaskForService(pKnownRRAnswer->m_Header, *pService)); - - if ((u8ServiceMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND - ((MDNS_SERVICE_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) - { - - if (AnswerType_PTR == pKnownRRAnswer->answerType()) - { - stcMDNS_RRDomain serviceDomain; - if ((u8ServiceMatchMask & ContentFlag_PTR_TYPE) && - (_buildDomainForService(*pService, false, serviceDomain)) && - (serviceDomain == ((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service type PTR already known... skipping!\n"));); - pService->m_u8ReplyMask &= ~ContentFlag_PTR_TYPE; - } - if ((u8ServiceMatchMask & ContentFlag_PTR_NAME) && - (_buildDomainForService(*pService, true, serviceDomain)) && - (serviceDomain == ((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service name PTR already known... skipping!\n"));); - pService->m_u8ReplyMask &= ~ContentFlag_PTR_NAME; - } - } - else if (u8ServiceMatchMask & ContentFlag_SRV) - { - DEBUG_EX_ERR(if (AnswerType_SRV != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: ERROR! INVALID answer type (SRV)!\n"));); - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (hostDomain == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match - { - - if ((MDNS_SRV_PRIORITY == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Priority) && - (MDNS_SRV_WEIGHT == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Weight) && - (pService->m_u16Port == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Port)) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service SRV answer already known... skipping!\n"));); - pService->m_u8ReplyMask &= ~ContentFlag_SRV; - } // else: Small differences -> send update message - } - } - else if (u8ServiceMatchMask & ContentFlag_TXT) - { - DEBUG_EX_ERR(if (AnswerType_TXT != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: ERROR! INVALID answer type (TXT)!\n"));); - _collectServiceTxts(*pService); - if (pService->m_Txts == ((stcMDNS_RRAnswerTXT*)pKnownRRAnswer)->m_Txts) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service TXT answer already known... skipping!\n"));); - pService->m_u8ReplyMask &= ~ContentFlag_TXT; - } - _releaseTempServiceTxts(*pService); - } - } // Service match and enough TTL - - // - // Check service tiebreak possibility - if (pService->m_ProbeInformation.m_bTiebreakNeeded) - { - stcMDNS_RRDomain serviceDomain; - if ((_buildDomainForService(*pService, true, serviceDomain)) && - (pKnownRRAnswer->m_Header.m_Domain == serviceDomain)) - { - // Service domain match - if (AnswerType_SRV == pKnownRRAnswer->answerType()) - { - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (hostDomain == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match - { - - // We've received an old message from ourselfs (same SRV) - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) won (was an old message)!\n"));); - pService->m_ProbeInformation.m_bTiebreakNeeded = false; - } - else - { - if (((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain > hostDomain) // The OTHER domain is 'higher' -> LOST - { - // LOST tiebreak - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) LOST (lower)!\n"));); - _cancelProbingForService(*pService); - pService->m_ProbeInformation.m_bTiebreakNeeded = false; - } - else // WON tiebreak - { - //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore - DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) won (higher)!\n"));); - pService->m_ProbeInformation.m_bTiebreakNeeded = false; - } - } - } - } - } // service tiebreak possibility - } // for services - } // ANY answers - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to read known answer!\n"));); - } - - if (pKnownRRAnswer) - { - delete pKnownRRAnswer; - pKnownRRAnswer = 0; - } - } // for answers - - if (bResult) - { - // Check, if a reply is needed - uint8_t u8ReplyNeeded = sendParameter.m_u8HostReplyMask; - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - u8ReplyNeeded |= pService->m_u8ReplyMask; - } - - if (u8ReplyNeeded) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Sending answer(0x%X)...\n"), u8ReplyNeeded);); - - sendParameter.m_bResponse = true; - sendParameter.m_bAuthorative = true; - - bResult = _sendMDNSMessage(sendParameter); - } - DEBUG_EX_INFO( - else - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: No reply needed\n")); - } - ); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Something FAILED!\n"));); - m_pUDPContext->flush(); - } - - // - // Check and reset tiebreak-states - if (m_HostProbeInformation.m_bTiebreakNeeded) - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: UNSOLVED tiebreak-need for host domain!\n"));); - m_HostProbeInformation.m_bTiebreakNeeded = false; - } - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - if (pService->m_ProbeInformation.m_bTiebreakNeeded) - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: UNSOLVED tiebreak-need for service domain (%s.%s.%s)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - pService->m_ProbeInformation.m_bTiebreakNeeded = false; - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_parseResponse - - Responses are of interest in two cases: - 1. find domain name conflicts while probing - 2. get answers to service queries - - In both cases any included questions are ignored - - 1. If any answer has a domain name similar to one of the domain names we're planning to use (and are probing for), - then we've got a 'probing conflict'. The conflict has to be solved on our side of the conflict (eg. by - setting a new hostname and restart probing). The callback 'm_fnProbeResultCallback' is called with - 'p_bProbeResult=false' in this case. - - 2. Service queries like '_http._tcp.local' will (if available) produce PTR, SRV, TXT and A/AAAA answers. - All stored answers are pivoted by the service instance name (from the PTR record). Other answer parts, - like host domain or IP address are than attached to this element. - Any answer part carries a TTL, this is also stored (incl. the reception time); if the TTL is '0' the - answer (part) is withdrawn by the sender and should be removed from any cache. RFC 6762, 10.1 proposes to - set the caches TTL-value to 1 second in such a case and to delete the item only, if no update has - has taken place in this second. - Answer parts may arrive in 'unsorted' order, so they are grouped into three levels: - Level 1: PRT - names the service instance (and is used as pivot), voids all other parts if is withdrawn or outdates - Level 2: SRV - links the instance name to a host domain and port, voids A/AAAA parts if is withdrawn or outdates - TXT - links the instance name to services TXTs - Level 3: A/AAAA - links the host domain to an IP address -*/ -bool MDNSResponder::_parseResponse(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse\n"));); - //DEBUG_EX_INFO(_udpDump();); - - bool bResult = false; - - // A response should be the result of a query or a probe - if ((_hasServiceQueriesWaitingForAnswers()) || // Waiting for query answers OR - (_hasProbesWaitingForAnswers())) // Probe responses - { - - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received a response\n")); - //_udpDump(); - ); - - bResult = true; - // - // Ignore questions here - stcMDNS_RRQuestion dummyRRQ; - for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received a response containing a question... ignoring!\n"));); - bResult = _readRRQuestion(dummyRRQ); - } // for queries - - // - // Read and collect answers - stcMDNS_RRAnswer* pCollectedRRAnswers = 0; - uint32_t u32NumberOfAnswerRRs = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); - for (uint32_t an = 0; ((bResult) && (an < u32NumberOfAnswerRRs)); ++an) - { - stcMDNS_RRAnswer* pRRAnswer = 0; - if (((bResult = _readRRAnswer(pRRAnswer))) && - (pRRAnswer)) - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: ADDING answer!\n"));); - pRRAnswer->m_pNext = pCollectedRRAnswers; - pCollectedRRAnswers = pRRAnswer; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED to read answer!\n"));); - if (pRRAnswer) - { - delete pRRAnswer; - pRRAnswer = 0; - } - bResult = false; - } - } // for answers - - // - // Process answers - if (bResult) - { - bResult = ((!pCollectedRRAnswers) || - (_processAnswers(pCollectedRRAnswers))); - } - else // Some failure while reading answers - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED to read answers!\n"));); - m_pUDPContext->flush(); - } - - // Delete collected answers - while (pCollectedRRAnswers) - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: DELETING answer!\n"));); - stcMDNS_RRAnswer* pNextAnswer = pCollectedRRAnswers->m_pNext; - delete pCollectedRRAnswers; - pCollectedRRAnswers = pNextAnswer; - } - } - else // Received an unexpected response -> ignore - { - /* DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received an unexpected response... ignoring!\nDUMP:\n")); - bool bDumpResult = true; - for (uint16_t qd=0; ((bDumpResult) && (qdflush(); - bResult = true; - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_processAnswers - Host: - A (0x01): eg. esp8266.local A OP TTL 123.456.789.012 - AAAA (01Cx): eg. esp8266.local AAAA OP TTL 1234:5678::90 - PTR (0x0C, IP4): eg. 012.789.456.123.in-addr.arpa PTR OP TTL esp8266.local - PTR (0x0C, IP6): eg. 90.0.0.0.0.0.0.0.0.0.0.0.78.56.34.12.ip6.arpa PTR OP TTL esp8266.local - Service: - PTR (0x0C, srv name): eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local - PTR (0x0C, srv type): eg. _services._dns-sd._udp.local PTR OP TTL _http._tcp.local - SRV (0x21): eg. MyESP._http._tcp.local SRV OP TTL PRIORITY WEIGHT PORT esp8266.local - TXT (0x10): eg. MyESP._http._tcp.local TXT OP TTL c#=1 - -*/ -bool MDNSResponder::_processAnswers(const MDNSResponder::stcMDNS_RRAnswer* p_pAnswers) -{ - - bool bResult = false; - - if (p_pAnswers) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Processing answers...\n"));); - bResult = true; - - // Answers may arrive in an unexpected order. So we loop our answers as long, as we - // can connect new information to service queries - bool bFoundNewKeyAnswer; - do - { - bFoundNewKeyAnswer = false; - - const stcMDNS_RRAnswer* pRRAnswer = p_pAnswers; - while ((pRRAnswer) && - (bResult)) - { - // 1. level answer (PTR) - if (AnswerType_PTR == pRRAnswer->answerType()) - { - // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local - bResult = _processPTRAnswer((stcMDNS_RRAnswerPTR*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new SRV or TXT answers to be linked to queries - } - // 2. level answers - // SRV -> host domain and port - else if (AnswerType_SRV == pRRAnswer->answerType()) - { - // eg. MyESP_http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local - bResult = _processSRVAnswer((stcMDNS_RRAnswerSRV*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new A/AAAA answers to be linked to queries - } - // TXT -> Txts - else if (AnswerType_TXT == pRRAnswer->answerType()) - { - // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 - bResult = _processTXTAnswer((stcMDNS_RRAnswerTXT*)pRRAnswer); - } - // 3. level answers -#ifdef MDNS_IP4_SUPPORT - // A -> IP4Address - else if (AnswerType_A == pRRAnswer->answerType()) - { - // eg. esp8266.local A xxxx xx 192.168.2.120 - bResult = _processAAnswer((stcMDNS_RRAnswerA*)pRRAnswer); - } -#endif -#ifdef MDNS_IP6_SUPPORT - // AAAA -> IP6Address - else if (AnswerType_AAAA == pRRAnswer->answerType()) - { - // eg. esp8266.local AAAA xxxx xx 09cf::0c - bResult = _processAAAAAnswer((stcMDNS_RRAnswerAAAA*)pRRAnswer); - } -#endif - - // Finally check for probing conflicts - // Host domain - if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && - ((AnswerType_A == pRRAnswer->answerType()) || - (AnswerType_AAAA == pRRAnswer->answerType()))) - { - - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (pRRAnswer->m_Header.m_Domain == hostDomain)) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Probing CONFLICT found with: %s.local\n"), m_pcHostname);); - _cancelProbingForHost(); - } - } - // Service domains - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && - ((AnswerType_TXT == pRRAnswer->answerType()) || - (AnswerType_SRV == pRRAnswer->answerType()))) - { - - stcMDNS_RRDomain serviceDomain; - if ((_buildDomainForService(*pService, true, serviceDomain)) && - (pRRAnswer->m_Header.m_Domain == serviceDomain)) - { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Probing CONFLICT found with: %s.%s.%s\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - _cancelProbingForService(*pService); - } - } - } - - pRRAnswer = pRRAnswer->m_pNext; // Next collected answer - } // while (answers) - } while ((bFoundNewKeyAnswer) && - (bResult)); - } // else: No answers provided - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_processPTRAnswer -*/ -bool MDNSResponder::_processPTRAnswer(const MDNSResponder::stcMDNS_RRAnswerPTR* p_pPTRAnswer, - bool& p_rbFoundNewKeyAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pPTRAnswer))) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Processing PTR answers...\n"));); - // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local - // Check pending service queries for eg. '_http._tcp' - - stcMDNSServiceQuery* pServiceQuery = _findNextServiceQueryByServiceType(p_pPTRAnswer->m_Header.m_Domain, 0); - while (pServiceQuery) - { - if (pServiceQuery->m_bAwaitingAnswers) - { - // Find answer for service domain (eg. MyESP._http._tcp.local) - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pPTRAnswer->m_PTRDomain); - if (pSQAnswer) // existing answer - { - if (p_pPTRAnswer->m_u32TTL) // Received update message - { - pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); // Update TTL tag - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Updated TTL(%d) for "), (int)p_pPTRAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - ); - } - else // received goodbye-message - { - pSQAnswer->m_TTLServiceDomain.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - ); - } - } - else if ((p_pPTRAnswer->m_u32TTL) && // Not just a goodbye-message - ((pSQAnswer = new stcMDNSServiceQuery::stcAnswer))) // Not yet included -> add answer - { - pSQAnswer->m_ServiceDomain = p_pPTRAnswer->m_PTRDomain; - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_ServiceDomain; - pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); - pSQAnswer->releaseServiceDomain(); - - bResult = pServiceQuery->addAnswer(pSQAnswer); - p_rbFoundNewKeyAnswer = true; - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_ServiceDomain), true); - } - } - } - pServiceQuery = _findNextServiceQueryByServiceType(p_pPTRAnswer->m_Header.m_Domain, pServiceQuery); - } - } // else: No p_pPTRAnswer - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_processSRVAnswer -*/ -bool MDNSResponder::_processSRVAnswer(const MDNSResponder::stcMDNS_RRAnswerSRV* p_pSRVAnswer, - bool& p_rbFoundNewKeyAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pSRVAnswer))) - { - // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pSRVAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available - { - if (p_pSRVAnswer->m_u32TTL) // First or update message (TTL != 0) - { - pSQAnswer->m_TTLHostDomainAndPort.set(p_pSRVAnswer->m_u32TTL); // Update TTL tag - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: Updated TTL(%d) for "), (int)p_pSRVAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); - ); - // Host domain & Port - if ((pSQAnswer->m_HostDomain != p_pSRVAnswer->m_SRVDomain) || - (pSQAnswer->m_u16Port != p_pSRVAnswer->m_u16Port)) - { - - pSQAnswer->m_HostDomain = p_pSRVAnswer->m_SRVDomain; - pSQAnswer->releaseHostDomain(); - pSQAnswer->m_u16Port = p_pSRVAnswer->m_u16Port; - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_HostDomainAndPort; - - p_rbFoundNewKeyAnswer = true; - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_HostDomainAndPort), true); - } - } - } - else // Goodby message - { - pSQAnswer->m_TTLHostDomainAndPort.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); - ); - } - } - pServiceQuery = pServiceQuery->m_pNext; - } // while(service query) - } // else: No p_pSRVAnswer - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_processTXTAnswer -*/ -bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT* p_pTXTAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pTXTAnswer))) - { - // eg. MyESP._http._tcp.local TXT xxxx xx c#=1 - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pTXTAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available - { - if (p_pTXTAnswer->m_u32TTL) // First or update message - { - pSQAnswer->m_TTLTxts.set(p_pTXTAnswer->m_u32TTL); // Update TTL tag - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: Updated TTL(%d) for "), (int)p_pTXTAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); - ); - if (!pSQAnswer->m_Txts.compare(p_pTXTAnswer->m_Txts)) - { - pSQAnswer->m_Txts = p_pTXTAnswer->m_Txts; - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_Txts; - pSQAnswer->releaseTxts(); - - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_Txts), true); - } - } - } - else // Goodby message - { - pSQAnswer->m_TTLTxts.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); - ); - } - } - pServiceQuery = pServiceQuery->m_pNext; - } // while(service query) - } // else: No p_pTXTAnswer - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: FAILED!\n")); - }); - return bResult; -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::_processAAnswer -*/ -bool MDNSResponder::_processAAnswer(const MDNSResponder::stcMDNS_RRAnswerA* p_pAAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pAAnswer))) - { - // eg. esp8266.local A xxxx xx 192.168.2.120 - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available - { - stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = pSQAnswer->findIP4Address(p_pAAnswer->m_IPAddress); - if (pIP4Address) - { - // Already known IP4 address - if (p_pAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL - { - pIP4Address->m_TTL.set(p_pAAnswer->m_u32TTL); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%d) for "), (int)p_pAAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP4Address (%s)\n"), pIP4Address->m_IPAddress.toString().c_str()); - ); - } - else // 'Goodbye' message for known IP4 address - { - pIP4Address->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP4 address (%s)\n"), pIP4Address->m_IPAddress.toString().c_str()); - ); - } - } - else - { - // Until now unknown IP4 address -> Add (if the message isn't just a 'Goodbye' note) - if (p_pAAnswer->m_u32TTL) // NOT just a 'Goodbye' message - { - pIP4Address = new stcMDNSServiceQuery::stcAnswer::stcIP4Address(p_pAAnswer->m_IPAddress, p_pAAnswer->m_u32TTL); - if ((pIP4Address) && - (pSQAnswer->addIP4Address(pIP4Address))) - { - - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_IP4Address; - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_IP4Address), true); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED to add IP4 address (%s)!\n"), p_pAAnswer->m_IPAddress.toString().c_str());); - } - } - } - } - pServiceQuery = pServiceQuery->m_pNext; - } // while(service query) - } // else: No p_pAAnswer - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED!\n")); - }); - return bResult; -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::_processAAAAAnswer -*/ -bool MDNSResponder::_processAAAAAnswer(const MDNSResponder::stcMDNS_RRAnswerAAAA* p_pAAAAAnswer) -{ - - bool bResult = false; - - if ((bResult = (0 != p_pAAAAAnswer))) - { - // eg. esp8266.local AAAA xxxx xx 0bf3::0c - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); - if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available - { - stcIP6Address* pIP6Address = pSQAnswer->findIP6Address(p_pAAAAAnswer->m_IPAddress); - if (pIP6Address) - { - // Already known IP6 address - if (p_pAAAAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL - { - pIP6Address->m_TTL.set(p_pAAAAAnswer->m_u32TTL); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%lu) for "), p_pAAAAAnswer->m_u32TTL); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), pIP6Address->m_IPAddress.toString().c_str()); - ); - } - else // 'Goodbye' message for known IP6 address - { - pIP6Address->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: 'Goodbye' received for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), pIP6Address->m_IPAddress.toString().c_str()); - ); - } - } - else - { - // Until now unknown IP6 address -> Add (if the message isn't just a 'Goodbye' note) - if (p_pAAAAAnswer->m_u32TTL) // NOT just a 'Goodbye' message - { - pIP6Address = new stcIP6Address(p_pAAAAAnswer->m_IPAddress, p_pAAAAAnswer->m_u32TTL); - if ((pIP6Address) && - (pSQAnswer->addIP6Address(pIP6Address))) - { - - pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_IP6Address; - - if (pServiceQuery->m_fnCallback) - { - pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP6Address, true, pServiceQuery->m_pUserdata); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED to add IP6 address (%s)!\n"), p_pAAAAAnswer->m_IPAddress.toString().c_str());); - } - } - } - } - pServiceQuery = pServiceQuery->m_pNext; - } // while(service query) - } // else: No p_pAAAAAnswer - - return bResult; -} -#endif - - -/* - PROBING -*/ - -/* - MDNSResponder::_updateProbeStatus - - Manages the (outgoing) probing process. - - If probing has not been started yet (ProbingStatus_NotStarted), the initial delay (see RFC 6762) is determined and - the process is started - - After timeout (of initial or subsequential delay) a probe message is send out for three times. If the message has - already been sent out three times, the probing has been successful and is finished. - - Conflict management is handled in '_parseResponse ff.' - Tiebraking is handled in 'parseQuery ff.' -*/ -bool MDNSResponder::_updateProbeStatus(void) -{ - - bool bResult = true; - - // - // Probe host domain - if ((ProbingStatus_ReadyToStart == m_HostProbeInformation.m_ProbingStatus) && // Ready to get started AND - //TODO: Fix the following to allow Ethernet shield or other interfaces - (_getResponseMulticastInterface() != IPAddress())) // Has IP address - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Starting host probing...\n"));); - - // First probe delay SHOULD be random 0-250 ms - m_HostProbeInformation.m_Timeout.reset(rand() % MDNS_PROBE_DELAY); - m_HostProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; - } - else if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing AND - (m_HostProbeInformation.m_Timeout.expired())) // Time for next probe - { - - if (MDNS_PROBE_COUNT > m_HostProbeInformation.m_u8SentCount) // Send next probe - { - if ((bResult = _sendHostProbe())) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Did sent host probe\n\n"));); - m_HostProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); - ++m_HostProbeInformation.m_u8SentCount; - } - } - else // Probing finished - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host probing.\n"));); - m_HostProbeInformation.m_ProbingStatus = ProbingStatus_Done; - m_HostProbeInformation.m_Timeout.resetToNeverExpires(); - if (m_HostProbeInformation.m_fnHostProbeResultCallback) - { - m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, true); - } - - // Prepare to announce host - m_HostProbeInformation.m_u8SentCount = 0; - m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Prepared host announcing.\n\n"));); - } - } // else: Probing already finished OR waiting for next time slot - else if ((ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) && - (m_HostProbeInformation.m_Timeout.expired())) - { - - if ((bResult = _announce(true, false))) // Don't announce services here - { - ++m_HostProbeInformation.m_u8SentCount; - - if (MDNS_ANNOUNCE_COUNT > m_HostProbeInformation.m_u8SentCount) - { - m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%d).\n\n"), m_HostProbeInformation.m_u8SentCount);); - } - else - { - m_HostProbeInformation.m_Timeout.resetToNeverExpires(); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host announcing.\n\n"));); - } - } - } - - // - // Probe services - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if (ProbingStatus_ReadyToStart == pService->m_ProbeInformation.m_ProbingStatus) // Ready to get started - { - - pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); // More or equal than first probe for host domain - pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; - } - else if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND - (pService->m_ProbeInformation.m_Timeout.expired())) // Time for next probe - { - - if (MDNS_PROBE_COUNT > pService->m_ProbeInformation.m_u8SentCount) // Send next probe - { - if ((bResult = _sendServiceProbe(*pService))) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Did sent service probe (%u)\n\n"), (pService->m_ProbeInformation.m_u8SentCount + 1));); - pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); - ++pService->m_ProbeInformation.m_u8SentCount; - } - } - else // Probing finished - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service probing %s.%s.%s\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_Done; - pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); - if (pService->m_ProbeInformation.m_fnServiceProbeResultCallback) - { - pService->m_ProbeInformation.m_fnServiceProbeResultCallback(pService->m_pcName, pService, true); - } - // Prepare to announce service - pService->m_ProbeInformation.m_u8SentCount = 0; - pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Prepared service announcing.\n\n"));); - } - } // else: Probing already finished OR waiting for next time slot - else if ((ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) && - (pService->m_ProbeInformation.m_Timeout.expired())) - { - - if ((bResult = _announceService(*pService))) // Announce service - { - ++pService->m_ProbeInformation.m_u8SentCount; - - if (MDNS_ANNOUNCE_COUNT > pService->m_ProbeInformation.m_u8SentCount) - { - pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing service %s.%s.%s (%d)\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount);); - } - else - { - pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service announcing for %s.%s.%s\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); - } - } - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: FAILED!\n\n")); - }); - return bResult; -} - -/* - MDNSResponder::_resetProbeStatus - - Resets the probe status. - If 'p_bRestart' is set, the status is set to ProbingStatus_NotStarted. Consequently, - when running 'updateProbeStatus' (which is done in every '_update' loop), the probing - process is restarted. -*/ -bool MDNSResponder::_resetProbeStatus(bool p_bRestart /*= true*/) -{ - - m_HostProbeInformation.clear(false); - m_HostProbeInformation.m_ProbingStatus = (p_bRestart ? ProbingStatus_ReadyToStart : ProbingStatus_Done); - - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - pService->m_ProbeInformation.clear(false); - pService->m_ProbeInformation.m_ProbingStatus = (p_bRestart ? ProbingStatus_ReadyToStart : ProbingStatus_Done); - } - return true; -} - -/* - MDNSResponder::_hasProbesWaitingForAnswers -*/ -bool MDNSResponder::_hasProbesWaitingForAnswers(void) const -{ - - bool bResult = ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing - (0 < m_HostProbeInformation.m_u8SentCount)); // And really probing - - for (stcMDNSService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) - { - bResult = ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing - (0 < pService->m_ProbeInformation.m_u8SentCount)); // And really probing - } - return bResult; -} - -/* - MDNSResponder::_sendHostProbe - - Asks (probes) in the local network for the planned host domain - - (eg. esp8266.local) - - To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in - the 'knwon answers' section of the query. - Host domain: - - A/AAAA (eg. esp8266.esp -> 192.168.2.120) -*/ -bool MDNSResponder::_sendHostProbe(void) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe (%s, %lu)\n"), m_pcHostname, millis());); - - bool bResult = true; - - // Requests for host domain - stcMDNSSendParameter sendParameter; - sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 - - sendParameter.m_pQuestions = new stcMDNS_RRQuestion; - if (((bResult = (0 != sendParameter.m_pQuestions))) && - ((bResult = _buildDomainForHost(m_pcHostname, sendParameter.m_pQuestions->m_Header.m_Domain)))) - { - - //sendParameter.m_pQuestions->m_bUnicast = true; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet - - // Add known answers -#ifdef MDNS_IP4_SUPPORT - sendParameter.m_u8HostReplyMask |= ContentFlag_A; // Add A answer -#endif -#ifdef MDNS_IP6_SUPPORT - sendParameter.m_u8HostReplyMask |= ContentFlag_AAAA; // Add AAAA answer -#endif - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe: FAILED to create host question!\n"));); - if (sendParameter.m_pQuestions) - { - delete sendParameter.m_pQuestions; - sendParameter.m_pQuestions = 0; - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe: FAILED!\n")); - }); - return ((bResult) && - (_sendMDNSMessage(sendParameter))); -} - -/* - MDNSResponder::_sendServiceProbe - - Asks (probes) in the local network for the planned service instance domain - - (eg. MyESP._http._tcp.local). - - To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in - the 'knwon answers' section of the query. - Service domain: - - SRV (eg. MyESP._http._tcp.local -> 5000 esp8266.local) - - PTR NAME (eg. _http._tcp.local -> MyESP._http._tcp.local) (TODO: Check if needed, maybe TXT is better) -*/ -bool MDNSResponder::_sendServiceProbe(stcMDNSService& p_rService) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe (%s.%s.%s, %lu)\n"), (p_rService.m_pcName ? : m_pcHostname), p_rService.m_pcService, p_rService.m_pcProtocol, millis());); - - bool bResult = true; - - // Requests for service instance domain - stcMDNSSendParameter sendParameter; - sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 - - sendParameter.m_pQuestions = new stcMDNS_RRQuestion; - if (((bResult = (0 != sendParameter.m_pQuestions))) && - ((bResult = _buildDomainForService(p_rService, true, sendParameter.m_pQuestions->m_Header.m_Domain)))) - { - - sendParameter.m_pQuestions->m_bUnicast = true; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet - - // Add known answers - p_rService.m_u8ReplyMask = (ContentFlag_SRV | ContentFlag_PTR_NAME); // Add SRV and PTR NAME answers - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe: FAILED to create service question!\n"));); - if (sendParameter.m_pQuestions) - { - delete sendParameter.m_pQuestions; - sendParameter.m_pQuestions = 0; - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe: FAILED!\n")); - }); - return ((bResult) && - (_sendMDNSMessage(sendParameter))); -} - -/* - MDNSResponder::_cancelProbingForHost -*/ -bool MDNSResponder::_cancelProbingForHost(void) -{ - - bool bResult = false; - - m_HostProbeInformation.clear(false); - // Send host notification - if (m_HostProbeInformation.m_fnHostProbeResultCallback) - { - m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, false); - - bResult = true; - } - - for (stcMDNSService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) - { - bResult = _cancelProbingForService(*pService); - } - return bResult; -} - -/* - MDNSResponder::_cancelProbingForService -*/ -bool MDNSResponder::_cancelProbingForService(stcMDNSService& p_rService) -{ - - bool bResult = false; - - p_rService.m_ProbeInformation.clear(false); - // Send notification - if (p_rService.m_ProbeInformation.m_fnServiceProbeResultCallback) - { - p_rService.m_ProbeInformation.m_fnServiceProbeResultCallback(p_rService.m_pcName, &p_rService, false); - bResult = true; - } - return bResult; -} - - - -/** - ANNOUNCING -*/ - -/* - MDNSResponder::_announce - - Announces the host domain: - - A/AAAA (eg. esp8266.local -> 192.168.2.120) - - PTR (eg. 192.168.2.120.in-addr.arpa -> esp8266.local) - - and all presented services: - - PTR_TYPE (_services._dns-sd._udp.local -> _http._tcp.local) - - PTR_NAME (eg. _http._tcp.local -> MyESP8266._http._tcp.local) - - SRV (eg. MyESP8266._http._tcp.local -> 5000 esp8266.local) - - TXT (eg. MyESP8266._http._tcp.local -> c#=1) - - Goodbye (Un-Announcing) for the host domain and all services is also handled here. - Goodbye messages are created by setting the TTL for the answer to 0, this happens - inside the '_writeXXXAnswer' procs via 'sendParameter.m_bUnannounce = true' -*/ -bool MDNSResponder::_announce(bool p_bAnnounce, - bool p_bIncludeServices) -{ - - bool bResult = false; - - stcMDNSSendParameter sendParameter; - if (ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) - { - - bResult = true; - - sendParameter.m_bResponse = true; // Announces are 'Unsolicited authorative responses' - sendParameter.m_bAuthorative = true; - sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers - - // Announce host - sendParameter.m_u8HostReplyMask = 0; -#ifdef MDNS_IP4_SUPPORT - sendParameter.m_u8HostReplyMask |= ContentFlag_A; // A answer - sendParameter.m_u8HostReplyMask |= ContentFlag_PTR_IP4; // PTR_IP4 answer -#endif -#ifdef MDNS_IP6_SUPPORT - sendParameter.m_u8HostReplyMask |= ContentFlag_AAAA; // AAAA answer - sendParameter.m_u8HostReplyMask |= ContentFlag_PTR_IP6; // PTR_IP6 answer -#endif - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing host %s (content 0x%X)\n"), m_pcHostname, sendParameter.m_u8HostReplyMask);); - - if (p_bIncludeServices) - { - // Announce services (service type, name, SRV (location) and TXTs) - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if (ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) - { - pService->m_u8ReplyMask = (ContentFlag_PTR_TYPE | ContentFlag_PTR_NAME | ContentFlag_SRV | ContentFlag_TXT); - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing service %s.%s.%s (content %u)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_u8ReplyMask);); - } - } - } - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: FAILED!\n")); - }); - return ((bResult) && - (_sendMDNSMessage(sendParameter))); -} - -/* - MDNSResponder::_announceService -*/ -bool MDNSResponder::_announceService(stcMDNSService& p_rService, - bool p_bAnnounce /*= true*/) -{ - - bool bResult = false; - - stcMDNSSendParameter sendParameter; - if (ProbingStatus_Done == p_rService.m_ProbeInformation.m_ProbingStatus) - { - - sendParameter.m_bResponse = true; // Announces are 'Unsolicited authorative responses' - sendParameter.m_bAuthorative = true; - sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers - - // DON'T announce host - sendParameter.m_u8HostReplyMask = 0; - - // Announce services (service type, name, SRV (location) and TXTs) - p_rService.m_u8ReplyMask = (ContentFlag_PTR_TYPE | ContentFlag_PTR_NAME | ContentFlag_SRV | ContentFlag_TXT); - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: Announcing service %s.%s.%s (content 0x%X)\n"), (p_rService.m_pcName ? : m_pcHostname), p_rService.m_pcService, p_rService.m_pcProtocol, p_rService.m_u8ReplyMask);); - - bResult = true; - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: FAILED!\n")); - }); - return ((bResult) && - (_sendMDNSMessage(sendParameter))); -} - - -/** - SERVICE QUERY CACHE -*/ - -/* - MDNSResponder::_hasServiceQueriesWaitingForAnswers -*/ -bool MDNSResponder::_hasServiceQueriesWaitingForAnswers(void) const -{ - - bool bOpenQueries = false; - - for (stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; pServiceQuery; pServiceQuery = pServiceQuery->m_pNext) - { - if (pServiceQuery->m_bAwaitingAnswers) - { - bOpenQueries = true; - break; - } - } - return bOpenQueries; -} - -/* - MDNSResponder::_checkServiceQueryCache - - For any 'living' service query (m_bAwaitingAnswers == true) all available answers (their components) - are checked for topicality based on the stored reception time and the answers TTL. - When the components TTL is outlasted by more than 80%, a new question is generated, to get updated information. - When no update arrived (in time), the component is removed from the answer (cache). - -*/ -bool MDNSResponder::_checkServiceQueryCache(void) -{ - - bool bResult = true; - - DEBUG_EX_INFO( - bool printedInfo = false; - ); - for (stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; ((bResult) && (pServiceQuery)); pServiceQuery = pServiceQuery->m_pNext) - { - - // - // Resend dynamic service queries, if not already done often enough - if ((!pServiceQuery->m_bLegacyQuery) && - (MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) && - (pServiceQuery->m_ResendTimeout.expired())) - { - - if ((bResult = _sendMDNSServiceQuery(*pServiceQuery))) - { - ++pServiceQuery->m_u8SentCount; - pServiceQuery->m_ResendTimeout.reset((MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) - ? (MDNS_DYNAMIC_QUERY_RESEND_DELAY * (pServiceQuery->m_u8SentCount - 1)) - : esp8266::polledTimeout::oneShotMs::neverExpires); - } - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: %s to resend service query!"), (bResult ? "Succeeded" : "FAILED")); - printedInfo = true; - ); - } - - // - // Schedule updates for cached answers - if (pServiceQuery->m_bAwaitingAnswers) - { - stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->m_pAnswers; - while ((bResult) && - (pSQAnswer)) - { - stcMDNSServiceQuery::stcAnswer* pNextSQAnswer = pSQAnswer->m_pNext; - - // 1. level answer - if ((bResult) && - (pSQAnswer->m_TTLServiceDomain.flagged())) - { - - if (!pSQAnswer->m_TTLServiceDomain.finalTimeoutLevel()) - { - - bResult = ((_sendMDNSServiceQuery(*pServiceQuery)) && - (pSQAnswer->m_TTLServiceDomain.restart())); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: PTR update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), (bResult ? "OK" : "FAILURE")); - printedInfo = true; - ); - } - else - { - // Timed out! -> Delete - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_ServiceDomain), false); - } - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove PTR answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - printedInfo = true; - ); - - bResult = pServiceQuery->removeAnswer(pSQAnswer); - pSQAnswer = 0; - continue; // Don't use this answer anymore - } - } // ServiceDomain flagged - - // 2. level answers - // HostDomain & Port (from SRV) - if ((bResult) && - (pSQAnswer->m_TTLHostDomainAndPort.flagged())) - { - - if (!pSQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) - { - - bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_SRV)) && - (pSQAnswer->m_TTLHostDomainAndPort.restart())); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: SRV update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" host domain and port %s\n"), (bResult ? "OK" : "FAILURE")); - printedInfo = true; - ); - } - else - { - // Timed out! -> Delete - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove SRV answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); - printedInfo = true; - ); - // Delete - pSQAnswer->m_HostDomain.clear(); - pSQAnswer->releaseHostDomain(); - pSQAnswer->m_u16Port = 0; - pSQAnswer->m_TTLHostDomainAndPort.set(0); - uint32_t u32ContentFlags = ServiceQueryAnswerType_HostDomainAndPort; - // As the host domain is the base for the IP4- and IP6Address, remove these too -#ifdef MDNS_IP4_SUPPORT - pSQAnswer->releaseIP4Addresses(); - u32ContentFlags |= ServiceQueryAnswerType_IP4Address; -#endif -#ifdef MDNS_IP6_SUPPORT - pSQAnswer->releaseIP6Addresses(); - u32ContentFlags |= ServiceQueryAnswerType_IP6Address; -#endif - - // Remove content flags for deleted answer parts - pSQAnswer->m_u32ContentFlags &= ~u32ContentFlags; - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(u32ContentFlags), false); - } - } - } // HostDomainAndPort flagged - - // Txts (from TXT) - if ((bResult) && - (pSQAnswer->m_TTLTxts.flagged())) - { - - if (!pSQAnswer->m_TTLTxts.finalTimeoutLevel()) - { - - bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_TXT)) && - (pSQAnswer->m_TTLTxts.restart())); - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: TXT update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" TXTs %s\n"), (bResult ? "OK" : "FAILURE")); - printedInfo = true; - ); - } - else - { - // Timed out! -> Delete - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove TXT answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); - printedInfo = true; - ); - // Delete - pSQAnswer->m_Txts.clear(); - pSQAnswer->m_TTLTxts.set(0); - - // Remove content flags for deleted answer parts - pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_Txts; - - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_Txts), false); - } - } - } // TXTs flagged - - // 3. level answers -#ifdef MDNS_IP4_SUPPORT - // IP4Address (from A) - stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = pSQAnswer->m_pIP4Addresses; - bool bAUpdateQuerySent = false; - while ((pIP4Address) && - (bResult)) - { - - stcMDNSServiceQuery::stcAnswer::stcIP4Address* pNextIP4Address = pIP4Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... - - if (pIP4Address->m_TTL.flagged()) - { - - if (!pIP4Address->m_TTL.finalTimeoutLevel()) // Needs update - { - - if ((bAUpdateQuerySent) || - ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_A)))) - { - - pIP4Address->m_TTL.restart(); - bAUpdateQuerySent = true; - - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: IP4 update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP4 address (%s)\n"), (pIP4Address->m_IPAddress.toString().c_str())); - printedInfo = true; - ); - } - } - else - { - // Timed out! -> Delete - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove IP4 answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP4 address\n")); - printedInfo = true; - ); - pSQAnswer->removeIP4Address(pIP4Address); - if (!pSQAnswer->m_pIP4Addresses) // NO IP4 address left -> remove content flag - { - pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_IP4Address; - } - // Notify client - if (pServiceQuery->m_fnCallback) - { - MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); - pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_IP4Address), false); - } - } - } // IP4 flagged - - pIP4Address = pNextIP4Address; // Next - } // while -#endif -#ifdef MDNS_IP6_SUPPORT - // IP6Address (from AAAA) - stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = pSQAnswer->m_pIP6Addresses; - bool bAAAAUpdateQuerySent = false; - while ((pIP6Address) && - (bResult)) - { - - stcMDNSServiceQuery::stcAnswer::stcIP6Address* pNextIP6Address = pIP6Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... - - if (pIP6Address->m_TTL.flagged()) - { - - if (!pIP6Address->m_TTL.finalTimeoutLevel()) // Needs update - { - - if ((bAAAAUpdateQuerySent) || - ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) - { - - pIP6Address->m_TTL.restart(); - bAAAAUpdateQuerySent = true; - - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: IP6 update scheduled for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), (pIP6Address->m_IPAddress.toString().c_str())); - printedInfo = true; - ); - } - } - else - { - // Timed out! -> Delete - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove answer for ")); - _printRRDomain(pSQAnswer->m_ServiceDomain); - DEBUG_OUTPUT.printf_P(PSTR(" IP6Address\n")); - printedInfo = true; - ); - pSQAnswer->removeIP6Address(pIP6Address); - if (!pSQAnswer->m_pIP6Addresses) // NO IP6 address left -> remove content flag - { - pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_IP6Address; - } - // Notify client - if (pServiceQuery->m_fnCallback) - { - pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP6Address, false, pServiceQuery->m_pUserdata); - } - } - } // IP6 flagged - - pIP6Address = pNextIP6Address; // Next - } // while -#endif - pSQAnswer = pNextSQAnswer; - } - } - } - DEBUG_EX_INFO( - if (printedInfo) -{ - DEBUG_OUTPUT.printf_P(PSTR("\n")); - } - ); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: FAILED!\n")); - }); - return bResult; -} - - -/* - MDNSResponder::_replyMaskForHost - - Determines the relavant host answers for the given question. - - A question for the hostname (eg. esp8266.local) will result in an A/AAAA (eg. 192.168.2.129) reply. - - A question for the reverse IP address (eg. 192-168.2.120.inarpa.arpa) will result in an PTR_IP4 (eg. esp8266.local) reply. - - In addition, a full name match (question domain == host domain) is marked. -*/ -uint8_t MDNSResponder::_replyMaskForHost(const MDNSResponder::stcMDNS_RRHeader& p_RRHeader, - bool* p_pbFullNameMatch /*= 0*/) const -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost\n"));); - - uint8_t u8ReplyMask = 0; - (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); - - if ((DNS_RRCLASS_IN == p_RRHeader.m_Attributes.m_u16Class) || - (DNS_RRCLASS_ANY == p_RRHeader.m_Attributes.m_u16Class)) - { - - if ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // PTR request -#ifdef MDNS_IP4_SUPPORT - stcMDNS_RRDomain reverseIP4Domain; - if ((_buildDomainForReverseIP4(_getResponseMulticastInterface(), reverseIP4Domain)) && - (p_RRHeader.m_Domain == reverseIP4Domain)) - { - // Reverse domain match - u8ReplyMask |= ContentFlag_PTR_IP4; - } -#endif -#ifdef MDNS_IP6_SUPPORT - // TODO -#endif - } // Address qeuest - - stcMDNS_RRDomain hostDomain; - if ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (p_RRHeader.m_Domain == hostDomain)) // Host domain match - { - - (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); - -#ifdef MDNS_IP4_SUPPORT - if ((DNS_RRTYPE_A == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // IP4 address request - u8ReplyMask |= ContentFlag_A; - } -#endif -#ifdef MDNS_IP6_SUPPORT - if ((DNS_RRTYPE_AAAA == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // IP6 address request - u8ReplyMask |= ContentFlag_AAAA; - } -#endif - } - } - else - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); - } - DEBUG_EX_INFO(if (u8ReplyMask) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: 0x%X\n"), u8ReplyMask); - }); - return u8ReplyMask; -} - -/* - MDNSResponder::_replyMaskForService - - Determines the relevant service answers for the given question - - A PTR dns-sd service enum question (_services.dns-sd._udp.local) will result into an PTR_TYPE (eg. _http._tcp.local) answer - - A PTR service type question (eg. _http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer - - A PTR service name question (eg. MyESP._http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer - - A SRV service name question (eg. MyESP._http._tcp.local) will result into an SRV (eg. 5000 MyESP.local) answer - - A TXT service name question (eg. MyESP._http._tcp.local) will result into an TXT (eg. c#=1) answer - - In addition, a full name match (question domain == service instance domain) is marked. -*/ -uint8_t MDNSResponder::_replyMaskForService(const MDNSResponder::stcMDNS_RRHeader& p_RRHeader, - const MDNSResponder::stcMDNSService& p_Service, - bool* p_pbFullNameMatch /*= 0*/) const -{ - - uint8_t u8ReplyMask = 0; - (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); - - if ((DNS_RRCLASS_IN == p_RRHeader.m_Attributes.m_u16Class) || - (DNS_RRCLASS_ANY == p_RRHeader.m_Attributes.m_u16Class)) - { - - stcMDNS_RRDomain DNSSDDomain; - if ((_buildDomainForDNSSD(DNSSDDomain)) && // _services._dns-sd._udp.local - (p_RRHeader.m_Domain == DNSSDDomain) && - ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) - { - // Common service info requested - u8ReplyMask |= ContentFlag_PTR_TYPE; - } - - stcMDNS_RRDomain serviceDomain; - if ((_buildDomainForService(p_Service, false, serviceDomain)) && // eg. _http._tcp.local - (p_RRHeader.m_Domain == serviceDomain) && - ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) - { - // Special service info requested - u8ReplyMask |= ContentFlag_PTR_NAME; - } - - if ((_buildDomainForService(p_Service, true, serviceDomain)) && // eg. MyESP._http._tcp.local - (p_RRHeader.m_Domain == serviceDomain)) - { - - (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); - - if ((DNS_RRTYPE_SRV == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // Instance info SRV requested - u8ReplyMask |= ContentFlag_SRV; - } - if ((DNS_RRTYPE_TXT == p_RRHeader.m_Attributes.m_u16Type) || - (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) - { - // Instance info TXT requested - u8ReplyMask |= ContentFlag_TXT; - } - } - } - else - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForService: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); - } - DEBUG_EX_INFO(if (u8ReplyMask) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForService(%s.%s.%s): 0x%X\n"), p_Service.m_pcName, p_Service.m_pcService, p_Service.m_pcProtocol, u8ReplyMask); - }); - return u8ReplyMask; -} - -} // namespace MDNSImplementation - -} // namespace esp8266 diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp deleted file mode 100644 index d23941ce53..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Helpers.cpp +++ /dev/null @@ -1,850 +0,0 @@ -/* - LEAmDNS_Helpers.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include "lwip/igmp.h" - -#include "LEAmDNS_lwIPdefs.h" -#include "LEAmDNS_Priv.h" - - -namespace -{ - -/* - strrstr (static) - - Backwards search for p_pcPattern in p_pcString - Based on: https://stackoverflow.com/a/1634398/2778898 - -*/ -const char* strrstr(const char*__restrict p_pcString, const char*__restrict p_pcPattern) -{ - - const char* pcResult = 0; - - size_t stStringLength = (p_pcString ? strlen(p_pcString) : 0); - size_t stPatternLength = (p_pcPattern ? strlen(p_pcPattern) : 0); - - if ((stStringLength) && - (stPatternLength) && - (stPatternLength <= stStringLength)) - { - // Pattern is shorter or has the same length tham the string - - for (const char* s = (p_pcString + stStringLength - stPatternLength); s >= p_pcString; --s) - { - if (0 == strncmp(s, p_pcPattern, stPatternLength)) - { - pcResult = s; - break; - } - } - } - return pcResult; -} - - -} // anonymous - - - - - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - HELPERS -*/ - -/* - MDNSResponder::indexDomain (static) - - Updates the given domain 'p_rpcHostname' by appending a delimiter and an index number. - - If the given domain already hasa numeric index (after the given delimiter), this index - incremented. If not, the delimiter and index '2' is added. - - If 'p_rpcHostname' is empty (==0), the given default name 'p_pcDefaultHostname' is used, - if no default is given, 'esp8266' is used. - -*/ -/*static*/ bool MDNSResponder::indexDomain(char*& p_rpcDomain, - const char* p_pcDivider /*= "-"*/, - const char* p_pcDefaultDomain /*= 0*/) -{ - - bool bResult = false; - - // Ensure a divider exists; use '-' as default - const char* pcDivider = (p_pcDivider ? : "-"); - - if (p_rpcDomain) - { - const char* pFoundDivider = strrstr(p_rpcDomain, pcDivider); - if (pFoundDivider) // maybe already extended - { - char* pEnd = 0; - unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10); - if ((ulIndex) && - ((pEnd - p_rpcDomain) == (ptrdiff_t)strlen(p_rpcDomain)) && - (!*pEnd)) // Valid (old) index found - { - - char acIndexBuffer[16]; - sprintf(acIndexBuffer, "%lu", (++ulIndex)); - size_t stLength = ((pFoundDivider - p_rpcDomain + strlen(pcDivider)) + strlen(acIndexBuffer) + 1); - char* pNewHostname = new char[stLength]; - if (pNewHostname) - { - memcpy(pNewHostname, p_rpcDomain, (pFoundDivider - p_rpcDomain + strlen(pcDivider))); - pNewHostname[pFoundDivider - p_rpcDomain + strlen(pcDivider)] = 0; - strcat(pNewHostname, acIndexBuffer); - - delete[] p_rpcDomain; - p_rpcDomain = pNewHostname; - - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); - } - } - else - { - pFoundDivider = 0; // Flag the need to (base) extend the hostname - } - } - - if (!pFoundDivider) // not yet extended (or failed to increment extension) -> start indexing - { - size_t stLength = strlen(p_rpcDomain) + (strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0' - char* pNewHostname = new char[stLength]; - if (pNewHostname) - { - sprintf(pNewHostname, "%s%s2", p_rpcDomain, pcDivider); - - delete[] p_rpcDomain; - p_rpcDomain = pNewHostname; - - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); - } - } - } - else - { - // No given host domain, use base or default - const char* cpcDefaultName = (p_pcDefaultDomain ? : "esp8266"); - - size_t stLength = strlen(cpcDefaultName) + 1; // '\0' - p_rpcDomain = new char[stLength]; - if (p_rpcDomain) - { - strncpy(p_rpcDomain, cpcDefaultName, stLength); - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); - } - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: %s\n"), p_rpcDomain);); - return bResult; -} - - -/* - UDP CONTEXT -*/ - -bool MDNSResponder::_callProcess(void) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf("[MDNSResponder] _callProcess (%lu, triggered by: %s)\n", millis(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str());); - - return _process(false); -} - -/* - MDNSResponder::_allocUDPContext - - (Re-)Creates the one-and-only UDP context for the MDNS responder. - The context is added to the 'multicast'-group and listens to the MDNS port (5353). - The travel-distance for multicast messages is set to 1 (local, via MDNS_MULTICAST_TTL). - Messages are received via the MDNSResponder '_update' function. CAUTION: This function - is called from the WiFi stack side of the ESP stack system. - -*/ -bool MDNSResponder::_allocUDPContext(void) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.println("[MDNSResponder] _allocUDPContext");); - - bool bResult = false; - - _releaseUDPContext(); - -#ifdef MDNS_IP4_SUPPORT - ip_addr_t multicast_addr = DNS_MQUERY_IPV4_GROUP_INIT; -#endif -#ifdef MDNS_IP6_SUPPORT - //TODO: set multicast address (lwip_joingroup() is IPv4 only at the time of writing) - multicast_addr.addr = DNS_MQUERY_IPV6_GROUP_INIT; -#endif - if (ERR_OK == igmp_joingroup(ip_2_ip4(&m_netif->ip_addr), ip_2_ip4(&multicast_addr))) - { - m_pUDPContext = new UdpContext; - m_pUDPContext->ref(); - - if (m_pUDPContext->listen(IP4_ADDR_ANY, DNS_MQUERY_PORT)) - { - m_pUDPContext->setMulticastTTL(MDNS_MULTICAST_TTL); - m_pUDPContext->onRx(std::bind(&MDNSResponder::_callProcess, this)); - - bResult = m_pUDPContext->connect(&multicast_addr, DNS_MQUERY_PORT); - } - } - return bResult; -} - -/* - MDNSResponder::_releaseUDPContext -*/ -bool MDNSResponder::_releaseUDPContext(void) -{ - - if (m_pUDPContext) - { - m_pUDPContext->unref(); - m_pUDPContext = 0; - } - return true; -} - - -/* - SERVICE QUERY -*/ - -/* - MDNSResponder::_allocServiceQuery -*/ -MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_allocServiceQuery(void) -{ - - stcMDNSServiceQuery* pServiceQuery = new stcMDNSServiceQuery; - if (pServiceQuery) - { - // Link to query list - pServiceQuery->m_pNext = m_pServiceQueries; - m_pServiceQueries = pServiceQuery; - } - return m_pServiceQueries; -} - -/* - MDNSResponder::_removeServiceQuery -*/ -bool MDNSResponder::_removeServiceQuery(MDNSResponder::stcMDNSServiceQuery* p_pServiceQuery) -{ - - bool bResult = false; - - if (p_pServiceQuery) - { - stcMDNSServiceQuery* pPred = m_pServiceQueries; - while ((pPred) && - (pPred->m_pNext != p_pServiceQuery)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pServiceQuery->m_pNext; - delete p_pServiceQuery; - bResult = true; - } - else // No predecesor - { - if (m_pServiceQueries == p_pServiceQuery) - { - m_pServiceQueries = p_pServiceQuery->m_pNext; - delete p_pServiceQuery; - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseServiceQuery: INVALID service query!");); - } - } - } - return bResult; -} - -/* - MDNSResponder::_removeLegacyServiceQuery -*/ -bool MDNSResponder::_removeLegacyServiceQuery(void) -{ - - stcMDNSServiceQuery* pLegacyServiceQuery = _findLegacyServiceQuery(); - return (pLegacyServiceQuery ? _removeServiceQuery(pLegacyServiceQuery) : true); -} - -/* - MDNSResponder::_findServiceQuery - - 'Convert' hMDNSServiceQuery to stcMDNSServiceQuery* (ensure existance) - -*/ -MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) -{ - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - if ((hMDNSServiceQuery)pServiceQuery == p_hServiceQuery) - { - break; - } - pServiceQuery = pServiceQuery->m_pNext; - } - return pServiceQuery; -} - -/* - MDNSResponder::_findLegacyServiceQuery -*/ -MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findLegacyServiceQuery(void) -{ - - stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; - while (pServiceQuery) - { - if (pServiceQuery->m_bLegacyQuery) - { - break; - } - pServiceQuery = pServiceQuery->m_pNext; - } - return pServiceQuery; -} - -/* - MDNSResponder::_releaseServiceQueries -*/ -bool MDNSResponder::_releaseServiceQueries(void) -{ - while (m_pServiceQueries) - { - stcMDNSServiceQuery* pNext = m_pServiceQueries->m_pNext; - delete m_pServiceQueries; - m_pServiceQueries = pNext; - } - return true; -} - -/* - MDNSResponder::_findNextServiceQueryByServiceType -*/ -MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceTypeDomain, - const stcMDNSServiceQuery* p_pPrevServiceQuery) -{ - stcMDNSServiceQuery* pMatchingServiceQuery = 0; - - stcMDNSServiceQuery* pServiceQuery = (p_pPrevServiceQuery ? p_pPrevServiceQuery->m_pNext : m_pServiceQueries); - while (pServiceQuery) - { - if (p_ServiceTypeDomain == pServiceQuery->m_ServiceTypeDomain) - { - pMatchingServiceQuery = pServiceQuery; - break; - } - pServiceQuery = pServiceQuery->m_pNext; - } - return pMatchingServiceQuery; -} - - -/* - HOSTNAME -*/ - -/* - MDNSResponder::_setHostname -*/ -bool MDNSResponder::_setHostname(const char* p_pcHostname) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _allocHostname (%s)\n"), p_pcHostname);); - - bool bResult = false; - - _releaseHostname(); - - size_t stLength = 0; - if ((p_pcHostname) && - (MDNS_DOMAIN_LABEL_MAXLENGTH >= (stLength = strlen(p_pcHostname)))) // char max size for a single label - { - // Copy in hostname characters as lowercase - if ((bResult = (0 != (m_pcHostname = new char[stLength + 1])))) - { -#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME - size_t i = 0; - for (; i < stLength; ++i) - { - m_pcHostname[i] = (isupper(p_pcHostname[i]) ? tolower(p_pcHostname[i]) : p_pcHostname[i]); - } - m_pcHostname[i] = 0; -#else - strncpy(m_pcHostname, p_pcHostname, (stLength + 1)); -#endif - } - } - return bResult; -} - -/* - MDNSResponder::_releaseHostname -*/ -bool MDNSResponder::_releaseHostname(void) -{ - - if (m_pcHostname) - { - delete[] m_pcHostname; - m_pcHostname = 0; - } - return true; -} - - -/* - SERVICE -*/ - -/* - MDNSResponder::_allocService -*/ -MDNSResponder::stcMDNSService* MDNSResponder::_allocService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol, - uint16_t p_u16Port) -{ - - stcMDNSService* pService = 0; - if (((!p_pcName) || - (MDNS_DOMAIN_LABEL_MAXLENGTH >= strlen(p_pcName))) && - (p_pcService) && - (MDNS_SERVICE_NAME_LENGTH >= strlen(p_pcService)) && - (p_pcProtocol) && - (MDNS_SERVICE_PROTOCOL_LENGTH >= strlen(p_pcProtocol)) && - (p_u16Port) && - (0 != (pService = new stcMDNSService)) && - (pService->setName(p_pcName ? : m_pcHostname)) && - (pService->setService(p_pcService)) && - (pService->setProtocol(p_pcProtocol))) - { - - pService->m_bAutoName = (0 == p_pcName); - pService->m_u16Port = p_u16Port; - - // Add to list (or start list) - pService->m_pNext = m_pServices; - m_pServices = pService; - } - return pService; -} - -/* - MDNSResponder::_releaseService -*/ -bool MDNSResponder::_releaseService(MDNSResponder::stcMDNSService* p_pService) -{ - - bool bResult = false; - - if (p_pService) - { - stcMDNSService* pPred = m_pServices; - while ((pPred) && - (pPred->m_pNext != p_pService)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pService->m_pNext; - delete p_pService; - bResult = true; - } - else // No predecesor - { - if (m_pServices == p_pService) - { - m_pServices = p_pService->m_pNext; - delete p_pService; - bResult = true; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseService: INVALID service!");); - } - } - } - return bResult; -} - -/* - MDNSResponder::_releaseServices -*/ -bool MDNSResponder::_releaseServices(void) -{ - - stcMDNSService* pService = m_pServices; - while (pService) - { - _releaseService(pService); - pService = m_pServices; - } - return true; -} - -/* - MDNSResponder::_findService -*/ -MDNSResponder::stcMDNSService* MDNSResponder::_findService(const char* p_pcName, - const char* p_pcService, - const char* p_pcProtocol) -{ - - stcMDNSService* pService = m_pServices; - while (pService) - { - if ((0 == strcmp(pService->m_pcName, p_pcName)) && - (0 == strcmp(pService->m_pcService, p_pcService)) && - (0 == strcmp(pService->m_pcProtocol, p_pcProtocol))) - { - - break; - } - pService = pService->m_pNext; - } - return pService; -} - -/* - MDNSResponder::_findService -*/ -MDNSResponder::stcMDNSService* MDNSResponder::_findService(const MDNSResponder::hMDNSService p_hService) -{ - - stcMDNSService* pService = m_pServices; - while (pService) - { - if (p_hService == (hMDNSService)pService) - { - break; - } - pService = pService->m_pNext; - } - return pService; -} - - -/* - SERVICE TXT -*/ - -/* - MDNSResponder::_allocServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_allocServiceTxt(MDNSResponder::stcMDNSService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp) -{ - - stcMDNSServiceTxt* pTxt = 0; - - if ((p_pService) && - (p_pcKey) && - (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() + - 1 + // Length byte - (p_pcKey ? strlen(p_pcKey) : 0) + - 1 + // '=' - (p_pcValue ? strlen(p_pcValue) : 0)))) - { - - pTxt = new stcMDNSServiceTxt; - if (pTxt) - { - size_t stLength = (p_pcKey ? strlen(p_pcKey) : 0); - pTxt->m_pcKey = new char[stLength + 1]; - if (pTxt->m_pcKey) - { - strncpy(pTxt->m_pcKey, p_pcKey, stLength); pTxt->m_pcKey[stLength] = 0; - } - - if (p_pcValue) - { - stLength = (p_pcValue ? strlen(p_pcValue) : 0); - pTxt->m_pcValue = new char[stLength + 1]; - if (pTxt->m_pcValue) - { - strncpy(pTxt->m_pcValue, p_pcValue, stLength); pTxt->m_pcValue[stLength] = 0; - } - } - pTxt->m_bTemp = p_bTemp; - - // Add to list (or start list) - p_pService->m_Txts.add(pTxt); - } - } - return pTxt; -} - -/* - MDNSResponder::_releaseServiceTxt -*/ -bool MDNSResponder::_releaseServiceTxt(MDNSResponder::stcMDNSService* p_pService, - MDNSResponder::stcMDNSServiceTxt* p_pTxt) -{ - - return ((p_pService) && - (p_pTxt) && - (p_pService->m_Txts.remove(p_pTxt))); -} - -/* - MDNSResponder::_updateServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_updateServiceTxt(MDNSResponder::stcMDNSService* p_pService, - MDNSResponder::stcMDNSServiceTxt* p_pTxt, - const char* p_pcValue, - bool p_bTemp) -{ - - if ((p_pService) && - (p_pTxt) && - (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() - - (p_pTxt->m_pcValue ? strlen(p_pTxt->m_pcValue) : 0) + - (p_pcValue ? strlen(p_pcValue) : 0)))) - { - p_pTxt->update(p_pcValue); - p_pTxt->m_bTemp = p_bTemp; - } - return p_pTxt; -} - -/* - MDNSResponder::_findServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, - const char* p_pcKey) -{ - - return (p_pService ? p_pService->m_Txts.find(p_pcKey) : 0); -} - -/* - MDNSResponder::_findServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, - const hMDNSTxt p_hTxt) -{ - - return (((p_pService) && (p_hTxt)) ? p_pService->m_Txts.find((stcMDNSServiceTxt*)p_hTxt) : 0); -} - -/* - MDNSResponder::_addServiceTxt -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_addServiceTxt(MDNSResponder::stcMDNSService* p_pService, - const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp) -{ - stcMDNSServiceTxt* pResult = 0; - - if ((p_pService) && - (p_pcKey) && - (strlen(p_pcKey))) - { - - stcMDNSServiceTxt* pTxt = p_pService->m_Txts.find(p_pcKey); - if (pTxt) - { - pResult = _updateServiceTxt(p_pService, pTxt, p_pcValue, p_bTemp); - } - else - { - pResult = _allocServiceTxt(p_pService, p_pcKey, p_pcValue, p_bTemp); - } - } - return pResult; -} - -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_answerKeyValue(const hMDNSServiceQuery p_hServiceQuery, - const uint32_t p_u32AnswerIndex) -{ - stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); - stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); - // Fill m_pcTxts (if not already done) - return (pSQAnswer) ? pSQAnswer->m_Txts.m_pTxts : 0; -} - -/* - MDNSResponder::_collectServiceTxts -*/ -bool MDNSResponder::_collectServiceTxts(MDNSResponder::stcMDNSService& p_rService) -{ - - // Call Dynamic service callbacks - if (m_fnServiceTxtCallback) - { - m_fnServiceTxtCallback((hMDNSService)&p_rService); - } - if (p_rService.m_fnTxtCallback) - { - p_rService.m_fnTxtCallback((hMDNSService)&p_rService); - } - return true; -} - -/* - MDNSResponder::_releaseTempServiceTxts -*/ -bool MDNSResponder::_releaseTempServiceTxts(MDNSResponder::stcMDNSService& p_rService) -{ - - return (p_rService.m_Txts.removeTempTxts()); -} - - -/* - MISC -*/ - -#ifdef DEBUG_ESP_MDNS_RESPONDER -/* - MDNSResponder::_printRRDomain -*/ -bool MDNSResponder::_printRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_RRDomain) const -{ - - //DEBUG_OUTPUT.printf_P(PSTR("Domain: ")); - - const char* pCursor = p_RRDomain.m_acName; - uint8_t u8Length = *pCursor++; - if (u8Length) - { - while (u8Length) - { - for (uint8_t u = 0; u < u8Length; ++u) - { - DEBUG_OUTPUT.printf_P(PSTR("%c"), *(pCursor++)); - } - u8Length = *pCursor++; - if (u8Length) - { - DEBUG_OUTPUT.printf_P(PSTR(".")); - } - } - } - else // empty domain - { - DEBUG_OUTPUT.printf_P(PSTR("-empty-")); - } - //DEBUG_OUTPUT.printf_P(PSTR("\n")); - - return true; -} - -/* - MDNSResponder::_printRRAnswer -*/ -bool MDNSResponder::_printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const -{ - - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] RRAnswer: ")); - _printRRDomain(p_RRAnswer.m_Header.m_Domain); - DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, "), p_RRAnswer.m_Header.m_Attributes.m_u16Type, p_RRAnswer.m_Header.m_Attributes.m_u16Class, p_RRAnswer.m_u32TTL); - switch (p_RRAnswer.m_Header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag - { -#ifdef MDNS_IP4_SUPPORT - case DNS_RRTYPE_A: - DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((const stcMDNS_RRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str()); - break; -#endif - case DNS_RRTYPE_PTR: - DEBUG_OUTPUT.printf_P(PSTR("PTR ")); - _printRRDomain(((const stcMDNS_RRAnswerPTR*)&p_RRAnswer)->m_PTRDomain); - break; - case DNS_RRTYPE_TXT: - { - size_t stTxtLength = ((const stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength(); - char* pTxts = new char[stTxtLength]; - if (pTxts) - { - ((/*const c_str()!!*/stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts); - DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); - delete[] pTxts; - } - break; - } -#ifdef MDNS_IP6_SUPPORT - case DNS_RRTYPE_AAAA: - DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); - break; -#endif - case DNS_RRTYPE_SRV: - DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_u16Port); - _printRRDomain(((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_SRVDomain); - break; - default: - DEBUG_OUTPUT.printf_P(PSTR("generic ")); - break; - } - DEBUG_OUTPUT.printf_P(PSTR("\n")); - - return true; -} -#endif - -} // namespace MDNSImplementation - -} // namespace esp8266 - - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h deleted file mode 100644 index cc56b133a9..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Priv.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - LEAmDNS_Priv.h - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#ifndef MDNS_PRIV_H -#define MDNS_PRIV_H - -namespace esp8266 -{ - -/* - LEAmDNS -*/ - -namespace MDNSImplementation -{ - -// Enable class debug functions -#define ESP_8266_MDNS_INCLUDE -//#define DEBUG_ESP_MDNS_RESPONDER - -#if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS) -#define DEBUG_ESP_MDNS_RESPONDER -#endif - -#ifndef LWIP_OPEN_SRC -#define LWIP_OPEN_SRC -#endif - -// -// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing -// This allows to drive the responder in a environment, where 'update()' isn't called in the loop -//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE - -// Enable/disable debug trace macros -#ifdef DEBUG_ESP_MDNS_RESPONDER -#define DEBUG_ESP_MDNS_INFO -#define DEBUG_ESP_MDNS_ERR -#define DEBUG_ESP_MDNS_TX -#define DEBUG_ESP_MDNS_RX -#endif - -#ifdef DEBUG_ESP_MDNS_RESPONDER -#ifdef DEBUG_ESP_MDNS_INFO -#define DEBUG_EX_INFO(A) A -#else -#define DEBUG_EX_INFO(A) do { (void)0; } while (0) -#endif -#ifdef DEBUG_ESP_MDNS_ERR -#define DEBUG_EX_ERR(A) A -#else -#define DEBUG_EX_ERR(A) do { (void)0; } while (0) -#endif -#ifdef DEBUG_ESP_MDNS_TX -#define DEBUG_EX_TX(A) A -#else -#define DEBUG_EX_TX(A) do { (void)0; } while (0) -#endif -#ifdef DEBUG_ESP_MDNS_RX -#define DEBUG_EX_RX(A) A -#else -#define DEBUG_EX_RX(A) do { (void)0; } while (0) -#endif - -#ifdef DEBUG_ESP_PORT -#define DEBUG_OUTPUT DEBUG_ESP_PORT -#else -#define DEBUG_OUTPUT Serial -#endif -#else -#define DEBUG_EX_INFO(A) do { (void)0; } while (0) -#define DEBUG_EX_ERR(A) do { (void)0; } while (0) -#define DEBUG_EX_TX(A) do { (void)0; } while (0) -#define DEBUG_EX_RX(A) do { (void)0; } while (0) -#endif - - -/* Replaced by 'lwip/prot/dns.h' definitions - #ifdef MDNS_IP4_SUPPORT - #define MDNS_MULTICAST_ADDR_IP4 (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT - #endif - #ifdef MDNS_IP6_SUPPORT - #define MDNS_MULTICAST_ADDR_IP6 (IPAddress("FF02::FB")) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT - #endif*/ -//#define MDNS_MULTICAST_PORT 5353 - -/* - This is NOT the TTL (Time-To-Live) for MDNS records, but the - subnet level distance MDNS records should travel. - 1 sets the subnet distance to 'local', which is default for MDNS. - (Btw.: 255 would set it to 'as far as possible' -> internet) - - However, RFC 3171 seems to force 255 instead -*/ -#define MDNS_MULTICAST_TTL 255/*1*/ - -/* - This is the MDNS record TTL - Host level records are set to 2min (120s) - service level records are set to 75min (4500s) -*/ -#define MDNS_HOST_TTL 120 -#define MDNS_SERVICE_TTL 4500 - -/* - Compressed labels are flaged by the two topmost bits of the length byte being set -*/ -#define MDNS_DOMAIN_COMPRESS_MARK 0xC0 -/* - Avoid endless recursion because of malformed compressed labels -*/ -#define MDNS_DOMAIN_MAX_REDIRCTION 6 - -/* - Default service priority and weight in SRV answers -*/ -#define MDNS_SRV_PRIORITY 0 -#define MDNS_SRV_WEIGHT 0 - -/* - Delay between and number of probes for host and service domains - Delay between and number of announces for host and service domains - Delay between and number of service queries; the delay is multiplied by the resent number in '_checkServiceQueryCache' -*/ -#define MDNS_PROBE_DELAY 250 -#define MDNS_PROBE_COUNT 3 -#define MDNS_ANNOUNCE_DELAY 1000 -#define MDNS_ANNOUNCE_COUNT 8 -#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5 -#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000 - - -/* - Force host domain to use only lowercase letters -*/ -//#define MDNS_FORCE_LOWERCASE_HOSTNAME - -/* - Enable/disable the usage of the F() macro in debug trace printf calls. - There needs to be an PGM comptible printf function to use this. - - USE_PGM_PRINTF and F -*/ -#define USE_PGM_PRINTF - -#ifdef USE_PGM_PRINTF -#else -#ifdef F -#undef F -#endif -#define F(A) A -#endif - -} // namespace MDNSImplementation - -} // namespace esp8266 - -// Include the main header, so the submodlues only need to include this header -#include "LEAmDNS.h" - - -#endif // MDNS_PRIV_H diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp deleted file mode 100644 index ce475de3ba..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Structs.cpp +++ /dev/null @@ -1,2476 +0,0 @@ -/* - LEAmDNS_Structs.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#include "LEAmDNS_Priv.h" -#include "LEAmDNS_lwIPdefs.h" - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - STRUCTS -*/ - -/** - MDNSResponder::stcMDNSServiceTxt - - One MDNS TXT item. - m_pcValue may be '\0'. - Objects can be chained together (list, m_pNext). - A 'm_bTemp' flag differentiates between static and dynamic items. - Output as byte array 'c#=1' is supported. -*/ - -/* - MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt constructor -*/ -MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const char* p_pcKey /*= 0*/, - const char* p_pcValue /*= 0*/, - bool p_bTemp /*= false*/) - : m_pNext(0), - m_pcKey(0), - m_pcValue(0), - m_bTemp(p_bTemp) -{ - - setKey(p_pcKey); - setValue(p_pcValue); -} - -/* - MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt copy-constructor -*/ -MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const MDNSResponder::stcMDNSServiceTxt& p_Other) - : m_pNext(0), - m_pcKey(0), - m_pcValue(0), - m_bTemp(false) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt destructor -*/ -MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceTxt::operator= -*/ -MDNSResponder::stcMDNSServiceTxt& MDNSResponder::stcMDNSServiceTxt::operator=(const MDNSResponder::stcMDNSServiceTxt& p_Other) -{ - - if (&p_Other != this) - { - clear(); - set(p_Other.m_pcKey, p_Other.m_pcValue, p_Other.m_bTemp); - } - return *this; -} - -/* - MDNSResponder::stcMDNSServiceTxt::clear -*/ -bool MDNSResponder::stcMDNSServiceTxt::clear(void) -{ - - releaseKey(); - releaseValue(); - return true; -} - -/* - MDNSResponder::stcMDNSServiceTxt::allocKey -*/ -char* MDNSResponder::stcMDNSServiceTxt::allocKey(size_t p_stLength) -{ - - releaseKey(); - if (p_stLength) - { - m_pcKey = new char[p_stLength + 1]; - } - return m_pcKey; -} - -/* - MDNSResponder::stcMDNSServiceTxt::setKey -*/ -bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey, - size_t p_stLength) -{ - - bool bResult = false; - - releaseKey(); - if (p_stLength) - { - if (allocKey(p_stLength)) - { - strncpy(m_pcKey, p_pcKey, p_stLength); - m_pcKey[p_stLength] = 0; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxt::setKey -*/ -bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey) -{ - - return setKey(p_pcKey, (p_pcKey ? strlen(p_pcKey) : 0)); -} - -/* - MDNSResponder::stcMDNSServiceTxt::releaseKey -*/ -bool MDNSResponder::stcMDNSServiceTxt::releaseKey(void) -{ - - if (m_pcKey) - { - delete[] m_pcKey; - m_pcKey = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceTxt::allocValue -*/ -char* MDNSResponder::stcMDNSServiceTxt::allocValue(size_t p_stLength) -{ - - releaseValue(); - if (p_stLength) - { - m_pcValue = new char[p_stLength + 1]; - } - return m_pcValue; -} - -/* - MDNSResponder::stcMDNSServiceTxt::setValue -*/ -bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue, - size_t p_stLength) -{ - - bool bResult = false; - - releaseValue(); - if (p_stLength) - { - if (allocValue(p_stLength)) - { - strncpy(m_pcValue, p_pcValue, p_stLength); - m_pcValue[p_stLength] = 0; - bResult = true; - } - } - else // No value -> also OK - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxt::setValue -*/ -bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue) -{ - - return setValue(p_pcValue, (p_pcValue ? strlen(p_pcValue) : 0)); -} - -/* - MDNSResponder::stcMDNSServiceTxt::releaseValue -*/ -bool MDNSResponder::stcMDNSServiceTxt::releaseValue(void) -{ - - if (m_pcValue) - { - delete[] m_pcValue; - m_pcValue = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceTxt::set -*/ -bool MDNSResponder::stcMDNSServiceTxt::set(const char* p_pcKey, - const char* p_pcValue, - bool p_bTemp /*= false*/) -{ - - m_bTemp = p_bTemp; - return ((setKey(p_pcKey)) && - (setValue(p_pcValue))); -} - -/* - MDNSResponder::stcMDNSServiceTxt::update -*/ -bool MDNSResponder::stcMDNSServiceTxt::update(const char* p_pcValue) -{ - - return setValue(p_pcValue); -} - -/* - MDNSResponder::stcMDNSServiceTxt::length - - length of eg. 'c#=1' without any closing '\0' -*/ -size_t MDNSResponder::stcMDNSServiceTxt::length(void) const -{ - - size_t stLength = 0; - if (m_pcKey) - { - stLength += strlen(m_pcKey); // Key - stLength += 1; // '=' - stLength += (m_pcValue ? strlen(m_pcValue) : 0); // Value - } - return stLength; -} - - -/** - MDNSResponder::stcMDNSServiceTxts - - A list of zero or more MDNS TXT items. - Dynamic TXT items can be removed by 'removeTempTxts'. - A TXT item can be looke up by its 'key' member. - Export as ';'-separated byte array is supported. - Export as 'length byte coded' byte array is supported. - Comparision ((all A TXT items in B and equal) AND (all B TXT items in A and equal)) is supported. - -*/ - -/* - MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts contructor -*/ -MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(void) - : m_pTxts(0) -{ - -} - -/* - MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts copy-constructor -*/ -MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other) - : m_pTxts(0) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts destructor -*/ -MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceTxts::operator= -*/ -MDNSResponder::stcMDNSServiceTxts& MDNSResponder::stcMDNSServiceTxts::operator=(const stcMDNSServiceTxts& p_Other) -{ - - if (this != &p_Other) - { - clear(); - - for (stcMDNSServiceTxt* pOtherTxt = p_Other.m_pTxts; pOtherTxt; pOtherTxt = pOtherTxt->m_pNext) - { - add(new stcMDNSServiceTxt(*pOtherTxt)); - } - } - return *this; -} - -/* - MDNSResponder::stcMDNSServiceTxts::clear -*/ -bool MDNSResponder::stcMDNSServiceTxts::clear(void) -{ - - while (m_pTxts) - { - stcMDNSServiceTxt* pNext = m_pTxts->m_pNext; - delete m_pTxts; - m_pTxts = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceTxts::add -*/ -bool MDNSResponder::stcMDNSServiceTxts::add(MDNSResponder::stcMDNSServiceTxt* p_pTxt) -{ - - bool bResult = false; - - if (p_pTxt) - { - p_pTxt->m_pNext = m_pTxts; - m_pTxts = p_pTxt; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::remove -*/ -bool MDNSResponder::stcMDNSServiceTxts::remove(stcMDNSServiceTxt* p_pTxt) -{ - - bool bResult = false; - - if (p_pTxt) - { - stcMDNSServiceTxt* pPred = m_pTxts; - while ((pPred) && - (pPred->m_pNext != p_pTxt)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pTxt->m_pNext; - delete p_pTxt; - bResult = true; - } - else if (m_pTxts == p_pTxt) // No predecesor, but first item - { - m_pTxts = p_pTxt->m_pNext; - delete p_pTxt; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::removeTempTxts -*/ -bool MDNSResponder::stcMDNSServiceTxts::removeTempTxts(void) -{ - - bool bResult = true; - - stcMDNSServiceTxt* pTxt = m_pTxts; - while ((bResult) && - (pTxt)) - { - stcMDNSServiceTxt* pNext = pTxt->m_pNext; - if (pTxt->m_bTemp) - { - bResult = remove(pTxt); - } - pTxt = pNext; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::find -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) -{ - - stcMDNSServiceTxt* pResult = 0; - - for (stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if ((p_pcKey) && - (0 == strcmp(pTxt->m_pcKey, p_pcKey))) - { - pResult = pTxt; - break; - } - } - return pResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::find -*/ -const MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) const -{ - - const stcMDNSServiceTxt* pResult = 0; - - for (const stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if ((p_pcKey) && - (0 == strcmp(pTxt->m_pcKey, p_pcKey))) - { - - pResult = pTxt; - break; - } - } - return pResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::find -*/ -MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const stcMDNSServiceTxt* p_pTxt) -{ - - stcMDNSServiceTxt* pResult = 0; - - for (stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) - { - if (p_pTxt == pTxt) - { - pResult = pTxt; - break; - } - } - return pResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::length -*/ -uint16_t MDNSResponder::stcMDNSServiceTxts::length(void) const -{ - - uint16_t u16Length = 0; - - stcMDNSServiceTxt* pTxt = m_pTxts; - while (pTxt) - { - u16Length += 1; // Length byte - u16Length += pTxt->length(); // Text - pTxt = pTxt->m_pNext; - } - return u16Length; -} - -/* - MDNSResponder::stcMDNSServiceTxts::c_strLength - - (incl. closing '\0'). Length bytes place is used for delimiting ';' and closing '\0' -*/ -size_t MDNSResponder::stcMDNSServiceTxts::c_strLength(void) const -{ - - return length(); -} - -/* - MDNSResponder::stcMDNSServiceTxts::c_str -*/ -bool MDNSResponder::stcMDNSServiceTxts::c_str(char* p_pcBuffer) -{ - - bool bResult = false; - - if (p_pcBuffer) - { - bResult = true; - - *p_pcBuffer = 0; - for (stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - size_t stLength; - if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) - { - if (pTxt != m_pTxts) - { - *p_pcBuffer++ = ';'; - } - strncpy(p_pcBuffer, pTxt->m_pcKey, stLength); p_pcBuffer[stLength] = 0; - p_pcBuffer += stLength; - *p_pcBuffer++ = '='; - if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) - { - strncpy(p_pcBuffer, pTxt->m_pcValue, stLength); p_pcBuffer[stLength] = 0; - p_pcBuffer += stLength; - } - } - } - *p_pcBuffer++ = 0; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::bufferLength - - (incl. closing '\0'). -*/ -size_t MDNSResponder::stcMDNSServiceTxts::bufferLength(void) const -{ - - return (length() + 1); -} - -/* - MDNSResponder::stcMDNSServiceTxts::toBuffer -*/ -bool MDNSResponder::stcMDNSServiceTxts::buffer(char* p_pcBuffer) -{ - - bool bResult = false; - - if (p_pcBuffer) - { - bResult = true; - - *p_pcBuffer = 0; - for (stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - *(unsigned char*)p_pcBuffer++ = pTxt->length(); - size_t stLength; - if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) - { - memcpy(p_pcBuffer, pTxt->m_pcKey, stLength); - p_pcBuffer += stLength; - *p_pcBuffer++ = '='; - if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) - { - memcpy(p_pcBuffer, pTxt->m_pcValue, stLength); - p_pcBuffer += stLength; - } - } - } - *p_pcBuffer++ = 0; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::compare -*/ -bool MDNSResponder::stcMDNSServiceTxts::compare(const MDNSResponder::stcMDNSServiceTxts& p_Other) const -{ - - bool bResult = false; - - if ((bResult = (length() == p_Other.length()))) - { - // Compare A->B - for (const stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - const stcMDNSServiceTxt* pOtherTxt = p_Other.find(pTxt->m_pcKey); - bResult = ((pOtherTxt) && - (pTxt->m_pcValue) && - (pOtherTxt->m_pcValue) && - (strlen(pTxt->m_pcValue) == strlen(pOtherTxt->m_pcValue)) && - (0 == strcmp(pTxt->m_pcValue, pOtherTxt->m_pcValue))); - } - // Compare B->A - for (const stcMDNSServiceTxt* pOtherTxt = p_Other.m_pTxts; ((bResult) && (pOtherTxt)); pOtherTxt = pOtherTxt->m_pNext) - { - const stcMDNSServiceTxt* pTxt = find(pOtherTxt->m_pcKey); - bResult = ((pTxt) && - (pOtherTxt->m_pcValue) && - (pTxt->m_pcValue) && - (strlen(pOtherTxt->m_pcValue) == strlen(pTxt->m_pcValue)) && - (0 == strcmp(pOtherTxt->m_pcValue, pTxt->m_pcValue))); - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceTxts::operator== -*/ -bool MDNSResponder::stcMDNSServiceTxts::operator==(const stcMDNSServiceTxts& p_Other) const -{ - - return compare(p_Other); -} - -/* - MDNSResponder::stcMDNSServiceTxts::operator!= -*/ -bool MDNSResponder::stcMDNSServiceTxts::operator!=(const stcMDNSServiceTxts& p_Other) const -{ - - return !compare(p_Other); -} - - -/** - MDNSResponder::stcMDNS_MsgHeader - - A MDNS message haeder. - -*/ - -/* - MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader -*/ -MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader(uint16_t p_u16ID /*= 0*/, - bool p_bQR /*= false*/, - unsigned char p_ucOpcode /*= 0*/, - bool p_bAA /*= false*/, - bool p_bTC /*= false*/, - bool p_bRD /*= false*/, - bool p_bRA /*= false*/, - unsigned char p_ucRCode /*= 0*/, - uint16_t p_u16QDCount /*= 0*/, - uint16_t p_u16ANCount /*= 0*/, - uint16_t p_u16NSCount /*= 0*/, - uint16_t p_u16ARCount /*= 0*/) - : m_u16ID(p_u16ID), - m_1bQR(p_bQR), m_4bOpcode(p_ucOpcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), - m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_ucRCode), - m_u16QDCount(p_u16QDCount), - m_u16ANCount(p_u16ANCount), - m_u16NSCount(p_u16NSCount), - m_u16ARCount(p_u16ARCount) -{ - -} - - -/** - MDNSResponder::stcMDNS_RRDomain - - A MDNS domain object. - The labels of the domain are stored (DNS-like encoded) in 'm_acName': - [length byte]varlength label[length byte]varlength label[0] - 'm_u16NameLength' stores the used length of 'm_acName'. - Dynamic label addition is supported. - Comparison is supported. - Export as byte array 'esp8266.local' is supported. - -*/ - -/* - MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain constructor -*/ -MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(void) - : m_u16NameLength(0) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain copy-constructor -*/ -MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other) - : m_u16NameLength(0) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRDomain::operator = -*/ -MDNSResponder::stcMDNS_RRDomain& MDNSResponder::stcMDNS_RRDomain::operator=(const stcMDNS_RRDomain& p_Other) -{ - - if (&p_Other != this) - { - memcpy(m_acName, p_Other.m_acName, sizeof(m_acName)); - m_u16NameLength = p_Other.m_u16NameLength; - } - return *this; -} - -/* - MDNSResponder::stcMDNS_RRDomain::clear -*/ -bool MDNSResponder::stcMDNS_RRDomain::clear(void) -{ - - memset(m_acName, 0, sizeof(m_acName)); - m_u16NameLength = 0; - return true; -} - -/* - MDNSResponder::stcMDNS_RRDomain::addLabel -*/ -bool MDNSResponder::stcMDNS_RRDomain::addLabel(const char* p_pcLabel, - bool p_bPrependUnderline /*= false*/) -{ - - bool bResult = false; - - size_t stLength = (p_pcLabel - ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) - : 0); - if ((MDNS_DOMAIN_LABEL_MAXLENGTH >= stLength) && - (MDNS_DOMAIN_MAXLENGTH >= (m_u16NameLength + (1 + stLength)))) - { - // Length byte - m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! - ++m_u16NameLength; - // Label - if (stLength) - { - if (p_bPrependUnderline) - { - m_acName[m_u16NameLength++] = '_'; - --stLength; - } - strncpy(&(m_acName[m_u16NameLength]), p_pcLabel, stLength); m_acName[m_u16NameLength + stLength] = 0; - m_u16NameLength += stLength; - } - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNS_RRDomain::compare -*/ -bool MDNSResponder::stcMDNS_RRDomain::compare(const stcMDNS_RRDomain& p_Other) const -{ - - bool bResult = false; - - if (m_u16NameLength == p_Other.m_u16NameLength) - { - const char* pT = m_acName; - const char* pO = p_Other.m_acName; - while ((pT) && - (pO) && - (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND - (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content - { - if (*((unsigned char*)pT)) // Not 0 - { - pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and lenght - pO += (1 + * ((unsigned char*)pO)); - } - else // Is 0 -> Successfully reached the end - { - bResult = true; - break; - } - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNS_RRDomain::operator == -*/ -bool MDNSResponder::stcMDNS_RRDomain::operator==(const stcMDNS_RRDomain& p_Other) const -{ - - return compare(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRDomain::operator != -*/ -bool MDNSResponder::stcMDNS_RRDomain::operator!=(const stcMDNS_RRDomain& p_Other) const -{ - - return !compare(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRDomain::operator > -*/ -bool MDNSResponder::stcMDNS_RRDomain::operator>(const stcMDNS_RRDomain& p_Other) const -{ - - // TODO: Check, if this is a good idea... - return !compare(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRDomain::c_strLength -*/ -size_t MDNSResponder::stcMDNS_RRDomain::c_strLength(void) const -{ - - size_t stLength = 0; - - unsigned char* pucLabelLength = (unsigned char*)m_acName; - while (*pucLabelLength) - { - stLength += (*pucLabelLength + 1 /* +1 for '.' or '\0'*/); - pucLabelLength += (*pucLabelLength + 1); - } - return stLength; -} - -/* - MDNSResponder::stcMDNS_RRDomain::c_str -*/ -bool MDNSResponder::stcMDNS_RRDomain::c_str(char* p_pcBuffer) -{ - - bool bResult = false; - - if (p_pcBuffer) - { - *p_pcBuffer = 0; - unsigned char* pucLabelLength = (unsigned char*)m_acName; - while (*pucLabelLength) - { - memcpy(p_pcBuffer, (const char*)(pucLabelLength + 1), *pucLabelLength); - p_pcBuffer += *pucLabelLength; - pucLabelLength += (*pucLabelLength + 1); - *p_pcBuffer++ = (*pucLabelLength ? '.' : '\0'); - } - bResult = true; - } - return bResult; -} - - -/** - MDNSResponder::stcMDNS_RRAttributes - - A MDNS attributes object. - -*/ - -/* - MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes constructor -*/ -MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(uint16_t p_u16Type /*= 0*/, - uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) - : m_u16Type(p_u16Type), - m_u16Class(p_u16Class) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes copy-constructor -*/ -MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Other) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRAttributes::operator = -*/ -MDNSResponder::stcMDNS_RRAttributes& MDNSResponder::stcMDNS_RRAttributes::operator=(const MDNSResponder::stcMDNS_RRAttributes& p_Other) -{ - - if (&p_Other != this) - { - m_u16Type = p_Other.m_u16Type; - m_u16Class = p_Other.m_u16Class; - } - return *this; -} - - -/** - MDNSResponder::stcMDNS_RRHeader - - A MDNS record header (domain and attributes) object. - -*/ - -/* - MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader constructor -*/ -MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(void) -{ - -} - -/* - MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader copy-constructor -*/ -MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other) -{ - - operator=(p_Other); -} - -/* - MDNSResponder::stcMDNS_RRHeader::operator = -*/ -MDNSResponder::stcMDNS_RRHeader& MDNSResponder::stcMDNS_RRHeader::operator=(const MDNSResponder::stcMDNS_RRHeader& p_Other) -{ - - if (&p_Other != this) - { - m_Domain = p_Other.m_Domain; - m_Attributes = p_Other.m_Attributes; - } - return *this; -} - -/* - MDNSResponder::stcMDNS_RRHeader::clear -*/ -bool MDNSResponder::stcMDNS_RRHeader::clear(void) -{ - - m_Domain.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRQuestion - - A MDNS question record object (header + question flags) - -*/ - -/* - MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion constructor -*/ -MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion(void) - : m_pNext(0), - m_bUnicast(false) -{ - -} - - -/** - MDNSResponder::stcMDNS_RRAnswer - - A MDNS answer record object (header + answer content). - This is a 'virtual' base class for all other MDNS answer classes. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer constructor -*/ -MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer(enuAnswerType p_AnswerType, - const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : m_pNext(0), - m_AnswerType(p_AnswerType), - m_Header(p_Header), - m_u32TTL(p_u32TTL) -{ - - // Extract 'cache flush'-bit - m_bCacheFlush = (m_Header.m_Attributes.m_u16Class & 0x8000); - m_Header.m_Attributes.m_u16Class &= (~0x8000); -} - -/* - MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer destructor -*/ -MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer(void) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswer::answerType -*/ -MDNSResponder::enuAnswerType MDNSResponder::stcMDNS_RRAnswer::answerType(void) const -{ - - return m_AnswerType; -} - -/* - MDNSResponder::stcMDNS_RRAnswer::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswer::clear(void) -{ - - m_pNext = 0; - m_Header.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRAnswerA - - A MDNS A answer object. - Extends the base class by an IP4 address member. - -*/ - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA constructor -*/ -MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_A, p_Header, p_u32TTL), - m_IPAddress(0, 0, 0, 0) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA destructor -*/ -MDNSResponder::stcMDNS_RRAnswerA::~stcMDNS_RRAnswerA(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerA::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerA::clear(void) -{ - - m_IPAddress = IPAddress(0, 0, 0, 0); - return true; -} -#endif - - -/** - MDNSResponder::stcMDNS_RRAnswerPTR - - A MDNS PTR answer object. - Extends the base class by a MDNS domain member. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR constructor -*/ -MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_PTR, p_Header, p_u32TTL) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR destructor -*/ -MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerPTR::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerPTR::clear(void) -{ - - m_PTRDomain.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRAnswerTXT - - A MDNS TXT answer object. - Extends the base class by a MDNS TXT items list member. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT constructor -*/ -MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_TXT, p_Header, p_u32TTL) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT destructor -*/ -MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerTXT::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerTXT::clear(void) -{ - - m_Txts.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRAnswerAAAA - - A MDNS AAAA answer object. - (Should) extend the base class by an IP6 address member. - -*/ - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA constructor -*/ -MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_AAAA, p_Header, p_u32TTL) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA destructor -*/ -MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerAAAA::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerAAAA::clear(void) -{ - - return true; -} -#endif - - -/** - MDNSResponder::stcMDNS_RRAnswerSRV - - A MDNS SRV answer object. - Extends the base class by a port member. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV constructor -*/ -MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV(const MDNSResponder::stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_SRV, p_Header, p_u32TTL), - m_u16Priority(0), - m_u16Weight(0), - m_u16Port(0) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV destructor -*/ -MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerSRV::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerSRV::clear(void) -{ - - m_u16Priority = 0; - m_u16Weight = 0; - m_u16Port = 0; - m_SRVDomain.clear(); - return true; -} - - -/** - MDNSResponder::stcMDNS_RRAnswerGeneric - - An unknown (generic) MDNS answer object. - Extends the base class by a RDATA buffer member. - -*/ - -/* - MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric constructor -*/ -MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header, - uint32_t p_u32TTL) - : stcMDNS_RRAnswer(AnswerType_Generic, p_Header, p_u32TTL), - m_u16RDLength(0), - m_pu8RDData(0) -{ - -} - -/* - MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric destructor -*/ -MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNS_RRAnswerGeneric::clear -*/ -bool MDNSResponder::stcMDNS_RRAnswerGeneric::clear(void) -{ - - if (m_pu8RDData) - { - delete[] m_pu8RDData; - m_pu8RDData = 0; - } - m_u16RDLength = 0; - - return true; -} - - -/** - MDNSResponder::stcProbeInformation - - Probing status information for a host or service domain - -*/ - -/* - MDNSResponder::stcProbeInformation::stcProbeInformation constructor -*/ -MDNSResponder::stcProbeInformation::stcProbeInformation(void) - : m_ProbingStatus(ProbingStatus_WaitingForData), - m_u8SentCount(0), - m_Timeout(esp8266::polledTimeout::oneShotMs::neverExpires), - m_bConflict(false), - m_bTiebreakNeeded(false), - m_fnHostProbeResultCallback(0), - m_fnServiceProbeResultCallback(0) -{ -} - -/* - MDNSResponder::stcProbeInformation::clear -*/ -bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/) -{ - - m_ProbingStatus = ProbingStatus_WaitingForData; - m_u8SentCount = 0; - m_Timeout.resetToNeverExpires(); - m_bConflict = false; - m_bTiebreakNeeded = false; - if (p_bClearUserdata) - { - m_fnHostProbeResultCallback = 0; - m_fnServiceProbeResultCallback = 0; - } - return true; -} - -/** - MDNSResponder::stcMDNSService - - A MDNS service object (to be announced by the MDNS responder) - The service instance may be '\0'; in this case the hostname is used - and the flag m_bAutoName is set. If the hostname changes, all 'auto- - named' services are renamed also. - m_u8Replymask is used while preparing a response to a MDNS query. It is - resetted in '_sendMDNSMessage' afterwards. -*/ - -/* - MDNSResponder::stcMDNSService::stcMDNSService constructor -*/ -MDNSResponder::stcMDNSService::stcMDNSService(const char* p_pcName /*= 0*/, - const char* p_pcService /*= 0*/, - const char* p_pcProtocol /*= 0*/) - : m_pNext(0), - m_pcName(0), - m_bAutoName(false), - m_pcService(0), - m_pcProtocol(0), - m_u16Port(0), - m_u8ReplyMask(0), - m_fnTxtCallback(0) -{ - - setName(p_pcName); - setService(p_pcService); - setProtocol(p_pcProtocol); -} - -/* - MDNSResponder::stcMDNSService::~stcMDNSService destructor -*/ -MDNSResponder::stcMDNSService::~stcMDNSService(void) -{ - - releaseName(); - releaseService(); - releaseProtocol(); -} - -/* - MDNSResponder::stcMDNSService::setName -*/ -bool MDNSResponder::stcMDNSService::setName(const char* p_pcName) -{ - - bool bResult = false; - - releaseName(); - size_t stLength = (p_pcName ? strlen(p_pcName) : 0); - if (stLength) - { - if ((bResult = (0 != (m_pcName = new char[stLength + 1])))) - { - strncpy(m_pcName, p_pcName, stLength); - m_pcName[stLength] = 0; - } - } - else - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSService::releaseName -*/ -bool MDNSResponder::stcMDNSService::releaseName(void) -{ - - if (m_pcName) - { - delete[] m_pcName; - m_pcName = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSService::setService -*/ -bool MDNSResponder::stcMDNSService::setService(const char* p_pcService) -{ - - bool bResult = false; - - releaseService(); - size_t stLength = (p_pcService ? strlen(p_pcService) : 0); - if (stLength) - { - if ((bResult = (0 != (m_pcService = new char[stLength + 1])))) - { - strncpy(m_pcService, p_pcService, stLength); - m_pcService[stLength] = 0; - } - } - else - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSService::releaseService -*/ -bool MDNSResponder::stcMDNSService::releaseService(void) -{ - - if (m_pcService) - { - delete[] m_pcService; - m_pcService = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSService::setProtocol -*/ -bool MDNSResponder::stcMDNSService::setProtocol(const char* p_pcProtocol) -{ - - bool bResult = false; - - releaseProtocol(); - size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); - if (stLength) - { - if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) - { - strncpy(m_pcProtocol, p_pcProtocol, stLength); - m_pcProtocol[stLength] = 0; - } - } - else - { - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSService::releaseProtocol -*/ -bool MDNSResponder::stcMDNSService::releaseProtocol(void) -{ - - if (m_pcProtocol) - { - delete[] m_pcProtocol; - m_pcProtocol = 0; - } - return true; -} - - -/** - MDNSResponder::stcMDNSServiceQuery - - A MDNS service query object. - Service queries may be static or dynamic. - As the static service query is processed in the blocking function 'queryService', - only one static service service may exist. The processing of the answers is done - on the WiFi-stack side of the ESP stack structure (via 'UDPContext.onRx(_update)'). - -*/ - -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer - - One answer for a service query. - Every answer must contain - - a service instance entry (pivot), - and may contain - - a host domain, - - a port - - an IP4 address - (- an IP6 address) - - a MDNS TXTs - The existance of a component is flaged in 'm_u32ContentFlags'. - For every answer component a TTL value is maintained. - Answer objects can be connected to a linked list. - - For the host domain, service domain and TXTs components, a char array - representation can be retrieved (which is created on demand). - -*/ - -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL - - The TTL (Time-To-Live) for an specific answer content. - The 80% and outdated states are calculated based on the current time (millis) - and the 'set' time (also millis). - If the answer is scheduled for an update, the corresponding flag should be set. - - / - - / * - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor - / - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(uint32_t p_u32TTL / *= 0* /) - : m_bUpdateScheduled(false) { - - set(p_u32TTL * 1000); - } - - / * - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set - / - bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) { - - m_TTLTimeFlag.restart(p_u32TTL * 1000); - m_bUpdateScheduled = false; - - return true; - } - - / * - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent - / - bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent(void) const { - - return ((m_TTLTimeFlag.getTimeout()) && - (!m_bUpdateScheduled) && - (m_TTLTimeFlag.hypotheticalTimeout((m_TTLTimeFlag.getTimeout() * 800) / 1000))); - } - - / * - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated - / - bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated(void) const { - - return ((m_TTLTimeFlag.getTimeout()) && - (m_TTLTimeFlag.flagged())); - }*/ - - -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL - - The TTL (Time-To-Live) for an specific answer content. - The 80% and outdated states are calculated based on the current time (millis) - and the 'set' time (also millis). - If the answer is scheduled for an update, the corresponding flag should be set. - -*/ - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(void) - : m_u32TTL(0), - m_TTLTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), - m_timeoutLevel(TIMEOUTLEVEL_UNSET) -{ - -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) -{ - - m_u32TTL = p_u32TTL; - if (m_u32TTL) - { - m_timeoutLevel = TIMEOUTLEVEL_BASE; // Set to 80% - m_TTLTimeout.reset(timeout()); - } - else - { - m_timeoutLevel = TIMEOUTLEVEL_UNSET; // undef - m_TTLTimeout.resetToNeverExpires(); - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) -{ - - return ((m_u32TTL) && - (TIMEOUTLEVEL_UNSET != m_timeoutLevel) && - (m_TTLTimeout.expired())); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart(void) -{ - - bool bResult = true; - - if ((TIMEOUTLEVEL_BASE <= m_timeoutLevel) && // >= 80% AND - (TIMEOUTLEVEL_FINAL > m_timeoutLevel)) // < 100% - { - - m_timeoutLevel += TIMEOUTLEVEL_INTERVAL; // increment by 5% - m_TTLTimeout.reset(timeout()); - } - else - { - bResult = false; - m_TTLTimeout.resetToNeverExpires(); - m_timeoutLevel = TIMEOUTLEVEL_UNSET; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion(void) -{ - - m_timeoutLevel = TIMEOUTLEVEL_FINAL; - m_TTLTimeout.reset(1 * 1000); // See RFC 6762, 10.1 - - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel(void) const -{ - - return (TIMEOUTLEVEL_FINAL == m_timeoutLevel); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout -*/ -unsigned long MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout(void) const -{ - - uint32_t u32Timeout = esp8266::polledTimeout::oneShotMs::neverExpires; - - if (TIMEOUTLEVEL_BASE == m_timeoutLevel) // 80% - { - u32Timeout = (m_u32TTL * 800); // to milliseconds - } - else if ((TIMEOUTLEVEL_BASE < m_timeoutLevel) && // >80% AND - (TIMEOUTLEVEL_FINAL >= m_timeoutLevel)) // <= 100% - { - - u32Timeout = (m_u32TTL * 50); - } // else: invalid - return u32Timeout; -} - - -#ifdef MDNS_IP4_SUPPORT -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address - -*/ - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address constructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address(IPAddress p_IPAddress, - uint32_t p_u32TTL /*= 0*/) - : m_pNext(0), - m_IPAddress(p_IPAddress) -{ - - m_TTL.set(p_u32TTL); -} -#endif - - -/** - MDNSResponder::stcMDNSServiceQuery::stcAnswer -*/ - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer constructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer(void) - : m_pNext(0), - m_pcServiceDomain(0), - m_pcHostDomain(0), - m_u16Port(0), - m_pcTxts(0), -#ifdef MDNS_IP4_SUPPORT - m_pIP4Addresses(0), -#endif -#ifdef MDNS_IP6_SUPPORT - m_pIP6Addresses(0), -#endif - m_u32ContentFlags(0) -{ -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer destructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear(void) -{ - - return ((releaseTxts()) && -#ifdef MDNS_IP4_SUPPORT - (releaseIP4Addresses()) && -#endif -#ifdef MDNS_IP6_SUPPORT - (releaseIP6Addresses()) -#endif - (releaseHostDomain()) && - (releaseServiceDomain())); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain - - Alloc memory for the char array representation of the service domain. - -*/ -char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain(size_t p_stLength) -{ - - releaseServiceDomain(); - if (p_stLength) - { - m_pcServiceDomain = new char[p_stLength]; - } - return m_pcServiceDomain; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain(void) -{ - - if (m_pcServiceDomain) - { - delete[] m_pcServiceDomain; - m_pcServiceDomain = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain - - Alloc memory for the char array representation of the host domain. - -*/ -char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain(size_t p_stLength) -{ - - releaseHostDomain(); - if (p_stLength) - { - m_pcHostDomain = new char[p_stLength]; - } - return m_pcHostDomain; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain(void) -{ - - if (m_pcHostDomain) - { - delete[] m_pcHostDomain; - m_pcHostDomain = 0; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts - - Alloc memory for the char array representation of the TXT items. - -*/ -char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts(size_t p_stLength) -{ - - releaseTxts(); - if (p_stLength) - { - m_pcTxts = new char[p_stLength]; - } - return m_pcTxts; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts(void) -{ - - if (m_pcTxts) - { - delete[] m_pcTxts; - m_pcTxts = 0; - } - return true; -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses(void) -{ - - while (m_pIP4Addresses) - { - stcIP4Address* pNext = m_pIP4Addresses->m_pNext; - delete m_pIP4Addresses; - m_pIP4Addresses = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) -{ - - bool bResult = false; - - if (p_pIP4Address) - { - p_pIP4Address->m_pNext = m_pIP4Addresses; - m_pIP4Addresses = p_pIP4Address; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) -{ - - bool bResult = false; - - if (p_pIP4Address) - { - stcIP4Address* pPred = m_pIP4Addresses; - while ((pPred) && - (pPred->m_pNext != p_pIP4Address)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pIP4Address->m_pNext; - delete p_pIP4Address; - bResult = true; - } - else if (m_pIP4Addresses == p_pIP4Address) // No predecesor, but first item - { - m_pIP4Addresses = p_pIP4Address->m_pNext; - delete p_pIP4Address; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address (const) -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) const -{ - - return (stcIP4Address*)(((const stcAnswer*)this)->findIP4Address(p_IPAddress)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) -{ - - stcIP4Address* pIP4Address = m_pIP4Addresses; - while (pIP4Address) - { - if (pIP4Address->m_IPAddress == p_IPAddress) - { - break; - } - pIP4Address = pIP4Address->m_pNext; - } - return pIP4Address; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount -*/ -uint32_t MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount(void) const -{ - - uint32_t u32Count = 0; - - stcIP4Address* pIP4Address = m_pIP4Addresses; - while (pIP4Address) - { - ++u32Count; - pIP4Address = pIP4Address->m_pNext; - } - return u32Count; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) -{ - - return (stcIP4Address*)(((const stcAnswer*)this)->IP4AddressAtIndex(p_u32Index)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex (const) -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) const -{ - - const stcIP4Address* pIP4Address = 0; - - if (((uint32_t)(-1) != p_u32Index) && - (m_pIP4Addresses)) - { - - uint32_t u32Index; - for (pIP4Address = m_pIP4Addresses, u32Index = 0; ((pIP4Address) && (u32Index < p_u32Index)); pIP4Address = pIP4Address->m_pNext, ++u32Index); - } - return pIP4Address; -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP6Addresses -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP6Addresses(void) -{ - - while (m_pIP6Addresses) - { - stcIP6Address* pNext = m_pIP6Addresses->m_pNext; - delete m_pIP6Addresses; - m_pIP6Addresses = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP6Address -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP6Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* p_pIP6Address) -{ - - bool bResult = false; - - if (p_pIP6Address) - { - p_pIP6Address->m_pNext = m_pIP6Addresses; - m_pIP6Addresses = p_pIP6Address; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP6Address -*/ -bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP6Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* p_pIP6Address) -{ - - bool bResult = false; - - if (p_pIP6Address) - { - stcIP6Address* pPred = m_pIP6Addresses; - while ((pPred) && - (pPred->m_pNext != p_pIP6Address)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pIP6Address->m_pNext; - delete p_pIP6Address; - bResult = true; - } - else if (m_pIP6Addresses == p_pIP6Address) // No predecesor, but first item - { - m_pIP6Addresses = p_pIP6Address->m_pNext; - delete p_pIP6Address; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address(const IP6Address& p_IPAddress) -{ - - return (stcIP6Address*)(((const stcAnswer*)this)->findIP6Address(p_IPAddress)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address (const) -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address(const IPAddress& p_IPAddress) const -{ - - const stcIP6Address* pIP6Address = m_pIP6Addresses; - while (pIP6Address) - { - if (p_IP6Address->m_IPAddress == p_IPAddress) - { - break; - } - pIP6Address = pIP6Address->m_pNext; - } - return pIP6Address; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressCount -*/ -uint32_t MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressCount(void) const -{ - - uint32_t u32Count = 0; - - stcIP6Address* pIP6Address = m_pIP6Addresses; - while (pIP6Address) - { - ++u32Count; - pIP6Address = pIP6Address->m_pNext; - } - return u32Count; -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex (const) -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex(uint32_t p_u32Index) const -{ - - return (stcIP6Address*)(((const stcAnswer*)this)->IP6AddressAtIndex(p_u32Index)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex(uint32_t p_u32Index) -{ - - stcIP6Address* pIP6Address = 0; - - if (((uint32_t)(-1) != p_u32Index) && - (m_pIP6Addresses)) - { - - uint32_t u32Index; - for (pIP6Address = m_pIP6Addresses, u32Index = 0; ((pIP6Address) && (u32Index < p_u32Index)); pIP6Address = pIP6Address->m_pNext, ++u32Index); - } - return pIP6Address; -} -#endif - - -/** - MDNSResponder::stcMDNSServiceQuery - - A service query object. - A static query is flaged via 'm_bLegacyQuery'; while the function 'queryService' - is waiting for answers, the internal flag 'm_bAwaitingAnswers' is set. When the - timeout is reached, the flag is removed. These two flags are only used for static - service queries. - All answers to the service query are stored in 'm_pAnswers' list. - Individual answers may be addressed by index (in the list of answers). - Every time a answer component is added (or changes) in a dynamic service query, - the callback 'm_fnCallback' is called. - The answer list may be searched by service and host domain. - - Service query object may be connected to a linked list. -*/ - -/* - MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery constructor -*/ -MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery(void) - : m_pNext(0), - m_fnCallback(0), - m_bLegacyQuery(false), - m_u8SentCount(0), - m_ResendTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), - m_bAwaitingAnswers(true), - m_pAnswers(0) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery destructor -*/ -MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSServiceQuery::clear -*/ -bool MDNSResponder::stcMDNSServiceQuery::clear(void) -{ - - m_fnCallback = 0; - m_bLegacyQuery = false; - m_u8SentCount = 0; - m_ResendTimeout.resetToNeverExpires(); - m_bAwaitingAnswers = true; - while (m_pAnswers) - { - stcAnswer* pNext = m_pAnswers->m_pNext; - delete m_pAnswers; - m_pAnswers = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSServiceQuery::answerCount -*/ -uint32_t MDNSResponder::stcMDNSServiceQuery::answerCount(void) const -{ - - uint32_t u32Count = 0; - - stcAnswer* pAnswer = m_pAnswers; - while (pAnswer) - { - ++u32Count; - pAnswer = pAnswer->m_pNext; - } - return u32Count; -} - -/* - MDNSResponder::stcMDNSServiceQuery::answerAtIndex -*/ -const MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::answerAtIndex(uint32_t p_u32Index) const -{ - - const stcAnswer* pAnswer = 0; - - if (((uint32_t)(-1) != p_u32Index) && - (m_pAnswers)) - { - - uint32_t u32Index; - for (pAnswer = m_pAnswers, u32Index = 0; ((pAnswer) && (u32Index < p_u32Index)); pAnswer = pAnswer->m_pNext, ++u32Index); - } - return pAnswer; -} - -/* - MDNSResponder::stcMDNSServiceQuery::answerAtIndex -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::answerAtIndex(uint32_t p_u32Index) -{ - - return (stcAnswer*)(((const stcMDNSServiceQuery*)this)->answerAtIndex(p_u32Index)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::indexOfAnswer -*/ -uint32_t MDNSResponder::stcMDNSServiceQuery::indexOfAnswer(const MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) const -{ - - uint32_t u32Index = 0; - - for (const stcAnswer* pAnswer = m_pAnswers; pAnswer; pAnswer = pAnswer->m_pNext, ++u32Index) - { - if (pAnswer == p_pAnswer) - { - return u32Index; - } - } - return ((uint32_t)(-1)); -} - -/* - MDNSResponder::stcMDNSServiceQuery::addAnswer -*/ -bool MDNSResponder::stcMDNSServiceQuery::addAnswer(MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) -{ - - bool bResult = false; - - if (p_pAnswer) - { - p_pAnswer->m_pNext = m_pAnswers; - m_pAnswers = p_pAnswer; - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::removeAnswer -*/ -bool MDNSResponder::stcMDNSServiceQuery::removeAnswer(MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) -{ - - bool bResult = false; - - if (p_pAnswer) - { - stcAnswer* pPred = m_pAnswers; - while ((pPred) && - (pPred->m_pNext != p_pAnswer)) - { - pPred = pPred->m_pNext; - } - if (pPred) - { - pPred->m_pNext = p_pAnswer->m_pNext; - delete p_pAnswer; - bResult = true; - } - else if (m_pAnswers == p_pAnswer) // No predecesor, but first item - { - m_pAnswers = p_pAnswer->m_pNext; - delete p_pAnswer; - bResult = true; - } - } - return bResult; -} - -/* - MDNSResponder::stcMDNSServiceQuery::findAnswerForServiceDomain -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::findAnswerForServiceDomain(const MDNSResponder::stcMDNS_RRDomain& p_ServiceDomain) -{ - - stcAnswer* pAnswer = m_pAnswers; - while (pAnswer) - { - if (pAnswer->m_ServiceDomain == p_ServiceDomain) - { - break; - } - pAnswer = pAnswer->m_pNext; - } - return pAnswer; -} - -/* - MDNSResponder::stcMDNSServiceQuery::findAnswerForHostDomain -*/ -MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::findAnswerForHostDomain(const MDNSResponder::stcMDNS_RRDomain& p_HostDomain) -{ - - stcAnswer* pAnswer = m_pAnswers; - while (pAnswer) - { - if (pAnswer->m_HostDomain == p_HostDomain) - { - break; - } - pAnswer = pAnswer->m_pNext; - } - return pAnswer; -} - - -/** - MDNSResponder::stcMDNSSendParameter - - A 'collection' of properties and flags for one MDNS query or response. - Mainly managed by the 'Control' functions. - The current offset in the UPD output buffer is tracked to be able to do - a simple host or service domain compression. - -*/ - -/** - MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem - - A cached host or service domain, incl. the offset in the UDP output buffer. - -*/ - -/* - MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem::stcDomainCacheItem constructor -*/ -MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem::stcDomainCacheItem(const void* p_pHostnameOrService, - bool p_bAdditionalData, - uint32_t p_u16Offset) - : m_pNext(0), - m_pHostnameOrService(p_pHostnameOrService), - m_bAdditionalData(p_bAdditionalData), - m_u16Offset(p_u16Offset) -{ - -} - -/** - MDNSResponder::stcMDNSSendParameter -*/ - -/* - MDNSResponder::stcMDNSSendParameter::stcMDNSSendParameter constructor -*/ -MDNSResponder::stcMDNSSendParameter::stcMDNSSendParameter(void) - : m_pQuestions(0), - m_pDomainCacheItems(0) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSSendParameter::~stcMDNSSendParameter destructor -*/ -MDNSResponder::stcMDNSSendParameter::~stcMDNSSendParameter(void) -{ - - clear(); -} - -/* - MDNSResponder::stcMDNSSendParameter::clear -*/ -bool MDNSResponder::stcMDNSSendParameter::clear(void) -{ - - m_u16ID = 0; - m_u8HostReplyMask = 0; - m_u16Offset = 0; - - m_bLegacyQuery = false; - m_bResponse = false; - m_bAuthorative = false; - m_bUnicast = false; - m_bUnannounce = false; - - m_bCacheFlush = true; - - while (m_pQuestions) - { - stcMDNS_RRQuestion* pNext = m_pQuestions->m_pNext; - delete m_pQuestions; - m_pQuestions = pNext; - } - while (m_pDomainCacheItems) - { - stcDomainCacheItem* pNext = m_pDomainCacheItems->m_pNext; - delete m_pDomainCacheItems; - m_pDomainCacheItems = pNext; - } - return true; -} - -/* - MDNSResponder::stcMDNSSendParameter::shiftOffset -*/ -bool MDNSResponder::stcMDNSSendParameter::shiftOffset(uint16_t p_u16Shift) -{ - - m_u16Offset += p_u16Shift; - return true; -} - -/* - MDNSResponder::stcMDNSSendParameter::addDomainCacheItem -*/ -bool MDNSResponder::stcMDNSSendParameter::addDomainCacheItem(const void* p_pHostnameOrService, - bool p_bAdditionalData, - uint16_t p_u16Offset) -{ - - bool bResult = false; - - stcDomainCacheItem* pNewItem = 0; - if ((p_pHostnameOrService) && - (p_u16Offset) && - ((pNewItem = new stcDomainCacheItem(p_pHostnameOrService, p_bAdditionalData, p_u16Offset)))) - { - - pNewItem->m_pNext = m_pDomainCacheItems; - bResult = ((m_pDomainCacheItems = pNewItem)); - } - return bResult; -} - -/* - MDNSResponder::stcMDNSSendParameter::findCachedDomainOffset -*/ -uint16_t MDNSResponder::stcMDNSSendParameter::findCachedDomainOffset(const void* p_pHostnameOrService, - bool p_bAdditionalData) const -{ - - const stcDomainCacheItem* pCacheItem = m_pDomainCacheItems; - - for (; pCacheItem; pCacheItem = pCacheItem->m_pNext) - { - if ((pCacheItem->m_pHostnameOrService == p_pHostnameOrService) && - (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item - { - break; - } - } - return (pCacheItem ? pCacheItem->m_u16Offset : 0); -} - -} // namespace MDNSImplementation - -} // namespace esp8266 - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp deleted file mode 100644 index 7400abec42..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_Transfer.cpp +++ /dev/null @@ -1,1779 +0,0 @@ -/* - LEAmDNS_Transfer.cpp - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -extern "C" { -#include "user_interface.h" -} - -#include "LEAmDNS_lwIPdefs.h" -#include "LEAmDNS_Priv.h" - - -namespace esp8266 -{ - -/* - LEAmDNS -*/ -namespace MDNSImplementation -{ - -/** - CONST STRINGS -*/ -static const char* scpcLocal = "local"; -static const char* scpcServices = "services"; -static const char* scpcDNSSD = "dns-sd"; -static const char* scpcUDP = "udp"; -//static const char* scpcTCP = "tcp"; - -#ifdef MDNS_IP4_SUPPORT -static const char* scpcReverseIP4Domain = "in-addr"; -#endif -#ifdef MDNS_IP6_SUPPORT -static const char* scpcReverseIP6Domain = "ip6"; -#endif -static const char* scpcReverseTopDomain = "arpa"; - -/** - TRANSFER -*/ - - -/** - SENDING -*/ - -/* - MDNSResponder::_sendMDNSMessage - - Unicast responses are prepared and sent directly to the querier. - Multicast responses or queries are transferred to _sendMDNSMessage_Multicast - - Any reply flags in installed services are removed at the end! - -*/ -bool MDNSResponder::_sendMDNSMessage(MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - bool bResult = true; - - if (p_rSendParameter.m_bResponse && - p_rSendParameter.m_bUnicast) // Unicast response -> Send to querier - { - DEBUG_EX_ERR(if (!m_pUDPContext->getRemoteAddress()) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: MISSING remote address for response!\n")); - }); - IPAddress ipRemote; - ipRemote = m_pUDPContext->getRemoteAddress(); - bResult = ((_prepareMDNSMessage(p_rSendParameter, _getResponseMulticastInterface())) && - (m_pUDPContext->send(ipRemote, m_pUDPContext->getRemotePort()))); - } - else // Multicast response - { - bResult = _sendMDNSMessage_Multicast(p_rSendParameter); - } - - // Finally clear service reply masks - for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) - { - pService->m_u8ReplyMask = 0; - } - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_sendMDNSMessage_Multicast - - Fills the UDP output buffer (via _prepareMDNSMessage) and sends the buffer - via the selected WiFi interface (Station or AP) -*/ -bool MDNSResponder::_sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - bool bResult = false; - - IPAddress fromIPAddress; - fromIPAddress = _getResponseMulticastInterface(); - m_pUDPContext->setMulticastInterface(fromIPAddress); - -#ifdef MDNS_IP4_SUPPORT - IPAddress toMulticastAddress(DNS_MQUERY_IPV4_GROUP_INIT); -#endif -#ifdef MDNS_IP6_SUPPORT - //TODO: set multicast address - IPAddress toMulticastAddress(DNS_MQUERY_IPV6_GROUP_INIT); -#endif - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage_Multicast: Will send to '%s'.\n"), toMulticastAddress.toString().c_str());); - bResult = ((_prepareMDNSMessage(p_rSendParameter, fromIPAddress)) && - (m_pUDPContext->send(toMulticastAddress, DNS_MQUERY_PORT))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage_Multicast: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_prepareMDNSMessage - - The MDNS message is composed in a two-step process. - In the first loop 'only' the header informations (mainly number of answers) are collected, - while in the seconds loop, the header and all queries and answers are written to the UDP - output buffer. - -*/ -bool MDNSResponder::_prepareMDNSMessage(MDNSResponder::stcMDNSSendParameter& p_rSendParameter, - IPAddress p_IPAddress) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage\n"));); - bool bResult = true; - - // Prepare header; count answers - stcMDNS_MsgHeader msgHeader(p_rSendParameter.m_u16ID, p_rSendParameter.m_bResponse, 0, p_rSendParameter.m_bAuthorative); - // If this is a response, the answers are anwers, - // else this is a query or probe and the answers go into auth section - uint16_t& ru16Answers = (p_rSendParameter.m_bResponse - ? msgHeader.m_u16ANCount - : msgHeader.m_u16NSCount); - - /** - enuSequence - */ - enum enuSequence - { - Sequence_Count = 0, - Sequence_Send = 1 - }; - - // Two step sequence: 'Count' and 'Send' - for (uint32_t sequence = Sequence_Count; ((bResult) && (sequence <= Sequence_Send)); ++sequence) - { - DEBUG_EX_INFO( - if (Sequence_Send == sequence) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), - (unsigned)msgHeader.m_u16ID, - (unsigned)msgHeader.m_1bQR, (unsigned)msgHeader.m_4bOpcode, (unsigned)msgHeader.m_1bAA, (unsigned)msgHeader.m_1bTC, (unsigned)msgHeader.m_1bRD, - (unsigned)msgHeader.m_1bRA, (unsigned)msgHeader.m_4bRCode, - (unsigned)msgHeader.m_u16QDCount, - (unsigned)msgHeader.m_u16ANCount, - (unsigned)msgHeader.m_u16NSCount, - (unsigned)msgHeader.m_u16ARCount); - } - ); - // Count/send - // Header - bResult = ((Sequence_Count == sequence) - ? true - : _writeMDNSMsgHeader(msgHeader, p_rSendParameter)); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSMsgHeader FAILED!\n"));); - // Questions - for (stcMDNS_RRQuestion* pQuestion = p_rSendParameter.m_pQuestions; ((bResult) && (pQuestion)); pQuestion = pQuestion->m_pNext) - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16QDCount - : (bResult = _writeMDNSQuestion(*pQuestion, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSQuestion FAILED!\n"));); - } - - // Answers and authorative answers -#ifdef MDNS_IP4_SUPPORT - if ((bResult) && - (p_rSendParameter.m_u8HostReplyMask & ContentFlag_A)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(A) FAILED!\n"));); - } - if ((bResult) && - (p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP4)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_PTR_IP4(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP4 FAILED!\n"));); - } -#endif -#ifdef MDNS_IP6_SUPPORT - if ((bResult) && - (p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(A) FAILED!\n"));); - } - if ((bResult) && - (p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP6)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_PTR_IP6(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP6 FAILED!\n"));); - } -#endif - - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_PTR_TYPE)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_PTR_TYPE(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_TYPE FAILED!\n"));); - } - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_PTR_NAME)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_PTR_NAME(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_NAME FAILED!\n"));); - } - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_SRV)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(A) FAILED!\n"));); - } - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_TXT)) - { - ((Sequence_Count == sequence) - ? ++ru16Answers - : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(A) FAILED!\n"));); - } - } // for services - - // Additional answers -#ifdef MDNS_IP4_SUPPORT - bool bNeedsAdditionalAnswerA = false; -#endif -#ifdef MDNS_IP6_SUPPORT - bool bNeedsAdditionalAnswerAAAA = false; -#endif - for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) - { - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND - (!(pService->m_u8ReplyMask & ContentFlag_SRV))) // NOT SRV -> add SRV as additional answer - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16ARCount - : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(B) FAILED!\n"));); - } - if ((bResult) && - (pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND - (!(pService->m_u8ReplyMask & ContentFlag_TXT))) // NOT TXT -> add TXT as additional answer - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16ARCount - : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(B) FAILED!\n"));); - } - if ((pService->m_u8ReplyMask & (ContentFlag_PTR_NAME | ContentFlag_SRV)) || // If service instance name or SRV OR - (p_rSendParameter.m_u8HostReplyMask & (ContentFlag_A | ContentFlag_AAAA))) // any host IP address is requested - { -#ifdef MDNS_IP4_SUPPORT - if ((bResult) && - (!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_A))) // Add IP4 address - { - bNeedsAdditionalAnswerA = true; - } -#endif -#ifdef MDNS_IP6_SUPPORT - if ((bResult) && - (!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA))) // Add IP6 address - { - bNeedsAdditionalAnswerAAAA = true; - } -#endif - } - } // for services - - // Answer A needed? -#ifdef MDNS_IP4_SUPPORT - if ((bResult) && - (bNeedsAdditionalAnswerA)) - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16ARCount - : (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(B) FAILED!\n"));); - } -#endif -#ifdef MDNS_IP6_SUPPORT - // Answer AAAA needed? - if ((bResult) && - (bNeedsAdditionalAnswerAAAA)) - { - ((Sequence_Count == sequence) - ? ++msgHeader.m_u16ARCount - : (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(B) FAILED!\n"));); - } -#endif - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: Loop %i FAILED!\n"), sequence);); - } // for sequence - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_sendMDNSServiceQuery - - Creates and sends a PTR query for the given service domain. - -*/ -bool MDNSResponder::_sendMDNSServiceQuery(const MDNSResponder::stcMDNSServiceQuery& p_ServiceQuery) -{ - - return _sendMDNSQuery(p_ServiceQuery.m_ServiceTypeDomain, DNS_RRTYPE_PTR); -} - -/* - MDNSResponder::_sendMDNSQuery - - Creates and sends a query for the given domain and query type. - -*/ -bool MDNSResponder::_sendMDNSQuery(const MDNSResponder::stcMDNS_RRDomain& p_QueryDomain, - uint16_t p_u16QueryType, - stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers /*= 0*/) -{ - - bool bResult = false; - - stcMDNSSendParameter sendParameter; - if (0 != ((sendParameter.m_pQuestions = new stcMDNS_RRQuestion))) - { - sendParameter.m_pQuestions->m_Header.m_Domain = p_QueryDomain; - - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = p_u16QueryType; - // It seems, that some mDNS implementations don't support 'unicast response' questions... - sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN); // /*Unicast &*/ INternet - - // TODO: Add knwon answer to the query - (void)p_pKnownAnswers; - - bResult = _sendMDNSMessage(sendParameter); - } // else: FAILED to alloc question - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSQuery: FAILED to alloc question!\n"));); - return bResult; -} - -/** - HELPERS -*/ - -/** - RESOURCE RECORDS -*/ - -/* - MDNSResponder::_readRRQuestion - - Reads a question (eg. MyESP._http._tcp.local ANY IN) from the UPD input buffer. - -*/ -bool MDNSResponder::_readRRQuestion(MDNSResponder::stcMDNS_RRQuestion& p_rRRQuestion) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion\n"));); - - bool bResult = false; - - if ((bResult = _readRRHeader(p_rRRQuestion.m_Header))) - { - // Extract unicast flag from class field - p_rRRQuestion.m_bUnicast = (p_rRRQuestion.m_Header.m_Attributes.m_u16Class & 0x8000); - p_rRRQuestion.m_Header.m_Attributes.m_u16Class &= (~0x8000); - - DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion ")); - _printRRDomain(p_rRRQuestion.m_Header.m_Domain); - DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X %s\n"), (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Type, (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Class, (p_rRRQuestion.m_bUnicast ? "Unicast" : "Multicast")); - ); - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_readRRAnswer - - Reads an answer (eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local) - from the UDP input buffer. - After reading the domain and type info, the further processing of the answer - is transferred the answer specific reading functions. - Unknown answer types are processed by the generic answer reader (to remove them - from the input buffer). - -*/ -bool MDNSResponder::_readRRAnswer(MDNSResponder::stcMDNS_RRAnswer*& p_rpRRAnswer) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer\n"));); - - bool bResult = false; - - stcMDNS_RRHeader header; - uint32_t u32TTL; - uint16_t u16RDLength; - if ((_readRRHeader(header)) && - (_udpRead32(u32TTL)) && - (_udpRead16(u16RDLength))) - { - - /* DEBUG_EX_INFO( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: Reading 0x%04X answer (class:0x%04X, TTL:%u, RDLength:%u) for "), header.m_Attributes.m_u16Type, header.m_Attributes.m_u16Class, u32TTL, u16RDLength); - _printRRDomain(header.m_Domain); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - );*/ - - switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag - { -#ifdef MDNS_IP4_SUPPORT - case DNS_RRTYPE_A: - p_rpRRAnswer = new stcMDNS_RRAnswerA(header, u32TTL); - bResult = _readRRAnswerA(*(stcMDNS_RRAnswerA*&)p_rpRRAnswer, u16RDLength); - break; -#endif - case DNS_RRTYPE_PTR: - p_rpRRAnswer = new stcMDNS_RRAnswerPTR(header, u32TTL); - bResult = _readRRAnswerPTR(*(stcMDNS_RRAnswerPTR*&)p_rpRRAnswer, u16RDLength); - break; - case DNS_RRTYPE_TXT: - p_rpRRAnswer = new stcMDNS_RRAnswerTXT(header, u32TTL); - bResult = _readRRAnswerTXT(*(stcMDNS_RRAnswerTXT*&)p_rpRRAnswer, u16RDLength); - break; -#ifdef MDNS_IP6_SUPPORT - case DNS_RRTYPE_AAAA: - p_rpRRAnswer = new stcMDNS_RRAnswerAAAA(header, u32TTL); - bResult = _readRRAnswerAAAA(*(stcMDNS_RRAnswerAAAA*&)p_rpRRAnswer, u16RDLength); - break; -#endif - case DNS_RRTYPE_SRV: - p_rpRRAnswer = new stcMDNS_RRAnswerSRV(header, u32TTL); - bResult = _readRRAnswerSRV(*(stcMDNS_RRAnswerSRV*&)p_rpRRAnswer, u16RDLength); - break; - default: - p_rpRRAnswer = new stcMDNS_RRAnswerGeneric(header, u32TTL); - bResult = _readRRAnswerGeneric(*(stcMDNS_RRAnswerGeneric*&)p_rpRRAnswer, u16RDLength); - break; - } - DEBUG_EX_INFO( - if ((bResult) && - (p_rpRRAnswer)) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: ")); - _printRRDomain(p_rpRRAnswer->m_Header.m_Domain); - DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, RDLength:%u "), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type, p_rpRRAnswer->m_Header.m_Attributes.m_u16Class, p_rpRRAnswer->m_u32TTL, u16RDLength); - switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag - { -#ifdef MDNS_IP4_SUPPORT - case DNS_RRTYPE_A: - DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); - break; -#endif - case DNS_RRTYPE_PTR: - DEBUG_OUTPUT.printf_P(PSTR("PTR ")); - _printRRDomain(((stcMDNS_RRAnswerPTR*&)p_rpRRAnswer)->m_PTRDomain); - break; - case DNS_RRTYPE_TXT: - { - size_t stTxtLength = ((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_strLength(); - char* pTxts = new char[stTxtLength]; - if (pTxts) - { - ((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_str(pTxts); - DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); - delete[] pTxts; - } - break; - } -#ifdef MDNS_IP6_SUPPORT - case DNS_RRTYPE_AAAA: - DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); - break; -#endif - case DNS_RRTYPE_SRV: - DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_u16Port); - _printRRDomain(((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_SRVDomain); - break; - default: - DEBUG_OUTPUT.printf_P(PSTR("generic ")); - break; - } - DEBUG_OUTPUT.printf_P(PSTR("\n")); - } - else - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED to read specific answer of type 0x%04X!\n"), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type); - } - ); // DEBUG_EX_INFO - } - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED!\n"));); - return bResult; -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::_readRRAnswerA -*/ -bool MDNSResponder::_readRRAnswerA(MDNSResponder::stcMDNS_RRAnswerA& p_rRRAnswerA, - uint16_t p_u16RDLength) -{ - - uint32_t u32IP4Address; - bool bResult = ((MDNS_IP4_SIZE == p_u16RDLength) && - (_udpReadBuffer((unsigned char*)&u32IP4Address, MDNS_IP4_SIZE)) && - ((p_rRRAnswerA.m_IPAddress = IPAddress(u32IP4Address)))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerA: FAILED!\n"));); - return bResult; -} -#endif - -/* - MDNSResponder::_readRRAnswerPTR -*/ -bool MDNSResponder::_readRRAnswerPTR(MDNSResponder::stcMDNS_RRAnswerPTR& p_rRRAnswerPTR, - uint16_t p_u16RDLength) -{ - - bool bResult = ((p_u16RDLength) && - (_readRRDomain(p_rRRAnswerPTR.m_PTRDomain))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerPTR: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRAnswerTXT - - Read TXT items from a buffer like 4c#=15ff=20 -*/ -bool MDNSResponder::_readRRAnswerTXT(MDNSResponder::stcMDNS_RRAnswerTXT& p_rRRAnswerTXT, - uint16_t p_u16RDLength) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: RDLength:%u\n"), p_u16RDLength);); - bool bResult = true; - - p_rRRAnswerTXT.clear(); - if (p_u16RDLength) - { - bResult = false; - - unsigned char* pucBuffer = new unsigned char[p_u16RDLength]; - if (pucBuffer) - { - if (_udpReadBuffer(pucBuffer, p_u16RDLength)) - { - bResult = true; - - const unsigned char* pucCursor = pucBuffer; - while ((pucCursor < (pucBuffer + p_u16RDLength)) && - (bResult)) - { - bResult = false; - - stcMDNSServiceTxt* pTxt = 0; - unsigned char ucLength = *pucCursor++; // Length of the next txt item - if (ucLength) - { - DEBUG_EX_INFO( - static char sacBuffer[64]; *sacBuffer = 0; - uint8_t u8MaxLength = ((ucLength > (sizeof(sacBuffer) - 1)) ? (sizeof(sacBuffer) - 1) : ucLength); - os_strncpy(sacBuffer, (const char*)pucCursor, u8MaxLength); sacBuffer[u8MaxLength] = 0; - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: Item(%u): %s\n"), ucLength, sacBuffer); - ); - - unsigned char* pucEqualSign = (unsigned char*)os_strchr((const char*)pucCursor, '='); // Position of the '=' sign - unsigned char ucKeyLength; - if ((pucEqualSign) && - ((ucKeyLength = (pucEqualSign - pucCursor)))) - { - unsigned char ucValueLength = (ucLength - (pucEqualSign - pucCursor + 1)); - bResult = (((pTxt = new stcMDNSServiceTxt)) && - (pTxt->setKey((const char*)pucCursor, ucKeyLength)) && - (pTxt->setValue((const char*)(pucEqualSign + 1), ucValueLength))); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: INVALID TXT format (No '=')!\n"));); - } - pucCursor += ucLength; - } - else // no/zero length TXT - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: TXT answer contains no items.\n"));); - bResult = true; - } - - if ((bResult) && - (pTxt)) // Everythings fine so far - { - // Link TXT item to answer TXTs - pTxt->m_pNext = p_rRRAnswerTXT.m_Txts.m_pTxts; - p_rRRAnswerTXT.m_Txts.m_pTxts = pTxt; - } - else // At least no TXT (migth be OK, if length was 0) OR an error - { - if (!bResult) - { - DEBUG_EX_ERR( - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT item!\n")); - DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); - _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - ); - } - if (pTxt) - { - delete pTxt; - pTxt = 0; - } - p_rRRAnswerTXT.clear(); - } - } // while - - DEBUG_EX_ERR( - if (!bResult) // Some failure - { - DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); - _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); - DEBUG_OUTPUT.printf_P(PSTR("\n")); - } - ); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT content!\n"));); - } - // Clean up - delete[] pucBuffer; - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to alloc buffer for TXT content!\n"));); - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: WARNING! No content!\n"));); - } - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED!\n"));); - return bResult; -} - -#ifdef MDNS_IP6_SUPPORT -bool MDNSResponder::_readRRAnswerAAAA(MDNSResponder::stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA, - uint16_t p_u16RDLength) -{ - bool bResult = false; - // TODO: Implement - return bResult; -} -#endif - -/* - MDNSResponder::_readRRAnswerSRV -*/ -bool MDNSResponder::_readRRAnswerSRV(MDNSResponder::stcMDNS_RRAnswerSRV& p_rRRAnswerSRV, - uint16_t p_u16RDLength) -{ - - bool bResult = (((3 * sizeof(uint16_t)) < p_u16RDLength) && - (_udpRead16(p_rRRAnswerSRV.m_u16Priority)) && - (_udpRead16(p_rRRAnswerSRV.m_u16Weight)) && - (_udpRead16(p_rRRAnswerSRV.m_u16Port)) && - (_readRRDomain(p_rRRAnswerSRV.m_SRVDomain))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerSRV: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRAnswerGeneric -*/ -bool MDNSResponder::_readRRAnswerGeneric(MDNSResponder::stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric, - uint16_t p_u16RDLength) -{ - bool bResult = (0 == p_u16RDLength); - - p_rRRAnswerGeneric.clear(); - if (((p_rRRAnswerGeneric.m_u16RDLength = p_u16RDLength)) && - ((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength]))) - { - - bResult = _udpReadBuffer(p_rRRAnswerGeneric.m_pu8RDData, p_rRRAnswerGeneric.m_u16RDLength); - } - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerGeneric: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRHeader -*/ -bool MDNSResponder::_readRRHeader(MDNSResponder::stcMDNS_RRHeader& p_rRRHeader) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader\n"));); - - bool bResult = ((_readRRDomain(p_rRRHeader.m_Domain)) && - (_readRRAttributes(p_rRRHeader.m_Attributes))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRDomain - - Reads a (maybe multilevel compressed) domain from the UDP input buffer. - -*/ -bool MDNSResponder::_readRRDomain(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain\n"));); - - bool bResult = ((p_rRRDomain.clear()) && - (_readRRDomain_Loop(p_rRRDomain, 0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_readRRDomain_Loop - - Reads a domain from the UDP input buffer. For every compression level, the functions - calls itself recursively. To avoid endless recursion because of malformed MDNS records, - the maximum recursion depth is set by MDNS_DOMAIN_MAX_REDIRCTION. - -*/ -bool MDNSResponder::_readRRDomain_Loop(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain, - uint8_t p_u8Depth) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u)\n"), p_u8Depth);); - - bool bResult = false; - - if (MDNS_DOMAIN_MAX_REDIRCTION >= p_u8Depth) - { - bResult = true; - - uint8_t u8Len = 0; - do - { - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Offset:%u p0:%02x\n"), p_u8Depth, m_pUDPContext->tell(), m_pUDPContext->peek());); - _udpRead8(u8Len); - - if (u8Len & MDNS_DOMAIN_COMPRESS_MARK) - { - // Compressed label(s) - uint16_t u16Offset = ((u8Len & ~MDNS_DOMAIN_COMPRESS_MARK) << 8); // Implicit BE to LE conversion! - _udpRead8(u8Len); - u16Offset |= u8Len; - - if (m_pUDPContext->isValidOffset(u16Offset)) - { - size_t stCurrentPosition = m_pUDPContext->tell(); // Prepare return from recursion - - //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Redirecting from %u to %u!\n"), p_u8Depth, stCurrentPosition, u16Offset);); - m_pUDPContext->seek(u16Offset); - if (_readRRDomain_Loop(p_rRRDomain, p_u8Depth + 1)) // Do recursion - { - //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Succeeded to read redirected label! Returning to %u\n"), p_u8Depth, stCurrentPosition);); - m_pUDPContext->seek(stCurrentPosition); // Restore after recursion - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): FAILED to read redirected label!\n"), p_u8Depth);); - bResult = false; - } - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): INVALID offset in redirection!\n"), p_u8Depth);); - bResult = false; - } - break; - } - else - { - // Normal (uncompressed) label (maybe '\0' only) - if (MDNS_DOMAIN_MAXLENGTH > (p_rRRDomain.m_u16NameLength + u8Len)) - { - // Add length byte - p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength] = u8Len; - ++(p_rRRDomain.m_u16NameLength); - if (u8Len) // Add name - { - if ((bResult = _udpReadBuffer((unsigned char*) & (p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength]), u8Len))) - { - /* DEBUG_EX_INFO( - p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength + u8Len] = 0; // Closing '\0' for printing - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Domain label (%u): %s\n"), p_u8Depth, (unsigned)(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength - 1]), &(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength])); - );*/ - - p_rRRDomain.m_u16NameLength += u8Len; - } - } - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(2) offset:%u p0:%x\n"), m_pUDPContext->tell(), m_pUDPContext->peek());); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Domain name too long (%u + %u)!\n"), p_u8Depth, p_rRRDomain.m_u16NameLength, u8Len);); - bResult = false; - break; - } - } - } while ((bResult) && - (0 != u8Len)); - } - else - { - DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Too many redirections!\n"), p_u8Depth);); - } - return bResult; -} - -/* - MDNSResponder::_readRRAttributes -*/ -bool MDNSResponder::_readRRAttributes(MDNSResponder::stcMDNS_RRAttributes& p_rRRAttributes) -{ - //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes\n"));); - - bool bResult = ((_udpRead16(p_rRRAttributes.m_u16Type)) && - (_udpRead16(p_rRRAttributes.m_u16Class))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes: FAILED!\n"));); - return bResult; -} - - -/* - DOMAIN NAMES -*/ - -/* - MDNSResponder::_buildDomainForHost - - Builds a MDNS host domain (eg. esp8266.local) for the given hostname. - -*/ -bool MDNSResponder::_buildDomainForHost(const char* p_pcHostname, - MDNSResponder::stcMDNS_RRDomain& p_rHostDomain) const -{ - - p_rHostDomain.clear(); - bool bResult = ((p_pcHostname) && - (*p_pcHostname) && - (p_rHostDomain.addLabel(p_pcHostname)) && - (p_rHostDomain.addLabel(scpcLocal)) && - (p_rHostDomain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForHost: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_buildDomainForDNSSD - - Builds the '_services._dns-sd._udp.local' domain. - Used while detecting generic service enum question (DNS-SD) and answering these questions. - -*/ -bool MDNSResponder::_buildDomainForDNSSD(MDNSResponder::stcMDNS_RRDomain& p_rDNSSDDomain) const -{ - - p_rDNSSDDomain.clear(); - bool bResult = ((p_rDNSSDDomain.addLabel(scpcServices, true)) && - (p_rDNSSDDomain.addLabel(scpcDNSSD, true)) && - (p_rDNSSDDomain.addLabel(scpcUDP, true)) && - (p_rDNSSDDomain.addLabel(scpcLocal)) && - (p_rDNSSDDomain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForDNSSD: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_buildDomainForService - - Builds the domain for the given service (eg. _http._tcp.local or - MyESP._http._tcp.local (if p_bIncludeName is set)). - -*/ -bool MDNSResponder::_buildDomainForService(const MDNSResponder::stcMDNSService& p_Service, - bool p_bIncludeName, - MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const -{ - - p_rServiceDomain.clear(); - bool bResult = (((!p_bIncludeName) || - (p_rServiceDomain.addLabel(p_Service.m_pcName))) && - (p_rServiceDomain.addLabel(p_Service.m_pcService, true)) && - (p_rServiceDomain.addLabel(p_Service.m_pcProtocol, true)) && - (p_rServiceDomain.addLabel(scpcLocal)) && - (p_rServiceDomain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED!\n"));); - return bResult; -} - -/* - MDNSResponder::_buildDomainForService - - Builds the domain for the given service properties (eg. _http._tcp.local). - The usual prepended '_' are added, if missing in the input strings. - -*/ -bool MDNSResponder::_buildDomainForService(const char* p_pcService, - const char* p_pcProtocol, - MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const -{ - - p_rServiceDomain.clear(); - bool bResult = ((p_pcService) && - (p_pcProtocol) && - (p_rServiceDomain.addLabel(p_pcService, ('_' != *p_pcService))) && - (p_rServiceDomain.addLabel(p_pcProtocol, ('_' != *p_pcProtocol))) && - (p_rServiceDomain.addLabel(scpcLocal)) && - (p_rServiceDomain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED for (%s.%s)!\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); - return bResult; -} - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::_buildDomainForReverseIP4 - - The IP4 address is stringized by printing the four address bytes into a char buffer in reverse order - and adding 'in-addr.arpa' (eg. 012.789.456.123.in-addr.arpa). - Used while detecting reverse IP4 questions and answering these -*/ -bool MDNSResponder::_buildDomainForReverseIP4(IPAddress p_IP4Address, - MDNSResponder::stcMDNS_RRDomain& p_rReverseIP4Domain) const -{ - - bool bResult = true; - - p_rReverseIP4Domain.clear(); - - char acBuffer[32]; - for (int i = MDNS_IP4_SIZE; ((bResult) && (i >= 1)); --i) - { - itoa(p_IP4Address[i - 1], acBuffer, 10); - bResult = p_rReverseIP4Domain.addLabel(acBuffer); - } - bResult = ((bResult) && - (p_rReverseIP4Domain.addLabel(scpcReverseIP4Domain)) && - (p_rReverseIP4Domain.addLabel(scpcReverseTopDomain)) && - (p_rReverseIP4Domain.addLabel(0))); - DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForReverseIP4: FAILED!\n"));); - return bResult; -} -#endif - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::_buildDomainForReverseIP6 - - Used while detecting reverse IP6 questions and answering these -*/ -bool MDNSResponder::_buildDomainForReverseIP6(IPAddress p_IP4Address, - MDNSResponder::stcMDNS_RRDomain& p_rReverseIP6Domain) const -{ - // TODO: Implement - return false; -} -#endif - - -/* - UDP -*/ - -/* - MDNSResponder::_udpReadBuffer -*/ -bool MDNSResponder::_udpReadBuffer(unsigned char* p_pBuffer, - size_t p_stLength) -{ - - bool bResult = ((m_pUDPContext) && - (true/*m_pUDPContext->getSize() > p_stLength*/) && - (p_pBuffer) && - (p_stLength) && - ((p_stLength == m_pUDPContext->read((char*)p_pBuffer, p_stLength)))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpReadBuffer: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_udpRead8 -*/ -bool MDNSResponder::_udpRead8(uint8_t& p_ru8Value) -{ - - return _udpReadBuffer((unsigned char*)&p_ru8Value, sizeof(p_ru8Value)); -} - -/* - MDNSResponder::_udpRead16 -*/ -bool MDNSResponder::_udpRead16(uint16_t& p_ru16Value) -{ - - bool bResult = false; - - if (_udpReadBuffer((unsigned char*)&p_ru16Value, sizeof(p_ru16Value))) - { - p_ru16Value = lwip_ntohs(p_ru16Value); - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::_udpRead32 -*/ -bool MDNSResponder::_udpRead32(uint32_t& p_ru32Value) -{ - - bool bResult = false; - - if (_udpReadBuffer((unsigned char*)&p_ru32Value, sizeof(p_ru32Value))) - { - p_ru32Value = lwip_ntohl(p_ru32Value); - bResult = true; - } - return bResult; -} - -/* - MDNSResponder::_udpAppendBuffer -*/ -bool MDNSResponder::_udpAppendBuffer(const unsigned char* p_pcBuffer, - size_t p_stLength) -{ - - bool bResult = ((m_pUDPContext) && - (p_pcBuffer) && - (p_stLength) && - (p_stLength == m_pUDPContext->append((const char*)p_pcBuffer, p_stLength))); - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpAppendBuffer: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_udpAppend8 -*/ -bool MDNSResponder::_udpAppend8(uint8_t p_u8Value) -{ - - return (_udpAppendBuffer((unsigned char*)&p_u8Value, sizeof(p_u8Value))); -} - -/* - MDNSResponder::_udpAppend16 -*/ -bool MDNSResponder::_udpAppend16(uint16_t p_u16Value) -{ - - p_u16Value = lwip_htons(p_u16Value); - return (_udpAppendBuffer((unsigned char*)&p_u16Value, sizeof(p_u16Value))); -} - -/* - MDNSResponder::_udpAppend32 -*/ -bool MDNSResponder::_udpAppend32(uint32_t p_u32Value) -{ - - p_u32Value = lwip_htonl(p_u32Value); - return (_udpAppendBuffer((unsigned char*)&p_u32Value, sizeof(p_u32Value))); -} - -#ifdef DEBUG_ESP_MDNS_RESPONDER -/* - MDNSResponder::_udpDump -*/ -bool MDNSResponder::_udpDump(bool p_bMovePointer /*= false*/) -{ - - const uint8_t cu8BytesPerLine = 16; - - uint32_t u32StartPosition = m_pUDPContext->tell(); - DEBUG_OUTPUT.println("UDP Context Dump:"); - uint32_t u32Counter = 0; - uint8_t u8Byte = 0; - - while (_udpRead8(u8Byte)) - { - DEBUG_OUTPUT.printf_P(PSTR("%02x %s"), u8Byte, ((++u32Counter % cu8BytesPerLine) ? "" : "\n")); - } - DEBUG_OUTPUT.printf_P(PSTR("%sDone: %u bytes\n"), (((u32Counter) && (u32Counter % cu8BytesPerLine)) ? "\n" : ""), u32Counter); - - if (!p_bMovePointer) // Restore - { - m_pUDPContext->seek(u32StartPosition); - } - return true; -} - -/* - MDNSResponder::_udpDump -*/ -bool MDNSResponder::_udpDump(unsigned p_uOffset, - unsigned p_uLength) -{ - - if ((m_pUDPContext) && - (m_pUDPContext->isValidOffset(p_uOffset))) - { - unsigned uCurrentPosition = m_pUDPContext->tell(); // Remember start position - - m_pUDPContext->seek(p_uOffset); - uint8_t u8Byte; - for (unsigned u = 0; ((u < p_uLength) && (_udpRead8(u8Byte))); ++u) - { - DEBUG_OUTPUT.printf_P(PSTR("%02x "), u8Byte); - } - // Return to start position - m_pUDPContext->seek(uCurrentPosition); - } - return true; -} -#endif - - -/** - READ/WRITE MDNS STRUCTS -*/ - -/* - MDNSResponder::_readMDNSMsgHeader - - Read a MDNS header from the UDP input buffer. - | 8 | 8 | 8 | 8 | - 00| Identifier | Flags & Codes | - 01| Question count | Answer count | - 02| NS answer count | Ad answer count | - - All 16-bit and 32-bit elements need to be translated form network coding to host coding (done in _udpRead16 and _udpRead32) - In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they - need some mapping here -*/ -bool MDNSResponder::_readMDNSMsgHeader(MDNSResponder::stcMDNS_MsgHeader& p_rMsgHeader) -{ - - bool bResult = false; - - uint8_t u8B1; - uint8_t u8B2; - if ((_udpRead16(p_rMsgHeader.m_u16ID)) && - (_udpRead8(u8B1)) && - (_udpRead8(u8B2)) && - (_udpRead16(p_rMsgHeader.m_u16QDCount)) && - (_udpRead16(p_rMsgHeader.m_u16ANCount)) && - (_udpRead16(p_rMsgHeader.m_u16NSCount)) && - (_udpRead16(p_rMsgHeader.m_u16ARCount))) - { - - p_rMsgHeader.m_1bQR = (u8B1 & 0x80); // Query/Responde flag - p_rMsgHeader.m_4bOpcode = (u8B1 & 0x78); // Operation code (0: Standard query, others ignored) - p_rMsgHeader.m_1bAA = (u8B1 & 0x04); // Authorative answer - p_rMsgHeader.m_1bTC = (u8B1 & 0x02); // Truncation flag - p_rMsgHeader.m_1bRD = (u8B1 & 0x01); // Recursion desired - - p_rMsgHeader.m_1bRA = (u8B2 & 0x80); // Recursion available - p_rMsgHeader.m_3bZ = (u8B2 & 0x70); // Zero - p_rMsgHeader.m_4bRCode = (u8B2 & 0x0F); // Response code - - /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), - (unsigned)p_rMsgHeader.m_u16ID, - (unsigned)p_rMsgHeader.m_1bQR, (unsigned)p_rMsgHeader.m_4bOpcode, (unsigned)p_rMsgHeader.m_1bAA, (unsigned)p_rMsgHeader.m_1bTC, (unsigned)p_rMsgHeader.m_1bRD, - (unsigned)p_rMsgHeader.m_1bRA, (unsigned)p_rMsgHeader.m_4bRCode, - (unsigned)p_rMsgHeader.m_u16QDCount, - (unsigned)p_rMsgHeader.m_u16ANCount, - (unsigned)p_rMsgHeader.m_u16NSCount, - (unsigned)p_rMsgHeader.m_u16ARCount););*/ - bResult = true; - } - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_write8 -*/ -bool MDNSResponder::_write8(uint8_t p_u8Value, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - return ((_udpAppend8(p_u8Value)) && - (p_rSendParameter.shiftOffset(sizeof(p_u8Value)))); -} - -/* - MDNSResponder::_write16 -*/ -bool MDNSResponder::_write16(uint16_t p_u16Value, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - return ((_udpAppend16(p_u16Value)) && - (p_rSendParameter.shiftOffset(sizeof(p_u16Value)))); -} - -/* - MDNSResponder::_write32 -*/ -bool MDNSResponder::_write32(uint32_t p_u32Value, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - return ((_udpAppend32(p_u32Value)) && - (p_rSendParameter.shiftOffset(sizeof(p_u32Value)))); -} - -/* - MDNSResponder::_writeMDNSMsgHeader - - Write MDNS header to the UDP output buffer. - - All 16-bit and 32-bit elements need to be translated form host coding to network coding (done in _udpAppend16 and _udpAppend32) - In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they - need some mapping here -*/ -bool MDNSResponder::_writeMDNSMsgHeader(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), - (unsigned)p_MsgHeader.m_u16ID, - (unsigned)p_MsgHeader.m_1bQR, (unsigned)p_MsgHeader.m_4bOpcode, (unsigned)p_MsgHeader.m_1bAA, (unsigned)p_MsgHeader.m_1bTC, (unsigned)p_MsgHeader.m_1bRD, - (unsigned)p_MsgHeader.m_1bRA, (unsigned)p_MsgHeader.m_4bRCode, - (unsigned)p_MsgHeader.m_u16QDCount, - (unsigned)p_MsgHeader.m_u16ANCount, - (unsigned)p_MsgHeader.m_u16NSCount, - (unsigned)p_MsgHeader.m_u16ARCount););*/ - - uint8_t u8B1((p_MsgHeader.m_1bQR << 7) | (p_MsgHeader.m_4bOpcode << 3) | (p_MsgHeader.m_1bAA << 2) | (p_MsgHeader.m_1bTC << 1) | (p_MsgHeader.m_1bRD)); - uint8_t u8B2((p_MsgHeader.m_1bRA << 7) | (p_MsgHeader.m_3bZ << 4) | (p_MsgHeader.m_4bRCode)); - bool bResult = ((_write16(p_MsgHeader.m_u16ID, p_rSendParameter)) && - (_write8(u8B1, p_rSendParameter)) && - (_write8(u8B2, p_rSendParameter)) && - (_write16(p_MsgHeader.m_u16QDCount, p_rSendParameter)) && - (_write16(p_MsgHeader.m_u16ANCount, p_rSendParameter)) && - (_write16(p_MsgHeader.m_u16NSCount, p_rSendParameter)) && - (_write16(p_MsgHeader.m_u16ARCount, p_rSendParameter))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeRRAttributes -*/ -bool MDNSResponder::_writeMDNSRRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Attributes, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - bool bResult = ((_write16(p_Attributes.m_u16Type, p_rSendParameter)) && - (_write16(p_Attributes.m_u16Class, p_rSendParameter))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRAttributes: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeMDNSRRDomain -*/ -bool MDNSResponder::_writeMDNSRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_Domain, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - bool bResult = ((_udpAppendBuffer((const unsigned char*)p_Domain.m_acName, p_Domain.m_u16NameLength)) && - (p_rSendParameter.shiftOffset(p_Domain.m_u16NameLength))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRDomain: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeMDNSHostDomain - - Write a host domain to the UDP output buffer. - If the domain record is part of the answer, the records length is - prepended (p_bPrependRDLength is set). - - A very simple form of name compression is applied here: - If the domain is written to the UDP output buffer, the write offset is stored - together with a domain id (the pointer) in a p_rSendParameter substructure (cache). - If the same domain (pointer) should be written to the UDP output later again, - the old offset is retrieved from the cache, marked as a compressed domain offset - and written to the output buffer. - -*/ -bool MDNSResponder::_writeMDNSHostDomain(const char* p_pcHostname, - bool p_bPrependRDLength, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' - uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)p_pcHostname, false); - - stcMDNS_RRDomain hostDomain; - bool bResult = (u16CachedDomainOffset - // Found cached domain -> mark as compressed domain - ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset - ((!p_bPrependRDLength) || - (_write16(2, p_rSendParameter))) && // Length of 'Cxxx' - (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) - (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) - // No cached domain -> add this domain to cache and write full domain name - : ((_buildDomainForHost(p_pcHostname, hostDomain)) && // eg. esp8266.local - ((!p_bPrependRDLength) || - (_write16(hostDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed) - (p_rSendParameter.addDomainCacheItem((const void*)p_pcHostname, false, p_rSendParameter.m_u16Offset)) && - (_writeMDNSRRDomain(hostDomain, p_rSendParameter)))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSHostDomain: FAILED!\n")); - }); - return bResult; - -} - -/* - MDNSResponder::_writeMDNSServiceDomain - - Write a service domain to the UDP output buffer. - If the domain record is part of the answer, the records length is - prepended (p_bPrependRDLength is set). - - A very simple form of name compression is applied here: see '_writeMDNSHostDomain' - The cache differentiates of course between service domains which includes - the instance name (p_bIncludeName is set) and thoose who don't. - -*/ -bool MDNSResponder::_writeMDNSServiceDomain(const MDNSResponder::stcMDNSService& p_Service, - bool p_bIncludeName, - bool p_bPrependRDLength, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - - // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' - uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)&p_Service, p_bIncludeName); - - stcMDNS_RRDomain serviceDomain; - bool bResult = (u16CachedDomainOffset - // Found cached domain -> mark as compressed domain - ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset - ((!p_bPrependRDLength) || - (_write16(2, p_rSendParameter))) && // Lenght of 'Cxxx' - (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) - (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) - // No cached domain -> add this domain to cache and write full domain name - : ((_buildDomainForService(p_Service, p_bIncludeName, serviceDomain)) && // eg. MyESP._http._tcp.local - ((!p_bPrependRDLength) || - (_write16(serviceDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed) - (p_rSendParameter.addDomainCacheItem((const void*)&p_Service, p_bIncludeName, p_rSendParameter.m_u16Offset)) && - (_writeMDNSRRDomain(serviceDomain, p_rSendParameter)))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSServiceDomain: FAILED!\n")); - }); - return bResult; - -} - -/* - MDNSResponder::_writeMDNSQuestion - - Write a MDNS question to the UDP output buffer - - QNAME (host/service domain, eg. esp8266.local) - QTYPE (16bit, eg. ANY) - QCLASS (16bit, eg. IN) - -*/ -bool MDNSResponder::_writeMDNSQuestion(MDNSResponder::stcMDNS_RRQuestion& p_Question, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion\n"));); - - bool bResult = ((_writeMDNSRRDomain(p_Question.m_Header.m_Domain, p_rSendParameter)) && - (_writeMDNSRRAttributes(p_Question.m_Header.m_Attributes, p_rSendParameter))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion: FAILED!\n")); - }); - return bResult; - -} - - -#ifdef MDNS_IP4_SUPPORT -/* - MDNSResponder::_writeMDNSAnswer_A - - Write a MDNS A answer to the UDP output buffer. - - NAME (var, host/service domain, eg. esp8266.local - TYPE (16bit, eg. A) - CLASS (16bit, eg. IN) - TTL (32bit, eg. 120) - RDLENGTH (16bit, eg 4) - RDATA (var, eg. 123.456.789.012) - - eg. esp8266.local A 0x8001 120 4 123.456.789.012 - Ref: http://www.zytrax.com/books/dns/ch8/a.html -*/ -bool MDNSResponder::_writeMDNSAnswer_A(IPAddress p_IPAddress, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A (%s)\n"), p_IPAddress.toString().c_str());); - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_A, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - const unsigned char aucIPAddress[MDNS_IP4_SIZE] = { p_IPAddress[0], p_IPAddress[1], p_IPAddress[2], p_IPAddress[3] }; - bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL - (_write16(MDNS_IP4_SIZE, p_rSendParameter)) && // RDLength - (_udpAppendBuffer(aucIPAddress, MDNS_IP4_SIZE)) && // RData - (p_rSendParameter.shiftOffset(MDNS_IP4_SIZE))); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A: FAILED!\n")); - }); - return bResult; - -} - -/* - MDNSResponder::_writeMDNSAnswer_PTR_IP4 - - Write a MDNS reverse IP4 PTR answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - eg. 012.789.456.123.in-addr.arpa PTR 0x8001 120 15 esp8266.local - Used while answering reverse IP4 questions -*/ -bool MDNSResponder::_writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4 (%s)\n"), p_IPAddress.toString().c_str());); - - stcMDNS_RRDomain reverseIP4Domain; - stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - stcMDNS_RRDomain hostDomain; - bool bResult = ((_buildDomainForReverseIP4(p_IPAddress, reverseIP4Domain)) && // 012.789.456.123.in-addr.arpa - (_writeMDNSRRDomain(reverseIP4Domain, p_rSendParameter)) && - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL - (_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4: FAILED!\n")); - }); - return bResult; -} -#endif - -/* - MDNSResponder::_writeMDNSAnswer_PTR_TYPE - - Write a MDNS PTR answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - PTR all-services -> service type - eg. _services._dns-sd._udp.local PTR 0x8001 5400 xx _http._tcp.local - http://www.zytrax.com/books/dns/ch8/ptr.html -*/ -bool MDNSResponder::_writeMDNSAnswer_PTR_TYPE(MDNSResponder::stcMDNSService& p_rService, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE\n"));); - - stcMDNS_RRDomain dnssdDomain; - stcMDNS_RRDomain serviceDomain; - stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet - bool bResult = ((_buildDomainForDNSSD(dnssdDomain)) && // _services._dns-sd._udp.local - (_writeMDNSRRDomain(dnssdDomain, p_rSendParameter)) && - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL - (_writeMDNSServiceDomain(p_rService, false, true, p_rSendParameter))); // RDLength & RData (service domain, eg. _http._tcp.local) - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeMDNSAnswer_PTR_NAME - - Write a MDNS PTR answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - PTR service type -> service name - eg. _http.tcp.local PTR 0x8001 120 xx myESP._http._tcp.local - http://www.zytrax.com/books/dns/ch8/ptr.html -*/ -bool MDNSResponder::_writeMDNSAnswer_PTR_NAME(MDNSResponder::stcMDNSService& p_rService, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME\n"));); - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet - bool bResult = ((_writeMDNSServiceDomain(p_rService, false, false, p_rSendParameter)) && // _http._tcp.local - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL - (_writeMDNSServiceDomain(p_rService, true, true, p_rSendParameter))); // RDLength & RData (service domain, eg. MyESP._http._tcp.local) - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME: FAILED!\n")); - }); - return bResult; -} - - -/* - MDNSResponder::_writeMDNSAnswer_TXT - - Write a MDNS TXT answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - The TXT items in the RDATA block are 'length byte encoded': [len]vardata - - eg. myESP._http._tcp.local TXT 0x8001 120 4 c#=1 - http://www.zytrax.com/books/dns/ch8/txt.html -*/ -bool MDNSResponder::_writeMDNSAnswer_TXT(MDNSResponder::stcMDNSService& p_rService, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT\n"));); - - bool bResult = false; - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_TXT, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - - if ((_collectServiceTxts(p_rService)) && - (_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL - (_write16(p_rService.m_Txts.length(), p_rSendParameter))) // RDLength - { - - bResult = true; - // RData Txts - for (stcMDNSServiceTxt* pTxt = p_rService.m_Txts.m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) - { - unsigned char ucLengthByte = pTxt->length(); - bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length - (p_rSendParameter.shiftOffset(sizeof(ucLengthByte))) && - ((size_t)os_strlen(pTxt->m_pcKey) == m_pUDPContext->append(pTxt->m_pcKey, os_strlen(pTxt->m_pcKey))) && // Key - (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcKey))) && - (1 == m_pUDPContext->append("=", 1)) && // = - (p_rSendParameter.shiftOffset(1)) && - ((!pTxt->m_pcValue) || - (((size_t)os_strlen(pTxt->m_pcValue) == m_pUDPContext->append(pTxt->m_pcValue, os_strlen(pTxt->m_pcValue))) && // Value - (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcValue)))))); - - DEBUG_EX_ERR(if (!bResult) - { - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED to write %sTxt %s=%s!\n"), (pTxt->m_bTemp ? "temp. " : ""), (pTxt->m_pcKey ? : "?"), (pTxt->m_pcValue ? : "?")); - }); - } - } - _releaseTempServiceTxts(p_rService); - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED!\n")); - }); - return bResult; -} - -#ifdef MDNS_IP6_SUPPORT -/* - MDNSResponder::_writeMDNSAnswer_AAAA - - Write a MDNS AAAA answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - eg. esp8266.local AAAA 0x8001 120 16 xxxx::xx - http://www.zytrax.com/books/dns/ch8/aaaa.html -*/ -bool MDNSResponder::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA\n"));); - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_AAAA, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && // esp8266.local - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL - (_write16(MDNS_IP6_SIZE, p_rSendParameter)) && // RDLength - (false /*TODO: IP6 version of: _udpAppendBuffer((uint32_t)p_IPAddress, MDNS_IP4_SIZE)*/)); // RData - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA: FAILED!\n")); - }); - return bResult; -} - -/* - MDNSResponder::_writeMDNSAnswer_PTR_IP6 - - Write a MDNS reverse IP6 PTR answer to the UDP output buffer. - See: '_writeMDNSAnswer_A' - - eg. xxxx::xx.in6.arpa PTR 0x8001 120 15 esp8266.local - Used while answering reverse IP6 questions -*/ -bool MDNSResponder::_writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6\n"));); - - stcMDNS_RRDomain reverseIP6Domain; - stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - bool bResult = ((_buildDomainForReverseIP6(p_IPAddress, reverseIP6Domain)) && // xxxx::xx.ip6.arpa - (_writeMDNSRRDomain(reverseIP6Domain, p_rSendParameter)) && - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL - (_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6: FAILED!\n")); - }); - return bResult; -} -#endif - -/* - MDNSResponder::_writeMDNSAnswer_SRV - - eg. MyESP._http.tcp.local SRV 0x8001 120 0 0 60068 esp8266.local - http://www.zytrax.com/books/dns/ch8/srv.html ???? Include instance name ???? -*/ -bool MDNSResponder::_writeMDNSAnswer_SRV(MDNSResponder::stcMDNSService& p_rService, - MDNSResponder::stcMDNSSendParameter& p_rSendParameter) -{ - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV\n"));); - - uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyQuery - ? 0 - : p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostname, false)); - - stcMDNS_RRAttributes attributes(DNS_RRTYPE_SRV, - ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet - stcMDNS_RRDomain hostDomain; - bool bResult = ((_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local - (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS - (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL - (!u16CachedDomainOffset - // No cache for domain name (or no compression allowed) - ? ((_buildDomainForHost(m_pcHostname, hostDomain)) && - (_write16((sizeof(uint16_t /*Prio*/) + // RDLength - sizeof(uint16_t /*Weight*/) + - sizeof(uint16_t /*Port*/) + - hostDomain.m_u16NameLength), p_rSendParameter)) && // Domain length - (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority - (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight - (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port - (p_rSendParameter.addDomainCacheItem((const void*)m_pcHostname, false, p_rSendParameter.m_u16Offset)) && - (_writeMDNSRRDomain(hostDomain, p_rSendParameter))) // Host, eg. esp8266.local - // Cache available for domain - : ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset - (_write16((sizeof(uint16_t /*Prio*/) + // RDLength - sizeof(uint16_t /*Weight*/) + - sizeof(uint16_t /*Port*/) + - 2), p_rSendParameter)) && // Length of 'C0xx' - (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority - (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight - (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port - (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) - (_write8((uint8_t)u16CachedDomainOffset, p_rSendParameter))))); // Offset - - DEBUG_EX_ERR(if (!bResult) -{ - DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV: FAILED!\n")); - }); - return bResult; -} - -} // namespace MDNSImplementation - -} // namespace esp8266 - - - - - - diff --git a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h b/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h deleted file mode 100644 index a3bcc4b370..0000000000 --- a/libraries/ESP8266mDNS/OLDmDNS/LEAmDNS_lwIPdefs.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - LEAmDNS_Priv.h - - License (MIT license): - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -*/ - -#ifndef MDNS_LWIPDEFS_H -#define MDNS_LWIPDEFS_H - -#include -#if LWIP_VERSION_MAJOR == 1 - -#include // DNS_RRTYPE_xxx - -// cherry pick from lwip1 dns.c/mdns.c source files: -#define DNS_MQUERY_PORT 5353 -#define DNS_MQUERY_IPV4_GROUP_INIT IPAddress(224,0,0,251) /* resolver1.opendns.com */ -#define DNS_RRCLASS_ANY 255 /* any class */ - -#else // lwIP > 1 - -#include // DNS_RRTYPE_xxx, DNS_MQUERY_PORT - -#endif - -#endif // MDNS_LWIPDEFS_H From b5fefcfc2815e29c5526fe9df0d1b307dd47fb81 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Sat, 23 May 2020 18:26:52 +0200 Subject: [PATCH 11/12] fix for lwIP-v1 --- cores/esp8266/IPAddress.h | 1 + libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp | 2 +- libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp | 2 +- libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/IPAddress.h b/cores/esp8266/IPAddress.h index cdd4b2499f..6fcbee95fe 100644 --- a/cores/esp8266/IPAddress.h +++ b/cores/esp8266/IPAddress.h @@ -42,6 +42,7 @@ #define CONST /* nothing: lwIP-v1 does not use const */ #define ip4_addr_netcmp ip_addr_netcmp #define netif_dhcp_data(netif) ((netif)->dhcp) +#define netif_get_index(netif) ((u8_t)((netif)->num + 1)) #else // lwIP-v2+ #define CONST const #if !LWIP_IPV6 diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp index c8c05082c5..1553c3df4c 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp @@ -941,7 +941,7 @@ bool clsLEAMDNSHost::_leaveMulticastGroups(void) #ifdef MDNS_IPV4_SUPPORT ip_addr_t multicast_addr_V4 = DNS_MQUERY_IPV4_GROUP_INIT; #if LWIP_VERSION_MAJOR == 1 - if (ERR_OK != igmp_leavegroup(ip_2_ip4(&m_rNetIf.ip_addr), ip_2_ip4(&multicast_addr_V4))) + if (ERR_OK != igmp_leavegroup(ip_2_ip4(&m_pNetIf->ip_addr), ip_2_ip4(&multicast_addr_V4))) #else if (ERR_OK != igmp_leavegroup_netif(m_pNetIf, ip_2_ip4(&multicast_addr_V4))) #endif diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp index 36b5ece554..0165d2962d 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp @@ -624,7 +624,7 @@ IPAddress clsLEAMDNSHost::_getResponderIPAddress(enuIPProtocolType p_IPProtocolT if (enuIPProtocolType::V4 == p_IPProtocolType) { #if LWIP_VERSION_MAJOR == 1 - ipResponder = ip_2_ip4(m_rNetIf.ip_addr); + ipResponder = ip_2_ip4(m_pNetIf->ip_addr); #else ipResponder = netif_ip_addr4(m_pNetIf); #endif diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h b/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h index b28ea2a26e..54d7f36f48 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h @@ -35,6 +35,8 @@ #define DNS_MQUERY_IPV4_GROUP_INIT IPAddress(224,0,0,251) /* resolver1.opendns.com */ #define DNS_RRCLASS_ANY 255 /* any class */ +struct netif* netif_get_by_index(u8_t idx); + #else // lwIP > 1 #include // DNS_RRTYPE_xxx, DNS_MQUERY_PORT From ad6b4260013639a2cabdf27bda75590464e3c91c Mon Sep 17 00:00:00 2001 From: david gauchard Date: Sun, 24 May 2020 11:50:48 +0200 Subject: [PATCH 12/12] fix for lwIP-1.4 --- libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp | 1 + libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp b/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp index d3d4849a54..4eb45918f9 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp @@ -311,6 +311,7 @@ const char* clsLEAMDNSHost::clsBackbone::_DH(void) const Extracted (and slightly changed) from: https://github.com/yarrick/lwip/blob/master/src/core/netif.c */ +extern "C" struct netif* netif_get_by_index(u8_t idx) { struct netif *netif; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h b/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h index 54d7f36f48..0aa1712a81 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h @@ -35,6 +35,9 @@ #define DNS_MQUERY_IPV4_GROUP_INIT IPAddress(224,0,0,251) /* resolver1.opendns.com */ #define DNS_RRCLASS_ANY 255 /* any class */ +#ifdef __cplusplus +extern "C" +#endif struct netif* netif_get_by_index(u8_t idx); #else // lwIP > 1