2020-05-19 18:56:17 +00:00
|
|
|
#include "ReliableRouter.h"
|
2022-03-09 08:01:43 +00:00
|
|
|
#include "MeshModule.h"
|
2020-05-19 18:56:17 +00:00
|
|
|
#include "MeshTypes.h"
|
2022-05-07 10:31:21 +00:00
|
|
|
#include "configuration.h"
|
2020-05-19 18:56:17 +00:00
|
|
|
#include "mesh-pb-constants.h"
|
|
|
|
|
|
|
|
// ReliableRouter::ReliableRouter() {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If the message is want_ack, then add it to a list of packets to retransmit.
|
|
|
|
* If we run out of retransmissions, send a nak packet towards the original client to indicate failure.
|
|
|
|
*/
|
|
|
|
ErrorCode ReliableRouter::send(MeshPacket *p)
|
|
|
|
{
|
|
|
|
if (p->want_ack) {
|
2020-05-21 23:34:16 +00:00
|
|
|
// If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our
|
2022-05-07 10:31:21 +00:00
|
|
|
// message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop
|
|
|
|
// counts and we want this message to get through the whole mesh, so use the default.
|
2022-08-01 21:59:50 +00:00
|
|
|
if (p->hop_limit == 0) {
|
2022-05-21 20:38:33 +00:00
|
|
|
if (config.lora.hop_limit && config.lora.hop_limit <= HOP_MAX) {
|
|
|
|
p->hop_limit = (config.lora.hop_limit >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit;
|
2021-12-18 21:21:12 +00:00
|
|
|
} else {
|
|
|
|
p->hop_limit = HOP_RELIABLE;
|
|
|
|
}
|
|
|
|
}
|
2020-05-21 23:34:16 +00:00
|
|
|
|
2020-05-19 18:56:17 +00:00
|
|
|
auto copy = packetPool.allocCopy(*p);
|
|
|
|
startRetransmission(copy);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FloodingRouter::send(p);
|
|
|
|
}
|
|
|
|
|
2021-11-23 02:31:12 +00:00
|
|
|
bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
|
2020-05-25 18:55:42 +00:00
|
|
|
{
|
2021-03-05 03:44:45 +00:00
|
|
|
// Note: do not use getFrom() here, because we want to ignore messages sent from phone
|
2022-08-01 21:59:50 +00:00
|
|
|
if (p->from == getNodeNum()) {
|
2020-06-14 22:30:42 +00:00
|
|
|
printPacket("Rx someone rebroadcasting for us", p);
|
2020-05-25 18:55:42 +00:00
|
|
|
|
|
|
|
// We are seeing someone rebroadcast one of our broadcast attempts.
|
|
|
|
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
|
|
|
|
// the original sending process.
|
2021-03-13 00:29:58 +00:00
|
|
|
|
2022-05-07 10:31:21 +00:00
|
|
|
// FIXME - we might want to turn off this "optimization", it does save lots of airtime but it assumes that once we've
|
|
|
|
// heard one one adjacent node hear our packet that a) probably other adjacent nodes heard it and b) we can trust those
|
|
|
|
// nodes to reach our destination. Both of which might be incorrect.
|
2021-03-13 00:29:58 +00:00
|
|
|
auto key = GlobalPacketId(getFrom(p), p->id);
|
|
|
|
auto old = findPendingPacket(key);
|
|
|
|
if (old) {
|
2021-03-06 09:40:20 +00:00
|
|
|
DEBUG_MSG("generating implicit ack\n");
|
|
|
|
// NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be
|
|
|
|
// marked as wantAck
|
2021-03-13 00:29:58 +00:00
|
|
|
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, old->packet->channel);
|
|
|
|
|
|
|
|
stopRetransmission(key);
|
2022-05-07 10:31:21 +00:00
|
|
|
} else {
|
2021-05-03 06:46:30 +00:00
|
|
|
DEBUG_MSG("didn't find pending packet\n");
|
2021-05-03 02:53:06 +00:00
|
|
|
}
|
2020-05-25 18:55:42 +00:00
|
|
|
}
|
|
|
|
|
2021-11-23 02:31:12 +00:00
|
|
|
/* send acks for repeated packets that want acks and are destined for us
|
|
|
|
* this way if an ACK is dropped and a packet is resent we'll ACK the resent packet
|
|
|
|
* make sure wasSeenRecently _doesn't_ update
|
|
|
|
* finding the channel requires decoding the packet. */
|
|
|
|
if (p->want_ack && (p->to == getNodeNum()) && wasSeenRecently(p, false)) {
|
|
|
|
if (perhapsDecode(p)) {
|
|
|
|
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
|
|
|
DEBUG_MSG("acking a repeated want_ack packet\n");
|
|
|
|
}
|
2022-08-13 15:09:43 +00:00
|
|
|
} else if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE) {
|
|
|
|
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
|
|
|
|
DEBUG_MSG("Resending implicit ack for a repeated floodmsg\n");
|
|
|
|
MeshPacket *tosend = packetPool.allocCopy(*p);
|
|
|
|
tosend->hop_limit--; // bump down the hop count
|
|
|
|
Router::send(tosend);
|
2021-11-23 02:31:12 +00:00
|
|
|
}
|
|
|
|
|
2020-05-25 18:55:42 +00:00
|
|
|
return FloodingRouter::shouldFilterReceived(p);
|
|
|
|
}
|
|
|
|
|
2020-05-19 18:56:17 +00:00
|
|
|
/**
|
|
|
|
* If we receive a want_ack packet (do not check for wasSeenRecently), send back an ack (this might generate multiple ack sends in
|
|
|
|
* case the our first ack gets lost)
|
|
|
|
*
|
|
|
|
* If we receive an ack packet (do check wasSeenRecently), clear out any retransmissions and
|
|
|
|
* forward the ack to the application layer.
|
|
|
|
*
|
|
|
|
* If we receive a nak packet (do check wasSeenRecently), clear out any retransmissions
|
|
|
|
* and forward the nak to the application layer.
|
|
|
|
*
|
|
|
|
* Otherwise, let superclass handle it.
|
|
|
|
*/
|
2021-02-21 04:59:47 +00:00
|
|
|
void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
2020-05-19 18:56:17 +00:00
|
|
|
{
|
2020-05-21 19:47:41 +00:00
|
|
|
NodeNum ourNode = getNodeNum();
|
|
|
|
|
2020-05-25 18:55:42 +00:00
|
|
|
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability
|
|
|
|
// - not DSR routing)
|
2020-05-19 18:56:17 +00:00
|
|
|
if (p->want_ack) {
|
2022-03-09 08:01:43 +00:00
|
|
|
if (MeshModule::currentReply)
|
2021-03-12 06:10:36 +00:00
|
|
|
DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack\n");
|
2021-03-05 03:44:45 +00:00
|
|
|
else
|
2021-03-12 06:10:36 +00:00
|
|
|
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
2020-05-19 18:56:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-05 03:44:45 +00:00
|
|
|
// We consider an ack to be either a !routing packet with a request ID or a routing packet with !error
|
|
|
|
PacketId ackId = ((c && c->error_reason == Routing_Error_NONE) || !c) ? p->decoded.request_id : 0;
|
2020-05-19 18:56:17 +00:00
|
|
|
|
2021-03-05 03:44:45 +00:00
|
|
|
// A nak is a routing packt that has an error code
|
|
|
|
PacketId nakId = (c && c->error_reason != Routing_Error_NONE) ? p->decoded.request_id : 0;
|
|
|
|
|
|
|
|
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
|
|
|
|
if (ackId || nakId) {
|
|
|
|
if (ackId) {
|
|
|
|
DEBUG_MSG("Received a ack for 0x%x, stopping retransmissions\n", ackId);
|
|
|
|
stopRetransmission(p->to, ackId);
|
|
|
|
} else {
|
|
|
|
DEBUG_MSG("Received a nak for 0x%x, stopping retransmissions\n", nakId);
|
|
|
|
stopRetransmission(p->to, nakId);
|
2020-05-19 18:56:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle the packet as normal
|
2021-02-17 05:06:23 +00:00
|
|
|
FloodingRouter::sniffReceived(p, c);
|
2020-05-19 18:56:17 +00:00
|
|
|
}
|
|
|
|
|
2020-05-19 21:54:47 +00:00
|
|
|
#define NUM_RETRANSMISSIONS 3
|
|
|
|
|
|
|
|
PendingPacket::PendingPacket(MeshPacket *p)
|
|
|
|
{
|
|
|
|
packet = p;
|
|
|
|
numRetransmissions = NUM_RETRANSMISSIONS - 1; // We subtract one, because we assume the user just did the first send
|
|
|
|
}
|
|
|
|
|
2020-05-23 22:48:23 +00:00
|
|
|
PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key)
|
|
|
|
{
|
|
|
|
auto old = pending.find(key); // If we have an old record, someone messed up because id got reused
|
|
|
|
if (old != pending.end()) {
|
|
|
|
return &old->second;
|
|
|
|
} else
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-05-19 18:56:17 +00:00
|
|
|
/**
|
|
|
|
* Stop any retransmissions we are doing of the specified node/packet ID pair
|
|
|
|
*/
|
2020-05-21 19:47:41 +00:00
|
|
|
bool ReliableRouter::stopRetransmission(NodeNum from, PacketId id)
|
2020-05-19 21:54:47 +00:00
|
|
|
{
|
|
|
|
auto key = GlobalPacketId(from, id);
|
2020-05-21 22:55:57 +00:00
|
|
|
return stopRetransmission(key);
|
2020-05-19 21:54:47 +00:00
|
|
|
}
|
2020-05-19 18:56:17 +00:00
|
|
|
|
2020-05-21 19:47:41 +00:00
|
|
|
bool ReliableRouter::stopRetransmission(GlobalPacketId key)
|
2020-05-19 21:54:47 +00:00
|
|
|
{
|
2020-05-23 22:48:23 +00:00
|
|
|
auto old = findPendingPacket(key);
|
|
|
|
if (old) {
|
2020-05-19 21:54:47 +00:00
|
|
|
auto numErased = pending.erase(key);
|
|
|
|
assert(numErased == 1);
|
2022-05-07 13:39:14 +00:00
|
|
|
cancelSending(getFrom(old->packet), old->packet->id);
|
2020-05-21 19:47:41 +00:00
|
|
|
return true;
|
|
|
|
} else
|
|
|
|
return false;
|
2020-05-19 21:54:47 +00:00
|
|
|
}
|
2020-05-23 22:48:23 +00:00
|
|
|
|
2020-05-19 18:56:17 +00:00
|
|
|
/**
|
|
|
|
* Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting.
|
|
|
|
*/
|
2020-05-27 22:31:32 +00:00
|
|
|
PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p)
|
2020-05-19 21:54:47 +00:00
|
|
|
{
|
|
|
|
auto id = GlobalPacketId(p);
|
|
|
|
auto rec = PendingPacket(p);
|
|
|
|
|
2021-03-05 02:19:27 +00:00
|
|
|
stopRetransmission(getFrom(p), p->id);
|
2021-03-06 03:13:33 +00:00
|
|
|
|
|
|
|
setNextTx(&rec);
|
2020-05-19 21:54:47 +00:00
|
|
|
pending[id] = rec;
|
2020-05-27 22:31:32 +00:00
|
|
|
|
|
|
|
return &pending[id];
|
2020-05-19 21:54:47 +00:00
|
|
|
}
|
2020-05-19 18:56:17 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Do any retransmissions that are scheduled (FIXME - for the time being called from loop)
|
|
|
|
*/
|
2020-10-10 01:57:57 +00:00
|
|
|
int32_t ReliableRouter::doRetransmissions()
|
2020-05-19 21:54:47 +00:00
|
|
|
{
|
2020-09-05 19:34:48 +00:00
|
|
|
uint32_t now = millis();
|
2020-10-10 01:57:57 +00:00
|
|
|
int32_t d = INT32_MAX;
|
2020-05-19 21:54:47 +00:00
|
|
|
|
|
|
|
// FIXME, we should use a better datastructure rather than walking through this map.
|
|
|
|
// for(auto el: pending) {
|
|
|
|
for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt) {
|
|
|
|
++nextIt; // we use this odd pattern because we might be deleting it...
|
|
|
|
auto &p = it->second;
|
|
|
|
|
2021-03-06 03:13:33 +00:00
|
|
|
bool stillValid = true; // assume we'll keep this record around
|
|
|
|
|
2020-05-19 21:54:47 +00:00
|
|
|
// FIXME, handle 51 day rolloever here!!!
|
|
|
|
if (p.nextTxMsec <= now) {
|
|
|
|
if (p.numRetransmissions == 0) {
|
2021-03-06 03:19:52 +00:00
|
|
|
DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
|
2020-05-21 22:55:57 +00:00
|
|
|
p.packet->id);
|
2021-03-12 06:10:36 +00:00
|
|
|
sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel);
|
2020-05-23 22:48:23 +00:00
|
|
|
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which
|
|
|
|
// allows the DSR version to still be able to look at the PendingPacket
|
2020-05-25 18:55:42 +00:00
|
|
|
stopRetransmission(it->first);
|
2021-03-06 03:13:33 +00:00
|
|
|
stillValid = false; // just deleted it
|
2020-05-19 21:54:47 +00:00
|
|
|
} else {
|
2021-03-06 03:13:33 +00:00
|
|
|
DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from,
|
|
|
|
p.packet->to, p.packet->id, p.numRetransmissions);
|
2020-05-21 22:55:57 +00:00
|
|
|
|
|
|
|
// Note: we call the superclass version because we don't want to have our version of send() add a new
|
|
|
|
// retransmission record
|
|
|
|
FloodingRouter::send(packetPool.allocCopy(*p.packet));
|
2020-05-19 21:54:47 +00:00
|
|
|
|
|
|
|
// Queue again
|
|
|
|
--p.numRetransmissions;
|
2020-11-12 09:49:04 +00:00
|
|
|
setNextTx(&p);
|
2020-05-19 21:54:47 +00:00
|
|
|
}
|
2021-03-06 09:40:20 +00:00
|
|
|
}
|
2021-03-06 03:13:33 +00:00
|
|
|
|
2021-03-06 09:40:20 +00:00
|
|
|
if (stillValid) {
|
2021-03-06 03:13:33 +00:00
|
|
|
// Update our desired sleep delay
|
2020-10-10 01:57:57 +00:00
|
|
|
int32_t t = p.nextTxMsec - now;
|
|
|
|
|
|
|
|
d = min(t, d);
|
|
|
|
}
|
2020-05-19 21:54:47 +00:00
|
|
|
}
|
2020-10-10 01:57:57 +00:00
|
|
|
|
|
|
|
return d;
|
2021-03-06 03:13:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReliableRouter::setNextTx(PendingPacket *pending)
|
|
|
|
{
|
|
|
|
assert(iface);
|
|
|
|
auto d = iface->getRetransmissionMsec(pending->packet);
|
|
|
|
pending->nextTxMsec = millis() + d;
|
|
|
|
DEBUG_MSG("Setting next retransmission in %u msecs: ", d);
|
|
|
|
printPacket("", pending->packet);
|
|
|
|
setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time
|
2022-08-01 21:59:50 +00:00
|
|
|
}
|