1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-07 16:23:38 +03:00
This commit is contained in:
Lars Englund 2016-03-09 09:59:17 +01:00
parent 42cb81938f
commit 0426e000cf
2 changed files with 110 additions and 169 deletions

View File

@ -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,10 +251,7 @@ 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[] = "_";
// build service name with _ // build service name with _
@ -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,11 +304,14 @@ 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;
int numAnswers = 0; int numAnswers = 0;
@ -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,159 +482,133 @@ 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) {
// Add new answer to answer list
if (_answers == 0) {
_answers = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer)));
answer = _answers;
}
else {
answer = _answers;
while (answer->next != 0) {
answer = _answers->next;
}
answer->next = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer)));
answer = answer->next;
}
answer->next = 0;
answer->hostname = 0;
}
} }
if (type == MDNS_TYPE_TXT) { if (answerType == MDNS_TYPE_TXT) {
Serial.println("Got a TXT answer!"); partsCollected |= 0x02;
_conn_readS(hostName, answerRdlength); // Read rdata
Serial.print(rdlength); #ifdef MDNS_DEBUG_RX
Serial.print(" "); for (int n = 0; n < answerRdlength; n++) {
_conn_readS(hostName, rdlength); // Skip rdata
for (int n = 0; n < rdlength; n++) {
Serial.printf("%02x ", hostName[n]); Serial.printf("%02x ", hostName[n]);
} }
Serial.println(); Serial.println();
#endif
} }
if (type == MDNS_TYPE_SRV) { if (answerType == MDNS_TYPE_SRV) {
Serial.println("Got a SRV answer!"); partsCollected |= 0x04;
tmp16 = _conn_read16(); // Read priority uint16_t answerPrio = _conn_read16(); // Read priority
tmp16 = _conn_read16(); // Read weight uint16_t answerWeight = _conn_read16(); // Read weight
answer->port = _conn_read16(); // Read port answerPort = _conn_read16(); // Read port
// Read hostname // Read hostname
tmp8 = _conn_read8(); tmp8 = _conn_read8();
if (tmp8 & 0xC0) { // Compressed pointer if (tmp8 & 0xC0) { // Compressed pointer (not supported)
Serial.println("Skipping compressed pointer"); Serial.println("Skipping compressed pointer");
tmp8 = _conn_read8(); tmp8 = _conn_read8();
} }
else { else {
Serial.print(" "); _conn_readS(answerHostName, tmp8);
Serial.print(tmp8); answerHostName[tmp8] = '\0';
Serial.print(" "); #ifdef MDNS_DEBUG_RX
answer->hostname = (char *)os_malloc(tmp8 + 1); Serial.printf(" %d ", tmp8);
_conn_readS(answer->hostname, tmp8);
answer->hostname[tmp8] = '\0';
for (int n = 0; n < tmp8; n++) { for (int n = 0; n < tmp8; n++) {
Serial.printf("%02x ", answer->hostname[n]); Serial.printf("%02x ", answerHostName[n]);
} }
Serial.println(); Serial.printf("\n%s\n", answerHostName);
Serial.println(answer->hostname); #endif
if (rdlength - (6 + 1 + tmp8) > 0) { // Skip remaining rdata if (answerRdlength - (6 + 1 + tmp8) > 0) { // Skip any remaining rdata
_conn_readS(hostName, rdlength - (6 + 1 + tmp8)); _conn_readS(hostName, answerRdlength - (6 + 1 + tmp8));
} }
} }
} }
if (type == MDNS_TYPE_A) { if (answerType == MDNS_TYPE_A) {
Serial.println("Got a A answer!"); partsCollected |= 0x08;
answer->ip[0] = _conn_read8(); for (int i = 0; i < 4; i++) {
answer->ip[1] = _conn_read8(); answerIp[i] = _conn_read8();
answer->ip[2] = _conn_read8(); }
answer->ip[3] = _conn_read8();
} }
if (serviceMatch) { Serial.printf("Parts collected: %02x\n", partsCollected);
// Populate answer
// TODO: assign all strings to local variables and populate answer here if ((partsCollected == 0x0F) && serviceMatch) {
//answer->port = answerPort; #ifdef MDNS_DEBUG_RX
//answer->ip = ; Serial.println("All answers parsed, adding to _answers list..");
//answer->hostname = ; #endif
// Add new answer to answer list
if (_answers == 0) {
_answers = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer)));
answer = _answers;
}
else {
answer = _answers;
while (answer->next != 0) {
answer = _answers->next;
}
answer->next = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer)));
answer = answer->next;
}
answer->next = 0;
answer->hostname = 0;
// Populate new answer
answer->port = answerPort;
for (int i = 0; i < 4; i++) {
answer->ip[i] = answerIp[i];
}
answer->hostname = (char *)os_malloc(strlen(answerHostName) + 1);
os_strcpy(answer->hostname, answerHostName);
} }
} }
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;
} }

View File

@ -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