mirror of
https://github.com/esp8266/Arduino.git
synced 2025-05-21 14:13:47 +03:00
* MDNS MultiInterface * Move strlcat & strlcpy to __cplusplus * Add LwipIntfCB.cpp to Makefile
1789 lines
72 KiB
C++
1789 lines
72 KiB
C++
/*
|
|
LEAmDNS_Transfer.cpp
|
|
|
|
License (MIT license):
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
extern "C" {
|
|
#include "user_interface.h"
|
|
}
|
|
|
|
#include "ESP8266mDNS.h"
|
|
#include "LEAmDNS_lwIPdefs.h"
|
|
#include "LEAmDNS_Priv.h"
|
|
|
|
|
|
namespace esp8266
|
|
{
|
|
|
|
/*
|
|
LEAmDNS
|
|
*/
|
|
namespace MDNSImplementation
|
|
{
|
|
|
|
/**
|
|
CONST STRINGS
|
|
*/
|
|
static const char* scpcLocal = "local";
|
|
static const char* scpcServices = "services";
|
|
static const char* scpcDNSSD = "dns-sd";
|
|
static const char* scpcUDP = "udp";
|
|
//static const char* scpcTCP = "tcp";
|
|
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
static const char* scpcReverseIP4Domain = "in-addr";
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
static const char* scpcReverseIP6Domain = "ip6";
|
|
#endif
|
|
static const char* scpcReverseTopDomain = "arpa";
|
|
|
|
/**
|
|
TRANSFER
|
|
*/
|
|
|
|
|
|
/**
|
|
SENDING
|
|
*/
|
|
|
|
/*
|
|
MDNSResponder::_sendMDNSMessage
|
|
|
|
Unicast responses are prepared and sent directly to the querier.
|
|
Multicast responses or queries are transferred to _sendMDNSMessage_Multicast
|
|
|
|
Any reply flags in installed services are removed at the end!
|
|
|
|
*/
|
|
bool MDNSResponder::_sendMDNSMessage(MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
|
|
bool bResult = true;
|
|
|
|
if (p_rSendParameter.m_bResponse &&
|
|
p_rSendParameter.m_bUnicast) // Unicast response -> Send to querier
|
|
{
|
|
DEBUG_EX_ERR(if (!m_pUDPContext->getRemoteAddress())
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: MISSING remote address for response!\n"));
|
|
});
|
|
IPAddress ipRemote;
|
|
ipRemote = m_pUDPContext->getRemoteAddress();
|
|
bResult = ((_prepareMDNSMessage(p_rSendParameter, m_pUDPContext->getInputNetif()->ip_addr)) &&
|
|
(m_pUDPContext->sendTimeout(ipRemote, m_pUDPContext->getRemotePort(), MDNS_UDPCONTEXT_TIMEOUT)));
|
|
}
|
|
else // Multicast response
|
|
{
|
|
bResult = _sendMDNSMessage_Multicast(p_rSendParameter);
|
|
}
|
|
|
|
// Finally clear service reply masks
|
|
for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext)
|
|
{
|
|
pService->m_u8ReplyMask = 0;
|
|
}
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_sendMDNSMessage_Multicast
|
|
|
|
Fills the UDP output buffer (via _prepareMDNSMessage) and sends the buffer
|
|
via the selected WiFi interface (Station or AP)
|
|
*/
|
|
bool MDNSResponder::_sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
|
|
bool bResult = false;
|
|
|
|
for (netif* pNetIf = netif_list; pNetIf; pNetIf = pNetIf->next)
|
|
{
|
|
if (netif_is_up(pNetIf))
|
|
{
|
|
IPAddress fromIPAddress;
|
|
//fromIPAddress = _getResponseMulticastInterface();
|
|
fromIPAddress = pNetIf->ip_addr;
|
|
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->sendTimeout(toMulticastAddress, DNS_MQUERY_PORT, MDNS_UDPCONTEXT_TIMEOUT)));
|
|
|
|
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;
|
|
p_rSendParameter.clearCachedNames(); // Need to remove cached names, p_SendParameter might have been used before on other interface
|
|
|
|
// Prepare header; count answers
|
|
stcMDNS_MsgHeader msgHeader(p_rSendParameter.m_u16ID, p_rSendParameter.m_bResponse, 0, p_rSendParameter.m_bAuthorative);
|
|
// If this is a response, the answers are anwers,
|
|
// else this is a query or probe and the answers go into auth section
|
|
uint16_t& ru16Answers = (p_rSendParameter.m_bResponse
|
|
? msgHeader.m_u16ANCount
|
|
: msgHeader.m_u16NSCount);
|
|
|
|
/**
|
|
enuSequence
|
|
*/
|
|
enum enuSequence
|
|
{
|
|
Sequence_Count = 0,
|
|
Sequence_Send = 1
|
|
};
|
|
|
|
// Two step sequence: 'Count' and 'Send'
|
|
for (uint32_t sequence = Sequence_Count; ((bResult) && (sequence <= Sequence_Send)); ++sequence)
|
|
{
|
|
DEBUG_EX_INFO(
|
|
if (Sequence_Send == sequence)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"),
|
|
(unsigned)msgHeader.m_u16ID,
|
|
(unsigned)msgHeader.m_1bQR, (unsigned)msgHeader.m_4bOpcode, (unsigned)msgHeader.m_1bAA, (unsigned)msgHeader.m_1bTC, (unsigned)msgHeader.m_1bRD,
|
|
(unsigned)msgHeader.m_1bRA, (unsigned)msgHeader.m_4bRCode,
|
|
(unsigned)msgHeader.m_u16QDCount,
|
|
(unsigned)msgHeader.m_u16ANCount,
|
|
(unsigned)msgHeader.m_u16NSCount,
|
|
(unsigned)msgHeader.m_u16ARCount);
|
|
}
|
|
);
|
|
// Count/send
|
|
// Header
|
|
bResult = ((Sequence_Count == sequence)
|
|
? true
|
|
: _writeMDNSMsgHeader(msgHeader, p_rSendParameter));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSMsgHeader FAILED!\n")););
|
|
// Questions
|
|
for (stcMDNS_RRQuestion* pQuestion = p_rSendParameter.m_pQuestions; ((bResult) && (pQuestion)); pQuestion = pQuestion->m_pNext)
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++msgHeader.m_u16QDCount
|
|
: (bResult = _writeMDNSQuestion(*pQuestion, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSQuestion FAILED!\n")););
|
|
}
|
|
|
|
// Answers and authorative answers
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
if ((bResult) &&
|
|
(p_rSendParameter.m_u8HostReplyMask & ContentFlag_A))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++ru16Answers
|
|
: (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(A) FAILED!\n")););
|
|
}
|
|
if ((bResult) &&
|
|
(p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP4))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++ru16Answers
|
|
: (bResult = _writeMDNSAnswer_PTR_IP4(p_IPAddress, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP4 FAILED!\n")););
|
|
}
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
if ((bResult) &&
|
|
(p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++ru16Answers
|
|
: (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(A) FAILED!\n")););
|
|
}
|
|
if ((bResult) &&
|
|
(p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP6))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++ru16Answers
|
|
: (bResult = _writeMDNSAnswer_PTR_IP6(p_IPAddress, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP6 FAILED!\n")););
|
|
}
|
|
#endif
|
|
|
|
for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext)
|
|
{
|
|
if ((bResult) &&
|
|
(pService->m_u8ReplyMask & ContentFlag_PTR_TYPE))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++ru16Answers
|
|
: (bResult = _writeMDNSAnswer_PTR_TYPE(*pService, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_TYPE FAILED!\n")););
|
|
}
|
|
if ((bResult) &&
|
|
(pService->m_u8ReplyMask & ContentFlag_PTR_NAME))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++ru16Answers
|
|
: (bResult = _writeMDNSAnswer_PTR_NAME(*pService, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_NAME FAILED!\n")););
|
|
}
|
|
if ((bResult) &&
|
|
(pService->m_u8ReplyMask & ContentFlag_SRV))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++ru16Answers
|
|
: (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(A) FAILED!\n")););
|
|
}
|
|
if ((bResult) &&
|
|
(pService->m_u8ReplyMask & ContentFlag_TXT))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++ru16Answers
|
|
: (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(A) FAILED!\n")););
|
|
}
|
|
} // for services
|
|
|
|
// Additional answers
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
bool bNeedsAdditionalAnswerA = false;
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
bool bNeedsAdditionalAnswerAAAA = false;
|
|
#endif
|
|
for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext)
|
|
{
|
|
if ((bResult) &&
|
|
(pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND
|
|
(!(pService->m_u8ReplyMask & ContentFlag_SRV))) // NOT SRV -> add SRV as additional answer
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++msgHeader.m_u16ARCount
|
|
: (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(B) FAILED!\n")););
|
|
}
|
|
if ((bResult) &&
|
|
(pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND
|
|
(!(pService->m_u8ReplyMask & ContentFlag_TXT))) // NOT TXT -> add TXT as additional answer
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++msgHeader.m_u16ARCount
|
|
: (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(B) FAILED!\n")););
|
|
}
|
|
if ((pService->m_u8ReplyMask & (ContentFlag_PTR_NAME | ContentFlag_SRV)) || // If service instance name or SRV OR
|
|
(p_rSendParameter.m_u8HostReplyMask & (ContentFlag_A | ContentFlag_AAAA))) // any host IP address is requested
|
|
{
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
if ((bResult) &&
|
|
(!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_A))) // Add IP4 address
|
|
{
|
|
bNeedsAdditionalAnswerA = true;
|
|
}
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
if ((bResult) &&
|
|
(!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA))) // Add IP6 address
|
|
{
|
|
bNeedsAdditionalAnswerAAAA = true;
|
|
}
|
|
#endif
|
|
}
|
|
} // for services
|
|
|
|
// Answer A needed?
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
if ((bResult) &&
|
|
(bNeedsAdditionalAnswerA))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++msgHeader.m_u16ARCount
|
|
: (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(B) FAILED!\n")););
|
|
}
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
// Answer AAAA needed?
|
|
if ((bResult) &&
|
|
(bNeedsAdditionalAnswerAAAA))
|
|
{
|
|
((Sequence_Count == sequence)
|
|
? ++msgHeader.m_u16ARCount
|
|
: (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(B) FAILED!\n")););
|
|
}
|
|
#endif
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: Loop %i FAILED!\n"), sequence););
|
|
} // for sequence
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_sendMDNSServiceQuery
|
|
|
|
Creates and sends a PTR query for the given service domain.
|
|
|
|
*/
|
|
bool MDNSResponder::_sendMDNSServiceQuery(const MDNSResponder::stcMDNSServiceQuery& p_ServiceQuery)
|
|
{
|
|
|
|
return _sendMDNSQuery(p_ServiceQuery.m_ServiceTypeDomain, DNS_RRTYPE_PTR);
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_sendMDNSQuery
|
|
|
|
Creates and sends a query for the given domain and query type.
|
|
|
|
*/
|
|
bool MDNSResponder::_sendMDNSQuery(const MDNSResponder::stcMDNS_RRDomain& p_QueryDomain,
|
|
uint16_t p_u16QueryType,
|
|
stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers /*= 0*/)
|
|
{
|
|
|
|
bool bResult = false;
|
|
|
|
stcMDNSSendParameter sendParameter;
|
|
if (0 != ((sendParameter.m_pQuestions = new stcMDNS_RRQuestion)))
|
|
{
|
|
sendParameter.m_pQuestions->m_Header.m_Domain = p_QueryDomain;
|
|
|
|
sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = p_u16QueryType;
|
|
// It seems, that some mDNS implementations don't support 'unicast response' questions...
|
|
sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN); // /*Unicast &*/ INternet
|
|
|
|
// TODO: Add knwon answer to the query
|
|
(void)p_pKnownAnswers;
|
|
|
|
bResult = _sendMDNSMessage(sendParameter);
|
|
} // else: FAILED to alloc question
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSQuery: FAILED to alloc question!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/**
|
|
HELPERS
|
|
*/
|
|
|
|
/**
|
|
RESOURCE RECORDS
|
|
*/
|
|
|
|
/*
|
|
MDNSResponder::_readRRQuestion
|
|
|
|
Reads a question (eg. MyESP._http._tcp.local ANY IN) from the UPD input buffer.
|
|
|
|
*/
|
|
bool MDNSResponder::_readRRQuestion(MDNSResponder::stcMDNS_RRQuestion& p_rRRQuestion)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion\n")););
|
|
|
|
bool bResult = false;
|
|
|
|
if ((bResult = _readRRHeader(p_rRRQuestion.m_Header)))
|
|
{
|
|
// Extract unicast flag from class field
|
|
p_rRRQuestion.m_bUnicast = (p_rRRQuestion.m_Header.m_Attributes.m_u16Class & 0x8000);
|
|
p_rRRQuestion.m_Header.m_Attributes.m_u16Class &= (~0x8000);
|
|
|
|
DEBUG_EX_INFO(
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion "));
|
|
_printRRDomain(p_rRRQuestion.m_Header.m_Domain);
|
|
DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X %s\n"), (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Type, (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Class, (p_rRRQuestion.m_bUnicast ? "Unicast" : "Multicast"));
|
|
);
|
|
}
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_readRRAnswer
|
|
|
|
Reads an answer (eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local)
|
|
from the UDP input buffer.
|
|
After reading the domain and type info, the further processing of the answer
|
|
is transferred the answer specific reading functions.
|
|
Unknown answer types are processed by the generic answer reader (to remove them
|
|
from the input buffer).
|
|
|
|
*/
|
|
bool MDNSResponder::_readRRAnswer(MDNSResponder::stcMDNS_RRAnswer*& p_rpRRAnswer)
|
|
{
|
|
//DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer\n")););
|
|
|
|
bool bResult = false;
|
|
|
|
stcMDNS_RRHeader header;
|
|
uint32_t u32TTL;
|
|
uint16_t u16RDLength;
|
|
if ((_readRRHeader(header)) &&
|
|
(_udpRead32(u32TTL)) &&
|
|
(_udpRead16(u16RDLength)))
|
|
{
|
|
|
|
/* DEBUG_EX_INFO(
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: Reading 0x%04X answer (class:0x%04X, TTL:%u, RDLength:%u) for "), header.m_Attributes.m_u16Type, header.m_Attributes.m_u16Class, u32TTL, u16RDLength);
|
|
_printRRDomain(header.m_Domain);
|
|
DEBUG_OUTPUT.printf_P(PSTR("\n"));
|
|
);*/
|
|
|
|
switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag
|
|
{
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
case DNS_RRTYPE_A:
|
|
p_rpRRAnswer = new stcMDNS_RRAnswerA(header, u32TTL);
|
|
bResult = _readRRAnswerA(*(stcMDNS_RRAnswerA*&)p_rpRRAnswer, u16RDLength);
|
|
break;
|
|
#endif
|
|
case DNS_RRTYPE_PTR:
|
|
p_rpRRAnswer = new stcMDNS_RRAnswerPTR(header, u32TTL);
|
|
bResult = _readRRAnswerPTR(*(stcMDNS_RRAnswerPTR*&)p_rpRRAnswer, u16RDLength);
|
|
break;
|
|
case DNS_RRTYPE_TXT:
|
|
p_rpRRAnswer = new stcMDNS_RRAnswerTXT(header, u32TTL);
|
|
bResult = _readRRAnswerTXT(*(stcMDNS_RRAnswerTXT*&)p_rpRRAnswer, u16RDLength);
|
|
break;
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
case DNS_RRTYPE_AAAA:
|
|
p_rpRRAnswer = new stcMDNS_RRAnswerAAAA(header, u32TTL);
|
|
bResult = _readRRAnswerAAAA(*(stcMDNS_RRAnswerAAAA*&)p_rpRRAnswer, u16RDLength);
|
|
break;
|
|
#endif
|
|
case DNS_RRTYPE_SRV:
|
|
p_rpRRAnswer = new stcMDNS_RRAnswerSRV(header, u32TTL);
|
|
bResult = _readRRAnswerSRV(*(stcMDNS_RRAnswerSRV*&)p_rpRRAnswer, u16RDLength);
|
|
break;
|
|
default:
|
|
p_rpRRAnswer = new stcMDNS_RRAnswerGeneric(header, u32TTL);
|
|
bResult = _readRRAnswerGeneric(*(stcMDNS_RRAnswerGeneric*&)p_rpRRAnswer, u16RDLength);
|
|
break;
|
|
}
|
|
DEBUG_EX_INFO(
|
|
if ((bResult) &&
|
|
(p_rpRRAnswer))
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: "));
|
|
_printRRDomain(p_rpRRAnswer->m_Header.m_Domain);
|
|
DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, RDLength:%u "), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type, p_rpRRAnswer->m_Header.m_Attributes.m_u16Class, p_rpRRAnswer->m_u32TTL, u16RDLength);
|
|
switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag
|
|
{
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
case DNS_RRTYPE_A:
|
|
DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str());
|
|
break;
|
|
#endif
|
|
case DNS_RRTYPE_PTR:
|
|
DEBUG_OUTPUT.printf_P(PSTR("PTR "));
|
|
_printRRDomain(((stcMDNS_RRAnswerPTR*&)p_rpRRAnswer)->m_PTRDomain);
|
|
break;
|
|
case DNS_RRTYPE_TXT:
|
|
{
|
|
size_t stTxtLength = ((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_strLength();
|
|
char* pTxts = new char[stTxtLength];
|
|
if (pTxts)
|
|
{
|
|
((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_str(pTxts);
|
|
DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts);
|
|
delete[] pTxts;
|
|
}
|
|
break;
|
|
}
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
case DNS_RRTYPE_AAAA:
|
|
DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str());
|
|
break;
|
|
#endif
|
|
case DNS_RRTYPE_SRV:
|
|
DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_u16Port);
|
|
_printRRDomain(((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_SRVDomain);
|
|
break;
|
|
default:
|
|
DEBUG_OUTPUT.printf_P(PSTR("generic "));
|
|
break;
|
|
}
|
|
DEBUG_OUTPUT.printf_P(PSTR("\n"));
|
|
}
|
|
else
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED to read specific answer of type 0x%04X!\n"), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type);
|
|
}
|
|
); // DEBUG_EX_INFO
|
|
}
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
/*
|
|
MDNSResponder::_readRRAnswerA
|
|
*/
|
|
bool MDNSResponder::_readRRAnswerA(MDNSResponder::stcMDNS_RRAnswerA& p_rRRAnswerA,
|
|
uint16_t p_u16RDLength)
|
|
{
|
|
|
|
uint32_t u32IP4Address;
|
|
bool bResult = ((MDNS_IP4_SIZE == p_u16RDLength) &&
|
|
(_udpReadBuffer((unsigned char*)&u32IP4Address, MDNS_IP4_SIZE)) &&
|
|
((p_rRRAnswerA.m_IPAddress = IPAddress(u32IP4Address))));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerA: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
MDNSResponder::_readRRAnswerPTR
|
|
*/
|
|
bool MDNSResponder::_readRRAnswerPTR(MDNSResponder::stcMDNS_RRAnswerPTR& p_rRRAnswerPTR,
|
|
uint16_t p_u16RDLength)
|
|
{
|
|
|
|
bool bResult = ((p_u16RDLength) &&
|
|
(_readRRDomain(p_rRRAnswerPTR.m_PTRDomain)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerPTR: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_readRRAnswerTXT
|
|
|
|
Read TXT items from a buffer like 4c#=15ff=20
|
|
*/
|
|
bool MDNSResponder::_readRRAnswerTXT(MDNSResponder::stcMDNS_RRAnswerTXT& p_rRRAnswerTXT,
|
|
uint16_t p_u16RDLength)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: RDLength:%u\n"), p_u16RDLength););
|
|
bool bResult = true;
|
|
|
|
p_rRRAnswerTXT.clear();
|
|
if (p_u16RDLength)
|
|
{
|
|
bResult = false;
|
|
|
|
unsigned char* pucBuffer = new unsigned char[p_u16RDLength];
|
|
if (pucBuffer)
|
|
{
|
|
if (_udpReadBuffer(pucBuffer, p_u16RDLength))
|
|
{
|
|
bResult = true;
|
|
|
|
const unsigned char* pucCursor = pucBuffer;
|
|
while ((pucCursor < (pucBuffer + p_u16RDLength)) &&
|
|
(bResult))
|
|
{
|
|
bResult = false;
|
|
|
|
stcMDNSServiceTxt* pTxt = 0;
|
|
unsigned char ucLength = *pucCursor++; // Length of the next txt item
|
|
if (ucLength)
|
|
{
|
|
DEBUG_EX_INFO(
|
|
static char sacBuffer[64]; *sacBuffer = 0;
|
|
uint8_t u8MaxLength = ((ucLength > (sizeof(sacBuffer) - 1)) ? (sizeof(sacBuffer) - 1) : ucLength);
|
|
os_strncpy(sacBuffer, (const char*)pucCursor, u8MaxLength); sacBuffer[u8MaxLength] = 0;
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: Item(%u): %s\n"), ucLength, sacBuffer);
|
|
);
|
|
|
|
unsigned char* pucEqualSign = (unsigned char*)os_strchr((const char*)pucCursor, '='); // Position of the '=' sign
|
|
unsigned char ucKeyLength;
|
|
if ((pucEqualSign) &&
|
|
((ucKeyLength = (pucEqualSign - pucCursor))))
|
|
{
|
|
unsigned char ucValueLength = (ucLength - (pucEqualSign - pucCursor + 1));
|
|
bResult = (((pTxt = new stcMDNSServiceTxt)) &&
|
|
(pTxt->setKey((const char*)pucCursor, ucKeyLength)) &&
|
|
(pTxt->setValue((const char*)(pucEqualSign + 1), ucValueLength)));
|
|
}
|
|
else
|
|
{
|
|
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: INVALID TXT format (No '=')!\n")););
|
|
}
|
|
pucCursor += ucLength;
|
|
}
|
|
else // no/zero length TXT
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: TXT answer contains no items.\n")););
|
|
bResult = true;
|
|
}
|
|
|
|
if ((bResult) &&
|
|
(pTxt)) // Everythings fine so far
|
|
{
|
|
// Link TXT item to answer TXTs
|
|
pTxt->m_pNext = p_rRRAnswerTXT.m_Txts.m_pTxts;
|
|
p_rRRAnswerTXT.m_Txts.m_pTxts = pTxt;
|
|
}
|
|
else // At least no TXT (migth be OK, if length was 0) OR an error
|
|
{
|
|
if (!bResult)
|
|
{
|
|
DEBUG_EX_ERR(
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT item!\n"));
|
|
DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n"));
|
|
_udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength);
|
|
DEBUG_OUTPUT.printf_P(PSTR("\n"));
|
|
);
|
|
}
|
|
if (pTxt)
|
|
{
|
|
delete pTxt;
|
|
pTxt = 0;
|
|
}
|
|
p_rRRAnswerTXT.clear();
|
|
}
|
|
} // while
|
|
|
|
DEBUG_EX_ERR(
|
|
if (!bResult) // Some failure
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n"));
|
|
_udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength);
|
|
DEBUG_OUTPUT.printf_P(PSTR("\n"));
|
|
}
|
|
);
|
|
}
|
|
else
|
|
{
|
|
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT content!\n")););
|
|
}
|
|
// Clean up
|
|
delete[] pucBuffer;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to alloc buffer for TXT content!\n")););
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: WARNING! No content!\n")););
|
|
}
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
bool MDNSResponder::_readRRAnswerAAAA(MDNSResponder::stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA,
|
|
uint16_t p_u16RDLength)
|
|
{
|
|
bool bResult = false;
|
|
// TODO: Implement
|
|
return bResult;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
MDNSResponder::_readRRAnswerSRV
|
|
*/
|
|
bool MDNSResponder::_readRRAnswerSRV(MDNSResponder::stcMDNS_RRAnswerSRV& p_rRRAnswerSRV,
|
|
uint16_t p_u16RDLength)
|
|
{
|
|
|
|
bool bResult = (((3 * sizeof(uint16_t)) < p_u16RDLength) &&
|
|
(_udpRead16(p_rRRAnswerSRV.m_u16Priority)) &&
|
|
(_udpRead16(p_rRRAnswerSRV.m_u16Weight)) &&
|
|
(_udpRead16(p_rRRAnswerSRV.m_u16Port)) &&
|
|
(_readRRDomain(p_rRRAnswerSRV.m_SRVDomain)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerSRV: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_readRRAnswerGeneric
|
|
*/
|
|
bool MDNSResponder::_readRRAnswerGeneric(MDNSResponder::stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric,
|
|
uint16_t p_u16RDLength)
|
|
{
|
|
bool bResult = (0 == p_u16RDLength);
|
|
|
|
p_rRRAnswerGeneric.clear();
|
|
if (((p_rRRAnswerGeneric.m_u16RDLength = p_u16RDLength)) &&
|
|
((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength])))
|
|
{
|
|
|
|
bResult = _udpReadBuffer(p_rRRAnswerGeneric.m_pu8RDData, p_rRRAnswerGeneric.m_u16RDLength);
|
|
}
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerGeneric: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_readRRHeader
|
|
*/
|
|
bool MDNSResponder::_readRRHeader(MDNSResponder::stcMDNS_RRHeader& p_rRRHeader)
|
|
{
|
|
//DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader\n")););
|
|
|
|
bool bResult = ((_readRRDomain(p_rRRHeader.m_Domain)) &&
|
|
(_readRRAttributes(p_rRRHeader.m_Attributes)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_readRRDomain
|
|
|
|
Reads a (maybe multilevel compressed) domain from the UDP input buffer.
|
|
|
|
*/
|
|
bool MDNSResponder::_readRRDomain(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain)
|
|
{
|
|
//DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain\n")););
|
|
|
|
bool bResult = ((p_rRRDomain.clear()) &&
|
|
(_readRRDomain_Loop(p_rRRDomain, 0)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_readRRDomain_Loop
|
|
|
|
Reads a domain from the UDP input buffer. For every compression level, the functions
|
|
calls itself recursively. To avoid endless recursion because of malformed MDNS records,
|
|
the maximum recursion depth is set by MDNS_DOMAIN_MAX_REDIRCTION.
|
|
|
|
*/
|
|
bool MDNSResponder::_readRRDomain_Loop(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain,
|
|
uint8_t p_u8Depth)
|
|
{
|
|
//DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u)\n"), p_u8Depth););
|
|
|
|
bool bResult = false;
|
|
|
|
if (MDNS_DOMAIN_MAX_REDIRCTION >= p_u8Depth)
|
|
{
|
|
bResult = true;
|
|
|
|
uint8_t u8Len = 0;
|
|
do
|
|
{
|
|
//DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Offset:%u p0:%02x\n"), p_u8Depth, m_pUDPContext->tell(), m_pUDPContext->peek()););
|
|
_udpRead8(u8Len);
|
|
|
|
if (u8Len & MDNS_DOMAIN_COMPRESS_MARK)
|
|
{
|
|
// Compressed label(s)
|
|
uint16_t u16Offset = ((u8Len & ~MDNS_DOMAIN_COMPRESS_MARK) << 8); // Implicit BE to LE conversion!
|
|
_udpRead8(u8Len);
|
|
u16Offset |= u8Len;
|
|
|
|
if (m_pUDPContext->isValidOffset(u16Offset))
|
|
{
|
|
size_t stCurrentPosition = m_pUDPContext->tell(); // Prepare return from recursion
|
|
|
|
//DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Redirecting from %u to %u!\n"), p_u8Depth, stCurrentPosition, u16Offset););
|
|
m_pUDPContext->seek(u16Offset);
|
|
if (_readRRDomain_Loop(p_rRRDomain, p_u8Depth + 1)) // Do recursion
|
|
{
|
|
//DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Succeeded to read redirected label! Returning to %u\n"), p_u8Depth, stCurrentPosition););
|
|
m_pUDPContext->seek(stCurrentPosition); // Restore after recursion
|
|
}
|
|
else
|
|
{
|
|
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): FAILED to read redirected label!\n"), p_u8Depth););
|
|
bResult = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): INVALID offset in redirection!\n"), p_u8Depth););
|
|
bResult = false;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Normal (uncompressed) label (maybe '\0' only)
|
|
if (MDNS_DOMAIN_MAXLENGTH > (p_rRRDomain.m_u16NameLength + u8Len))
|
|
{
|
|
// Add length byte
|
|
p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength] = u8Len;
|
|
++(p_rRRDomain.m_u16NameLength);
|
|
if (u8Len) // Add name
|
|
{
|
|
if ((bResult = _udpReadBuffer((unsigned char*) & (p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength]), u8Len)))
|
|
{
|
|
/* DEBUG_EX_INFO(
|
|
p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength + u8Len] = 0; // Closing '\0' for printing
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Domain label (%u): %s\n"), p_u8Depth, (unsigned)(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength - 1]), &(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength]));
|
|
);*/
|
|
|
|
p_rRRDomain.m_u16NameLength += u8Len;
|
|
}
|
|
}
|
|
//DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(2) offset:%u p0:%x\n"), m_pUDPContext->tell(), m_pUDPContext->peek()););
|
|
}
|
|
else
|
|
{
|
|
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Domain name too long (%u + %u)!\n"), p_u8Depth, p_rRRDomain.m_u16NameLength, u8Len););
|
|
bResult = false;
|
|
break;
|
|
}
|
|
}
|
|
} while ((bResult) &&
|
|
(0 != u8Len));
|
|
}
|
|
else
|
|
{
|
|
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Too many redirections!\n"), p_u8Depth););
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_readRRAttributes
|
|
*/
|
|
bool MDNSResponder::_readRRAttributes(MDNSResponder::stcMDNS_RRAttributes& p_rRRAttributes)
|
|
{
|
|
//DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes\n")););
|
|
|
|
bool bResult = ((_udpRead16(p_rRRAttributes.m_u16Type)) &&
|
|
(_udpRead16(p_rRRAttributes.m_u16Class)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/*
|
|
DOMAIN NAMES
|
|
*/
|
|
|
|
/*
|
|
MDNSResponder::_buildDomainForHost
|
|
|
|
Builds a MDNS host domain (eg. esp8266.local) for the given hostname.
|
|
|
|
*/
|
|
bool MDNSResponder::_buildDomainForHost(const char* p_pcHostname,
|
|
MDNSResponder::stcMDNS_RRDomain& p_rHostDomain) const
|
|
{
|
|
|
|
p_rHostDomain.clear();
|
|
bool bResult = ((p_pcHostname) &&
|
|
(*p_pcHostname) &&
|
|
(p_rHostDomain.addLabel(p_pcHostname)) &&
|
|
(p_rHostDomain.addLabel(scpcLocal)) &&
|
|
(p_rHostDomain.addLabel(0)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForHost: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_buildDomainForDNSSD
|
|
|
|
Builds the '_services._dns-sd._udp.local' domain.
|
|
Used while detecting generic service enum question (DNS-SD) and answering these questions.
|
|
|
|
*/
|
|
bool MDNSResponder::_buildDomainForDNSSD(MDNSResponder::stcMDNS_RRDomain& p_rDNSSDDomain) const
|
|
{
|
|
|
|
p_rDNSSDDomain.clear();
|
|
bool bResult = ((p_rDNSSDDomain.addLabel(scpcServices, true)) &&
|
|
(p_rDNSSDDomain.addLabel(scpcDNSSD, true)) &&
|
|
(p_rDNSSDDomain.addLabel(scpcUDP, true)) &&
|
|
(p_rDNSSDDomain.addLabel(scpcLocal)) &&
|
|
(p_rDNSSDDomain.addLabel(0)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForDNSSD: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_buildDomainForService
|
|
|
|
Builds the domain for the given service (eg. _http._tcp.local or
|
|
MyESP._http._tcp.local (if p_bIncludeName is set)).
|
|
|
|
*/
|
|
bool MDNSResponder::_buildDomainForService(const MDNSResponder::stcMDNSService& p_Service,
|
|
bool p_bIncludeName,
|
|
MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const
|
|
{
|
|
|
|
p_rServiceDomain.clear();
|
|
bool bResult = (((!p_bIncludeName) ||
|
|
(p_rServiceDomain.addLabel(p_Service.m_pcName))) &&
|
|
(p_rServiceDomain.addLabel(p_Service.m_pcService, true)) &&
|
|
(p_rServiceDomain.addLabel(p_Service.m_pcProtocol, true)) &&
|
|
(p_rServiceDomain.addLabel(scpcLocal)) &&
|
|
(p_rServiceDomain.addLabel(0)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_buildDomainForService
|
|
|
|
Builds the domain for the given service properties (eg. _http._tcp.local).
|
|
The usual prepended '_' are added, if missing in the input strings.
|
|
|
|
*/
|
|
bool MDNSResponder::_buildDomainForService(const char* p_pcService,
|
|
const char* p_pcProtocol,
|
|
MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const
|
|
{
|
|
|
|
p_rServiceDomain.clear();
|
|
bool bResult = ((p_pcService) &&
|
|
(p_pcProtocol) &&
|
|
(p_rServiceDomain.addLabel(p_pcService, ('_' != *p_pcService))) &&
|
|
(p_rServiceDomain.addLabel(p_pcProtocol, ('_' != *p_pcProtocol))) &&
|
|
(p_rServiceDomain.addLabel(scpcLocal)) &&
|
|
(p_rServiceDomain.addLabel(0)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED for (%s.%s)!\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-")););
|
|
return bResult;
|
|
}
|
|
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
/*
|
|
MDNSResponder::_buildDomainForReverseIP4
|
|
|
|
The IP4 address is stringized by printing the four address bytes into a char buffer in reverse order
|
|
and adding 'in-addr.arpa' (eg. 012.789.456.123.in-addr.arpa).
|
|
Used while detecting reverse IP4 questions and answering these
|
|
*/
|
|
bool MDNSResponder::_buildDomainForReverseIP4(IPAddress p_IP4Address,
|
|
MDNSResponder::stcMDNS_RRDomain& p_rReverseIP4Domain) const
|
|
{
|
|
|
|
bool bResult = true;
|
|
|
|
p_rReverseIP4Domain.clear();
|
|
|
|
char acBuffer[32];
|
|
for (int i = MDNS_IP4_SIZE; ((bResult) && (i >= 1)); --i)
|
|
{
|
|
itoa(p_IP4Address[i - 1], acBuffer, 10);
|
|
bResult = p_rReverseIP4Domain.addLabel(acBuffer);
|
|
}
|
|
bResult = ((bResult) &&
|
|
(p_rReverseIP4Domain.addLabel(scpcReverseIP4Domain)) &&
|
|
(p_rReverseIP4Domain.addLabel(scpcReverseTopDomain)) &&
|
|
(p_rReverseIP4Domain.addLabel(0)));
|
|
DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForReverseIP4: FAILED!\n")););
|
|
return bResult;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
/*
|
|
MDNSResponder::_buildDomainForReverseIP6
|
|
|
|
Used while detecting reverse IP6 questions and answering these
|
|
*/
|
|
bool MDNSResponder::_buildDomainForReverseIP6(IPAddress p_IP4Address,
|
|
MDNSResponder::stcMDNS_RRDomain& p_rReverseIP6Domain) const
|
|
{
|
|
// TODO: Implement
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
UDP
|
|
*/
|
|
|
|
/*
|
|
MDNSResponder::_udpReadBuffer
|
|
*/
|
|
bool MDNSResponder::_udpReadBuffer(unsigned char* p_pBuffer,
|
|
size_t p_stLength)
|
|
{
|
|
|
|
bool bResult = ((m_pUDPContext) &&
|
|
(true/*m_pUDPContext->getSize() > p_stLength*/) &&
|
|
(p_pBuffer) &&
|
|
(p_stLength) &&
|
|
((p_stLength == m_pUDPContext->read((char*)p_pBuffer, p_stLength))));
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpReadBuffer: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_udpRead8
|
|
*/
|
|
bool MDNSResponder::_udpRead8(uint8_t& p_ru8Value)
|
|
{
|
|
|
|
return _udpReadBuffer((unsigned char*)&p_ru8Value, sizeof(p_ru8Value));
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_udpRead16
|
|
*/
|
|
bool MDNSResponder::_udpRead16(uint16_t& p_ru16Value)
|
|
{
|
|
|
|
bool bResult = false;
|
|
|
|
if (_udpReadBuffer((unsigned char*)&p_ru16Value, sizeof(p_ru16Value)))
|
|
{
|
|
p_ru16Value = lwip_ntohs(p_ru16Value);
|
|
bResult = true;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_udpRead32
|
|
*/
|
|
bool MDNSResponder::_udpRead32(uint32_t& p_ru32Value)
|
|
{
|
|
|
|
bool bResult = false;
|
|
|
|
if (_udpReadBuffer((unsigned char*)&p_ru32Value, sizeof(p_ru32Value)))
|
|
{
|
|
p_ru32Value = lwip_ntohl(p_ru32Value);
|
|
bResult = true;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_udpAppendBuffer
|
|
*/
|
|
bool MDNSResponder::_udpAppendBuffer(const unsigned char* p_pcBuffer,
|
|
size_t p_stLength)
|
|
{
|
|
|
|
bool bResult = ((m_pUDPContext) &&
|
|
(p_pcBuffer) &&
|
|
(p_stLength) &&
|
|
(p_stLength == m_pUDPContext->append((const char*)p_pcBuffer, p_stLength)));
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpAppendBuffer: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_udpAppend8
|
|
*/
|
|
bool MDNSResponder::_udpAppend8(uint8_t p_u8Value)
|
|
{
|
|
|
|
return (_udpAppendBuffer((unsigned char*)&p_u8Value, sizeof(p_u8Value)));
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_udpAppend16
|
|
*/
|
|
bool MDNSResponder::_udpAppend16(uint16_t p_u16Value)
|
|
{
|
|
|
|
p_u16Value = lwip_htons(p_u16Value);
|
|
return (_udpAppendBuffer((unsigned char*)&p_u16Value, sizeof(p_u16Value)));
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_udpAppend32
|
|
*/
|
|
bool MDNSResponder::_udpAppend32(uint32_t p_u32Value)
|
|
{
|
|
|
|
p_u32Value = lwip_htonl(p_u32Value);
|
|
return (_udpAppendBuffer((unsigned char*)&p_u32Value, sizeof(p_u32Value)));
|
|
}
|
|
|
|
#ifdef DEBUG_ESP_MDNS_RESPONDER
|
|
/*
|
|
MDNSResponder::_udpDump
|
|
*/
|
|
bool MDNSResponder::_udpDump(bool p_bMovePointer /*= false*/)
|
|
{
|
|
|
|
const uint8_t cu8BytesPerLine = 16;
|
|
|
|
uint32_t u32StartPosition = m_pUDPContext->tell();
|
|
DEBUG_OUTPUT.println("UDP Context Dump:");
|
|
uint32_t u32Counter = 0;
|
|
uint8_t u8Byte = 0;
|
|
|
|
while (_udpRead8(u8Byte))
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("%02x %s"), u8Byte, ((++u32Counter % cu8BytesPerLine) ? "" : "\n"));
|
|
}
|
|
DEBUG_OUTPUT.printf_P(PSTR("%sDone: %u bytes\n"), (((u32Counter) && (u32Counter % cu8BytesPerLine)) ? "\n" : ""), u32Counter);
|
|
|
|
if (!p_bMovePointer) // Restore
|
|
{
|
|
m_pUDPContext->seek(u32StartPosition);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_udpDump
|
|
*/
|
|
bool MDNSResponder::_udpDump(unsigned p_uOffset,
|
|
unsigned p_uLength)
|
|
{
|
|
|
|
if ((m_pUDPContext) &&
|
|
(m_pUDPContext->isValidOffset(p_uOffset)))
|
|
{
|
|
unsigned uCurrentPosition = m_pUDPContext->tell(); // Remember start position
|
|
|
|
m_pUDPContext->seek(p_uOffset);
|
|
uint8_t u8Byte;
|
|
for (unsigned u = 0; ((u < p_uLength) && (_udpRead8(u8Byte))); ++u)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("%02x "), u8Byte);
|
|
}
|
|
// Return to start position
|
|
m_pUDPContext->seek(uCurrentPosition);
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
|
|
/**
|
|
READ/WRITE MDNS STRUCTS
|
|
*/
|
|
|
|
/*
|
|
MDNSResponder::_readMDNSMsgHeader
|
|
|
|
Read a MDNS header from the UDP input buffer.
|
|
| 8 | 8 | 8 | 8 |
|
|
00| Identifier | Flags & Codes |
|
|
01| Question count | Answer count |
|
|
02| NS answer count | Ad answer count |
|
|
|
|
All 16-bit and 32-bit elements need to be translated form network coding to host coding (done in _udpRead16 and _udpRead32)
|
|
In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they
|
|
need some mapping here
|
|
*/
|
|
bool MDNSResponder::_readMDNSMsgHeader(MDNSResponder::stcMDNS_MsgHeader& p_rMsgHeader)
|
|
{
|
|
|
|
bool bResult = false;
|
|
|
|
uint8_t u8B1;
|
|
uint8_t u8B2;
|
|
if ((_udpRead16(p_rMsgHeader.m_u16ID)) &&
|
|
(_udpRead8(u8B1)) &&
|
|
(_udpRead8(u8B2)) &&
|
|
(_udpRead16(p_rMsgHeader.m_u16QDCount)) &&
|
|
(_udpRead16(p_rMsgHeader.m_u16ANCount)) &&
|
|
(_udpRead16(p_rMsgHeader.m_u16NSCount)) &&
|
|
(_udpRead16(p_rMsgHeader.m_u16ARCount)))
|
|
{
|
|
|
|
p_rMsgHeader.m_1bQR = (u8B1 & 0x80); // Query/Responde flag
|
|
p_rMsgHeader.m_4bOpcode = (u8B1 & 0x78); // Operation code (0: Standard query, others ignored)
|
|
p_rMsgHeader.m_1bAA = (u8B1 & 0x04); // Authorative answer
|
|
p_rMsgHeader.m_1bTC = (u8B1 & 0x02); // Truncation flag
|
|
p_rMsgHeader.m_1bRD = (u8B1 & 0x01); // Recursion desired
|
|
|
|
p_rMsgHeader.m_1bRA = (u8B2 & 0x80); // Recursion available
|
|
p_rMsgHeader.m_3bZ = (u8B2 & 0x70); // Zero
|
|
p_rMsgHeader.m_4bRCode = (u8B2 & 0x0F); // Response code
|
|
|
|
/* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"),
|
|
(unsigned)p_rMsgHeader.m_u16ID,
|
|
(unsigned)p_rMsgHeader.m_1bQR, (unsigned)p_rMsgHeader.m_4bOpcode, (unsigned)p_rMsgHeader.m_1bAA, (unsigned)p_rMsgHeader.m_1bTC, (unsigned)p_rMsgHeader.m_1bRD,
|
|
(unsigned)p_rMsgHeader.m_1bRA, (unsigned)p_rMsgHeader.m_4bRCode,
|
|
(unsigned)p_rMsgHeader.m_u16QDCount,
|
|
(unsigned)p_rMsgHeader.m_u16ANCount,
|
|
(unsigned)p_rMsgHeader.m_u16NSCount,
|
|
(unsigned)p_rMsgHeader.m_u16ARCount););*/
|
|
bResult = true;
|
|
}
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_write8
|
|
*/
|
|
bool MDNSResponder::_write8(uint8_t p_u8Value,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
|
|
return ((_udpAppend8(p_u8Value)) &&
|
|
(p_rSendParameter.shiftOffset(sizeof(p_u8Value))));
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_write16
|
|
*/
|
|
bool MDNSResponder::_write16(uint16_t p_u16Value,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
|
|
return ((_udpAppend16(p_u16Value)) &&
|
|
(p_rSendParameter.shiftOffset(sizeof(p_u16Value))));
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_write32
|
|
*/
|
|
bool MDNSResponder::_write32(uint32_t p_u32Value,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
|
|
return ((_udpAppend32(p_u32Value)) &&
|
|
(p_rSendParameter.shiftOffset(sizeof(p_u32Value))));
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSMsgHeader
|
|
|
|
Write MDNS header to the UDP output buffer.
|
|
|
|
All 16-bit and 32-bit elements need to be translated form host coding to network coding (done in _udpAppend16 and _udpAppend32)
|
|
In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they
|
|
need some mapping here
|
|
*/
|
|
bool MDNSResponder::_writeMDNSMsgHeader(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
/* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"),
|
|
(unsigned)p_MsgHeader.m_u16ID,
|
|
(unsigned)p_MsgHeader.m_1bQR, (unsigned)p_MsgHeader.m_4bOpcode, (unsigned)p_MsgHeader.m_1bAA, (unsigned)p_MsgHeader.m_1bTC, (unsigned)p_MsgHeader.m_1bRD,
|
|
(unsigned)p_MsgHeader.m_1bRA, (unsigned)p_MsgHeader.m_4bRCode,
|
|
(unsigned)p_MsgHeader.m_u16QDCount,
|
|
(unsigned)p_MsgHeader.m_u16ANCount,
|
|
(unsigned)p_MsgHeader.m_u16NSCount,
|
|
(unsigned)p_MsgHeader.m_u16ARCount););*/
|
|
|
|
uint8_t u8B1((p_MsgHeader.m_1bQR << 7) | (p_MsgHeader.m_4bOpcode << 3) | (p_MsgHeader.m_1bAA << 2) | (p_MsgHeader.m_1bTC << 1) | (p_MsgHeader.m_1bRD));
|
|
uint8_t u8B2((p_MsgHeader.m_1bRA << 7) | (p_MsgHeader.m_3bZ << 4) | (p_MsgHeader.m_4bRCode));
|
|
bool bResult = ((_write16(p_MsgHeader.m_u16ID, p_rSendParameter)) &&
|
|
(_write8(u8B1, p_rSendParameter)) &&
|
|
(_write8(u8B2, p_rSendParameter)) &&
|
|
(_write16(p_MsgHeader.m_u16QDCount, p_rSendParameter)) &&
|
|
(_write16(p_MsgHeader.m_u16ANCount, p_rSendParameter)) &&
|
|
(_write16(p_MsgHeader.m_u16NSCount, p_rSendParameter)) &&
|
|
(_write16(p_MsgHeader.m_u16ARCount, p_rSendParameter)));
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_writeRRAttributes
|
|
*/
|
|
bool MDNSResponder::_writeMDNSRRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Attributes,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
|
|
bool bResult = ((_write16(p_Attributes.m_u16Type, p_rSendParameter)) &&
|
|
(_write16(p_Attributes.m_u16Class, p_rSendParameter)));
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRAttributes: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSRRDomain
|
|
*/
|
|
bool MDNSResponder::_writeMDNSRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_Domain,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
|
|
bool bResult = ((_udpAppendBuffer((const unsigned char*)p_Domain.m_acName, p_Domain.m_u16NameLength)) &&
|
|
(p_rSendParameter.shiftOffset(p_Domain.m_u16NameLength)));
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRDomain: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSHostDomain
|
|
|
|
Write a host domain to the UDP output buffer.
|
|
If the domain record is part of the answer, the records length is
|
|
prepended (p_bPrependRDLength is set).
|
|
|
|
A very simple form of name compression is applied here:
|
|
If the domain is written to the UDP output buffer, the write offset is stored
|
|
together with a domain id (the pointer) in a p_rSendParameter substructure (cache).
|
|
If the same domain (pointer) should be written to the UDP output later again,
|
|
the old offset is retrieved from the cache, marked as a compressed domain offset
|
|
and written to the output buffer.
|
|
|
|
*/
|
|
bool MDNSResponder::_writeMDNSHostDomain(const char* p_pcHostname,
|
|
bool p_bPrependRDLength,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
|
|
// The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV'
|
|
uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)p_pcHostname, false);
|
|
|
|
stcMDNS_RRDomain hostDomain;
|
|
bool bResult = (u16CachedDomainOffset
|
|
// Found cached domain -> mark as compressed domain
|
|
? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset
|
|
((!p_bPrependRDLength) ||
|
|
(_write16(2, p_rSendParameter))) && // Length of 'Cxxx'
|
|
(_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset)
|
|
(_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter)))
|
|
// No cached domain -> add this domain to cache and write full domain name
|
|
: ((_buildDomainForHost(p_pcHostname, hostDomain)) && // eg. esp8266.local
|
|
((!p_bPrependRDLength) ||
|
|
(_write16(hostDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed)
|
|
(p_rSendParameter.addDomainCacheItem((const void*)p_pcHostname, false, p_rSendParameter.m_u16Offset)) &&
|
|
(_writeMDNSRRDomain(hostDomain, p_rSendParameter))));
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSHostDomain: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSServiceDomain
|
|
|
|
Write a service domain to the UDP output buffer.
|
|
If the domain record is part of the answer, the records length is
|
|
prepended (p_bPrependRDLength is set).
|
|
|
|
A very simple form of name compression is applied here: see '_writeMDNSHostDomain'
|
|
The cache differentiates of course between service domains which includes
|
|
the instance name (p_bIncludeName is set) and thoose who don't.
|
|
|
|
*/
|
|
bool MDNSResponder::_writeMDNSServiceDomain(const MDNSResponder::stcMDNSService& p_Service,
|
|
bool p_bIncludeName,
|
|
bool p_bPrependRDLength,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
|
|
// The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV'
|
|
uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)&p_Service, p_bIncludeName);
|
|
|
|
stcMDNS_RRDomain serviceDomain;
|
|
bool bResult = (u16CachedDomainOffset
|
|
// Found cached domain -> mark as compressed domain
|
|
? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset
|
|
((!p_bPrependRDLength) ||
|
|
(_write16(2, p_rSendParameter))) && // Lenght of 'Cxxx'
|
|
(_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset)
|
|
(_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter)))
|
|
// No cached domain -> add this domain to cache and write full domain name
|
|
: ((_buildDomainForService(p_Service, p_bIncludeName, serviceDomain)) && // eg. MyESP._http._tcp.local
|
|
((!p_bPrependRDLength) ||
|
|
(_write16(serviceDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed)
|
|
(p_rSendParameter.addDomainCacheItem((const void*)&p_Service, p_bIncludeName, p_rSendParameter.m_u16Offset)) &&
|
|
(_writeMDNSRRDomain(serviceDomain, p_rSendParameter))));
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSServiceDomain: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSQuestion
|
|
|
|
Write a MDNS question to the UDP output buffer
|
|
|
|
QNAME (host/service domain, eg. esp8266.local)
|
|
QTYPE (16bit, eg. ANY)
|
|
QCLASS (16bit, eg. IN)
|
|
|
|
*/
|
|
bool MDNSResponder::_writeMDNSQuestion(MDNSResponder::stcMDNS_RRQuestion& p_Question,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion\n")););
|
|
|
|
bool bResult = ((_writeMDNSRRDomain(p_Question.m_Header.m_Domain, p_rSendParameter)) &&
|
|
(_writeMDNSRRAttributes(p_Question.m_Header.m_Attributes, p_rSendParameter)));
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
|
|
}
|
|
|
|
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
/*
|
|
MDNSResponder::_writeMDNSAnswer_A
|
|
|
|
Write a MDNS A answer to the UDP output buffer.
|
|
|
|
NAME (var, host/service domain, eg. esp8266.local
|
|
TYPE (16bit, eg. A)
|
|
CLASS (16bit, eg. IN)
|
|
TTL (32bit, eg. 120)
|
|
RDLENGTH (16bit, eg 4)
|
|
RDATA (var, eg. 123.456.789.012)
|
|
|
|
eg. esp8266.local A 0x8001 120 4 123.456.789.012
|
|
Ref: http://www.zytrax.com/books/dns/ch8/a.html
|
|
*/
|
|
bool MDNSResponder::_writeMDNSAnswer_A(IPAddress p_IPAddress,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A (%s)\n"), p_IPAddress.toString().c_str()););
|
|
|
|
stcMDNS_RRAttributes attributes(DNS_RRTYPE_A,
|
|
((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet
|
|
const unsigned char aucIPAddress[MDNS_IP4_SIZE] = { p_IPAddress[0], p_IPAddress[1], p_IPAddress[2], p_IPAddress[3] };
|
|
bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) &&
|
|
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
|
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL
|
|
(_write16(MDNS_IP4_SIZE, p_rSendParameter)) && // RDLength
|
|
(_udpAppendBuffer(aucIPAddress, MDNS_IP4_SIZE)) && // RData
|
|
(p_rSendParameter.shiftOffset(MDNS_IP4_SIZE)));
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSAnswer_PTR_IP4
|
|
|
|
Write a MDNS reverse IP4 PTR answer to the UDP output buffer.
|
|
See: '_writeMDNSAnswer_A'
|
|
|
|
eg. 012.789.456.123.in-addr.arpa PTR 0x8001 120 15 esp8266.local
|
|
Used while answering reverse IP4 questions
|
|
*/
|
|
bool MDNSResponder::_writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4 (%s)\n"), p_IPAddress.toString().c_str()););
|
|
|
|
stcMDNS_RRDomain reverseIP4Domain;
|
|
stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR,
|
|
((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet
|
|
stcMDNS_RRDomain hostDomain;
|
|
bool bResult = ((_buildDomainForReverseIP4(p_IPAddress, reverseIP4Domain)) && // 012.789.456.123.in-addr.arpa
|
|
(_writeMDNSRRDomain(reverseIP4Domain, p_rSendParameter)) &&
|
|
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
|
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL
|
|
(_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local)
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSAnswer_PTR_TYPE
|
|
|
|
Write a MDNS PTR answer to the UDP output buffer.
|
|
See: '_writeMDNSAnswer_A'
|
|
|
|
PTR all-services -> service type
|
|
eg. _services._dns-sd._udp.local PTR 0x8001 5400 xx _http._tcp.local
|
|
http://www.zytrax.com/books/dns/ch8/ptr.html
|
|
*/
|
|
bool MDNSResponder::_writeMDNSAnswer_PTR_TYPE(MDNSResponder::stcMDNSService& p_rService,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE\n")););
|
|
|
|
stcMDNS_RRDomain dnssdDomain;
|
|
stcMDNS_RRDomain serviceDomain;
|
|
stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet
|
|
bool bResult = ((_buildDomainForDNSSD(dnssdDomain)) && // _services._dns-sd._udp.local
|
|
(_writeMDNSRRDomain(dnssdDomain, p_rSendParameter)) &&
|
|
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
|
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL
|
|
(_writeMDNSServiceDomain(p_rService, false, true, p_rSendParameter))); // RDLength & RData (service domain, eg. _http._tcp.local)
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSAnswer_PTR_NAME
|
|
|
|
Write a MDNS PTR answer to the UDP output buffer.
|
|
See: '_writeMDNSAnswer_A'
|
|
|
|
PTR service type -> service name
|
|
eg. _http.tcp.local PTR 0x8001 120 xx myESP._http._tcp.local
|
|
http://www.zytrax.com/books/dns/ch8/ptr.html
|
|
*/
|
|
bool MDNSResponder::_writeMDNSAnswer_PTR_NAME(MDNSResponder::stcMDNSService& p_rService,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME\n")););
|
|
|
|
stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet
|
|
bool bResult = ((_writeMDNSServiceDomain(p_rService, false, false, p_rSendParameter)) && // _http._tcp.local
|
|
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
|
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL
|
|
(_writeMDNSServiceDomain(p_rService, true, true, p_rSendParameter))); // RDLength & RData (service domain, eg. MyESP._http._tcp.local)
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSAnswer_TXT
|
|
|
|
Write a MDNS TXT answer to the UDP output buffer.
|
|
See: '_writeMDNSAnswer_A'
|
|
|
|
The TXT items in the RDATA block are 'length byte encoded': [len]vardata
|
|
|
|
eg. myESP._http._tcp.local TXT 0x8001 120 4 c#=1
|
|
http://www.zytrax.com/books/dns/ch8/txt.html
|
|
*/
|
|
bool MDNSResponder::_writeMDNSAnswer_TXT(MDNSResponder::stcMDNSService& p_rService,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT\n")););
|
|
|
|
bool bResult = false;
|
|
|
|
stcMDNS_RRAttributes attributes(DNS_RRTYPE_TXT,
|
|
((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet
|
|
|
|
if ((_collectServiceTxts(p_rService)) &&
|
|
(_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local
|
|
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
|
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL
|
|
(_write16(p_rService.m_Txts.length(), p_rSendParameter))) // RDLength
|
|
{
|
|
|
|
bResult = true;
|
|
// RData Txts
|
|
for (stcMDNSServiceTxt* pTxt = p_rService.m_Txts.m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext)
|
|
{
|
|
unsigned char ucLengthByte = pTxt->length();
|
|
bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length
|
|
(p_rSendParameter.shiftOffset(sizeof(ucLengthByte))) &&
|
|
((size_t)os_strlen(pTxt->m_pcKey) == m_pUDPContext->append(pTxt->m_pcKey, os_strlen(pTxt->m_pcKey))) && // Key
|
|
(p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcKey))) &&
|
|
(1 == m_pUDPContext->append("=", 1)) && // =
|
|
(p_rSendParameter.shiftOffset(1)) &&
|
|
((!pTxt->m_pcValue) ||
|
|
(((size_t)os_strlen(pTxt->m_pcValue) == m_pUDPContext->append(pTxt->m_pcValue, os_strlen(pTxt->m_pcValue))) && // Value
|
|
(p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcValue))))));
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED to write %sTxt %s=%s!\n"), (pTxt->m_bTemp ? "temp. " : ""), (pTxt->m_pcKey ? : "?"), (pTxt->m_pcValue ? : "?"));
|
|
});
|
|
}
|
|
}
|
|
_releaseTempServiceTxts(p_rService);
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
/*
|
|
MDNSResponder::_writeMDNSAnswer_AAAA
|
|
|
|
Write a MDNS AAAA answer to the UDP output buffer.
|
|
See: '_writeMDNSAnswer_A'
|
|
|
|
eg. esp8266.local AAAA 0x8001 120 16 xxxx::xx
|
|
http://www.zytrax.com/books/dns/ch8/aaaa.html
|
|
*/
|
|
bool MDNSResponder::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA\n")););
|
|
|
|
stcMDNS_RRAttributes attributes(DNS_RRTYPE_AAAA,
|
|
((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet
|
|
bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && // esp8266.local
|
|
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
|
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL
|
|
(_write16(MDNS_IP6_SIZE, p_rSendParameter)) && // RDLength
|
|
(false /*TODO: IP6 version of: _udpAppendBuffer((uint32_t)p_IPAddress, MDNS_IP4_SIZE)*/)); // RData
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSAnswer_PTR_IP6
|
|
|
|
Write a MDNS reverse IP6 PTR answer to the UDP output buffer.
|
|
See: '_writeMDNSAnswer_A'
|
|
|
|
eg. xxxx::xx.in6.arpa PTR 0x8001 120 15 esp8266.local
|
|
Used while answering reverse IP6 questions
|
|
*/
|
|
bool MDNSResponder::_writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6\n")););
|
|
|
|
stcMDNS_RRDomain reverseIP6Domain;
|
|
stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR,
|
|
((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet
|
|
bool bResult = ((_buildDomainForReverseIP6(p_IPAddress, reverseIP6Domain)) && // xxxx::xx.ip6.arpa
|
|
(_writeMDNSRRDomain(reverseIP6Domain, p_rSendParameter)) &&
|
|
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
|
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL
|
|
(_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local)
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
MDNSResponder::_writeMDNSAnswer_SRV
|
|
|
|
eg. MyESP._http.tcp.local SRV 0x8001 120 0 0 60068 esp8266.local
|
|
http://www.zytrax.com/books/dns/ch8/srv.html ???? Include instance name ????
|
|
*/
|
|
bool MDNSResponder::_writeMDNSAnswer_SRV(MDNSResponder::stcMDNSService& p_rService,
|
|
MDNSResponder::stcMDNSSendParameter& p_rSendParameter)
|
|
{
|
|
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV\n")););
|
|
|
|
uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyQuery
|
|
? 0
|
|
: p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostname, false));
|
|
|
|
stcMDNS_RRAttributes attributes(DNS_RRTYPE_SRV,
|
|
((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet
|
|
stcMDNS_RRDomain hostDomain;
|
|
bool bResult = ((_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local
|
|
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
|
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL
|
|
(!u16CachedDomainOffset
|
|
// No cache for domain name (or no compression allowed)
|
|
? ((_buildDomainForHost(m_pcHostname, hostDomain)) &&
|
|
(_write16((sizeof(uint16_t /*Prio*/) + // RDLength
|
|
sizeof(uint16_t /*Weight*/) +
|
|
sizeof(uint16_t /*Port*/) +
|
|
hostDomain.m_u16NameLength), p_rSendParameter)) && // Domain length
|
|
(_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority
|
|
(_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight
|
|
(_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port
|
|
(p_rSendParameter.addDomainCacheItem((const void*)m_pcHostname, false, p_rSendParameter.m_u16Offset)) &&
|
|
(_writeMDNSRRDomain(hostDomain, p_rSendParameter))) // Host, eg. esp8266.local
|
|
// Cache available for domain
|
|
: ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset
|
|
(_write16((sizeof(uint16_t /*Prio*/) + // RDLength
|
|
sizeof(uint16_t /*Weight*/) +
|
|
sizeof(uint16_t /*Port*/) +
|
|
2), p_rSendParameter)) && // Length of 'C0xx'
|
|
(_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority
|
|
(_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight
|
|
(_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port
|
|
(_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset)
|
|
(_write8((uint8_t)u16CachedDomainOffset, p_rSendParameter))))); // Offset
|
|
|
|
DEBUG_EX_ERR(if (!bResult)
|
|
{
|
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV: FAILED!\n"));
|
|
});
|
|
return bResult;
|
|
}
|
|
|
|
} // namespace MDNSImplementation
|
|
|
|
} // namespace esp8266
|
|
|
|
|
|
|
|
|
|
|
|
|