Skip to content

Commit d46f848

Browse files
committed
Basic query (and answer parsing) working
1 parent 1c9f9c3 commit d46f848

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

libraries/ESP8266mDNS/ESP8266mDNS.cpp

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Version 1.1
55
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
66
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
77
MDNS-SD Suport 2015 Hristo Gochkov
8+
Extended MDNS-SD support 2016 Lars Englund
89
910
1011
License (MIT license):
@@ -104,6 +105,7 @@ struct MDNSTxt{
104105
MDNSResponder::MDNSResponder() : _conn(0) {
105106
_services = 0;
106107
_instanceName = "";
108+
p_answer_function_ = NULL;
107109
}
108110
MDNSResponder::~MDNSResponder() {}
109111

@@ -221,6 +223,90 @@ void MDNSResponder::addService(char *name, char *proto, uint16_t port){
221223

222224
}
223225

226+
void MDNSResponder::queryService(char *service, void(*p_answer_function)(const char*)) {
227+
Serial.print("queryService: ");
228+
Serial.println(service);
229+
p_answer_function_ = p_answer_function;
230+
231+
// TODO: copy _reply() to new method called _query() that sends out a PTR query
232+
// Relevant RFCs
233+
// https://tools.ietf.org/html/rfc1035
234+
// https://tools.ietf.org/html/rfc6762
235+
// https://tools.ietf.org/html/rfc6763
236+
237+
238+
// Example query sent by node.js for _lalala._tcp.local
239+
//0000 00 00 00 00 00 01 00 00 00 00 00 00 07 5f 6c 61 ............._la
240+
//0010 6c 61 6c 61 04 5f 74 63 70 05 6c 6f 63 61 6c 00 lala._tcp.local.
241+
//0020 00 0c 00 01 ....
242+
243+
//String instanceName = _instanceName;
244+
//size_t instanceNameLen = instanceName.length();
245+
246+
//String hostName = _hostName;
247+
//size_t hostNameLen = hostName.length();
248+
249+
//char underscore[] = "_";
250+
251+
// build service name with _
252+
char serviceName[] = "_esp";
253+
size_t serviceNameLen = 4;
254+
255+
//build proto name with _
256+
char protoName[] = "_tcp";
257+
size_t protoNameLen = 4;
258+
259+
//local string
260+
char localName[] = "local";
261+
size_t localNameLen = 5;
262+
263+
//terminator
264+
char terminator[] = "\0";
265+
266+
uint8_t questionCount = 1;
267+
268+
// Write the header
269+
_conn->flush();
270+
uint8_t head[12] = {
271+
0x00, 0x00, //ID = 0
272+
0x00, 0x00, //Flags = response + authoritative answer
273+
0x00, questionCount, //Question count
274+
0x00, 0x00, //Answer count
275+
0x00, 0x00, //Name server records
276+
0x00, 0x00 //Additional records
277+
};
278+
_conn->append(reinterpret_cast<const char*>(head), 12);
279+
280+
// PTR Query
281+
//if(replyMask & 0x8){
282+
// Send the Name field (eg. "_http._tcp.local")
283+
_conn->append(reinterpret_cast<const char*>(&serviceNameLen), 1); // lenght of "_" + service
284+
_conn->append(reinterpret_cast<const char*>(serviceName), serviceNameLen); // "_" + service
285+
_conn->append(reinterpret_cast<const char*>(&protoNameLen), 1); // lenght of "_" + proto
286+
_conn->append(reinterpret_cast<const char*>(protoName), protoNameLen); // "_" + proto
287+
_conn->append(reinterpret_cast<const char*>(&localNameLen), 1); // lenght "local"
288+
_conn->append(reinterpret_cast<const char*>(localName), localNameLen); // "local"
289+
_conn->append(reinterpret_cast<const char*>(&terminator), 1); // terminator
290+
291+
//Send the type and class
292+
//uint8_t ptrDataLen = instanceNameLen + serviceNameLen + protoNameLen + localNameLen + 5; // 5 is four label sizes and the terminator
293+
uint8_t ptrAttrs[4] = {
294+
0x00, 0x0c, //PTR record query
295+
0x00, 0x01 //Class IN
296+
};
297+
_conn->append(reinterpret_cast<const char*>(ptrAttrs), 4);
298+
//}
299+
300+
_conn->send();
301+
302+
/*const char *answer = "Hello from MDNSResponder!";
303+
304+
if (p_answer_function_) {
305+
// Since a callback function has been registered, execute it.
306+
p_answer_function_(answer);
307+
}*/
308+
}
309+
224310
MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto){
225311
MDNSService* servicePtr;
226312
for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) {
@@ -298,6 +384,95 @@ void MDNSResponder::_parsePacket(){
298384
for(i=0; i<6; i++) packetHeader[i] = _conn_read16();
299385

300386
if((packetHeader[1] & 0x8000) != 0){ //not parsing responses yet
387+
388+
Serial.println("Response parsing");
389+
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]);
390+
391+
int numAnswers = packetHeader[3];
392+
393+
// TODO: parse answers and call p_answer_function_ with host (.local), IP, port,
394+
// http://www.ietf.org/rfc/rfc1035.txt
395+
396+
// 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)):
397+
// 1. PTR - ignore for now (gives domain name (instance.service) (ex. Domain Name: ESP_81CC47._lalala._tcp.local))
398+
// 2. TXT - ignore for now
399+
// 3. SRV - gives service name, protocol, port and target host
400+
// 4. A - gives ip addr of target host
401+
402+
/*
403+
PTR
404+
0000 07 5f 6c 61 6c 61 6c 61 04 5f 74 63 70 05 6c 6f ._lalala._tcp.lo
405+
0010 63 61 6c 00 00 0c 00 01 00 00 11 94 00 1f 0a 45 cal............E
406+
0020 53 50 5f 38 31 43 43 34 37 07 5f 6c 61 6c 61 6c SP_81CC47._lalal
407+
0030 61 04 5f 74 63 70 05 6c 6f 63 61 6c 00 a._tcp.local.
408+
*/
409+
uint8_t tmp8;
410+
uint16_t tmp16;
411+
uint32_t tmp32;
412+
413+
while (numAnswers--) {
414+
Serial.println("Parsing answer..");
415+
// Skip name
416+
tmp8 = _conn_read8();
417+
if (tmp8 & 0xC0) { // Compressed
418+
tmp8 = _conn_read8();
419+
}
420+
else { // Not compressed
421+
while (tmp8 != 0x00) {
422+
Serial.print(" ");
423+
Serial.print(tmp8);
424+
_conn_readS(hostName, tmp8);
425+
Serial.printf("%s ", hostName);
426+
tmp8 = _conn_read8();
427+
if (tmp8 & 0xC0) { // Compressed
428+
tmp8 = _conn_read8();
429+
break;
430+
}
431+
}
432+
}
433+
uint16_t type = _conn_read16(); // Read type
434+
if (type == MDNS_TYPE_PTR) {
435+
Serial.println("Got a PTR answer!");
436+
}
437+
if (type == MDNS_TYPE_TXT) {
438+
Serial.println("Got a TXT answer!");
439+
}
440+
if (type == MDNS_TYPE_SRV) {
441+
Serial.println("Got a SRV answer!");
442+
}
443+
if (type == MDNS_TYPE_A) {
444+
Serial.println("Got a A answer!");
445+
}
446+
tmp16 = _conn_read16(); // Skip class
447+
tmp32 = _conn_read32(); // Skip ttl
448+
tmp16 = _conn_read16(); // Skip rdlength
449+
Serial.println("\nskip ");
450+
Serial.print(tmp16);
451+
_conn_readS(hostName, tmp16); // Skip rdata
452+
Serial.printf("%s ", hostName);
453+
}
454+
Serial.println("All answers parsed!");
455+
/*
456+
TXT
457+
0000 0a 45 53 50 5f 38 31 43 43 34 37 07 5f 6c 61 6c .ESP_81CC47._lal
458+
0010 61 6c 61 04 5f 74 63 70 05 6c 6f 63 61 6c 00 00 ala._tcp.local..
459+
0020 10 00 01 00 00 11 94 00 00 .........
460+
*/
461+
462+
/*
463+
SRV
464+
0000 0a 45 53 50 5f 38 31 43 43 34 37 07 5f 6c 61 6c .ESP_81CC47._lal
465+
0010 61 6c 61 04 5f 74 63 70 05 6c 6f 63 61 6c 00 00 ala._tcp.local..
466+
0020 21 80 01 00 00 00 78 00 18 00 00 00 00 1f 90 0a !.....x.........
467+
0030 65 73 70 5f 38 31 63 63 34 37 05 6c 6f 63 61 6c esp_81cc47.local
468+
0040 00 .
469+
*/
470+
/*
471+
A
472+
0000 0a 65 73 70 5f 38 31 63 63 34 37 05 6c 6f 63 61 .esp_81cc47.loca
473+
0010 6c 00 00 01 80 01 00 00 00 78 00 04 c0 a8 01 0c l........x......
474+
*/
475+
301476
_conn->flush();
302477
return;
303478
}

libraries/ESP8266mDNS/ESP8266mDNS.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
33
Version 1.1
44
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
55
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
6+
Extended MDNS-SD support 2016 Lars Englund
67
78
This is a simple implementation of multicast DNS query support for an Arduino
89
running on ESP8266 chip. Only support for resolving address queries is currently
@@ -82,6 +83,14 @@ class MDNSResponder {
8283
addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
8384
}
8485

86+
void queryService(char *service, void(*p_answer_function)(const char*));
87+
void queryService(const char *service, void(*p_answer_function)(const char*)){
88+
queryService((char *)service, p_answer_function);
89+
}
90+
void queryService(String service, void(*p_answer_function)(const char*)){
91+
queryService(service.c_str(), p_answer_function);
92+
}
93+
8594
void enableArduino(uint16_t port, bool auth=false);
8695

8796
void setInstanceName(String name);
@@ -97,6 +106,8 @@ class MDNSResponder {
97106
UdpContext* _conn;
98107
String _hostName;
99108
String _instanceName;
109+
// Pointer to function that gets called for every incoming answer.
110+
void(*p_answer_function_)(const char*);
100111

101112
uint32_t _getOurIp();
102113
uint16_t _getServicePort(char *service, char *proto);

0 commit comments

Comments
 (0)