From 3140611392a7a829699fea91a40803a636ae0f02 Mon Sep 17 00:00:00 2001
From: LaborEtArs <laboretars@googlemail.com>
Date: Sun, 13 Jan 2019 16:10:36 +0100
Subject: [PATCH 1/3] Fixes 1

- Better separation of ESP wifi thread code from user thread code
- Added a flag for 'update()'-less use (disabled by default)
- The too fast updates for service queries are fixed
- Switched fully to PolledTimeout; LEATimeFlag not needed anymore (BTW: a const 'expired()' method would be helpful)
- The device should stay visible now even after the first TTL timeout
- Improved service querying (queries five times now)

From 6b43b52093cec6c0575aa346626651655c979d95 Mon Sep 17 00:00:00 2001
From: LaborEtArs <laboretars@googlemail.com>
Date: Sun, 13 Jan 2019 16:25:51 +0100
Subject: [PATCH 2/3] LEAmDNS fixes 1

- Better separation of ESP wifi thread code from user thread code
- Added a flag for 'update()'-less use (disabled by default)
- The too fast updates for service queries are fixed
- Switched fully to PolledTimeout; LEATimeFlag not needed anymore (BTW: a const 'expired()' method would be helpful)
- The device should stay visible now even after the first TTL timeout
- Improved service querying (queries five times now)
---
 LEAmDNS.cpp          | 1130 +++++++++++++++++++++
 LEAmDNS.h            | 1291 ++++++++++++++++++++++++
 LEAmDNS_Control.cpp  | 1853 +++++++++++++++++++++++++++++++++++
 LEAmDNS_Helpers.cpp  |  743 ++++++++++++++
 LEAmDNS_Priv.h       |  177 ++++
 LEAmDNS_Structs.cpp  | 2221 ++++++++++++++++++++++++++++++++++++++++++
 LEAmDNS_Transfer.cpp | 1638 +++++++++++++++++++++++++++++++
 7 files changed, 9053 insertions(+)
 create mode 100644 LEAmDNS.cpp
 create mode 100644 LEAmDNS.h
 create mode 100644 LEAmDNS_Control.cpp
 create mode 100644 LEAmDNS_Helpers.cpp
 create mode 100644 LEAmDNS_Priv.h
 create mode 100644 LEAmDNS_Structs.cpp
 create mode 100644 LEAmDNS_Transfer.cpp

diff --git a/LEAmDNS.cpp b/LEAmDNS.cpp
new file mode 100644
index 0000000000..a88d46c6af
--- /dev/null
+++ b/LEAmDNS.cpp
@@ -0,0 +1,1130 @@
+/*
+ * 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 "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),
+    m_pServiceTxtCallbackUserdata(0),
+#ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
+    m_bPassivModeEnabled(true) {
+#else
+    m_bPassivModeEnabled(false) {
+#endif
+    
+}
+
+/*
+ * 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) {
+    
+    bool    bResult = false;
+    
+    if (_setHostname(p_pcHostname)) {
+        
+        m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP& pEvent) {
+            (void) pEvent;
+            _restart();
+        });
+
+        m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected& pEvent) {
+            (void) pEvent;
+            _restart();
+        });
+            
+        bResult = _restart();
+    }
+    DEBUG_EX_ERR(if (!bResult) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: FAILED for '%s'!\n"), (p_pcHostname ?: "-")); } );
+    return bResult;
+}
+
+/*
+ * MDNSResponder::begin (LEGACY)
+ */
+bool MDNSResponder::begin(const char* p_pcHostname,
+                          IPAddress p_IPAddress,
+                          uint32_t p_u32TTL /*= 120*/) {
+    
+    (void) p_IPAddress;
+    (void) p_u32TTL;
+    return begin(p_pcHostname);
+}
+
+/*
+ * MDNSResponder::close
+ *
+ * Ends the MDNS responder.
+ * Announced services are unannounced (by multicasting a goodbye message)
+ *
+ */
+bool MDNSResponder::close(void) {
+    
+    _announce(false, true);
+    _resetProbeStatus(false);   // Stop probing
+
+    _releaseServiceQueries();
+    _releaseUDPContext();
+    _releaseHostname();
+    
+    return true;
+}
+
+/*
+ * 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(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(String p_strService,
+                               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(String p_strService,
+                                  String p_strProtocol,
+                                  String p_strKey,
+                                  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::MDNSDynamicServiceTxtCallbackFn p_fnCallback,
+                                                 void* p_pUserdata) {
+    
+    m_fnServiceTxtCallback = p_fnCallback;
+    m_pServiceTxtCallbackUserdata = p_pUserdata;
+    
+    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::MDNSDynamicServiceTxtCallbackFn p_fnCallback,
+                                                 void* p_pUserdata) {
+
+    bool    bResult = false;
+    
+    stcMDNSService* pService = _findService(p_hService);
+    if (pService) {
+        pService->m_fnTxtCallback = p_fnCallback;
+        pService->m_pTxtCallbackUserdata = p_pUserdata;
+        
+        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*/) {
+    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"), p_pcService, p_pcProtocol););
+    }
+    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(String p_strService,
+                                     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::MDNSServiceQueryCallbackFn p_fnCallback,
+                                                                    void* p_pUserdata) {
+    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_pUserdata = p_pUserdata;
+        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);
+}
+
+/*
+ * 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::setProbeResultCallback(MDNSResponder::MDNSProbeResultCallbackFn p_fnCallback,
+                                           void* p_pUserdata) {
+    
+    m_HostProbeInformation.m_fnProbeResultCallback = p_fnCallback;
+    m_HostProbeInformation.m_pProbeResultCallbackUserdata = p_pUserdata;
+    
+    return true;
+}
+
+/*
+ * 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::MDNSProbeResultCallbackFn p_fnCallback,
+                                                  void* p_pUserdata) {
+    bool    bResult = false;
+
+    stcMDNSService* pService = _findService(p_hService);
+    if (pService) {
+        pService->m_ProbeInformation.m_fnProbeResultCallback = p_fnCallback;
+        pService->m_ProbeInformation.m_pProbeResultCallbackUserdata = p_pUserdata;
+
+        bResult = true;
+    }
+    return bResult;
+}
+
+
+/*
+ * 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/LEAmDNS.h b/LEAmDNS.h
new file mode 100644
index 0000000000..f5a6702707
--- /dev/null
+++ b/LEAmDNS.h
@@ -0,0 +1,1291 @@
+/*
+ * 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<u32AnswerCount; ++u) { const char* pHostname = MDNS.answerHostname(u); }'
+ *    You should call MDNS.removeQuery() sometimes later (when the answers are nott needed anymore)
+ *
+ *  Dynamic:
+ *    Install a dynamic query by calling 'DNSResponder::hMDNSServiceQuery hServiceQuery = MDNS.installServiceQuery("http", "tcp", serviceQueryCallback, &userData);'
+ *    The callback 'serviceQueryCallback(MDNSResponder* p_MDNSResponder, const hMDNSServiceQuery p_hServiceQuery, uint32_t p_u32AnswerIndex,
+ *                                       enuServiceQueryAnswerType p_ServiceQueryAnswerType, bool p_bSetContent, void* p_pUserdata)'
+ *    is called for any change in the answer set.
+ *    Call 'MDNS.removeServiceQuery(hServiceQuery);' 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, 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
+ *  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
+ *
+ *  Some NOT used message types:
+ *  OPT (0x29):             eDNS
+ *  NSEC (0x2F):            DNSSEC
+ *
+ *
+ *  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_H
+#define MDNS_H
+
+#include <functional>   // for UdpContext.h
+#include "WiFiUdp.h"
+#include "lwip/udp.h"
+#include "debug.h"
+#include "include/UdpContext.h"
+#include <limits>
+#include <PolledTimeout.h>
+
+#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, ...)
+    bool begin(const char* p_pcHostname);
+    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(void);
+
+    // Change hostname (probing is restarted)
+    bool setHostname(const char* p_pcHostname);
+        // for compatibility...
+        bool setHostname(String p_strHostname);
+    
+    /**
+     * 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(String p_strServiceName,
+                        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);}
+    
+    /**
+     * 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(String p_strService,
+                           String p_strProtocol,
+                           String p_strKey,
+                           String p_strValue);
+    
+    /**
+     * MDNSDynamicServiceTxtCallbackFn
+     * Callback function for dynamic MDNS TXT items
+     */
+    typedef bool (*MDNSDynamicServiceTxtCallbackFn)(MDNSResponder* p_pMDNSResponder,
+                                                    const hMDNSService p_hService,
+                                                    void* p_pUserdata);
+
+    // 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,
+                                      void* p_pUserdata);
+    // 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,
+                                      void* p_pUserdata);
+    
+    // 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(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_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;
+
+    /**
+     * MDNSServiceQueryCallbackFn
+     * Callback function for received answers for dynamic service queries
+     */
+    typedef bool (*MDNSServiceQueryCallbackFn)(MDNSResponder* p_pMDNSResponder,
+                                               const hMDNSServiceQuery p_hServiceQuery, // dynamic service query handle
+                                               uint32_t p_u32AnswerIndex,               // index of the updated answer
+                                               uint32_t p_u32ServiceQueryAnswerMask,    // flag for the updated answer item
+                                               bool p_bSetContent,                      // true: Answer component set, false: component deleted
+                                               void* p_pUserdata);                      // pUserdata set via 'installServiceQuery'
+
+    // 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,
+                                          void* p_pUserdata);
+    // Remove a dynamic service query
+    bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery);
+
+    uint32_t answerCount(const 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 bool (*MDNSProbeResultCallbackFn)(MDNSResponder* p_pMDNSResponder,
+                                              const char* p_pcDomainName,
+                                              const hMDNSService p_hMDNSService,    // 0 for host domain
+                                              bool p_bProbeResult,
+                                              void* p_pUserdata);
+
+    // Set a global callback function for host and service probe results
+    // The callback function is called, when the probeing for the host domain
+    // (or a service domain, which hasn't got a service specific callback)
+    // Succeededs or fails.
+    // In case of failure, the failed domain name should be changed.
+    bool setProbeResultCallback(MDNSProbeResultCallbackFn p_fnCallback,
+                                void* p_pUserdata);
+    // Set a service specific probe result callcack
+    bool setServiceProbeResultCallback(const hMDNSService p_hService,
+                                       MDNSProbeResultCallbackFn p_fnCallback,
+                                       void* p_pUserdata);
+    
+    // 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:
+    /** STRUCTS **/
+    /**
+     * 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::oneShot m_Timeout;      // Used for probes and announcements
+        //clsMDNSTimeFlag                 m_TimeFlag;     // Used for probes and announcements
+        bool                            m_bConflict;
+        bool                            m_bTiebreakNeeded;
+        MDNSProbeResultCallbackFn       m_fnProbeResultCallback;
+        void*                           m_pProbeResultCallbackUserdata;
+
+        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;
+        MDNSDynamicServiceTxtCallbackFn m_fnTxtCallback;
+        void*                           m_pTxtCallbackUserdata;
+        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::oneShot m_TTLTimeout;
+                timeoutLevel_t                  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;
+            };
+#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
+        MDNSServiceQueryCallbackFn      m_fnCallback;
+        void*                           m_pUserdata;
+        bool                            m_bLegacyQuery;
+        uint8_t                         m_u8SentCount;
+        esp8266::polledTimeout::oneShot 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;
+    MDNSDynamicServiceTxtCallbackFn m_fnServiceTxtCallback;
+    void*                           m_pServiceTxtCallbackUserdata;
+    bool                            m_bPassivModeEnabled;
+    stcProbeInformation             m_HostProbeInformation;
+
+    /** 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,
+                                    int p_iWiFiOpMode);
+    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);
+                        
+    IPAddress _getResponseMulticastInterface(int p_iWiFiOpModes) const;
+
+    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);
+
+    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/LEAmDNS_Control.cpp b/LEAmDNS_Control.cpp
new file mode 100644
index 0000000000..507c43b1ec
--- /dev/null
+++ b/LEAmDNS_Control.cpp
@@ -0,0 +1,1853 @@
+/*
+ * 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 <arch/cc.h>
+#include <sys/time.h>
+#include <HardwareSerial.h>
+#include <IPAddress.h>
+#include <lwip/ip_addr.h>
+#include <WString.h>
+#include <cstdint>
+
+/*
+ * 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 = ((WiFi.isConnected()) &&          // Has connection?
+                   (_updateProbeStatus()) &&        // Probing
+                   (_checkServiceQueryCache()));    // Service query cache check
+    }
+    return bResult;
+}
+
+/*
+ * MDNSResponder::_restart
+ */
+bool MDNSResponder::_restart(void) {
+    
+    return ((_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")););
+                    Serial.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););
+                        Serial.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!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()););
+
+                        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(SOFTAP_MODE | STATION_MODE))) {
+
+                            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(SOFTAP_MODE | STATION_MODE))) {
+
+                            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(SOFTAP_MODE | STATION_MODE));
+                            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;
+            sendParameter.m_bCacheFlush = false;
+
+            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) && (qd<p_MsgHeader.m_u16QDCount)); ++qd) {
+                    stcMDNS_RRQuestion  questionRR;
+                    bDumpResult = _readRRQuestion(questionRR);
+                    esp_yield();
+                }   // for questions
+                // Handle known answers
+                uint32_t    u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount);
+                for (uint32_t an=0; ((bDumpResult) && (an<u32Answers)); ++an) {
+                    stcMDNS_RRAnswer*   pRRAnswer = 0;
+                    bDumpResult = _readRRAnswer(pRRAnswer);
+                    if (pRRAnswer) {
+                        delete pRRAnswer;
+                        pRRAnswer = 0;
+                    }
+                    esp_yield();
+                }
+        );*/
+        m_pUDPContext->flush();
+        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(%lu) for "), 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) {
+                        pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_ServiceDomain, true, pServiceQuery->m_pUserdata);
+                    }
+                }
+            }
+            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(%lu) for "), 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) {
+                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_HostDomainAndPort, true, pServiceQuery->m_pUserdata);
+                        }
+                    }
+                }
+                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(%lu) for "), 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) {
+                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_Txts, true, pServiceQuery->m_pUserdata);
+                        }
+                    }
+                }
+                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(%lu) for "), 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) {
+                                    pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP4Address, true, pServiceQuery->m_pUserdata);
+                                }
+                            }
+                            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(SOFTAP_MODE | STATION_MODE) != 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.checkExpired(millis()))) {                           // 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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+
+            if (m_HostProbeInformation.m_fnProbeResultCallback) {
+                m_HostProbeInformation.m_fnProbeResultCallback(this, m_pcHostname, 0, true, m_HostProbeInformation.m_pProbeResultCallbackUserdata);
+            }
+
+            // 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.checkExpired(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()))) {
+
+        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 (%lu).\n\n"), m_HostProbeInformation.m_u8SentCount););
+            }
+            else {
+                m_HostProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+                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.checkExpired(millis()))) {             // 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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+
+                MDNSProbeResultCallbackFn   fnProbeResultCallback = 0;
+                void*                       pProbeResultCallbackUserdata = 0;
+                if (pService->m_ProbeInformation.m_fnProbeResultCallback) {
+                    fnProbeResultCallback = pService->m_ProbeInformation.m_fnProbeResultCallback;
+                    pProbeResultCallbackUserdata = pService->m_ProbeInformation.m_pProbeResultCallbackUserdata;
+                }
+                else {
+                    fnProbeResultCallback = m_HostProbeInformation.m_fnProbeResultCallback;
+                    pProbeResultCallbackUserdata = m_HostProbeInformation.m_pProbeResultCallbackUserdata;
+                }
+                if (fnProbeResultCallback) {
+                    fnProbeResultCallback(this, (pService->m_pcName ?: m_pcHostname), pService, true, pProbeResultCallbackUserdata);
+                }
+
+                // 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.checkExpired(millis()))) {
+
+            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 (%lu)\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount););
+                }
+                else {
+                    pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+                    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_fnProbeResultCallback) {
+        m_HostProbeInformation.m_fnProbeResultCallback(this, m_pcHostname, 0, false, m_HostProbeInformation.m_pProbeResultCallbackUserdata);
+
+        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
+    MDNSProbeResultCallbackFn   fnProbeResultCallback = 0;
+    void*                       pProbeResultCallbackUserdata = 0;
+    if (p_rService.m_ProbeInformation.m_fnProbeResultCallback) {
+        fnProbeResultCallback = p_rService.m_ProbeInformation.m_fnProbeResultCallback;
+        pProbeResultCallbackUserdata = p_rService.m_ProbeInformation.m_pProbeResultCallbackUserdata;
+    }
+    else {
+        fnProbeResultCallback = m_HostProbeInformation.m_fnProbeResultCallback;
+        pProbeResultCallbackUserdata = m_HostProbeInformation.m_pProbeResultCallbackUserdata;
+    }
+    if (fnProbeResultCallback) {
+        fnProbeResultCallback(this, (p_rService.m_pcName ?: m_pcHostname), &p_rService, false, pProbeResultCallbackUserdata);
+        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.checkExpired(millis()))) {
+
+            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))
+                                                        : std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+            }
+            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) {
+                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_ServiceDomain, false, pServiceQuery->m_pUserdata);
+                        }
+                        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) {
+                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), u32ContentFlags, false, pServiceQuery->m_pUserdata);
+                        }
+                    }
+                }   // 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) {
+                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_Txts, false, pServiceQuery->m_pUserdata);
+                        }
+                    }
+                }   // 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) {
+                                pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP4Address, false, pServiceQuery->m_pUserdata);
+                            }
+                        }
+                    }   // 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(SOFTAP_MODE | STATION_MODE), 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/LEAmDNS_Helpers.cpp b/LEAmDNS_Helpers.cpp
new file mode 100644
index 0000000000..f8042ff185
--- /dev/null
+++ b/LEAmDNS_Helpers.cpp
@@ -0,0 +1,743 @@
+/*
+ * 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(), 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(IP4_ADDR_ANY4, 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::_collectServiceTxts
+ */
+bool MDNSResponder::_collectServiceTxts(MDNSResponder::stcMDNSService& p_rService) {
+    
+    bool    bResult = (m_fnServiceTxtCallback
+                        ? m_fnServiceTxtCallback(this, (hMDNSService)&p_rService, m_pServiceTxtCallbackUserdata)
+                        : true);
+    
+    if ((bResult) &&
+        (p_rService.m_fnTxtCallback)) {
+        bResult = p_rService.m_fnTxtCallback(this, (hMDNSService)&p_rService, p_rService.m_pTxtCallbackUserdata);
+    }
+    return bResult;
+}
+
+/*
+ * 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/LEAmDNS_Priv.h b/LEAmDNS_Priv.h
new file mode 100644
index 0000000000..1893c119cf
--- /dev/null
+++ b/LEAmDNS_Priv.h
@@ -0,0 +1,177 @@
+/*
+ * 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
+
+
+#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
+
+
+/*  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                   40
+#define MDNS_SERVICE_TTL                180//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/LEAmDNS_Structs.cpp b/LEAmDNS_Structs.cpp
new file mode 100644
index 0000000000..e41e4a08ba
--- /dev/null
+++ b/LEAmDNS_Structs.cpp
@@ -0,0 +1,2221 @@
+/*
+ * 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(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
+    m_bConflict(false),
+    m_bTiebreakNeeded(false),
+    m_fnProbeResultCallback(0),
+    m_pProbeResultCallbackUserdata(0) {
+}
+
+/*
+ * MDNSResponder::stcProbeInformation::clear
+ */
+bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/) {
+
+    m_ProbingStatus = ProbingStatus_WaitingForData;
+    m_u8SentCount = 0;
+    m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+    m_bConflict = false;
+    m_bTiebreakNeeded = false;
+    if (p_bClearUserdata) {
+        m_fnProbeResultCallback = 0;
+        m_pProbeResultCallbackUserdata = 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),
+    m_pTxtCallbackUserdata(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(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
+    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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+    }
+    return true;
+}
+
+/*
+ * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged
+ */
+bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) const {
+
+    return ((m_u32TTL) &&
+            (TIMEOUTLEVEL_UNSET != m_timeoutLevel) &&
+            (m_TTLTimeout.checkExpired(millis())));
+}
+
+/*
+ * 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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+        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 = std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max();
+
+    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_pUserdata(0),
+    m_bLegacyQuery(false),
+    m_u8SentCount(0),
+    m_ResendTimeout(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
+    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_pUserdata = 0;
+    m_bLegacyQuery = false;
+    m_u8SentCount = 0;
+    m_ResendTimeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+    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/LEAmDNS_Transfer.cpp b/LEAmDNS_Transfer.cpp
new file mode 100644
index 0000000000..9554f97df1
--- /dev/null
+++ b/LEAmDNS_Transfer.cpp
@@ -0,0 +1,1638 @@
+/*
+ * 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) {
+        if (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(SOFTAP_MODE | STATION_MODE))) &&
+                       (m_pUDPContext->send(ipRemote, m_pUDPContext->getRemotePort())));
+        }
+        else {                              // Multicast response -> Send via the same network interface, that received the query
+            bResult = _sendMDNSMessage_Multicast(p_rSendParameter, (SOFTAP_MODE | STATION_MODE));
+        }
+    }
+    else {                                  // Multicast query -> Send by all available network interfaces
+        const int   caiWiFiOpModes[2] = { SOFTAP_MODE, STATION_MODE };
+        for (int iInterfaceId=0; ((bResult) && (iInterfaceId<=1)); ++iInterfaceId) {
+            if (wifi_get_opmode() & caiWiFiOpModes[iInterfaceId]) {
+                bResult = _sendMDNSMessage_Multicast(p_rSendParameter, caiWiFiOpModes[iInterfaceId]);
+            }
+        }
+    }
+
+    // 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,
+                                               int p_iWiFiOpMode) {
+    bool    bResult = false;
+
+    IPAddress   fromIPAddress;
+    fromIPAddress = _getResponseMulticastInterface(p_iWiFiOpMode);
+    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(0, 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;
+}
+
+/*
+ * MDNSResponder::_getResponseMulticastInterface
+ *
+ * Selects the appropriate interface for responses.
+ * If AP mode is enabled and the remote contact is in the APs local net, then the
+ * AP interface is used to send the response.
+ * Otherwise the Station interface (if available) is used.
+ *
+ */
+IPAddress MDNSResponder::_getResponseMulticastInterface(int p_iWiFiOpModes) const {
+    
+    ip_info IPInfo_Local;
+    bool    bFoundMatch = false;
+    
+    if ((p_iWiFiOpModes & SOFTAP_MODE) &&
+        (wifi_get_opmode() & SOFTAP_MODE)) {
+        //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _getResponseMulticastInterface: SOFTAP_MODE\n")););
+        // Get remote IP address
+        IPAddress IP_Remote;
+        IP_Remote = m_pUDPContext->getRemoteAddress();
+        // Get local (AP) IP address
+        wifi_get_ip_info(SOFTAP_IF, &IPInfo_Local);
+        
+        if ((IPInfo_Local.ip.addr) &&                                                       // Has local AP IP address AND
+            (ip4_addr_netcmp(ip_2_ip4((const ip_addr_t*)IP_Remote), &IPInfo_Local.ip, &IPInfo_Local.netmask))) { // Remote address is in the same subnet as the AP
+            bFoundMatch = true;
+        }
+    }
+    if ((!bFoundMatch) &&
+        (p_iWiFiOpModes & STATION_MODE) &&
+        (wifi_get_opmode() & STATION_MODE)) {
+        //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _getResponseMulticastInterface: STATION_MODE\n")););
+        // Get local (STATION) IP address
+        wifi_get_ip_info(STATION_IF, &IPInfo_Local);
+    }
+    //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _getResponseMulticastInterface(%i): %s\n"), p_iWiFiOpModes, IPAddress(IPInfo_Local.ip).toString().c_str()););
+    return IPAddress(IPInfo_Local.ip);
+}
+
+
+/**
+ * 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,
+                                       ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN));   // Cache flush? & 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,
+                                       ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN));   // Cache flush? & 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
+
+
+
+
+
+

From 4f303d8fddb1abf94a06aa71f7cf8fc944789e44 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Mon, 14 Jan 2019 10:12:05 +0100
Subject: [PATCH 3/3] move files

---
 LEAmDNS.cpp                                   | 1130 ---------
 LEAmDNS.h                                     | 1291 ----------
 LEAmDNS_Control.cpp                           | 1853 --------------
 LEAmDNS_Helpers.cpp                           |  743 ------
 LEAmDNS_Priv.h                                |  177 --
 LEAmDNS_Structs.cpp                           | 2221 -----------------
 LEAmDNS_Transfer.cpp                          | 1638 ------------
 libraries/ESP8266mDNS/src/LEAmDNS.cpp         |   21 +-
 libraries/ESP8266mDNS/src/LEAmDNS.h           |   66 +-
 libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp |  525 ++--
 libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp |    1 +
 libraries/ESP8266mDNS/src/LEAmDNS_Priv.h      |   23 +-
 libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp |  149 +-
 .../ESP8266mDNS/src/LEAmDNS_Transfer.cpp      |   16 +-
 14 files changed, 533 insertions(+), 9321 deletions(-)
 delete mode 100644 LEAmDNS.cpp
 delete mode 100644 LEAmDNS.h
 delete mode 100644 LEAmDNS_Control.cpp
 delete mode 100644 LEAmDNS_Helpers.cpp
 delete mode 100644 LEAmDNS_Priv.h
 delete mode 100644 LEAmDNS_Structs.cpp
 delete mode 100644 LEAmDNS_Transfer.cpp

diff --git a/LEAmDNS.cpp b/LEAmDNS.cpp
deleted file mode 100644
index a88d46c6af..0000000000
--- a/LEAmDNS.cpp
+++ /dev/null
@@ -1,1130 +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 "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),
-    m_pServiceTxtCallbackUserdata(0),
-#ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
-    m_bPassivModeEnabled(true) {
-#else
-    m_bPassivModeEnabled(false) {
-#endif
-    
-}
-
-/*
- * 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) {
-    
-    bool    bResult = false;
-    
-    if (_setHostname(p_pcHostname)) {
-        
-        m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP& pEvent) {
-            (void) pEvent;
-            _restart();
-        });
-
-        m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected& pEvent) {
-            (void) pEvent;
-            _restart();
-        });
-            
-        bResult = _restart();
-    }
-    DEBUG_EX_ERR(if (!bResult) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: FAILED for '%s'!\n"), (p_pcHostname ?: "-")); } );
-    return bResult;
-}
-
-/*
- * MDNSResponder::begin (LEGACY)
- */
-bool MDNSResponder::begin(const char* p_pcHostname,
-                          IPAddress p_IPAddress,
-                          uint32_t p_u32TTL /*= 120*/) {
-    
-    (void) p_IPAddress;
-    (void) p_u32TTL;
-    return begin(p_pcHostname);
-}
-
-/*
- * MDNSResponder::close
- *
- * Ends the MDNS responder.
- * Announced services are unannounced (by multicasting a goodbye message)
- *
- */
-bool MDNSResponder::close(void) {
-    
-    _announce(false, true);
-    _resetProbeStatus(false);   // Stop probing
-
-    _releaseServiceQueries();
-    _releaseUDPContext();
-    _releaseHostname();
-    
-    return true;
-}
-
-/*
- * 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(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(String p_strService,
-                               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(String p_strService,
-                                  String p_strProtocol,
-                                  String p_strKey,
-                                  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::MDNSDynamicServiceTxtCallbackFn p_fnCallback,
-                                                 void* p_pUserdata) {
-    
-    m_fnServiceTxtCallback = p_fnCallback;
-    m_pServiceTxtCallbackUserdata = p_pUserdata;
-    
-    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::MDNSDynamicServiceTxtCallbackFn p_fnCallback,
-                                                 void* p_pUserdata) {
-
-    bool    bResult = false;
-    
-    stcMDNSService* pService = _findService(p_hService);
-    if (pService) {
-        pService->m_fnTxtCallback = p_fnCallback;
-        pService->m_pTxtCallbackUserdata = p_pUserdata;
-        
-        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*/) {
-    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"), p_pcService, p_pcProtocol););
-    }
-    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(String p_strService,
-                                     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::MDNSServiceQueryCallbackFn p_fnCallback,
-                                                                    void* p_pUserdata) {
-    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_pUserdata = p_pUserdata;
-        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);
-}
-
-/*
- * 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::setProbeResultCallback(MDNSResponder::MDNSProbeResultCallbackFn p_fnCallback,
-                                           void* p_pUserdata) {
-    
-    m_HostProbeInformation.m_fnProbeResultCallback = p_fnCallback;
-    m_HostProbeInformation.m_pProbeResultCallbackUserdata = p_pUserdata;
-    
-    return true;
-}
-
-/*
- * 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::MDNSProbeResultCallbackFn p_fnCallback,
-                                                  void* p_pUserdata) {
-    bool    bResult = false;
-
-    stcMDNSService* pService = _findService(p_hService);
-    if (pService) {
-        pService->m_ProbeInformation.m_fnProbeResultCallback = p_fnCallback;
-        pService->m_ProbeInformation.m_pProbeResultCallbackUserdata = p_pUserdata;
-
-        bResult = true;
-    }
-    return bResult;
-}
-
-
-/*
- * 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/LEAmDNS.h b/LEAmDNS.h
deleted file mode 100644
index f5a6702707..0000000000
--- a/LEAmDNS.h
+++ /dev/null
@@ -1,1291 +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<u32AnswerCount; ++u) { const char* pHostname = MDNS.answerHostname(u); }'
- *    You should call MDNS.removeQuery() sometimes later (when the answers are nott needed anymore)
- *
- *  Dynamic:
- *    Install a dynamic query by calling 'DNSResponder::hMDNSServiceQuery hServiceQuery = MDNS.installServiceQuery("http", "tcp", serviceQueryCallback, &userData);'
- *    The callback 'serviceQueryCallback(MDNSResponder* p_MDNSResponder, const hMDNSServiceQuery p_hServiceQuery, uint32_t p_u32AnswerIndex,
- *                                       enuServiceQueryAnswerType p_ServiceQueryAnswerType, bool p_bSetContent, void* p_pUserdata)'
- *    is called for any change in the answer set.
- *    Call 'MDNS.removeServiceQuery(hServiceQuery);' 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, 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
- *  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
- *
- *  Some NOT used message types:
- *  OPT (0x29):             eDNS
- *  NSEC (0x2F):            DNSSEC
- *
- *
- *  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_H
-#define MDNS_H
-
-#include <functional>   // for UdpContext.h
-#include "WiFiUdp.h"
-#include "lwip/udp.h"
-#include "debug.h"
-#include "include/UdpContext.h"
-#include <limits>
-#include <PolledTimeout.h>
-
-#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, ...)
-    bool begin(const char* p_pcHostname);
-    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(void);
-
-    // Change hostname (probing is restarted)
-    bool setHostname(const char* p_pcHostname);
-        // for compatibility...
-        bool setHostname(String p_strHostname);
-    
-    /**
-     * 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(String p_strServiceName,
-                        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);}
-    
-    /**
-     * 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(String p_strService,
-                           String p_strProtocol,
-                           String p_strKey,
-                           String p_strValue);
-    
-    /**
-     * MDNSDynamicServiceTxtCallbackFn
-     * Callback function for dynamic MDNS TXT items
-     */
-    typedef bool (*MDNSDynamicServiceTxtCallbackFn)(MDNSResponder* p_pMDNSResponder,
-                                                    const hMDNSService p_hService,
-                                                    void* p_pUserdata);
-
-    // 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,
-                                      void* p_pUserdata);
-    // 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,
-                                      void* p_pUserdata);
-    
-    // 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(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_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;
-
-    /**
-     * MDNSServiceQueryCallbackFn
-     * Callback function for received answers for dynamic service queries
-     */
-    typedef bool (*MDNSServiceQueryCallbackFn)(MDNSResponder* p_pMDNSResponder,
-                                               const hMDNSServiceQuery p_hServiceQuery, // dynamic service query handle
-                                               uint32_t p_u32AnswerIndex,               // index of the updated answer
-                                               uint32_t p_u32ServiceQueryAnswerMask,    // flag for the updated answer item
-                                               bool p_bSetContent,                      // true: Answer component set, false: component deleted
-                                               void* p_pUserdata);                      // pUserdata set via 'installServiceQuery'
-
-    // 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,
-                                          void* p_pUserdata);
-    // Remove a dynamic service query
-    bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery);
-
-    uint32_t answerCount(const 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 bool (*MDNSProbeResultCallbackFn)(MDNSResponder* p_pMDNSResponder,
-                                              const char* p_pcDomainName,
-                                              const hMDNSService p_hMDNSService,    // 0 for host domain
-                                              bool p_bProbeResult,
-                                              void* p_pUserdata);
-
-    // Set a global callback function for host and service probe results
-    // The callback function is called, when the probeing for the host domain
-    // (or a service domain, which hasn't got a service specific callback)
-    // Succeededs or fails.
-    // In case of failure, the failed domain name should be changed.
-    bool setProbeResultCallback(MDNSProbeResultCallbackFn p_fnCallback,
-                                void* p_pUserdata);
-    // Set a service specific probe result callcack
-    bool setServiceProbeResultCallback(const hMDNSService p_hService,
-                                       MDNSProbeResultCallbackFn p_fnCallback,
-                                       void* p_pUserdata);
-    
-    // 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:
-    /** STRUCTS **/
-    /**
-     * 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::oneShot m_Timeout;      // Used for probes and announcements
-        //clsMDNSTimeFlag                 m_TimeFlag;     // Used for probes and announcements
-        bool                            m_bConflict;
-        bool                            m_bTiebreakNeeded;
-        MDNSProbeResultCallbackFn       m_fnProbeResultCallback;
-        void*                           m_pProbeResultCallbackUserdata;
-
-        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;
-        MDNSDynamicServiceTxtCallbackFn m_fnTxtCallback;
-        void*                           m_pTxtCallbackUserdata;
-        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::oneShot m_TTLTimeout;
-                timeoutLevel_t                  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;
-            };
-#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
-        MDNSServiceQueryCallbackFn      m_fnCallback;
-        void*                           m_pUserdata;
-        bool                            m_bLegacyQuery;
-        uint8_t                         m_u8SentCount;
-        esp8266::polledTimeout::oneShot 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;
-    MDNSDynamicServiceTxtCallbackFn m_fnServiceTxtCallback;
-    void*                           m_pServiceTxtCallbackUserdata;
-    bool                            m_bPassivModeEnabled;
-    stcProbeInformation             m_HostProbeInformation;
-
-    /** 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,
-                                    int p_iWiFiOpMode);
-    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);
-                        
-    IPAddress _getResponseMulticastInterface(int p_iWiFiOpModes) const;
-
-    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);
-
-    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/LEAmDNS_Control.cpp b/LEAmDNS_Control.cpp
deleted file mode 100644
index 507c43b1ec..0000000000
--- a/LEAmDNS_Control.cpp
+++ /dev/null
@@ -1,1853 +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 <arch/cc.h>
-#include <sys/time.h>
-#include <HardwareSerial.h>
-#include <IPAddress.h>
-#include <lwip/ip_addr.h>
-#include <WString.h>
-#include <cstdint>
-
-/*
- * 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 = ((WiFi.isConnected()) &&          // Has connection?
-                   (_updateProbeStatus()) &&        // Probing
-                   (_checkServiceQueryCache()));    // Service query cache check
-    }
-    return bResult;
-}
-
-/*
- * MDNSResponder::_restart
- */
-bool MDNSResponder::_restart(void) {
-    
-    return ((_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")););
-                    Serial.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););
-                        Serial.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!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()););
-
-                        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(SOFTAP_MODE | STATION_MODE))) {
-
-                            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(SOFTAP_MODE | STATION_MODE))) {
-
-                            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(SOFTAP_MODE | STATION_MODE));
-                            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;
-            sendParameter.m_bCacheFlush = false;
-
-            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) && (qd<p_MsgHeader.m_u16QDCount)); ++qd) {
-                    stcMDNS_RRQuestion  questionRR;
-                    bDumpResult = _readRRQuestion(questionRR);
-                    esp_yield();
-                }   // for questions
-                // Handle known answers
-                uint32_t    u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount);
-                for (uint32_t an=0; ((bDumpResult) && (an<u32Answers)); ++an) {
-                    stcMDNS_RRAnswer*   pRRAnswer = 0;
-                    bDumpResult = _readRRAnswer(pRRAnswer);
-                    if (pRRAnswer) {
-                        delete pRRAnswer;
-                        pRRAnswer = 0;
-                    }
-                    esp_yield();
-                }
-        );*/
-        m_pUDPContext->flush();
-        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(%lu) for "), 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) {
-                        pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_ServiceDomain, true, pServiceQuery->m_pUserdata);
-                    }
-                }
-            }
-            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(%lu) for "), 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) {
-                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_HostDomainAndPort, true, pServiceQuery->m_pUserdata);
-                        }
-                    }
-                }
-                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(%lu) for "), 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) {
-                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_Txts, true, pServiceQuery->m_pUserdata);
-                        }
-                    }
-                }
-                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(%lu) for "), 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) {
-                                    pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP4Address, true, pServiceQuery->m_pUserdata);
-                                }
-                            }
-                            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(SOFTAP_MODE | STATION_MODE) != 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.checkExpired(millis()))) {                           // 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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
-
-            if (m_HostProbeInformation.m_fnProbeResultCallback) {
-                m_HostProbeInformation.m_fnProbeResultCallback(this, m_pcHostname, 0, true, m_HostProbeInformation.m_pProbeResultCallbackUserdata);
-            }
-
-            // 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.checkExpired(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()))) {
-
-        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 (%lu).\n\n"), m_HostProbeInformation.m_u8SentCount););
-            }
-            else {
-                m_HostProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
-                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.checkExpired(millis()))) {             // 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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
-
-                MDNSProbeResultCallbackFn   fnProbeResultCallback = 0;
-                void*                       pProbeResultCallbackUserdata = 0;
-                if (pService->m_ProbeInformation.m_fnProbeResultCallback) {
-                    fnProbeResultCallback = pService->m_ProbeInformation.m_fnProbeResultCallback;
-                    pProbeResultCallbackUserdata = pService->m_ProbeInformation.m_pProbeResultCallbackUserdata;
-                }
-                else {
-                    fnProbeResultCallback = m_HostProbeInformation.m_fnProbeResultCallback;
-                    pProbeResultCallbackUserdata = m_HostProbeInformation.m_pProbeResultCallbackUserdata;
-                }
-                if (fnProbeResultCallback) {
-                    fnProbeResultCallback(this, (pService->m_pcName ?: m_pcHostname), pService, true, pProbeResultCallbackUserdata);
-                }
-
-                // 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.checkExpired(millis()))) {
-
-            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 (%lu)\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount););
-                }
-                else {
-                    pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
-                    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_fnProbeResultCallback) {
-        m_HostProbeInformation.m_fnProbeResultCallback(this, m_pcHostname, 0, false, m_HostProbeInformation.m_pProbeResultCallbackUserdata);
-
-        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
-    MDNSProbeResultCallbackFn   fnProbeResultCallback = 0;
-    void*                       pProbeResultCallbackUserdata = 0;
-    if (p_rService.m_ProbeInformation.m_fnProbeResultCallback) {
-        fnProbeResultCallback = p_rService.m_ProbeInformation.m_fnProbeResultCallback;
-        pProbeResultCallbackUserdata = p_rService.m_ProbeInformation.m_pProbeResultCallbackUserdata;
-    }
-    else {
-        fnProbeResultCallback = m_HostProbeInformation.m_fnProbeResultCallback;
-        pProbeResultCallbackUserdata = m_HostProbeInformation.m_pProbeResultCallbackUserdata;
-    }
-    if (fnProbeResultCallback) {
-        fnProbeResultCallback(this, (p_rService.m_pcName ?: m_pcHostname), &p_rService, false, pProbeResultCallbackUserdata);
-        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.checkExpired(millis()))) {
-
-            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))
-                                                        : std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
-            }
-            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) {
-                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_ServiceDomain, false, pServiceQuery->m_pUserdata);
-                        }
-                        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) {
-                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), u32ContentFlags, false, pServiceQuery->m_pUserdata);
-                        }
-                    }
-                }   // 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) {
-                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_Txts, false, pServiceQuery->m_pUserdata);
-                        }
-                    }
-                }   // 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) {
-                                pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP4Address, false, pServiceQuery->m_pUserdata);
-                            }
-                        }
-                    }   // 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(SOFTAP_MODE | STATION_MODE), 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/LEAmDNS_Helpers.cpp b/LEAmDNS_Helpers.cpp
deleted file mode 100644
index f8042ff185..0000000000
--- a/LEAmDNS_Helpers.cpp
+++ /dev/null
@@ -1,743 +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(), 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(IP4_ADDR_ANY4, 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::_collectServiceTxts
- */
-bool MDNSResponder::_collectServiceTxts(MDNSResponder::stcMDNSService& p_rService) {
-    
-    bool    bResult = (m_fnServiceTxtCallback
-                        ? m_fnServiceTxtCallback(this, (hMDNSService)&p_rService, m_pServiceTxtCallbackUserdata)
-                        : true);
-    
-    if ((bResult) &&
-        (p_rService.m_fnTxtCallback)) {
-        bResult = p_rService.m_fnTxtCallback(this, (hMDNSService)&p_rService, p_rService.m_pTxtCallbackUserdata);
-    }
-    return bResult;
-}
-
-/*
- * 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/LEAmDNS_Priv.h b/LEAmDNS_Priv.h
deleted file mode 100644
index 1893c119cf..0000000000
--- a/LEAmDNS_Priv.h
+++ /dev/null
@@ -1,177 +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
-
-
-#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
-
-
-/*  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                   40
-#define MDNS_SERVICE_TTL                180//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/LEAmDNS_Structs.cpp b/LEAmDNS_Structs.cpp
deleted file mode 100644
index e41e4a08ba..0000000000
--- a/LEAmDNS_Structs.cpp
+++ /dev/null
@@ -1,2221 +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(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
-    m_bConflict(false),
-    m_bTiebreakNeeded(false),
-    m_fnProbeResultCallback(0),
-    m_pProbeResultCallbackUserdata(0) {
-}
-
-/*
- * MDNSResponder::stcProbeInformation::clear
- */
-bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/) {
-
-    m_ProbingStatus = ProbingStatus_WaitingForData;
-    m_u8SentCount = 0;
-    m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
-    m_bConflict = false;
-    m_bTiebreakNeeded = false;
-    if (p_bClearUserdata) {
-        m_fnProbeResultCallback = 0;
-        m_pProbeResultCallbackUserdata = 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),
-    m_pTxtCallbackUserdata(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(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
-    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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
-    }
-    return true;
-}
-
-/*
- * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged
- */
-bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) const {
-
-    return ((m_u32TTL) &&
-            (TIMEOUTLEVEL_UNSET != m_timeoutLevel) &&
-            (m_TTLTimeout.checkExpired(millis())));
-}
-
-/*
- * 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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
-        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 = std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max();
-
-    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_pUserdata(0),
-    m_bLegacyQuery(false),
-    m_u8SentCount(0),
-    m_ResendTimeout(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
-    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_pUserdata = 0;
-    m_bLegacyQuery = false;
-    m_u8SentCount = 0;
-    m_ResendTimeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
-    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/LEAmDNS_Transfer.cpp b/LEAmDNS_Transfer.cpp
deleted file mode 100644
index 9554f97df1..0000000000
--- a/LEAmDNS_Transfer.cpp
+++ /dev/null
@@ -1,1638 +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) {
-        if (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(SOFTAP_MODE | STATION_MODE))) &&
-                       (m_pUDPContext->send(ipRemote, m_pUDPContext->getRemotePort())));
-        }
-        else {                              // Multicast response -> Send via the same network interface, that received the query
-            bResult = _sendMDNSMessage_Multicast(p_rSendParameter, (SOFTAP_MODE | STATION_MODE));
-        }
-    }
-    else {                                  // Multicast query -> Send by all available network interfaces
-        const int   caiWiFiOpModes[2] = { SOFTAP_MODE, STATION_MODE };
-        for (int iInterfaceId=0; ((bResult) && (iInterfaceId<=1)); ++iInterfaceId) {
-            if (wifi_get_opmode() & caiWiFiOpModes[iInterfaceId]) {
-                bResult = _sendMDNSMessage_Multicast(p_rSendParameter, caiWiFiOpModes[iInterfaceId]);
-            }
-        }
-    }
-
-    // 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,
-                                               int p_iWiFiOpMode) {
-    bool    bResult = false;
-
-    IPAddress   fromIPAddress;
-    fromIPAddress = _getResponseMulticastInterface(p_iWiFiOpMode);
-    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(0, 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;
-}
-
-/*
- * MDNSResponder::_getResponseMulticastInterface
- *
- * Selects the appropriate interface for responses.
- * If AP mode is enabled and the remote contact is in the APs local net, then the
- * AP interface is used to send the response.
- * Otherwise the Station interface (if available) is used.
- *
- */
-IPAddress MDNSResponder::_getResponseMulticastInterface(int p_iWiFiOpModes) const {
-    
-    ip_info IPInfo_Local;
-    bool    bFoundMatch = false;
-    
-    if ((p_iWiFiOpModes & SOFTAP_MODE) &&
-        (wifi_get_opmode() & SOFTAP_MODE)) {
-        //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _getResponseMulticastInterface: SOFTAP_MODE\n")););
-        // Get remote IP address
-        IPAddress IP_Remote;
-        IP_Remote = m_pUDPContext->getRemoteAddress();
-        // Get local (AP) IP address
-        wifi_get_ip_info(SOFTAP_IF, &IPInfo_Local);
-        
-        if ((IPInfo_Local.ip.addr) &&                                                       // Has local AP IP address AND
-            (ip4_addr_netcmp(ip_2_ip4((const ip_addr_t*)IP_Remote), &IPInfo_Local.ip, &IPInfo_Local.netmask))) { // Remote address is in the same subnet as the AP
-            bFoundMatch = true;
-        }
-    }
-    if ((!bFoundMatch) &&
-        (p_iWiFiOpModes & STATION_MODE) &&
-        (wifi_get_opmode() & STATION_MODE)) {
-        //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _getResponseMulticastInterface: STATION_MODE\n")););
-        // Get local (STATION) IP address
-        wifi_get_ip_info(STATION_IF, &IPInfo_Local);
-    }
-    //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _getResponseMulticastInterface(%i): %s\n"), p_iWiFiOpModes, IPAddress(IPInfo_Local.ip).toString().c_str()););
-    return IPAddress(IPInfo_Local.ip);
-}
-
-
-/**
- * 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,
-                                       ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN));   // Cache flush? & 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,
-                                       ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN));   // Cache flush? & 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.cpp b/libraries/ESP8266mDNS/src/LEAmDNS.cpp
index 638853388d..a88d46c6af 100644
--- a/libraries/ESP8266mDNS/src/LEAmDNS.cpp
+++ b/libraries/ESP8266mDNS/src/LEAmDNS.cpp
@@ -55,7 +55,12 @@ MDNSResponder::MDNSResponder(void)
     m_pcHostname(0),
     m_pServiceQueries(0),
     m_fnServiceTxtCallback(0),
-    m_pServiceTxtCallbackUserdata(0) {
+    m_pServiceTxtCallbackUserdata(0),
+#ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
+    m_bPassivModeEnabled(true) {
+#else
+    m_bPassivModeEnabled(false) {
+#endif
     
 }
 
@@ -123,7 +128,7 @@ bool MDNSResponder::begin(const char* p_pcHostname,
  */
 bool MDNSResponder::close(void) {
     
-    _announce(false);
+    _announce(false, true);
     _resetProbeStatus(false);   // Stop probing
 
     _releaseServiceQueries();
@@ -205,6 +210,7 @@ MDNSResponder::hMDNSService MDNSResponder::addService(const char* p_pcName,
           }
         }
     }   // 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;
 }
@@ -768,13 +774,17 @@ MDNSResponder::hMDNSServiceQuery MDNSResponder::installServiceQuery(const char*
         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_ERR(if (!hResult) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: FAILED for '%s.%s'!\n"), (p_pcService ?: "-"), (p_pcProtocol ?: "-")); } );
+    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;
 }
 
@@ -1073,6 +1083,9 @@ bool MDNSResponder::notifyAPChange(void) {
  */
 bool MDNSResponder::update(void) {
     
+    if (m_bPassivModeEnabled) {
+        m_bPassivModeEnabled = false;
+    }
     return _process(true);
 }
 
@@ -1083,7 +1096,7 @@ bool MDNSResponder::update(void) {
  */
 bool MDNSResponder::announce(void) {
     
-    return (_announce());
+    return (_announce(true, true));
 }       
 
 /*
diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.h b/libraries/ESP8266mDNS/src/LEAmDNS.h
index fc98b541b3..f5a6702707 100644
--- a/libraries/ESP8266mDNS/src/LEAmDNS.h
+++ b/libraries/ESP8266mDNS/src/LEAmDNS.h
@@ -65,7 +65,7 @@
  *  Reference:
  *  Used mDNS messages:
  *  A (0x01):               eg. esp8266.local A OP TTL 123.456.789.012
- *  AAAA (01Cx):            eg. esp8266.local AAAA OP TTL 1234:5678::90
+ *  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, IP4):        eg. 012.789.456.123.in-addr.arpa PTR OP TTL esp8266.local
@@ -107,7 +107,8 @@
 #include "lwip/udp.h"
 #include "debug.h"
 #include "include/UdpContext.h"
-#include "LEATimeFlag.h"
+#include <limits>
+#include <PolledTimeout.h>
 
 #include "ESP8266WiFi.h"
 
@@ -786,8 +787,9 @@ class MDNSResponder {
      */
     struct stcProbeInformation {
         enuProbingStatus                m_ProbingStatus;
-        uint8_t                         m_u8ProbesSent;
-        clsMDNSTimeFlag                  m_NextProbeTimeFlag;
+        uint8_t                         m_u8SentCount;  // Used for probes and announcements
+        esp8266::polledTimeout::oneShot m_Timeout;      // Used for probes and announcements
+        //clsMDNSTimeFlag                 m_TimeFlag;     // Used for probes and announcements
         bool                            m_bConflict;
         bool                            m_bTiebreakNeeded;
         MDNSProbeResultCallbackFn       m_fnProbeResultCallback;
@@ -842,14 +844,32 @@ class MDNSResponder {
              * stcTTL
              */
             struct stcTTL {
-                clsMDNSTimeFlag  m_TTLTimeFlag;
-                bool            m_bUpdateScheduled;
+                /**
+                 * 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;
 
-                stcTTL(uint32_t p_u32TTL = 0);
+                uint32_t                        m_u32TTL;
+                esp8266::polledTimeout::oneShot m_TTLTimeout;
+                timeoutLevel_t                  m_timeoutLevel;
+
+                stcTTL(void);
                 bool set(uint32_t p_u32TTL);
 
-                bool has80Percent(void) const;
-                bool isOutdated(void) const;
+                bool flagged(void) const;
+                bool restart(void);
+
+                bool prepareDeletion(void);
+                bool finalTimeoutLevel(void) const;
+
+                unsigned long timeout(void) const;
             };
 #ifdef MDNS_IP4_SUPPORT
             /**
@@ -861,7 +881,7 @@ class MDNSResponder {
                 stcTTL          m_TTL;
                 
                 stcIP4Address(IPAddress p_IPAddress,
-                               uint32_t p_u32TTL = 0);
+                              uint32_t p_u32TTL = 0);
             };
 #endif
 #ifdef MDNS_IP6_SUPPORT
@@ -872,6 +892,9 @@ class MDNSResponder {
                 stcIP6Address*  m_pNext;
                 IP6Address      m_IPAddress;
                 stcTTL          m_TTL;
+
+                stcIP6Address(IPAddress p_IPAddress,
+                              uint32_t p_u32TTL = 0);
             };
 #endif
 
@@ -932,13 +955,15 @@ class MDNSResponder {
 #endif
         };
 
-        stcMDNSServiceQuery*        m_pNext;
-        stcMDNS_RRDomain            m_ServiceTypeDomain;    // eg. _http._tcp.local
-        MDNSServiceQueryCallbackFn  m_fnCallback;
-        void*                       m_pUserdata;
-        bool                        m_bLegacyQuery;
-        bool                        m_bAwaitingAnswers;
-        stcAnswer*                  m_pAnswers;
+        stcMDNSServiceQuery*            m_pNext;
+        stcMDNS_RRDomain                m_ServiceTypeDomain;    // eg. _http._tcp.local
+        MDNSServiceQueryCallbackFn      m_fnCallback;
+        void*                           m_pUserdata;
+        bool                            m_bLegacyQuery;
+        uint8_t                         m_u8SentCount;
+        esp8266::polledTimeout::oneShot m_ResendTimeout;
+        bool                            m_bAwaitingAnswers;
+        stcAnswer*                      m_pAnswers;
 
         stcMDNSServiceQuery(void);
         ~stcMDNSServiceQuery(void);
@@ -1012,6 +1037,7 @@ class MDNSResponder {
     WiFiEventHandler                m_GotIPHandler;
     MDNSDynamicServiceTxtCallbackFn m_fnServiceTxtCallback;
     void*                           m_pServiceTxtCallbackUserdata;
+    bool                            m_bPassivModeEnabled;
     stcProbeInformation             m_HostProbeInformation;
 
     /** CONTROL **/
@@ -1047,7 +1073,8 @@ class MDNSResponder {
     bool _cancelProbingForService(stcMDNSService& p_rService);
     
     /* ANNOUNCE */
-    bool _announce(bool p_bAnnounce = true);
+    bool _announce(bool p_bAnnounce,
+                   bool p_bIncludeServices);
     bool _announceService(stcMDNSService& p_rService,
                           bool p_bAnnounce = true);
     
@@ -1064,7 +1091,8 @@ class MDNSResponder {
                              IPAddress p_IPAddress);
     bool _sendMDNSServiceQuery(const stcMDNSServiceQuery& p_ServiceQuery);
     bool _sendMDNSQuery(const stcMDNS_RRDomain& p_QueryDomain,
-                        uint16_t p_u16QueryType);
+                        uint16_t p_u16QueryType,
+                        stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers = 0);
                         
     IPAddress _getResponseMulticastInterface(int p_iWiFiOpModes) const;
 
diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp
index 1328e14892..507c43b1ec 100644
--- a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp
+++ b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp
@@ -59,30 +59,29 @@ namespace MDNSImplementation {
 /*
  * MDNSResponder::_process
  *
- * Run the MDNS process. Should be called in every 'loop'.
+ * 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 ((m_pUDPContext) &&          // UDPContext available AND
-        (m_pUDPContext->next())) {  // has content
-        //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _update: Calling _parseMessage\n")););
+    if (!p_bUserContext) {
         
-        bResult = _parseMessage();
-        if (p_bUserContext) {
-            esp_yield();
+        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")););
         }
-        //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parsePacket %s\n"), (bResult ? "succeeded" : "FAILED")););
     }
-    else if (p_bUserContext) {
-        if (bResult) {              // Probing
-            bResult = _updateProbeStatus();
-        }
-        if (bResult) {              // Service query cache check
-            bResult = _checkServiceQueryCache();
-        }
+    else {
+        bResult = ((WiFi.isConnected()) &&          // Has connection?
+                   (_updateProbeStatus()) &&        // Probing
+                   (_checkServiceQueryCache()));    // Service query cache check
     }
     return bResult;
 }
@@ -173,10 +172,11 @@ bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHea
         if ((bResult = _readRRQuestion(questionRR))) {
             // Define host replies, BUT only answer queries after probing is done
             u8HostOrServiceReplies =
-            sendParameter.m_u8HostReplyMask = ((ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus)
+            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 %u\n"), u8HostOrServiceReplies); });
+            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) {
@@ -197,15 +197,12 @@ bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHea
             // 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 = ((ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus)
+                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): %u (%s)\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, u8ReplyMaskForQuestion, IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()); } );
-                /*if ((u8ReplyMaskForQuestion) &&
-                    (0 == strcmp("hap", pService->m_pcService))) {
-                    DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service reply needed for (%s.%s.%s): %u (%s)\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, u8ReplyMaskForQuestion, IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str());
-                }*/
+                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) {
@@ -227,7 +224,7 @@ bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHea
             // 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
+                 (questionRR.m_bUnicast)) &&                                // Expressivly unicast query
                 (!sendParameter.m_bUnicast)) {
 
                 sendParameter.m_bUnicast = true;
@@ -272,7 +269,6 @@ bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHea
         else {
             DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to read question!\n")););
         }
-        //*esp_yield();
     }   // 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()); } );
@@ -386,11 +382,7 @@ bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHea
                     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 ((0 == strcmp("hap", pService->m_pcService))) {
-                            DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Known answer for (%s.%s.%s): %u (%s) %u\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pKnownRRAnswer->answerType(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), pKnownRRAnswer->m_u32TTL);
-                        }*/
-                        
-                        if (AnswerType_PTR == pKnownRRAnswer->answerType()) {
+                         if (AnswerType_PTR == pKnownRRAnswer->answerType()) {
                             stcMDNS_RRDomain    serviceDomain;
                             if ((u8ServiceMatchMask & ContentFlag_PTR_TYPE) &&
                                 (_buildDomainForService(*pService, false, serviceDomain)) &&
@@ -474,7 +466,6 @@ bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHea
             delete pKnownRRAnswer;
             pKnownRRAnswer = 0;
         }
-        //*esp_yield();
     }   // for answers
 
     if (bResult) {
@@ -482,22 +473,22 @@ bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHea
         uint8_t u8ReplyNeeded = sendParameter.m_u8HostReplyMask;
         for (stcMDNSService* pService=m_pServices; pService; pService=pService->m_pNext) {
             u8ReplyNeeded |= pService->m_u8ReplyMask;
-
-            if ((u8ReplyNeeded) &&
-                (0 == strcmp("hap", pService->m_pcService))) {
-                DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Sending service reply for (%s.%s.%s): %u (%s)\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, u8ReplyNeeded, IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()););
-            }
         }
 
         if (u8ReplyNeeded) {
-            DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Sending answer(%u)...\n"), 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;
+            sendParameter.m_bCacheFlush = false;
+
             bResult = _sendMDNSMessage(sendParameter);
         }
-        else {
-            //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: No reply needed\n")););
-        }
+        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")););
@@ -569,7 +560,6 @@ bool MDNSResponder::_parseResponse(const MDNSResponder::stcMDNS_MsgHeader& p_Msg
         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);
-            //*esp_yield();
         }   // for queries
         
         //
@@ -592,7 +582,6 @@ bool MDNSResponder::_parseResponse(const MDNSResponder::stcMDNS_MsgHeader& p_Msg
                 }
                 bResult = false;
             }
-            //*esp_yield();
         }   // for answers
         
         //
@@ -737,7 +726,6 @@ bool MDNSResponder::_processAnswers(const MDNSResponder::stcMDNS_RRAnswer* p_pAn
                 
                 pRRAnswer = pRRAnswer->m_pNext; // Next collected answer
             }   // while (answers)
-            //*esp_yield();
         } while ((bFoundNewKeyAnswer) &&
                  (bResult));
     }   // else: No answers provided
@@ -756,7 +744,7 @@ bool MDNSResponder::_processPTRAnswer(const MDNSResponder::stcMDNS_RRAnswerPTR*
     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 '_http._tcp'
+        // Check pending service queries for eg. '_http._tcp'
         
         stcMDNSServiceQuery*    pServiceQuery = _findNextServiceQueryByServiceType(p_pPTRAnswer->m_Header.m_Domain, 0);
         while (pServiceQuery) {
@@ -767,14 +755,13 @@ bool MDNSResponder::_processPTRAnswer(const MDNSResponder::stcMDNS_RRAnswerPTR*
                     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 for "));
+                                DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Updated TTL(%lu) for "), p_pPTRAnswer->m_u32TTL);
                                 _printRRDomain(pSQAnswer->m_ServiceDomain);
                                 DEBUG_OUTPUT.printf_P(PSTR("\n"));
                         );
                     }
-                    else {                      // received goodbye-message
-                        pSQAnswer->m_TTLServiceDomain.set(1);             // See RFC 6762, 10.1
-                        pSQAnswer->m_TTLServiceDomain.m_bUpdateScheduled = true;    // Avoid 'cache update' query
+                    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);
@@ -822,7 +809,7 @@ bool MDNSResponder::_processSRVAnswer(const MDNSResponder::stcMDNS_RRAnswerSRV*
                 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 for "));
+                            DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: Updated TTL(%lu) for "), p_pSRVAnswer->m_u32TTL);
                             _printRRDomain(pSQAnswer->m_ServiceDomain);
                             DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n"));
                     );
@@ -842,8 +829,7 @@ bool MDNSResponder::_processSRVAnswer(const MDNSResponder::stcMDNS_RRAnswerSRV*
                     }
                 }
                 else {                      // Goodby message
-                    pSQAnswer->m_TTLHostDomainAndPort.set(1);             // See RFC 6762, 10.1
-                    pSQAnswer->m_TTLHostDomainAndPort.m_bUpdateScheduled = true;    // Avoid 'cache update' query
+                    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);
@@ -875,7 +861,7 @@ bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT*
                 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 for "));
+                            DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: Updated TTL(%lu) for "), p_pTXTAnswer->m_u32TTL);
                             _printRRDomain(pSQAnswer->m_ServiceDomain);
                             DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n"));
                     );
@@ -890,8 +876,7 @@ bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT*
                     }
                 }
                 else {                      // Goodby message
-                    pSQAnswer->m_TTLTxts.set(1);          // See RFC 6762, 10.1
-                    pSQAnswer->m_TTLTxts.m_bUpdateScheduled = true; // Avoid 'cache update' query
+                    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);
@@ -927,14 +912,13 @@ bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT*
                         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 for "));
+                                    DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%lu) for "), 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.set(1);            // See RFC 6762, 10.1
-                            pIP4Address->m_TTL.m_bUpdateScheduled = true;   // Avoid 'cache update' query
+                            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);
@@ -990,14 +974,13 @@ bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT*
                         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 for "));
+                                    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.set(1);            // See RFC 6762, 10.1
-                            pIP6Address->m_TTL.m_bUpdateScheduled = true;   // Avoid 'cache update' query
+                            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);
@@ -1061,54 +1044,73 @@ bool MDNSResponder::_updateProbeStatus(void) {
         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_NextProbeTimeFlag.restart(rand() % MDNS_PROBE_DELAY);
+        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_NextProbeTimeFlag.flagged())) {                              // Time for next probe
+             (m_HostProbeInformation.m_Timeout.checkExpired(millis()))) {                           // Time for next probe
 
-        if (MDNS_PROBE_COUNT > m_HostProbeInformation.m_u8ProbesSent) {                             // Send 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")););
-                m_HostProbeInformation.m_NextProbeTimeFlag.restart(MDNS_PROBE_DELAY);
-                ++m_HostProbeInformation.m_u8ProbesSent;
+                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_NextProbeTimeFlag.reset();
+            m_HostProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
 
             if (m_HostProbeInformation.m_fnProbeResultCallback) {
                 m_HostProbeInformation.m_fnProbeResultCallback(this, m_pcHostname, 0, true, m_HostProbeInformation.m_pProbeResultCallbackUserdata);
             }
 
-            _announce();
+            // 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.checkExpired(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()))) {
+
+        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 (%lu).\n\n"), m_HostProbeInformation.m_u8SentCount););
+            }
+            else {
+                m_HostProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+                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_NextProbeTimeFlag.restart(MDNS_PROBE_DELAY);           // More or equal than first probe for host domain
+            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_NextProbeTimeFlag.flagged())) {                // Time for next probe
+                 (pService->m_ProbeInformation.m_Timeout.checkExpired(millis()))) {             // Time for next probe
 
-            if (MDNS_PROBE_COUNT > pService->m_ProbeInformation.m_u8ProbesSent) {                           // Send 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"), (pService->m_ProbeInformation.m_u8ProbesSent + 1)););
-                    pService->m_ProbeInformation.m_NextProbeTimeFlag.restart(MDNS_PROBE_DELAY);
-                    ++pService->m_ProbeInformation.m_u8ProbesSent;
+                    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"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol););
+                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_NextProbeTimeFlag.reset();
+                pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
 
                 MDNSProbeResultCallbackFn   fnProbeResultCallback = 0;
                 void*                       pProbeResultCallbackUserdata = 0;
@@ -1124,11 +1126,30 @@ bool MDNSResponder::_updateProbeStatus(void) {
                     fnProbeResultCallback(this, (pService->m_pcName ?: m_pcHostname), pService, true, pProbeResultCallbackUserdata);
                 }
 
-                //_announceService(*pService);
+                // 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.checkExpired(millis()))) {
+
+            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 (%lu)\n\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount););
+                }
+                else {
+                    pService->m_ProbeInformation.m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+                    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")); });
+    DEBUG_EX_ERR(if (!bResult) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: FAILED!\n\n")); });
     return bResult;
 }
 
@@ -1158,11 +1179,11 @@ bool MDNSResponder::_resetProbeStatus(bool p_bRestart /*= true*/) {
 bool MDNSResponder::_hasProbesWaitingForAnswers(void) const {
 
     bool    bResult = ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) &&      // Probing
-                       (0 < m_HostProbeInformation.m_u8ProbesSent));                                // And really 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_u8ProbesSent));                              // And really probing
+                   (0 < pService->m_ProbeInformation.m_u8SentCount));                               // And really probing
     }
     return bResult;
 }
@@ -1191,9 +1212,9 @@ bool MDNSResponder::_sendHostProbe(void) {
     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_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_pQuestions->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN);   // Unicast & INternet
     
         // Add known answers
 #ifdef MDNS_IP4_SUPPORT
@@ -1331,7 +1352,8 @@ bool MDNSResponder::_cancelProbingForService(stcMDNSService& p_rService) {
  * 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 /*= true*/) {
+bool MDNSResponder::_announce(bool p_bAnnounce,
+                              bool p_bIncludeServices) {
     
     bool    bResult = false;
 
@@ -1355,27 +1377,22 @@ bool MDNSResponder::_announce(bool p_bAnnounce /*= true*/) {
         sendParameter.m_u8HostReplyMask |= ContentFlag_PTR_IP6;             // PTR_IP6 answer
     #endif
 
-        DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing host %s (%u)\n"), m_pcHostname, sendParameter.m_u8HostReplyMask););
-        //bResult = _sendMDNSMessage(sendParameter);
-        //DEBUG_EX_ERR(if (!bResult) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: FAILED (A)!\n")); });
-
-        // Announce services (service type, name, SRV (location) and TXTs)
-        for (stcMDNSService* pService=m_pServices; ((bResult) && (pService)); pService=pService->m_pNext) {
-            //bResult = _announceService(*pService, p_bAnnounce);
-            //DEBUG_EX_ERR(if (!bResult) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: FAILED (B)!\n")); });
-
+        DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing host %s (content 0x%X)\n"), m_pcHostname, sendParameter.m_u8HostReplyMask););
 
-            if (ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) {
-                pService->m_u8ReplyMask = (ContentFlag_PTR_TYPE | ContentFlag_PTR_NAME | ContentFlag_SRV | ContentFlag_TXT);
+        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 (%u)\n"), (pService->m_pcName ?: m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_u8ReplyMask););
+                    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] _announceService: FAILED!\n")); });
+    DEBUG_EX_ERR(if (!bResult) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: FAILED!\n")); });
     return ((bResult) &&
             (_sendMDNSMessage(sendParameter)));
-    //return bResult;
 }
 
 /*
@@ -1398,7 +1415,7 @@ bool MDNSResponder::_announceService(stcMDNSService& p_rService,
 
         // 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 (%u)\n"), (p_rService.m_pcName ?: m_pcHostname), p_rService.m_pcService, p_rService.m_pcProtocol, p_rService.m_u8ReplyMask););
+        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;
     }
@@ -1441,7 +1458,31 @@ 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.checkExpired(millis()))) {
+
+            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))
+                                                        : std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+            }
+            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) &&
@@ -1450,94 +1491,121 @@ bool MDNSResponder::_checkServiceQueryCache(void) {
                 
                 // 1. level answer
                 if ((bResult) &&
-                    (pSQAnswer->m_TTLServiceDomain.has80Percent())) {
-                    
-                    bResult = ((_sendMDNSServiceQuery(*pServiceQuery)) &&
-                               ((pSQAnswer->m_TTLServiceDomain.m_bUpdateScheduled = true)));
-                    DEBUG_EX_INFO(
-                            DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Update scheduled for "));
-                            _printRRDomain(pSQAnswer->m_ServiceDomain);
-                            DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), (bResult ? "OK" : "FAILURE"));
-                    );
-                }
-                else if ((bResult) &&
-                         (pSQAnswer->m_TTLServiceDomain.isOutdated())) {
-                    
-                    // Delete
-                    if (pServiceQuery->m_fnCallback) {
-                        pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)/*(uint32_t)(-1)*/, ServiceQueryAnswerType_ServiceDomain, false, pServiceQuery->m_pUserdata);
+                    (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;
+                        );
                     }
-                    bResult = pServiceQuery->removeAnswer(pSQAnswer);
-                    pSQAnswer = 0;
-                    continue;   // Don't use this answer anymore
-                }
+                    else {
+                        // Timed out! -> Delete
+                        if (pServiceQuery->m_fnCallback) {
+                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_ServiceDomain, false, pServiceQuery->m_pUserdata);
+                        }
+                        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.has80Percent())) {
-                    
-                    bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_SRV)) &&
-                               ((pSQAnswer->m_TTLHostDomainAndPort.m_bUpdateScheduled = true)));
-                    DEBUG_EX_INFO(
-                            DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Update scheduled for "));
-                            _printRRDomain(pSQAnswer->m_ServiceDomain);
-                            DEBUG_OUTPUT.printf_P(PSTR(" host domain and port %s\n"), (bResult ? "OK" : "FAILURE"));
-                    );
-                }
-                else if ((bResult) &&
-                         (pSQAnswer->m_TTLHostDomainAndPort.isOutdated())) {
-                    
-                    // Delete
-                    pSQAnswer->m_HostDomain.clear();
-                    pSQAnswer->releaseHostDomain();
-                    pSQAnswer->m_u16Port = 0;
-                    pSQAnswer->m_TTLHostDomainAndPort.set(0/*, 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
+                    (pSQAnswer->m_TTLHostDomainAndPort.flagged())) {
 
-                    // Remove content flags for deleted answer parts
-                    pSQAnswer->m_u32ContentFlags &= ~u32ContentFlags;
+                    if (!pSQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) {
 
-                    if (pServiceQuery->m_fnCallback) {
-                        pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), u32ContentFlags, false, pServiceQuery->m_pUserdata);
+                        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) {
+                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), u32ContentFlags, false, pServiceQuery->m_pUserdata);
+                        }
+                    }
+                }   // HostDomainAndPort flagged
                 
                 // Txts (from TXT)
                 if ((bResult) &&
-                    (pSQAnswer->m_TTLTxts.has80Percent())) {
-                    
-                    bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_TXT)) &&
-                               ((pSQAnswer->m_TTLTxts.m_bUpdateScheduled = true)));
-                    DEBUG_EX_INFO(
-                            DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Update scheduled for "));
-                            _printRRDomain(pSQAnswer->m_ServiceDomain);
-                            DEBUG_OUTPUT.printf_P(PSTR(" TXTs %s\n"), (bResult ? "OK" : "FAILURE"));
-                    );
-                }
-                else if ((bResult) &&
-                         (pSQAnswer->m_TTLTxts.isOutdated())) {
-                    
-                    // Delete
-                    pSQAnswer->m_Txts.clear();
-                    pSQAnswer->m_TTLTxts.set(0/*, 0*/);
-                    
-                    // Remove content flags for deleted answer parts
-                    pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_Txts;
+                    (pSQAnswer->m_TTLTxts.flagged())) {
 
-                    if (pServiceQuery->m_fnCallback) {
-                        pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_Txts, false, pServiceQuery->m_pUserdata);
+                    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) {
+                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_Txts, false, pServiceQuery->m_pUserdata);
+                        }
+                    }
+                }   // TXTs flagged
                 
                 // 3. level answers
 #ifdef MDNS_IP4_SUPPORT
@@ -1549,30 +1617,42 @@ bool MDNSResponder::_checkServiceQueryCache(void) {
                            
                     stcMDNSServiceQuery::stcAnswer::stcIP4Address*  pNextIP4Address = pIP4Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end...
                     
-                    if (pIP4Address->m_TTL.has80Percent()) {      // Needs update
-                        if ((bAUpdateQuerySent) ||
-                            ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_A)))) {
-                            
-                            pIP4Address->m_TTL.m_bUpdateScheduled = true;
-                            bAUpdateQuerySent = true;
-                            
+                    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: Update scheduled for "));
+                                    DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove IP4 answer for "));
                                     _printRRDomain(pSQAnswer->m_ServiceDomain);
-                                    DEBUG_OUTPUT.printf_P(PSTR(" IP4 address (%s)\n"), (pIP4Address->m_IPAddress.toString().c_str()));
+                                    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) {
+                                pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP4Address, false, pServiceQuery->m_pUserdata);
+                            }
                         }
-                    }
-                    else if (pIP4Address->m_TTL.isOutdated()) {   // Outdated: can be deleted
-                        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) {
-                            pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP4Address, false, pServiceQuery->m_pUserdata);
-                        }
-                    }
+                    }   // IP4 flagged
                     
                     pIP4Address = pNextIP4Address;  // Next
                 }   // while
@@ -1586,30 +1666,42 @@ bool MDNSResponder::_checkServiceQueryCache(void) {
                            
                     stcMDNSServiceQuery::stcAnswer::stcIP6Address*  pNextIP6Address = pIP6Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end...
                     
-                    if (pIP6Address->m_TTL.has80Percent()) {      // Needs update
-                        if ((bAAAAUpdateQuerySent) ||
-                            ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) {
-                            
-                            pIP6Address->m_TTL.m_bUpdateScheduled = true;
-                            bAAAAUpdateQuerySent = true;
+                    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: Update scheduled for "));
+                                    DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove answer for "));
                                     _printRRDomain(pSQAnswer->m_ServiceDomain);
-                                    DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), (pIP6Address->m_IPAddress.toString().c_str()));
+                                    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);
+                            }
                         }
-                    }
-                    else if (pIP6Address->m_TTL.isOutdated()) {   // Outdated: can be deleted
-                        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
@@ -1618,6 +1710,11 @@ bool MDNSResponder::_checkServiceQueryCache(void) {
             }
         }
     }
+    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;
 }
@@ -1683,7 +1780,7 @@ uint8_t MDNSResponder::_replyMaskForHost(const MDNSResponder::stcMDNS_RRHeader&
     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(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: %u\n"), u8ReplyMask););
+    DEBUG_EX_INFO(if (u8ReplyMask) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: 0x%X\n"), u8ReplyMask); } );
     return u8ReplyMask;
 }
 
@@ -1747,7 +1844,7 @@ uint8_t MDNSResponder::_replyMaskForService(const MDNSResponder::stcMDNS_RRHeade
     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(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForService(%s.%s.%s): %u\n"), p_Service.m_pcName, p_Service.m_pcService, p_Service.m_pcProtocol, u8ReplyMask););
+    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;
 }
 
diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp
index d745f0b37e..f8042ff185 100644
--- a/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp
+++ b/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp
@@ -170,6 +170,7 @@ namespace MDNSImplementation {
  */
 
 bool MDNSResponder::_callProcess(void) {
+    DEBUG_EX_INFO(DEBUG_OUTPUT.printf("[MDNSResponder] _callProcess (%lu, triggered by: %s)\n", millis(), m_pUDPContext->getRemoteAddress().toString().c_str()););
 
     return _process(false);
 }
diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h b/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h
index 8abea5c31d..1893c119cf 100644
--- a/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h
+++ b/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h
@@ -35,16 +35,21 @@ namespace MDNSImplementation {
 
 // Enable class debug functions
 #define ESP_8266_MDNS_INCLUDE
-// #define DEBUG_ESP_MDNS_RESPONDER
+//#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_INFO
 #define DEBUG_ESP_MDNS_ERR
 #define DEBUG_ESP_MDNS_TX
 #define DEBUG_ESP_MDNS_RX
@@ -99,16 +104,18 @@ namespace MDNSImplementation {
  * 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              1
+#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
+#define MDNS_HOST_TTL                   40
+#define MDNS_SERVICE_TTL                180//4500
 
 /*
  * Compressed labels are flaged by the two topmost bits of the length byte being set
@@ -127,9 +134,15 @@ namespace MDNSImplementation {
 
 /*
  * 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
 
 
 /*
diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp
index c30094f580..e41e4a08ba 100644
--- a/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp
+++ b/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp
@@ -1158,9 +1158,8 @@ bool MDNSResponder::stcMDNS_RRAnswerGeneric::clear(void) {
  */
 MDNSResponder::stcProbeInformation::stcProbeInformation(void)
 :   m_ProbingStatus(ProbingStatus_WaitingForData),
-    m_u8ProbesSent(0),
-    //m_ulNextProbeTimeout(0),
-    m_NextProbeTimeFlag(),
+    m_u8SentCount(0),
+    m_Timeout(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
     m_bConflict(false),
     m_bTiebreakNeeded(false),
     m_fnProbeResultCallback(0),
@@ -1173,9 +1172,8 @@ MDNSResponder::stcProbeInformation::stcProbeInformation(void)
 bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/) {
 
     m_ProbingStatus = ProbingStatus_WaitingForData;
-    m_u8ProbesSent = 0;
-    //m_ulNextProbeTimeout = 0;
-    m_NextProbeTimeFlag.reset();
+    m_u8SentCount = 0;
+    m_Timeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
     m_bConflict = false;
     m_bTiebreakNeeded = false;
     if (p_bClearUserdata) {
@@ -1200,8 +1198,8 @@ bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/
  * MDNSResponder::stcMDNSService::stcMDNSService constructor
  */
 MDNSResponder::stcMDNSService::stcMDNSService(const char* p_pcName /*= 0*/,
-                                                const char* p_pcService /*= 0*/,
-                                                const char* p_pcProtocol /*= 0*/)
+                                              const char* p_pcService /*= 0*/,
+                                              const char* p_pcProtocol /*= 0*/)
 :   m_pNext(0),
     m_pcName(0),
     m_bAutoName(false),
@@ -1367,20 +1365,20 @@ bool MDNSResponder::stcMDNSService::releaseProtocol(void) {
  * 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*/)
+ * /
+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);
@@ -1389,9 +1387,9 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TT
     return true;
 }
 
-/*
+/ *
  * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent
- */
+ * /
 bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent(void) const {
     
     return ((m_TTLTimeFlag.getTimeout()) &&
@@ -1399,13 +1397,119 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent(void) c
             (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(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
+    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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+    }
+    return true;
+}
+
+/*
+ * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged
+ */
+bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) const {
+
+    return ((m_u32TTL) &&
+            (TIMEOUTLEVEL_UNSET != m_timeoutLevel) &&
+            (m_TTLTimeout.checkExpired(millis())));
+}
+
+/*
+ * 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.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
+        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 = std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max();
+
+    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;
 }
 
 
@@ -1421,8 +1525,9 @@ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated(void) con
 MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address(IPAddress p_IPAddress,
                                                                                 uint32_t p_u32TTL /*= 0*/)
 :   m_pNext(0),
-    m_IPAddress(p_IPAddress),
-    m_TTL(p_u32TTL) {
+    m_IPAddress(p_IPAddress) {
+
+    m_TTL.set(p_u32TTL);
 }
 #endif
 
@@ -1818,6 +1923,8 @@ MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery(void)
     m_fnCallback(0),
     m_pUserdata(0),
     m_bLegacyQuery(false),
+    m_u8SentCount(0),
+    m_ResendTimeout(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max()),
     m_bAwaitingAnswers(true),
     m_pAnswers(0) {
 
@@ -1840,6 +1947,8 @@ bool MDNSResponder::stcMDNSServiceQuery::clear(void) {
     m_fnCallback = 0;
     m_pUserdata = 0;
     m_bLegacyQuery = false;
+    m_u8SentCount = 0;
+    m_ResendTimeout.reset(std::numeric_limits<esp8266::polledTimeout::oneShot::timeType>::max());
     m_bAwaitingAnswers = true;
     while (m_pAnswers) {
         stcAnswer*  pNext = m_pAnswers->m_pNext;
diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp
index e163d64daa..9554f97df1 100644
--- a/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp
+++ b/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp
@@ -343,7 +343,8 @@ bool MDNSResponder::_sendMDNSServiceQuery(const MDNSResponder::stcMDNSServiceQue
  *
  */
 bool MDNSResponder::_sendMDNSQuery(const MDNSResponder::stcMDNS_RRDomain& p_QueryDomain,
-                                   uint16_t p_u16QueryType) {
+                                   uint16_t p_u16QueryType,
+                                   stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers /*= 0*/) {
 
     bool                    bResult = false;
     
@@ -351,9 +352,12 @@ bool MDNSResponder::_sendMDNSQuery(const MDNSResponder::stcMDNS_RRDomain& p_Quer
     if (0 != ((sendParameter.m_pQuestions = new stcMDNS_RRQuestion))) {
         sendParameter.m_pQuestions->m_Header.m_Domain = p_QueryDomain;
 
-        sendParameter.m_pQuestions->m_bUnicast = true;
         sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = p_u16QueryType;
-        sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN);   // Unicast & INternet
+        // 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
@@ -447,7 +451,7 @@ bool MDNSResponder::_readRRQuestion(MDNSResponder::stcMDNS_RRQuestion& p_rRRQues
  *
  */
 bool MDNSResponder::_readRRAnswer(MDNSResponder::stcMDNS_RRAnswer*& p_rpRRAnswer) {
-    DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer\n")););
+    //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer\n")););
     
     bool    bResult = false;
     
@@ -458,11 +462,11 @@ bool MDNSResponder::_readRRAnswer(MDNSResponder::stcMDNS_RRAnswer*& p_rpRRAnswer
         (_udpRead32(u32TTL)) &&
         (_udpRead16(u16RDLength))) {
 
-        DEBUG_EX_INFO(
+        /*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