Skip to content

Commit

Permalink
Handle repeated packet after potentially canceling previous Tx (#5330)
Browse files Browse the repository at this point in the history
* Revert "Fix sending duplicate packets to PhoneAPI/MQTT (#5315)"

This reverts commit 40bc04b.

* Handle repeated packet after potentially canceling previous Tx
  • Loading branch information
GUVWAF authored Nov 12, 2024
1 parent 2ec3958 commit e866734
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 48 deletions.
38 changes: 30 additions & 8 deletions src/mesh/FloodingRouter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
if (Router::cancelSending(p->from, p->id))
txRelayCanceled++;
}

/* If the original transmitter is doing retransmissions (hopStart equals hopLimit) for a reliable transmission, e.g., when
the ACK got lost, we will handle the packet again to make sure it gets an ACK to its packet. */
bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit;
if (isRepeated) {
LOG_DEBUG("Repeated reliable tx");
if (!perhapsRebroadcast(p) && isToUs(p) && p->want_ack) {
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0);
}
}

return true;
}

Expand All @@ -41,14 +52,8 @@ bool FloodingRouter::isRebroadcaster()
config.device.rebroadcast_mode != meshtastic_Config_DeviceConfig_RebroadcastMode_NONE;
}

void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p)
{
bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0);
if (isAckorReply && !isToUs(p) && !isBroadcast(p->to)) {
// do not flood direct message that is ACKed or replied to
LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast");
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM
}
if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) {
if (p->id != 0) {
if (isRebroadcaster()) {
Expand All @@ -67,13 +72,30 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
// Note: we are careful to resend using the original senders node id
// We are careful not to call our hooked version of send() - because we don't want to check this again
Router::send(tosend);

return true;
} else {
LOG_DEBUG("No rebroadcast: Role = CLIENT_MUTE or Rebroadcast Mode = NONE");
}
} else {
LOG_DEBUG("Ignore 0 id broadcast");
}
}

return false;
}

void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
{
bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0);
if (isAckorReply && !isToUs(p) && !isBroadcast(p->to)) {
// do not flood direct message that is ACKed or replied to
LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast");
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM
}

perhapsRebroadcast(p);

// handle the packet as normal
Router::sniffReceived(p, c);
}
}
7 changes: 6 additions & 1 deletion src/mesh/FloodingRouter.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "PacketHistory.h"
#include "Router.h"

/**
Expand All @@ -25,11 +26,15 @@
Any entries in recentBroadcasts that are older than X seconds (longer than the
max time a flood can take) will be discarded.
*/
class FloodingRouter : public Router
class FloodingRouter : public Router, protected PacketHistory
{
private:
bool isRebroadcaster();

/** Check if we should rebroadcast this packet, and do so if needed
* @return true if rebroadcasted */
bool perhapsRebroadcast(const meshtastic_MeshPacket *p);

public:
/**
* Constructor
Expand Down
16 changes: 2 additions & 14 deletions src/mesh/PacketHistory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ PacketHistory::PacketHistory()
/**
* Update recentBroadcasts and return true if we have already seen this packet
*/
bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate, bool *isRepeated)
bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate)
{
if (p->id == 0) {
LOG_DEBUG("Ignore message with zero id");
Expand All @@ -38,18 +38,6 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd
seenRecently = false;
}

/* If the original transmitter is doing retransmissions (hopStart equals hopLimit) for a reliable transmission, e.g., when the
ACK got lost, we will handle the packet again to make sure it gets an ACK/response to its packet. */
if (seenRecently && p->hop_start > 0 && p->hop_start == p->hop_limit) {
if (withUpdate)
LOG_DEBUG("Repeated reliable tx");

if (isRepeated)
*isRepeated = true;

seenRecently = false;
}

if (seenRecently) {
LOG_DEBUG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x", p->from, p->to, p->id);
}
Expand All @@ -59,7 +47,7 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd
recentPackets.erase(found); // as unsorted_set::iterator is const (can't update timestamp - so re-insert..)
}
recentPackets.insert(r);
LOG_DEBUG("Add packet record fr=0x%x, id=0x%x", p->from, p->id);
printPacket("Add packet record", p);
}

// Capacity is reerved, so only purge expired packets if recentPackets fills past 90% capacity
Expand Down
6 changes: 3 additions & 3 deletions src/mesh/PacketHistory.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "NodeDB.h"
#include "Router.h"
#include <unordered_set>

/// We clear our old flood record 10 minutes after we see the last of it
Expand Down Expand Up @@ -41,5 +41,5 @@ class PacketHistory
*
* @param withUpdate if true and not found we add an entry to recentPackets
*/
bool wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate = true, bool *isRepeated = nullptr);
};
bool wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate = true);
};
3 changes: 1 addition & 2 deletions src/mesh/PhoneAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include "PhoneAPI.h"
#include "PowerFSM.h"
#include "RadioInterface.h"
#include "Router.h"
#include "TypeConversions.h"
#include "main.h"
#include "xmodem.h"
Expand Down Expand Up @@ -657,4 +656,4 @@ int PhoneAPI::onNotify(uint32_t newValue)
}

return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one
}
}
12 changes: 2 additions & 10 deletions src/mesh/Router.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -622,17 +622,9 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
// us (because we would be able to decrypt it)
if (!decoded && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 && !isBroadcast(p->to) && !isToUs(p))
p_encrypted->pki_encrypted = true;

// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
if ((decoded || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled && !isFromUs(p) && mqtt) {
// Check if it wasn't already seen, then we don't need to handle it again
bool isRepeated = false;
bool *rptr = &isRepeated;
wasSeenRecently(p, false, rptr);
if (!isRepeated) {
mqtt->onSend(*p_encrypted, *p, p->channel);
}
}
if ((decoded || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled && !isFromUs(p) && mqtt)
mqtt->onSend(*p_encrypted, *p, p->channel);
#endif
}

Expand Down
3 changes: 1 addition & 2 deletions src/mesh/Router.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
#include "MemoryPool.h"
#include "MeshTypes.h"
#include "Observer.h"
#include "PacketHistory.h"
#include "PointerQueue.h"
#include "RadioInterface.h"
#include "concurrency/OSThread.h"

/**
* A mesh aware router that supports multiple interfaces.
*/
class Router : protected concurrency::OSThread, protected PacketHistory
class Router : protected concurrency::OSThread
{
private:
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
Expand Down
10 changes: 2 additions & 8 deletions src/modules/RoutingModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,8 @@ bool RoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mesh
// FIXME - move this to a non promsicious PhoneAPI module?
// Note: we are careful not to send back packets that started with the phone back to the phone
if ((isBroadcast(mp.to) || isToUs(&mp)) && (mp.from != 0)) {
// Check if it wasn't already seen, then we don't need to handle it again
bool isRepeated = false;
bool *rptr = &isRepeated;
router->wasSeenRecently(&mp, false, rptr);
if (!isRepeated) {
printPacket("Delivering rx packet", &mp);
service->handleFromRadio(&mp);
}
printPacket("Delivering rx packet", &mp);
service->handleFromRadio(&mp);
}

return false; // Let others look at this message also if they want
Expand Down

0 comments on commit e866734

Please sign in to comment.