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

LEA mDNS v2 (#7540)

* LEAmDNSv2
This commit is contained in:
Labor-Et-Ars 2020-09-25 11:12:39 +02:00 committed by GitHub
parent faf59f5190
commit a3281fe2f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 12359 additions and 1846 deletions

View File

@ -32,6 +32,13 @@
struct ip_addr: ipv4_addr { };
#endif // !LWIP_IPV6
// to display a netif id with printf:
#define NETIFID_STR "%c%c%u"
#define NETIFID_VAL(netif) \
((netif)? (netif)->name[0]: '-'), \
((netif)? (netif)->name[1]: '-'), \
((netif)? netif_get_index(netif): 42)
// A class to make it easier to handle and pass around IP addresses
// IPv6 update:
// IPAddress is now a decorator class for lwIP's ip_addr_t

26
cores/esp8266/LwipIntf.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _LWIPINTF_H
#define _LWIPINTF_H
#include <lwip/netif.h>
#include <functional>
class LwipIntf
{
public:
using CBType = std::function <void(netif*)>;
static bool stateUpCB (LwipIntf::CBType&& cb);
private:
LwipIntf () { } // private, cannot be directly allocated
protected:
static bool stateChangeSysCB (LwipIntf::CBType&& cb);
};
#endif // _LWIPINTF_H

View File

@ -0,0 +1,42 @@
#include <LwipIntf.h>
#include <Schedule.h>
#include <debug.h>
#define NETIF_STATUS_CB_SIZE 3
static int netifStatusChangeListLength = 0;
LwipIntf::CBType netifStatusChangeList [NETIF_STATUS_CB_SIZE];
extern "C" void netif_status_changed (struct netif* netif)
{
// override the default empty weak function
for (int i = 0; i < netifStatusChangeListLength; i++)
netifStatusChangeList[i](netif);
}
bool LwipIntf::stateChangeSysCB (LwipIntf::CBType&& cb)
{
if (netifStatusChangeListLength >= NETIF_STATUS_CB_SIZE)
{
#if defined(DEBUG_ESP_CORE)
DEBUGV("NETIF_STATUS_CB_SIZE is too low\n");
#endif
return false;
}
netifStatusChangeList[netifStatusChangeListLength++] = cb;
return true;
}
bool LwipIntf::stateUpCB (LwipIntf::CBType&& cb)
{
return stateChangeSysCB([cb](netif* nif)
{
if (netif_is_up(nif))
schedule_function([cb, nif]()
{
cb(nif);
});
});
}

View File

@ -117,4 +117,36 @@ char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
return s;
}
/*
strrstr (static)
Backwards search for p_pcPattern in p_pcString
Based on: https://stackoverflow.com/a/1634398/2778898
*/
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 than 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;
}
};

View File

@ -44,6 +44,9 @@ char* dtostrf (double val, signed char width, unsigned char prec, char *s);
void reverse(char* begin, char* end);
const char* strrstr(const char*__restrict p_pcString,
const char*__restrict p_pcPattern);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -30,6 +30,7 @@ void esp_schedule();
}
#include <AddrList.h>
#include <PolledTimeout.h>
#define PBUF_ALIGNER_ADJUST 4
#define PBUF_ALIGNER(x) ((void*)((((intptr_t)(x))+3)&~3))
@ -390,14 +391,39 @@ public:
return size;
}
void cancelBuffer ()
{
if (_tx_buf_head)
pbuf_free(_tx_buf_head);
_tx_buf_head = 0;
_tx_buf_cur = 0;
_tx_buf_offset = 0;
}
bool send(const ip_addr_t* addr = 0, uint16_t port = 0)
{
return trySend(addr, port, /* don't keep buffer */false) == ERR_OK;
}
bool sendTimeout(const ip_addr_t* addr, uint16_t port,
esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs)
{
err_t err;
esp8266::polledTimeout::oneShotFastMs timeout(timeoutMs);
while (((err = trySend(addr, port, /* keep buffer on error */true)) != ERR_OK) && !timeout)
delay(0);
if (err != ERR_OK)
cancelBuffer(); // get rid of buffer kept on error after timeout
return err == ERR_OK;
}
private:
err_t trySend(const ip_addr_t* addr, uint16_t port, bool keepBufferOnError)
{
size_t data_size = _tx_buf_offset;
pbuf* tx_copy = pbuf_alloc(PBUF_TRANSPORT, data_size, PBUF_RAM);
if(!tx_copy){
DEBUGV("failed pbuf_alloc");
}
else{
if (tx_copy) {
uint8_t* dst = reinterpret_cast<uint8_t*>(tx_copy->payload);
for (pbuf* p = _tx_buf_head; p; p = p->next) {
size_t will_copy = (data_size < p->len) ? data_size : p->len;
@ -406,38 +432,32 @@ public:
data_size -= will_copy;
}
}
if (_tx_buf_head)
pbuf_free(_tx_buf_head);
_tx_buf_head = 0;
_tx_buf_cur = 0;
_tx_buf_offset = 0;
if(!tx_copy){
return false;
}
if (!keepBufferOnError)
cancelBuffer();
if (!tx_copy){
DEBUGV("failed pbuf_alloc");
return ERR_MEM;
}
if (!addr) {
addr = &_pcb->remote_ip;
port = _pcb->remote_port;
}
#ifdef LWIP_MAYBE_XCC
uint16_t old_ttl = _pcb->ttl;
if (ip_addr_ismulticast(addr)) {
_pcb->ttl = _mcast_ttl;
}
#endif
err_t err = udp_sendto(_pcb, tx_copy, addr, port);
if (err != ERR_OK) {
DEBUGV(":ust rc=%d\r\n", (int) err);
}
#ifdef LWIP_MAYBE_XCC
_pcb->ttl = old_ttl;
#endif
pbuf_free(tx_copy);
return err == ERR_OK;
}
private:
pbuf_free(tx_copy);
if (err == ERR_OK)
cancelBuffer(); // no error: get rid of buffer
return err;
}
size_t _processSize (const pbuf* pb)
{

View File

@ -36,21 +36,9 @@
#include <WiFiClient.h>
#include <ESP8266WebServer.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 <PolledTimeout.h>
#include <ESP8266mDNS.h>
/*
Global defines and vars
*/

View File

@ -0,0 +1,269 @@
/*
ESP8266 mDNS responder clock
This example demonstrates two features of the LEA clsLEAMDNSHost:
1. The host and service domain negotiation process that ensures
the uniqueness of the finally chosen 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 negotiated. Keep an
eye on 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 also installed 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 <ESP8266WebServer.h>
#include <LwipIntf.h>
#include <time.h>
#include <PolledTimeout.h>
// uses API MDNSApiVersion::LEAv2
#define NO_GLOBAL_MDNS // our MDNS is defined below
#include <ESP8266mDNS.h>
/*
Global defines and vars
*/
#define TIMEZONE_OFFSET 1 // CET
#define DST_OFFSET 1 // CEST
#define UPDATE_CYCLE (1 * 1000) // every second
#define START_AP_AFTER_MS 10000 // start AP after delay
#define SERVICE_PORT 80 // HTTP port
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
#ifndef APSSID
#define APSSID "ap4mdnsClock"
#define APPSK "mdnsClock"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
clsLEAMDNSHost MDNSRESP; // MDNS responder
bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain
clsLEAMDNSHost::clsService* hMDNSService = 0; // The handle of the clock service in the MDNS responder
// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests
ESP8266WebServer 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 = 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 MDNSRESP.announce().
*/
void MDNSDynamicServiceTxtCallback(const clsLEAMDNSHost::hMDNSService& p_hService) {
Serial.println("MDNSDynamicServiceTxtCallback");
if (hMDNSService == &p_hService) {
Serial.printf("Updating curtime TXT item to: %s\n", getTimeString());
hMDNSService->addDynamicServiceTxt("curtime", getTimeString());
}
}
/*
handleHTTPClient
*/
void handleHTTPRequest() {
Serial.println("");
Serial.println("HTTP Request");
// Get current time
time_t now = time(nullptr);;
struct tm timeinfo;
gmtime_r(&now, &timeinfo);
String s;
s.reserve(300);
s = "<!DOCTYPE HTML>\r\n<html>Hello from ";
s += WiFi.hostname() + " at " + WiFi.localIP().toString();
// Simple addition of the current time
s += "\r\nCurrent time is: ";
s += getTimeString();
// done :-)
s += "</html>\r\n\r\n";
Serial.println("Sending 200");
server.send(200, "text/html", s);
}
/*
setup
*/
void setup(void) {
Serial.begin(115200);
// Connect to WiFi network
WiFi.persistent(false);
// useless informative callback
if (!LwipIntf::stateUpCB([](netif * nif) {
Serial.printf("New interface %c%c/%d is up\n",
nif->name[0],
nif->name[1],
netif_get_index(nif));
})) {
Serial.println("Error: could not add informative callback\n");
}
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
// Init the (currently empty) host domain string with 'leamdnsv2'
if (MDNSRESP.begin("leamdnsv2",
[](clsLEAMDNSHost & p_rMDNSHost, const char* p_pcDomainName, bool p_bProbeResult)->void {
if (p_bProbeResult) {
Serial.printf("mDNSHost_AP::ProbeResultCallback: '%s' is %s\n", p_pcDomainName, (p_bProbeResult ? "FREE" : "USED!"));
// Unattended added service
hMDNSService = p_rMDNSHost.addService(0, "espclk", "tcp", 80);
hMDNSService->addDynamicServiceTxt("curtime", getTimeString());
hMDNSService->setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallback);
} else {
// Change hostname, use '-' as divider between base name and index
MDNSRESP.setHostName(clsLEAMDNSHost::indexDomainName(p_pcDomainName, "-", 0));
}
})) {
Serial.println("mDNS-AP started");
} else {
Serial.println("FAILED to start mDNS-AP");
}
// Setup HTTP server
server.on("/", handleHTTPRequest);
server.begin();
Serial.println("HTTP server started");
}
/*
loop
*/
void loop(void) {
// Check if a request has come in
server.handleClient();
// Allow MDNS processing
MDNSRESP.update();
static esp8266::polledTimeout::periodicMs timeout(UPDATE_CYCLE);
if (timeout.expired()) {
if (hMDNSService) {
// Just trigger a new MDNS announcement, this will lead to a call to
// 'MDNSDynamicServiceTxtCallback', which will update the time TXT item
Serial.printf("Announce trigger from user\n");
MDNSRESP.announce();
}
}
static bool AP_started = false;
if (!AP_started && millis() > START_AP_AFTER_MS) {
AP_started = true;
Serial.printf("Starting AP...\n");
WiFi.mode(WIFI_AP_STA);
WiFi.softAP(APSSID, APPSK);
Serial.printf("AP started...(%s:%s, %s)\n",
WiFi.softAPSSID().c_str(),
WiFi.softAPPSK().c_str(),
WiFi.softAPIP().toString().c_str());
}
}

View File

@ -33,19 +33,6 @@
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.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>
/*

View File

@ -0,0 +1,259 @@
/*
ESP8266 mDNS Responder Service Monitor
This example demonstrates two features of the LEA clsLEAMDNSHost:
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.
*/
// THIS IS A WORK IN PROGRESS: some TODOs need completion
#ifndef STASSID
#define STASSID "ssid"
#define STAPSK "psk"
#endif
#ifndef APSSID
#define APSSID "esp8266"
//#define APPSK "psk"
#endif
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#define NO_GLOBAL_MDNS // our MDNS is defined below
#include <ESP8266mDNS.h>
/*
Global defines and vars
*/
#define SERVICE_PORT 80 // HTTP port
clsLEAMDNSHost MDNS; // MDNS responder
char* pcHostDomain = 0; // Negociated host domain
bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain
clsLEAMDNSHost::clsService* hMDNSService = 0; // The handle of the http service in the MDNS responder
clsLEAMDNSHost::clsQuery* 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;
// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests
ESP8266WebServer 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;
}
return false;
}
void MDNSServiceQueryCallback(const clsLEAMDNSHost::clsQuery& p_Query,
const clsLEAMDNSHost::clsQuery::clsAnswer& p_Answer,
clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags,
bool p_bSetContent) {
(void)p_Query;
String answerInfo;
switch (p_QueryAnswerTypeFlags) {
case static_cast<clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType>(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain):
answerInfo = "ServiceDomain " + String(p_Answer.m_ServiceDomain.c_str());
break;
case static_cast<clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType>(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::HostDomainPort):
answerInfo = "HostDomainAndPort " + String(p_Answer.m_HostDomain.c_str()) + ":" + String(p_Answer.m_u16Port);
break;
case static_cast<clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType>(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address):
answerInfo = "IP4Address ";
for (auto ip : p_Answer.m_IPv4Addresses) {
answerInfo += "- " + ip->m_IPAddress.toString();
};
break;
case static_cast<clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType>(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Txts):
answerInfo = "TXT ";
for (auto kv : p_Answer.m_Txts.m_Txts) {
answerInfo += "\nkv : " + String(kv->m_pcKey) + " : " + String(kv->m_pcValue);
}
break;
default :
answerInfo = "Unknown Answertype " + String(p_QueryAnswerTypeFlags);
}
Serial.printf("Answer %s %s\n", answerInfo.c_str(), p_bSetContent ? "Modified" : "Deleted");
}
/*
MDNSServiceProbeResultCallback
Probe result callback for Services
*/
void serviceProbeResult(clsLEAMDNSHost::clsService& p_rMDNSService,
const char* p_pcInstanceName,
bool p_bProbeResult) {
(void)p_rMDNSService;
Serial.printf("MDNSServiceProbeResultCallback: Service %s probe %s\n", p_pcInstanceName, (p_bProbeResult ? "succeeded." : "failed!"));
}
/*
MDNSHostProbeResultCallback
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_pclsLEAMDNSHost->setHostname().
*/
void hostProbeResult(clsLEAMDNSHost & p_rMDNSHost, String p_pcDomainName, bool p_bProbeResult) {
(void)p_rMDNSHost;
Serial.printf("MDNSHostProbeResultCallback: Host domain '%s.local' is %s\n", p_pcDomainName.c_str(), (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 = MDNS.addService(0, "http", "tcp", SERVICE_PORT, serviceProbeResult);
if (hMDNSService) {
hMDNSService->setProbeResultCallback(serviceProbeResult);
// MDNS.setServiceProbeResultCallback(hMDNSService, serviceProbeResult);
// Add some '_http._tcp' protocol specific MDNS service TXT items
// See: http://www.dns-sd.org/txtrecords.html#http
hMDNSService->addServiceTxt("user", "");
hMDNSService->addServiceTxt("password", "");
hMDNSService->addServiceTxt("path", "/");
}
// Install dynamic 'http.tcp' service query
if (!hMDNSServiceQuery) {
hMDNSServiceQuery = MDNS.installServiceQuery("http", "tcp", MDNSServiceQueryCallback);
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
MDNS.setHostName(clsLEAMDNSHost::indexDomainName(p_pcDomainName.c_str(), "-", 0));
}
}
/*
HTTP request function (not found is handled by server)
*/
void handleHTTPRequest() {
Serial.println("");
Serial.println("HTTP Request");
IPAddress ip = server.client().localIP();
String ipStr = ip.toString();
String s;
s.reserve(200 /* + service listed */);
s = "<!DOCTYPE HTML>\r\n<html><h3><head>Hello from ";
s += WiFi.hostname() + ".local at " + server.client().localIP().toString() + "</h3></head>";
s += "<br/><h4>Local HTTP services are :</h4>";
s += "<ol>";
// TODO: list services
s += "</ol><br/>";
Serial.println("Sending 200");
server.send(200, "text/html", s);
Serial.println("Done with request");
}
/*
setup
*/
void setup(void) {
Serial.begin(115200);
Serial.setDebugOutput(false);
Serial.println("");
Serial.println("THIS IS A WORK IN PROGRESS: some TODOs need completion");
Serial.println("");
// Connect to WiFi network
WiFi.mode(WIFI_AP_STA);
WiFi.softAP(APSSID);
WiFi.begin(STASSID, STAPSK);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(STASSID);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Setup HTTP server
server.on("/", handleHTTPRequest);
// Setup MDNS responders
MDNS.setProbeResultCallback(hostProbeResult);
// Init the (currently empty) host domain string with 'leamdnsv2'
MDNS.begin("leamdnsv2");
Serial.println("MDNS responder started");
// Start HTTP server
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
// Check if a request has come in
server.handleClient();
// Allow MDNS processing
MDNS.update();
}

View File

@ -12,33 +12,38 @@
*/
#ifndef APSSID
#define APSSID "your-apssid"
#define APPSK "your-password"
#endif
#ifndef STASSID
#define STASSID "your-ssid"
#define STASSID "your-sta"
#define STAPSK "your-password"
#endif
// includes
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <FS.h>
#include <LittleFS.h>
#include <ArduinoOTA.h>
#include <ESP8266mDNS.h>
/**
@brief mDNS and OTA Constants
@{
*/
#define HOSTNAME "ESP8266-OTA-" ///< Hostename. The setup function adds the Chip ID at the end.
#define HOSTNAME "ESP8266-OTA-" ///< Hostname. The setup function adds the Chip ID at the end.
/// @}
/**
@brief Default WiFi connection information.
@{
*/
const char* ap_default_ssid = STASSID; ///< Default SSID.
const char* ap_default_psk = STAPSK; ///< Default PSK.
const char* ap_default_ssid = APSSID; ///< Default SSID.
const char* ap_default_psk = APPSK; ///< Default PSK.
/// @}
/// Uncomment the next line for verbose output over UART.
@ -166,8 +171,8 @@ void setup() {
// Load wifi connection information.
if (! loadConfig(&station_ssid, &station_psk)) {
station_ssid = "";
station_psk = "";
station_ssid = STASSID;
station_psk = STAPSK;
Serial.println("No WiFi connection information available.");
}

View File

@ -1,3 +1,25 @@
/*
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 <ESP8266mDNS.h>
/*

View File

@ -10,7 +10,7 @@
- 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)
- 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)
@ -42,15 +42,18 @@
*/
#include "ESP8266mDNS_Legacy.h"
#include "LEAmDNS.h"
enum class MDNSApiVersion { LEA, LEAv2 };
#include "LEAmDNS.h" // LEA
#include "LEAmDNS2Host.h" // LEAv2 - API updated
// clsLEAMDNSHost replaces MDNSResponder in LEAv2
using clsLEAMDNSHost = esp8266::experimental::clsLEAMDNSHost;
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
// Maps the implementation to use to the global namespace type
//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; //legacy
using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new
using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; // LEA
//using MDNSResponder = clsLEAMDNSHost; // LEAv2
extern MDNSResponder MDNS;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,166 +0,0 @@
/*
ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
Version 1.1
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
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.
Requirements:
- ESP8266WiFi library
Usage:
- Include the ESP8266 Multicast DNS library in the sketch.
- Call the begin method in the sketch's setup and provide a domain name (without
the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the
Adafruit CC3000 class instance. Optionally provide a time to live (in seconds)
for the DNS record--the default is 1 hour.
- Call the update method in each iteration of the sketch's loop function.
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 ESP8266MDNS_LEGACY_H
#define ESP8266MDNS_LEGACY_H
#include "ESP8266WiFi.h"
#include "WiFiUdp.h"
//this should be defined at build time
#ifndef ARDUINO_BOARD
#define ARDUINO_BOARD "generic"
#endif
class UdpContext;
namespace Legacy_MDNSResponder
{
struct MDNSService;
struct MDNSTxt;
struct MDNSAnswer;
class MDNSResponder
{
public:
MDNSResponder();
~MDNSResponder();
bool begin(const char* hostName);
bool begin(const String& hostName)
{
return begin(hostName.c_str());
}
//for compatibility
bool begin(const char* hostName, IPAddress ip, uint32_t ttl = 120)
{
(void) ip;
(void) ttl;
return begin(hostName);
}
bool begin(const String& hostName, IPAddress ip, uint32_t ttl = 120)
{
return begin(hostName.c_str(), ip, ttl);
}
/* Application should call this whenever AP is configured/disabled */
void notifyAPChange();
void update();
void addService(char *service, char *proto, uint16_t port);
void addService(const char *service, const char *proto, uint16_t port)
{
addService((char *)service, (char *)proto, port);
}
void addService(const String& service, const String& proto, uint16_t port)
{
addService(service.c_str(), proto.c_str(), port);
}
bool addServiceTxt(char *name, char *proto, char * key, char * value);
bool addServiceTxt(const char *name, const char *proto, const char *key, const char * value)
{
return addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
}
bool addServiceTxt(const String& name, const String& proto, const String& key, const String& value)
{
return addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
}
int queryService(char *service, char *proto);
int queryService(const char *service, const char *proto)
{
return queryService((char *)service, (char *)proto);
}
int queryService(const String& service, const String& proto)
{
return queryService(service.c_str(), proto.c_str());
}
String hostname(int idx);
IPAddress IP(int idx);
uint16_t port(int idx);
void enableArduino(uint16_t port, bool auth = false);
void setInstanceName(String name);
void setInstanceName(const char * name)
{
setInstanceName(String(name));
}
void setInstanceName(char * name)
{
setInstanceName(String(name));
}
private:
struct MDNSService * _services;
UdpContext* _conn;
String _hostName;
String _instanceName;
struct MDNSAnswer * _answers;
struct MDNSQuery * _query;
bool _newQuery;
bool _waitingForAnswers;
WiFiEventHandler _disconnectedHandler;
WiFiEventHandler _gotIPHandler;
uint16_t _getServicePort(char *service, char *proto);
MDNSTxt * _getServiceTxt(char *name, char *proto);
uint16_t _getServiceTxtLen(char *name, char *proto);
IPAddress _getRequestMulticastInterface();
void _parsePacket();
void _replyToTypeEnumRequest(IPAddress multicastInterface);
void _replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface);
MDNSAnswer* _getAnswerFromIdx(int idx);
int _getNumAnswers();
bool _listen();
void _restart();
};
} // namespace Legacy_MDNSResponder
#endif //ESP8266MDNS_H

View File

@ -25,6 +25,7 @@
#include <Schedule.h>
#include <AddrList.h>
#include "ESP8266mDNS.h"
#include "LEAmDNS_Priv.h"

View File

@ -14,7 +14,7 @@
- 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)
- 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)
@ -172,6 +172,7 @@ class MDNSResponder
{
public:
/* INTERFACE */
MDNSResponder(void);
virtual ~MDNSResponder(void);

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,328 @@
/*
LEAmDNS2Host_Debug.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.
*/
#include "ESP8266mDNS.h"
#include "LEAmDNS2Host.h"
#include "LEAmDNS2_Priv.h"
namespace esp8266
{
namespace experimental
{
#ifdef DEBUG_ESP_PORT
/*
clsLEAmDNS2_Host::_DH
*/
const char* clsLEAMDNSHost::_DH(const clsLEAMDNSHost::clsService* p_pService /*= 0*/) const
{
static char acBuffer[16 + 64];
*acBuffer = 0;
sprintf_P(acBuffer, PSTR("[mDNS]"));
if (p_pService)
{
strcat_P(acBuffer, PSTR(">"));
strcat(acBuffer, _service2String(p_pService));
}
return acBuffer;
}
/*
clsLEAmDNS2_Host::_service2String
*/
const char* clsLEAMDNSHost::_service2String(const clsLEAMDNSHost::clsService* p_pService) const
{
static char acBuffer[64];
*acBuffer = 0;
if (p_pService)
{
sprintf_P(acBuffer, PSTR("%s.%s%s.%s%s.local"),
(p_pService->m_pcInstanceName ? : "-"),
(p_pService->m_pcType ? ('_' == *(p_pService->m_pcType) ? "" : "_") : "-"),
(p_pService->m_pcType ? : "-"),
(p_pService->m_pcProtocol ? ('_' == *(p_pService->m_pcProtocol) ? "" : "_") : "-"),
(p_pService->m_pcProtocol ? : "-"));
}
return acBuffer;
}
/*
clsLEAmDNS2_Host::_printRRDomain
*/
bool clsLEAMDNSHost::_printRRDomain(const clsLEAMDNSHost::clsRRDomain& p_RRDomain) const
{
//DEBUG_OUTPUT.printf_P(PSTR("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("%c"), *(pCursor++));
}
u8Length = *pCursor++;
if (u8Length)
{
DEBUG_OUTPUT.printf_P(PSTR("."));
}
}
}
else // empty domain
{
DEBUG_OUTPUT.printf_P(PSTR("-empty-"));
}
//DEBUG_OUTPUT.printf_P(PSTR("\n"));
return true;
}
/*
clsLEAmDNS2_Host::_printRRAnswer
*/
bool clsLEAMDNSHost::_printRRAnswer(const clsLEAMDNSHost::clsRRAnswer& p_RRAnswer) const
{
DEBUG_OUTPUT.printf_P(PSTR("%s RRAnswer: "), _DH());
_printRRDomain(p_RRAnswer.m_Header.m_Domain);
DEBUG_OUTPUT.printf_P(PSTR(" 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_IPV4_SUPPORT
case DNS_RRTYPE_A:
DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((const clsRRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str());
break;
#endif
case DNS_RRTYPE_PTR:
DEBUG_OUTPUT.printf_P(PSTR("PTR "));
_printRRDomain(((const clsRRAnswerPTR*)&p_RRAnswer)->m_PTRDomain);
break;
case DNS_RRTYPE_TXT:
{
size_t stTxtLength = ((const clsRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength();
char* pTxts = new char[stTxtLength];
if (pTxts)
{
((/*const c_str()!!*/clsRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts);
DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts);
delete[] pTxts;
}
break;
}
#ifdef MDNS_IPV6_SUPPORT
case DNS_RRTYPE_AAAA:
DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((clsRRAnswerAAAA*&)p_RRAnswer)->m_IPAddress.toString().c_str());
break;
#endif
case DNS_RRTYPE_SRV:
DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((const clsRRAnswerSRV*)&p_RRAnswer)->m_u16Port);
_printRRDomain(((const clsRRAnswerSRV*)&p_RRAnswer)->m_SRVDomain);
break;
default:
DEBUG_OUTPUT.printf_P(PSTR("generic "));
break;
}
DEBUG_OUTPUT.printf_P(PSTR("\n"));
return true;
}
/*
clsLEAmDNS2_Host::_RRType2Name
*/
const char* clsLEAMDNSHost::_RRType2Name(uint16_t p_u16RRType) const
{
static char acRRName[16];
*acRRName = 0;
switch (p_u16RRType & (~0x8000)) // Topmost bit might carry 'cache flush' flag
{
#ifdef MDNS_IPV4_SUPPORT
case DNS_RRTYPE_A: strcpy_P(acRRName, PSTR("A")); break;
#endif
case DNS_RRTYPE_PTR: strcpy_P(acRRName, PSTR("PTR")); break;
case DNS_RRTYPE_TXT: strcpy_P(acRRName, PSTR("TXT")); break;
#ifdef MDNS_IPV6_SUPPORT
case DNS_RRTYPE_AAAA: strcpy_P(acRRName, PSTR("AAAA")); break;
#endif
case DNS_RRTYPE_SRV: strcpy_P(acRRName, PSTR("SRV")); break;
case clsConsts::u8DNS_RRTYPE_NSEC: strcpy_P(acRRName, PSTR("NSEC")); break;
case DNS_RRTYPE_ANY: strcpy_P(acRRName, PSTR("ANY")); break;
default: sprintf_P(acRRName, PSTR("Unknown(0x%04X"), p_u16RRType); // MAX 15!
}
return acRRName;
}
/*
clsLEAmDNS2_Host::_RRClass2String
*/
const char* clsLEAMDNSHost::_RRClass2String(uint16_t p_u16RRClass,
bool p_bIsQuery) const
{
static char acClassString[16];
*acClassString = 0;
if (p_u16RRClass & 0x0001)
{
strcat_P(acClassString, PSTR("IN ")); // 3
}
if (p_u16RRClass & 0x8000)
{
strcat_P(acClassString, (p_bIsQuery ? PSTR("UNICAST ") : PSTR("FLUSH "))); // 8/6
}
return acClassString; // 11
}
/*
clsLEAmDNS2_Host::_replyFlags2String
*/
const char* clsLEAMDNSHost::_replyFlags2String(uint32_t p_u32ReplyFlags) const
{
static char acFlagsString[64];
*acFlagsString = 0;
if (p_u32ReplyFlags & static_cast<uint32_t>(enuContentFlag::A))
{
strcat_P(acFlagsString, PSTR("A ")); // 2
}
if (p_u32ReplyFlags & static_cast<uint32_t>(enuContentFlag::PTR_IPv4))
{
strcat_P(acFlagsString, PSTR("PTR_IPv4 ")); // 7
}
if (p_u32ReplyFlags & static_cast<uint32_t>(enuContentFlag::PTR_IPv6))
{
strcat_P(acFlagsString, PSTR("PTR_IPv6 ")); // 7
}
if (p_u32ReplyFlags & static_cast<uint32_t>(enuContentFlag::AAAA))
{
strcat_P(acFlagsString, PSTR("AAAA ")); // 5
}
if (p_u32ReplyFlags & static_cast<uint32_t>(enuContentFlag::PTR_TYPE))
{
strcat_P(acFlagsString, PSTR("PTR_TYPE ")); // 9
}
if (p_u32ReplyFlags & static_cast<uint32_t>(enuContentFlag::PTR_NAME))
{
strcat_P(acFlagsString, PSTR("PTR_NAME ")); // 9
}
if (p_u32ReplyFlags & static_cast<uint32_t>(enuContentFlag::TXT))
{
strcat_P(acFlagsString, PSTR("TXT ")); // 4
}
if (p_u32ReplyFlags & static_cast<uint32_t>(enuContentFlag::SRV))
{
strcat_P(acFlagsString, PSTR("SRV ")); // 4
}
if (p_u32ReplyFlags & static_cast<uint32_t>(enuContentFlag::NSEC))
{
strcat_P(acFlagsString, PSTR("NSEC ")); // 5
}
if (0 == p_u32ReplyFlags)
{
strcpy_P(acFlagsString, PSTR("none"));
}
// Remove trailing spaces
while ((*acFlagsString) &&
(' ' == acFlagsString[strlen(acFlagsString) - 1]))
{
acFlagsString[strlen(acFlagsString) - 1] = 0;
}
return acFlagsString; // 63
}
/*
clsLEAmDNS2_Host::_NSECBitmap2String
*/
const char* clsLEAMDNSHost::_NSECBitmap2String(const clsNSECBitmap* p_pNSECBitmap) const
{
static char acFlagsString[32];
*acFlagsString = 0;
#ifdef MDNS_IPV4_SUPPORT
if (p_pNSECBitmap->getBit(DNS_RRTYPE_A))
{
strcat_P(acFlagsString, PSTR("A ")); // 2
}
#endif
if (p_pNSECBitmap->getBit(DNS_RRTYPE_PTR))
{
strcat_P(acFlagsString, PSTR("PTR ")); // 4
}
#ifdef MDNS_IPV6_SUPPORT
if (p_pNSECBitmap->getBit(DNS_RRTYPE_AAAA))
{
strcat_P(acFlagsString, PSTR("AAAA ")); // 5
}
#endif
if (p_pNSECBitmap->getBit(DNS_RRTYPE_TXT))
{
strcat_P(acFlagsString, PSTR("TXT ")); // 4
}
if (p_pNSECBitmap->getBit(DNS_RRTYPE_SRV))
{
strcat_P(acFlagsString, PSTR("SRV ")); // 4
}
if (p_pNSECBitmap->getBit(clsConsts::u8DNS_RRTYPE_NSEC))
{
strcat_P(acFlagsString, PSTR("NSEC ")); // 5
}
if (!*acFlagsString)
{
strcpy_P(acFlagsString, PSTR("none"));
}
return acFlagsString; // 31
}
#endif // DEBUG_ESP_PORT
} // namespace MDNSImplementation
} // namespace esp8266

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,262 @@
/*
LEAmDNS2_Backbone.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 "ESP8266mDNS.h"
#include "LEAmDNS2Host.h"
#include "LEAmDNS2_Priv.h"
namespace esp8266
{
namespace experimental
{
/*
clsLEAmDNS2_Host::clsBackbone::clsBackbone constructor
*/
clsLEAMDNSHost::clsBackbone::clsBackbone(void)
: m_pUDPContext(0),
m_bDelayUDPProcessing(false),
m_u32DelayedDatagrams(0),
m_uniqueHost(0)
{
}
/*
clsLEAmDNS2_Host::clsBackbone::clsBackbone destructor
*/
clsLEAMDNSHost::clsBackbone::~clsBackbone(void)
{
_releaseUDPContext();
}
/*
clsLEAmDNS2_Host::clsBackbone::init
*/
bool clsLEAMDNSHost::clsBackbone::init(void)
{
return _allocUDPContext();
}
/*
clsLEAmDNS2_Host::clsBackbone::addHost
*/
UdpContext* clsLEAMDNSHost::clsBackbone::addHost(clsLEAMDNSHost* p_pHost)
{
UdpContext* pUDPContext = nullptr;
if ((m_pUDPContext) && (p_pHost) && (m_uniqueHost == nullptr))
{
m_uniqueHost = p_pHost;
pUDPContext = m_pUDPContext;
}
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s addHost: %s to add host!\n"), _DH(), (pUDPContext ? "Succeeded" : "FAILED")););
return pUDPContext;
}
/*
clsLEAmDNS2_Host::clsBackbone::removeHost
*/
bool clsLEAMDNSHost::clsBackbone::removeHost(clsLEAMDNSHost* p_pHost)
{
bool bResult = false;
if ((p_pHost) && (m_uniqueHost == p_pHost))
{
m_uniqueHost = nullptr;
bResult = true;
}
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s removeHost: %s to remove host!\n"), _DH(), (bResult ? "Succeeded" : "FAILED")););
return bResult;
}
/*
clsLEAmDNS2_Host::clsBackbone::hostCount
*/
size_t clsLEAMDNSHost::clsBackbone::hostCount(void) const
{
return m_uniqueHost == nullptr ? 0 : 1;
}
/*
clsLEAMDNSHost::clsBackbone::::setDelayUDPProcessing
When executing _sendMessage, with multiple or larger messages, sometimes the ESP IP stack seems
to need a small delay to get the job done. To allow for this delay, a 'delay' was added after one
send operation. However, while 'taking' this delay, sometimes a UDP datagram is received and
processed (which might cause another send operation or change global states).
To avoid 're-entry-like' problems, UDP processing might be blocked for a short period of time.
*/
bool clsLEAMDNSHost::clsBackbone::setDelayUDPProcessing(bool p_bDelayUDPProcessing)
{
if (m_bDelayUDPProcessing != p_bDelayUDPProcessing)
{
m_bDelayUDPProcessing = p_bDelayUDPProcessing;
if ((!m_bDelayUDPProcessing) &&
(m_u32DelayedDatagrams))
{
DEBUG_EX_INFO2(if (6 <= m_u32DelayedDatagrams) DEBUG_OUTPUT.printf_P(PSTR("%s setDelayUDPProcessing: Processing %u delayed datagram(s)\n"), _DH(), m_u32DelayedDatagrams););
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s setDelayUDPProcessing: Processing %u delayed datagram(s)\n"), _DH(), m_u32DelayedDatagrams););
_processUDPInput();
}
m_u32DelayedDatagrams = 0;
}
return true;
}
/*
clsLEAmDNS2_Host::clsBackbone::_allocUDPContext
*/
bool clsLEAMDNSHost::clsBackbone::_allocUDPContext(void)
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext\n"), _DH()););
if (_releaseUDPContext())
{
m_pUDPContext = new UdpContext;
if (m_pUDPContext)
{
m_pUDPContext->ref();
//ip_set_option(m_pUDPContext->pcb(), SOF_REUSEADDR);
//udp_bind_netif(m_pUDPContext->pcb(), m_pNetIf);
if (m_pUDPContext->listen(IP_ANY_TYPE, DNS_MQUERY_PORT))
{
// 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), however, RFC 3171 seems to force 255 instead
const uint8_t c_u8MulticastTTL = 255;//1;//255;
m_pUDPContext->setMulticastTTL(c_u8MulticastTTL);
m_pUDPContext->onRx(std::bind(&clsLEAMDNSHost::clsBackbone::_processUDPInput, this));
/* m_pUDPContext->onRx([&](void)->void
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext::onRx Received data!\n"), _DH()););
});*/
m_pUDPContext->connect(IP_ANY_TYPE, DNS_MQUERY_PORT);
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: Succeeded to alloc UDPContext!\n"), _DH()););
}
else
{
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to make UDPContext listening!\n"), _DH()););
_releaseUDPContext();
}
}
else
{
DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to alloc UDPContext!\n"), _DH()););
}
}
DEBUG_EX_ERR(if (!m_pUDPContext) DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED!\n"), _DH()););
return (0 != m_pUDPContext);
}
/*
clsLEAmDNS2_Host::clsBackbone::_releaseUDPContext
*/
bool clsLEAMDNSHost::clsBackbone::_releaseUDPContext(void)
{
if (m_pUDPContext)
{
m_pUDPContext->unref();
m_pUDPContext = nullptr;
}
return true;
}
/*
clsLEAmDNS2_Host::clsBackbone::_processUDPInput
Called in SYS context!
*/
bool clsLEAMDNSHost::clsBackbone::_processUDPInput(void)
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput\n"), _DH()););
bool bResult = true;
if (!m_bDelayUDPProcessing)
{
while ((m_pUDPContext) &&
(m_pUDPContext->next()))
{
clsLEAMDNSHost* pHost = _findHost();
bResult = pHost->_processUDPInput();
DEBUG_EX_INFO2_IF(!bResult,
DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: FAILED to process UDP input!\n"), _DH()));
DEBUG_EX_ERR_IF((-1) != m_pUDPContext->peek(),
DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: !!!! CONTENT LEFT IN UDP BUFFER !!!!\n"),
_DH()));
m_pUDPContext->flush();
}
}
else
{
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Delaying datagram!\n"), _DH()););
++m_u32DelayedDatagrams;
}
return bResult;
}
/*
MISC
*/
#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_PORT
/*
clsLEAmDNS2_Host::clsBackbone::_DH
*/
const char* clsLEAMDNSHost::clsBackbone::_DH(void) const
{
static char acBuffer[20] = { 0, };
if (!acBuffer[0])
{
strcpy_P(acBuffer, PSTR("[mDNS::backbone]"));
}
return acBuffer;
}
#endif
} // namespace MDNSImplementation
} // namespace esp8266

View File

@ -0,0 +1,115 @@
/*
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 MDNS2_PRIV_H
#define MDNS2_PRIV_H
/*
LWIP_OPEN_SRC
*/
#ifndef LWIP_OPEN_SRC
#define LWIP_OPEN_SRC
#endif
/*
Enable class debug functions
*/
#define ESP_8266_MDNS_INCLUDE
//#define DEBUG_ESP_MDNS_RESPONDER // force debug, arduino IDE uses DEBUG_ESP_MDNS
/*
Enable/disable debug trace macros
*/
#if defined(DEBUG_ESP_PORT)
#define DEBUG_ESP_MDNS_ERR
#endif
#if defined(DEBUG_ESP_PORT) && (defined(DEBUG_ESP_MDNS) || defined(DEBUG_ESP_MDNS_RESPONDER))
#define DEBUG_ESP_MDNS_INFO
#define DEBUG_ESP_MDNS_INFO2
//#define DEBUG_ESP_MDNS_TX
//#define DEBUG_ESP_MDNS_RX
#endif
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serialx
#endif
#ifdef DEBUG_ESP_MDNS_INFO
#define DEBUG_EX_INFO(A) A
#define DEBUG_EX_INFO_IF(C,A...) do if (C) { A; } while (0)
#else
#define DEBUG_EX_INFO(A)
#define DEBUG_EX_INFO_IF(C,A...)
#endif
#ifdef DEBUG_ESP_MDNS_INFO2
#define DEBUG_EX_INFO2(A) A
#define DEBUG_EX_INFO2_IF(C,A...) do if (C) { A; } while (0)
#else
#define DEBUG_EX_INFO2(A)
#define DEBUG_EX_INFO2_IF(C,A...)
#endif
#ifdef DEBUG_ESP_MDNS_ERR
#define DEBUG_EX_ERR(A) A
#define DEBUG_EX_ERR_IF(C,A...) do if (C) { A; } while (0)
#else
#define DEBUG_EX_ERR(A)
#define DEBUG_EX_ERR_IF(C,A...)
#endif
#ifdef DEBUG_ESP_MDNS_TX
#define DEBUG_EX_TX(A) do { A; } while (0)
#else
#define DEBUG_EX_TX(A)
#endif
#ifdef DEBUG_ESP_MDNS_RX
#define DEBUG_EX_RX(A) do { A; } while (0)
#else
#define DEBUG_EX_RX(A)
#endif
/*
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
#else
#ifdef F
#undef F
#endif
#define F(A) A
#endif
#endif // MDNS2_PRIV_H

View File

@ -0,0 +1,31 @@
/*
LEAmDNS2_lwIPdefs.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 LEAMDNS2_LWIPDEFS_H
#define LEAMDNS2_LWIPDEFS_H
#include <lwip/init.h>
#include <lwip/prot/dns.h> // DNS_RRTYPE_xxx, DNS_MQUERY_PORT
#endif // LEAMDNS2_LWIPDEFS_H

View File

@ -37,6 +37,7 @@ extern "C" {
#include "user_interface.h"
}
#include "ESP8266mDNS.h"
#include "LEAmDNS_lwIPdefs.h"
#include "LEAmDNS_Priv.h"
@ -1982,7 +1983,7 @@ bool MDNSResponder::_checkServiceQueryCache(void)
/*
MDNSResponder::_replyMaskForHost
Determines the relavant host answers for the given question.
Determines the relevant host answers for the given question.
- A question for the hostname (eg. esp8266.local) will result in an A/AAAA (eg. 192.168.2.129) reply.
- A question for the reverse IP address (eg. 192-168.2.120.inarpa.arpa) will result in an PTR_IP4 (eg. esp8266.local) reply.

View File

@ -22,55 +22,13 @@
*/
#include "lwip/igmp.h"
#include <lwip/igmp.h>
#include <stdlib_noniso.h> // strrstr()
#include "ESP8266mDNS.h"
#include "LEAmDNS_lwIPdefs.h"
#include "LEAmDNS_Priv.h"
namespace
{
/*
strrstr (static)
Backwards search for p_pcPattern in p_pcString
Based on: https://stackoverflow.com/a/1634398/2778898
*/
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;
}
} // anonymous
namespace esp8266
{

View File

@ -53,7 +53,7 @@ namespace MDNSImplementation
//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
// Enable/disable debug trace macros
#ifdef DEBUG_ESP_MDNS_RESPONDER
#if defined(DEBUG_ESP_PORT) && defined(DEBUG_ESP_MDNS_RESPONDER)
#define DEBUG_ESP_MDNS_INFO
#define DEBUG_ESP_MDNS_ERR
#define DEBUG_ESP_MDNS_TX
@ -64,22 +64,22 @@ namespace MDNSImplementation
#ifdef DEBUG_ESP_MDNS_INFO
#define DEBUG_EX_INFO(A) A
#else
#define DEBUG_EX_INFO(A) do { (void)0; } while (0)
#define DEBUG_EX_INFO(A)
#endif
#ifdef DEBUG_ESP_MDNS_ERR
#define DEBUG_EX_ERR(A) A
#else
#define DEBUG_EX_ERR(A) do { (void)0; } while (0)
#define DEBUG_EX_ERR(A)
#endif
#ifdef DEBUG_ESP_MDNS_TX
#define DEBUG_EX_TX(A) A
#else
#define DEBUG_EX_TX(A) do { (void)0; } while (0)
#define DEBUG_EX_TX(A)
#endif
#ifdef DEBUG_ESP_MDNS_RX
#define DEBUG_EX_RX(A) A
#else
#define DEBUG_EX_RX(A) do { (void)0; } while (0)
#define DEBUG_EX_RX(A)
#endif
#ifdef DEBUG_ESP_PORT

View File

@ -22,6 +22,7 @@
*/
#include "ESP8266mDNS.h"
#include "LEAmDNS_Priv.h"
#include "LEAmDNS_lwIPdefs.h"
@ -787,7 +788,7 @@ bool MDNSResponder::stcMDNS_RRDomain::compare(const stcMDNS_RRDomain& p_Other) c
{
if (*((unsigned char*)pT)) // Not 0
{
pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and lenght
pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and length
pO += (1 + * ((unsigned char*)pO));
}
else // Is 0 -> Successfully reached the end

View File

@ -26,6 +26,7 @@ extern "C" {
#include "user_interface.h"
}
#include "ESP8266mDNS.h"
#include "LEAmDNS_lwIPdefs.h"
#include "LEAmDNS_Priv.h"

View File

@ -295,6 +295,12 @@ OPT_ARDUINO_LIBS ?= $(addprefix ../../libraries/,\
LEAmDNS_Structs.cpp \
LEAmDNS_Transfer.cpp \
ESP8266mDNS.cpp \
LEAmDNS2Host.cpp \
LEAmDNS2Host_Control.cpp \
LEAmDNS2Host_Debug.cpp \
LEAmDNS2Host_Structs.cpp \
LEAmDNS2Host_Transfer.cpp \
LEAmDNS2_Backbone.cpp \
) \
ArduinoOTA/ArduinoOTA.cpp \
DNSServer/src/DNSServer.cpp \

View File

@ -270,3 +270,10 @@ extern "C" void configTime(long timezone, int daylightOffset_sec,
#include "pins_arduino.h"
#endif /* Arduino_h */
#if __cplusplus
#include <WString.h>
#include <map>
#define MOCKARGS 1
extern std::map<String,String> mockArgs;
#endif

View File

@ -56,6 +56,8 @@ const char* fspath = nullptr;
static struct termios initial_settings;
std::map<String,String> mockArgs;
int mockverbose (const char* fmt, ...)
{
va_list ap;
@ -135,6 +137,8 @@ void help (const char* argv0, int exitcode)
"\t-S - spiffs size in KBytes (default: %zd)\n"
"\t-L - littlefs size in KBytes (default: %zd)\n"
"\t (spiffs, littlefs: negative value will force mismatched size)\n"
"\t-K - key\n"
"\t-V - value\n"
"\tgeneral:\n"
"\t-c - ignore CTRL-C (send it via Serial)\n"
"\t-f - no throttle (possibly 100%%CPU)\n"
@ -158,6 +162,8 @@ static struct option options[] =
{ "spiffskb", required_argument, NULL, 'S' },
{ "littlefskb", required_argument, NULL, 'L' },
{ "portshifter", required_argument, NULL, 's' },
{ "key", required_argument, NULL, 'K' },
{ "value", required_argument, NULL, 'V' },
{ "once", no_argument, NULL, '1' },
};
@ -209,10 +215,11 @@ int main (int argc, char* const argv [])
mock_port_shifter = 0;
else
mock_port_shifter = MOCK_PORT_SHIFTER;
String key;
for (;;)
{
int n = getopt_long(argc, argv, "hlcfbvTi:S:s:L:P:1", options, NULL);
int n = getopt_long(argc, argv, "hlcfbvTi:S:s:L:P:1K:V:", options, NULL);
if (n < 0)
break;
switch (n)
@ -253,6 +260,12 @@ int main (int argc, char* const argv [])
case 'T':
serial_timestamp = true;
break;
case 'K':
key = optarg;
break;
case 'V':
mockArgs[key] = optarg;
break;
case '1':
run_once = true;
break;

View File

@ -29,11 +29,6 @@
DEALINGS WITH THE SOFTWARE.
*/
#include "lwip/opt.h"
#include "lwip/udp.h"
#include "lwip/inet.h"
#include "lwip/igmp.h"
#include "lwip/mem.h"
#include <include/UdpContext.h>
#include <poll.h>
#include <map>

View File

@ -1,6 +1,7 @@
#include <AddrList.h>
#include <lwip/netif.h>
#include "MocklwIP.h"
esp8266::AddressListImplementation::AddressList addrList;

View File

@ -0,0 +1,15 @@
#ifndef __MOCKLWIP_H
#define __MOCKLWIP_H
extern "C"
{
#include <user_interface.h>
#include <lwip/netif.h>
extern netif netif0;
} // extern "C"
#endif // __MOCKLWIP_H

View File

@ -1,28 +1,32 @@
/*
UdpContext.h - emulation of UDP connection handling on top of lwIP
UdpContext.h - emulation of UDP connection handling on top of lwIP
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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 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.
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
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
*/
#ifndef UDPCONTEXT_H
#define UDPCONTEXT_H
#include <functional>
#include <MocklwIP.h>
#include <IPAddress.h>
#include <PolledTimeout.h>
class UdpContext;
#define GET_IP_HDR(pb) reinterpret_cast<ip_hdr*>(((uint8_t*)((pb)->payload)) - UDP_HLEN - IP_HLEN);
@ -52,12 +56,13 @@ public:
void unref()
{
if(--_refcnt == 0) {
if (--_refcnt == 0)
{
delete this;
}
}
bool connect (const ip_addr_t* addr, uint16_t port)
bool connect(const ip_addr_t* addr, uint16_t port)
{
_dst = *addr;
_dstport = port;
@ -108,7 +113,8 @@ public:
// warning: handler is called from tcp stack context
// esp_yield and non-reentrant functions which depend on it will fail
void onRx(rxhandler_t handler) {
void onRx(rxhandler_t handler)
{
_on_rx = handler;
}
@ -132,11 +138,12 @@ public:
mockUDPSwallow(pos, _inbuf, _inbufsize);
}
bool isValidOffset(const size_t pos) const {
bool isValidOffset(const size_t pos) const
{
return pos <= _inbufsize;
}
uint32_t getRemoteAddress()
IPAddress getRemoteAddress()
{
return _dst.addr;
}
@ -146,7 +153,7 @@ public:
return _dstport;
}
uint32_t getDestAddress()
IPAddress getDestAddress()
{
mockverbose("TODO: implement UDP getDestAddress\n");
return 0; //ip_hdr* iphdr = GET_IP_HDR(_rx_buf);
@ -173,7 +180,7 @@ public:
int read()
{
char c;
return read(&c, 1)? c: -1;
return read(&c, 1) ? c : -1;
}
size_t read(char* dst, size_t size)
@ -184,7 +191,7 @@ public:
int peek()
{
char c;
return mockUDPPeekBytes(_sock, &c, 1, _timeout_ms, _inbuf, _inbufsize)?: -1;
return mockUDPPeekBytes(_sock, &c, 1, _timeout_ms, _inbuf, _inbufsize) ? : -1;
}
void flush()
@ -195,7 +202,7 @@ public:
_inbufsize = 0;
}
size_t append (const char* data, size_t size)
size_t append(const char* data, size_t size)
{
if (size + _outbufsize > sizeof _outbuf)
{
@ -208,16 +215,40 @@ public:
return size;
}
bool send (ip_addr_t* addr = 0, uint16_t port = 0)
err_t trySend(ip_addr_t* addr = 0, uint16_t port = 0, bool keepBuffer = true)
{
uint32_t dst = addr? addr->addr: _dst.addr;
uint16_t dstport = port?: _dstport;
size_t ret = mockUDPWrite(_sock, (const uint8_t*)_outbuf, _outbufsize, _timeout_ms, dst, dstport);
_outbufsize = 0;
return ret > 0;
uint32_t dst = addr ? addr->addr : _dst.addr;
uint16_t dstport = port ? : _dstport;
size_t wrt = mockUDPWrite(_sock, (const uint8_t*)_outbuf, _outbufsize, _timeout_ms, dst, dstport);
err_t ret = _outbufsize ? ERR_OK : ERR_ABRT;
if (!keepBuffer || wrt == _outbufsize)
cancelBuffer();
return ret;
}
void mock_cb (void)
void cancelBuffer()
{
_outbufsize = 0;
}
bool send(ip_addr_t* addr = 0, uint16_t port = 0)
{
return trySend(addr, port, false) == ERR_OK;
}
bool sendTimeout(ip_addr_t* addr, uint16_t port,
esp8266::polledTimeout::oneShotFastMs::timeType timeoutMs)
{
err_t err;
esp8266::polledTimeout::oneShotFastMs timeout(timeoutMs);
while (((err = trySend(addr, port)) != ERR_OK) && !timeout)
delay(0);
if (err != ERR_OK)
cancelBuffer();
return err == ERR_OK;
}
void mock_cb(void)
{
if (_on_rx) _on_rx();
}
@ -228,7 +259,7 @@ public:
private:
void translate_addr ()
void translate_addr()
{
if (addrsize == 4)
{
@ -260,7 +291,7 @@ private:
uint8_t addr[16];
};
extern "C" inline err_t igmp_joingroup (const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr)
extern "C" inline err_t igmp_joingroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr)
{
(void)ifaddr;
UdpContext::staticMCastAddr = groupaddr->addr;

View File

@ -39,6 +39,7 @@
#include <string.h>
#include <arpa/inet.h>
#include "MocklwIP.h"
extern "C"
{
@ -138,6 +139,7 @@ extern "C"
if (host_interface)
mockverbose("host: looking for interface '%s':\n", host_interface);
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next)
{
mockverbose("host: interface: %s", ifa->ifa_name);