Be more judicious about responding to want_response in existing meshes (#9014)

* Be more judicious about sending want_response in existing meshes and responding to nodes we already heard from

* Turns out we don't actually use this
This commit is contained in:
Ben Meadors
2025-12-19 13:56:10 -06:00
committed by GitHub
parent 85aba3a4f7
commit 31e55d0b66
3 changed files with 65 additions and 1 deletions

View File

@@ -7,17 +7,41 @@
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include <Throttle.h> #include <Throttle.h>
#include <algorithm>
#ifndef USERPREFS_NODEINFO_REPLY_SUPPRESS_SECS
#define USERPREFS_NODEINFO_REPLY_SUPPRESS_SECS (12 * 60 * 60)
#endif
NodeInfoModule *nodeInfoModule; NodeInfoModule *nodeInfoModule;
static constexpr uint32_t NodeInfoReplySuppressSeconds = USERPREFS_NODEINFO_REPLY_SUPPRESS_SECS;
bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_User *pptr) bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_User *pptr)
{ {
suppressReplyForCurrentRequest = false;
if (mp.from == nodeDB->getNodeNum()) { if (mp.from == nodeDB->getNodeNum()) {
LOG_WARN("Ignoring packet supposed to be from our own node: %08x", mp.from); LOG_WARN("Ignoring packet supposed to be from our own node: %08x", mp.from);
return false; return false;
} }
auto p = *pptr; auto p = *pptr;
if (mp.decoded.want_response) {
const NodeNum sender = getFrom(&mp);
const uint32_t now = mp.rx_time ? mp.rx_time : getTime();
auto it = lastNodeInfoSeen.find(sender);
if (it != lastNodeInfoSeen.end()) {
uint32_t sinceLast = now >= it->second ? now - it->second : 0;
if (sinceLast < NodeInfoReplySuppressSeconds) {
suppressReplyForCurrentRequest = true;
}
}
lastNodeInfoSeen[sender] = now;
pruneLastNodeInfoCache();
}
if (p.is_licensed != owner.is_licensed) { if (p.is_licensed != owner.is_licensed) {
LOG_WARN("Invalid nodeInfo detected, is_licensed mismatch!"); LOG_WARN("Invalid nodeInfo detected, is_licensed mismatch!");
return true; return true;
@@ -42,6 +66,8 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
service->sendToPhone(packetCopy); service->sendToPhone(packetCopy);
} }
pruneLastNodeInfoCache();
// LOG_DEBUG("did handleReceived"); // LOG_DEBUG("did handleReceived");
return false; // Let others look at this message also if they want return false; // Let others look at this message also if they want
} }
@@ -68,9 +94,11 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
if (p) { // Check whether we didn't ignore it if (p) { // Check whether we didn't ignore it
p->to = dest; p->to = dest;
p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && bool requestWantResponse = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&
config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
wantReplies; wantReplies;
p->decoded.want_response = requestWantResponse;
if (_shorterTimeout) if (_shorterTimeout)
p->priority = meshtastic_MeshPacket_Priority_DEFAULT; p->priority = meshtastic_MeshPacket_Priority_DEFAULT;
else else
@@ -89,6 +117,13 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
meshtastic_MeshPacket *NodeInfoModule::allocReply() meshtastic_MeshPacket *NodeInfoModule::allocReply()
{ {
if (suppressReplyForCurrentRequest) {
LOG_DEBUG("Skip send NodeInfo since we heard the requester <12h ago");
ignoreRequest = true;
suppressReplyForCurrentRequest = false;
return NULL;
}
if (!airTime->isTxAllowedChannelUtil(false)) { if (!airTime->isTxAllowedChannelUtil(false)) {
ignoreRequest = true; // Mark it as ignored for MeshModule ignoreRequest = true; // Mark it as ignored for MeshModule
LOG_DEBUG("Skip send NodeInfo > 40%% ch. util"); LOG_DEBUG("Skip send NodeInfo > 40%% ch. util");
@@ -125,6 +160,29 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply()
} }
} }
void NodeInfoModule::pruneLastNodeInfoCache()
{
if (!nodeDB || !nodeDB->meshNodes)
return;
const size_t maxEntries = nodeDB->meshNodes->size();
for (auto it = lastNodeInfoSeen.begin(); it != lastNodeInfoSeen.end();) {
if (!nodeDB->getMeshNode(it->first)) {
it = lastNodeInfoSeen.erase(it);
} else {
++it;
}
}
while (!lastNodeInfoSeen.empty() && lastNodeInfoSeen.size() > maxEntries) {
auto oldestIt = std::min_element(lastNodeInfoSeen.begin(), lastNodeInfoSeen.end(),
[](const std::pair<const NodeNum, uint32_t> &lhs,
const std::pair<const NodeNum, uint32_t> &rhs) { return lhs.second < rhs.second; });
lastNodeInfoSeen.erase(oldestIt);
}
}
NodeInfoModule::NodeInfoModule() NodeInfoModule::NodeInfoModule()
: ProtobufModule("nodeinfo", meshtastic_PortNum_NODEINFO_APP, &meshtastic_User_msg), concurrency::OSThread("NodeInfo") : ProtobufModule("nodeinfo", meshtastic_PortNum_NODEINFO_APP, &meshtastic_User_msg), concurrency::OSThread("NodeInfo")
{ {

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "ProtobufModule.h" #include "ProtobufModule.h"
#include <map>
/** /**
* NodeInfo module for sending/receiving NodeInfos into the mesh * NodeInfo module for sending/receiving NodeInfos into the mesh
@@ -43,6 +44,10 @@ class NodeInfoModule : public ProtobufModule<meshtastic_User>, private concurren
private: private:
uint32_t lastSentToMesh = 0; // Last time we sent our NodeInfo to the mesh uint32_t lastSentToMesh = 0; // Last time we sent our NodeInfo to the mesh
bool shorterTimeout = false; bool shorterTimeout = false;
bool suppressReplyForCurrentRequest = false;
std::map<NodeNum, uint32_t> lastNodeInfoSeen;
void pruneLastNodeInfoCache();
}; };
extern NodeInfoModule *nodeInfoModule; extern NodeInfoModule *nodeInfoModule;

View File

@@ -55,6 +55,7 @@
// "USERPREFS_MQTT_TLS_ENABLED": "false", // "USERPREFS_MQTT_TLS_ENABLED": "false",
// "USERPREFS_MQTT_ROOT_TOPIC": "event/REPLACEME", // "USERPREFS_MQTT_ROOT_TOPIC": "event/REPLACEME",
// "USERPREFS_RINGTONE_NAG_SECS": "60", // "USERPREFS_RINGTONE_NAG_SECS": "60",
// "USERPREFS_NODEINFO_REPLY_SUPPRESS_SECS": "43200",
"USERPREFS_RINGTONE_RTTTL": "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p", "USERPREFS_RINGTONE_RTTTL": "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p",
// "USERPREFS_NETWORK_IPV6_ENABLED": "1", // "USERPREFS_NETWORK_IPV6_ENABLED": "1",
"USERPREFS_TZ_STRING": "tzplaceholder " "USERPREFS_TZ_STRING": "tzplaceholder "