From d46f84821eea837df8aa0db8d707827abd71ba25 Mon Sep 17 00:00:00 2001 From: Lars Englund Date: Mon, 7 Mar 2016 14:25:31 +0100 Subject: [PATCH 1/6] Basic query (and answer parsing) working --- libraries/ESP8266mDNS/ESP8266mDNS.cpp | 175 ++++++++++++++++++++++++++ libraries/ESP8266mDNS/ESP8266mDNS.h | 11 ++ 2 files changed, 186 insertions(+) diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index 04b66fede..80733984c 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -5,6 +5,7 @@ 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 +Extended MDNS-SD support 2016 Lars Englund License (MIT license): @@ -104,6 +105,7 @@ struct MDNSTxt{ MDNSResponder::MDNSResponder() : _conn(0) { _services = 0; _instanceName = ""; + p_answer_function_ = NULL; } MDNSResponder::~MDNSResponder() {} @@ -221,6 +223,90 @@ void MDNSResponder::addService(char *name, char *proto, uint16_t port){ } +void MDNSResponder::queryService(char *service, void(*p_answer_function)(const char*)) { + Serial.print("queryService: "); + Serial.println(service); + p_answer_function_ = p_answer_function; + + // TODO: copy _reply() to new method called _query() that sends out a PTR query + // Relevant RFCs + // https://tools.ietf.org/html/rfc1035 + // https://tools.ietf.org/html/rfc6762 + // https://tools.ietf.org/html/rfc6763 + + +// Example query sent by node.js 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 .... + + //String instanceName = _instanceName; + //size_t instanceNameLen = instanceName.length(); + + //String hostName = _hostName; + //size_t hostNameLen = hostName.length(); + + //char underscore[] = "_"; + + // build service name with _ + char serviceName[] = "_esp"; + size_t serviceNameLen = 4; + + //build proto name with _ + char protoName[] = "_tcp"; + size_t protoNameLen = 4; + + //local string + char localName[] = "local"; + size_t localNameLen = 5; + + //terminator + char terminator[] = "\0"; + + uint8_t questionCount = 1; + + // Write the header + _conn->flush(); + uint8_t head[12] = { + 0x00, 0x00, //ID = 0 + 0x00, 0x00, //Flags = response + authoritative answer + 0x00, questionCount, //Question count + 0x00, 0x00, //Answer count + 0x00, 0x00, //Name server records + 0x00, 0x00 //Additional records + }; + _conn->append(reinterpret_cast(head), 12); + + // PTR Query + //if(replyMask & 0x8){ + // Send the Name field (eg. "_http._tcp.local") + _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_" + service + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_" + service + _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_" + proto + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_" + proto + _conn->append(reinterpret_cast(&localNameLen), 1); // lenght "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + //Send the type and class + //uint8_t ptrDataLen = instanceNameLen + serviceNameLen + protoNameLen + localNameLen + 5; // 5 is four label sizes and the terminator + uint8_t ptrAttrs[4] = { + 0x00, 0x0c, //PTR record query + 0x00, 0x01 //Class IN + }; + _conn->append(reinterpret_cast(ptrAttrs), 4); + //} + + _conn->send(); + + /*const char *answer = "Hello from MDNSResponder!"; + + if (p_answer_function_) { + // Since a callback function has been registered, execute it. + p_answer_function_(answer); + }*/ +} + MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto){ MDNSService* servicePtr; for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) { @@ -298,6 +384,95 @@ void MDNSResponder::_parsePacket(){ for(i=0; i<6; i++) packetHeader[i] = _conn_read16(); if((packetHeader[1] & 0x8000) != 0){ //not parsing responses yet + + Serial.println("Response parsing"); + Serial.printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]); + + int numAnswers = packetHeader[3]; + + // 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; + uint16_t tmp16; + uint32_t tmp32; + + while (numAnswers--) { + Serial.println("Parsing answer.."); + // Skip name + tmp8 = _conn_read8(); + if (tmp8 & 0xC0) { // Compressed + tmp8 = _conn_read8(); + } + else { // Not compressed + while (tmp8 != 0x00) { + Serial.print(" "); + Serial.print(tmp8); + _conn_readS(hostName, tmp8); + Serial.printf("%s ", hostName); + tmp8 = _conn_read8(); + if (tmp8 & 0xC0) { // Compressed + tmp8 = _conn_read8(); + break; + } + } + } + uint16_t type = _conn_read16(); // Read type + if (type == MDNS_TYPE_PTR) { + Serial.println("Got a PTR answer!"); + } + if (type == MDNS_TYPE_TXT) { + Serial.println("Got a TXT answer!"); + } + if (type == MDNS_TYPE_SRV) { + Serial.println("Got a SRV answer!"); + } + if (type == MDNS_TYPE_A) { + Serial.println("Got a A answer!"); + } + tmp16 = _conn_read16(); // Skip class + tmp32 = _conn_read32(); // Skip ttl + tmp16 = _conn_read16(); // Skip rdlength + Serial.println("\nskip "); + Serial.print(tmp16); + _conn_readS(hostName, tmp16); // Skip rdata + Serial.printf("%s ", 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(); return; } diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.h b/libraries/ESP8266mDNS/ESP8266mDNS.h index 8e3108e0e..f100dcbed 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/ESP8266mDNS.h @@ -3,6 +3,7 @@ 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 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 @@ -82,6 +83,14 @@ public: addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str()); } + void queryService(char *service, void(*p_answer_function)(const char*)); + void queryService(const char *service, void(*p_answer_function)(const char*)){ + queryService((char *)service, p_answer_function); + } + void queryService(String service, void(*p_answer_function)(const char*)){ + queryService(service.c_str(), p_answer_function); + } + void enableArduino(uint16_t port, bool auth=false); void setInstanceName(String name); @@ -97,6 +106,8 @@ private: UdpContext* _conn; String _hostName; String _instanceName; + // Pointer to function that gets called for every incoming answer. + void(*p_answer_function_)(const char*); uint32_t _getOurIp(); uint16_t _getServicePort(char *service, char *proto); From 42cb81938f415a527d7685a4be5a78af6ef90a98 Mon Sep 17 00:00:00 2001 From: Lars Englund Date: Tue, 8 Mar 2016 15:26:23 +0100 Subject: [PATCH 2/6] Changed to blocking behaviour --- libraries/ESP8266mDNS/ESP8266mDNS.cpp | 355 ++++++++++++++++++++------ libraries/ESP8266mDNS/ESP8266mDNS.h | 21 +- 2 files changed, 289 insertions(+), 87 deletions(-) diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index 80733984c..7e2b3388b 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -100,12 +100,28 @@ struct MDNSTxt{ String _txt; }; +struct MDNSAnswer { + MDNSAnswer* next; + uint8_t ip[4]; + uint16_t port; + char *hostname; +}; + +struct MDNSQuery { + char _service[32]; + char _proto[4]; +}; + + MDNSResponder::MDNSResponder() : _conn(0) { _services = 0; _instanceName = ""; - p_answer_function_ = NULL; + _answers = 0; + _query = 0; + _newQuery = false; + _waitingForAnswers = false; } MDNSResponder::~MDNSResponder() {} @@ -223,37 +239,45 @@ void MDNSResponder::addService(char *name, char *proto, uint16_t port){ } -void MDNSResponder::queryService(char *service, void(*p_answer_function)(const char*)) { +int MDNSResponder::queryService(char *service, char *proto) { Serial.print("queryService: "); - Serial.println(service); - p_answer_function_ = p_answer_function; + Serial.print(service); + Serial.print(" "); + Serial.println(proto); - // TODO: copy _reply() to new method called _query() that sends out a PTR query // 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 .... -// Example query sent by node.js 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) { + os_free(_query); + _query = 0; + } + _query = (struct MDNSQuery*)(os_malloc(sizeof(struct MDNSQuery))); + os_strcpy(_query->_service, service); + os_strcpy(_query->_proto, proto); + _newQuery = true; + _waitingForAnswers = true; + + //Serial.println("building strings"); - //String instanceName = _instanceName; - //size_t instanceNameLen = instanceName.length(); - - //String hostName = _hostName; - //size_t hostNameLen = hostName.length(); - - //char underscore[] = "_"; + char underscore[] = "_"; // build service name with _ - char serviceName[] = "_esp"; - size_t serviceNameLen = 4; + char serviceName[os_strlen(service) + 2]; + os_strcpy(serviceName, underscore); + os_strcat(serviceName, service); + size_t serviceNameLen = os_strlen(serviceName); //build proto name with _ - char protoName[] = "_tcp"; + char protoName[5]; + os_strcpy(protoName, underscore); + os_strcat(protoName, proto); size_t protoNameLen = 4; //local string @@ -263,10 +287,13 @@ void MDNSResponder::queryService(char *service, void(*p_answer_function)(const c //terminator char terminator[] = "\0"; + // Only supports sending one PTR query uint8_t questionCount = 1; // Write the header _conn->flush(); + //Serial.println("a"); + uint8_t head[12] = { 0x00, 0x00, //ID = 0 0x00, 0x00, //Flags = response + authoritative answer @@ -275,36 +302,83 @@ void MDNSResponder::queryService(char *service, void(*p_answer_function)(const c 0x00, 0x00, //Name server records 0x00, 0x00 //Additional records }; - _conn->append(reinterpret_cast(head), 12); + Serial.print("serviceName "); + Serial.print(serviceNameLen); + Serial.print(" "); + Serial.println(serviceName); - // PTR Query - //if(replyMask & 0x8){ - // Send the Name field (eg. "_http._tcp.local") - _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_" + service - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_" + service - _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_" + proto - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_" + proto - _conn->append(reinterpret_cast(&localNameLen), 1); // lenght "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator + Serial.print("protoName "); + Serial.print(protoNameLen); + Serial.print(" "); + Serial.println(protoName); + + _conn->append(reinterpret_cast(head), 12); + //Serial.println("c"); + + // Only supports sending one PTR query + // Send the Name field (eg. "_http._tcp.local") + _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_" + service + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_" + service + _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_" + proto + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_" + proto + _conn->append(reinterpret_cast(&localNameLen), 1); // lenght of "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator - //Send the type and class - //uint8_t ptrDataLen = instanceNameLen + serviceNameLen + protoNameLen + localNameLen + 5; // 5 is four label sizes and the terminator - uint8_t ptrAttrs[4] = { - 0x00, 0x0c, //PTR record query - 0x00, 0x01 //Class IN - }; - _conn->append(reinterpret_cast(ptrAttrs), 4); - //} - + //Send the type and class + uint8_t ptrAttrs[4] = { + 0x00, 0x0c, //PTR record query + 0x00, 0x01 //Class IN + }; + _conn->append(reinterpret_cast(ptrAttrs), 4); _conn->send(); + + //Serial.println("Waiting for answers.."); + delay(1000); - /*const char *answer = "Hello from MDNSResponder!"; - - if (p_answer_function_) { - // Since a callback function has been registered, execute it. - p_answer_function_(answer); - }*/ + _waitingForAnswers = false; + + int numAnswers = 0; + MDNSAnswer *answer = _answers; + while (answer != 0) { + numAnswers++; + answer = answer->next; + } + + return numAnswers; +} + +String MDNSResponder::hostname(int idx) { + if (_answers == 0) { + return String(); + } + MDNSAnswer *answer = _answers; + while (answer != 0 && idx-- > 0) { + answer = answer->next; + } + return answer->hostname; +} + +IPAddress MDNSResponder::IP(int idx) { + if (_answers == 0) { + return IPAddress(); + } + MDNSAnswer *answer = _answers; + while (answer != 0 && idx-- > 0) { + answer = answer->next; + } + return answer->ip; +} + +uint16_t MDNSResponder::port(int idx) { + if (_answers == 0) { + return 0; + } + MDNSAnswer *answer = _answers; + while (answer != 0 && idx-- > 0) { + answer = answer->next; + } + return answer->port; } MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto){ @@ -383,13 +457,23 @@ void MDNSResponder::_parsePacket(){ for(i=0; i<6; i++) packetHeader[i] = _conn_read16(); - if((packetHeader[1] & 0x8000) != 0){ //not parsing responses yet - - Serial.println("Response parsing"); - Serial.printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]); - + if ((packetHeader[1] & 0x8000) != 0) { + 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]); + if (!_waitingForAnswers) { + Serial.println("Not waiting for answers, returning"); + _conn->flush(); + return; + } + int numAnswers = packetHeader[3]; + // 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) { + Serial.println("Expecting a packet with 4 answers"); + _conn->flush(); + return; + } + // TODO: parse answers and call p_answer_function_ with host (.local), IP, port, // http://www.ietf.org/rfc/rfc1035.txt @@ -406,52 +490,163 @@ PTR 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; uint16_t tmp16; uint32_t tmp32; + bool serviceMatch; + MDNSAnswer *answer; + + // Clear answer list + if (_newQuery) { + answer = _answers; + while (answer != 0) { + while (answer->next != 0) { + answer = answer->next; + } + if (answer == _answers) { + _answers = 0; + } + os_free(answer->hostname); + os_free(answer); + answer = _answers; + } + _newQuery = false; + } while (numAnswers--) { - Serial.println("Parsing answer.."); - // Skip name - tmp8 = _conn_read8(); - if (tmp8 & 0xC0) { // Compressed + Serial.print("Parsing answer "); + Serial.println(numAnswers); + + serviceMatch = false; + + // Read name + do { tmp8 = _conn_read8(); + if (tmp8 & 0xC0) { // Compressed pointer + tmp8 = _conn_read8(); + break; + } + if (tmp8 == 0x00) { // End of name (not compressed) + break; + } + Serial.print(" "); + Serial.print(tmp8); + Serial.print(" "); + _conn_readS(hostName, tmp8); + hostName[tmp8] = '\0'; + for (int n = 0; n < tmp8; n++) { + Serial.printf("%02x ", hostName[n]); + } + Serial.println(); + //Serial.printf(" %s ", hostName); + if (hostName[0] == '_') { + if (strcmp(&hostName[1], _query->_service) == 0) { + serviceMatch = true; + Serial.print("Got a "); + Serial.print(_query->_service); + Serial.println(" answer!"); + } + } + } while (true); + + uint16_t type = _conn_read16(); // Read type + Serial.print("Type: "); + Serial.printf("%04x\n", type); + tmp16 = _conn_read16(); // Read class + tmp32 = _conn_read32(); // Read ttl + uint16_t rdlength = _conn_read16(); // Read rdlength + + if (type == MDNS_TYPE_PTR) { + Serial.println("Got a PTR answer!"); + + Serial.print(rdlength); + Serial.print(" "); + _conn_readS(hostName, rdlength); // Skip rdata + for (int n = 0; n < rdlength; n++) { + Serial.printf("%02x ", hostName[n]); + } + Serial.println(); + + 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; + } } - else { // Not compressed - while (tmp8 != 0x00) { + + if (type == MDNS_TYPE_TXT) { + Serial.println("Got a TXT answer!"); + + Serial.print(rdlength); + Serial.print(" "); + _conn_readS(hostName, rdlength); // Skip rdata + for (int n = 0; n < rdlength; n++) { + Serial.printf("%02x ", hostName[n]); + } + Serial.println(); + } + + 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); - _conn_readS(hostName, tmp8); - Serial.printf("%s ", hostName); - tmp8 = _conn_read8(); - if (tmp8 & 0xC0) { // Compressed - tmp8 = _conn_read8(); - break; + 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)); } } } - uint16_t type = _conn_read16(); // Read type - if (type == MDNS_TYPE_PTR) { - Serial.println("Got a PTR answer!"); - } - if (type == MDNS_TYPE_TXT) { - Serial.println("Got a TXT answer!"); - } - if (type == MDNS_TYPE_SRV) { - Serial.println("Got a SRV answer!"); - } + 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 = ; } - tmp16 = _conn_read16(); // Skip class - tmp32 = _conn_read32(); // Skip ttl - tmp16 = _conn_read16(); // Skip rdlength - Serial.println("\nskip "); - Serial.print(tmp16); - _conn_readS(hostName, tmp16); // Skip rdata - Serial.printf("%s ", 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 diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.h b/libraries/ESP8266mDNS/ESP8266mDNS.h index f100dcbed..1b6b3fed7 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/ESP8266mDNS.h @@ -55,6 +55,7 @@ class UdpContext; struct MDNSService; struct MDNSTxt; +struct MDNSAnswer; class MDNSResponder { public: @@ -83,13 +84,16 @@ public: addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str()); } - void queryService(char *service, void(*p_answer_function)(const char*)); - void queryService(const char *service, void(*p_answer_function)(const char*)){ - queryService((char *)service, p_answer_function); + int queryService(char *service, char *proto); + int queryService(const char *service, const char *proto){ + return queryService((char *)service, (char *)proto); } - void queryService(String service, void(*p_answer_function)(const char*)){ - queryService(service.c_str(), p_answer_function); + int queryService(String service, 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); @@ -106,8 +110,11 @@ private: UdpContext* _conn; String _hostName; String _instanceName; - // Pointer to function that gets called for every incoming answer. - void(*p_answer_function_)(const char*); + struct MDNSAnswer * _answers; + struct MDNSQuery * _query; + bool _newQuery; + bool _waitingForAnswers; + uint32_t _getOurIp(); uint16_t _getServicePort(char *service, char *proto); From 0426e000cfabf8dbcb8033ea39975ecd8c640061 Mon Sep 17 00:00:00 2001 From: Lars Englund Date: Wed, 9 Mar 2016 09:59:17 +0100 Subject: [PATCH 3/6] Clean up --- libraries/ESP8266mDNS/ESP8266mDNS.cpp | 277 ++++++++++---------------- libraries/ESP8266mDNS/ESP8266mDNS.h | 2 +- 2 files changed, 110 insertions(+), 169 deletions(-) diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index 7e2b3388b..733704250 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -5,7 +5,7 @@ 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 -Extended MDNS-SD support 2016 Lars Englund +Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com) License (MIT license): @@ -32,6 +32,7 @@ License (MIT license): // Important RFC's for reference: // - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt // - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt +// - MDNS-SD: https://tools.ietf.org/html/rfc6763 #define LWIP_OPEN_SRC @@ -113,8 +114,6 @@ struct MDNSQuery { }; - - MDNSResponder::MDNSResponder() : _conn(0) { _services = 0; _instanceName = ""; @@ -240,19 +239,9 @@ void MDNSResponder::addService(char *name, char *proto, uint16_t port){ } int MDNSResponder::queryService(char *service, char *proto) { - Serial.print("queryService: "); - Serial.print(service); - Serial.print(" "); - 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 .... +#ifdef MDNS_DEBUG_TX + Serial.printf("queryService %s %s\n", service, proto); +#endif if (_query != 0) { os_free(_query); @@ -262,10 +251,7 @@ int MDNSResponder::queryService(char *service, char *proto) { os_strcpy(_query->_service, service); os_strcpy(_query->_proto, proto); _newQuery = true; - _waitingForAnswers = true; - //Serial.println("building strings"); - char underscore[] = "_"; // build service name with _ @@ -292,8 +278,6 @@ int MDNSResponder::queryService(char *service, char *proto) { // Write the header _conn->flush(); - //Serial.println("a"); - uint8_t head[12] = { 0x00, 0x00, //ID = 0 0x00, 0x00, //Flags = response + authoritative answer @@ -302,18 +286,7 @@ int MDNSResponder::queryService(char *service, char *proto) { 0x00, 0x00, //Name server 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(head), 12); - //Serial.println("c"); // Only supports sending one PTR query // Send the Name field (eg. "_http._tcp.local") @@ -331,11 +304,14 @@ int MDNSResponder::queryService(char *service, char *proto) { 0x00, 0x01 //Class IN }; _conn->append(reinterpret_cast(ptrAttrs), 4); + _waitingForAnswers = true; _conn->send(); - //Serial.println("Waiting for answers.."); +#ifdef MDNS_DEBUG_TX + Serial.println("Waiting for answers.."); +#endif delay(1000); - + _waitingForAnswers = false; int numAnswers = 0; @@ -367,7 +343,7 @@ IPAddress MDNSResponder::IP(int idx) { while (answer != 0 && idx-- > 0) { answer = answer->next; } - return answer->ip; + return IPAddress(answer->ip); } uint16_t MDNSResponder::port(int idx) { @@ -457,45 +433,36 @@ void MDNSResponder::_parsePacket(){ for(i=0; i<6; i++) packetHeader[i] = _conn_read16(); - if ((packetHeader[1] & 0x8000) != 0) { - 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]); + if ((packetHeader[1] & 0x8000) != 0) { // Read answers +#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) { - Serial.println("Not waiting for answers, returning"); +#ifdef MDNS_DEBUG_RX + Serial.println("Not expecting any answers right now, returning"); +#endif _conn->flush(); return; } int numAnswers = packetHeader[3]; - - // 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. + // 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. 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(); 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; - uint16_t tmp16; - uint32_t tmp32; - bool serviceMatch; + uint16_t answerPort = 0; + uint8_t answerIp[4] = { 0,0,0,0 }; + char answerHostName[255]; + bool serviceMatch = false; MDNSAnswer *answer; + uint8_t partsCollected = 0; // Clear answer list if (_newQuery) { @@ -515,159 +482,133 @@ PTR } while (numAnswers--) { - Serial.print("Parsing answer "); - Serial.println(numAnswers); - - serviceMatch = false; - // Read name do { tmp8 = _conn_read8(); - if (tmp8 & 0xC0) { // Compressed pointer + if (tmp8 & 0xC0) { // Compressed pointer (not supported) tmp8 = _conn_read8(); break; } - if (tmp8 == 0x00) { // End of name (not compressed) + if (tmp8 == 0x00) { // Énd of name break; } - Serial.print(" "); - Serial.print(tmp8); - Serial.print(" "); - _conn_readS(hostName, tmp8); - hostName[tmp8] = '\0'; + _conn_readS(serviceName, tmp8); + serviceName[tmp8] = '\0'; +#ifdef MDNS_DEBUG_RX + Serial.printf(" %d ", tmp8); for (int n = 0; n < tmp8; n++) { - Serial.printf("%02x ", hostName[n]); + Serial.printf("%02x ", serviceName[n]); } Serial.println(); - //Serial.printf(" %s ", hostName); - if (hostName[0] == '_') { - if (strcmp(&hostName[1], _query->_service) == 0) { +#endif + if (serviceName[0] == '_') { + if (strcmp(&serviceName[1], _query->_service) == 0) { serviceMatch = true; - Serial.print("Got a "); - Serial.print(_query->_service); - Serial.println(" answer!"); +#ifdef MDNS_DEBUG_RX + Serial.printf("found matching service: %s\n", _query->_service); +#endif } } } while (true); - uint16_t type = _conn_read16(); // Read type - Serial.print("Type: "); - Serial.printf("%04x\n", type); - tmp16 = _conn_read16(); // Read class - tmp32 = _conn_read32(); // Read ttl - uint16_t rdlength = _conn_read16(); // Read rdlength + uint16_t answerType = _conn_read16(); // Read type + uint16_t answerClass = _conn_read16(); // Read class + uint32_t answerTtl = _conn_read32(); // Read ttl + uint16_t answerRdlength = _conn_read16(); // Read rdlength - if (type == MDNS_TYPE_PTR) { - Serial.println("Got a PTR answer!"); +#ifdef MDNS_DEBUG_RX + Serial.printf("type: %04x rdlength: %d\n", answerType, answerRdlength); +#endif - Serial.print(rdlength); - Serial.print(" "); - _conn_readS(hostName, rdlength); // Skip rdata - for (int n = 0; n < rdlength; n++) { + if (answerType == MDNS_TYPE_PTR) { + partsCollected |= 0x01; + _conn_readS(hostName, answerRdlength); // Read rdata +#ifdef MDNS_DEBUG_RX + for (int n = 0; n < answerRdlength; n++) { Serial.printf("%02x ", hostName[n]); } Serial.println(); - - 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; - } +#endif } - if (type == MDNS_TYPE_TXT) { - Serial.println("Got a TXT answer!"); - - Serial.print(rdlength); - Serial.print(" "); - _conn_readS(hostName, rdlength); // Skip rdata - for (int n = 0; n < rdlength; n++) { + 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 (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 + 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 + if (tmp8 & 0xC0) { // Compressed pointer (not supported) 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'; + _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 ", answer->hostname[n]); + Serial.printf("%02x ", answerHostName[n]); } - Serial.println(); - Serial.println(answer->hostname); - if (rdlength - (6 + 1 + tmp8) > 0) { // Skip remaining rdata - _conn_readS(hostName, rdlength - (6 + 1 + tmp8)); + 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 (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 (answerType == MDNS_TYPE_A) { + partsCollected |= 0x08; + for (int i = 0; i < 4; i++) { + answerIp[i] = _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.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 + 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(); return; } diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.h b/libraries/ESP8266mDNS/ESP8266mDNS.h index 1b6b3fed7..e13c5884d 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/ESP8266mDNS.h @@ -3,7 +3,7 @@ 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 +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 From e09c939c42d92f801b190e926876b68933802bd2 Mon Sep 17 00:00:00 2001 From: Lars Englund Date: Wed, 9 Mar 2016 11:12:47 +0100 Subject: [PATCH 4/6] Clean code and add example --- libraries/ESP8266mDNS/ESP8266mDNS.cpp | 28 +++---- libraries/ESP8266mDNS/ESP8266mDNS.h | 1 + .../mDNS-SD_Extended/mDNS-SD_Extended.ino | 75 +++++++++++++++++++ 3 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 libraries/ESP8266mDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index 733704250..6cecae055 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -325,36 +325,38 @@ int MDNSResponder::queryService(char *service, char *proto) { } String MDNSResponder::hostname(int idx) { - if (_answers == 0) { + MDNSAnswer *answer = _getAnswerFromIdx(idx); + if (answer == 0) { return String(); } - MDNSAnswer *answer = _answers; - while (answer != 0 && idx-- > 0) { - answer = answer->next; - } return answer->hostname; } IPAddress MDNSResponder::IP(int idx) { - if (_answers == 0) { + MDNSAnswer *answer = _getAnswerFromIdx(idx); + if (answer == 0) { return IPAddress(); } - MDNSAnswer *answer = _answers; - while (answer != 0 && idx-- > 0) { - answer = answer->next; - } return IPAddress(answer->ip); } uint16_t MDNSResponder::port(int idx) { - if (_answers == 0) { + MDNSAnswer *answer = _getAnswerFromIdx(idx); + if (answer == 0) { return 0; } + return answer->port; +} + +MDNSAnswer* MDNSResponder::_getAnswerFromIdx(int idx) { MDNSAnswer *answer = _answers; while (answer != 0 && idx-- > 0) { answer = answer->next; } - return answer->port; + if (idx > 0) { + return 0; + } + return answer; } MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto){ @@ -577,8 +579,6 @@ void MDNSResponder::_parsePacket(){ } } - Serial.printf("Parts collected: %02x\n", partsCollected); - if ((partsCollected == 0x0F) && serviceMatch) { #ifdef MDNS_DEBUG_RX Serial.println("All answers parsed, adding to _answers list.."); diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.h b/libraries/ESP8266mDNS/ESP8266mDNS.h index e13c5884d..54ce5e800 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/ESP8266mDNS.h @@ -123,6 +123,7 @@ private: void _parsePacket(); void _reply(uint8_t replyMask, char * service, char *proto, uint16_t port); size_t advertiseServices(); // advertise all hosted services + MDNSAnswer* _getAnswerFromIdx(int idx); }; extern MDNSResponder MDNS; diff --git a/libraries/ESP8266mDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino b/libraries/ESP8266mDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino new file mode 100644 index 000000000..d3feedee5 --- /dev/null +++ b/libraries/ESP8266mDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino @@ -0,0 +1,75 @@ +/* + ESP8266 mDNS-SD responder and query sample + + This is an example of announcing and finding services. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to two ESP8266 boards + - The last one powered on should now find the other. + */ + +#include +#include + +const char* ssid = "..."; +const char* password = "..."; +char hostString[16] = {0}; + +void setup() { + Serial.begin(115200); + delay(100); + Serial.println("\r\nsetup()"); + + sprintf(hostString, "ESP_%06X", ESP.getChipId()); + Serial.print("Hostname: "); + Serial.println(hostString); + WiFi.hostname(hostString); + + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(250); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (!MDNS.begin(hostString)) { + Serial.println("Error setting up MDNS responder!"); + } + Serial.println("mDNS responder started"); + MDNS.addService("esp", "tcp", 8080); // Announce esp tcp service on port 8080 + + Serial.println("Sending mDNS query"); + int n = MDNS.queryService("esp", "tcp"); // Send out query for esp tcp services + Serial.println("mDNS query done"); + if (n == 0) { + Serial.println("no services found"); + } + else { + Serial.print(n); + Serial.println(" service(s) found"); + for (int i = 0; i < n; ++i) { + // Print details for each service found + Serial.print(i + 1); + Serial.print(": "); + Serial.print(MDNS.hostname(i)); + Serial.print(" ("); + Serial.print(MDNS.IP(i)); + Serial.print(":"); + Serial.print(MDNS.port(i)); + Serial.println(")"); + } + } + Serial.println(); + + Serial.println("loop() next"); +} + +void loop() { + // put your main code here, to run repeatedly: + +} From 59c66670500b770530588a205ff0fd2986e9f26a Mon Sep 17 00:00:00 2001 From: Lars Englund Date: Wed, 9 Mar 2016 15:43:03 +0100 Subject: [PATCH 5/6] Fixed bug when making multiple consecutive queries --- libraries/ESP8266mDNS/ESP8266mDNS.cpp | 33 +++++++++++++-------------- libraries/ESP8266mDNS/ESP8266mDNS.h | 1 + 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index 6cecae055..883551142 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -314,14 +314,7 @@ int MDNSResponder::queryService(char *service, char *proto) { _waitingForAnswers = false; - int numAnswers = 0; - MDNSAnswer *answer = _answers; - while (answer != 0) { - numAnswers++; - answer = answer->next; - } - - return numAnswers; + return _getNumAnswers(); } String MDNSResponder::hostname(int idx) { @@ -359,6 +352,16 @@ MDNSAnswer* MDNSResponder::_getAnswerFromIdx(int idx) { return answer; } +int MDNSResponder::_getNumAnswers() { + int numAnswers = 0; + MDNSAnswer *answer = _answers; + while (answer != 0) { + numAnswers++; + answer = answer->next; + } + return numAnswers; +} + MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto){ MDNSService* servicePtr; for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) { @@ -468,18 +471,14 @@ void MDNSResponder::_parsePacket(){ // Clear answer list if (_newQuery) { - answer = _answers; - while (answer != 0) { - while (answer->next != 0) { - answer = answer->next; - } - if (answer == _answers) { - _answers = 0; - } + int numAnswers = _getNumAnswers(); + for (int n = numAnswers - 1; n >= 0; n--) { + answer = _getAnswerFromIdx(n); os_free(answer->hostname); os_free(answer); - answer = _answers; + answer = 0; } + _answers = 0; _newQuery = false; } diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.h b/libraries/ESP8266mDNS/ESP8266mDNS.h index 54ce5e800..7d6cb110f 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/ESP8266mDNS.h @@ -124,6 +124,7 @@ private: void _reply(uint8_t replyMask, char * service, char *proto, uint16_t port); size_t advertiseServices(); // advertise all hosted services MDNSAnswer* _getAnswerFromIdx(int idx); + int _getNumAnswers(); }; extern MDNSResponder MDNS; From 609c84b29fa10e95151b224136eeb2102fef8132 Mon Sep 17 00:00:00 2001 From: Lars Englund Date: Thu, 10 Mar 2016 10:11:46 +0100 Subject: [PATCH 6/6] Delete query and answer list in destructor --- libraries/ESP8266mDNS/ESP8266mDNS.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index 883551142..44d67c671 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -122,7 +122,23 @@ MDNSResponder::MDNSResponder() : _conn(0) { _newQuery = false; _waitingForAnswers = false; } -MDNSResponder::~MDNSResponder() {} +MDNSResponder::~MDNSResponder() { + if (_query != 0) { + os_free(_query); + _query = 0; + } + + // Clear answer list + MDNSAnswer *answer; + int numAnswers = _getNumAnswers(); + for (int n = numAnswers - 1; n >= 0; n--) { + answer = _getAnswerFromIdx(n); + os_free(answer->hostname); + os_free(answer); + answer = 0; + } + _answers = 0; +} bool MDNSResponder::begin(const char* hostname){ // Open the MDNS socket if it isn't already open.