Files
MeshCore/src/helpers/CompanionDelayedReplies.h
T

96 lines
3.7 KiB
C++

#pragma once
#include "BaseSerialInterface.h"
#include <stdint.h>
namespace mesh {
// Fixed producer storage, independent of the transport's bounded frame queue.
// History is volatile and finite: it does not authenticate a host process or
// disambiguate arbitrarily late login replies, which have no reflected tag.
class CompanionDelayedReplies {
public:
CompanionDelayedReplies() noexcept;
enum Kind : uint8_t { None, Login, Status, Telemetry, Discovery, Binary, Trace };
enum Phase : uint8_t { Empty, Reserved, AwaitRadio, AwaitAdmission };
static constexpr uint8_t HISTORY_SIZE = 8;
static constexpr uint8_t NO_HISTORY = 255;
static constexpr uint32_t DELIVERY_GRACE_MS = 10000;
static constexpr uint32_t HOST_EXTRA_TIMEOUT_MS = 5000;
static constexpr uint32_t LOGIN_QUARANTINE_MS = 30000;
struct Reply {
BaseSerialInterface* route = nullptr;
uint32_t tag = 0, auth = 0;
uint32_t timeout = 0, radio_deadline = 0;
uint32_t sent_deadline = 0, delivery_deadline = 0;
uint16_t frame_len = 0;
Kind kind = None;
Phase phase = Empty;
uint8_t history = NO_HISTORY;
bool terminal = false, sent_pending = false, flood = false;
uint8_t frame[MAX_FRAME_SIZE] = {};
};
Reply request, trace;
private:
struct RequestGuard {
uint8_t peer[32] = {};
uint32_t tag = 0, until = 0;
Phase phase = Empty;
bool login = false;
};
struct TraceGuard {
uint32_t tag = 0, auth = 0, until = 0;
Phase phase = Empty;
};
RequestGuard requests[HISTORY_SIZE] = {};
TraceGuard traces[HISTORY_SIZE] = {};
static bool due(uint32_t now, uint32_t deadline);
static uint32_t retirementDeadline(uint32_t now, uint32_t radio_deadline,
uint32_t floor);
static uint32_t radioBudget(const Reply& reply);
static void reset(Reply& reply);
static void arm(Reply& reply, uint32_t timeout, bool flood, uint32_t now);
static bool store(Reply& reply, const uint8_t* frame, size_t len, uint32_t now);
static bool service(Reply& reply, BaseSerialInterface* serial, uint32_t now);
void prune(uint32_t now);
public:
bool reserveRequest(Kind kind, const uint8_t peer[32],
BaseSerialInterface* route, bool terminal, uint32_t now);
bool allowRequestTag(uint32_t tag);
void rememberLoginTag(uint32_t tag);
void armRequest(uint32_t tag, uint32_t timeout, bool flood, uint32_t now);
void abandonRequest();
void retireRequest(uint32_t now);
const uint8_t* requestPeer() const;
bool requestMatches(const uint8_t peer[32], uint32_t tag) const;
bool blocksResponse(const uint8_t peer[32], uint32_t tag, uint32_t now) const;
bool storeRequest(const uint8_t* frame, size_t len, uint32_t now);
void serviceRequest(BaseSerialInterface* serial, uint32_t now);
// Terminal TRACE reserves the same tuple history without taking the Binary
// slot. A live reservation is never evicted to make room for another host.
uint8_t reserveTrace(uint32_t tag, uint32_t auth, uint32_t now);
void abandonTrace(uint8_t history);
void retireTrace(uint8_t history, uint32_t now, uint32_t radio_deadline);
bool reserveBinaryTrace(uint32_t tag, uint32_t auth,
BaseSerialInterface* route, uint32_t now);
void armBinaryTrace(uint32_t timeout, uint32_t now);
void abandonBinaryTrace();
void retireBinaryTrace(uint32_t now);
bool blocksTrace(uint32_t tag, uint32_t auth, uint32_t now) const;
bool storeBinaryTrace(const uint8_t* frame, size_t len, uint32_t now);
void serviceBinaryTrace(BaseSerialInterface* serial, uint32_t now);
bool hasRequest() const { return request.phase != Empty; }
bool hasBinaryTrace() const { return trace.phase != Empty; }
bool hasReplyForRoute(BaseSerialInterface* route, uint32_t now) const;
};
} // namespace mesh