1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00
david gauchard e5f4514847
mDNS: protect MDNSResponder::queryService against misuse (#7216)
* mDNS: protect MDNSResponder::queryService against misuse

* fix style
2020-04-15 14:22:02 -04:00

1382 lines
41 KiB
C++

/*
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 <Schedule.h>
#include <AddrList.h>
#include "LEAmDNS_Priv.h"
namespace esp8266
{
/*
LEAmDNS
*/
namespace MDNSImplementation
{
/**
STRINGIZE
*/
#ifndef STRINGIZE
#define STRINGIZE(x) #x
#endif
#ifndef STRINGIZE_VALUE_OF
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
#endif
/**
INTERFACE
*/
/**
MDNSResponder::MDNSResponder
*/
MDNSResponder::MDNSResponder(void)
: m_pServices(0),
m_pUDPContext(0),
m_pcHostname(0),
m_pServiceQueries(0),
m_fnServiceTxtCallback(0),
#ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
m_bPassivModeEnabled(true),
#else
m_bPassivModeEnabled(false),
#endif
m_netif(nullptr)
{
}
/*
MDNSResponder::~MDNSResponder
*/
MDNSResponder::~MDNSResponder(void)
{
_resetProbeStatus(false);
_releaseServiceQueries();
_releaseHostname();
_releaseUDPContext();
_releaseServices();
}
/*
MDNSResponder::begin
Set the host domain (for probing) and install WiFi event handlers for
IP assignment and disconnection management. In both cases, the MDNS responder
is restarted (reset and restart probe status)
Finally the responder is (re)started
*/
bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress, uint32_t p_u32TTL)
{
(void)p_u32TTL; // ignored
bool bResult = false;
if (0 == m_pUDPContext)
{
if (_setHostname(p_pcHostname))
{
//// select interface
m_netif = nullptr;
IPAddress ipAddress = p_IPAddress;
if (!ipAddress.isSet())
{
IPAddress sta = WiFi.localIP();
IPAddress ap = WiFi.softAPIP();
if (sta.isSet())
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] STA interface selected\n")));
ipAddress = sta;
}
else if (ap.isSet())
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] AP interface selected\n")));
ipAddress = ap;
}
else
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] standard interfaces are not up, please specify one in ::begin()\n")));
return false;
}
// continue to ensure interface is UP
}
// check existence of this IP address in the interface list
bool found = false;
m_netif = nullptr;
for (auto a : addrList)
if (ipAddress == a.addr())
{
if (a.ifUp())
{
found = true;
m_netif = a.interface();
break;
}
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] found interface for IP '%s' but it is not UP\n"), ipAddress.toString().c_str()););
}
if (!found)
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] interface defined by IP '%s' not found\n"), ipAddress.toString().c_str()););
return false;
}
//// done selecting the interface
if (m_netif->num == STATION_IF)
{
m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & pEvent)
{
(void) pEvent;
// Ensure that _restart() runs in USER context
schedule_function([this]()
{
MDNSResponder::_restart();
});
});
m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & pEvent)
{
(void) pEvent;
// Ensure that _restart() runs in USER context
schedule_function([this]()
{
MDNSResponder::_restart();
});
});
}
bResult = _restart();
}
DEBUG_EX_ERR(if (!bResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: FAILED for '%s'!\n"), (p_pcHostname ? : "-"));
});
}
else
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: Ignoring multiple calls to begin (Ignored host domain: '%s')!\n"), (p_pcHostname ? : "-")););
}
return bResult;
}
/*
MDNSResponder::close
Ends the MDNS responder.
Announced services are unannounced (by multicasting a goodbye message)
*/
bool MDNSResponder::close(void)
{
bool bResult = false;
if (0 != m_pUDPContext)
{
m_GotIPHandler.reset(); // reset WiFi event callbacks.
m_DisconnectedHandler.reset();
_announce(false, true);
_resetProbeStatus(false); // Stop probing
_releaseServiceQueries();
_releaseUDPContext();
_releaseHostname();
bResult = true;
}
else
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] close: Ignoring call to close!\n")););
}
return bResult;
}
/*
MDNSResponder::end
Ends the MDNS responder.
for compatibility with esp32
*/
bool MDNSResponder::end(void)
{
return close();
}
/*
MDNSResponder::setHostname
Replaces the current hostname and restarts probing.
For services without own instance name (when the host name was used a instance
name), the instance names are replaced also (and the probing is restarted).
*/
bool MDNSResponder::setHostname(const char* p_pcHostname)
{
bool bResult = false;
if (_setHostname(p_pcHostname))
{
m_HostProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart;
// Replace 'auto-set' service names
bResult = true;
for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext)
{
if (pService->m_bAutoName)
{
bResult = pService->setName(p_pcHostname);
pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart;
}
}
}
DEBUG_EX_ERR(if (!bResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setHostname: FAILED for '%s'!\n"), (p_pcHostname ? : "-"));
});
return bResult;
}
/*
MDNSResponder::setHostname (LEGACY)
*/
bool MDNSResponder::setHostname(const String& p_strHostname)
{
return setHostname(p_strHostname.c_str());
}
/*
SERVICES
*/
/*
MDNSResponder::addService
Add service; using hostname if no name is explicitly provided for the service
The usual '_' underline, which is prepended to service and protocol, eg. _http,
may be given. If not, it is added automatically.
*/
MDNSResponder::hMDNSService MDNSResponder::addService(const char* p_pcName,
const char* p_pcService,
const char* p_pcProtocol,
uint16_t p_u16Port)
{
hMDNSService hResult = 0;
if (((!p_pcName) || // NO name OR
(MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcName))) && // Fitting name
(p_pcService) &&
(MDNS_SERVICE_NAME_LENGTH >= os_strlen(p_pcService)) &&
(p_pcProtocol) &&
((MDNS_SERVICE_PROTOCOL_LENGTH - 1) != os_strlen(p_pcProtocol)) &&
(p_u16Port))
{
if (!_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol)) // Not already used
{
if (0 != (hResult = (hMDNSService)_allocService(p_pcName, p_pcService, p_pcProtocol, p_u16Port)))
{
// Start probing
((stcMDNSService*)hResult)->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart;
}
}
} // else: bad arguments
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: %s to add '%s.%s.%s'!\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcName ? : "-"), p_pcService, p_pcProtocol););
DEBUG_EX_ERR(if (!hResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: FAILED to add '%s.%s.%s'!\n"), (p_pcName ? : "-"), p_pcService, p_pcProtocol);
});
return hResult;
}
/*
MDNSResponder::removeService
Unanounce a service (by sending a goodbye message) and remove it
from the MDNS responder
*/
bool MDNSResponder::removeService(const MDNSResponder::hMDNSService p_hService)
{
stcMDNSService* pService = 0;
bool bResult = (((pService = _findService(p_hService))) &&
(_announceService(*pService, false)) &&
(_releaseService(pService)));
DEBUG_EX_ERR(if (!bResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeService: FAILED!\n"));
});
return bResult;
}
/*
MDNSResponder::removeService
*/
bool MDNSResponder::removeService(const char* p_pcName,
const char* p_pcService,
const char* p_pcProtocol)
{
return removeService((hMDNSService)_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol));
}
/*
MDNSResponder::addService (LEGACY)
*/
bool MDNSResponder::addService(const String& p_strService,
const String& p_strProtocol,
uint16_t p_u16Port)
{
return (0 != addService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str(), p_u16Port));
}
/*
MDNSResponder::setServiceName
*/
bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSService p_hService,
const char* p_pcInstanceName)
{
stcMDNSService* pService = 0;
bool bResult = (((!p_pcInstanceName) ||
(MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcInstanceName))) &&
((pService = _findService(p_hService))) &&
(pService->setName(p_pcInstanceName)) &&
((pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart)));
DEBUG_EX_ERR(if (!bResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setServiceName: FAILED for '%s'!\n"), (p_pcInstanceName ? : "-"));
});
return bResult;
}
/*
SERVICE TXT
*/
/*
MDNSResponder::addServiceTxt
Add a static service TXT item ('Key'='Value') to a service.
*/
MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
const char* p_pcValue)
{
hMDNSTxt hTxt = 0;
stcMDNSService* pService = _findService(p_hService);
if (pService)
{
hTxt = (hMDNSTxt)_addServiceTxt(pService, p_pcKey, p_pcValue, false);
}
DEBUG_EX_ERR(if (!hTxt)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-"));
});
return hTxt;
}
/*
MDNSResponder::addServiceTxt (uint32_t)
Formats: http://www.cplusplus.com/reference/cstdio/printf/
*/
MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
uint32_t p_u32Value)
{
char acBuffer[32]; *acBuffer = 0;
sprintf(acBuffer, "%u", p_u32Value);
return addServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addServiceTxt (uint16_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
uint16_t p_u16Value)
{
char acBuffer[16]; *acBuffer = 0;
sprintf(acBuffer, "%hu", p_u16Value);
return addServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addServiceTxt (uint8_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
uint8_t p_u8Value)
{
char acBuffer[8]; *acBuffer = 0;
sprintf(acBuffer, "%hhu", p_u8Value);
return addServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addServiceTxt (int32_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
int32_t p_i32Value)
{
char acBuffer[32]; *acBuffer = 0;
sprintf(acBuffer, "%i", p_i32Value);
return addServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addServiceTxt (int16_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
int16_t p_i16Value)
{
char acBuffer[16]; *acBuffer = 0;
sprintf(acBuffer, "%hi", p_i16Value);
return addServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addServiceTxt (int8_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
int8_t p_i8Value)
{
char acBuffer[8]; *acBuffer = 0;
sprintf(acBuffer, "%hhi", p_i8Value);
return addServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::removeServiceTxt
Remove a static service TXT item from a service.
*/
bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService,
const MDNSResponder::hMDNSTxt p_hTxt)
{
bool bResult = false;
stcMDNSService* pService = _findService(p_hService);
if (pService)
{
stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_hTxt);
if (pTxt)
{
bResult = _releaseServiceTxt(pService, pTxt);
}
}
DEBUG_EX_ERR(if (!bResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED!\n"));
});
return bResult;
}
/*
MDNSResponder::removeServiceTxt
*/
bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService,
const char* p_pcKey)
{
bool bResult = false;
stcMDNSService* pService = _findService(p_hService);
if (pService)
{
stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey);
if (pTxt)
{
bResult = _releaseServiceTxt(pService, pTxt);
}
}
DEBUG_EX_ERR(if (!bResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED for '%s'!\n"), (p_pcKey ? : "-"));
});
return bResult;
}
/*
MDNSResponder::removeServiceTxt
*/
bool MDNSResponder::removeServiceTxt(const char* p_pcName,
const char* p_pcService,
const char* p_pcProtocol,
const char* p_pcKey)
{
bool bResult = false;
stcMDNSService* pService = _findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol);
if (pService)
{
stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey);
if (pTxt)
{
bResult = _releaseServiceTxt(pService, pTxt);
}
}
return bResult;
}
/*
MDNSResponder::addServiceTxt (LEGACY)
*/
bool MDNSResponder::addServiceTxt(const char* p_pcService,
const char* p_pcProtocol,
const char* p_pcKey,
const char* p_pcValue)
{
return (0 != _addServiceTxt(_findService(m_pcHostname, p_pcService, p_pcProtocol), p_pcKey, p_pcValue, false));
}
/*
MDNSResponder::addServiceTxt (LEGACY)
*/
bool MDNSResponder::addServiceTxt(const String& p_strService,
const String& p_strProtocol,
const String& p_strKey,
const String& p_strValue)
{
return (0 != _addServiceTxt(_findService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str()), p_strKey.c_str(), p_strValue.c_str(), false));
}
/*
MDNSResponder::setDynamicServiceTxtCallback (global)
Set a global callback for dynamic service TXT items. The callback is called, whenever
service TXT items are needed.
*/
bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback)
{
m_fnServiceTxtCallback = p_fnCallback;
return true;
}
/*
MDNSResponder::setDynamicServiceTxtCallback (service specific)
Set a service specific callback for dynamic service TXT items. The callback is called, whenever
service TXT items are needed for the given service.
*/
bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::hMDNSService p_hService,
MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback)
{
bool bResult = false;
stcMDNSService* pService = _findService(p_hService);
if (pService)
{
pService->m_fnTxtCallback = p_fnCallback;
bResult = true;
}
DEBUG_EX_ERR(if (!bResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setDynamicServiceTxtCallback: FAILED!\n"));
});
return bResult;
}
/*
MDNSResponder::addDynamicServiceTxt
*/
MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
const char* p_pcValue)
{
//DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt (%s=%s)\n"), p_pcKey, p_pcValue););
hMDNSTxt hTxt = 0;
stcMDNSService* pService = _findService(p_hService);
if (pService)
{
hTxt = _addServiceTxt(pService, p_pcKey, p_pcValue, true);
}
DEBUG_EX_ERR(if (!hTxt)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-"));
});
return hTxt;
}
/*
MDNSResponder::addDynamicServiceTxt (uint32_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
uint32_t p_u32Value)
{
char acBuffer[32]; *acBuffer = 0;
sprintf(acBuffer, "%u", p_u32Value);
return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addDynamicServiceTxt (uint16_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
uint16_t p_u16Value)
{
char acBuffer[16]; *acBuffer = 0;
sprintf(acBuffer, "%hu", p_u16Value);
return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addDynamicServiceTxt (uint8_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
uint8_t p_u8Value)
{
char acBuffer[8]; *acBuffer = 0;
sprintf(acBuffer, "%hhu", p_u8Value);
return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addDynamicServiceTxt (int32_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
int32_t p_i32Value)
{
char acBuffer[32]; *acBuffer = 0;
sprintf(acBuffer, "%i", p_i32Value);
return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addDynamicServiceTxt (int16_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
int16_t p_i16Value)
{
char acBuffer[16]; *acBuffer = 0;
sprintf(acBuffer, "%hi", p_i16Value);
return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer);
}
/*
MDNSResponder::addDynamicServiceTxt (int8_t)
*/
MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService,
const char* p_pcKey,
int8_t p_i8Value)
{
char acBuffer[8]; *acBuffer = 0;
sprintf(acBuffer, "%hhi", p_i8Value);
return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer);
}
/**
STATIC SERVICE QUERY (LEGACY)
*/
/*
MDNSResponder::queryService
Perform a (blocking) static service query.
The arrived answers can be queried by calling:
- answerHostname (or 'hostname')
- answerIP (or 'IP')
- answerPort (or 'port')
*/
uint32_t MDNSResponder::queryService(const char* p_pcService,
const char* p_pcProtocol,
const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/)
{
if (0 == m_pUDPContext)
{
// safeguard against misuse
return 0;
}
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService '%s.%s'\n"), p_pcService, p_pcProtocol););
uint32_t u32Result = 0;
stcMDNSServiceQuery* pServiceQuery = 0;
if ((p_pcService) &&
(os_strlen(p_pcService)) &&
(p_pcProtocol) &&
(os_strlen(p_pcProtocol)) &&
(p_u16Timeout) &&
(_removeLegacyServiceQuery()) &&
((pServiceQuery = _allocServiceQuery())) &&
(_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain)))
{
pServiceQuery->m_bLegacyQuery = true;
if (_sendMDNSServiceQuery(*pServiceQuery))
{
// Wait for answers to arrive
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: Waiting %u ms for answers...\n"), p_u16Timeout););
delay(p_u16Timeout);
// All answers should have arrived by now -> stop adding new answers
pServiceQuery->m_bAwaitingAnswers = false;
u32Result = pServiceQuery->answerCount();
}
else // FAILED to send query
{
_removeServiceQuery(pServiceQuery);
}
}
else
{
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: INVALID input data!\n")););
}
return u32Result;
}
/*
MDNSResponder::removeQuery
Remove the last static service query (and all answers).
*/
bool MDNSResponder::removeQuery(void)
{
return _removeLegacyServiceQuery();
}
/*
MDNSResponder::queryService (LEGACY)
*/
uint32_t MDNSResponder::queryService(const String& p_strService,
const String& p_strProtocol)
{
return queryService(p_strService.c_str(), p_strProtocol.c_str());
}
/*
MDNSResponder::answerHostname
*/
const char* MDNSResponder::answerHostname(const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery();
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
if ((pSQAnswer) &&
(pSQAnswer->m_HostDomain.m_u16NameLength) &&
(!pSQAnswer->m_pcHostDomain))
{
char* pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength());
if (pcHostDomain)
{
pSQAnswer->m_HostDomain.c_str(pcHostDomain);
}
}
return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0);
}
#ifdef MDNS_IP4_SUPPORT
/*
MDNSResponder::answerIP
*/
IPAddress MDNSResponder::answerIP(const uint32_t p_u32AnswerIndex)
{
const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery();
const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
const stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (((pSQAnswer) && (pSQAnswer->m_pIP4Addresses)) ? pSQAnswer->IP4AddressAtIndex(0) : 0);
return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress());
}
#endif
#ifdef MDNS_IP6_SUPPORT
/*
MDNSResponder::answerIP6
*/
IPAddress MDNSResponder::answerIP6(const uint32_t p_u32AnswerIndex)
{
const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery();
const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
const stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (((pSQAnswer) && (pSQAnswer->m_pIP6Addresses)) ? pSQAnswer->IP6AddressAtIndex(0) : 0);
return (pIP6Address ? pIP6Address->m_IPAddress : IP6Address());
}
#endif
/*
MDNSResponder::answerPort
*/
uint16_t MDNSResponder::answerPort(const uint32_t p_u32AnswerIndex)
{
const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery();
const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
return (pSQAnswer ? pSQAnswer->m_u16Port : 0);
}
/*
MDNSResponder::hostname (LEGACY)
*/
String MDNSResponder::hostname(const uint32_t p_u32AnswerIndex)
{
return String(answerHostname(p_u32AnswerIndex));
}
/*
MDNSResponder::IP (LEGACY)
*/
IPAddress MDNSResponder::IP(const uint32_t p_u32AnswerIndex)
{
return answerIP(p_u32AnswerIndex);
}
/*
MDNSResponder::port (LEGACY)
*/
uint16_t MDNSResponder::port(const uint32_t p_u32AnswerIndex)
{
return answerPort(p_u32AnswerIndex);
}
/**
DYNAMIC SERVICE QUERY
*/
/*
MDNSResponder::installServiceQuery
Add a dynamic service query and a corresponding callback to the MDNS responder.
The callback will be called for every answer update.
The answers can also be queried by calling:
- answerServiceDomain
- answerHostDomain
- answerIP4Address/answerIP6Address
- answerPort
- answerTxts
*/
MDNSResponder::hMDNSServiceQuery MDNSResponder::installServiceQuery(const char* p_pcService,
const char* p_pcProtocol,
MDNSResponder::MDNSServiceQueryCallbackFunc p_fnCallback)
{
hMDNSServiceQuery hResult = 0;
stcMDNSServiceQuery* pServiceQuery = 0;
if ((p_pcService) &&
(os_strlen(p_pcService)) &&
(p_pcProtocol) &&
(os_strlen(p_pcProtocol)) &&
(p_fnCallback) &&
((pServiceQuery = _allocServiceQuery())) &&
(_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain)))
{
pServiceQuery->m_fnCallback = p_fnCallback;
pServiceQuery->m_bLegacyQuery = false;
if (_sendMDNSServiceQuery(*pServiceQuery))
{
pServiceQuery->m_u8SentCount = 1;
pServiceQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY);
hResult = (hMDNSServiceQuery)pServiceQuery;
}
else
{
_removeServiceQuery(pServiceQuery);
}
}
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: %s for '%s.%s'!\n\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-")););
DEBUG_EX_ERR(if (!hResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: FAILED for '%s.%s'!\n\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));
});
return hResult;
}
/*
MDNSResponder::removeServiceQuery
Remove a dynamic service query (and all collected answers) from the MDNS responder
*/
bool MDNSResponder::removeServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery)
{
stcMDNSServiceQuery* pServiceQuery = 0;
bool bResult = (((pServiceQuery = _findServiceQuery(p_hServiceQuery))) &&
(_removeServiceQuery(pServiceQuery)));
DEBUG_EX_ERR(if (!bResult)
{
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceQuery: FAILED!\n"));
});
return bResult;
}
/*
MDNSResponder::answerCount
*/
uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
return (pServiceQuery ? pServiceQuery->answerCount() : 0);
}
std::vector<MDNSResponder::MDNSServiceInfo> MDNSResponder::answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery)
{
std::vector<MDNSResponder::MDNSServiceInfo> tempVector;
for (uint32_t i = 0; i < answerCount(p_hServiceQuery); i++)
{
tempVector.emplace_back(*this, p_hServiceQuery, i);
}
return tempVector;
}
/*
MDNSResponder::answerServiceDomain
Returns the domain for the given service.
If not already existing, the string is allocated, filled and attached to the answer.
*/
const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
// Fill m_pcServiceDomain (if not already done)
if ((pSQAnswer) &&
(pSQAnswer->m_ServiceDomain.m_u16NameLength) &&
(!pSQAnswer->m_pcServiceDomain))
{
pSQAnswer->m_pcServiceDomain = pSQAnswer->allocServiceDomain(pSQAnswer->m_ServiceDomain.c_strLength());
if (pSQAnswer->m_pcServiceDomain)
{
pSQAnswer->m_ServiceDomain.c_str(pSQAnswer->m_pcServiceDomain);
}
}
return (pSQAnswer ? pSQAnswer->m_pcServiceDomain : 0);
}
/*
MDNSResponder::hasAnswerHostDomain
*/
bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
return ((pSQAnswer) &&
(pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort));
}
/*
MDNSResponder::answerHostDomain
Returns the host domain for the given service.
If not already existing, the string is allocated, filled and attached to the answer.
*/
const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
// Fill m_pcHostDomain (if not already done)
if ((pSQAnswer) &&
(pSQAnswer->m_HostDomain.m_u16NameLength) &&
(!pSQAnswer->m_pcHostDomain))
{
pSQAnswer->m_pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength());
if (pSQAnswer->m_pcHostDomain)
{
pSQAnswer->m_HostDomain.c_str(pSQAnswer->m_pcHostDomain);
}
}
return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0);
}
#ifdef MDNS_IP4_SUPPORT
/*
MDNSResponder::hasAnswerIP4Address
*/
bool MDNSResponder::hasAnswerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
return ((pSQAnswer) &&
(pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_IP4Address));
}
/*
MDNSResponder::answerIP4AddressCount
*/
uint32_t MDNSResponder::answerIP4AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
return (pSQAnswer ? pSQAnswer->IP4AddressCount() : 0);
}
/*
MDNSResponder::answerIP4Address
*/
IPAddress MDNSResponder::answerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex,
const uint32_t p_u32AddressIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (pSQAnswer ? pSQAnswer->IP4AddressAtIndex(p_u32AddressIndex) : 0);
return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress());
}
#endif
#ifdef MDNS_IP6_SUPPORT
/*
MDNSResponder::hasAnswerIP6Address
*/
bool MDNSResponder::hasAnswerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
return ((pSQAnswer) &&
(pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostIP6Address));
}
/*
MDNSResponder::answerIP6AddressCount
*/
uint32_t MDNSResponder::answerIP6AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
return (pSQAnswer ? pSQAnswer->IP6AddressCount() : 0);
}
/*
MDNSResponder::answerIP6Address
*/
IPAddress MDNSResponder::answerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex,
const uint32_t p_u32AddressIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (pSQAnswer ? pSQAnswer->IP6AddressAtIndex(p_u32AddressIndex) : 0);
return (pIP6Address ? pIP6Address->m_IPAddress : IPAddress());
}
#endif
/*
MDNSResponder::hasAnswerPort
*/
bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
return ((pSQAnswer) &&
(pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort));
}
/*
MDNSResponder::answerPort
*/
uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
return (pSQAnswer ? pSQAnswer->m_u16Port : 0);
}
/*
MDNSResponder::hasAnswerTxts
*/
bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
return ((pSQAnswer) &&
(pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_Txts));
}
/*
MDNSResponder::answerTxts
Returns all TXT items for the given service as a ';'-separated string.
If not already existing; the string is alloced, filled and attached to the answer.
*/
const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery,
const uint32_t p_u32AnswerIndex)
{
stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery);
stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0);
// Fill m_pcTxts (if not already done)
if ((pSQAnswer) &&
(pSQAnswer->m_Txts.m_pTxts) &&
(!pSQAnswer->m_pcTxts))
{
pSQAnswer->m_pcTxts = pSQAnswer->allocTxts(pSQAnswer->m_Txts.c_strLength());
if (pSQAnswer->m_pcTxts)
{
pSQAnswer->m_Txts.c_str(pSQAnswer->m_pcTxts);
}
}
return (pSQAnswer ? pSQAnswer->m_pcTxts : 0);
}
/*
PROBING
*/
/*
MDNSResponder::setProbeResultCallback
Set a global callback for probe results. The callback is called, when probing
for the host domain (or a service domain, without specific probe result callback)
failes or succeedes.
In the case of failure, the domain name should be changed via 'setHostname' or 'setServiceName'.
When succeeded, the host or service domain will be announced by the MDNS responder.
*/
bool MDNSResponder::setHostProbeResultCallback(MDNSResponder::MDNSHostProbeFn p_fnCallback)
{
m_HostProbeInformation.m_fnHostProbeResultCallback = p_fnCallback;
return true;
}
bool MDNSResponder::setHostProbeResultCallback(MDNSHostProbeFn1 pfn)
{
using namespace std::placeholders;
return setHostProbeResultCallback([this, pfn](const char* p_pcDomainName, bool p_bProbeResult)
{
pfn(*this, p_pcDomainName, p_bProbeResult);
});
}
/*
MDNSResponder::setServiceProbeResultCallback
Set a service specific callback for probe results. The callback is called, when probing
for the service domain failes or succeedes.
In the case of failure, the service name should be changed via 'setServiceName'.
When succeeded, the service domain will be announced by the MDNS responder.
*/
bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService,
MDNSResponder::MDNSServiceProbeFn p_fnCallback)
{
bool bResult = false;
stcMDNSService* pService = _findService(p_hService);
if (pService)
{
pService->m_ProbeInformation.m_fnServiceProbeResultCallback = p_fnCallback;
bResult = true;
}
return bResult;
}
bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService,
MDNSResponder::MDNSServiceProbeFn1 p_fnCallback)
{
using namespace std::placeholders;
return setServiceProbeResultCallback(p_hService, [this, p_fnCallback](const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult)
{
p_fnCallback(*this, p_pcServiceName, p_hMDNSService, p_bProbeResult);
});
}
/*
MISC
*/
/*
MDNSResponder::notifyAPChange
Should be called, whenever the AP for the MDNS responder changes.
A bit of this is caught by the event callbacks installed in the constructor.
*/
bool MDNSResponder::notifyAPChange(void)
{
return _restart();
}
/*
MDNSResponder::update
Should be called in every 'loop'.
*/
bool MDNSResponder::update(void)
{
if (m_bPassivModeEnabled)
{
m_bPassivModeEnabled = false;
}
return _process(true);
}
/*
MDNSResponder::announce
Should be called, if the 'configuration' changes. Mainly this will be changes in the TXT items...
*/
bool MDNSResponder::announce(void)
{
return (_announce(true, true));
}
/*
MDNSResponder::enableArduino
Enable the OTA update service.
*/
MDNSResponder::hMDNSService MDNSResponder::enableArduino(uint16_t p_u16Port,
bool p_bAuthUpload /*= false*/)
{
hMDNSService hService = addService(0, "arduino", "tcp", p_u16Port);
if (hService)
{
if ((!addServiceTxt(hService, "tcp_check", "no")) ||
(!addServiceTxt(hService, "ssh_upload", "no")) ||
(!addServiceTxt(hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) ||
(!addServiceTxt(hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no")))
{
removeService(hService);
hService = 0;
}
}
return hService;
}
} //namespace MDNSImplementation
} //namespace esp8266