diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index 000b6b32f..e30eb817d 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -450,6 +450,21 @@ uint16_t MDNSResponder::_getServicePort(char *name, char *proto){ return 0; } +IPAddress MDNSResponder::_getRequestMulticastInterface(){ + struct ip_info ip_info; + bool match_ap = false; + if (wifi_get_opmode() & SOFTAP_MODE) { + struct ip_info remote_ip_info; + remote_ip_info.ip.addr = _conn->getRemoteAddress(); + wifi_get_ip_info(SOFTAP_IF, &ip_info); + if (ip_info.ip.addr && ip_addr_netcmp(&remote_ip_info.ip, &ip_info.ip, &ip_info.netmask)) + match_ap = true; + } + if (!match_ap) + wifi_get_ip_info(STATION_IF, &ip_info); + return IPAddress(ip_info.ip.addr); +} + void MDNSResponder::_parsePacket(){ int i; char tmp; @@ -759,7 +774,8 @@ void MDNSResponder::_parsePacket(){ protoParsed = true; } else if(strcmp("services", serviceName) == 0 && strcmp("_dns-sd", protoName) == 0){ _conn->flush(); - advertiseServices(); + IPAddress interface = _getRequestMulticastInterface(); + _replyToTypeEnumRequest(interface); return; } else { #ifdef MDNS_DEBUG_ERR @@ -854,28 +870,26 @@ void MDNSResponder::_parsePacket(){ Serial.printf("\n"); #endif } + uint8_t questionMask = 0; uint8_t responseMask = 0; for(i=0;igetRemoteAddress(); - wifi_get_ip_info(SOFTAP_IF, &ip_info); - if (ip_info.ip.addr && ip_addr_netcmp(&remote_ip_info.ip, &ip_info.ip, &ip_info.netmask)) - match_ap = true; - } - if (!match_ap) - wifi_get_ip_info(STATION_IF, &ip_info); - uint32_t ip = ip_info.ip.addr; - - return _reply(responseMask, serviceName, protoName, servicePort, ip); + IPAddress interface = _getRequestMulticastInterface(); + return _replyToInstanceRequest(questionMask, responseMask, serviceName, protoName, servicePort, interface); } void MDNSResponder::enableArduino(uint16_t port, bool auth){ @@ -887,38 +901,106 @@ void MDNSResponder::enableArduino(uint16_t port, bool auth){ addServiceTxt("arduino", "tcp", "auth_upload", (auth) ? "yes":"no"); } -size_t MDNSResponder::advertiseServices(){ +void MDNSResponder::_replyToTypeEnumRequest(IPAddress multicastInterface) { MDNSService* servicePtr; - struct ip_info ip_info; - uint32_t ip; - size_t i = 0; for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) { if(servicePtr->_port > 0){ - wifi_get_ip_info(SOFTAP_IF, &ip_info); - ip = ip_info.ip.addr; - if (ip) - _reply(0x0F, servicePtr->_name, servicePtr->_proto, servicePtr->_port, ip); - - wifi_get_ip_info(STATION_IF, &ip_info); - ip = ip_info.ip.addr; - if (ip) - _reply(0x0F, servicePtr->_name, servicePtr->_proto, servicePtr->_port, ip); - - i++; - } - } - return i; -} - -void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint16_t port, uint32_t ip) { - int i; - if(replyMask == 0) return; + char *service = servicePtr->_name; + char *proto = servicePtr->_proto; + uint16_t port = servicePtr->_port; #ifdef MDNS_DEBUG_TX - Serial.printf("TX: mask:%01X, service:%s, proto:%s, port:%u\n", replyMask, service, proto, port); + Serial.printf("TX: service:%s, proto:%s\n", service, proto); #endif - + char sdHostName[] = "_services"; + size_t sdHostNameLen = 9; + char sdServiceName[] = "_dns-sd"; + size_t sdServiceNameLen = 7; + char sdProtoName[] = "_udp"; + size_t sdProtoNameLen = 4; + + char underscore[] = "_"; + + // build service name with _ + 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[5]; + os_strcpy(protoName, underscore); + os_strcat(protoName, proto); + size_t protoNameLen = 4; + + //local string + char localName[] = "local"; + size_t localNameLen = 5; + + //terminator + char terminator[] = "\0"; + + //Write the header + _conn->flush(); + uint8_t head[12] = { + 0x00, 0x00, //ID = 0 + 0x84, 0x00, //Flags = response + authoritative answer + 0x00, 0x00, //Question count + 0x00, 0x01, //Answer count + 0x00, 0x00, //Name server records + 0x00, 0x00, //Additional records + }; + _conn->append(reinterpret_cast(head), 12); + + // Send the Name field (ie. "_services._dns-sd._udp.local") + _conn->append(reinterpret_cast(&sdHostNameLen), 1); // length of "_services" + _conn->append(reinterpret_cast(sdHostName), sdHostNameLen); // "_services" + _conn->append(reinterpret_cast(&sdServiceNameLen), 1); // length of "_dns-sd" + _conn->append(reinterpret_cast(sdServiceName), sdServiceNameLen);// "_dns-sd" + _conn->append(reinterpret_cast(&sdProtoNameLen), 1); // length of "_udp" + _conn->append(reinterpret_cast(sdProtoName), sdProtoNameLen); // "_udp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + //Send the type, class, ttl and rdata length + uint8_t ptrDataLen = serviceNameLen + protoNameLen + localNameLen + 4; // 4 is three label sizes and the terminator + uint8_t ptrAttrs[10] = { + 0x00, 0x0c, //PTR record query + 0x00, 0x01, //Class IN + 0x00, 0x00, 0x11, 0x94, //TTL 4500 + 0x00, ptrDataLen, //RData length + }; + _conn->append(reinterpret_cast(ptrAttrs), 10); + + //Send the RData (ie. "_http._tcp.local") + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + ip_addr_t ifaddr; + ifaddr.addr = multicastInterface; + _conn->setMulticastInterface(ifaddr); + _conn->send(); + } + } +} + +void MDNSResponder::_replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface) { + int i; + if(questionMask == 0) return; + if(responseMask == 0) return; + +#ifdef MDNS_DEBUG_TX + Serial.printf("TX: qmask:%01X, rmask:%01X, service:%s, proto:%s, port:%u\n", questionMask, responseMask, service, proto, port); +#endif + + String instanceName = _instanceName; size_t instanceNameLen = instanceName.length(); @@ -937,18 +1019,22 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1 char protoName[5]; os_strcpy(protoName,underscore); os_strcat(protoName, proto); - size_t protoNameLen = 4; - + size_t protoNameLen = 4; + //local string char localName[] = "local"; - size_t localNameLen = 5; - + size_t localNameLen = 5; + //terminator char terminator[] = "\0"; + uint8_t answerMask = responseMask & questionMask; uint8_t answerCount = 0; + uint8_t additionalMask = responseMask & ~questionMask; + uint8_t additionalCount = 0; for(i=0;i<4;i++){ - if(replyMask & (1 << i)) answerCount++; + if(answerMask & (1 << i)) answerCount++; + if(additionalMask & (1 << i)) additionalCount++; } @@ -960,146 +1046,150 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1 0x00, 0x00, //Question count 0x00, answerCount, //Answer count 0x00, 0x00, //Name server records - 0x00, 0x00, //Additional records + 0x00, additionalCount, //Additional records }; _conn->append(reinterpret_cast(head), 12); - // PTR Response - if(replyMask & 0x8){ - // Send the Name field (ie. "_http._tcp.local") - _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _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, class, ttl and rdata length - uint8_t ptrDataLen = instanceNameLen + serviceNameLen + protoNameLen + localNameLen + 5; // 5 is four label sizes and the terminator - uint8_t ptrAttrs[10] = { - 0x00, 0x0c, //PTR record query - 0x00, 0x01, //Class IN - 0x00, 0x00, 0x11, 0x94, //TTL 4500 - 0x00, ptrDataLen, //RData length - }; - _conn->append(reinterpret_cast(ptrAttrs), 10); - - //Send the RData (ie. "My IOT device._http._tcp.local") - _conn->append(reinterpret_cast(&instanceNameLen), 1); // lenght of "My IOT device" - _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" - _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // lenght "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - } + for(int responseSection = 0; responseSection < 2; ++responseSection) { - //TXT Responce - if(replyMask & 0x4){ - //Send the name field (ie. "My IOT device._http._tcp.local") - _conn->append(reinterpret_cast(&instanceNameLen), 1); // lenght of "My IOT device" - _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" - _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _conn->append(reinterpret_cast(&localNameLen), 1); // lenght "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator + // PTR Response + if((responseSection == 0 ? answerMask : additionalMask) & 0x8){ + // Send the Name field (ie. "_http._tcp.local") + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator - //Send the type, class, ttl and rdata length - uint8_t txtDataLen = _getServiceTxtLen(service,proto); - uint8_t txtAttrs[10] = { - 0x00, 0x10, //TXT record query - 0x00, 0x01, //Class IN - 0x00, 0x00, 0x11, 0x94, //TTL 4500 - 0x00, txtDataLen, //RData length - }; - _conn->append(reinterpret_cast(txtAttrs), 10); + //Send the type, class, ttl and rdata length + uint8_t ptrDataLen = instanceNameLen + serviceNameLen + protoNameLen + localNameLen + 5; // 5 is four label sizes and the terminator + uint8_t ptrAttrs[10] = { + 0x00, 0x0c, //PTR record query + 0x00, 0x01, //Class IN + 0x00, 0x00, 0x00, 0x78, //TTL 120 + 0x00, ptrDataLen, //RData length + }; + _conn->append(reinterpret_cast(ptrAttrs), 10); - //Send the RData - MDNSTxt * txtPtr = _getServiceTxt(service,proto); - while(txtPtr !=0){ - uint8_t txtLen = txtPtr->_txt.length(); - _conn->append(reinterpret_cast(&txtLen), 1); // lenght of txt - _conn->append(reinterpret_cast(txtPtr->_txt.c_str()), txtLen);// the txt - txtPtr = txtPtr->_next; + //Send the RData (ie. "My IOT device._http._tcp.local") + _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" + _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + } + + //TXT Responce + if((responseSection == 0 ? answerMask : additionalMask) & 0x4){ + //Send the name field (ie. "My IOT device._http._tcp.local") + _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" + _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + //Send the type, class, ttl and rdata length + uint8_t txtDataLen = _getServiceTxtLen(service,proto); + uint8_t txtAttrs[10] = { + 0x00, 0x10, //TXT record query + 0x80, 0x01, //Class IN, with cache flush + 0x00, 0x00, 0x11, 0x94, //TTL 4500 + 0x00, txtDataLen, //RData length + }; + _conn->append(reinterpret_cast(txtAttrs), 10); + + //Send the RData + MDNSTxt * txtPtr = _getServiceTxt(service,proto); + while(txtPtr !=0){ + uint8_t txtLen = txtPtr->_txt.length(); + _conn->append(reinterpret_cast(&txtLen), 1); // length of txt + _conn->append(reinterpret_cast(txtPtr->_txt.c_str()), txtLen);// the txt + txtPtr = txtPtr->_next; + } + } + + + //SRV Responce + if((responseSection == 0 ? answerMask : additionalMask) & 0x2){ + //Send the name field (ie. "My IOT device._http._tcp.local") + _conn->append(reinterpret_cast(&instanceNameLen), 1); // length of "My IOT device" + _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" + _conn->append(reinterpret_cast(&serviceNameLen), 1); // length of "_http" + _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" + _conn->append(reinterpret_cast(&protoNameLen), 1); // length of "_tcp" + _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + //Send the type, class, ttl, rdata length, priority and weight + uint8_t srvDataSize = hostNameLen + localNameLen + 3; // 3 is 2 lable size bytes and the terminator + srvDataSize += 6; // Size of Priority, weight and port + uint8_t srvAttrs[10] = { + 0x00, 0x21, //Type SRV + 0x80, 0x01, //Class IN, with cache flush + 0x00, 0x00, 0x00, 0x78, //TTL 120 + 0x00, srvDataSize, //RData length + }; + _conn->append(reinterpret_cast(srvAttrs), 10); + + //Send the RData Priority weight and port + uint8_t srvRData[6] = { + 0x00, 0x00, //Priority 0 + 0x00, 0x00, //Weight 0 + (uint8_t)((port >> 8) & 0xFF), (uint8_t)(port & 0xFF) + }; + _conn->append(reinterpret_cast(srvRData), 6); + //Send the RData (ie. "esp8266.local") + _conn->append(reinterpret_cast(&hostNameLen), 1); // length of "esp8266" + _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + } + + // A Response + if((responseSection == 0 ? answerMask : additionalMask) & 0x1){ + //Send the RData (ie. "esp8266.local") + _conn->append(reinterpret_cast(&hostNameLen), 1); // length of "esp8266" + _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" + _conn->append(reinterpret_cast(&localNameLen), 1); // length "local" + _conn->append(reinterpret_cast(localName), localNameLen); // "local" + _conn->append(reinterpret_cast(&terminator), 1); // terminator + + uint8_t aaaAttrs[10] = { + 0x00, 0x01, //TYPE A + 0x80, 0x01, //Class IN, with cache flush + 0x00, 0x00, 0x00, 0x78, //TTL 120 + 0x00, 0x04, //DATA LEN + }; + _conn->append(reinterpret_cast(aaaAttrs), 10); + + // Send RData + uint32_t ip = multicastInterface; + uint8_t aaaRData[4] = { + (uint8_t)(ip & 0xFF), //IP first octet + (uint8_t)((ip >> 8) & 0xFF), //IP second octet + (uint8_t)((ip >> 16) & 0xFF), //IP third octet + (uint8_t)((ip >> 24) & 0xFF) //IP fourth octet + }; + _conn->append(reinterpret_cast(aaaRData), 4); } } - - //SRV Responce - if(replyMask & 0x2){ - //Send the name field (ie. "My IOT device._http._tcp.local") - _conn->append(reinterpret_cast(&instanceNameLen), 1); // lenght of "My IOT device" - _conn->append(reinterpret_cast(instanceName.c_str()), instanceNameLen);// "My IOT device" - _conn->append(reinterpret_cast(&serviceNameLen), 1); // lenght of "_http" - _conn->append(reinterpret_cast(serviceName), serviceNameLen); // "_http" - _conn->append(reinterpret_cast(&protoNameLen), 1); // lenght of "_tcp" - _conn->append(reinterpret_cast(protoName), protoNameLen); // "_tcp" - _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, class, ttl, rdata length, priority and weight - uint8_t srvDataSize = hostNameLen + localNameLen + 3; // 3 is 2 lable size bytes and the terminator - srvDataSize += 6; // Size of Priority, weight and port - uint8_t srvAttrs[10] = { - 0x00, 0x21, //Type SRV - 0x80, 0x01, //Class IN, with cache flush - 0x00, 0x00, 0x00, 0x78, //TTL 120 - 0x00, srvDataSize, //RData length - }; - _conn->append(reinterpret_cast(srvAttrs), 10); - - //Send the RData Priority weight and port - uint8_t srvRData[6] = { - 0x00, 0x00, //Priority 0 - 0x00, 0x00, //Weight 0 - (uint8_t)((port >> 8) & 0xFF), (uint8_t)(port & 0xFF) - }; - _conn->append(reinterpret_cast(srvRData), 6); - //Send the RData (ie. "esp8266.local") - _conn->append(reinterpret_cast(&hostNameLen), 1); // lenght of "esp8266" - _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" - _conn->append(reinterpret_cast(&localNameLen), 1); // lenght "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - } - - // A Response - if(replyMask & 0x1){ - //Send the RData (ie. "esp8266.local") - _conn->append(reinterpret_cast(&hostNameLen), 1); // lenght of "esp8266" - _conn->append(reinterpret_cast(hostName.c_str()), hostNameLen);// "esp8266" - _conn->append(reinterpret_cast(&localNameLen), 1); // lenght "local" - _conn->append(reinterpret_cast(localName), localNameLen); // "local" - _conn->append(reinterpret_cast(&terminator), 1); // terminator - - uint8_t aaaAttrs[10] = { - 0x00, 0x01, //TYPE A - 0x80, 0x01, //Class IN, with cache flush - 0x00, 0x00, 0x00, 0x78, //TTL 120 - 0x00, 0x04, //DATA LEN - }; - _conn->append(reinterpret_cast(aaaAttrs), 10); - - // Send RData - uint8_t aaaRData[4] = { - (uint8_t)(ip & 0xFF), //IP first octet - (uint8_t)((ip >> 8) & 0xFF), //IP second octet - (uint8_t)((ip >> 16) & 0xFF), //IP third octet - (uint8_t)((ip >> 24) & 0xFF) //IP fourth octet - }; - _conn->append(reinterpret_cast(aaaRData), 4); - } - ip_addr_t ifaddr; - ifaddr.addr = ip; + ifaddr.addr = multicastInterface; _conn->setMulticastInterface(ifaddr); _conn->send(); } diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.h b/libraries/ESP8266mDNS/ESP8266mDNS.h index c8b3ee89e..37874194e 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/ESP8266mDNS.h @@ -125,9 +125,10 @@ private: uint16_t _getServicePort(char *service, char *proto); MDNSTxt * _getServiceTxt(char *name, char *proto); uint16_t _getServiceTxtLen(char *name, char *proto); + IPAddress _getRequestMulticastInterface(); void _parsePacket(); - void _reply(uint8_t replyMask, char * service, char *proto, uint16_t port, uint32_t ip); - size_t advertiseServices(); // advertise all hosted services + void _replyToTypeEnumRequest(IPAddress multicastInterface); + void _replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface); MDNSAnswer* _getAnswerFromIdx(int idx); int _getNumAnswers(); bool _listen();