From a546d64e07d29306d8dad291e7fcbd2c18c71688 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Sat, 14 Jan 2017 21:09:09 -0700 Subject: [PATCH] ESP8266mDNS: support AP and STA interfaces at once Bind the UDP connection to IP_ADDR_ANY rather than a specific interface IP, so that it can receive queries from all interfaces at once. When processing a query, detect which interface it was received on, and pass this information to the reply code. Set the IP multicast interface before each transmission, so that we can route each packet to a different interface if required. These changes enable the code to respond correctly on both AP and STA interfaces at once. The original code only worked correctly for the STA interface if both were enabled. When advertizing all services, do it on both AP and STA interfaces if they're both enabled. Provide an API for the application to notify the MDNS code if the AP configuration changes (enabled, disabled, IP changed). Ideally, the WiFi core would provide an event callback for this purpose, as it does for STA changes, but it does not appear to, so the application must provide this information. --- libraries/ESP8266mDNS/ESP8266mDNS.cpp | 73 ++++++++++++++------------- libraries/ESP8266mDNS/ESP8266mDNS.h | 5 +- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index 2643d6c4a..6d92b7c66 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -170,6 +170,10 @@ bool MDNSResponder::begin(const char* hostname){ return _listen(); } +void MDNSResponder::notifyAPChange() { + _restart(); +} + void MDNSResponder::_restart() { if (_conn) { _conn->unref(); @@ -181,23 +185,13 @@ void MDNSResponder::_restart() { bool MDNSResponder::_listen() { // Open the MDNS socket if it isn't already open. if (!_conn) { - uint32_t ourIp = _getOurIp(); - if(ourIp == 0){ - #ifdef MDNS_DEBUG_RX - Serial.println("MDNS: no IP address to listen on"); - #endif - return false; - } #ifdef MDNS_DEBUG_RX - Serial.print("MDNS listening on IP: "); - Serial.println(IPAddress(ourIp)); + Serial.println("MDNS listening"); #endif - ip_addr_t ifaddr; - ifaddr.addr = ourIp; ip_addr_t multicast_addr; multicast_addr.addr = (uint32_t) MDNS_MULTICAST_ADDR; - if (igmp_joingroup(&ifaddr, &multicast_addr)!= ERR_OK) { + if (igmp_joingroup(IP_ADDR_ANY, &multicast_addr)!= ERR_OK) { return false; } @@ -207,7 +201,6 @@ bool MDNSResponder::_listen() { if (!_conn->listen(*IP_ADDR_ANY, MDNS_PORT)) { return false; } - _conn->setMulticastInterface(ifaddr); _conn->setMulticastTTL(MDNS_MULTICAST_TTL); _conn->onRx(std::bind(&MDNSResponder::update, this)); _conn->connect(multicast_addr, MDNS_PORT); @@ -444,24 +437,6 @@ uint16_t MDNSResponder::_getServicePort(char *name, char *proto){ return 0; } -uint32_t MDNSResponder::_getOurIp(){ - int mode = wifi_get_opmode(); - if(mode & STATION_MODE){ - struct ip_info staIpInfo; - wifi_get_ip_info(STATION_IF, &staIpInfo); - return staIpInfo.ip.addr; - } else if (mode & SOFTAP_MODE) { - struct ip_info staIpInfo; - wifi_get_ip_info(SOFTAP_IF, &staIpInfo); - return staIpInfo.ip.addr; - } else { -#ifdef MDNS_DEBUG_ERR - Serial.printf("ERR_NO_LOCAL_IP\n"); -#endif - return 0; - } -} - void MDNSResponder::_parsePacket(){ int i; char tmp; @@ -868,7 +843,20 @@ void MDNSResponder::_parsePacket(){ else if(questions[i] == MDNS_TYPE_PTR) responseMask |= 0xF; } - return _reply(responseMask, serviceName, protoName, servicePort); + 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); + uint32_t ip = ip_info.ip.addr; + + return _reply(responseMask, serviceName, protoName, servicePort, ip); } void MDNSResponder::enableArduino(uint16_t port, bool auth){ @@ -882,17 +870,28 @@ void MDNSResponder::enableArduino(uint16_t port, bool auth){ size_t MDNSResponder::advertiseServices(){ 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){ - _reply(0x0F, servicePtr->_name, servicePtr->_proto, servicePtr->_port); + 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(SOFTAP_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){ +void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint16_t port, uint32_t ip) { int i; if(replyMask == 0) return; @@ -1062,7 +1061,6 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1 _conn->append(reinterpret_cast(localName), localNameLen); // "local" _conn->append(reinterpret_cast(&terminator), 1); // terminator - uint32_t ip = _getOurIp(); uint8_t aaaAttrs[10] = { 0x00, 0x01, //TYPE A 0x80, 0x01, //Class IN, with cache flush @@ -1081,7 +1079,10 @@ void MDNSResponder::_reply(uint8_t replyMask, char * service, char *proto, uint1 _conn->append(reinterpret_cast(aaaRData), 4); } - _conn->send(); + ip_addr_t ifaddr; + ifaddr.addr = ip; + _conn->setMulticastInterface(ifaddr); + _conn->send(); } #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.h b/libraries/ESP8266mDNS/ESP8266mDNS.h index 01cffe28f..e7b9955bc 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.h +++ b/libraries/ESP8266mDNS/ESP8266mDNS.h @@ -66,6 +66,8 @@ public: bool begin(const char* hostName, IPAddress ip, uint32_t ttl=120){ return begin(hostName); } + /* Application should call this whenever AP is configured/disabled */ + void notifyAPChange(); void update(); void addService(char *service, char *proto, uint16_t port); @@ -118,12 +120,11 @@ private: WiFiEventHandler _gotIPHandler; - uint32_t _getOurIp(); uint16_t _getServicePort(char *service, char *proto); MDNSTxt * _getServiceTxt(char *name, char *proto); uint16_t _getServiceTxtLen(char *name, char *proto); void _parsePacket(); - void _reply(uint8_t replyMask, char * service, char *proto, uint16_t port); + void _reply(uint8_t replyMask, char * service, char *proto, uint16_t port, uint32_t ip); size_t advertiseServices(); // advertise all hosted services MDNSAnswer* _getAnswerFromIdx(int idx); int _getNumAnswers();