mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-25 20:02:37 +03:00
commit
3fe8a642bc
@ -4,6 +4,8 @@ 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)
|
||||
MDNS-SD Suport 2015 Hristo Gochkov
|
||||
|
||||
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -34,14 +36,15 @@ License (MIT license):
|
||||
#include "ESP8266mDNS.h"
|
||||
#include <functional>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "debug.h"
|
||||
|
||||
extern "C" {
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "ip_addr.h"
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "WiFiUdp.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/udp.h"
|
||||
@ -52,131 +55,58 @@ extern "C"
|
||||
|
||||
|
||||
|
||||
//#define MDNS_DEBUG_ERR
|
||||
//#define MDNS_DEBUG_TX
|
||||
//#define MDNS_DEBUG_RX
|
||||
|
||||
// #define MDNS_DEBUG
|
||||
#define MDNS_NAME_REF 0xC000
|
||||
|
||||
#define HEADER_SIZE 12
|
||||
#define QDCOUNT_OFFSET 4
|
||||
#define A_RECORD_SIZE 14
|
||||
#define NSEC_RECORD_SIZE 20
|
||||
#define TTL_OFFSET 4
|
||||
#define IP_OFFSET 10
|
||||
#define MDNS_TYPE_AAAA 0x001C
|
||||
#define MDNS_TYPE_A 0x0001
|
||||
#define MDNS_TYPE_PTR 0x000C
|
||||
#define MDNS_TYPE_SRV 0x0021
|
||||
#define MDNS_TYPE_TXT 0x0010
|
||||
#define MDNS_TYPE_NSEC 0x002F
|
||||
|
||||
#define MDNS_CLASS_IN 0x0001
|
||||
#define MDNS_CLASS_IN_FLUSH_CACHE 0x8001
|
||||
|
||||
#define _conn_read32() (((uint32_t)_conn->read() << 24) | ((uint32_t)_conn->read() << 16) | ((uint32_t)_conn->read() << 8) | _conn->read())
|
||||
#define _conn_read16() (((uint16_t)_conn->read() << 8) | _conn->read())
|
||||
#define _conn_read8() _conn->read()
|
||||
#define _conn_readS(b,l) _conn->read((char*)(b),l);
|
||||
|
||||
static const IPAddress MDNS_MULTICAST_ADDR(224, 0, 0, 251);
|
||||
static const int MDNS_MULTICAST_TTL = 1;
|
||||
static const int MDNS_PORT = 5353;
|
||||
|
||||
MDNSResponder::MDNSResponder() : _conn(0) { _services = 0; }
|
||||
MDNSResponder::~MDNSResponder() {}
|
||||
|
||||
MDNSResponder::MDNSResponder()
|
||||
: _expected(NULL)
|
||||
, _expectedLen(0)
|
||||
, _response(NULL)
|
||||
, _responseLen(0)
|
||||
, _index(0)
|
||||
, _conn(0)
|
||||
{ }
|
||||
|
||||
MDNSResponder::~MDNSResponder() {
|
||||
if (_expected) {
|
||||
delete[] _expected;
|
||||
}
|
||||
if (_response) {
|
||||
delete[] _response;
|
||||
}
|
||||
}
|
||||
|
||||
bool MDNSResponder::begin(const char* domain, IPAddress addr, uint32_t ttlSeconds)
|
||||
{
|
||||
_localAddr = addr;
|
||||
// Construct DNS request/response fully qualified domain name of form:
|
||||
// <domain length>, <domain characters>, 5, "local"
|
||||
bool MDNSResponder::begin(const char* domain){
|
||||
// Open the MDNS socket if it isn't already open.
|
||||
|
||||
size_t n = strlen(domain);
|
||||
if (n > 255) {
|
||||
// Can only handle domains that are 255 chars in length.
|
||||
if (n > 255) { // Can only handle domains that are 255 chars in length.
|
||||
return false;
|
||||
}
|
||||
_expectedLen = 12 + n;
|
||||
if (_expected) {
|
||||
delete[] _expected;
|
||||
}
|
||||
_expected = new uint8_t[_expectedLen];
|
||||
_expected[0] = (uint8_t)n;
|
||||
|
||||
|
||||
// Copy in domain characters as lowercase
|
||||
for (int i = 0; i < n; ++i) {
|
||||
_expected[1+i] = tolower(domain[i]);
|
||||
}
|
||||
|
||||
// Values for:
|
||||
// - 5 (length)
|
||||
// - "local"
|
||||
// - 0x00 (end of domain)
|
||||
// - 0x00 0x01 (A record query)
|
||||
// - 0x00 0x01 (Class IN)
|
||||
const uint8_t local[] = { 0x05, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x00, 0x00, 0x01, 0x00, 0x01 };
|
||||
memcpy(&_expected[1+n], local, 11);
|
||||
|
||||
// Construct DNS query response
|
||||
// TODO: Move these to flash or just construct in code.
|
||||
const uint8_t respHeader[] = { 0x00, 0x00, // ID = 0
|
||||
0x84, 0x00, // Flags = response + authoritative answer
|
||||
0x00, 0x00, // Question count = 0
|
||||
0x00, 0x01, // Answer count = 1
|
||||
0x00, 0x00, // Name server records = 0
|
||||
0x00, 0x01 // Additional records = 1
|
||||
};
|
||||
// Generate positive response for IPV4 address
|
||||
const uint8_t aRecord[] = { 0x00, 0x01, // Type = 1, A record/IPV4 address
|
||||
0x80, 0x01, // Class = Internet, with cache flush bit
|
||||
0x00, 0x00, 0x00, 0x00, // TTL in seconds, to be filled in later
|
||||
0x00, 0x04, // Length of record
|
||||
0x00, 0x00, 0x00, 0x00 // IP address, to be filled in later
|
||||
};
|
||||
// Generate negative response for IPV6 address (CC3000 doesn't support IPV6)
|
||||
const uint8_t nsecRecord[] = { 0xC0, 0x0C, // Name offset
|
||||
0x00, 0x2F, // Type = 47, NSEC (overloaded by MDNS)
|
||||
0x80, 0x01, // Class = Internet, with cache flush bit
|
||||
0x00, 0x00, 0x00, 0x00, // TTL in seconds, to be filled in later
|
||||
0x00, 0x08, // Length of record
|
||||
0xC0, 0x0C, // Next domain = offset to FQDN
|
||||
0x00, // Block number = 0
|
||||
0x04, // Length of bitmap = 4 bytes
|
||||
0x40, 0x00, 0x00, 0x00 // Bitmap value = Only first bit (A record/IPV4) is set
|
||||
};
|
||||
|
||||
// Allocate memory for response.
|
||||
int queryFQDNLen = _expectedLen - 4;
|
||||
_responseLen = HEADER_SIZE + queryFQDNLen + A_RECORD_SIZE + NSEC_RECORD_SIZE;
|
||||
if (_response) {
|
||||
delete[] _response;
|
||||
}
|
||||
_response = new uint8_t[_responseLen];
|
||||
|
||||
// Copy data into response.
|
||||
memcpy(_response, respHeader, HEADER_SIZE);
|
||||
memcpy(_response + HEADER_SIZE, _expected, queryFQDNLen);
|
||||
uint8_t* records = _response + HEADER_SIZE + queryFQDNLen;
|
||||
memcpy(records, aRecord, A_RECORD_SIZE);
|
||||
memcpy(records + A_RECORD_SIZE, nsecRecord, NSEC_RECORD_SIZE);
|
||||
|
||||
// Add TTL to records.
|
||||
uint8_t ttl[4] = { (uint8_t)(ttlSeconds >> 24), (uint8_t)(ttlSeconds >> 16), (uint8_t)(ttlSeconds >> 8), (uint8_t)ttlSeconds };
|
||||
memcpy(records + TTL_OFFSET, ttl, 4);
|
||||
memcpy(records + A_RECORD_SIZE + 2 + TTL_OFFSET, ttl, 4);
|
||||
|
||||
// Add IP address to response
|
||||
|
||||
uint32_t ipAddress = (uint32_t) addr;
|
||||
|
||||
records[IP_OFFSET + 3] = (uint8_t)(ipAddress >> 24);
|
||||
records[IP_OFFSET + 2] = (uint8_t)(ipAddress >> 16);
|
||||
records[IP_OFFSET + 1] = (uint8_t)(ipAddress >> 8);
|
||||
records[IP_OFFSET + 0] = (uint8_t) ipAddress;
|
||||
for (int i = 0; i < n; ++i)
|
||||
_hostName[i] = tolower(domain[i]);
|
||||
_hostName[n] = '\0';
|
||||
|
||||
os_strcpy(_boardName, ARDUINO_BOARD);
|
||||
|
||||
// Open the MDNS socket if it isn't already open.
|
||||
if (!_conn) {
|
||||
uint32_t ourIp = _getOurIp();
|
||||
if(ourIp == 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
ip_addr_t ifaddr;
|
||||
ifaddr.addr = (uint32_t) addr;
|
||||
ifaddr.addr = ourIp;
|
||||
ip_addr_t multicast_addr;
|
||||
multicast_addr.addr = (uint32_t) MDNS_MULTICAST_ADDR;
|
||||
|
||||
@ -202,55 +132,369 @@ void MDNSResponder::update() {
|
||||
if (!_conn->next()) {
|
||||
return;
|
||||
}
|
||||
_parsePacket();
|
||||
}
|
||||
|
||||
// Read available data.
|
||||
int n = _conn->getSize();
|
||||
void MDNSResponder::addService(char *name, char *proto, uint16_t port){
|
||||
if(_getServicePort(name, proto) != 0) return;
|
||||
if(os_strlen(name) > 32 || os_strlen(proto) != 3) return; //bad arguments
|
||||
struct MDNSService *srv = (struct MDNSService*)(os_malloc(sizeof(struct MDNSService)));
|
||||
os_strcpy(srv->_name, name);
|
||||
os_strcpy(srv->_proto, proto);
|
||||
srv->_port = port;
|
||||
srv->_next = 0;
|
||||
if(_services) _services->_next = srv;
|
||||
else _services = srv;
|
||||
}
|
||||
|
||||
_index = 0;
|
||||
|
||||
#ifdef MDNS_DEBUG
|
||||
Serial.println("{");
|
||||
#endif
|
||||
// Look for domain name in request and respond with canned response if found.
|
||||
for (int i = 0; i < n; ++i) {
|
||||
uint8_t ch = tolower(_conn->read());
|
||||
|
||||
#ifdef MDNS_DEBUG
|
||||
String str(ch, 16);
|
||||
Serial.print("0x");
|
||||
Serial.print(str);
|
||||
Serial.print(", ");
|
||||
#endif
|
||||
// Check character matches expected.
|
||||
if (ch == _expected[_index])
|
||||
{
|
||||
_index++;
|
||||
// Check if domain name was found and send a response.
|
||||
if (_index == _expectedLen) {
|
||||
// Send response to multicast address.
|
||||
#ifdef MDNS_DEBUG
|
||||
Serial.print("responding, i=");
|
||||
Serial.println(i);
|
||||
#endif
|
||||
ip_addr_t multicast_addr;
|
||||
multicast_addr.addr = (uint32_t) MDNS_MULTICAST_ADDR;
|
||||
|
||||
_conn->append(reinterpret_cast<const char*>(_response), _responseLen);
|
||||
_conn->send();
|
||||
|
||||
_index = 0;
|
||||
}
|
||||
}
|
||||
else if (ch == _expected[0]) {
|
||||
// Found a character that doesn't match, but does match the start of the domain.
|
||||
_index = 1;
|
||||
}
|
||||
else {
|
||||
// Found a character that doesn't match the expected character or start of domain.
|
||||
_index = 0;
|
||||
uint16_t MDNSResponder::_getServicePort(char *name, char *proto){
|
||||
MDNSService* servicePtr;
|
||||
for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) {
|
||||
if(servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0){
|
||||
return servicePtr->_port;
|
||||
}
|
||||
}
|
||||
#ifdef MDNS_DEBUG
|
||||
Serial.println("}");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MDNSResponder::_getOurIp(){
|
||||
if(wifi_get_opmode() & STATION_MODE){
|
||||
struct ip_info staIpInfo;
|
||||
wifi_get_ip_info(STATION_IF, &staIpInfo);
|
||||
return staIpInfo.ip.addr;
|
||||
}
|
||||
#ifdef MDNS_DEBUG_ERR
|
||||
os_printf("ERR_NO_LOCAL_IP\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MDNSResponder::_parsePacket(){
|
||||
int i;
|
||||
char tmp;
|
||||
bool serviceParsed = false;
|
||||
bool protoParsed = false;
|
||||
bool localParsed = false;
|
||||
|
||||
char hostName[255];
|
||||
uint8_t hostNameLen;
|
||||
|
||||
char serviceName[32];
|
||||
uint8_t serviceNameLen;
|
||||
uint16_t servicePort;
|
||||
|
||||
char protoName[32];
|
||||
uint8_t protoNameLen;
|
||||
|
||||
uint16_t packetHeader[6];
|
||||
|
||||
for(i=0; i<6; i++) packetHeader[i] = _conn_read16();
|
||||
|
||||
if((packetHeader[1] & 0x8000) != 0){ //not parsing responses yet
|
||||
_conn->flush();
|
||||
return;
|
||||
}
|
||||
|
||||
// PARSE REQUEST NAME
|
||||
|
||||
hostNameLen = _conn_read8();
|
||||
_conn_readS(hostName, hostNameLen);
|
||||
hostName[hostNameLen] = '\0';
|
||||
|
||||
if(hostName[0] == '_'){
|
||||
serviceParsed = true;
|
||||
memcpy(serviceName, hostName+1, hostNameLen);
|
||||
serviceNameLen = hostNameLen-1;
|
||||
hostNameLen = 0;
|
||||
}
|
||||
|
||||
if(hostNameLen > 0 && strcmp(_hostName, hostName) != 0){
|
||||
#ifdef MDNS_DEBUG_ERR
|
||||
os_printf("ERR_NO_HOST: %s\n", hostName);
|
||||
#endif
|
||||
_conn->flush();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!serviceParsed){
|
||||
serviceNameLen = _conn_read8();
|
||||
_conn_readS(serviceName, serviceNameLen);
|
||||
serviceName[serviceNameLen] = '\0';
|
||||
|
||||
if(serviceName[0] == '_'){
|
||||
memcpy(serviceName, serviceName+1, serviceNameLen);
|
||||
serviceNameLen--;
|
||||
serviceParsed = true;
|
||||
} else if(serviceNameLen == 5 && strcmp("local", serviceName) == 0){
|
||||
tmp = _conn_read8();
|
||||
if(tmp == 0){
|
||||
serviceParsed = true;
|
||||
serviceNameLen = 0;
|
||||
protoParsed = true;
|
||||
protoNameLen = 0;
|
||||
localParsed = true;
|
||||
} else {
|
||||
#ifdef MDNS_DEBUG_ERR
|
||||
os_printf("ERR_FQDN: %s\n", serviceName);
|
||||
#endif
|
||||
_conn->flush();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
#ifdef MDNS_DEBUG_ERR
|
||||
os_printf("ERR_SERVICE: %s\n", serviceName);
|
||||
#endif
|
||||
_conn->flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!protoParsed){
|
||||
protoNameLen = _conn_read8();
|
||||
_conn_readS(protoName, protoNameLen);
|
||||
protoName[protoNameLen] = '\0';
|
||||
if(protoNameLen == 4 && protoName[0] == '_'){
|
||||
memcpy(protoName, protoName+1, protoNameLen);
|
||||
protoNameLen--;
|
||||
protoParsed = true;
|
||||
} else {
|
||||
#ifdef MDNS_DEBUG_ERR
|
||||
os_printf("ERR_PROTO: %s\n", protoName);
|
||||
#endif
|
||||
_conn->flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!localParsed){
|
||||
char localName[32];
|
||||
uint8_t localNameLen = _conn_read8();
|
||||
_conn_readS(localName, localNameLen);
|
||||
localName[localNameLen] = '\0';
|
||||
tmp = _conn_read8();
|
||||
if(localNameLen == 5 && strcmp("local", localName) == 0 && tmp == 0){
|
||||
localParsed = true;
|
||||
} else {
|
||||
#ifdef MDNS_DEBUG_ERR
|
||||
os_printf("ERR_FQDN: %s\n", localName);
|
||||
#endif
|
||||
_conn->flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(serviceNameLen > 0 && protoNameLen > 0){
|
||||
servicePort = _getServicePort(serviceName, protoName);
|
||||
if(servicePort == 0){
|
||||
#ifdef MDNS_DEBUG_ERR
|
||||
os_printf("ERR_NO_SERVICE: %s\n", serviceName);
|
||||
#endif
|
||||
_conn->flush();
|
||||
return;
|
||||
}
|
||||
} else if(serviceNameLen > 0 || protoNameLen > 0){
|
||||
#ifdef MDNS_DEBUG_ERR
|
||||
os_printf("ERR_SERVICE_PROTO: %s\n", serviceName);
|
||||
#endif
|
||||
_conn->flush();
|
||||
return;
|
||||
}
|
||||
|
||||
// RESPOND
|
||||
|
||||
#ifdef MDNS_DEBUG_RX
|
||||
os_printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]);
|
||||
#endif
|
||||
|
||||
uint16_t currentType;
|
||||
uint16_t currentClass;
|
||||
|
||||
int numQuestions = packetHeader[2];
|
||||
if(numQuestions > 4) numQuestions = 4;
|
||||
uint16_t questions[4];
|
||||
int question = 0;
|
||||
|
||||
while(numQuestions--){
|
||||
currentType = _conn_read16();
|
||||
if(currentType & MDNS_NAME_REF){ //new header handle it better!
|
||||
currentType = _conn_read16();
|
||||
}
|
||||
currentClass = _conn_read16();
|
||||
if(currentClass & MDNS_CLASS_IN) questions[question++] = currentType;
|
||||
|
||||
if(numQuestions > 0){
|
||||
if(_conn_read16() != 0xC00C){//new question but for another host/service
|
||||
_conn->flush();
|
||||
numQuestions = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MDNS_DEBUG_RX
|
||||
os_printf("REQ: ");
|
||||
if(hostNameLen > 0) os_printf("%s.", hostName);
|
||||
if(serviceNameLen > 0) os_printf("_%s.", serviceName);
|
||||
if(protoNameLen > 0) os_printf("_%s.", protoName);
|
||||
os_printf("local. ");
|
||||
|
||||
if(currentType == MDNS_TYPE_AAAA) os_printf(" AAAA ");
|
||||
else if(currentType == MDNS_TYPE_A) os_printf(" A ");
|
||||
else if(currentType == MDNS_TYPE_PTR) os_printf(" PTR ");
|
||||
else if(currentType == MDNS_TYPE_SRV) os_printf(" SRV ");
|
||||
else if(currentType == MDNS_TYPE_TXT) os_printf(" TXT ");
|
||||
else if(currentType == MDNS_TYPE_NSEC) os_printf(" NSEC ");
|
||||
else os_printf(" 0x%04X ", currentType);
|
||||
|
||||
if(currentClass == MDNS_CLASS_IN) os_printf(" IN ");
|
||||
else if(currentClass == MDNS_CLASS_IN_FLUSH_CACHE) os_printf(" IN[F] ");
|
||||
else os_printf(" 0x%04X ", currentClass);
|
||||
|
||||
os_printf("\n");
|
||||
#endif
|
||||
}
|
||||
uint8_t responseMask = 0;
|
||||
for(i=0;i<question;i++){
|
||||
if(questions[i] == MDNS_TYPE_A) responseMask |= 0x1;
|
||||
else if(questions[i] == MDNS_TYPE_SRV) responseMask |= 0x3;
|
||||
else if(questions[i] == MDNS_TYPE_TXT) responseMask |= 0x4;
|
||||
else if(questions[i] == MDNS_TYPE_PTR) responseMask |= 0xF;
|
||||
}
|
||||
|
||||
return _reply(responseMask, (serviceName), (protoName), servicePort);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint16_t port){
|
||||
int i;
|
||||
if(replyMask == 0) return;
|
||||
|
||||
#ifdef MDNS_DEBUG_TX
|
||||
os_printf("TX: mask:%01X, service:%s, proto:%s, port:%u\n", replyMask, service, proto, port);
|
||||
#endif
|
||||
|
||||
char nameLen = os_strlen(_hostName);
|
||||
size_t serviceLen = os_strlen(service);
|
||||
|
||||
uint8_t answerCount = 0;
|
||||
for(i=0;i<4;i++){
|
||||
if(replyMask & (1 << i)) answerCount++;
|
||||
}
|
||||
|
||||
_conn->flush();
|
||||
uint8_t head[12] = {
|
||||
0x00, 0x00, //ID = 0
|
||||
0x84, 0x00, //Flags = response + authoritative answer
|
||||
0x00, 0x00, //Question count
|
||||
0x00, answerCount, //Answer count
|
||||
0x00, 0x00, //Name server records
|
||||
0x00, 0x00, //Additional records
|
||||
};
|
||||
_conn->append(reinterpret_cast<const char*>(head), 12);
|
||||
|
||||
if((replyMask & 0x8) == 0){
|
||||
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
||||
}
|
||||
|
||||
if(replyMask & 0xE){
|
||||
uint8_t servHead[2] = {(uint8_t)(serviceLen+1), '_'};
|
||||
uint8_t protoHead[2] = {0x4, '_'};
|
||||
_conn->append(reinterpret_cast<const char*>(servHead), 2);
|
||||
_conn->append(reinterpret_cast<const char*>(service), serviceLen);
|
||||
_conn->append(reinterpret_cast<const char*>(protoHead), 2);
|
||||
_conn->append(reinterpret_cast<const char*>(proto), 3);
|
||||
}
|
||||
|
||||
uint8_t local[7] = {
|
||||
0x05, //strlen(_local)
|
||||
0x6C, 0x6F, 0x63, 0x61, 0x6C, //local
|
||||
0x00, //End of domain
|
||||
};
|
||||
_conn->append(reinterpret_cast<const char*>(local), 7);
|
||||
|
||||
// PTR Response
|
||||
if(replyMask & 0x8){
|
||||
uint8_t ptr[10] = {
|
||||
0x00, 0x0c, //PTR record query
|
||||
0x00, 0x01, //Class IN
|
||||
0x00, 0x00, 0x11, 0x94, //TTL 4500
|
||||
0x00, (uint8_t)(3 + nameLen), //***DATA LEN (3 + strlen(host))
|
||||
};
|
||||
_conn->append(reinterpret_cast<const char*>(ptr), 10);
|
||||
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
||||
uint8_t ptrTail[2] = {0xC0, 0x0C};
|
||||
_conn->append(reinterpret_cast<const char*>(ptrTail), 2);
|
||||
}
|
||||
|
||||
// TXT Response
|
||||
if(replyMask & 0x4){
|
||||
if(replyMask & 0x8){//send the name
|
||||
uint8_t txtHead[2] = {0xC0, (uint8_t)(36 + serviceLen)};
|
||||
_conn->append(reinterpret_cast<const char*>(txtHead), 2);
|
||||
}
|
||||
|
||||
uint8_t boardNameLen = os_strlen(_boardName);
|
||||
|
||||
uint8_t txt[24] = {
|
||||
0x00, 0x10, //Type TXT
|
||||
0x80, 0x01, //Class IN, with cache flush
|
||||
0x00, 0x00, 0x11, 0x94, //TTL 4500
|
||||
0x00, 0x0e, //DATA LEN
|
||||
(uint8_t)(6 + boardNameLen), //strlen(board=) + strlen(boardName)
|
||||
0x62, 0x6f, 0x61, 0x72, 0x64, 0x3d //board=
|
||||
};
|
||||
_conn->append(reinterpret_cast<const char*>(txt), 17);
|
||||
_conn->append(reinterpret_cast<const char*>(_boardName), boardNameLen);
|
||||
|
||||
}
|
||||
|
||||
// SRV Response
|
||||
if(replyMask & 0x2){
|
||||
if(replyMask & 0xC){//send the name
|
||||
uint8_t srvHead[2] = {0xC0, 0x0C};
|
||||
if(replyMask & 0x8)
|
||||
srvHead[1] = 36 + serviceLen;
|
||||
_conn->append(reinterpret_cast<const char*>(srvHead), 2);
|
||||
}
|
||||
|
||||
uint8_t srv[16] = {
|
||||
0x00, 0x21, //Type SRV
|
||||
0x80, 0x01, //Class IN, with cache flush
|
||||
0x00, 0x00, 0x00, 0x78, //TTL 120
|
||||
0x00, (uint8_t)(9 + nameLen), //DATA LEN (9 + strlen(host))
|
||||
0x00, 0x00, //Priority 0
|
||||
0x00, 0x00, //Weight 0
|
||||
(uint8_t)((port >> 8) & 0xFF), (uint8_t)(port & 0xFF)
|
||||
};
|
||||
_conn->append(reinterpret_cast<const char*>(srv), 16);
|
||||
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
||||
uint8_t srvTail[2] = {0xC0, (uint8_t)(20 + serviceLen + nameLen)};
|
||||
if(replyMask & 0x8)
|
||||
srvTail[1] = 19 + serviceLen;
|
||||
_conn->append(reinterpret_cast<const char*>(srvTail), 2);
|
||||
}
|
||||
|
||||
// A Response
|
||||
if(replyMask & 0x1){
|
||||
uint32_t ip = _getOurIp();
|
||||
if(replyMask & 0x2){//send the name (no compression for now)
|
||||
_conn->append(reinterpret_cast<const char*>(&nameLen), 1);
|
||||
_conn->append(reinterpret_cast<const char*>(_hostName), nameLen);
|
||||
_conn->append(reinterpret_cast<const char*>(local), 7);
|
||||
}
|
||||
|
||||
uint8_t aaa[14] = {
|
||||
0x00, 0x01, //TYPE A
|
||||
0x80, 0x01, //Class IN, with cache flush
|
||||
0x00, 0x00, 0x00, 0x78, //TTL 120
|
||||
0x00, 0x04, //DATA LEN
|
||||
(uint8_t)(ip & 0xFF), (uint8_t)((ip >> 8) & 0xFF), (uint8_t)((ip >> 16) & 0xFF), (uint8_t)((ip >> 24) & 0xFF)
|
||||
};
|
||||
_conn->append(reinterpret_cast<const char*>(aaa), 14);
|
||||
}
|
||||
_conn->send();
|
||||
}
|
||||
|
||||
MDNSResponder MDNS = MDNSResponder();
|
||||
|
@ -46,29 +46,51 @@ License (MIT license):
|
||||
#include "ESP8266WiFi.h"
|
||||
#include "WiFiUdp.h"
|
||||
|
||||
//this should be defined at build time
|
||||
#ifndef ARDUINO_BOARD
|
||||
#define ARDUINO_BOARD "generic"
|
||||
#endif
|
||||
|
||||
class UdpContext;
|
||||
|
||||
struct MDNSService {
|
||||
MDNSService* _next;
|
||||
char _name[32];
|
||||
char _proto[3];
|
||||
uint16_t _port;
|
||||
};
|
||||
|
||||
class MDNSResponder {
|
||||
public:
|
||||
MDNSResponder();
|
||||
~MDNSResponder();
|
||||
bool begin(const char* domain, IPAddress addr, uint32_t ttlSeconds = 3600);
|
||||
bool begin(const char* hostName);
|
||||
//for compatibility
|
||||
bool begin(const char* hostName, IPAddress ip, uint32_t ttl=120){
|
||||
return begin(hostName);
|
||||
}
|
||||
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(String service, String proto, uint16_t port){
|
||||
addService(service.c_str(), proto.c_str(), port);
|
||||
}
|
||||
|
||||
private:
|
||||
// Expected query values
|
||||
uint8_t* _expected;
|
||||
int _expectedLen;
|
||||
// Current parsing state
|
||||
int _index;
|
||||
// Response data
|
||||
uint8_t* _response;
|
||||
int _responseLen;
|
||||
// Socket for MDNS communication
|
||||
struct MDNSService * _services;
|
||||
UdpContext* _conn;
|
||||
// local IP Address
|
||||
IPAddress _localAddr;
|
||||
char _hostName[128];
|
||||
char _boardName[64];
|
||||
|
||||
uint32_t _getOurIp();
|
||||
uint16_t _getServicePort(char *service, char *proto);
|
||||
void _parsePacket();
|
||||
void _reply(uint8_t replyMask, char * service, char *proto, uint16_t port);
|
||||
};
|
||||
|
||||
extern MDNSResponder MDNS;
|
||||
|
||||
#endif //ESP8266MDNS_H
|
||||
|
@ -23,9 +23,6 @@
|
||||
const char* ssid = "............";
|
||||
const char* password = "..............";
|
||||
|
||||
// multicast DNS responder
|
||||
MDNSResponder mdns;
|
||||
|
||||
// TCP server at port 80 will respond to HTTP requests
|
||||
WiFiServer server(80);
|
||||
|
||||
@ -53,7 +50,7 @@ void setup(void)
|
||||
// the fully-qualified domain name is "esp8266.local"
|
||||
// - second argument is the IP address to advertise
|
||||
// we send our IP address on the WiFi network
|
||||
if (!mdns.begin("esp8266", WiFi.localIP())) {
|
||||
if (!MDNS.begin("esp8266")) {
|
||||
Serial.println("Error setting up MDNS responder!");
|
||||
while(1) {
|
||||
delay(1000);
|
||||
@ -64,6 +61,9 @@ void setup(void)
|
||||
// Start TCP (HTTP) server
|
||||
server.begin();
|
||||
Serial.println("TCP server started");
|
||||
|
||||
// Add service to MDNS-SD
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
|
@ -6,14 +6,17 @@
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
ESP8266mDNS KEYWORD1
|
||||
MDNSResponder KEYWORD1
|
||||
MDNS KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
update KEYWORD2
|
||||
begin KEYWORD2
|
||||
update KEYWORD2
|
||||
addService KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user