Files
RTNode-HeltecV4/lib/microReticulum/src/Destination.h
James L 5ed70dcca9 v1.0.0: Boundary mode with bidirectional LoRa↔TCP transport
Vendor microReticulum library with boundary mode transport fixes:
- Two-whitelist system gates backbone traffic (local addresses +
  mentioned addresses from local devices)
- Allow control_hashes and local destinations through boundary filter
  (fixes backbone→LoRa path discovery)
- Fix get_cached_packet() to call unpack() instead of update_hash()
  (fixes empty destination_hash in path responses)
- LRPROOF Identity::recall null guard
- remaining_hops HEADER_1/BROADCAST fix for final-hop delivery
- PROOF packets excluded from boundary wrapping
- Iterator invalidation fix in transport table cleanup
- is_backbone flag replaces string matching for interface identification

Firmware changes:
- Set is_backbone(true) on backbone TCP interface
- Rename default TcpInterface name to BackboneInterface
- Update comments for dual-use TcpInterface (backbone + local AP)
- Use vendored lib/microReticulum instead of PlatformIO registry
2026-02-23 18:08:29 -05:00

259 lines
11 KiB
C++
Executable File

#pragma once
//#include "Reticulum.h"
//#include "Link.h"
//#include "Interface.h"
#include "Identity.h"
#include "Bytes.h"
#include "Type.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <map>
#include <set>
#include <cassert>
#include <stdint.h>
namespace RNS {
class Interface;
class Link;
class Packet;
class RequestHandler {
public:
//p response_generator(path, data, request_id, link_id, remote_identity, requested_at)
using response_generator = Bytes(*)(const Bytes& path, const Bytes& data, const Bytes& request_id, const Bytes& link_id, const Identity& remote_identity, double requested_at);
public:
RequestHandler(const RequestHandler& handler) {
_path = handler._path;
_response_generator = handler._response_generator;
_allow = handler._allow;
_allowed_list = handler._allowed_list;
}
Bytes _path;
response_generator _response_generator = nullptr;
Type::Destination::request_policies _allow = Type::Destination::ALLOW_NONE;
std::set<Bytes> _allowed_list;
};
/**
* @brief A class used to describe endpoints in a Reticulum Network. Destination
* instances are used both to create outgoing and incoming endpoints. The
* destination type will decide if encryption, and what type, is used in
* communication with the endpoint. A destination can also announce its
* presence on the network, which will also distribute necessary keys for
* encrypted communication with it.
*
* @param identity An instance of :ref:`RNS.Identity<api-identity>`. Can hold only public keys for an outgoing destination, or holding private keys for an ingoing.
* @param direction ``RNS.Destination.IN`` or ``RNS.Destination.OUT``.
* @param type ``RNS.Destination.SINGLE``, ``RNS.Destination.GROUP`` or ``RNS.Destination.PLAIN``.
* @param app_name A string specifying the app name.
* @param aspects Any non-zero number of string arguments.
*/
class Destination {
public:
class Callbacks {
public:
using link_established = void(*)(Link& link);
//using packet = void(*)(uint8_t* data, uint16_t data_len, Packet *packet);
using packet = void(*)(const Bytes& data, const Packet& packet);
using proof_requested = bool(*)(const Packet& packet);
public:
link_established _link_established = nullptr;
packet _packet = nullptr;
proof_requested _proof_requested = nullptr;
friend class Destination;
};
using PathResponse = std::pair<double, Bytes>;
public:
Destination(Type::NoneConstructor none) {
MEM("Destination NONE object created, this: " + std::to_string((uintptr_t)this));
}
Destination(const Destination& destination) : _object(destination._object) {
MEM("Destination object copy created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Destination(
const Identity& identity,
const Type::Destination::directions direction,
const Type::Destination::types type,
const char* app_name,
const char* aspects
);
Destination(
const Identity& identity,
const Type::Destination::directions direction,
const Type::Destination::types type,
const Bytes& hash
);
virtual ~Destination();
inline Destination& operator = (const Destination& destination) {
_object = destination._object;
MEM("Destination object copy created by assignment, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
return *this;
}
inline operator bool() const {
return _object.get() != nullptr;
}
inline bool operator < (const Destination& destination) const {
return _object.get() < destination._object.get();
}
public:
static std::string expand_name(const Identity& identity, const char* app_name, const char* aspects);
static Bytes hash(const Identity& identity, const char* app_name, const char* aspects);
static Bytes name_hash(const char* app_name, const char* aspects);
static std::vector<std::string> app_and_aspects_from_name(const char* full_name);
static Bytes hash_from_name_and_identity(const char* full_name, const Identity& identity);
public:
//Packet announce(const Bytes& app_data = {}, bool path_response = false, const Interface& attached_interface = {Type::NONE}, const Bytes& tag = {}, bool send = true);
Packet announce(const Bytes& app_data, bool path_response, const Interface& attached_interface, const Bytes& tag = {}, bool send = true);
Packet announce(const Bytes& app_data = {}, bool path_response = false);
/*
Set or query whether the destination accepts incoming link requests.
:param accepts: If ``True`` or ``False``, this method sets whether the destination accepts incoming link requests. If not provided or ``None``, the method returns whether the destination currently accepts link requests.
:returns: ``True`` or ``False`` depending on whether the destination accepts incoming link requests, if the *accepts* parameter is not provided or ``None``.
*/
inline void accepts_links(bool accepts) { assert(_object); _object->_accept_link_requests = accepts; }
inline bool accepts_links() { assert(_object); return _object->_accept_link_requests; }
/*
Registers a function to be called when a link has been established to
this destination.
:param callback: A function or method with the signature *callback(link)* to be called when a new link is established with this destination.
*/
inline void set_link_established_callback(Callbacks::link_established callback) {
assert(_object);
_object->_callbacks._link_established = callback;
}
/*
Registers a function to be called when a packet has been received by
this destination.
:param callback: A function or method with the signature *callback(data, packet)* to be called when this destination receives a packet.
*/
inline void set_packet_callback(Callbacks::packet callback) {
assert(_object);
_object->_callbacks._packet = callback;
}
/*
Registers a function to be called when a proof has been requested for
a packet sent to this destination. Allows control over when and if
proofs should be returned for received packets.
:param callback: A function or method to with the signature *callback(packet)* be called when a packet that requests a proof is received. The callback must return one of True or False. If the callback returns True, a proof will be sent. If it returns False, a proof will not be sent.
*/
inline void set_proof_requested_callback(Callbacks::proof_requested callback) {
assert(_object);
_object->_callbacks._proof_requested = callback;
}
/*
Sets the destinations proof strategy.
:param proof_strategy: One of ``RNS.Destination.PROVE_NONE``, ``RNS.Destination.PROVE_ALL`` or ``RNS.Destination.PROVE_APP``. If ``RNS.Destination.PROVE_APP`` is set, the `proof_requested_callback` will be called to determine whether a proof should be sent or not.
*/
inline void set_proof_strategy(Type::Destination::proof_strategies proof_strategy) {
assert(_object);
//if (proof_strategy <= PROOF_NONE) {
// throw throw std::invalid_argument("Unsupported proof strategy");
//}
_object->_proof_strategy = proof_strategy;
}
void receive(const Packet& packet);
void incoming_link_request(const Bytes& data, const Packet& packet);
virtual const Bytes encrypt(const Bytes& data);
virtual const Bytes decrypt(const Bytes& data);
virtual const Bytes sign(const Bytes& message);
// CBA
bool has_link(const Link& link);
void remove_link(const Link& link);
inline std::string toString() const { if (!_object) return ""; return "{Destination:" + _object->_hash.toHex() + "}"; }
// getters
inline Type::Destination::types type() const { assert(_object); return _object->_type; }
inline Type::Destination::directions direction() const { assert(_object); return _object->_direction; }
inline Type::Destination::proof_strategies proof_strategy() const { assert(_object); return _object->_proof_strategy; }
inline const Bytes& hash() const { assert(_object); return _object->_hash; }
inline uint16_t mtu() const { assert(_object); return _object->_mtu; }
// CBA LINK
//inline const Bytes& link_id() const { assert(_object); return _object->_link_id; }
//inline Type::Link::status status() const { assert(_object); return _object->_status; }
inline const Callbacks& callbacks() const { assert(_object); return _object->_callbacks; }
inline const Identity& identity() const { assert(_object); return _object->_identity; }
inline const std::map<Bytes, PathResponse>& path_responses() const { assert(_object); return _object->_path_responses; }
inline const std::map<Bytes, RequestHandler>& request_handlers() const { assert(_object); return _object->_request_handlers; }
// setters
// CBA Don't allow changing destination hash after construction since it's used as key in collections
//inline void hash(const Bytes& hash) { assert(_object); _object->_hash = hash; _object->_hexhash = _object->_hash.toHex(); }
inline void type(Type::Destination::types type) { assert(_object); _object->_type = type; }
inline void mtu(uint16_t mtu) { assert(_object); _object->_mtu = mtu; }
// CBA LINK
//inline void link_id(const Bytes& id) { assert(_object); _object->_link_id = id; }
//inline void last_outbound(double time) { assert(_object); _object->_last_outbound = time; }
//inline void increment_tx() { assert(_object); ++_object->_tx; }
//inline void increment_txbytes(uint16_t bytes) { assert(_object); _object->_txbytes += bytes; }
private:
class Object {
public:
Object(const Identity& identity) : _identity(identity) { MEM("Destination::Data object created, this: " + std::to_string((uintptr_t)this)); }
virtual ~Object() { MEM("Destination::Data object destroyed, this: " + std::to_string((uintptr_t)this)); }
private:
bool _accept_link_requests = true;
Callbacks _callbacks;
std::map<Bytes, RequestHandler> _request_handlers;
Type::Destination::types _type;
Type::Destination::directions _direction;
Type::Destination::proof_strategies _proof_strategy = Type::Destination::PROVE_NONE;
uint16_t _mtu = 0;
std::map<Bytes, PathResponse> _path_responses;
std::set<Link> _links;
Identity _identity;
std::string _name;
// Generate the destination address hash
Bytes _hash;
Bytes _name_hash;
std::string _hexhash;
// CBA TODO when is _default_app_data a "callable"?
Bytes _default_app_data;
//z _callback = None
//z _proofcallback = None
// CBA LINK
// CBA _link_id is expected by Packet but only present in Link
// CBA TODO determine if Link needs to inherit from Destination or vice-versa
//Bytes _link_id;
//Type::Link::status _status;
//double _last_outbound = 0.0;
//uint16_t _tx = 0;
//uint32_t _txbytes = 0;
friend class Destination;
};
std::shared_ptr<Object> _object;
};
}