From be5f0a9ade316b7bda9feeb668e6b80613f88e72 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 4 Feb 2026 11:15:38 -0600 Subject: [PATCH] Implement UDP multicast handler start/stop to ensure proper lifecycle (#9524) * Implement UDP multicast handler start/stop to ensure proper lifecycle * Add close method to AsyncUDP and improve UDP multicast handler lifecycle management * Guard portduino --- src/mesh/udp/UdpMulticastHandler.h | 25 +++++++++++++++++++++++-- src/mesh/wifi/WiFiAPClient.cpp | 10 ++++++++++ src/platform/nrf52/AsyncUDP.cpp | 7 +++++++ src/platform/nrf52/AsyncUDP.h | 1 + 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/mesh/udp/UdpMulticastHandler.h b/src/mesh/udp/UdpMulticastHandler.h index 2df8686a3..d79b63ceb 100644 --- a/src/mesh/udp/UdpMulticastHandler.h +++ b/src/mesh/udp/UdpMulticastHandler.h @@ -22,10 +22,14 @@ class UdpMulticastHandler final { public: - UdpMulticastHandler() { udpIpAddress = IPAddress(224, 0, 0, 69); } + UdpMulticastHandler() : isRunning(false) { udpIpAddress = IPAddress(224, 0, 0, 69); } void start() { + if (isRunning) { + LOG_DEBUG("UDP multicast already running"); + return; + } if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT, 64)) { #if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) LOG_DEBUG("UDP Listening on IP: %u.%u.%u.%u:%u", udpIpAddress[0], udpIpAddress[1], udpIpAddress[2], udpIpAddress[3], @@ -34,13 +38,29 @@ class UdpMulticastHandler final LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str()); #endif udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); }); + isRunning = true; } else { LOG_DEBUG("Failed to listen on UDP"); } } + void stop() + { + if (!isRunning) { + return; + } + LOG_DEBUG("Stopping UDP multicast"); +#if defined(ARCH_ESP32) || defined(ARCH_NRF52) + udp.close(); +#endif + isRunning = false; + } + void onReceive(AsyncUDPPacket packet) { + if (!isRunning) { + return; + } size_t packetLength = packet.length(); #if defined(ARCH_NRF52) IPAddress ip = packet.remoteIP(); @@ -67,7 +87,7 @@ class UdpMulticastHandler final bool onSend(const meshtastic_MeshPacket *mp) { - if (!mp || !udp) { + if (!isRunning || !mp || !udp) { return false; } #if defined(ARCH_NRF52) @@ -92,5 +112,6 @@ class UdpMulticastHandler final private: IPAddress udpIpAddress; AsyncUDP udp; + bool isRunning; }; #endif // HAS_UDP_MULTICAST \ No newline at end of file diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index a95dfa58f..5d05c7fc6 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -391,6 +391,11 @@ static void WiFiEvent(WiFiEvent_t event) LOG_INFO("Disconnected from WiFi access point"); #ifdef WIFI_LED digitalWrite(WIFI_LED, LOW); +#endif +#if HAS_UDP_MULTICAST + if (udpHandler) { + udpHandler->stop(); + } #endif if (!isReconnecting) { WiFi.disconnect(false, true); @@ -417,6 +422,11 @@ static void WiFiEvent(WiFiEvent_t event) break; case ARDUINO_EVENT_WIFI_STA_LOST_IP: LOG_INFO("Lost IP address and IP address is reset to 0"); +#if HAS_UDP_MULTICAST + if (udpHandler) { + udpHandler->stop(); + } +#endif if (!isReconnecting) { WiFi.disconnect(false, true); syslog.disable(); diff --git a/src/platform/nrf52/AsyncUDP.cpp b/src/platform/nrf52/AsyncUDP.cpp index 836fb1307..d119ffddb 100644 --- a/src/platform/nrf52/AsyncUDP.cpp +++ b/src/platform/nrf52/AsyncUDP.cpp @@ -36,6 +36,13 @@ bool AsyncUDP::writeTo(const uint8_t *data, size_t len, IPAddress ip, uint16_t p return udp.endPacket(); } +void AsyncUDP::close() +{ + udp.stop(); + localPort = 0; + _onPacket = nullptr; +} + // AsyncUDPPacket AsyncUDPPacket::AsyncUDPPacket(EthernetUDP &source) : _udp(source), _remoteIP(source.remoteIP()), _remotePort(source.remotePort()) { diff --git a/src/platform/nrf52/AsyncUDP.h b/src/platform/nrf52/AsyncUDP.h index e2b406ba9..718277309 100644 --- a/src/platform/nrf52/AsyncUDP.h +++ b/src/platform/nrf52/AsyncUDP.h @@ -22,6 +22,7 @@ class AsyncUDP : public Print, private concurrency::OSThread bool listenMulticast(IPAddress multicastIP, uint16_t port, uint8_t ttl = 64); bool writeTo(const uint8_t *data, size_t len, IPAddress ip, uint16_t port); + void close(); size_t write(uint8_t b) override; size_t write(const uint8_t *data, size_t len) override;