/* * LEAmDNS_Structs.cpp * * License (MIT license): * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ #include "LEAmDNS_Priv.h" #include "LEAmDNS_lwIPdefs.h" namespace esp8266 { /* * LEAmDNS */ namespace MDNSImplementation { /** * STRUCTS */ /** * MDNSResponder::stcMDNSServiceTxt * * One MDNS TXT item. * m_pcValue may be '\0'. * Objects can be chained together (list, m_pNext). * A 'm_bTemp' flag differentiates between static and dynamic items. * Output as byte array 'c#=1' is supported. */ /* * MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt constructor */ MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const char* p_pcKey /*= 0*/, const char* p_pcValue /*= 0*/, bool p_bTemp /*= false*/) : m_pNext(0), m_pcKey(0), m_pcValue(0), m_bTemp(p_bTemp) { setKey(p_pcKey); setValue(p_pcValue); } /* * MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt copy-constructor */ MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const MDNSResponder::stcMDNSServiceTxt& p_Other) : m_pNext(0), m_pcKey(0), m_pcValue(0), m_bTemp(false) { operator=(p_Other); } /* * MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt destructor */ MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt(void) { clear(); } /* * MDNSResponder::stcMDNSServiceTxt::operator= */ MDNSResponder::stcMDNSServiceTxt& MDNSResponder::stcMDNSServiceTxt::operator=(const MDNSResponder::stcMDNSServiceTxt& p_Other) { if (&p_Other != this) { clear(); set(p_Other.m_pcKey, p_Other.m_pcValue, p_Other.m_bTemp); } return *this; } /* * MDNSResponder::stcMDNSServiceTxt::clear */ bool MDNSResponder::stcMDNSServiceTxt::clear(void) { releaseKey(); releaseValue(); return true; } /* * MDNSResponder::stcMDNSServiceTxt::allocKey */ char* MDNSResponder::stcMDNSServiceTxt::allocKey(size_t p_stLength) { releaseKey(); if (p_stLength) { m_pcKey = new char[p_stLength + 1]; } return m_pcKey; } /* * MDNSResponder::stcMDNSServiceTxt::setKey */ bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey, size_t p_stLength) { bool bResult = false; releaseKey(); if (p_stLength) { if (allocKey(p_stLength)) { strncpy(m_pcKey, p_pcKey, p_stLength); m_pcKey[p_stLength] = 0; bResult = true; } } return bResult; } /* * MDNSResponder::stcMDNSServiceTxt::setKey */ bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey) { return setKey(p_pcKey, (p_pcKey ? strlen(p_pcKey) : 0)); } /* * MDNSResponder::stcMDNSServiceTxt::releaseKey */ bool MDNSResponder::stcMDNSServiceTxt::releaseKey(void) { if (m_pcKey) { delete[] m_pcKey; m_pcKey = 0; } return true; } /* * MDNSResponder::stcMDNSServiceTxt::allocValue */ char* MDNSResponder::stcMDNSServiceTxt::allocValue(size_t p_stLength) { releaseValue(); if (p_stLength) { m_pcValue = new char[p_stLength + 1]; } return m_pcValue; } /* * MDNSResponder::stcMDNSServiceTxt::setValue */ bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue, size_t p_stLength) { bool bResult = false; releaseValue(); if (p_stLength) { if (allocValue(p_stLength)) { strncpy(m_pcValue, p_pcValue, p_stLength); m_pcValue[p_stLength] = 0; bResult = true; } } else { // No value -> also OK bResult = true; } return bResult; } /* * MDNSResponder::stcMDNSServiceTxt::setValue */ bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue) { return setValue(p_pcValue, (p_pcValue ? strlen(p_pcValue) : 0)); } /* * MDNSResponder::stcMDNSServiceTxt::releaseValue */ bool MDNSResponder::stcMDNSServiceTxt::releaseValue(void) { if (m_pcValue) { delete[] m_pcValue; m_pcValue = 0; } return true; } /* * MDNSResponder::stcMDNSServiceTxt::set */ bool MDNSResponder::stcMDNSServiceTxt::set(const char* p_pcKey, const char* p_pcValue, bool p_bTemp /*= false*/) { m_bTemp = p_bTemp; return ((setKey(p_pcKey)) && (setValue(p_pcValue))); } /* * MDNSResponder::stcMDNSServiceTxt::update */ bool MDNSResponder::stcMDNSServiceTxt::update(const char* p_pcValue) { return setValue(p_pcValue); } /* * MDNSResponder::stcMDNSServiceTxt::length * * length of eg. 'c#=1' without any closing '\0' */ size_t MDNSResponder::stcMDNSServiceTxt::length(void) const { size_t stLength = 0; if (m_pcKey) { stLength += strlen(m_pcKey); // Key stLength += 1; // '=' stLength += (m_pcValue ? strlen(m_pcValue) : 0); // Value } return stLength; } /** * MDNSResponder::stcMDNSServiceTxts * * A list of zero or more MDNS TXT items. * Dynamic TXT items can be removed by 'removeTempTxts'. * A TXT item can be looke up by its 'key' member. * Export as ';'-separated byte array is supported. * Export as 'length byte coded' byte array is supported. * Comparision ((all A TXT items in B and equal) AND (all B TXT items in A and equal)) is supported. * */ /* * MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts contructor */ MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(void) : m_pTxts(0) { } /* * MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts copy-constructor */ MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other) : m_pTxts(0) { operator=(p_Other); } /* * MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts destructor */ MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts(void) { clear(); } /* * MDNSResponder::stcMDNSServiceTxts::operator= */ MDNSResponder::stcMDNSServiceTxts& MDNSResponder::stcMDNSServiceTxts::operator=(const stcMDNSServiceTxts& p_Other) { if (this != &p_Other) { clear(); for (stcMDNSServiceTxt* pOtherTxt=p_Other.m_pTxts; pOtherTxt; pOtherTxt=pOtherTxt->m_pNext) { add(new stcMDNSServiceTxt(*pOtherTxt)); } } return *this; } /* * MDNSResponder::stcMDNSServiceTxts::clear */ bool MDNSResponder::stcMDNSServiceTxts::clear(void) { while (m_pTxts) { stcMDNSServiceTxt* pNext = m_pTxts->m_pNext; delete m_pTxts; m_pTxts = pNext; } return true; } /* * MDNSResponder::stcMDNSServiceTxts::add */ bool MDNSResponder::stcMDNSServiceTxts::add(MDNSResponder::stcMDNSServiceTxt* p_pTxt) { bool bResult = false; if (p_pTxt) { p_pTxt->m_pNext = m_pTxts; m_pTxts = p_pTxt; bResult = true; } return bResult; } /* * MDNSResponder::stcMDNSServiceTxts::remove */ bool MDNSResponder::stcMDNSServiceTxts::remove(stcMDNSServiceTxt* p_pTxt) { bool bResult = false; if (p_pTxt) { stcMDNSServiceTxt* pPred = m_pTxts; while ((pPred) && (pPred->m_pNext != p_pTxt)) { pPred = pPred->m_pNext; } if (pPred) { pPred->m_pNext = p_pTxt->m_pNext; delete p_pTxt; bResult = true; } else if (m_pTxts == p_pTxt) { // No predecesor, but first item m_pTxts = p_pTxt->m_pNext; delete p_pTxt; bResult = true; } } return bResult; } /* * MDNSResponder::stcMDNSServiceTxts::removeTempTxts */ bool MDNSResponder::stcMDNSServiceTxts::removeTempTxts(void) { bool bResult = true; stcMDNSServiceTxt* pTxt = m_pTxts; while ((bResult) && (pTxt)) { stcMDNSServiceTxt* pNext = pTxt->m_pNext; if (pTxt->m_bTemp) { bResult = remove(pTxt); } pTxt = pNext; } return bResult; } /* * MDNSResponder::stcMDNSServiceTxts::find */ MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) { stcMDNSServiceTxt* pResult = 0; for (stcMDNSServiceTxt* pTxt=m_pTxts; pTxt; pTxt=pTxt->m_pNext) { if ((p_pcKey) && (0 == strcmp(pTxt->m_pcKey, p_pcKey))) { pResult = pTxt; break; } } return pResult; } /* * MDNSResponder::stcMDNSServiceTxts::find */ const MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) const { const stcMDNSServiceTxt* pResult = 0; for (const stcMDNSServiceTxt* pTxt=m_pTxts; pTxt; pTxt=pTxt->m_pNext) { if ((p_pcKey) && (0 == strcmp(pTxt->m_pcKey, p_pcKey))) { pResult = pTxt; break; } } return pResult; } /* * MDNSResponder::stcMDNSServiceTxts::find */ MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const stcMDNSServiceTxt* p_pTxt) { stcMDNSServiceTxt* pResult = 0; for (stcMDNSServiceTxt* pTxt=m_pTxts; pTxt; pTxt=pTxt->m_pNext) { if (p_pTxt == pTxt) { pResult = pTxt; break; } } return pResult; } /* * MDNSResponder::stcMDNSServiceTxts::length */ uint16_t MDNSResponder::stcMDNSServiceTxts::length(void) const { uint16_t u16Length = 0; stcMDNSServiceTxt* pTxt = m_pTxts; while (pTxt) { u16Length += 1; // Length byte u16Length += pTxt->length(); // Text pTxt = pTxt->m_pNext; } return u16Length; } /* * MDNSResponder::stcMDNSServiceTxts::c_strLength * * (incl. closing '\0'). Length bytes place is used for delimiting ';' and closing '\0' */ size_t MDNSResponder::stcMDNSServiceTxts::c_strLength(void) const { return length(); } /* * MDNSResponder::stcMDNSServiceTxts::c_str */ bool MDNSResponder::stcMDNSServiceTxts::c_str(char* p_pcBuffer) { bool bResult = false; if (p_pcBuffer) { bResult = true; *p_pcBuffer = 0; for (stcMDNSServiceTxt* pTxt=m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) { size_t stLength; if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) { if (pTxt != m_pTxts) { *p_pcBuffer++ = ';'; } strncpy(p_pcBuffer, pTxt->m_pcKey, stLength); p_pcBuffer[stLength] = 0; p_pcBuffer += stLength; *p_pcBuffer++ = '='; if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) { strncpy(p_pcBuffer, pTxt->m_pcValue, stLength); p_pcBuffer[stLength] = 0; p_pcBuffer += stLength; } } } *p_pcBuffer++ = 0; } return bResult; } /* * MDNSResponder::stcMDNSServiceTxts::bufferLength * * (incl. closing '\0'). */ size_t MDNSResponder::stcMDNSServiceTxts::bufferLength(void) const { return (length() + 1); } /* * MDNSResponder::stcMDNSServiceTxts::toBuffer */ bool MDNSResponder::stcMDNSServiceTxts::buffer(char* p_pcBuffer) { bool bResult = false; if (p_pcBuffer) { bResult = true; *p_pcBuffer = 0; for (stcMDNSServiceTxt* pTxt=m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) { *(unsigned char*)p_pcBuffer++ = pTxt->length(); size_t stLength; if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) { memcpy(p_pcBuffer, pTxt->m_pcKey, stLength); p_pcBuffer += stLength; *p_pcBuffer++ = '='; if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) { memcpy(p_pcBuffer, pTxt->m_pcValue, stLength); p_pcBuffer += stLength; } } } *p_pcBuffer++ = 0; } return bResult; } /* * MDNSResponder::stcMDNSServiceTxts::compare */ bool MDNSResponder::stcMDNSServiceTxts::compare(const MDNSResponder::stcMDNSServiceTxts& p_Other) const { bool bResult = false; if ((bResult = (length() == p_Other.length()))) { // Compare A->B for (const stcMDNSServiceTxt* pTxt=m_pTxts; ((bResult) && (pTxt)); pTxt=pTxt->m_pNext) { const stcMDNSServiceTxt* pOtherTxt = p_Other.find(pTxt->m_pcKey); bResult = ((pOtherTxt) && (pTxt->m_pcValue) && (pOtherTxt->m_pcValue) && (strlen(pTxt->m_pcValue) == strlen(pOtherTxt->m_pcValue)) && (0 == strcmp(pTxt->m_pcValue, pOtherTxt->m_pcValue))); } // Compare B->A for (const stcMDNSServiceTxt* pOtherTxt=p_Other.m_pTxts; ((bResult) && (pOtherTxt)); pOtherTxt=pOtherTxt->m_pNext) { const stcMDNSServiceTxt* pTxt = find(pOtherTxt->m_pcKey); bResult = ((pTxt) && (pOtherTxt->m_pcValue) && (pTxt->m_pcValue) && (strlen(pOtherTxt->m_pcValue) == strlen(pTxt->m_pcValue)) && (0 == strcmp(pOtherTxt->m_pcValue, pTxt->m_pcValue))); } } return bResult; } /* * MDNSResponder::stcMDNSServiceTxts::operator== */ bool MDNSResponder::stcMDNSServiceTxts::operator==(const stcMDNSServiceTxts& p_Other) const { return compare(p_Other); } /* * MDNSResponder::stcMDNSServiceTxts::operator!= */ bool MDNSResponder::stcMDNSServiceTxts::operator!=(const stcMDNSServiceTxts& p_Other) const { return !compare(p_Other); } /** * MDNSResponder::stcMDNS_MsgHeader * * A MDNS message haeder. * */ /* * MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader */ MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader(uint16_t p_u16ID /*= 0*/, bool p_bQR /*= false*/, unsigned char p_ucOpcode /*= 0*/, bool p_bAA /*= false*/, bool p_bTC /*= false*/, bool p_bRD /*= false*/, bool p_bRA /*= false*/, unsigned char p_ucRCode /*= 0*/, uint16_t p_u16QDCount /*= 0*/, uint16_t p_u16ANCount /*= 0*/, uint16_t p_u16NSCount /*= 0*/, uint16_t p_u16ARCount /*= 0*/) : m_u16ID(p_u16ID), m_1bQR(p_bQR), m_4bOpcode(p_ucOpcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_ucRCode), m_u16QDCount(p_u16QDCount), m_u16ANCount(p_u16ANCount), m_u16NSCount(p_u16NSCount), m_u16ARCount(p_u16ARCount) { } /** * MDNSResponder::stcMDNS_RRDomain * * A MDNS domain object. * The labels of the domain are stored (DNS-like encoded) in 'm_acName': * [length byte]varlength label[length byte]varlength label[0] * 'm_u16NameLength' stores the used length of 'm_acName'. * Dynamic label addition is supported. * Comparison is supported. * Export as byte array 'esp8266.local' is supported. * */ /* * MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain constructor */ MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(void) : m_u16NameLength(0) { clear(); } /* * MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain copy-constructor */ MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other) : m_u16NameLength(0) { operator=(p_Other); } /* * MDNSResponder::stcMDNS_RRDomain::operator = */ MDNSResponder::stcMDNS_RRDomain& MDNSResponder::stcMDNS_RRDomain::operator=(const stcMDNS_RRDomain& p_Other) { if (&p_Other != this) { memcpy(m_acName, p_Other.m_acName, sizeof(m_acName)); m_u16NameLength = p_Other.m_u16NameLength; } return *this; } /* * MDNSResponder::stcMDNS_RRDomain::clear */ bool MDNSResponder::stcMDNS_RRDomain::clear(void) { memset(m_acName, 0, sizeof(m_acName)); m_u16NameLength = 0; return true; } /* * MDNSResponder::stcMDNS_RRDomain::addLabel */ bool MDNSResponder::stcMDNS_RRDomain::addLabel(const char* p_pcLabel, bool p_bPrependUnderline /*= false*/) { bool bResult = false; size_t stLength = (p_pcLabel ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) : 0); if ((MDNS_DOMAIN_LABEL_MAXLENGTH >= stLength) && (MDNS_DOMAIN_MAXLENGTH >= (m_u16NameLength + (1 + stLength)))) { // Length byte m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! ++m_u16NameLength; // Label if (stLength) { if (p_bPrependUnderline) { m_acName[m_u16NameLength++] = '_'; --stLength; } strncpy(&(m_acName[m_u16NameLength]), p_pcLabel, stLength); m_acName[m_u16NameLength + stLength] = 0; m_u16NameLength += stLength; } bResult = true; } return bResult; } /* * MDNSResponder::stcMDNS_RRDomain::compare */ bool MDNSResponder::stcMDNS_RRDomain::compare(const stcMDNS_RRDomain& p_Other) const { bool bResult = false; if (m_u16NameLength == p_Other.m_u16NameLength) { const char* pT = m_acName; const char* pO = p_Other.m_acName; while ((pT) && (pO) && (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) { // Same content if (*((unsigned char*)pT)) { // Not 0 pT += (1 + *((unsigned char*)pT)); // Shift by length byte and lenght pO += (1 + *((unsigned char*)pO)); } else { // Is 0 -> Successfully reached the end bResult = true; break; } } } return bResult; } /* * MDNSResponder::stcMDNS_RRDomain::operator == */ bool MDNSResponder::stcMDNS_RRDomain::operator==(const stcMDNS_RRDomain& p_Other) const { return compare(p_Other); } /* * MDNSResponder::stcMDNS_RRDomain::operator != */ bool MDNSResponder::stcMDNS_RRDomain::operator!=(const stcMDNS_RRDomain& p_Other) const { return !compare(p_Other); } /* * MDNSResponder::stcMDNS_RRDomain::operator > */ bool MDNSResponder::stcMDNS_RRDomain::operator>(const stcMDNS_RRDomain& p_Other) const { // TODO: Check, if this is a good idea... return !compare(p_Other); } /* * MDNSResponder::stcMDNS_RRDomain::c_strLength */ size_t MDNSResponder::stcMDNS_RRDomain::c_strLength(void) const { size_t stLength = 0; unsigned char* pucLabelLength = (unsigned char*)m_acName; while (*pucLabelLength) { stLength += (*pucLabelLength + 1 /* +1 for '.' or '\0'*/); pucLabelLength += (*pucLabelLength + 1); } return stLength; } /* * MDNSResponder::stcMDNS_RRDomain::c_str */ bool MDNSResponder::stcMDNS_RRDomain::c_str(char* p_pcBuffer) { bool bResult = false; if (p_pcBuffer) { *p_pcBuffer = 0; unsigned char* pucLabelLength = (unsigned char*)m_acName; while (*pucLabelLength) { memcpy(p_pcBuffer, (const char*)(pucLabelLength + 1), *pucLabelLength); p_pcBuffer += *pucLabelLength; pucLabelLength += (*pucLabelLength + 1); *p_pcBuffer++ = (*pucLabelLength ? '.' : '\0'); } bResult = true; } return bResult; } /** * MDNSResponder::stcMDNS_RRAttributes * * A MDNS attributes object. * */ /* * MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes constructor */ MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(uint16_t p_u16Type /*= 0*/, uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) : m_u16Type(p_u16Type), m_u16Class(p_u16Class) { } /* * MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes copy-constructor */ MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Other) { operator=(p_Other); } /* * MDNSResponder::stcMDNS_RRAttributes::operator = */ MDNSResponder::stcMDNS_RRAttributes& MDNSResponder::stcMDNS_RRAttributes::operator=(const MDNSResponder::stcMDNS_RRAttributes& p_Other) { if (&p_Other != this) { m_u16Type = p_Other.m_u16Type; m_u16Class = p_Other.m_u16Class; } return *this; } /** * MDNSResponder::stcMDNS_RRHeader * * A MDNS record header (domain and attributes) object. * */ /* * MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader constructor */ MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(void) { } /* * MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader copy-constructor */ MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other) { operator=(p_Other); } /* * MDNSResponder::stcMDNS_RRHeader::operator = */ MDNSResponder::stcMDNS_RRHeader& MDNSResponder::stcMDNS_RRHeader::operator=(const MDNSResponder::stcMDNS_RRHeader& p_Other) { if (&p_Other != this) { m_Domain = p_Other.m_Domain; m_Attributes = p_Other.m_Attributes; } return *this; } /* * MDNSResponder::stcMDNS_RRHeader::clear */ bool MDNSResponder::stcMDNS_RRHeader::clear(void) { m_Domain.clear(); return true; } /** * MDNSResponder::stcMDNS_RRQuestion * * A MDNS question record object (header + question flags) * */ /* * MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion constructor */ MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion(void) : m_pNext(0), m_bUnicast(false) { } /** * MDNSResponder::stcMDNS_RRAnswer * * A MDNS answer record object (header + answer content). * This is a 'virtual' base class for all other MDNS answer classes. * */ /* * MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer constructor */ MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer(enuAnswerType p_AnswerType, const MDNSResponder::stcMDNS_RRHeader& p_Header, uint32_t p_u32TTL) : m_pNext(0), m_AnswerType(p_AnswerType), m_Header(p_Header), m_u32TTL(p_u32TTL) { // Extract 'cache flush'-bit m_bCacheFlush = (m_Header.m_Attributes.m_u16Class & 0x8000); m_Header.m_Attributes.m_u16Class &= (~0x8000); } /* * MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer destructor */ MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer(void) { } /* * MDNSResponder::stcMDNS_RRAnswer::answerType */ MDNSResponder::enuAnswerType MDNSResponder::stcMDNS_RRAnswer::answerType(void) const { return m_AnswerType; } /* * MDNSResponder::stcMDNS_RRAnswer::clear */ bool MDNSResponder::stcMDNS_RRAnswer::clear(void) { m_pNext = 0; m_Header.clear(); return true; } /** * MDNSResponder::stcMDNS_RRAnswerA * * A MDNS A answer object. * Extends the base class by an IP4 address member. * */ #ifdef MDNS_IP4_SUPPORT /* * MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA constructor */ MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA(const MDNSResponder::stcMDNS_RRHeader& p_Header, uint32_t p_u32TTL) : stcMDNS_RRAnswer(AnswerType_A, p_Header, p_u32TTL), m_IPAddress(0, 0, 0, 0) { } /* * MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA destructor */ MDNSResponder::stcMDNS_RRAnswerA::~stcMDNS_RRAnswerA(void) { clear(); } /* * MDNSResponder::stcMDNS_RRAnswerA::clear */ bool MDNSResponder::stcMDNS_RRAnswerA::clear(void) { m_IPAddress = IPAddress(0, 0, 0, 0); return true; } #endif /** * MDNSResponder::stcMDNS_RRAnswerPTR * * A MDNS PTR answer object. * Extends the base class by a MDNS domain member. * */ /* * MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR constructor */ MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR(const MDNSResponder::stcMDNS_RRHeader& p_Header, uint32_t p_u32TTL) : stcMDNS_RRAnswer(AnswerType_PTR, p_Header, p_u32TTL) { } /* * MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR destructor */ MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR(void) { clear(); } /* * MDNSResponder::stcMDNS_RRAnswerPTR::clear */ bool MDNSResponder::stcMDNS_RRAnswerPTR::clear(void) { m_PTRDomain.clear(); return true; } /** * MDNSResponder::stcMDNS_RRAnswerTXT * * A MDNS TXT answer object. * Extends the base class by a MDNS TXT items list member. * */ /* * MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT constructor */ MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT(const MDNSResponder::stcMDNS_RRHeader& p_Header, uint32_t p_u32TTL) : stcMDNS_RRAnswer(AnswerType_TXT, p_Header, p_u32TTL) { } /* * MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT destructor */ MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT(void) { clear(); } /* * MDNSResponder::stcMDNS_RRAnswerTXT::clear */ bool MDNSResponder::stcMDNS_RRAnswerTXT::clear(void) { m_Txts.clear(); return true; } /** * MDNSResponder::stcMDNS_RRAnswerAAAA * * A MDNS AAAA answer object. * (Should) extend the base class by an IP6 address member. * */ #ifdef MDNS_IP6_SUPPORT /* * MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA constructor */ MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA(const MDNSResponder::stcMDNS_RRHeader& p_Header, uint32_t p_u32TTL) : stcMDNS_RRAnswer(AnswerType_AAAA, p_Header, p_u32TTL) { } /* * MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA destructor */ MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA(void) { clear(); } /* * MDNSResponder::stcMDNS_RRAnswerAAAA::clear */ bool MDNSResponder::stcMDNS_RRAnswerAAAA::clear(void) { return true; } #endif /** * MDNSResponder::stcMDNS_RRAnswerSRV * * A MDNS SRV answer object. * Extends the base class by a port member. * */ /* * MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV constructor */ MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV(const MDNSResponder::stcMDNS_RRHeader& p_Header, uint32_t p_u32TTL) : stcMDNS_RRAnswer(AnswerType_SRV, p_Header, p_u32TTL), m_u16Priority(0), m_u16Weight(0), m_u16Port(0) { } /* * MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV destructor */ MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV(void) { clear(); } /* * MDNSResponder::stcMDNS_RRAnswerSRV::clear */ bool MDNSResponder::stcMDNS_RRAnswerSRV::clear(void) { m_u16Priority = 0; m_u16Weight = 0; m_u16Port = 0; m_SRVDomain.clear(); return true; } /** * MDNSResponder::stcMDNS_RRAnswerGeneric * * An unknown (generic) MDNS answer object. * Extends the base class by a RDATA buffer member. * */ /* * MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric constructor */ MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header, uint32_t p_u32TTL) : stcMDNS_RRAnswer(AnswerType_Generic, p_Header, p_u32TTL), m_u16RDLength(0), m_pu8RDData(0) { } /* * MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric destructor */ MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric(void) { clear(); } /* * MDNSResponder::stcMDNS_RRAnswerGeneric::clear */ bool MDNSResponder::stcMDNS_RRAnswerGeneric::clear(void) { if (m_pu8RDData) { delete[] m_pu8RDData; m_pu8RDData = 0; } m_u16RDLength = 0; return true; } /** * MDNSResponder::stcProbeInformation * * Probing status information for a host or service domain * */ /* * MDNSResponder::stcProbeInformation::stcProbeInformation constructor */ MDNSResponder::stcProbeInformation::stcProbeInformation(void) : m_ProbingStatus(ProbingStatus_WaitingForData), m_u8SentCount(0), m_Timeout(esp8266::polledTimeout::oneShotMs::neverExpires), m_bConflict(false), m_bTiebreakNeeded(false), m_fnHostProbeResultCallback(0), m_fnServiceProbeResultCallback(0) { } /* * MDNSResponder::stcProbeInformation::clear */ bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/) { m_ProbingStatus = ProbingStatus_WaitingForData; m_u8SentCount = 0; m_Timeout.resetToNeverExpires(); m_bConflict = false; m_bTiebreakNeeded = false; if (p_bClearUserdata) { m_fnHostProbeResultCallback = 0; m_fnServiceProbeResultCallback = 0; } return true; } /** * MDNSResponder::stcMDNSService * * A MDNS service object (to be announced by the MDNS responder) * The service instance may be '\0'; in this case the hostname is used * and the flag m_bAutoName is set. If the hostname changes, all 'auto- * named' services are renamed also. * m_u8Replymask is used while preparing a response to a MDNS query. It is * resetted in '_sendMDNSMessage' afterwards. */ /* * MDNSResponder::stcMDNSService::stcMDNSService constructor */ MDNSResponder::stcMDNSService::stcMDNSService(const char* p_pcName /*= 0*/, const char* p_pcService /*= 0*/, const char* p_pcProtocol /*= 0*/) : m_pNext(0), m_pcName(0), m_bAutoName(false), m_pcService(0), m_pcProtocol(0), m_u16Port(0), m_u8ReplyMask(0), m_fnTxtCallback(0) { setName(p_pcName); setService(p_pcService); setProtocol(p_pcProtocol); } /* * MDNSResponder::stcMDNSService::~stcMDNSService destructor */ MDNSResponder::stcMDNSService::~stcMDNSService(void) { releaseName(); releaseService(); releaseProtocol(); } /* * MDNSResponder::stcMDNSService::setName */ bool MDNSResponder::stcMDNSService::setName(const char* p_pcName) { bool bResult = false; releaseName(); size_t stLength = (p_pcName ? strlen(p_pcName) : 0); if (stLength) { if ((bResult = (0 != (m_pcName = new char[stLength + 1])))) { strncpy(m_pcName, p_pcName, stLength); m_pcName[stLength] = 0; } } else { bResult = true; } return bResult; } /* * MDNSResponder::stcMDNSService::releaseName */ bool MDNSResponder::stcMDNSService::releaseName(void) { if (m_pcName) { delete[] m_pcName; m_pcName = 0; } return true; } /* * MDNSResponder::stcMDNSService::setService */ bool MDNSResponder::stcMDNSService::setService(const char* p_pcService) { bool bResult = false; releaseService(); size_t stLength = (p_pcService ? strlen(p_pcService) : 0); if (stLength) { if ((bResult = (0 != (m_pcService = new char[stLength + 1])))) { strncpy(m_pcService, p_pcService, stLength); m_pcService[stLength] = 0; } } else { bResult = true; } return bResult; } /* * MDNSResponder::stcMDNSService::releaseService */ bool MDNSResponder::stcMDNSService::releaseService(void) { if (m_pcService) { delete[] m_pcService; m_pcService = 0; } return true; } /* * MDNSResponder::stcMDNSService::setProtocol */ bool MDNSResponder::stcMDNSService::setProtocol(const char* p_pcProtocol) { bool bResult = false; releaseProtocol(); size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); if (stLength) { if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) { strncpy(m_pcProtocol, p_pcProtocol, stLength); m_pcProtocol[stLength] = 0; } } else { bResult = true; } return bResult; } /* * MDNSResponder::stcMDNSService::releaseProtocol */ bool MDNSResponder::stcMDNSService::releaseProtocol(void) { if (m_pcProtocol) { delete[] m_pcProtocol; m_pcProtocol = 0; } return true; } /** * MDNSResponder::stcMDNSServiceQuery * * A MDNS service query object. * Service queries may be static or dynamic. * As the static service query is processed in the blocking function 'queryService', * only one static service service may exist. The processing of the answers is done * on the WiFi-stack side of the ESP stack structure (via 'UDPContext.onRx(_update)'). * */ /** * MDNSResponder::stcMDNSServiceQuery::stcAnswer * * One answer for a service query. * Every answer must contain * - a service instance entry (pivot), * and may contain * - a host domain, * - a port * - an IP4 address * (- an IP6 address) * - a MDNS TXTs * The existance of a component is flaged in 'm_u32ContentFlags'. * For every answer component a TTL value is maintained. * Answer objects can be connected to a linked list. * * For the host domain, service domain and TXTs components, a char array * representation can be retrieved (which is created on demand). * */ /** * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL * * The TTL (Time-To-Live) for an specific answer content. * The 80% and outdated states are calculated based on the current time (millis) * and the 'set' time (also millis). * If the answer is scheduled for an update, the corresponding flag should be set. * * / / * * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor * / MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(uint32_t p_u32TTL / *= 0* /) : m_bUpdateScheduled(false) { set(p_u32TTL * 1000); } / * * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set * / bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) { m_TTLTimeFlag.restart(p_u32TTL * 1000); m_bUpdateScheduled = false; return true; } / * * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent * / bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent(void) const { return ((m_TTLTimeFlag.getTimeout()) && (!m_bUpdateScheduled) && (m_TTLTimeFlag.hypotheticalTimeout((m_TTLTimeFlag.getTimeout() * 800) / 1000))); } / * * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated * / bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated(void) const { return ((m_TTLTimeFlag.getTimeout()) && (m_TTLTimeFlag.flagged())); }*/ /** * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL * * The TTL (Time-To-Live) for an specific answer content. * The 80% and outdated states are calculated based on the current time (millis) * and the 'set' time (also millis). * If the answer is scheduled for an update, the corresponding flag should be set. * */ /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor */ MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(void) : m_u32TTL(0), m_TTLTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), m_timeoutLevel(TIMEOUTLEVEL_UNSET) { } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) { m_u32TTL = p_u32TTL; if (m_u32TTL) { m_timeoutLevel = TIMEOUTLEVEL_BASE; // Set to 80% m_TTLTimeout.reset(timeout()); } else { m_timeoutLevel = TIMEOUTLEVEL_UNSET; // undef m_TTLTimeout.resetToNeverExpires(); } return true; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) { return ((m_u32TTL) && (TIMEOUTLEVEL_UNSET != m_timeoutLevel) && (m_TTLTimeout.expired())); } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart(void) { bool bResult = true; if ((TIMEOUTLEVEL_BASE <= m_timeoutLevel) && // >= 80% AND (TIMEOUTLEVEL_FINAL > m_timeoutLevel)) { // < 100% m_timeoutLevel += TIMEOUTLEVEL_INTERVAL; // increment by 5% m_TTLTimeout.reset(timeout()); } else { bResult = false; m_TTLTimeout.resetToNeverExpires(); m_timeoutLevel = TIMEOUTLEVEL_UNSET; } return bResult; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion(void) { m_timeoutLevel = TIMEOUTLEVEL_FINAL; m_TTLTimeout.reset(1 * 1000); // See RFC 6762, 10.1 return true; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel(void) const { return (TIMEOUTLEVEL_FINAL == m_timeoutLevel); } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout */ unsigned long MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout(void) const { uint32_t u32Timeout = esp8266::polledTimeout::oneShotMs::neverExpires; if (TIMEOUTLEVEL_BASE == m_timeoutLevel) { // 80% u32Timeout = (m_u32TTL * 800); // to milliseconds } else if ((TIMEOUTLEVEL_BASE < m_timeoutLevel) && // >80% AND (TIMEOUTLEVEL_FINAL >= m_timeoutLevel)) { // <= 100% u32Timeout = (m_u32TTL * 50); } // else: invalid return u32Timeout; } #ifdef MDNS_IP4_SUPPORT /** * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address * */ /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address constructor */ MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address(IPAddress p_IPAddress, uint32_t p_u32TTL /*= 0*/) : m_pNext(0), m_IPAddress(p_IPAddress) { m_TTL.set(p_u32TTL); } #endif /** * MDNSResponder::stcMDNSServiceQuery::stcAnswer */ /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer constructor */ MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer(void) : m_pNext(0), m_pcServiceDomain(0), m_pcHostDomain(0), m_u16Port(0), m_pcTxts(0), #ifdef MDNS_IP4_SUPPORT m_pIP4Addresses(0), #endif #ifdef MDNS_IP6_SUPPORT m_pIP6Addresses(0), #endif m_u32ContentFlags(0) { } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer destructor */ MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer(void) { clear(); } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear(void) { return ((releaseTxts()) && #ifdef MDNS_IP4_SUPPORT (releaseIP4Addresses()) && #endif #ifdef MDNS_IP6_SUPPORT (releaseIP6Addresses()) #endif (releaseHostDomain()) && (releaseServiceDomain())); } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain * * Alloc memory for the char array representation of the service domain. * */ char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain(size_t p_stLength) { releaseServiceDomain(); if (p_stLength) { m_pcServiceDomain = new char[p_stLength]; } return m_pcServiceDomain; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain(void) { if (m_pcServiceDomain) { delete[] m_pcServiceDomain; m_pcServiceDomain = 0; } return true; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain * * Alloc memory for the char array representation of the host domain. * */ char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain(size_t p_stLength) { releaseHostDomain(); if (p_stLength) { m_pcHostDomain = new char[p_stLength]; } return m_pcHostDomain; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain(void) { if (m_pcHostDomain) { delete[] m_pcHostDomain; m_pcHostDomain = 0; } return true; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts * * Alloc memory for the char array representation of the TXT items. * */ char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts(size_t p_stLength) { releaseTxts(); if (p_stLength) { m_pcTxts = new char[p_stLength]; } return m_pcTxts; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts(void) { if (m_pcTxts) { delete[] m_pcTxts; m_pcTxts = 0; } return true; } #ifdef MDNS_IP4_SUPPORT /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses(void) { while (m_pIP4Addresses) { stcIP4Address* pNext = m_pIP4Addresses->m_pNext; delete m_pIP4Addresses; m_pIP4Addresses = pNext; } return true; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) { bool bResult = false; if (p_pIP4Address) { p_pIP4Address->m_pNext = m_pIP4Addresses; m_pIP4Addresses = p_pIP4Address; bResult = true; } return bResult; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address */ bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) { bool bResult = false; if (p_pIP4Address) { stcIP4Address* pPred = m_pIP4Addresses; while ((pPred) && (pPred->m_pNext != p_pIP4Address)) { pPred = pPred->m_pNext; } if (pPred) { pPred->m_pNext = p_pIP4Address->m_pNext; delete p_pIP4Address; bResult = true; } else if (m_pIP4Addresses == p_pIP4Address) { // No predecesor, but first item m_pIP4Addresses = p_pIP4Address->m_pNext; delete p_pIP4Address; bResult = true; } } return bResult; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address (const) */ const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) const { return (stcIP4Address*)(((const stcAnswer*)this)->findIP4Address(p_IPAddress)); } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address */ MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) { stcIP4Address* pIP4Address = m_pIP4Addresses; while (pIP4Address) { if (pIP4Address->m_IPAddress == p_IPAddress) { break; } pIP4Address = pIP4Address->m_pNext; } return pIP4Address; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount */ uint32_t MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount(void) const { uint32_t u32Count = 0; stcIP4Address* pIP4Address = m_pIP4Addresses; while (pIP4Address) { ++u32Count; pIP4Address = pIP4Address->m_pNext; } return u32Count; } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex */ MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) { return (stcIP4Address*)(((const stcAnswer*)this)->IP4AddressAtIndex(p_u32Index)); } /* * MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex (const) */ const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) const { const stcIP4Address* pIP4Address = 0; if (((uint32_t)(-1) != p_u32Index) && (m_pIP4Addresses)) { uint32_t u32Index; for (pIP4Address=m_pIP4Addresses, u32Index=0; ((pIP4Address) && (u32Indexm_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) && (u32Indexm_pNext, ++u32Index); } return pIP6Address; } #endif /** * MDNSResponder::stcMDNSServiceQuery * * A service query object. * A static query is flaged via 'm_bLegacyQuery'; while the function 'queryService' * is waiting for answers, the internal flag 'm_bAwaitingAnswers' is set. When the * timeout is reached, the flag is removed. These two flags are only used for static * service queries. * All answers to the service query are stored in 'm_pAnswers' list. * Individual answers may be addressed by index (in the list of answers). * Every time a answer component is added (or changes) in a dynamic service query, * the callback 'm_fnCallback' is called. * The answer list may be searched by service and host domain. * * Service query object may be connected to a linked list. */ /* * MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery constructor */ MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery(void) : m_pNext(0), m_fnCallback(0), m_bLegacyQuery(false), m_u8SentCount(0), m_ResendTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), m_bAwaitingAnswers(true), m_pAnswers(0) { clear(); } /* * MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery destructor */ MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery(void) { clear(); } /* * MDNSResponder::stcMDNSServiceQuery::clear */ bool MDNSResponder::stcMDNSServiceQuery::clear(void) { m_fnCallback = 0; m_bLegacyQuery = false; m_u8SentCount = 0; m_ResendTimeout.resetToNeverExpires(); m_bAwaitingAnswers = true; while (m_pAnswers) { stcAnswer* pNext = m_pAnswers->m_pNext; delete m_pAnswers; m_pAnswers = pNext; } return true; } /* * MDNSResponder::stcMDNSServiceQuery::answerCount */ uint32_t MDNSResponder::stcMDNSServiceQuery::answerCount(void) const { uint32_t u32Count = 0; stcAnswer* pAnswer = m_pAnswers; while (pAnswer) { ++u32Count; pAnswer = pAnswer->m_pNext; } return u32Count; } /* * MDNSResponder::stcMDNSServiceQuery::answerAtIndex */ const MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::answerAtIndex(uint32_t p_u32Index) const { const stcAnswer* pAnswer = 0; if (((uint32_t)(-1) != p_u32Index) && (m_pAnswers)) { uint32_t u32Index; for (pAnswer=m_pAnswers, u32Index=0; ((pAnswer) && (u32Indexm_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