From a0ac96dd5e5d3e6249b7e521b66fe7b912cae836 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Sun, 3 May 2020 23:30:48 +0200 Subject: [PATCH 1/3] udp multicast: testing multicasting and looping on interfaces --- libraries/ESP8266WiFi/src/WiFiUdp.cpp | 19 ++++++-- libraries/ESP8266WiFi/src/WiFiUdp.h | 8 ++++ .../ESP8266WiFi/src/include/UdpContext.h | 47 +++++++++++++++---- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/libraries/ESP8266WiFi/src/WiFiUdp.cpp b/libraries/ESP8266WiFi/src/WiFiUdp.cpp index a0a5c1d4e4..1561d8b269 100644 --- a/libraries/ESP8266WiFi/src/WiFiUdp.cpp +++ b/libraries/ESP8266WiFi/src/WiFiUdp.cpp @@ -85,6 +85,11 @@ uint8_t WiFiUDP::begin(uint16_t port) return (_ctx->listen(IPAddress(), port)) ? 1 : 0; } +uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) +{ + return beginMulticast(IPAddress(IP4_ADDR_ANY), multicast port); +} + uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) { if (_ctx) { @@ -156,11 +161,7 @@ int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) int WiFiUDP::beginPacketMulticast(IPAddress multicastAddress, uint16_t port, IPAddress interfaceAddress, int ttl) { - if (!_ctx) { - _ctx = new UdpContext; - _ctx->ref(); - } - if (!_ctx->connect(multicastAddress, port)) { + if (!beginPacket(multicastAddress, port)) return 0; } _ctx->setMulticastInterface(interfaceAddress); @@ -176,6 +177,14 @@ int WiFiUDP::endPacket() return (_ctx->send()) ? 1 : 0; } +int WiFiUDP::endPacketOverMulticast() +{ + if (!_ctx) + return 0; + + return (_ctx->send_multicast_all()) ? 1 : 0; +} + size_t WiFiUDP::write(uint8_t byte) { return write(&byte, 1); diff --git a/libraries/ESP8266WiFi/src/WiFiUdp.h b/libraries/ESP8266WiFi/src/WiFiUdp.h index a1cf42be10..428a018fb6 100644 --- a/libraries/ESP8266WiFi/src/WiFiUdp.h +++ b/libraries/ESP8266WiFi/src/WiFiUdp.h @@ -48,15 +48,18 @@ class WiFiUDP : public UDP, public SList { void stop() override; // join a multicast group and listen on the given port uint8_t beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port); + uint8_t beginMulticast(IPAddress multicast, uint16_t port); // Sending UDP packets // Start building up a packet to send to the remote host specific in ip and port // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port int beginPacket(IPAddress ip, uint16_t port) override; + // Start building up a packet to send to the remote host specific in host and port // Returns 1 if successful, 0 if there was a problem resolving the hostname or port int beginPacket(const char *host, uint16_t port) override; + // Start building up a packet to send to the multicast address // multicastAddress - muticast address to send to // interfaceAddress - the local IP address of the interface that should be used @@ -67,9 +70,14 @@ class WiFiUDP : public UDP, public SList { uint16_t port, IPAddress interfaceAddress, int ttl = 1); + // Finish off this packet and send it // Returns 1 if the packet was sent successfully, 0 if there was an error int endPacket() override; + + int beginPacketOverMulticast(const IPAddress& ip, uint16_t port) { return beginPacket(ip, port); } + int endPacketOverMulticast(); + // Write a single byte into the packet size_t write(uint8_t) override; // Write size bytes from buffer into the packet diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index a81384b2a7..3a67319bba 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -444,28 +444,55 @@ class UdpContext return false; } - if (!addr) { addr = &_pcb->remote_ip; port = _pcb->remote_port; } -#ifdef LWIP_MAYBE_XCC - uint16_t old_ttl = _pcb->ttl; - if (ip_addr_ismulticast(addr)) { - _pcb->ttl = _mcast_ttl; - } -#endif + err_t err = udp_sendto(_pcb, tx_copy, addr, port); if (err != ERR_OK) { DEBUGV(":ust rc=%d\r\n", (int) err); } -#ifdef LWIP_MAYBE_XCC - _pcb->ttl = old_ttl; -#endif + pbuf_free(tx_copy); return err == ERR_OK; } + bool send_multicast_all (CONST ip_addr_t* addr, uint16_t port) + { + if (!ip_addr_ismulticast(addr)) + { + return false; + } + + // backup PCB multicast settings + + // backup multicast IPv4 address + ip4_addr_t backup_mcast_addr; + ip4_addr_set(&backup_mcast_addr, udp_get_multicast_netif_addr(_pcb)); + // reset it in PCB (may be useless, interface setting is used first (i set))) + ip4_addr_set_any(udp_get_multicast_netif_addr(_pcb)); + // backup multicast interface (will be overwritten) + u8_t backup_mcast_index = udp_get_multicast_netif_index(_pcb); + + // loop on all interfaces and send + + bool ret = false; + for (netif* nif = netif_list; nif; nif = nif->next) + if (netif_is_up(nif)) + { + // change multicast interface + setMulticastInterface(nif); + ret ||= send(addr, port); + } + + // restore PCB multicast settings + udp_set_multicast_netif_index(_pcb, backup_mcast_index); + udp_set_multicast_netif_addr(_pcb, &backup_mcast_addr); + + return ret; + } + private: size_t _processSize (const pbuf* pb) From d4cb9bb5a10652f2eb9e05a5e02f0747b54478bb Mon Sep 17 00:00:00 2001 From: david gauchard Date: Mon, 4 May 2020 00:31:34 +0200 Subject: [PATCH 2/3] test on mDNS --- libraries/ESP8266WiFi/src/WiFiUdp.cpp | 2 +- .../ESP8266WiFi/src/include/UdpContext.h | 24 +++-- libraries/ESP8266mDNS/src/LEAmDNS.cpp | 89 ++++--------------- libraries/ESP8266mDNS/src/LEAmDNS.h | 5 +- libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp | 8 +- libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp | 4 +- .../ESP8266mDNS/src/LEAmDNS_Transfer.cpp | 2 +- 7 files changed, 42 insertions(+), 92 deletions(-) diff --git a/libraries/ESP8266WiFi/src/WiFiUdp.cpp b/libraries/ESP8266WiFi/src/WiFiUdp.cpp index 1561d8b269..c9be6d8977 100644 --- a/libraries/ESP8266WiFi/src/WiFiUdp.cpp +++ b/libraries/ESP8266WiFi/src/WiFiUdp.cpp @@ -85,7 +85,7 @@ uint8_t WiFiUDP::begin(uint16_t port) return (_ctx->listen(IPAddress(), port)) ? 1 : 0; } -uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) +uint8_t WiFiUDP::beginMulticast(IPAddress multicast, uint16_t port) { return beginMulticast(IPAddress(IP4_ADDR_ANY), multicast port); } diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index 3a67319bba..23579d7970 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -419,7 +419,7 @@ class UdpContext return size; } - bool send(CONST ip_addr_t* addr = 0, uint16_t port = 0) + bool send(CONST ip_addr_t* addr = 0, uint16_t port = 0, bool release_source = true) { size_t data_size = _tx_buf_offset; pbuf* tx_copy = pbuf_alloc(PBUF_TRANSPORT, data_size, PBUF_RAM); @@ -435,11 +435,13 @@ class UdpContext data_size -= will_copy; } } - if (_tx_buf_head) - pbuf_free(_tx_buf_head); - _tx_buf_head = 0; - _tx_buf_cur = 0; - _tx_buf_offset = 0; + if (release_source) { + if (_tx_buf_head) + pbuf_free(_tx_buf_head); + _tx_buf_head = 0; + _tx_buf_cur = 0; + _tx_buf_offset = 0; + } if(!tx_copy){ return false; } @@ -483,9 +485,17 @@ class UdpContext { // change multicast interface setMulticastInterface(nif); - ret ||= send(addr, port); + ret ||= send(addr, port, false); } + // release source + if (_tx_buf_head) + pbuf_free(_tx_buf_head); + _tx_buf_head = 0; + _tx_buf_cur = 0; + _tx_buf_offset = 0; + // ^^ optimization path: avoid tx_copy multiple times in ::send(,,false) + // restore PCB multicast settings udp_set_multicast_netif_index(_pcb, backup_mcast_index); udp_set_multicast_netif_addr(_pcb, &backup_mcast_addr); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.cpp b/libraries/ESP8266mDNS/src/LEAmDNS.cpp index 87ff5167ff..92cbc7aecf 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS.cpp @@ -62,11 +62,10 @@ MDNSResponder::MDNSResponder(void) m_pServiceQueries(0), m_fnServiceTxtCallback(0), #ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE - m_bPassivModeEnabled(true), + m_bPassivModeEnabled(true) #else - m_bPassivModeEnabled(false), + m_bPassivModeEnabled(false) #endif - m_netif(nullptr) { } @@ -95,6 +94,7 @@ MDNSResponder::~MDNSResponder(void) bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress, uint32_t p_u32TTL) { + (void)p_IPAddress; (void)p_u32TTL; // ignored bool bResult = false; @@ -102,82 +102,25 @@ bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress { if (_setHostname(p_pcHostname)) { - - //// select interface - - m_netif = nullptr; - IPAddress ipAddress = p_IPAddress; - - if (!ipAddress.isSet()) - { - - IPAddress sta = WiFi.localIP(); - IPAddress ap = WiFi.softAPIP(); - - if (sta.isSet()) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] STA interface selected\n"))); - ipAddress = sta; - } - else if (ap.isSet()) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] AP interface selected\n"))); - ipAddress = ap; - } - else - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] standard interfaces are not up, please specify one in ::begin()\n"))); - return false; - } - - // continue to ensure interface is UP - } - - // check existence of this IP address in the interface list - bool found = false; - m_netif = nullptr; - for (auto a : addrList) - if (ipAddress == a.addr()) - { - if (a.ifUp()) - { - found = true; - m_netif = a.interface(); - break; - } - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] found interface for IP '%s' but it is not UP\n"), ipAddress.toString().c_str());); - } - if (!found) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] interface defined by IP '%s' not found\n"), ipAddress.toString().c_str());); - return false; - } - - //// done selecting the interface - - if (m_netif->num == STATION_IF) + m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & pEvent) { - - m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & pEvent) + (void) pEvent; + // Ensure that _restart() runs in USER context + schedule_function([this]() { - (void) pEvent; - // Ensure that _restart() runs in USER context - schedule_function([this]() - { - MDNSResponder::_restart(); - }); + MDNSResponder::_restart(); }); + }); - m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & pEvent) + m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & pEvent) + { + (void) pEvent; + // Ensure that _restart() runs in USER context + schedule_function([this]() { - (void) pEvent; - // Ensure that _restart() runs in USER context - schedule_function([this]() - { - MDNSResponder::_restart(); - }); + MDNSResponder::_restart(); }); - } + }); bResult = _restart(); } diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.h b/libraries/ESP8266mDNS/src/LEAmDNS.h index fe02560aec..6a3e650922 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS.h @@ -1203,7 +1203,6 @@ class MDNSResponder MDNSDynamicServiceTxtCallbackFunc m_fnServiceTxtCallback; bool m_bPassivModeEnabled; stcProbeInformation m_HostProbeInformation; - CONST netif* m_netif; // network interface to run on /** CONTROL **/ /* MAINTENANCE */ @@ -1258,10 +1257,12 @@ class MDNSResponder uint16_t p_u16QueryType, stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers = 0); +/* const IPAddress _getResponseMulticastInterface() const { - return IPAddress(m_netif->ip_addr); + return IPAddress(IP4_ANY_ADDR); } +*/ uint8_t _replyMaskForHost(const stcMDNS_RRHeader& p_RRHeader, bool* p_pbFullNameMatch = 0) const; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp index 41e9524aba..40ff53c008 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp @@ -84,9 +84,7 @@ bool MDNSResponder::_process(bool p_bUserContext) } else { - bResult = (m_netif != nullptr) && - (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running - _updateProbeStatus() && // Probing + bResult = _updateProbeStatus() && // Probing _checkServiceQueryCache(); // Service query cache check } return bResult; @@ -98,9 +96,7 @@ bool MDNSResponder::_process(bool p_bUserContext) bool MDNSResponder::_restart(void) { - return ((m_netif != nullptr) && - (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running - (_resetProbeStatus(true)) && // Stop and restart probing + return ((_resetProbeStatus(true)) && // Stop and restart probing (_allocUDPContext())); // Restart UDP } diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp index e6d39914fe..d8cdf61426 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp @@ -221,12 +221,12 @@ bool MDNSResponder::_allocUDPContext(void) //TODO: set multicast address (lwip_joingroup() is IPv4 only at the time of writing) multicast_addr.addr = DNS_MQUERY_IPV6_GROUP_INIT; #endif - if (ERR_OK == igmp_joingroup(ip_2_ip4(&m_netif->ip_addr), ip_2_ip4(&multicast_addr))) + if (ERR_OK == igmp_joingroup(IP4_ADDR_ANY, ip_2_ip4(&multicast_addr))) { m_pUDPContext = new UdpContext; m_pUDPContext->ref(); - if (m_pUDPContext->listen(&m_netif->ip_addr, DNS_MQUERY_PORT)) + if (m_pUDPContext->listen(IP4_ADDR_ANY, DNS_MQUERY_PORT)) { m_pUDPContext->setMulticastTTL(MDNS_MULTICAST_TTL); m_pUDPContext->onRx(std::bind(&MDNSResponder::_callProcess, this)); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp index 7400abec42..3535f0fa71 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp @@ -133,7 +133,7 @@ bool MDNSResponder::_sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParamet #endif DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage_Multicast: Will send to '%s'.\n"), toMulticastAddress.toString().c_str());); bResult = ((_prepareMDNSMessage(p_rSendParameter, fromIPAddress)) && - (m_pUDPContext->send(toMulticastAddress, DNS_MQUERY_PORT))); + (m_pUDPContext->send_multicast_all(toMulticastAddress, DNS_MQUERY_PORT))); DEBUG_EX_ERR(if (!bResult) { From b0240c4c8f178ade4976978b5b02be42484b55ab Mon Sep 17 00:00:00 2001 From: david gauchard Date: Mon, 4 May 2020 11:12:38 +0200 Subject: [PATCH 3/3] fixes --- libraries/ESP8266WiFi/src/WiFiUdp.cpp | 4 +-- .../ESP8266WiFi/src/include/UdpContext.h | 29 +++++++++++-------- libraries/ESP8266mDNS/src/LEAmDNS.h | 4 +-- libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp | 2 +- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/libraries/ESP8266WiFi/src/WiFiUdp.cpp b/libraries/ESP8266WiFi/src/WiFiUdp.cpp index c9be6d8977..adc6119bad 100644 --- a/libraries/ESP8266WiFi/src/WiFiUdp.cpp +++ b/libraries/ESP8266WiFi/src/WiFiUdp.cpp @@ -87,7 +87,7 @@ uint8_t WiFiUDP::begin(uint16_t port) uint8_t WiFiUDP::beginMulticast(IPAddress multicast, uint16_t port) { - return beginMulticast(IPAddress(IP4_ADDR_ANY), multicast port); + return beginMulticast(IPAddress(IP4_ADDR_ANY), multicast, port); } uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) @@ -161,7 +161,7 @@ int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) int WiFiUDP::beginPacketMulticast(IPAddress multicastAddress, uint16_t port, IPAddress interfaceAddress, int ttl) { - if (!beginPacket(multicastAddress, port)) + if (!beginPacket(multicastAddress, port)) { return 0; } _ctx->setMulticastInterface(interfaceAddress); diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index 23579d7970..c8f306d0f8 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -436,11 +436,7 @@ class UdpContext } } if (release_source) { - if (_tx_buf_head) - pbuf_free(_tx_buf_head); - _tx_buf_head = 0; - _tx_buf_cur = 0; - _tx_buf_offset = 0; + reset_send_buffer(); } if(!tx_copy){ return false; @@ -460,8 +456,12 @@ class UdpContext return err == ERR_OK; } - bool send_multicast_all (CONST ip_addr_t* addr, uint16_t port) + bool send_multicast_all (CONST ip_addr_t* addr = 0, uint16_t port = 0) { + if (!addr) { + addr = &_pcb->remote_ip; + port = _pcb->remote_port; + } if (!ip_addr_ismulticast(addr)) { return false; @@ -485,15 +485,11 @@ class UdpContext { // change multicast interface setMulticastInterface(nif); - ret ||= send(addr, port, false); + ret = ret || send(addr, port, false); } // release source - if (_tx_buf_head) - pbuf_free(_tx_buf_head); - _tx_buf_head = 0; - _tx_buf_cur = 0; - _tx_buf_offset = 0; + reset_send_buffer(); // ^^ optimization path: avoid tx_copy multiple times in ::send(,,false) // restore PCB multicast settings @@ -505,6 +501,15 @@ class UdpContext private: + void reset_send_buffer () + { + if (_tx_buf_head) + pbuf_free(_tx_buf_head); + _tx_buf_head = 0; + _tx_buf_cur = 0; + _tx_buf_offset = 0; + } + size_t _processSize (const pbuf* pb) { size_t ret = 0; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.h b/libraries/ESP8266mDNS/src/LEAmDNS.h index 6a3e650922..6233d14ac9 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS.h @@ -1257,12 +1257,10 @@ class MDNSResponder uint16_t p_u16QueryType, stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers = 0); -/* const IPAddress _getResponseMulticastInterface() const { - return IPAddress(IP4_ANY_ADDR); + return IPAddress(IP4_ADDR_ANY); } -*/ uint8_t _replyMaskForHost(const stcMDNS_RRHeader& p_RRHeader, bool* p_pbFullNameMatch = 0) const; diff --git a/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp b/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp index d8cdf61426..8d1f7e5c81 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp @@ -221,7 +221,7 @@ bool MDNSResponder::_allocUDPContext(void) //TODO: set multicast address (lwip_joingroup() is IPv4 only at the time of writing) multicast_addr.addr = DNS_MQUERY_IPV6_GROUP_INIT; #endif - if (ERR_OK == igmp_joingroup(IP4_ADDR_ANY, ip_2_ip4(&multicast_addr))) + if (ERR_OK == igmp_joingroup(IP4_ADDR_ANY4, ip_2_ip4(&multicast_addr))) { m_pUDPContext = new UdpContext; m_pUDPContext->ref();