mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-07 16:23:38 +03:00
Clean up
This commit is contained in:
parent
42cb81938f
commit
0426e000cf
@ -5,7 +5,7 @@ Version 1.1
|
|||||||
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||||
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||||
MDNS-SD Suport 2015 Hristo Gochkov
|
MDNS-SD Suport 2015 Hristo Gochkov
|
||||||
Extended MDNS-SD support 2016 Lars Englund
|
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||||
|
|
||||||
|
|
||||||
License (MIT license):
|
License (MIT license):
|
||||||
@ -32,6 +32,7 @@ License (MIT license):
|
|||||||
// Important RFC's for reference:
|
// Important RFC's for reference:
|
||||||
// - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt
|
// - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt
|
||||||
// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt
|
// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt
|
||||||
|
// - MDNS-SD: https://tools.ietf.org/html/rfc6763
|
||||||
|
|
||||||
#define LWIP_OPEN_SRC
|
#define LWIP_OPEN_SRC
|
||||||
|
|
||||||
@ -113,8 +114,6 @@ struct MDNSQuery {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MDNSResponder::MDNSResponder() : _conn(0) {
|
MDNSResponder::MDNSResponder() : _conn(0) {
|
||||||
_services = 0;
|
_services = 0;
|
||||||
_instanceName = "";
|
_instanceName = "";
|
||||||
@ -240,19 +239,9 @@ void MDNSResponder::addService(char *name, char *proto, uint16_t port){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int MDNSResponder::queryService(char *service, char *proto) {
|
int MDNSResponder::queryService(char *service, char *proto) {
|
||||||
Serial.print("queryService: ");
|
#ifdef MDNS_DEBUG_TX
|
||||||
Serial.print(service);
|
Serial.printf("queryService %s %s\n", service, proto);
|
||||||
Serial.print(" ");
|
#endif
|
||||||
Serial.println(proto);
|
|
||||||
|
|
||||||
// Relevant RFCs
|
|
||||||
// https://tools.ietf.org/html/rfc1035
|
|
||||||
// https://tools.ietf.org/html/rfc6762
|
|
||||||
// https://tools.ietf.org/html/rfc6763
|
|
||||||
// Example query sent for _lalala._tcp.local
|
|
||||||
//0000 00 00 00 00 00 01 00 00 00 00 00 00 07 5f 6c 61 ............._la
|
|
||||||
//0010 6c 61 6c 61 04 5f 74 63 70 05 6c 6f 63 61 6c 00 lala._tcp.local.
|
|
||||||
//0020 00 0c 00 01 ....
|
|
||||||
|
|
||||||
if (_query != 0) {
|
if (_query != 0) {
|
||||||
os_free(_query);
|
os_free(_query);
|
||||||
@ -262,9 +251,6 @@ int MDNSResponder::queryService(char *service, char *proto) {
|
|||||||
os_strcpy(_query->_service, service);
|
os_strcpy(_query->_service, service);
|
||||||
os_strcpy(_query->_proto, proto);
|
os_strcpy(_query->_proto, proto);
|
||||||
_newQuery = true;
|
_newQuery = true;
|
||||||
_waitingForAnswers = true;
|
|
||||||
|
|
||||||
//Serial.println("building strings");
|
|
||||||
|
|
||||||
char underscore[] = "_";
|
char underscore[] = "_";
|
||||||
|
|
||||||
@ -292,8 +278,6 @@ int MDNSResponder::queryService(char *service, char *proto) {
|
|||||||
|
|
||||||
// Write the header
|
// Write the header
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
//Serial.println("a");
|
|
||||||
|
|
||||||
uint8_t head[12] = {
|
uint8_t head[12] = {
|
||||||
0x00, 0x00, //ID = 0
|
0x00, 0x00, //ID = 0
|
||||||
0x00, 0x00, //Flags = response + authoritative answer
|
0x00, 0x00, //Flags = response + authoritative answer
|
||||||
@ -302,18 +286,7 @@ int MDNSResponder::queryService(char *service, char *proto) {
|
|||||||
0x00, 0x00, //Name server records
|
0x00, 0x00, //Name server records
|
||||||
0x00, 0x00 //Additional records
|
0x00, 0x00 //Additional records
|
||||||
};
|
};
|
||||||
Serial.print("serviceName ");
|
|
||||||
Serial.print(serviceNameLen);
|
|
||||||
Serial.print(" ");
|
|
||||||
Serial.println(serviceName);
|
|
||||||
|
|
||||||
Serial.print("protoName ");
|
|
||||||
Serial.print(protoNameLen);
|
|
||||||
Serial.print(" ");
|
|
||||||
Serial.println(protoName);
|
|
||||||
|
|
||||||
_conn->append(reinterpret_cast<const char*>(head), 12);
|
_conn->append(reinterpret_cast<const char*>(head), 12);
|
||||||
//Serial.println("c");
|
|
||||||
|
|
||||||
// Only supports sending one PTR query
|
// Only supports sending one PTR query
|
||||||
// Send the Name field (eg. "_http._tcp.local")
|
// Send the Name field (eg. "_http._tcp.local")
|
||||||
@ -331,9 +304,12 @@ int MDNSResponder::queryService(char *service, char *proto) {
|
|||||||
0x00, 0x01 //Class IN
|
0x00, 0x01 //Class IN
|
||||||
};
|
};
|
||||||
_conn->append(reinterpret_cast<const char*>(ptrAttrs), 4);
|
_conn->append(reinterpret_cast<const char*>(ptrAttrs), 4);
|
||||||
|
_waitingForAnswers = true;
|
||||||
_conn->send();
|
_conn->send();
|
||||||
|
|
||||||
//Serial.println("Waiting for answers..");
|
#ifdef MDNS_DEBUG_TX
|
||||||
|
Serial.println("Waiting for answers..");
|
||||||
|
#endif
|
||||||
delay(1000);
|
delay(1000);
|
||||||
|
|
||||||
_waitingForAnswers = false;
|
_waitingForAnswers = false;
|
||||||
@ -367,7 +343,7 @@ IPAddress MDNSResponder::IP(int idx) {
|
|||||||
while (answer != 0 && idx-- > 0) {
|
while (answer != 0 && idx-- > 0) {
|
||||||
answer = answer->next;
|
answer = answer->next;
|
||||||
}
|
}
|
||||||
return answer->ip;
|
return IPAddress(answer->ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t MDNSResponder::port(int idx) {
|
uint16_t MDNSResponder::port(int idx) {
|
||||||
@ -457,45 +433,36 @@ void MDNSResponder::_parsePacket(){
|
|||||||
|
|
||||||
for(i=0; i<6; i++) packetHeader[i] = _conn_read16();
|
for(i=0; i<6; i++) packetHeader[i] = _conn_read16();
|
||||||
|
|
||||||
if ((packetHeader[1] & 0x8000) != 0) {
|
if ((packetHeader[1] & 0x8000) != 0) { // Read answers
|
||||||
Serial.printf("Parsing answers RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]);
|
#ifdef MDNS_DEBUG_RX
|
||||||
|
Serial.printf("Reading answers RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!_waitingForAnswers) {
|
if (!_waitingForAnswers) {
|
||||||
Serial.println("Not waiting for answers, returning");
|
#ifdef MDNS_DEBUG_RX
|
||||||
|
Serial.println("Not expecting any answers right now, returning");
|
||||||
|
#endif
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int numAnswers = packetHeader[3];
|
int numAnswers = packetHeader[3];
|
||||||
|
// Assume that the PTR answer always comes first and that it is always accompanied by a TXT, SRV and A answer in the same packet.
|
||||||
// Assumes that the PTR answer always comes first and that it is always accompanied by a TXT, SRV and A answer in the same packet.
|
|
||||||
if (numAnswers != 4) {
|
if (numAnswers != 4) {
|
||||||
Serial.println("Expecting a packet with 4 answers");
|
#ifdef MDNS_DEBUG_RX
|
||||||
|
Serial.println("Expected a packet with 4 answers, returning");
|
||||||
|
#endif
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: parse answers and call p_answer_function_ with host (.local), IP, port,
|
|
||||||
// http://www.ietf.org/rfc/rfc1035.txt
|
|
||||||
|
|
||||||
// TODO: Parse 4 answers in 1 packet (that's what this library sends out, check if node.js mqtt advertisment sends out different answers (use esp8266_mdns to check)):
|
|
||||||
// 1. PTR - ignore for now (gives domain name (instance.service) (ex. Domain Name: ESP_81CC47._lalala._tcp.local))
|
|
||||||
// 2. TXT - ignore for now
|
|
||||||
// 3. SRV - gives service name, protocol, port and target host
|
|
||||||
// 4. A - gives ip addr of target host
|
|
||||||
|
|
||||||
/*
|
|
||||||
PTR
|
|
||||||
0000 07 5f 6c 61 6c 61 6c 61 04 5f 74 63 70 05 6c 6f ._lalala._tcp.lo
|
|
||||||
0010 63 61 6c 00 00 0c 00 01 00 00 11 94 00 1f 0a 45 cal............E
|
|
||||||
0020 53 50 5f 38 31 43 43 34 37 07 5f 6c 61 6c 61 6c SP_81CC47._lalal
|
|
||||||
0030 61 04 5f 74 63 70 05 6c 6f 63 61 6c 00 a._tcp.local.
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint8_t tmp8;
|
uint8_t tmp8;
|
||||||
uint16_t tmp16;
|
uint16_t answerPort = 0;
|
||||||
uint32_t tmp32;
|
uint8_t answerIp[4] = { 0,0,0,0 };
|
||||||
bool serviceMatch;
|
char answerHostName[255];
|
||||||
|
bool serviceMatch = false;
|
||||||
MDNSAnswer *answer;
|
MDNSAnswer *answer;
|
||||||
|
uint8_t partsCollected = 0;
|
||||||
|
|
||||||
// Clear answer list
|
// Clear answer list
|
||||||
if (_newQuery) {
|
if (_newQuery) {
|
||||||
@ -515,60 +482,107 @@ PTR
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (numAnswers--) {
|
while (numAnswers--) {
|
||||||
Serial.print("Parsing answer ");
|
|
||||||
Serial.println(numAnswers);
|
|
||||||
|
|
||||||
serviceMatch = false;
|
|
||||||
|
|
||||||
// Read name
|
// Read name
|
||||||
do {
|
do {
|
||||||
tmp8 = _conn_read8();
|
tmp8 = _conn_read8();
|
||||||
if (tmp8 & 0xC0) { // Compressed pointer
|
if (tmp8 & 0xC0) { // Compressed pointer (not supported)
|
||||||
tmp8 = _conn_read8();
|
tmp8 = _conn_read8();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tmp8 == 0x00) { // End of name (not compressed)
|
if (tmp8 == 0x00) { // Énd of name
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Serial.print(" ");
|
_conn_readS(serviceName, tmp8);
|
||||||
Serial.print(tmp8);
|
serviceName[tmp8] = '\0';
|
||||||
Serial.print(" ");
|
#ifdef MDNS_DEBUG_RX
|
||||||
_conn_readS(hostName, tmp8);
|
Serial.printf(" %d ", tmp8);
|
||||||
hostName[tmp8] = '\0';
|
|
||||||
for (int n = 0; n < tmp8; n++) {
|
for (int n = 0; n < tmp8; n++) {
|
||||||
Serial.printf("%02x ", hostName[n]);
|
Serial.printf("%02x ", serviceName[n]);
|
||||||
}
|
}
|
||||||
Serial.println();
|
Serial.println();
|
||||||
//Serial.printf(" %s ", hostName);
|
#endif
|
||||||
if (hostName[0] == '_') {
|
if (serviceName[0] == '_') {
|
||||||
if (strcmp(&hostName[1], _query->_service) == 0) {
|
if (strcmp(&serviceName[1], _query->_service) == 0) {
|
||||||
serviceMatch = true;
|
serviceMatch = true;
|
||||||
Serial.print("Got a ");
|
#ifdef MDNS_DEBUG_RX
|
||||||
Serial.print(_query->_service);
|
Serial.printf("found matching service: %s\n", _query->_service);
|
||||||
Serial.println(" answer!");
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
uint16_t type = _conn_read16(); // Read type
|
uint16_t answerType = _conn_read16(); // Read type
|
||||||
Serial.print("Type: ");
|
uint16_t answerClass = _conn_read16(); // Read class
|
||||||
Serial.printf("%04x\n", type);
|
uint32_t answerTtl = _conn_read32(); // Read ttl
|
||||||
tmp16 = _conn_read16(); // Read class
|
uint16_t answerRdlength = _conn_read16(); // Read rdlength
|
||||||
tmp32 = _conn_read32(); // Read ttl
|
|
||||||
uint16_t rdlength = _conn_read16(); // Read rdlength
|
|
||||||
|
|
||||||
if (type == MDNS_TYPE_PTR) {
|
#ifdef MDNS_DEBUG_RX
|
||||||
Serial.println("Got a PTR answer!");
|
Serial.printf("type: %04x rdlength: %d\n", answerType, answerRdlength);
|
||||||
|
#endif
|
||||||
|
|
||||||
Serial.print(rdlength);
|
if (answerType == MDNS_TYPE_PTR) {
|
||||||
Serial.print(" ");
|
partsCollected |= 0x01;
|
||||||
_conn_readS(hostName, rdlength); // Skip rdata
|
_conn_readS(hostName, answerRdlength); // Read rdata
|
||||||
for (int n = 0; n < rdlength; n++) {
|
#ifdef MDNS_DEBUG_RX
|
||||||
|
for (int n = 0; n < answerRdlength; n++) {
|
||||||
Serial.printf("%02x ", hostName[n]);
|
Serial.printf("%02x ", hostName[n]);
|
||||||
}
|
}
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (serviceMatch) {
|
if (answerType == MDNS_TYPE_TXT) {
|
||||||
|
partsCollected |= 0x02;
|
||||||
|
_conn_readS(hostName, answerRdlength); // Read rdata
|
||||||
|
#ifdef MDNS_DEBUG_RX
|
||||||
|
for (int n = 0; n < answerRdlength; n++) {
|
||||||
|
Serial.printf("%02x ", hostName[n]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (answerType == MDNS_TYPE_SRV) {
|
||||||
|
partsCollected |= 0x04;
|
||||||
|
uint16_t answerPrio = _conn_read16(); // Read priority
|
||||||
|
uint16_t answerWeight = _conn_read16(); // Read weight
|
||||||
|
answerPort = _conn_read16(); // Read port
|
||||||
|
|
||||||
|
// Read hostname
|
||||||
|
tmp8 = _conn_read8();
|
||||||
|
if (tmp8 & 0xC0) { // Compressed pointer (not supported)
|
||||||
|
Serial.println("Skipping compressed pointer");
|
||||||
|
tmp8 = _conn_read8();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conn_readS(answerHostName, tmp8);
|
||||||
|
answerHostName[tmp8] = '\0';
|
||||||
|
#ifdef MDNS_DEBUG_RX
|
||||||
|
Serial.printf(" %d ", tmp8);
|
||||||
|
for (int n = 0; n < tmp8; n++) {
|
||||||
|
Serial.printf("%02x ", answerHostName[n]);
|
||||||
|
}
|
||||||
|
Serial.printf("\n%s\n", answerHostName);
|
||||||
|
#endif
|
||||||
|
if (answerRdlength - (6 + 1 + tmp8) > 0) { // Skip any remaining rdata
|
||||||
|
_conn_readS(hostName, answerRdlength - (6 + 1 + tmp8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (answerType == MDNS_TYPE_A) {
|
||||||
|
partsCollected |= 0x08;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
answerIp[i] = _conn_read8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Parts collected: %02x\n", partsCollected);
|
||||||
|
|
||||||
|
if ((partsCollected == 0x0F) && serviceMatch) {
|
||||||
|
#ifdef MDNS_DEBUG_RX
|
||||||
|
Serial.println("All answers parsed, adding to _answers list..");
|
||||||
|
#endif
|
||||||
// Add new answer to answer list
|
// Add new answer to answer list
|
||||||
if (_answers == 0) {
|
if (_answers == 0) {
|
||||||
_answers = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer)));
|
_answers = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer)));
|
||||||
@ -584,89 +598,16 @@ PTR
|
|||||||
}
|
}
|
||||||
answer->next = 0;
|
answer->next = 0;
|
||||||
answer->hostname = 0;
|
answer->hostname = 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == MDNS_TYPE_TXT) {
|
// Populate new answer
|
||||||
Serial.println("Got a TXT answer!");
|
answer->port = answerPort;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
Serial.print(rdlength);
|
answer->ip[i] = answerIp[i];
|
||||||
Serial.print(" ");
|
|
||||||
_conn_readS(hostName, rdlength); // Skip rdata
|
|
||||||
for (int n = 0; n < rdlength; n++) {
|
|
||||||
Serial.printf("%02x ", hostName[n]);
|
|
||||||
}
|
}
|
||||||
Serial.println();
|
answer->hostname = (char *)os_malloc(strlen(answerHostName) + 1);
|
||||||
}
|
os_strcpy(answer->hostname, answerHostName);
|
||||||
|
|
||||||
if (type == MDNS_TYPE_SRV) {
|
|
||||||
Serial.println("Got a SRV answer!");
|
|
||||||
tmp16 = _conn_read16(); // Read priority
|
|
||||||
tmp16 = _conn_read16(); // Read weight
|
|
||||||
answer->port = _conn_read16(); // Read port
|
|
||||||
|
|
||||||
// Read hostname
|
|
||||||
tmp8 = _conn_read8();
|
|
||||||
if (tmp8 & 0xC0) { // Compressed pointer
|
|
||||||
Serial.println("Skipping compressed pointer");
|
|
||||||
tmp8 = _conn_read8();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Serial.print(" ");
|
|
||||||
Serial.print(tmp8);
|
|
||||||
Serial.print(" ");
|
|
||||||
answer->hostname = (char *)os_malloc(tmp8 + 1);
|
|
||||||
_conn_readS(answer->hostname, tmp8);
|
|
||||||
answer->hostname[tmp8] = '\0';
|
|
||||||
for (int n = 0; n < tmp8; n++) {
|
|
||||||
Serial.printf("%02x ", answer->hostname[n]);
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
Serial.println(answer->hostname);
|
|
||||||
if (rdlength - (6 + 1 + tmp8) > 0) { // Skip remaining rdata
|
|
||||||
_conn_readS(hostName, rdlength - (6 + 1 + tmp8));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (type == MDNS_TYPE_A) {
|
|
||||||
Serial.println("Got a A answer!");
|
|
||||||
answer->ip[0] = _conn_read8();
|
|
||||||
answer->ip[1] = _conn_read8();
|
|
||||||
answer->ip[2] = _conn_read8();
|
|
||||||
answer->ip[3] = _conn_read8();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serviceMatch) {
|
|
||||||
// Populate answer
|
|
||||||
// TODO: assign all strings to local variables and populate answer here
|
|
||||||
//answer->port = answerPort;
|
|
||||||
//answer->ip = ;
|
|
||||||
//answer->hostname = ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Serial.println("All answers parsed!");
|
|
||||||
|
|
||||||
/*
|
|
||||||
TXT
|
|
||||||
0000 0a 45 53 50 5f 38 31 43 43 34 37 07 5f 6c 61 6c .ESP_81CC47._lal
|
|
||||||
0010 61 6c 61 04 5f 74 63 70 05 6c 6f 63 61 6c 00 00 ala._tcp.local..
|
|
||||||
0020 10 00 01 00 00 11 94 00 00 .........
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
SRV
|
|
||||||
0000 0a 45 53 50 5f 38 31 43 43 34 37 07 5f 6c 61 6c .ESP_81CC47._lal
|
|
||||||
0010 61 6c 61 04 5f 74 63 70 05 6c 6f 63 61 6c 00 00 ala._tcp.local..
|
|
||||||
0020 21 80 01 00 00 00 78 00 18 00 00 00 00 1f 90 0a !.....x.........
|
|
||||||
0030 65 73 70 5f 38 31 63 63 34 37 05 6c 6f 63 61 6c esp_81cc47.local
|
|
||||||
0040 00 .
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
A
|
|
||||||
0000 0a 65 73 70 5f 38 31 63 63 34 37 05 6c 6f 63 61 .esp_81cc47.loca
|
|
||||||
0010 6c 00 00 01 80 01 00 00 00 78 00 04 c0 a8 01 0c l........x......
|
|
||||||
*/
|
|
||||||
|
|
||||||
_conn->flush();
|
_conn->flush();
|
||||||
return;
|
return;
|
||||||
|
@ -3,7 +3,7 @@ ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
|
|||||||
Version 1.1
|
Version 1.1
|
||||||
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||||
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||||
Extended MDNS-SD support 2016 Lars Englund
|
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||||
|
|
||||||
This is a simple implementation of multicast DNS query support for an Arduino
|
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
|
running on ESP8266 chip. Only support for resolving address queries is currently
|
||||||
|
Loading…
x
Reference in New Issue
Block a user