1463 lines
56 KiB
C++
1463 lines
56 KiB
C++
/*
|
|
LEAmDNS.h
|
|
(c) 2018, LaborEtArs
|
|
|
|
Version 0.9 beta
|
|
|
|
Some notes (from LaborEtArs, 2018):
|
|
Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS).
|
|
The target of this rewrite was to keep the existing interface as stable as possible while
|
|
adding and extending the supported set of mDNS features.
|
|
A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code.
|
|
|
|
Supported mDNS features (in some cases somewhat limited):
|
|
- Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service
|
|
- Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented
|
|
- Probing host and service domains for uniqueness in the local network
|
|
- Tiebreaking while probing is supported in a very minimalistic way (the 'higher' IP address wins the tiebreak)
|
|
- Announcing available services after successful probing
|
|
- Using fixed service TXT items or
|
|
- Using dynamic service TXT items for presented services (via callback)
|
|
- Remove services (and un-announcing them to the observers by sending goodbye-messages)
|
|
- Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period)
|
|
- Dynamic queries for DNS-SD services with cached and updated answers and user notifications
|
|
|
|
|
|
Usage:
|
|
In most cases, this implementation should work as a 'drop-in' replacement for the original
|
|
ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some
|
|
of the new features should be used.
|
|
|
|
For presenting services:
|
|
In 'setup()':
|
|
Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);'
|
|
Register DNS-SD services with 'MDNSResponder::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);'
|
|
(Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);')
|
|
Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback
|
|
using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific
|
|
'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);'
|
|
Call MDNS.begin("MyHostname");
|
|
|
|
In 'probeResultCallback(MDNSResponder* p_MDNSResponder, const char* p_pcDomain, MDNSResponder:hMDNSService p_hService, bool p_bProbeResult, void* p_pUserdata)':
|
|
Check the probe result and update the host or service domain name if the probe failed
|
|
|
|
In 'dynamicServiceTxtCallback(MDNSResponder* p_MDNSResponder, const hMDNSService p_hService, void* p_pUserdata)':
|
|
Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hService, "c#", "1");'
|
|
|
|
In loop():
|
|
Call 'MDNS.update();'
|
|
|
|
|
|
For querying services:
|
|
Static:
|
|
Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");'
|
|
Iterate answers by: 'for (uint32_t u=0; u<u32AnswerCount; ++u) { const char* pHostname = MDNS.answerHostname(u); }'
|
|
You should call MDNS.removeQuery() sometimes later (when the answers are nott needed anymore)
|
|
|
|
Dynamic:
|
|
Install a dynamic query by calling 'DNSResponder::hMDNSServiceQuery hServiceQuery = MDNS.installServiceQuery("http", "tcp", serviceQueryCallback, &userData);'
|
|
The callback 'serviceQueryCallback(MDNSResponder* p_MDNSResponder, const hMDNSServiceQuery p_hServiceQuery, uint32_t p_u32AnswerIndex,
|
|
enuServiceQueryAnswerType p_ServiceQueryAnswerType, bool p_bSetContent, void* p_pUserdata)'
|
|
is called for any change in the answer set.
|
|
Call 'MDNS.removeServiceQuery(hServiceQuery);' when the answers are not needed anymore
|
|
|
|
|
|
Reference:
|
|
Used mDNS messages:
|
|
A (0x01): eg. esp8266.local A OP TTL 123.456.789.012
|
|
AAAA (0x1C): eg. esp8266.local AAAA OP TTL 1234:5678::90
|
|
PTR (0x0C, srv name): eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local
|
|
PTR (0x0C, srv type): eg. _services._dns-sd._udp.local PTR OP TTL _http._tcp.local
|
|
PTR (0x0C, IP4): eg. 012.789.456.123.in-addr.arpa PTR OP TTL esp8266.local
|
|
PTR (0x0C, IP6): eg. 90.0.0.0.0.0.0.0.0.0.0.0.78.56.34.12.ip6.arpa PTR OP TTL esp8266.local
|
|
SRV (0x21): eg. MyESP._http._tcp.local SRV OP TTL PRIORITY WEIGHT PORT esp8266.local
|
|
TXT (0x10): eg. MyESP._http._tcp.local TXT OP TTL c#=1
|
|
|
|
Some NOT used message types:
|
|
OPT (0x29): eDNS
|
|
NSEC (0x2F): DNSSEC
|
|
|
|
|
|
License (MIT license):
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
#ifndef MDNS_H
|
|
#define MDNS_H
|
|
|
|
#include <functional> // for UdpContext.h
|
|
#include "WiFiUdp.h"
|
|
#include "lwip/udp.h"
|
|
#include "debug.h"
|
|
#include "include/UdpContext.h"
|
|
#include <limits>
|
|
#include <PolledTimeout.h>
|
|
#include <map>
|
|
|
|
|
|
#include "ESP8266WiFi.h"
|
|
|
|
|
|
namespace esp8266
|
|
{
|
|
|
|
/**
|
|
LEAmDNS
|
|
*/
|
|
namespace MDNSImplementation
|
|
{
|
|
|
|
//this should be defined at build time
|
|
#ifndef ARDUINO_BOARD
|
|
#define ARDUINO_BOARD "generic"
|
|
#endif
|
|
|
|
#define MDNS_IP4_SUPPORT
|
|
//#define MDNS_IP6_SUPPORT
|
|
|
|
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
#define MDNS_IP4_SIZE 4
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
#define MDNS_IP6_SIZE 16
|
|
#endif
|
|
/*
|
|
Maximum length for all service txts for one service
|
|
*/
|
|
#define MDNS_SERVICE_TXT_MAXLENGTH 1300
|
|
/*
|
|
Maximum length for a full domain name eg. MyESP._http._tcp.local
|
|
*/
|
|
#define MDNS_DOMAIN_MAXLENGTH 256
|
|
/*
|
|
Maximum length of on label in a domain name (length info fits into 6 bits)
|
|
*/
|
|
#define MDNS_DOMAIN_LABEL_MAXLENGTH 63
|
|
/*
|
|
Maximum length of a service name eg. http
|
|
*/
|
|
#define MDNS_SERVICE_NAME_LENGTH 15
|
|
/*
|
|
Maximum length of a service protocol name eg. tcp
|
|
*/
|
|
#define MDNS_SERVICE_PROTOCOL_LENGTH 3
|
|
/*
|
|
Default timeout for static service queries
|
|
*/
|
|
#define MDNS_QUERYSERVICES_WAIT_TIME 1000
|
|
|
|
|
|
/**
|
|
MDNSResponder
|
|
*/
|
|
class MDNSResponder
|
|
{
|
|
public:
|
|
/* INTERFACE */
|
|
|
|
MDNSResponder(void);
|
|
virtual ~MDNSResponder(void);
|
|
|
|
// Start the MDNS responder by setting the default hostname
|
|
// Later call MDNS::update() in every 'loop' to run the process loop
|
|
// (probing, announcing, responding, ...)
|
|
// if interfaceAddress is not specified, default interface is STA, or AP when STA is not set
|
|
bool begin(const char* p_pcHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/);
|
|
bool begin(const String& p_strHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/)
|
|
{
|
|
return begin(p_strHostname.c_str(), p_IPAddress, p_u32TTL);
|
|
}
|
|
|
|
// Finish MDNS processing
|
|
bool close(void);
|
|
// for esp32 compatability
|
|
bool end(void);
|
|
// Change hostname (probing is restarted)
|
|
bool setHostname(const char* p_pcHostname);
|
|
// for compatibility...
|
|
bool setHostname(const String& p_strHostname);
|
|
|
|
bool isRunning(void)
|
|
{
|
|
return (m_pUDPContext != 0);
|
|
}
|
|
|
|
/**
|
|
hMDNSService (opaque handle to access the service)
|
|
*/
|
|
typedef const void* hMDNSService;
|
|
|
|
// Add a new service to the MDNS responder. If no name (instance name) is given (p_pcName = 0)
|
|
// the current hostname is used. If the hostname is changed later, the instance names for
|
|
// these 'auto-named' services are changed to the new name also (and probing is restarted).
|
|
// The usual '_' before p_pcService (eg. http) and protocol (eg. tcp) may be given.
|
|
hMDNSService addService(const char* p_pcName,
|
|
const char* p_pcService,
|
|
const char* p_pcProtocol,
|
|
uint16_t p_u16Port);
|
|
// Removes a service from the MDNS responder
|
|
bool removeService(const hMDNSService p_hService);
|
|
bool removeService(const char* p_pcInstanceName,
|
|
const char* p_pcServiceName,
|
|
const char* p_pcProtocol);
|
|
// for compatibility...
|
|
bool addService(const String& p_strServiceName,
|
|
const String& p_strProtocol,
|
|
uint16_t p_u16Port);
|
|
|
|
|
|
// Change the services instance name (and restart probing).
|
|
bool setServiceName(const hMDNSService p_hService,
|
|
const char* p_pcInstanceName);
|
|
//for compatibility
|
|
//Warning: this has the side effect of changing the hostname.
|
|
//TODO: implement instancename different from hostname
|
|
void setInstanceName(const char* p_pcHostname)
|
|
{
|
|
setHostname(p_pcHostname);
|
|
}
|
|
// for esp32 compatibilty
|
|
void setInstanceName(const String& s_pcHostname)
|
|
{
|
|
setInstanceName(s_pcHostname.c_str());
|
|
}
|
|
|
|
/**
|
|
hMDNSTxt (opaque handle to access the TXT items)
|
|
*/
|
|
typedef void* hMDNSTxt;
|
|
|
|
// Add a (static) MDNS TXT item ('key' = 'value') to the service
|
|
hMDNSTxt addServiceTxt(const hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
const char* p_pcValue);
|
|
hMDNSTxt addServiceTxt(const hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
uint32_t p_u32Value);
|
|
hMDNSTxt addServiceTxt(const hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
uint16_t p_u16Value);
|
|
hMDNSTxt addServiceTxt(const hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
uint8_t p_u8Value);
|
|
hMDNSTxt addServiceTxt(const hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
int32_t p_i32Value);
|
|
hMDNSTxt addServiceTxt(const hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
int16_t p_i16Value);
|
|
hMDNSTxt addServiceTxt(const hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
int8_t p_i8Value);
|
|
|
|
// Remove an existing (static) MDNS TXT item from the service
|
|
bool removeServiceTxt(const hMDNSService p_hService,
|
|
const hMDNSTxt p_hTxt);
|
|
bool removeServiceTxt(const hMDNSService p_hService,
|
|
const char* p_pcKey);
|
|
bool removeServiceTxt(const char* p_pcinstanceName,
|
|
const char* p_pcServiceName,
|
|
const char* p_pcProtocol,
|
|
const char* p_pcKey);
|
|
// for compatibility...
|
|
bool addServiceTxt(const char* p_pcService,
|
|
const char* p_pcProtocol,
|
|
const char* p_pcKey,
|
|
const char* p_pcValue);
|
|
bool addServiceTxt(const String& p_strService,
|
|
const String& p_strProtocol,
|
|
const String& p_strKey,
|
|
const String& p_strValue);
|
|
|
|
/**
|
|
MDNSDynamicServiceTxtCallbackFn
|
|
Callback function for dynamic MDNS TXT items
|
|
*/
|
|
|
|
typedef std::function<void(const hMDNSService p_hService)> MDNSDynamicServiceTxtCallbackFunc;
|
|
|
|
// Set a global callback for dynamic MDNS TXT items. The callback function is called
|
|
// every time, a TXT item is needed for one of the installed services.
|
|
bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFunc p_fnCallback);
|
|
// Set a service specific callback for dynamic MDNS TXT items. The callback function
|
|
// is called every time, a TXT item is needed for the given service.
|
|
bool setDynamicServiceTxtCallback(const hMDNSService p_hService,
|
|
MDNSDynamicServiceTxtCallbackFunc p_fnCallback);
|
|
|
|
// Add a (dynamic) MDNS TXT item ('key' = 'value') to the service
|
|
// Dynamic TXT items are removed right after one-time use. So they need to be added
|
|
// every time the value s needed (via callback).
|
|
hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
const char* p_pcValue);
|
|
hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
uint32_t p_u32Value);
|
|
hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
uint16_t p_u16Value);
|
|
hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
uint8_t p_u8Value);
|
|
hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
int32_t p_i32Value);
|
|
hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
int16_t p_i16Value);
|
|
hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService,
|
|
const char* p_pcKey,
|
|
int8_t p_i8Value);
|
|
|
|
// Perform a (static) service query. The function returns after p_u16Timeout milliseconds
|
|
// The answers (the number of received answers is returned) can be retrieved by calling
|
|
// - answerHostname (or hostname)
|
|
// - answerIP (or IP)
|
|
// - answerPort (or port)
|
|
uint32_t queryService(const char* p_pcService,
|
|
const char* p_pcProtocol,
|
|
const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME);
|
|
bool removeQuery(void);
|
|
// for compatibility...
|
|
uint32_t queryService(const String& p_strService,
|
|
const String& p_strProtocol);
|
|
|
|
const char* answerHostname(const uint32_t p_u32AnswerIndex);
|
|
IPAddress answerIP(const uint32_t p_u32AnswerIndex);
|
|
uint16_t answerPort(const uint32_t p_u32AnswerIndex);
|
|
// for compatibility...
|
|
String hostname(const uint32_t p_u32AnswerIndex);
|
|
IPAddress IP(const uint32_t p_u32AnswerIndex);
|
|
uint16_t port(const uint32_t p_u32AnswerIndex);
|
|
|
|
/**
|
|
hMDNSServiceQuery (opaque handle to access dynamic service queries)
|
|
*/
|
|
typedef const void* hMDNSServiceQuery;
|
|
|
|
/**
|
|
enuServiceQueryAnswerType
|
|
*/
|
|
typedef enum _enuServiceQueryAnswerType
|
|
{
|
|
ServiceQueryAnswerType_ServiceDomain = (1 << 0), // Service instance name
|
|
ServiceQueryAnswerType_HostDomainAndPort = (1 << 1), // Host domain and service port
|
|
ServiceQueryAnswerType_Txts = (1 << 2), // TXT items
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
ServiceQueryAnswerType_IP4Address = (1 << 3), // IP4 address
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
ServiceQueryAnswerType_IP6Address = (1 << 4), // IP6 address
|
|
#endif
|
|
} enuServiceQueryAnswerType;
|
|
|
|
enum class AnswerType : uint32_t
|
|
{
|
|
Unknown = 0,
|
|
ServiceDomain = ServiceQueryAnswerType_ServiceDomain,
|
|
HostDomainAndPort = ServiceQueryAnswerType_HostDomainAndPort,
|
|
Txt = ServiceQueryAnswerType_Txts,
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
IP4Address = ServiceQueryAnswerType_IP4Address,
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
IP6Address = ServiceQueryAnswerType_IP6Address,
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
MDNSServiceQueryCallbackFn
|
|
Callback function for received answers for dynamic service queries
|
|
*/
|
|
struct MDNSServiceInfo; // forward declaration
|
|
typedef std::function<void(const MDNSServiceInfo& mdnsServiceInfo,
|
|
AnswerType answerType, // flag for the updated answer item
|
|
bool p_bSetContent // true: Answer component set, false: component deleted
|
|
)> MDNSServiceQueryCallbackFunc;
|
|
|
|
// Install a dynamic service query. For every received answer (part) the given callback
|
|
// function is called. The query will be updated every time, the TTL for an answer
|
|
// has timed-out.
|
|
// The answers can also be retrieved by calling
|
|
// - answerCount
|
|
// - answerServiceDomain
|
|
// - hasAnswerHostDomain/answerHostDomain
|
|
// - hasAnswerIP4Address/answerIP4Address
|
|
// - hasAnswerIP6Address/answerIP6Address
|
|
// - hasAnswerPort/answerPort
|
|
// - hasAnswerTxts/answerTxts
|
|
hMDNSServiceQuery installServiceQuery(const char* p_pcService,
|
|
const char* p_pcProtocol,
|
|
MDNSServiceQueryCallbackFunc p_fnCallback);
|
|
// Remove a dynamic service query
|
|
bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery);
|
|
|
|
uint32_t answerCount(const hMDNSServiceQuery p_hServiceQuery);
|
|
std::vector<MDNSResponder::MDNSServiceInfo> answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery);
|
|
|
|
const char* answerServiceDomain(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
bool hasAnswerHostDomain(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
const char* answerHostDomain(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
bool hasAnswerIP4Address(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
uint32_t answerIP4AddressCount(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
IPAddress answerIP4Address(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex,
|
|
const uint32_t p_u32AddressIndex);
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
bool hasAnswerIP6Address(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
uint32_t answerIP6AddressCount(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
IPAddress answerIP6Address(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex,
|
|
const uint32_t p_u32AddressIndex);
|
|
#endif
|
|
bool hasAnswerPort(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
uint16_t answerPort(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
bool hasAnswerTxts(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
// Get the TXT items as a ';'-separated string
|
|
const char* answerTxts(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
|
|
/**
|
|
MDNSProbeResultCallbackFn
|
|
Callback function for (host and service domain) probe results
|
|
*/
|
|
typedef std::function<void(const char* p_pcDomainName,
|
|
bool p_bProbeResult)> MDNSHostProbeFn;
|
|
|
|
typedef std::function<void(MDNSResponder& resp,
|
|
const char* p_pcDomainName,
|
|
bool p_bProbeResult)> MDNSHostProbeFn1;
|
|
|
|
typedef std::function<void(const char* p_pcServiceName,
|
|
const hMDNSService p_hMDNSService,
|
|
bool p_bProbeResult)> MDNSServiceProbeFn;
|
|
|
|
typedef std::function<void(MDNSResponder& resp,
|
|
const char* p_pcServiceName,
|
|
const hMDNSService p_hMDNSService,
|
|
bool p_bProbeResult)> MDNSServiceProbeFn1;
|
|
|
|
// Set a global callback function for host and service probe results
|
|
// The callback function is called, when the probing for the host domain
|
|
// (or a service domain, which hasn't got a service specific callback)
|
|
// Succeeds or fails.
|
|
// In case of failure, the failed domain name should be changed.
|
|
bool setHostProbeResultCallback(MDNSHostProbeFn p_fnCallback);
|
|
bool setHostProbeResultCallback(MDNSHostProbeFn1 p_fnCallback);
|
|
|
|
// Set a service specific probe result callback
|
|
bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService,
|
|
MDNSServiceProbeFn p_fnCallback);
|
|
bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService,
|
|
MDNSServiceProbeFn1 p_fnCallback);
|
|
|
|
// Application should call this whenever AP is configured/disabled
|
|
bool notifyAPChange(void);
|
|
|
|
// 'update' should be called in every 'loop' to run the MDNS processing
|
|
bool update(void);
|
|
|
|
// 'announce' can be called every time, the configuration of some service
|
|
// changes. Mainly, this would be changed content of TXT items.
|
|
bool announce(void);
|
|
|
|
// Enable OTA update
|
|
hMDNSService enableArduino(uint16_t p_u16Port,
|
|
bool p_bAuthUpload = false);
|
|
|
|
// Domain name helper
|
|
static bool indexDomain(char*& p_rpcDomain,
|
|
const char* p_pcDivider = "-",
|
|
const char* p_pcDefaultDomain = 0);
|
|
|
|
/** STRUCTS **/
|
|
|
|
public:
|
|
/**
|
|
MDNSServiceInfo, used in application callbacks
|
|
*/
|
|
struct MDNSServiceInfo
|
|
{
|
|
MDNSServiceInfo(MDNSResponder& p_pM, MDNSResponder::hMDNSServiceQuery p_hS, uint32_t p_u32A)
|
|
: p_pMDNSResponder(p_pM),
|
|
p_hServiceQuery(p_hS),
|
|
p_u32AnswerIndex(p_u32A)
|
|
{};
|
|
struct CompareKey
|
|
{
|
|
bool operator()(char const *a, char const *b) const
|
|
{
|
|
return strcmp(a, b) < 0;
|
|
}
|
|
};
|
|
using KeyValueMap = std::map<const char*, const char*, CompareKey>;
|
|
protected:
|
|
MDNSResponder& p_pMDNSResponder;
|
|
MDNSResponder::hMDNSServiceQuery p_hServiceQuery;
|
|
uint32_t p_u32AnswerIndex;
|
|
KeyValueMap keyValueMap;
|
|
public:
|
|
const char* serviceDomain()
|
|
{
|
|
return p_pMDNSResponder.answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex);
|
|
};
|
|
bool hostDomainAvailable()
|
|
{
|
|
return (p_pMDNSResponder.hasAnswerHostDomain(p_hServiceQuery, p_u32AnswerIndex));
|
|
}
|
|
const char* hostDomain()
|
|
{
|
|
return (hostDomainAvailable()) ?
|
|
p_pMDNSResponder.answerHostDomain(p_hServiceQuery, p_u32AnswerIndex) : nullptr;
|
|
};
|
|
bool hostPortAvailable()
|
|
{
|
|
return (p_pMDNSResponder.hasAnswerPort(p_hServiceQuery, p_u32AnswerIndex));
|
|
}
|
|
uint16_t hostPort()
|
|
{
|
|
return (hostPortAvailable()) ?
|
|
p_pMDNSResponder.answerPort(p_hServiceQuery, p_u32AnswerIndex) : 0;
|
|
};
|
|
bool IP4AddressAvailable()
|
|
{
|
|
return (p_pMDNSResponder.hasAnswerIP4Address(p_hServiceQuery, p_u32AnswerIndex));
|
|
}
|
|
std::vector<IPAddress> IP4Adresses()
|
|
{
|
|
std::vector<IPAddress> internalIP;
|
|
if (IP4AddressAvailable())
|
|
{
|
|
uint16_t cntIP4Adress = p_pMDNSResponder.answerIP4AddressCount(p_hServiceQuery, p_u32AnswerIndex);
|
|
for (uint32_t u2 = 0; u2 < cntIP4Adress; ++u2)
|
|
{
|
|
internalIP.emplace_back(p_pMDNSResponder.answerIP4Address(p_hServiceQuery, p_u32AnswerIndex, u2));
|
|
}
|
|
}
|
|
return internalIP;
|
|
};
|
|
bool txtAvailable()
|
|
{
|
|
return (p_pMDNSResponder.hasAnswerTxts(p_hServiceQuery, p_u32AnswerIndex));
|
|
}
|
|
const char* strKeyValue()
|
|
{
|
|
return (txtAvailable()) ?
|
|
p_pMDNSResponder.answerTxts(p_hServiceQuery, p_u32AnswerIndex) : nullptr;
|
|
};
|
|
const KeyValueMap& keyValues()
|
|
{
|
|
if (txtAvailable() && keyValueMap.size() == 0)
|
|
{
|
|
for (auto kv = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); kv != nullptr; kv = kv->m_pNext)
|
|
{
|
|
keyValueMap.emplace(std::pair<const char*, const char*>(kv->m_pcKey, kv->m_pcValue));
|
|
}
|
|
}
|
|
return keyValueMap;
|
|
}
|
|
const char* value(const char* key)
|
|
{
|
|
char* result = nullptr;
|
|
|
|
for (stcMDNSServiceTxt* pTxt = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); pTxt; pTxt = pTxt->m_pNext)
|
|
{
|
|
if ((key) &&
|
|
(0 == strcmp(pTxt->m_pcKey, key)))
|
|
{
|
|
result = pTxt->m_pcValue;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
protected:
|
|
|
|
/**
|
|
stcMDNSServiceTxt
|
|
*/
|
|
struct stcMDNSServiceTxt
|
|
{
|
|
stcMDNSServiceTxt* m_pNext;
|
|
char* m_pcKey;
|
|
char* m_pcValue;
|
|
bool m_bTemp;
|
|
|
|
stcMDNSServiceTxt(const char* p_pcKey = 0,
|
|
const char* p_pcValue = 0,
|
|
bool p_bTemp = false);
|
|
stcMDNSServiceTxt(const stcMDNSServiceTxt& p_Other);
|
|
~stcMDNSServiceTxt(void);
|
|
|
|
stcMDNSServiceTxt& operator=(const stcMDNSServiceTxt& p_Other);
|
|
bool clear(void);
|
|
|
|
char* allocKey(size_t p_stLength);
|
|
bool setKey(const char* p_pcKey,
|
|
size_t p_stLength);
|
|
bool setKey(const char* p_pcKey);
|
|
bool releaseKey(void);
|
|
|
|
char* allocValue(size_t p_stLength);
|
|
bool setValue(const char* p_pcValue,
|
|
size_t p_stLength);
|
|
bool setValue(const char* p_pcValue);
|
|
bool releaseValue(void);
|
|
|
|
bool set(const char* p_pcKey,
|
|
const char* p_pcValue,
|
|
bool p_bTemp = false);
|
|
|
|
bool update(const char* p_pcValue);
|
|
|
|
size_t length(void) const;
|
|
};
|
|
|
|
/**
|
|
stcMDNSTxts
|
|
*/
|
|
struct stcMDNSServiceTxts
|
|
{
|
|
stcMDNSServiceTxt* m_pTxts;
|
|
|
|
stcMDNSServiceTxts(void);
|
|
stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other);
|
|
~stcMDNSServiceTxts(void);
|
|
|
|
stcMDNSServiceTxts& operator=(const stcMDNSServiceTxts& p_Other);
|
|
|
|
bool clear(void);
|
|
|
|
bool add(stcMDNSServiceTxt* p_pTxt);
|
|
bool remove(stcMDNSServiceTxt* p_pTxt);
|
|
|
|
bool removeTempTxts(void);
|
|
|
|
stcMDNSServiceTxt* find(const char* p_pcKey);
|
|
const stcMDNSServiceTxt* find(const char* p_pcKey) const;
|
|
stcMDNSServiceTxt* find(const stcMDNSServiceTxt* p_pTxt);
|
|
|
|
uint16_t length(void) const;
|
|
|
|
size_t c_strLength(void) const;
|
|
bool c_str(char* p_pcBuffer);
|
|
|
|
size_t bufferLength(void) const;
|
|
bool buffer(char* p_pcBuffer);
|
|
|
|
bool compare(const stcMDNSServiceTxts& p_Other) const;
|
|
bool operator==(const stcMDNSServiceTxts& p_Other) const;
|
|
bool operator!=(const stcMDNSServiceTxts& p_Other) const;
|
|
};
|
|
|
|
/**
|
|
enuContentFlags
|
|
*/
|
|
typedef enum _enuContentFlags
|
|
{
|
|
// Host
|
|
ContentFlag_A = 0x01,
|
|
ContentFlag_PTR_IP4 = 0x02,
|
|
ContentFlag_PTR_IP6 = 0x04,
|
|
ContentFlag_AAAA = 0x08,
|
|
// Service
|
|
ContentFlag_PTR_TYPE = 0x10,
|
|
ContentFlag_PTR_NAME = 0x20,
|
|
ContentFlag_TXT = 0x40,
|
|
ContentFlag_SRV = 0x80,
|
|
} enuContentFlags;
|
|
|
|
/**
|
|
stcMDNS_MsgHeader
|
|
*/
|
|
struct stcMDNS_MsgHeader
|
|
{
|
|
uint16_t m_u16ID; // Identifier
|
|
bool m_1bQR : 1; // Query/Response flag
|
|
unsigned char m_4bOpcode : 4; // Operation code
|
|
bool m_1bAA : 1; // Authoritative Answer flag
|
|
bool m_1bTC : 1; // Truncation flag
|
|
bool m_1bRD : 1; // Recursion desired
|
|
bool m_1bRA : 1; // Recursion available
|
|
unsigned char m_3bZ : 3; // Zero
|
|
unsigned char m_4bRCode : 4; // Response code
|
|
uint16_t m_u16QDCount; // Question count
|
|
uint16_t m_u16ANCount; // Answer count
|
|
uint16_t m_u16NSCount; // Authority Record count
|
|
uint16_t m_u16ARCount; // Additional Record count
|
|
|
|
stcMDNS_MsgHeader(uint16_t p_u16ID = 0,
|
|
bool p_bQR = false,
|
|
unsigned char p_ucOpcode = 0,
|
|
bool p_bAA = false,
|
|
bool p_bTC = false,
|
|
bool p_bRD = false,
|
|
bool p_bRA = false,
|
|
unsigned char p_ucRCode = 0,
|
|
uint16_t p_u16QDCount = 0,
|
|
uint16_t p_u16ANCount = 0,
|
|
uint16_t p_u16NSCount = 0,
|
|
uint16_t p_u16ARCount = 0);
|
|
};
|
|
|
|
/**
|
|
stcMDNS_RRDomain
|
|
*/
|
|
struct stcMDNS_RRDomain
|
|
{
|
|
char m_acName[MDNS_DOMAIN_MAXLENGTH]; // Encoded domain name
|
|
uint16_t m_u16NameLength; // Length (incl. '\0')
|
|
|
|
stcMDNS_RRDomain(void);
|
|
stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other);
|
|
|
|
stcMDNS_RRDomain& operator=(const stcMDNS_RRDomain& p_Other);
|
|
|
|
bool clear(void);
|
|
|
|
bool addLabel(const char* p_pcLabel,
|
|
bool p_bPrependUnderline = false);
|
|
|
|
bool compare(const stcMDNS_RRDomain& p_Other) const;
|
|
bool operator==(const stcMDNS_RRDomain& p_Other) const;
|
|
bool operator!=(const stcMDNS_RRDomain& p_Other) const;
|
|
bool operator>(const stcMDNS_RRDomain& p_Other) const;
|
|
|
|
size_t c_strLength(void) const;
|
|
bool c_str(char* p_pcBuffer);
|
|
};
|
|
|
|
/**
|
|
stcMDNS_RRAttributes
|
|
*/
|
|
struct stcMDNS_RRAttributes
|
|
{
|
|
uint16_t m_u16Type; // Type
|
|
uint16_t m_u16Class; // Class, nearly always 'IN'
|
|
|
|
stcMDNS_RRAttributes(uint16_t p_u16Type = 0,
|
|
uint16_t p_u16Class = 1 /*DNS_RRCLASS_IN Internet*/);
|
|
stcMDNS_RRAttributes(const stcMDNS_RRAttributes& p_Other);
|
|
|
|
stcMDNS_RRAttributes& operator=(const stcMDNS_RRAttributes& p_Other);
|
|
};
|
|
|
|
/**
|
|
stcMDNS_RRHeader
|
|
*/
|
|
struct stcMDNS_RRHeader
|
|
{
|
|
stcMDNS_RRDomain m_Domain;
|
|
stcMDNS_RRAttributes m_Attributes;
|
|
|
|
stcMDNS_RRHeader(void);
|
|
stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other);
|
|
|
|
stcMDNS_RRHeader& operator=(const stcMDNS_RRHeader& p_Other);
|
|
|
|
bool clear(void);
|
|
};
|
|
|
|
/**
|
|
stcMDNS_RRQuestion
|
|
*/
|
|
struct stcMDNS_RRQuestion
|
|
{
|
|
stcMDNS_RRQuestion* m_pNext;
|
|
stcMDNS_RRHeader m_Header;
|
|
bool m_bUnicast; // Unicast reply requested
|
|
|
|
stcMDNS_RRQuestion(void);
|
|
};
|
|
|
|
/**
|
|
enuAnswerType
|
|
*/
|
|
typedef enum _enuAnswerType
|
|
{
|
|
AnswerType_A,
|
|
AnswerType_PTR,
|
|
AnswerType_TXT,
|
|
AnswerType_AAAA,
|
|
AnswerType_SRV,
|
|
AnswerType_Generic
|
|
} enuAnswerType;
|
|
|
|
/**
|
|
stcMDNS_RRAnswer
|
|
*/
|
|
struct stcMDNS_RRAnswer
|
|
{
|
|
stcMDNS_RRAnswer* m_pNext;
|
|
const enuAnswerType m_AnswerType;
|
|
stcMDNS_RRHeader m_Header;
|
|
bool m_bCacheFlush; // Cache flush command bit
|
|
uint32_t m_u32TTL; // Validity time in seconds
|
|
|
|
virtual ~stcMDNS_RRAnswer(void);
|
|
|
|
enuAnswerType answerType(void) const;
|
|
|
|
bool clear(void);
|
|
|
|
protected:
|
|
stcMDNS_RRAnswer(enuAnswerType p_AnswerType,
|
|
const stcMDNS_RRHeader& p_Header,
|
|
uint32_t p_u32TTL);
|
|
};
|
|
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
/**
|
|
stcMDNS_RRAnswerA
|
|
*/
|
|
struct stcMDNS_RRAnswerA : public stcMDNS_RRAnswer
|
|
{
|
|
IPAddress m_IPAddress;
|
|
|
|
stcMDNS_RRAnswerA(const stcMDNS_RRHeader& p_Header,
|
|
uint32_t p_u32TTL);
|
|
~stcMDNS_RRAnswerA(void);
|
|
|
|
bool clear(void);
|
|
};
|
|
#endif
|
|
|
|
/**
|
|
stcMDNS_RRAnswerPTR
|
|
*/
|
|
struct stcMDNS_RRAnswerPTR : public stcMDNS_RRAnswer
|
|
{
|
|
stcMDNS_RRDomain m_PTRDomain;
|
|
|
|
stcMDNS_RRAnswerPTR(const stcMDNS_RRHeader& p_Header,
|
|
uint32_t p_u32TTL);
|
|
~stcMDNS_RRAnswerPTR(void);
|
|
|
|
bool clear(void);
|
|
};
|
|
|
|
/**
|
|
stcMDNS_RRAnswerTXT
|
|
*/
|
|
struct stcMDNS_RRAnswerTXT : public stcMDNS_RRAnswer
|
|
{
|
|
stcMDNSServiceTxts m_Txts;
|
|
|
|
stcMDNS_RRAnswerTXT(const stcMDNS_RRHeader& p_Header,
|
|
uint32_t p_u32TTL);
|
|
~stcMDNS_RRAnswerTXT(void);
|
|
|
|
bool clear(void);
|
|
};
|
|
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
/**
|
|
stcMDNS_RRAnswerAAAA
|
|
*/
|
|
struct stcMDNS_RRAnswerAAAA : public stcMDNS_RRAnswer
|
|
{
|
|
//TODO: IP6Address m_IPAddress;
|
|
|
|
stcMDNS_RRAnswerAAAA(const stcMDNS_RRHeader& p_Header,
|
|
uint32_t p_u32TTL);
|
|
~stcMDNS_RRAnswerAAAA(void);
|
|
|
|
bool clear(void);
|
|
};
|
|
#endif
|
|
|
|
/**
|
|
stcMDNS_RRAnswerSRV
|
|
*/
|
|
struct stcMDNS_RRAnswerSRV : public stcMDNS_RRAnswer
|
|
{
|
|
uint16_t m_u16Priority;
|
|
uint16_t m_u16Weight;
|
|
uint16_t m_u16Port;
|
|
stcMDNS_RRDomain m_SRVDomain;
|
|
|
|
stcMDNS_RRAnswerSRV(const stcMDNS_RRHeader& p_Header,
|
|
uint32_t p_u32TTL);
|
|
~stcMDNS_RRAnswerSRV(void);
|
|
|
|
bool clear(void);
|
|
};
|
|
|
|
/**
|
|
stcMDNS_RRAnswerGeneric
|
|
*/
|
|
struct stcMDNS_RRAnswerGeneric : public stcMDNS_RRAnswer
|
|
{
|
|
uint16_t m_u16RDLength; // Length of variable answer
|
|
uint8_t* m_pu8RDData; // Offset of start of variable answer in packet
|
|
|
|
stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header,
|
|
uint32_t p_u32TTL);
|
|
~stcMDNS_RRAnswerGeneric(void);
|
|
|
|
bool clear(void);
|
|
};
|
|
|
|
|
|
/**
|
|
enuProbingStatus
|
|
*/
|
|
typedef enum _enuProbingStatus
|
|
{
|
|
ProbingStatus_WaitingForData,
|
|
ProbingStatus_ReadyToStart,
|
|
ProbingStatus_InProgress,
|
|
ProbingStatus_Done
|
|
} enuProbingStatus;
|
|
|
|
/**
|
|
stcProbeInformation
|
|
*/
|
|
struct stcProbeInformation
|
|
{
|
|
enuProbingStatus m_ProbingStatus;
|
|
uint8_t m_u8SentCount; // Used for probes and announcements
|
|
esp8266::polledTimeout::oneShotMs m_Timeout; // Used for probes and announcements
|
|
//clsMDNSTimeFlag m_TimeFlag; // Used for probes and announcements
|
|
bool m_bConflict;
|
|
bool m_bTiebreakNeeded;
|
|
MDNSHostProbeFn m_fnHostProbeResultCallback;
|
|
MDNSServiceProbeFn m_fnServiceProbeResultCallback;
|
|
|
|
stcProbeInformation(void);
|
|
|
|
bool clear(bool p_bClearUserdata = false);
|
|
};
|
|
|
|
|
|
/**
|
|
stcMDNSService
|
|
*/
|
|
struct stcMDNSService
|
|
{
|
|
stcMDNSService* m_pNext;
|
|
char* m_pcName;
|
|
bool m_bAutoName; // Name was set automatically to hostname (if no name was supplied)
|
|
char* m_pcService;
|
|
char* m_pcProtocol;
|
|
uint16_t m_u16Port;
|
|
uint8_t m_u8ReplyMask;
|
|
stcMDNSServiceTxts m_Txts;
|
|
MDNSDynamicServiceTxtCallbackFunc m_fnTxtCallback;
|
|
stcProbeInformation m_ProbeInformation;
|
|
|
|
stcMDNSService(const char* p_pcName = 0,
|
|
const char* p_pcService = 0,
|
|
const char* p_pcProtocol = 0);
|
|
~stcMDNSService(void);
|
|
|
|
bool setName(const char* p_pcName);
|
|
bool releaseName(void);
|
|
|
|
bool setService(const char* p_pcService);
|
|
bool releaseService(void);
|
|
|
|
bool setProtocol(const char* p_pcProtocol);
|
|
bool releaseProtocol(void);
|
|
};
|
|
|
|
/**
|
|
stcMDNSServiceQuery
|
|
*/
|
|
struct stcMDNSServiceQuery
|
|
{
|
|
/**
|
|
stcAnswer
|
|
*/
|
|
struct stcAnswer
|
|
{
|
|
/**
|
|
stcTTL
|
|
*/
|
|
struct stcTTL
|
|
{
|
|
/**
|
|
timeoutLevel_t
|
|
*/
|
|
typedef uint8_t timeoutLevel_t;
|
|
/**
|
|
TIMEOUTLEVELs
|
|
*/
|
|
const timeoutLevel_t TIMEOUTLEVEL_UNSET = 0;
|
|
const timeoutLevel_t TIMEOUTLEVEL_BASE = 80;
|
|
const timeoutLevel_t TIMEOUTLEVEL_INTERVAL = 5;
|
|
const timeoutLevel_t TIMEOUTLEVEL_FINAL = 100;
|
|
|
|
uint32_t m_u32TTL;
|
|
esp8266::polledTimeout::oneShotMs m_TTLTimeout;
|
|
timeoutLevel_t m_timeoutLevel;
|
|
|
|
stcTTL(void);
|
|
bool set(uint32_t p_u32TTL);
|
|
|
|
bool flagged(void);
|
|
bool restart(void);
|
|
|
|
bool prepareDeletion(void);
|
|
bool finalTimeoutLevel(void) const;
|
|
|
|
unsigned long timeout(void) const;
|
|
};
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
/**
|
|
stcIP4Address
|
|
*/
|
|
struct stcIP4Address
|
|
{
|
|
stcIP4Address* m_pNext;
|
|
IPAddress m_IPAddress;
|
|
stcTTL m_TTL;
|
|
|
|
stcIP4Address(IPAddress p_IPAddress,
|
|
uint32_t p_u32TTL = 0);
|
|
};
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
/**
|
|
stcIP6Address
|
|
*/
|
|
struct stcIP6Address
|
|
{
|
|
stcIP6Address* m_pNext;
|
|
IP6Address m_IPAddress;
|
|
stcTTL m_TTL;
|
|
|
|
stcIP6Address(IPAddress p_IPAddress,
|
|
uint32_t p_u32TTL = 0);
|
|
};
|
|
#endif
|
|
|
|
stcAnswer* m_pNext;
|
|
// The service domain is the first 'answer' (from PTR answer, using service and protocol) to be set
|
|
// Defines the key for additional answer, like host domain, etc.
|
|
stcMDNS_RRDomain m_ServiceDomain; // 1. level answer (PTR), eg. MyESP._http._tcp.local
|
|
char* m_pcServiceDomain;
|
|
stcTTL m_TTLServiceDomain;
|
|
stcMDNS_RRDomain m_HostDomain; // 2. level answer (SRV, using service domain), eg. esp8266.local
|
|
char* m_pcHostDomain;
|
|
uint16_t m_u16Port; // 2. level answer (SRV, using service domain), eg. 5000
|
|
stcTTL m_TTLHostDomainAndPort;
|
|
stcMDNSServiceTxts m_Txts; // 2. level answer (TXT, using service domain), eg. c#=1
|
|
char* m_pcTxts;
|
|
stcTTL m_TTLTxts;
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
stcIP4Address* m_pIP4Addresses; // 3. level answer (A, using host domain), eg. 123.456.789.012
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
stcIP6Address* m_pIP6Addresses; // 3. level answer (AAAA, using host domain), eg. 1234::09
|
|
#endif
|
|
uint32_t m_u32ContentFlags;
|
|
|
|
stcAnswer(void);
|
|
~stcAnswer(void);
|
|
|
|
bool clear(void);
|
|
|
|
char* allocServiceDomain(size_t p_stLength);
|
|
bool releaseServiceDomain(void);
|
|
|
|
char* allocHostDomain(size_t p_stLength);
|
|
bool releaseHostDomain(void);
|
|
|
|
char* allocTxts(size_t p_stLength);
|
|
bool releaseTxts(void);
|
|
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
bool releaseIP4Addresses(void);
|
|
bool addIP4Address(stcIP4Address* p_pIP4Address);
|
|
bool removeIP4Address(stcIP4Address* p_pIP4Address);
|
|
const stcIP4Address* findIP4Address(const IPAddress& p_IPAddress) const;
|
|
stcIP4Address* findIP4Address(const IPAddress& p_IPAddress);
|
|
uint32_t IP4AddressCount(void) const;
|
|
const stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index) const;
|
|
stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index);
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
bool releaseIP6Addresses(void);
|
|
bool addIP6Address(stcIP6Address* p_pIP6Address);
|
|
bool removeIP6Address(stcIP6Address* p_pIP6Address);
|
|
const stcIP6Address* findIP6Address(const IPAddress& p_IPAddress) const;
|
|
stcIP6Address* findIP6Address(const IPAddress& p_IPAddress);
|
|
uint32_t IP6AddressCount(void) const;
|
|
const stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index) const;
|
|
stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index);
|
|
#endif
|
|
};
|
|
|
|
stcMDNSServiceQuery* m_pNext;
|
|
stcMDNS_RRDomain m_ServiceTypeDomain; // eg. _http._tcp.local
|
|
MDNSServiceQueryCallbackFunc m_fnCallback;
|
|
bool m_bLegacyQuery;
|
|
uint8_t m_u8SentCount;
|
|
esp8266::polledTimeout::oneShotMs m_ResendTimeout;
|
|
bool m_bAwaitingAnswers;
|
|
stcAnswer* m_pAnswers;
|
|
|
|
stcMDNSServiceQuery(void);
|
|
~stcMDNSServiceQuery(void);
|
|
|
|
bool clear(void);
|
|
|
|
uint32_t answerCount(void) const;
|
|
const stcAnswer* answerAtIndex(uint32_t p_u32Index) const;
|
|
stcAnswer* answerAtIndex(uint32_t p_u32Index);
|
|
uint32_t indexOfAnswer(const stcAnswer* p_pAnswer) const;
|
|
|
|
bool addAnswer(stcAnswer* p_pAnswer);
|
|
bool removeAnswer(stcAnswer* p_pAnswer);
|
|
|
|
stcAnswer* findAnswerForServiceDomain(const stcMDNS_RRDomain& p_ServiceDomain);
|
|
stcAnswer* findAnswerForHostDomain(const stcMDNS_RRDomain& p_HostDomain);
|
|
};
|
|
|
|
/**
|
|
stcMDNSSendParameter
|
|
*/
|
|
struct stcMDNSSendParameter
|
|
{
|
|
protected:
|
|
/**
|
|
stcDomainCacheItem
|
|
*/
|
|
struct stcDomainCacheItem
|
|
{
|
|
stcDomainCacheItem* m_pNext;
|
|
const void* m_pHostnameOrService; // Opaque id for host or service domain (pointer)
|
|
bool m_bAdditionalData; // Opaque flag for special info (service domain included)
|
|
uint16_t m_u16Offset; // Offset in UDP output buffer
|
|
|
|
stcDomainCacheItem(const void* p_pHostnameOrService,
|
|
bool p_bAdditionalData,
|
|
uint32_t p_u16Offset);
|
|
};
|
|
|
|
public:
|
|
uint16_t m_u16ID; // Query ID (used only in lagacy queries)
|
|
stcMDNS_RRQuestion* m_pQuestions; // A list of queries
|
|
uint8_t m_u8HostReplyMask; // Flags for reply components/answers
|
|
bool m_bLegacyQuery; // Flag: Legacy query
|
|
bool m_bResponse; // Flag: Response to a query
|
|
bool m_bAuthorative; // Flag: Authorative (owner) response
|
|
bool m_bCacheFlush; // Flag: Clients should flush their caches
|
|
bool m_bUnicast; // Flag: Unicast response
|
|
bool m_bUnannounce; // Flag: Unannounce service
|
|
uint16_t m_u16Offset; // Current offset in UDP write buffer (mainly for domain cache)
|
|
stcDomainCacheItem* m_pDomainCacheItems; // Cached host and service domains
|
|
|
|
stcMDNSSendParameter(void);
|
|
~stcMDNSSendParameter(void);
|
|
|
|
bool clear(void);
|
|
|
|
bool shiftOffset(uint16_t p_u16Shift);
|
|
|
|
bool addDomainCacheItem(const void* p_pHostnameOrService,
|
|
bool p_bAdditionalData,
|
|
uint16_t p_u16Offset);
|
|
uint16_t findCachedDomainOffset(const void* p_pHostnameOrService,
|
|
bool p_bAdditionalData) const;
|
|
};
|
|
|
|
// Instance variables
|
|
stcMDNSService* m_pServices;
|
|
UdpContext* m_pUDPContext;
|
|
char* m_pcHostname;
|
|
stcMDNSServiceQuery* m_pServiceQueries;
|
|
WiFiEventHandler m_DisconnectedHandler;
|
|
WiFiEventHandler m_GotIPHandler;
|
|
MDNSDynamicServiceTxtCallbackFunc m_fnServiceTxtCallback;
|
|
bool m_bPassivModeEnabled;
|
|
stcProbeInformation m_HostProbeInformation;
|
|
const netif* m_netif; // network interface to run on
|
|
|
|
/** CONTROL **/
|
|
/* MAINTENANCE */
|
|
bool _process(bool p_bUserContext);
|
|
bool _restart(void);
|
|
|
|
/* RECEIVING */
|
|
bool _parseMessage(void);
|
|
bool _parseQuery(const stcMDNS_MsgHeader& p_Header);
|
|
|
|
bool _parseResponse(const stcMDNS_MsgHeader& p_Header);
|
|
bool _processAnswers(const stcMDNS_RRAnswer* p_pPTRAnswers);
|
|
bool _processPTRAnswer(const stcMDNS_RRAnswerPTR* p_pPTRAnswer,
|
|
bool& p_rbFoundNewKeyAnswer);
|
|
bool _processSRVAnswer(const stcMDNS_RRAnswerSRV* p_pSRVAnswer,
|
|
bool& p_rbFoundNewKeyAnswer);
|
|
bool _processTXTAnswer(const stcMDNS_RRAnswerTXT* p_pTXTAnswer);
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
bool _processAAnswer(const stcMDNS_RRAnswerA* p_pAAnswer);
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
bool _processAAAAAnswer(const stcMDNS_RRAnswerAAAA* p_pAAAAAnswer);
|
|
#endif
|
|
|
|
/* PROBING */
|
|
bool _updateProbeStatus(void);
|
|
bool _resetProbeStatus(bool p_bRestart = true);
|
|
bool _hasProbesWaitingForAnswers(void) const;
|
|
bool _sendHostProbe(void);
|
|
bool _sendServiceProbe(stcMDNSService& p_rService);
|
|
bool _cancelProbingForHost(void);
|
|
bool _cancelProbingForService(stcMDNSService& p_rService);
|
|
|
|
/* ANNOUNCE */
|
|
bool _announce(bool p_bAnnounce,
|
|
bool p_bIncludeServices);
|
|
bool _announceService(stcMDNSService& p_rService,
|
|
bool p_bAnnounce = true);
|
|
|
|
/* SERVICE QUERY CACHE */
|
|
bool _hasServiceQueriesWaitingForAnswers(void) const;
|
|
bool _checkServiceQueryCache(void);
|
|
|
|
/** TRANSFER **/
|
|
/* SENDING */
|
|
bool _sendMDNSMessage(stcMDNSSendParameter& p_SendParameter);
|
|
bool _sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter);
|
|
bool _prepareMDNSMessage(stcMDNSSendParameter& p_SendParameter,
|
|
IPAddress p_IPAddress);
|
|
bool _sendMDNSServiceQuery(const stcMDNSServiceQuery& p_ServiceQuery);
|
|
bool _sendMDNSQuery(const stcMDNS_RRDomain& p_QueryDomain,
|
|
uint16_t p_u16QueryType,
|
|
stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers = 0);
|
|
|
|
const IPAddress _getResponseMulticastInterface() const
|
|
{
|
|
return IPAddress(m_netif->ip_addr);
|
|
}
|
|
|
|
uint8_t _replyMaskForHost(const stcMDNS_RRHeader& p_RRHeader,
|
|
bool* p_pbFullNameMatch = 0) const;
|
|
uint8_t _replyMaskForService(const stcMDNS_RRHeader& p_RRHeader,
|
|
const stcMDNSService& p_Service,
|
|
bool* p_pbFullNameMatch = 0) const;
|
|
|
|
/* RESOURCE RECORD */
|
|
bool _readRRQuestion(stcMDNS_RRQuestion& p_rQuestion);
|
|
bool _readRRAnswer(stcMDNS_RRAnswer*& p_rpAnswer);
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
bool _readRRAnswerA(stcMDNS_RRAnswerA& p_rRRAnswerA,
|
|
uint16_t p_u16RDLength);
|
|
#endif
|
|
bool _readRRAnswerPTR(stcMDNS_RRAnswerPTR& p_rRRAnswerPTR,
|
|
uint16_t p_u16RDLength);
|
|
bool _readRRAnswerTXT(stcMDNS_RRAnswerTXT& p_rRRAnswerTXT,
|
|
uint16_t p_u16RDLength);
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
bool _readRRAnswerAAAA(stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA,
|
|
uint16_t p_u16RDLength);
|
|
#endif
|
|
bool _readRRAnswerSRV(stcMDNS_RRAnswerSRV& p_rRRAnswerSRV,
|
|
uint16_t p_u16RDLength);
|
|
bool _readRRAnswerGeneric(stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric,
|
|
uint16_t p_u16RDLength);
|
|
|
|
bool _readRRHeader(stcMDNS_RRHeader& p_rHeader);
|
|
bool _readRRDomain(stcMDNS_RRDomain& p_rRRDomain);
|
|
bool _readRRDomain_Loop(stcMDNS_RRDomain& p_rRRDomain,
|
|
uint8_t p_u8Depth);
|
|
bool _readRRAttributes(stcMDNS_RRAttributes& p_rAttributes);
|
|
|
|
/* DOMAIN NAMES */
|
|
bool _buildDomainForHost(const char* p_pcHostname,
|
|
stcMDNS_RRDomain& p_rHostDomain) const;
|
|
bool _buildDomainForDNSSD(stcMDNS_RRDomain& p_rDNSSDDomain) const;
|
|
bool _buildDomainForService(const stcMDNSService& p_Service,
|
|
bool p_bIncludeName,
|
|
stcMDNS_RRDomain& p_rServiceDomain) const;
|
|
bool _buildDomainForService(const char* p_pcService,
|
|
const char* p_pcProtocol,
|
|
stcMDNS_RRDomain& p_rServiceDomain) const;
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
bool _buildDomainForReverseIP4(IPAddress p_IP4Address,
|
|
stcMDNS_RRDomain& p_rReverseIP4Domain) const;
|
|
#endif
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
bool _buildDomainForReverseIP6(IPAddress p_IP4Address,
|
|
stcMDNS_RRDomain& p_rReverseIP6Domain) const;
|
|
#endif
|
|
|
|
/* UDP */
|
|
bool _udpReadBuffer(unsigned char* p_pBuffer,
|
|
size_t p_stLength);
|
|
bool _udpRead8(uint8_t& p_ru8Value);
|
|
bool _udpRead16(uint16_t& p_ru16Value);
|
|
bool _udpRead32(uint32_t& p_ru32Value);
|
|
|
|
bool _udpAppendBuffer(const unsigned char* p_pcBuffer,
|
|
size_t p_stLength);
|
|
bool _udpAppend8(uint8_t p_u8Value);
|
|
bool _udpAppend16(uint16_t p_u16Value);
|
|
bool _udpAppend32(uint32_t p_u32Value);
|
|
|
|
#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER
|
|
bool _udpDump(bool p_bMovePointer = false);
|
|
bool _udpDump(unsigned p_uOffset,
|
|
unsigned p_uLength);
|
|
#endif
|
|
|
|
/* READ/WRITE MDNS STRUCTS */
|
|
bool _readMDNSMsgHeader(stcMDNS_MsgHeader& p_rMsgHeader);
|
|
|
|
bool _write8(uint8_t p_u8Value,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _write16(uint16_t p_u16Value,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _write32(uint32_t p_u32Value,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
|
|
bool _writeMDNSMsgHeader(const stcMDNS_MsgHeader& p_MsgHeader,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _writeMDNSRRAttributes(const stcMDNS_RRAttributes& p_Attributes,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _writeMDNSRRDomain(const stcMDNS_RRDomain& p_Domain,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _writeMDNSHostDomain(const char* m_pcHostname,
|
|
bool p_bPrependRDLength,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _writeMDNSServiceDomain(const stcMDNSService& p_Service,
|
|
bool p_bIncludeName,
|
|
bool p_bPrependRDLength,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
|
|
bool _writeMDNSQuestion(stcMDNS_RRQuestion& p_Question,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
|
|
#ifdef MDNS_IP4_SUPPORT
|
|
bool _writeMDNSAnswer_A(IPAddress p_IPAddress,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
#endif
|
|
bool _writeMDNSAnswer_PTR_TYPE(stcMDNSService& p_rService,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _writeMDNSAnswer_PTR_NAME(stcMDNSService& p_rService,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _writeMDNSAnswer_TXT(stcMDNSService& p_rService,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
#ifdef MDNS_IP6_SUPPORT
|
|
bool _writeMDNSAnswer_AAAA(IPAddress p_IPAddress,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
bool _writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
#endif
|
|
bool _writeMDNSAnswer_SRV(stcMDNSService& p_rService,
|
|
stcMDNSSendParameter& p_rSendParameter);
|
|
|
|
/** HELPERS **/
|
|
/* UDP CONTEXT */
|
|
bool _callProcess(void);
|
|
bool _allocUDPContext(void);
|
|
bool _releaseUDPContext(void);
|
|
|
|
/* SERVICE QUERY */
|
|
stcMDNSServiceQuery* _allocServiceQuery(void);
|
|
bool _removeServiceQuery(stcMDNSServiceQuery* p_pServiceQuery);
|
|
bool _removeLegacyServiceQuery(void);
|
|
stcMDNSServiceQuery* _findServiceQuery(hMDNSServiceQuery p_hServiceQuery);
|
|
stcMDNSServiceQuery* _findLegacyServiceQuery(void);
|
|
bool _releaseServiceQueries(void);
|
|
stcMDNSServiceQuery* _findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceDomain,
|
|
const stcMDNSServiceQuery* p_pPrevServiceQuery);
|
|
|
|
/* HOSTNAME */
|
|
bool _setHostname(const char* p_pcHostname);
|
|
bool _releaseHostname(void);
|
|
|
|
/* SERVICE */
|
|
stcMDNSService* _allocService(const char* p_pcName,
|
|
const char* p_pcService,
|
|
const char* p_pcProtocol,
|
|
uint16_t p_u16Port);
|
|
bool _releaseService(stcMDNSService* p_pService);
|
|
bool _releaseServices(void);
|
|
|
|
stcMDNSService* _findService(const char* p_pcName,
|
|
const char* p_pcService,
|
|
const char* p_pcProtocol);
|
|
stcMDNSService* _findService(const hMDNSService p_hService);
|
|
|
|
size_t _countServices(void) const;
|
|
|
|
/* SERVICE TXT */
|
|
stcMDNSServiceTxt* _allocServiceTxt(stcMDNSService* p_pService,
|
|
const char* p_pcKey,
|
|
const char* p_pcValue,
|
|
bool p_bTemp);
|
|
bool _releaseServiceTxt(stcMDNSService* p_pService,
|
|
stcMDNSServiceTxt* p_pTxt);
|
|
stcMDNSServiceTxt* _updateServiceTxt(stcMDNSService* p_pService,
|
|
stcMDNSServiceTxt* p_pTxt,
|
|
const char* p_pcValue,
|
|
bool p_bTemp);
|
|
|
|
stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService,
|
|
const char* p_pcKey);
|
|
stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService,
|
|
const hMDNSTxt p_hTxt);
|
|
|
|
stcMDNSServiceTxt* _addServiceTxt(stcMDNSService* p_pService,
|
|
const char* p_pcKey,
|
|
const char* p_pcValue,
|
|
bool p_bTemp);
|
|
|
|
stcMDNSServiceTxt* _answerKeyValue(const hMDNSServiceQuery p_hServiceQuery,
|
|
const uint32_t p_u32AnswerIndex);
|
|
|
|
bool _collectServiceTxts(stcMDNSService& p_rService);
|
|
bool _releaseTempServiceTxts(stcMDNSService& p_rService);
|
|
const stcMDNSServiceTxt* _serviceTxts(const char* p_pcName,
|
|
const char* p_pcService,
|
|
const char* p_pcProtocol);
|
|
|
|
/* MISC */
|
|
#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER
|
|
bool _printRRDomain(const stcMDNS_RRDomain& p_rRRDomain) const;
|
|
bool _printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const;
|
|
#endif
|
|
};
|
|
|
|
}// namespace MDNSImplementation
|
|
|
|
}// namespace esp8266
|
|
|
|
#endif // MDNS_H
|