1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

LEAmDNS - Multicast DNS Responder (#5442)

* LEAmDNS Responder (II)

Created a new branch to solve commit conflicts with recent changes to ESP8266mDNSResponder.cpp by d-a-v.

* Removed millis() roll-over issues

* fix LEA-mDNS

* astyle on lea-mdns examples

* add compatibility with lwIP-v1

* ditto

* use strncasecmp instead of lwip's strnicmp from lwIP-v2 (thanks @devyte)

* ditto

* fixes

* Update mDNS_Clock.ino

unindent

* Update mDNS_ServiceMonitor.ino

unindent

* Update LEAmDNS.h

Add setInstanceName() forwarder for compat

* Disable DEBUG_ESP_MDNS_RESPONDER by default

* [Fixed] Debug output line

DEBUG_OUTPUT needs to go inside DEBUG_EX_ function otherwise throw error if DEBUG_ESP_MDNS_RESPONDER is not defined
This commit is contained in:
LaborEtArs 2018-12-05 20:51:01 +01:00 committed by Develo
parent e043806065
commit 58a044b254
17 changed files with 9663 additions and 7 deletions

View File

@ -0,0 +1,334 @@
/*
ESP8266 mDNS responder clock
This example demonstrates two features of the LEA MDNSResponder:
1. The host and service domain negotiation process that ensures
the uniqueness of the finally choosen host and service domain name.
2. The dynamic MDNS service TXT feature
A 'clock' service in announced via the MDNS responder and the current
time is set as a TXT item (eg. 'curtime=Mon Oct 15 19:54:35 2018').
The time value is updated every second!
The ESP is initially announced to clients as 'esp8266.local', if this host domain
is already used in the local network, another host domain is negociated. Keep an
eye to the serial output to learn the final host domain for the clock service.
The service itself is is announced as 'host domain'._espclk._tcp.local.
As the service uses port 80, a very simple HTTP server is installed also to deliver
a small web page containing a greeting and the current time (not updated).
The web server code is taken nearly 1:1 from the 'mDNS_Web_Server.ino' example.
Point your browser to 'host domain'.local to see this web page.
Instructions:
- Update WiFi SSID and password as necessary.
- Flash the sketch to the ESP8266 board
- Install host software:
- For Linux, install Avahi (http://avahi.org/).
- For Windows, install Bonjour (http://www.apple.com/support/bonjour/).
- For Mac OSX and iOS support is built in through Bonjour already.
- Use a MDNS/Bonjour browser like 'Discovery' to find the clock service in your local
network and see the current time updates.
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <time.h>
/*
Include the MDNSResponder (the library needs to be included also)
As LEA MDNSResponder is experimantal in the ESP8266 environment currently, the
legacy MDNSResponder is defaulted in th include file.
There are two ways to access LEA MDNSResponder:
1. Prepend every declaration and call to global declarations or functions with the namespace, like:
'LEAmDNS::MDNSResponder::hMDNSService hMDNSService;'
This way is used in the example. But be careful, if the namespace declaration is missing
somewhere, the call might go to the legacy implementation...
2. Open 'ESP8266mDNS.h' and set LEAmDNS to default.
*/
#include <ESP8266mDNS.h>
#include <LEATimeFlag.h>
/*
Global defines and vars
*/
#define TIMEZONE_OFFSET 1 // CET
#define DST_OFFSET 1 // CEST
#define UPDATE_CYCLE (1 * 1000) // every second
#define SERVICE_PORT 80 // HTTP port
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
char* pcHostDomain = 0; // Negociated host domain
bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain
LEAmDNS::MDNSResponder::hMDNSService hMDNSService = 0; // The handle of the clock service in the MDNS responder
// TCP server at port 'SERVICE_PORT' will respond to HTTP requests
WiFiServer server(SERVICE_PORT);
/*
getTimeString
*/
const char* getTimeString(void) {
static char acTimeString[32];
time_t now = time(nullptr);
ctime_r(&now, acTimeString);
size_t stLength;
while (((stLength = os_strlen(acTimeString))) &&
('\n' == acTimeString[stLength - 1])) {
acTimeString[stLength - 1] = 0; // Remove trailing line break...
}
return acTimeString;
}
/*
setClock
Set time via NTP
*/
void setClock(void) {
configTime((TIMEZONE_OFFSET * 3600), (DST_OFFSET * 3600), "pool.ntp.org", "time.nist.gov", "time.windows.com");
Serial.print("Waiting for NTP time sync: ");
time_t now = time(nullptr); // Secs since 01.01.1970 (when uninitalized starts with (8 * 3600 = 28800)
while (now < 8 * 3600 * 2) { // Wait for realistic value
delay(500);
Serial.print(".");
now = time(nullptr);
}
Serial.println("");
Serial.printf("Current time: %s\n", getTimeString());
}
/*
setStationHostname
*/
bool setStationHostname(const char* p_pcHostname) {
if (p_pcHostname) {
WiFi.hostname(p_pcHostname);
Serial.printf("setDeviceHostname: Station hostname is set to '%s'\n", p_pcHostname);
}
return true;
}
/*
MDNSDynamicServiceTxtCallback
Add a dynamic MDNS TXT item 'ct' to the clock service.
The callback function is called every time, the TXT items for the clock service
are needed.
This can be triggered by calling MDNS.announce().
*/
bool MDNSDynamicServiceTxtCallback(LEAmDNS::MDNSResponder* p_pMDNSResponder,
const LEAmDNS::MDNSResponder::hMDNSService p_hService,
void* p_pUserdata) {
Serial.println("MDNSDynamicServiceTxtCallback");
(void) p_pUserdata;
if ((p_pMDNSResponder) &&
(hMDNSService == p_hService)) {
Serial.printf("Updating curtime TXT item to: %s\n", getTimeString());
p_pMDNSResponder->addDynamicServiceTxt(p_hService, "curtime", getTimeString());
}
return true;
}
/*
MDNSProbeResultCallback
Probe result callback for the host domain.
If the domain is free, the host domain is set and the clock service is
added.
If the domain is already used, a new name is created and the probing is
restarted via p_pMDNSResponder->setHostname().
*/
bool MDNSProbeResultCallback(LEAmDNS::MDNSResponder* p_pMDNSResponder,
const char* p_pcDomainName,
const LEAmDNS::MDNSResponder::hMDNSService p_hService,
bool p_bProbeResult,
void* p_pUserdata) {
Serial.println("MDNSProbeResultCallback");
(void) p_pUserdata;
if ((p_pMDNSResponder) &&
(0 == p_hService)) { // Called for host domain
Serial.printf("MDNSProbeResultCallback: Host domain '%s.local' is %s\n", p_pcDomainName, (p_bProbeResult ? "free" : "already USED!"));
if (true == p_bProbeResult) {
// Set station hostname
setStationHostname(pcHostDomain);
if (!bHostDomainConfirmed) {
// Hostname free -> setup clock service
bHostDomainConfirmed = true;
if (!hMDNSService) {
// Add a 'clock.tcp' service to port 'SERVICE_PORT', using the host domain as instance domain
hMDNSService = p_pMDNSResponder->addService(0, "espclk", "tcp", SERVICE_PORT);
if (hMDNSService) {
// Add a simple static MDNS service TXT item
p_pMDNSResponder->addServiceTxt(hMDNSService, "port#", SERVICE_PORT);
// Set the callback function for dynamic service TXTs
p_pMDNSResponder->setDynamicServiceTxtCallback(hMDNSService, MDNSDynamicServiceTxtCallback, 0);
}
}
} else {
// Change hostname, use '-' as divider between base name and index
if (LEAmDNS::MDNSResponder::indexDomain(pcHostDomain, "-", 0)) {
p_pMDNSResponder->setHostname(pcHostDomain);
} else {
Serial.println("MDNSProbeResultCallback: FAILED to update hostname!");
}
}
}
}
return true;
}
/*
handleHTTPClient
*/
void handleHTTPClient(WiFiClient& client) {
Serial.println("");
Serial.println("New client");
// Wait for data from client to become available
while (client.connected() && !client.available()) {
delay(1);
}
// Read the first line of HTTP request
String req = client.readStringUntil('\r');
// First line of HTTP request looks like "GET /path HTTP/1.1"
// Retrieve the "/path" part by finding the spaces
int addr_start = req.indexOf(' ');
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) {
Serial.print("Invalid request: ");
Serial.println(req);
return;
}
req = req.substring(addr_start + 1, addr_end);
Serial.print("Request: ");
Serial.println(req);
client.flush();
// Get current time
time_t now = time(nullptr);;
struct tm timeinfo;
gmtime_r(&now, &timeinfo);
String s;
if (req == "/") {
IPAddress ip = WiFi.localIP();
String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>Hello from ESP8266 at ";
s += ipStr;
// Simple addition of the current time
s += "\r\nCurrent time is: ";
s += getTimeString();
// done :-)
s += "</html>\r\n\r\n";
Serial.println("Sending 200");
} else {
s = "HTTP/1.1 404 Not Found\r\n\r\n";
Serial.println("Sending 404");
}
client.print(s);
Serial.println("Done with client");
}
/*
setup
*/
void setup(void) {
Serial.begin(115200);
// Connect to WiFi network
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Sync clock
setClock();
// Setup MDNS responder
LEAmDNS::MDNS.setProbeResultCallback(MDNSProbeResultCallback, 0);
// Init the (currently empty) host domain string with 'esp8266'
if ((!LEAmDNS::MDNSResponder::indexDomain(pcHostDomain, 0, "esp8266")) ||
(!LEAmDNS::MDNS.begin(pcHostDomain))) {
Serial.println("Error setting up MDNS responder!");
while (1) { // STOP
delay(1000);
}
}
Serial.println("MDNS responder started");
// Start TCP (HTTP) server
server.begin();
Serial.println("TCP server started");
}
/*
loop
*/
void loop(void) {
// Check if a client has connected
WiFiClient client = server.available();
if (client) {
handleHTTPClient(client);
}
// Allow MDNS processing
LEAmDNS::MDNS.update();
// Update time (if needed)
//static unsigned long ulNextTimeUpdate = UPDATE_CYCLE;
static clsLEATimeFlag timeFlag(UPDATE_CYCLE);
if (timeFlag.flagged()/*ulNextTimeUpdate < millis()*/) {
if (hMDNSService) {
// Just trigger a new MDNS announcement, this will lead to a call to
// 'MDNSDynamicServiceTxtCallback', which will update the time TXT item
LEAmDNS::MDNS.announce();
}
//ulNextTimeUpdate = (millis() + UPDATE_CYCLE); // Set update 'timer'
timeFlag.restart();
}
}

View File

@ -0,0 +1,356 @@
/*
ESP8266 mDNS Responder Service Monitor
This example demonstrates two features of the LEA MDNSResponder:
1. The host and service domain negotiation process that ensures
the uniqueness of the finally choosen host and service domain name.
2. The dynamic MDNS service lookup/query feature.
A list of 'HTTP' services in the local network is created and kept up to date.
In addition to this, a (very simple) HTTP server is set up on port 80
and announced as a service.
The ESP itself is initially announced to clients as 'esp8266.local', if this host domain
is already used in the local network, another host domain is negociated. Keep an
eye to the serial output to learn the final host domain for the HTTP service.
The service itself is is announced as 'host domain'._http._tcp.local.
The HTTP server delivers a short greeting and the current list of other 'HTTP' services (not updated).
The web server code is taken nearly 1:1 from the 'mDNS_Web_Server.ino' example.
Point your browser to 'host domain'.local to see this web page.
Instructions:
- Update WiFi SSID and password as necessary.
- Flash the sketch to the ESP8266 board
- Install host software:
- For Linux, install Avahi (http://avahi.org/).
- For Windows, install Bonjour (http://www.apple.com/support/bonjour/).
- For Mac OSX and iOS support is built in through Bonjour already.
- Use a browser like 'Safari' to see the page at http://'host domain'.local.
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
/*
Include the MDNSResponder (the library needs to be included also)
As LEA MDNSResponder is experimantal in the ESP8266 environment currently, the
legacy MDNSResponder is defaulted in th include file.
There are two ways to access LEA MDNSResponder:
1. Prepend every declaration and call to global declarations or functions with the namespace, like:
'LEAmDNS:MDNSResponder::hMDNSService hMDNSService;'
This way is used in the example. But be careful, if the namespace declaration is missing
somewhere, the call might go to the legacy implementation...
2. Open 'ESP8266mDNS.h' and set LEAmDNS to default.
*/
#include <ESP8266mDNS.h>
/*
Global defines and vars
*/
#define SERVICE_PORT 80 // HTTP port
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
char* pcHostDomain = 0; // Negociated host domain
bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain
LEAmDNS::MDNSResponder::hMDNSService hMDNSService = 0; // The handle of the http service in the MDNS responder
LEAmDNS::MDNSResponder::hMDNSServiceQuery hMDNSServiceQuery = 0; // The handle of the 'http.tcp' service query in the MDNS responder
const String cstrNoHTTPServices = "Currently no 'http.tcp' services in the local network!<br/>";
String strHTTPServices = cstrNoHTTPServices;
// TCP server at port 'SERVICE_PORT' will respond to HTTP requests
WiFiServer server(SERVICE_PORT);
/*
setStationHostname
*/
bool setStationHostname(const char* p_pcHostname) {
if (p_pcHostname) {
WiFi.hostname(p_pcHostname);
Serial.printf("setStationHostname: Station hostname is set to '%s'\n", p_pcHostname);
}
return true;
}
/*
MDNSServiceQueryCallback
*/
bool MDNSServiceQueryCallback(LEAmDNS::MDNSResponder* p_pMDNSResponder, // The MDNS responder object
const LEAmDNS::MDNSResponder::hMDNSServiceQuery p_hServiceQuery, // Handle to the service query
uint32_t p_u32AnswerIndex, // Index of the updated answer
uint32_t p_u32ServiceQueryAnswerMask, // Mask for the updated component
bool p_bSetContent, // true: Component set, false: component deleted
void* p_pUserdata) { // pUserdata; here '0', as none set via 'installServiceQuery'
(void) p_pUserdata;
Serial.printf("MDNSServiceQueryCallback\n");
if ((p_pMDNSResponder) &&
(hMDNSServiceQuery == p_hServiceQuery)) {
if (LEAmDNS::MDNSResponder::ServiceQueryAnswerType_ServiceDomain & p_u32ServiceQueryAnswerMask) {
Serial.printf("MDNSServiceQueryCallback: Service domain '%s' %s index %u\n",
p_pMDNSResponder->answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex),
(p_bSetContent ? "added at" : "removed from"),
p_u32AnswerIndex);
} else if (LEAmDNS::MDNSResponder::ServiceQueryAnswerType_HostDomainAndPort & p_u32ServiceQueryAnswerMask) {
if (p_bSetContent) {
Serial.printf("MDNSServiceQueryCallback: Host domain and port added/updated for service '%s': %s:%u\n",
p_pMDNSResponder->answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex),
p_pMDNSResponder->answerHostDomain(p_hServiceQuery, p_u32AnswerIndex),
p_pMDNSResponder->answerPort(p_hServiceQuery, p_u32AnswerIndex));
} else {
Serial.printf("MDNSServiceQueryCallback: Host domain and port removed from service '%s'\n",
p_pMDNSResponder->answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex));
}
} else if (LEAmDNS::MDNSResponder::ServiceQueryAnswerType_IP4Address & p_u32ServiceQueryAnswerMask) {
if (p_bSetContent) {
Serial.printf("MDNSServiceQueryCallback: IP4 address added/updated for service '%s':\n",
p_pMDNSResponder->answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex));
for (uint32_t u = 0; u < p_pMDNSResponder->answerIP4AddressCount(p_hServiceQuery, p_u32AnswerIndex); ++u) {
Serial.printf("- %s\n", p_pMDNSResponder->answerIP4Address(p_hServiceQuery, p_u32AnswerIndex, u).toString().c_str());
}
} else {
Serial.printf("MDNSServiceQueryCallback: IP4 address removed from service '%s'\n",
p_pMDNSResponder->answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex));
}
} else if (LEAmDNS::MDNSResponder::ServiceQueryAnswerType_Txts & p_u32ServiceQueryAnswerMask) {
if (p_bSetContent) {
Serial.printf("MDNSServiceQueryCallback: TXT items added/updated for service '%s': %s\n",
p_pMDNSResponder->answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex),
p_pMDNSResponder->answerTxts(p_hServiceQuery, p_u32AnswerIndex));
} else {
Serial.printf("MDNSServiceQueryCallback: TXT items removed from service '%s'\n",
p_pMDNSResponder->answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex));
}
}
//
// Create the current list of 'http.tcp' services
uint32_t u32Answers = p_pMDNSResponder->answerCount(p_hServiceQuery);
if (u32Answers) {
strHTTPServices = "";
for (uint32_t u = 0; u < u32Answers; ++u) {
// Index and service domain
strHTTPServices += u;
strHTTPServices += ": ";
strHTTPServices += p_pMDNSResponder->answerServiceDomain(p_hServiceQuery, u);
// Host domain and port
if ((p_pMDNSResponder->hasAnswerHostDomain(p_hServiceQuery, u)) &&
(p_pMDNSResponder->hasAnswerPort(p_hServiceQuery, u))) {
strHTTPServices += " at ";
strHTTPServices += p_pMDNSResponder->answerHostDomain(p_hServiceQuery, u);
strHTTPServices += ":";
strHTTPServices += p_pMDNSResponder->answerPort(p_hServiceQuery, u);
}
// IP4 address
if (p_pMDNSResponder->hasAnswerIP4Address(p_hServiceQuery, u)) {
strHTTPServices += " IP4: ";
for (uint32_t u2 = 0; u2 < p_pMDNSResponder->answerIP4AddressCount(p_hServiceQuery, u); ++u2) {
if (0 != u2) {
strHTTPServices += ", ";
}
strHTTPServices += p_pMDNSResponder->answerIP4Address(p_hServiceQuery, u, u2).toString();
}
}
// MDNS TXT items
if (p_pMDNSResponder->hasAnswerTxts(p_hServiceQuery, u)) {
strHTTPServices += " TXT: ";
strHTTPServices += p_pMDNSResponder->answerTxts(p_hServiceQuery, u);
}
strHTTPServices += "<br/>";
}
} else {
strHTTPServices = cstrNoHTTPServices;
}
}
return true;
}
/*
MDNSProbeResultCallback
Probe result callback for the host domain.
If the domain is free, the host domain is set and the http service is
added.
If the domain is already used, a new name is created and the probing is
restarted via p_pMDNSResponder->setHostname().
*/
bool MDNSProbeResultCallback(LEAmDNS::MDNSResponder* p_pMDNSResponder,
const char* p_pcDomainName,
const LEAmDNS::MDNSResponder::hMDNSService p_hService,
bool p_bProbeResult,
void* p_pUserdata) {
(void) p_pUserdata;
if ((p_pMDNSResponder) &&
(0 == p_hService)) { // Called for host domain
Serial.printf("MDNSProbeResultCallback: Host domain '%s.local' is %s\n", p_pcDomainName, (p_bProbeResult ? "free" : "already USED!"));
if (true == p_bProbeResult) {
// Set station hostname
setStationHostname(pcHostDomain);
if (!bHostDomainConfirmed) {
// Hostname free -> setup clock service
bHostDomainConfirmed = true;
if (!hMDNSService) {
// Add a 'http.tcp' service to port 'SERVICE_PORT', using the host domain as instance domain
hMDNSService = p_pMDNSResponder->addService(0, "http", "tcp", SERVICE_PORT);
if (hMDNSService) {
// Add some '_http._tcp' protocol specific MDNS service TXT items
// See: http://www.dns-sd.org/txtrecords.html#http
p_pMDNSResponder->addServiceTxt(hMDNSService, "user", "");
p_pMDNSResponder->addServiceTxt(hMDNSService, "password", "");
p_pMDNSResponder->addServiceTxt(hMDNSService, "path", "/");
}
// Install dynamic 'http.tcp' service query
if (!hMDNSServiceQuery) {
hMDNSServiceQuery = p_pMDNSResponder->installServiceQuery("http", "tcp", MDNSServiceQueryCallback, 0);
if (hMDNSServiceQuery) {
Serial.printf("MDNSProbeResultCallback: Service query for 'http.tcp' services installed.\n");
} else {
Serial.printf("MDNSProbeResultCallback: FAILED to install service query for 'http.tcp' services!\n");
}
}
}
} else {
// Change hostname, use '-' as divider between base name and index
if (LEAmDNS::MDNSResponder::indexDomain(pcHostDomain, "-", 0)) {
p_pMDNSResponder->setHostname(pcHostDomain);
} else {
Serial.println("MDNSProbeResultCallback: FAILED to update hostname!");
}
}
}
}
return true;
}
/*
handleHTTPClient
*/
void handleHTTPClient(WiFiClient& client) {
Serial.println("");
Serial.println("New client");
// Wait for data from client to become available
while (client.connected() && !client.available()) {
delay(1);
}
// Read the first line of HTTP request
String req = client.readStringUntil('\r');
// First line of HTTP request looks like "GET /path HTTP/1.1"
// Retrieve the "/path" part by finding the spaces
int addr_start = req.indexOf(' ');
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) {
Serial.print("Invalid request: ");
Serial.println(req);
return;
}
req = req.substring(addr_start + 1, addr_end);
Serial.print("Request: ");
Serial.println(req);
client.flush();
String s;
if (req == "/") {
IPAddress ip = WiFi.localIP();
String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>Hello from ESP8266 at ";
s += ipStr;
// Simple addition of the current time
s += "<br/>Local HTTP services:<br/>";
s += strHTTPServices;
// done :-)
s += "</html>\r\n\r\n";
Serial.println("Sending 200");
} else {
s = "HTTP/1.1 404 Not Found\r\n\r\n";
Serial.println("Sending 404");
}
client.print(s);
Serial.println("Done with client");
}
/*
setup
*/
void setup(void) {
Serial.begin(115200);
Serial.setDebugOutput(false);
// Connect to WiFi network
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Setup MDNS responder
LEAmDNS::MDNS.setProbeResultCallback(MDNSProbeResultCallback, 0);
// Init the (currently empty) host domain string with 'esp8266'
if ((!LEAmDNS::MDNSResponder::indexDomain(pcHostDomain, 0, "esp8266")) ||
(!LEAmDNS::MDNS.begin(pcHostDomain))) {
Serial.println("Error setting up MDNS responder!");
while (1) { // STOP
delay(1000);
}
}
Serial.println("MDNS responder started");
// Start TCP (HTTP) server
server.begin();
Serial.println("TCP server started");
}
/*
loop
*/
void loop(void) {
// Check if a client has connected
WiFiClient client = server.available();
if (client) {
handleHTTPClient(client);
}
// Allow MDNS processing
LEAmDNS::MDNS.update();
}

View File

@ -1,10 +1,10 @@
name=ESP8266mDNS name=ESP8266mDNS
version=1.1 version=1.2
author=tony@tonydicola.com author=multiple, see files
maintainer=ivan@esp8266.com maintainer=LaborEtArs
sentence=A port of CC3000 Multicast DNS library sentence=Creates a mDNS responder.
paragraph=This is a simple implementation of multicast DNS query support for an Arduino running on ESP8266 chip. Only support for resolving address queries is currently implemented. paragraph=Creates a mDNS responder to ensure host domain uniqueness in local networks and to allow for mDNS service discovery and announcment.
category=Communication category=Communication
url= url=https://github.com/LaborEtArs/ESP8266mDNS
architectures=esp8266 architectures=esp8266
dot_a_linkage=true dot_a_linkage=true

View File

@ -0,0 +1,49 @@
/*
ESP8266mDNS.h - mDNSResponder for ESP8266 family
This file is part of the esp8266 core for Arduino environment.
Legacy_ESP8266mDNS:
The well known, thouroughly tested (yet no flawless) default mDNS library for the ESP8266 family
LEA_ESP8266mDNS:
An (currently) experimental mDNS implementation, that supports a lot more of mDNS features than Legacy_ESP8266mDNS, like:
- Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service
- Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented
- Probing host and service domains for uniqueness in the local network
- Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak)
- Announcing available services after successful probing
- Using fixed service TXT items or
- Using dynamic service TXT items for presented services (via callback)
- Remove services (and un-announcing them to the observers by sending goodbye-messages)
- Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period)
- Dynamic queries for DNS-SD services with cached and updated answers and user notifications
- Support for multi-homed client host domains
See 'LEA_ESP8266mDNS/EPS8266mDNS.h' for more implementation details and usage informations.
See 'examples/mDNS_Clock' and 'examples/mDNS_ServiceMonitor' for implementation examples of the advanced features.
LEA_ESP8266mDNS is (mostly) client source code compatible to 'Legacy_ESP8266mDNS', so it could be
use as a 'drop-in' replacement in existing projects.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "ESP8266mDNS_Legacy.h"
#include "LEAmDNS.h"
using namespace Legacy_MDNSResponder;
//using namespace LEAmDNS;

View File

@ -59,6 +59,9 @@ extern "C" {
namespace Legacy_MDNSResponder {
#ifdef DEBUG_ESP_MDNS #ifdef DEBUG_ESP_MDNS
#define DEBUG_ESP_MDNS_ERR #define DEBUG_ESP_MDNS_ERR
#define DEBUG_ESP_MDNS_TX #define DEBUG_ESP_MDNS_TX
@ -964,12 +967,24 @@ void MDNSResponder::_parsePacket(){
return _replyToInstanceRequest(questionMask, responseMask, serviceName, protoName, servicePort, interface); return _replyToInstanceRequest(questionMask, responseMask, serviceName, protoName, servicePort, interface);
} }
/**
* STRINGIZE
*/
#ifndef STRINGIZE
#define STRINGIZE(x) #x
#endif
#ifndef STRINGIZE_VALUE_OF
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
#endif
void MDNSResponder::enableArduino(uint16_t port, bool auth){ void MDNSResponder::enableArduino(uint16_t port, bool auth){
addService("arduino", "tcp", port); addService("arduino", "tcp", port);
addServiceTxt("arduino", "tcp", "tcp_check", "no"); addServiceTxt("arduino", "tcp", "tcp_check", "no");
addServiceTxt("arduino", "tcp", "ssh_upload", "no"); addServiceTxt("arduino", "tcp", "ssh_upload", "no");
addServiceTxt("arduino", "tcp", "board", ARDUINO_BOARD); addServiceTxt("arduino", "tcp", "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD));
addServiceTxt("arduino", "tcp", "auth_upload", (auth) ? "yes":"no"); addServiceTxt("arduino", "tcp", "auth_upload", (auth) ? "yes":"no");
} }
@ -1267,3 +1282,9 @@ void MDNSResponder::_replyToInstanceRequest(uint8_t questionMask, uint8_t respon
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
MDNSResponder MDNS; MDNSResponder MDNS;
#endif #endif
} // namespace Legacy_MDNSResponder

View File

@ -53,6 +53,10 @@ License (MIT license):
class UdpContext; class UdpContext;
namespace Legacy_MDNSResponder {
struct MDNSService; struct MDNSService;
struct MDNSTxt; struct MDNSTxt;
struct MDNSAnswer; struct MDNSAnswer;
@ -139,4 +143,9 @@ private:
extern MDNSResponder MDNS; extern MDNSResponder MDNS;
#endif #endif
} // namespace Legacy_MDNSResponder
#endif //ESP8266MDNS_H #endif //ESP8266MDNS_H

View File

@ -0,0 +1,62 @@
/*
* LEATimeFlag.h
*/
#ifndef __LEATIMEFLAG_H
#define __LEATIMEFLAG_H
#include <Arduino.h>
/**
* clsLEATimeFlag
*/
class clsLEATimeFlag {
public:
// constructor
clsLEATimeFlag(unsigned long p_ulTimeout = (unsigned long)(-1))
: m_ulStart(millis()),
m_ulTimeout(p_ulTimeout) {
}
// operator bool
operator bool(void) const {
return flagged();
}
// flagged
bool flagged(void) const {
return ((millis() - m_ulStart) > m_ulTimeout);
}
// restart
void restart(unsigned long p_ulNewTimeout = (unsigned long)(-1)) {
if ((unsigned long)(-1) != p_ulNewTimeout) {
m_ulTimeout = p_ulNewTimeout;
}
m_ulStart = millis();
}
void reset(void) {
m_ulTimeout = (unsigned long)(-1);
m_ulStart = millis();
}
unsigned long start(void) const {
return m_ulStart;
}
unsigned long timeout(void) const {
return m_ulTimeout;
}
bool hypotheticalTimeout(unsigned long p_ulHypotheticalTimeout) const {
return ((millis() - m_ulStart) > p_ulHypotheticalTimeout);
}
protected:
unsigned long m_ulStart;
unsigned long m_ulTimeout;
};
#endif // __LEATIMEFLAG_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,729 @@
/*
* LEAmDNS_Helpers.cpp
*
* License (MIT license):
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "lwip/igmp.h"
#include "LEAmDNS_lwIPdefs.h"
#include "LEAmDNS_Priv.h"
/*
* namespace LEAmDNS
*/
namespace LEAmDNS {
/**
* HELPERS
*/
/*
* strrstr (static)
*
* Backwards search for p_pcPattern in p_pcString
* Based on: https://stackoverflow.com/a/1634398/2778898
*
*/
static const char* strrstr(const char*__restrict p_pcString, const char*__restrict p_pcPattern) {
const char* pcResult = 0;
size_t stStringLength = (p_pcString ? strlen(p_pcString) : 0);
size_t stPatternLength = (p_pcPattern ? strlen(p_pcPattern) : 0);
if ((stStringLength) &&
(stPatternLength) &&
(stPatternLength <= stStringLength)) {
// Pattern is shorter or has the same length tham the string
for (const char* s=(p_pcString + stStringLength - stPatternLength); s>=p_pcString; --s) {
if (0 == strncmp(s, p_pcPattern, stPatternLength)) {
pcResult = s;
break;
}
}
}
return pcResult;
}
/*
* MDNSResponder::indexDomain (static)
*
* Updates the given domain 'p_rpcHostname' by appending a delimiter and an index number.
*
* If the given domain already hasa numeric index (after the given delimiter), this index
* incremented. If not, the delimiter and index '2' is added.
*
* If 'p_rpcHostname' is empty (==0), the given default name 'p_pcDefaultHostname' is used,
* if no default is given, 'esp8266' is used.
*
*/
/*static*/ bool MDNSResponder::indexDomain(char*& p_rpcDomain,
const char* p_pcDivider /*= "-"*/,
const char* p_pcDefaultDomain /*= 0*/) {
bool bResult = false;
// Ensure a divider exists; use '-' as default
const char* pcDivider = (p_pcDivider ?: "-");
if (p_rpcDomain) {
const char* pFoundDivider = strrstr(p_rpcDomain, pcDivider);
if (pFoundDivider) { // maybe already extended
char* pEnd = 0;
unsigned long ulIndex = strtoul((pFoundDivider + os_strlen(pcDivider)), &pEnd, 10);
if ((ulIndex) &&
((pEnd - p_rpcDomain) == os_strlen(p_rpcDomain)) &&
(!*pEnd)) { // Valid (old) index found
char acIndexBuffer[16];
sprintf(acIndexBuffer, "%lu", (++ulIndex));
size_t stLength = ((pFoundDivider - p_rpcDomain + os_strlen(pcDivider)) + os_strlen(acIndexBuffer) + 1);
char* pNewHostname = new char[stLength];
if (pNewHostname) {
memcpy(pNewHostname, p_rpcDomain, (pFoundDivider - p_rpcDomain + os_strlen(pcDivider)));
pNewHostname[pFoundDivider - p_rpcDomain + os_strlen(pcDivider)] = 0;
os_strcat(pNewHostname, acIndexBuffer);
delete[] p_rpcDomain;
p_rpcDomain = pNewHostname;
bResult = true;
}
else {
DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!")););
}
}
else {
pFoundDivider = 0; // Flag the need to (base) extend the hostname
}
}
if (!pFoundDivider) { // not yet extended (or failed to increment extension) -> start indexing
size_t stLength = os_strlen(p_rpcDomain) + (os_strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0'
char* pNewHostname = new char[stLength];
if (pNewHostname) {
sprintf(pNewHostname, "%s%s2", p_rpcDomain, pcDivider);
delete[] p_rpcDomain;
p_rpcDomain = pNewHostname;
bResult = true;
}
else {
DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!")););
}
}
}
else {
// No given host domain, use base or default
const char* cpcDefaultName = (p_pcDefaultDomain ?: "esp8266");
size_t stLength = os_strlen(cpcDefaultName) + 1; // '\0'
p_rpcDomain = new char[stLength];
if (p_rpcDomain) {
os_strncpy(p_rpcDomain, cpcDefaultName, stLength);
bResult = true;
}
else {
DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!")););
}
}
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR_LEA("[MDNSResponder] indexDomain: %s\n"), p_rpcDomain););
return bResult;
}
/*
* UDP CONTEXT
*/
bool MDNSResponder::_callProcess(void) {
return _process(false);
}
/*
* MDNSResponder::_allocUDPContext
*
* (Re-)Creates the one-and-only UDP context for the MDNS responder.
* The context is added to the 'multicast'-group and listens to the MDNS port (5353).
* The travel-distance for multicast messages is set to 1 (local, via MDNS_MULTICAST_TTL).
* Messages are received via the MDNSResponder '_update' function. CAUTION: This function
* is called from the WiFi stack side of the ESP stack system.
*
*/
bool MDNSResponder::_allocUDPContext(void) {
DEBUG_EX_INFO(DEBUG_OUTPUT.println("[MDNSResponder] _allocUDPContext"););
bool bResult = false;
_releaseUDPContext();
ip_addr_t multicast_addr;
#ifdef MDNS_IP4_SUPPORT
multicast_addr.addr = DNS_MQUERY_IPV4_GROUP_INIT;
#endif
#ifdef MDNS_IP6_SUPPORT
//TODO: set multicast address
multicast_addr.addr = DNS_MQUERY_IPV6_GROUP_INIT;
#endif
if (ERR_OK == igmp_joingroup(IP_ADDR_ANY, &multicast_addr)) {
m_pUDPContext = new UdpContext;
m_pUDPContext->ref();
if (m_pUDPContext->listen(IP_ADDR_ANY, DNS_MQUERY_PORT)) {
m_pUDPContext->setMulticastTTL(MDNS_MULTICAST_TTL);
m_pUDPContext->onRx(std::bind(&MDNSResponder::_callProcess, this));
bResult = m_pUDPContext->connect(&multicast_addr, DNS_MQUERY_PORT);
}
}
return bResult;
}
/*
* MDNSResponder::_releaseUDPContext
*/
bool MDNSResponder::_releaseUDPContext(void) {
if (m_pUDPContext) {
m_pUDPContext->unref();
m_pUDPContext = 0;
}
return true;
}
/*
* SERVICE QUERY
*/
/*
* MDNSResponder::_allocServiceQuery
*/
MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_allocServiceQuery(void) {
stcMDNSServiceQuery* pServiceQuery = new stcMDNSServiceQuery;
if (pServiceQuery) {
// Link to query list
pServiceQuery->m_pNext = m_pServiceQueries;
m_pServiceQueries = pServiceQuery;
}
return m_pServiceQueries;
}
/*
* MDNSResponder::_removeServiceQuery
*/
bool MDNSResponder::_removeServiceQuery(MDNSResponder::stcMDNSServiceQuery* p_pServiceQuery) {
bool bResult = false;
if (p_pServiceQuery) {
stcMDNSServiceQuery* pPred = m_pServiceQueries;
while ((pPred) &&
(pPred->m_pNext != p_pServiceQuery)) {
pPred = pPred->m_pNext;
}
if (pPred) {
pPred->m_pNext = p_pServiceQuery->m_pNext;
delete p_pServiceQuery;
bResult = true;
}
else { // No predecesor
if (m_pServiceQueries == p_pServiceQuery) {
m_pServiceQueries = p_pServiceQuery->m_pNext;
delete p_pServiceQuery;
bResult = true;
}
else {
DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseServiceQuery: INVALID service query!"););
}
}
}
return bResult;
}
/*
* MDNSResponder::_removeLegacyServiceQuery
*/
bool MDNSResponder::_removeLegacyServiceQuery(void) {
stcMDNSServiceQuery* pLegacyServiceQuery = _findLegacyServiceQuery();
return (pLegacyServiceQuery ? _removeServiceQuery(pLegacyServiceQuery) : true);
}
/*
* MDNSResponder::_findServiceQuery
*
* 'Convert' hMDNSServiceQuery to stcMDNSServiceQuery* (ensure existance)
*
*/
MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) {
stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries;
while (pServiceQuery) {
if ((hMDNSServiceQuery)pServiceQuery == p_hServiceQuery) {
break;
}
pServiceQuery = pServiceQuery->m_pNext;
}
return pServiceQuery;
}
/*
* MDNSResponder::_findLegacyServiceQuery
*/
MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findLegacyServiceQuery(void) {
stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries;
while (pServiceQuery) {
if (pServiceQuery->m_bLegacyQuery) {
break;
}
pServiceQuery = pServiceQuery->m_pNext;
}
return pServiceQuery;
}
/*
* MDNSResponder::_releaseServiceQueries
*/
bool MDNSResponder::_releaseServiceQueries(void) {
while (m_pServiceQueries) {
stcMDNSServiceQuery* pNext = m_pServiceQueries->m_pNext;
delete m_pServiceQueries;
m_pServiceQueries = pNext;
}
return true;
}
/*
* MDNSResponder::_findNextServiceQueryByServiceType
*/
MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceTypeDomain,
const stcMDNSServiceQuery* p_pPrevServiceQuery) {
stcMDNSServiceQuery* pMatchingServiceQuery = 0;
stcMDNSServiceQuery* pServiceQuery = (p_pPrevServiceQuery ? p_pPrevServiceQuery->m_pNext : m_pServiceQueries);
while (pServiceQuery) {
if (p_ServiceTypeDomain == pServiceQuery->m_ServiceTypeDomain) {
pMatchingServiceQuery = pServiceQuery;
break;
}
pServiceQuery = pServiceQuery->m_pNext;
}
return pMatchingServiceQuery;
}
/*
* HOSTNAME
*/
/*
* MDNSResponder::_setHostname
*/
bool MDNSResponder::_setHostname(const char* p_pcHostname) {
//DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR_LEA("[MDNSResponder] _allocHostname (%s)\n"), p_pcHostname););
bool bResult = false;
_releaseHostname();
size_t stLength = 0;
if ((p_pcHostname) &&
(MDNS_DOMAIN_LABEL_MAXLENGTH >= (stLength = os_strlen(p_pcHostname)))) { // char max size for a single label
// Copy in hostname characters as lowercase
if ((bResult = (0 != (m_pcHostname = new char[stLength + 1])))) {
#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME
size_t i = 0;
for (; i<stLength; ++i) {
m_pcHostname[i] = (isupper(p_pcHostname[i]) ? tolower(p_pcHostname[i]) : p_pcHostname[i]);
}
m_pcHostname[i] = 0;
#else
os_strncpy(m_pcHostname, p_pcHostname, (stLength + 1));
#endif
}
}
return bResult;
}
/*
* MDNSResponder::_releaseHostname
*/
bool MDNSResponder::_releaseHostname(void) {
if (m_pcHostname) {
delete[] m_pcHostname;
m_pcHostname = 0;
}
return true;
}
/*
* SERVICE
*/
/*
* MDNSResponder::_allocService
*/
MDNSResponder::stcMDNSService* MDNSResponder::_allocService(const char* p_pcName,
const char* p_pcService,
const char* p_pcProtocol,
uint16_t p_u16Port) {
stcMDNSService* pService = 0;
if (((!p_pcName) ||
(MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcName))) &&
(p_pcService) &&
(MDNS_SERVICE_NAME_LENGTH >= os_strlen(p_pcService)) &&
(p_pcProtocol) &&
(MDNS_SERVICE_PROTOCOL_LENGTH >= os_strlen(p_pcProtocol)) &&
(p_u16Port) &&
(0 != (pService = new stcMDNSService)) &&
(pService->setName(p_pcName ?: m_pcHostname)) &&
(pService->setService(p_pcService)) &&
(pService->setProtocol(p_pcProtocol))) {
pService->m_bAutoName = (0 == p_pcName);
pService->m_u16Port = p_u16Port;
// Add to list (or start list)
pService->m_pNext = m_pServices;
m_pServices = pService;
}
return pService;
}
/*
* MDNSResponder::_releaseService
*/
bool MDNSResponder::_releaseService(MDNSResponder::stcMDNSService* p_pService) {
bool bResult = false;
if (p_pService) {
stcMDNSService* pPred = m_pServices;
while ((pPred) &&
(pPred->m_pNext != p_pService)) {
pPred = pPred->m_pNext;
}
if (pPred) {
pPred->m_pNext = p_pService->m_pNext;
delete p_pService;
bResult = true;
}
else { // No predecesor
if (m_pServices == p_pService) {
m_pServices = p_pService->m_pNext;
delete p_pService;
bResult = true;
}
else {
DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseService: INVALID service!"););
}
}
}
return bResult;
}
/*
* MDNSResponder::_releaseServices
*/
bool MDNSResponder::_releaseServices(void) {
stcMDNSService* pService = m_pServices;
while (pService) {
_releaseService(pService);
pService = m_pServices;
}
return true;
}
/*
* MDNSResponder::_findService
*/
MDNSResponder::stcMDNSService* MDNSResponder::_findService(const char* p_pcName,
const char* p_pcService,
const char* p_pcProtocol) {
stcMDNSService* pService = m_pServices;
while (pService) {
if ((0 == strcmp(pService->m_pcName, p_pcName)) &&
(0 == strcmp(pService->m_pcService, p_pcService)) &&
(0 == strcmp(pService->m_pcProtocol, p_pcProtocol))) {
break;
}
pService = pService->m_pNext;
}
return pService;
}
/*
* MDNSResponder::_findService
*/
MDNSResponder::stcMDNSService* MDNSResponder::_findService(const MDNSResponder::hMDNSService p_hService) {
stcMDNSService* pService = m_pServices;
while (pService) {
if (p_hService == (hMDNSService)pService) {
break;
}
pService = pService->m_pNext;
}
return pService;
}
/*
* SERVICE TXT
*/
/*
* MDNSResponder::_allocServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_allocServiceTxt(MDNSResponder::stcMDNSService* p_pService,
const char* p_pcKey,
const char* p_pcValue,
bool p_bTemp) {
stcMDNSServiceTxt* pTxt = 0;
if ((p_pService) &&
(p_pcKey) &&
(MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() +
1 + // Length byte
(p_pcKey ? os_strlen(p_pcKey) : 0) +
1 + // '='
(p_pcValue ? os_strlen(p_pcValue) : 0)))) {
pTxt = new stcMDNSServiceTxt;
if (pTxt) {
size_t stLength = (p_pcKey ? os_strlen(p_pcKey) : 0);
pTxt->m_pcKey = new char[stLength + 1];
if (pTxt->m_pcKey) {
os_strncpy(pTxt->m_pcKey, p_pcKey, stLength); pTxt->m_pcKey[stLength] = 0;
}
if (p_pcValue) {
stLength = (p_pcValue ? os_strlen(p_pcValue) : 0);
pTxt->m_pcValue = new char[stLength + 1];
if (pTxt->m_pcValue) {
os_strncpy(pTxt->m_pcValue, p_pcValue, stLength); pTxt->m_pcValue[stLength] = 0;
}
}
pTxt->m_bTemp = p_bTemp;
// Add to list (or start list)
p_pService->m_Txts.add(pTxt);
}
}
return pTxt;
}
/*
* MDNSResponder::_releaseServiceTxt
*/
bool MDNSResponder::_releaseServiceTxt(MDNSResponder::stcMDNSService* p_pService,
MDNSResponder::stcMDNSServiceTxt* p_pTxt) {
return ((p_pService) &&
(p_pTxt) &&
(p_pService->m_Txts.remove(p_pTxt)));
}
/*
* MDNSResponder::_updateServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_updateServiceTxt(MDNSResponder::stcMDNSService* p_pService,
MDNSResponder::stcMDNSServiceTxt* p_pTxt,
const char* p_pcValue,
bool p_bTemp) {
if ((p_pService) &&
(p_pTxt) &&
(MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() -
(p_pTxt->m_pcValue ? os_strlen(p_pTxt->m_pcValue) : 0) +
(p_pcValue ? os_strlen(p_pcValue) : 0)))) {
p_pTxt->update(p_pcValue);
p_pTxt->m_bTemp = p_bTemp;
}
return p_pTxt;
}
/*
* MDNSResponder::_findServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService,
const char* p_pcKey) {
return (p_pService ? p_pService->m_Txts.find(p_pcKey) : 0);
}
/*
* MDNSResponder::_findServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService,
const hMDNSTxt p_hTxt) {
return (((p_pService) && (p_hTxt)) ? p_pService->m_Txts.find((stcMDNSServiceTxt*)p_hTxt) : 0);
}
/*
* MDNSResponder::_addServiceTxt
*/
MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_addServiceTxt(MDNSResponder::stcMDNSService* p_pService,
const char* p_pcKey,
const char* p_pcValue,
bool p_bTemp) {
stcMDNSServiceTxt* pResult = 0;
if ((p_pService) &&
(p_pcKey) &&
(os_strlen(p_pcKey))) {
stcMDNSServiceTxt* pTxt = p_pService->m_Txts.find(p_pcKey);
if (pTxt) {
pResult = _updateServiceTxt(p_pService, pTxt, p_pcValue, p_bTemp);
}
else {
pResult = _allocServiceTxt(p_pService, p_pcKey, p_pcValue, p_bTemp);
}
}
return pResult;
}
/*
* MDNSResponder::_collectServiceTxts
*/
bool MDNSResponder::_collectServiceTxts(MDNSResponder::stcMDNSService& p_rService) {
bool bResult = (m_fnServiceTxtCallback
? m_fnServiceTxtCallback(this, (hMDNSService)&p_rService, m_pServiceTxtCallbackUserdata)
: true);
if ((bResult) &&
(p_rService.m_fnTxtCallback)) {
bResult = p_rService.m_fnTxtCallback(this, (hMDNSService)&p_rService, p_rService.m_pTxtCallbackUserdata);
}
return bResult;
}
/*
* MDNSResponder::_releaseTempServiceTxts
*/
bool MDNSResponder::_releaseTempServiceTxts(MDNSResponder::stcMDNSService& p_rService) {
return (p_rService.m_Txts.removeTempTxts());
}
/*
* MISC
*/
#ifdef DEBUG_ESP_MDNS_RESPONDER
/*
* MDNSResponder::_printRRDomain
*/
bool MDNSResponder::_printRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_RRDomain) const {
//DEBUG_OUTPUT.printf_P(PSTR_LEA("Domain: "));
const char* pCursor = p_RRDomain.m_acName;
uint8_t u8Length = *pCursor++;
if (u8Length) {
while (u8Length) {
for (uint8_t u=0; u<u8Length; ++u) {
DEBUG_OUTPUT.printf_P(PSTR_LEA("%c"), *(pCursor++));
}
u8Length = *pCursor++;
if (u8Length) {
DEBUG_OUTPUT.printf_P(PSTR_LEA("."));
}
}
}
else { // empty domain
DEBUG_OUTPUT.printf_P(PSTR_LEA("-empty-"));
}
//DEBUG_OUTPUT.printf_P(PSTR_LEA("\n"));
return true;
}
/*
* MDNSResponder::_printRRAnswer
*/
bool MDNSResponder::_printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const {
DEBUG_OUTPUT.printf_P(PSTR_LEA("[MDNSResponder] RRAnswer: "));
_printRRDomain(p_RRAnswer.m_Header.m_Domain);
DEBUG_OUTPUT.printf_P(PSTR_LEA(" Type:0x%04X Class:0x%04X TTL:%u, "), p_RRAnswer.m_Header.m_Attributes.m_u16Type, p_RRAnswer.m_Header.m_Attributes.m_u16Class, p_RRAnswer.m_u32TTL);
switch (p_RRAnswer.m_Header.m_Attributes.m_u16Type & (~0x8000)) { // Topmost bit might carry 'cache flush' flag
#ifdef MDNS_IP4_SUPPORT
case DNS_RRTYPE_A:
DEBUG_OUTPUT.printf_P(PSTR_LEA("A IP:%s"), ((const stcMDNS_RRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str());
break;
#endif
case DNS_RRTYPE_PTR:
DEBUG_OUTPUT.printf_P(PSTR_LEA("PTR "));
_printRRDomain(((const stcMDNS_RRAnswerPTR*)&p_RRAnswer)->m_PTRDomain);
break;
case DNS_RRTYPE_TXT: {
size_t stTxtLength = ((const stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength();
char* pTxts = new char[stTxtLength];
if (pTxts) {
((/*const c_str()!!*/stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts);
DEBUG_OUTPUT.printf_P(PSTR_LEA("TXT(%u) %s"), stTxtLength, pTxts);
delete[] pTxts;
}
break;
}
#ifdef MDNS_IP6_SUPPORT
case DNS_RRTYPE_AAAA:
DEBUG_OUTPUT.printf_P(PSTR_LEA("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str());
break;
#endif
case DNS_RRTYPE_SRV:
DEBUG_OUTPUT.printf_P(PSTR_LEA("SRV Port:%u "), ((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_u16Port);
_printRRDomain(((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_SRVDomain);
break;
default:
DEBUG_OUTPUT.printf_P(PSTR_LEA("generic "));
break;
}
DEBUG_OUTPUT.printf_P(PSTR_LEA("\n"));
return true;
}
#endif
} // namespace LEAmDNS

View File

@ -0,0 +1,168 @@
/*
* LEAmDNS_Priv.h
*
* License (MIT license):
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef LEAMDNS_PRIV_H
#define LEAMDNS_PRIV_H
/*
* namespace LEAmDNS
*/
namespace LEAmDNS {
// Enable class debug functions
#define ESP_8266_MDNS_INCLUDE
// #define DEBUG_ESP_MDNS_RESPONDER
#ifndef LWIP_OPEN_SRC
#define LWIP_OPEN_SRC
#endif
// Enable/disable debug trace macros
#ifdef DEBUG_ESP_MDNS_RESPONDER
//#define DEBUG_ESP_MDNS_INFO
#define DEBUG_ESP_MDNS_ERR
#define DEBUG_ESP_MDNS_TX
#define DEBUG_ESP_MDNS_RX
#endif
#ifdef DEBUG_ESP_MDNS_RESPONDER
#ifdef DEBUG_ESP_MDNS_INFO
#define DEBUG_EX_INFO(A) A
#else
#define DEBUG_EX_INFO(A)
#endif
#ifdef DEBUG_ESP_MDNS_ERR
#define DEBUG_EX_ERR(A) A
#else
#define DEBUG_EX_ERR(A)
#endif
#ifdef DEBUG_ESP_MDNS_TX
#define DEBUG_EX_TX(A) A
#else
#define DEBUG_EX_TX(A)
#endif
#ifdef DEBUG_ESP_MDNS_RX
#define DEBUG_EX_RX(A) A
#else
#define DEBUG_EX_RX(A)
#endif
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
#else
#define DEBUG_EX_INFO(A)
#define DEBUG_EX_ERR(A)
#define DEBUG_EX_TX(A)
#define DEBUG_EX_RX(A)
#endif
/* Replaced by 'lwip/prot/dns.h' definitions
#ifdef MDNS_IP4_SUPPORT
#define MDNS_MULTICAST_ADDR_IP4 (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT
#endif
#ifdef MDNS_IP6_SUPPORT
#define MDNS_MULTICAST_ADDR_IP6 (IPAddress("FF02::FB")) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT
#endif*/
//#define MDNS_MULTICAST_PORT 5353
/*
* This is NOT the TTL (Time-To-Live) for MDNS records, but the
* subnet level distance MDNS records should travel.
* 1 sets the subnet distance to 'local', which is default for MDNS.
* (Btw.: 255 would set it to 'as far as possible' -> internet)
*/
#define MDNS_MULTICAST_TTL 1
/*
* This is the MDNS record TTL
* Host level records are set to 2min (120s)
* service level records are set to 75min (4500s)
*/
#define MDNS_HOST_TTL 120
#define MDNS_SERVICE_TTL 4500
/*
* Compressed labels are flaged by the two topmost bits of the length byte being set
*/
#define MDNS_DOMAIN_COMPRESS_MARK 0xC0
/*
* Avoid endless recursion because of malformed compressed labels
*/
#define MDNS_DOMAIN_MAX_REDIRCTION 6
/*
* Default service priority and weight in SRV answers
*/
#define MDNS_SRV_PRIORITY 0
#define MDNS_SRV_WEIGHT 0
/*
* Delay between and number of probes for host and service domains
*/
#define MDNS_PROBE_DELAY 250
#define MDNS_PROBE_COUNT 3
/*
* Force host domain to use only lowercase letters
*/
//#define MDNS_FORCE_LOWERCASE_HOSTNAME
/*
* Enable/disable the usage of the F() macro in debug trace printf calls.
* There needs to be an PGM comptible printf function to use this.
*
* USE_PGM_PRINTF and F
*/
#define USE_PGM_PRINTF
#ifdef USE_PGM_PRINTF
// See: https://github.com/esp8266/Arduino/issues/3369
#define PROGMEM_LEA __attribute__((section(".irom.text.LEA")))
#define PSTR_LEA(s) (__extension__({static const char __c[] PROGMEM_LEA = (s); &__c[0];}))
#else
#ifdef F
#undef F
#endif
#define F(A) A
#endif
} // namespace LEAmDNS
// Include the main header, so the submodlues only need to include this header
#include "LEAmDNS.h"
#endif // LEAMDNS_PRIV_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
/*
* LEAmDNS_Priv.h
*
* License (MIT license):
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef LEAMDNS_LWIPDEFS_H
#define LEAMDNS_LWIPDEFS_H
#include <lwip/init.h>
#if LWIP_VERSION_MAJOR == 1
#include <lwip/mdns.h> // DNS_RRTYPE_xxx
// cherry pick from lwip1 dns.c/mdns.c source files:
#define DNS_MQUERY_PORT 5353
#define DNS_MQUERY_IPV4_GROUP_INIT ipaddr_addr("224.0.0.251") /* resolver1.opendns.com */
#define DNS_RRCLASS_ANY 255 /* any class */
#else // lwIP > 1
#include <lwip/prot/dns.h> // DNS_RRTYPE_xxx, DNS_MQUERY_PORT
#endif
#endif // LEAMDNS_LWIPDEFS_H