WIP: Refactored to minimize circular dependenies

Moved core class constants and enums into single header Types.h.
Switched form class-specific NoneContructor to single
Type::NoneConstructor.
This commit is contained in:
attermann 2023-11-19 11:36:09 -07:00
parent a2e956eced
commit 33fda8a7f9
26 changed files with 561 additions and 519 deletions

View File

@ -19,6 +19,7 @@ build_flags =
-Wextra
-Wno-missing-field-initializers
-Wno-format
-Wno-unused-parameter
-Isrc
-DNATIVE
lib_deps =

View File

@ -65,6 +65,8 @@ namespace RNS { namespace Cryptography {
public:
// creates a new instance with a random seed
static inline Ptr generate() {
// CBA TODO determine why below is confused with (implicit) copy constructor
//return Ptr(new Ed25519PrivateKey({Bytes::NONE}));
return Ptr(new Ed25519PrivateKey(Bytes::NONE));
}

View File

@ -5,7 +5,7 @@
using namespace RNS;
Bytes RNS::Cryptography::hkdf(size_t length, const Bytes &derive_from, const Bytes &salt /*= Bytes::NONE*/, const Bytes &context /*= Bytes::NONE*/) {
Bytes RNS::Cryptography::hkdf(size_t length, const Bytes &derive_from, const Bytes &salt /*= {Bytes::NONE}*/, const Bytes &context /*= {Bytes::NONE}*/) {
if (length <= 0) {
throw std::invalid_argument("Invalid output key length");

View File

@ -4,6 +4,6 @@
namespace RNS { namespace Cryptography {
Bytes hkdf(size_t length, const Bytes &derive_from, const Bytes &salt = Bytes::NONE, const Bytes &context = Bytes::NONE);
Bytes hkdf(size_t length, const Bytes &derive_from, const Bytes &salt = {Bytes::NONE}, const Bytes &context = {Bytes::NONE});
} }

View File

@ -28,7 +28,7 @@ namespace RNS { namespace Cryptography {
msg: bytes or buffer, Initial input for the hash or None.
digest: The underlying hash algorithm to use
*/
HMAC(const Bytes &key, const Bytes &msg = Bytes::NONE, Digest digest = DIGEST_SHA256) {
HMAC(const Bytes &key, const Bytes &msg = {Bytes::NONE}, Digest digest = DIGEST_SHA256) {
if (digest == DIGEST_NONE) {
throw std::invalid_argument("Cannot derive key from empty input material");
@ -83,7 +83,7 @@ namespace RNS { namespace Cryptography {
method, and can ask for the hash value at any time by calling its digest()
method.
*/
static inline Ptr generate(const Bytes &key, const Bytes &msg = Bytes::NONE, Digest digest = DIGEST_SHA256) {
static inline Ptr generate(const Bytes &key, const Bytes &msg = {Bytes::NONE}, Digest digest = DIGEST_SHA256) {
return Ptr(new HMAC(key, msg, digest));
}

View File

@ -97,7 +97,7 @@ namespace RNS { namespace Cryptography {
}
*/
static inline Ptr generate() {
return from_private_bytes(Bytes::NONE);
return from_private_bytes({Bytes::NONE});
}
// creates a new instance with specified seed

View File

@ -10,6 +10,7 @@
#include <vector>
using namespace RNS;
using namespace RNS::Type::Destination;
Destination::Destination(const Identity &identity, const directions direction, const types type, const char* app_name, const char *aspects) : _object(new Object(identity)) {
assert(_object);
@ -23,7 +24,7 @@ Destination::Destination(const Identity &identity, const directions direction, c
_object->_direction = direction;
std::string fullaspects(aspects);
if (!identity && direction == Destination::IN && _object->_type != Destination::PLAIN) {
if (!identity && direction == IN && _object->_type != PLAIN) {
debug("Destination::Destination: identity not provided, creating new one");
_object->_identity = Identity();
// CBA TODO should following include a "." delimiter?
@ -31,7 +32,7 @@ Destination::Destination(const Identity &identity, const directions direction, c
}
debug("Destination::Destination: full aspects: " + fullaspects);
if (_object->_identity && _object->_type == Destination::PLAIN) {
if (_object->_identity && _object->_type == PLAIN) {
throw std::invalid_argument("Selected destination type PLAIN cannot hold an identity");
}
@ -45,7 +46,7 @@ Destination::Destination(const Identity &identity, const directions direction, c
debug("Destination::Destination: hash: " + _object->_hash.toHex());
// CBA TEST CRASH
debug("Destination::Destination: creating name hash...");
_object->_name_hash = Identity::truncated_hash(expand_name(Identity::NONE, app_name, fullaspects.c_str()));
_object->_name_hash = Identity::truncated_hash(expand_name({Type::NONE}, app_name, fullaspects.c_str()));
debug("Destination::Destination: name hash: " + _object->_name_hash.toHex());
debug("Destination::Destination: calling register_destination");
@ -60,7 +61,7 @@ Destination::Destination(const Identity &identity, const directions direction, c
/*static*/ Bytes Destination::hash(const Identity &identity, const char *app_name, const char *aspects) {
//name_hash = Identity::full_hash(Destination.expand_name(None, app_name, *aspects).encode("utf-8"))[:(RNS.Identity.NAME_HASH_LENGTH//8)]
//addr_hash_material = name_hash
Bytes addr_hash_material = Identity::truncated_hash(expand_name(Identity::NONE, app_name, aspects));
Bytes addr_hash_material = Identity::truncated_hash(expand_name({Type::NONE}, app_name, aspects));
//if identity != None:
// if isinstance(identity, RNS.Identity):
// addr_hash_material += identity.hash
@ -121,7 +122,7 @@ Packet Destination::announce(const Bytes &app_data, bool path_response, Interfac
//Response &entry = *it;
// map
PathResponse &entry = (*it).second;
if (now > (entry.first + Destination::PR_TAG_WINDOW)) {
if (now > (entry.first + PR_TAG_WINDOW)) {
it = _object->_path_responses.erase(it);
}
else {
@ -205,18 +206,18 @@ Packet Destination::announce(const Bytes &app_data, bool path_response, Interfac
}
debug("Destination::announce: announce_data:" + announce_data.toHex());
Packet::context_types announce_context = Packet::CONTEXT_NONE;
Type::Packet::context_types announce_context = Type::Packet::CONTEXT_NONE;
if (path_response) {
announce_context = Packet::PATH_RESPONSE;
announce_context = Type::Packet::PATH_RESPONSE;
}
debug("Destination::announce: creating announce packet...");
Packet announce_packet(*this, announce_data, Packet::ANNOUNCE, announce_context, Transport::BROADCAST, Packet::HEADER_1, nullptr, attached_interface);
Packet announce_packet(*this, announce_data, Type::Packet::ANNOUNCE, announce_context, Type::Transport::BROADCAST, Type::Packet::HEADER_1, nullptr, attached_interface);
if (send) {
debug("Destination::announce: sending announce packet...");
announce_packet.send();
return Packet::NONE;
return {Type::NONE};
}
else {
return announce_packet;
@ -267,7 +268,7 @@ bool Destination::deregister_request_handler(const Bytes &path) {
void Destination::receive(const Packet &packet) {
assert(_object);
if (packet.packet_type() == Packet::LINKREQUEST) {
if (packet.packet_type() == Type::Packet::LINKREQUEST) {
Bytes plaintext(packet.data());
incoming_link_request(plaintext, packet);
}
@ -276,7 +277,7 @@ void Destination::receive(const Packet &packet) {
Bytes plaintext(decrypt(packet.data()));
extreme("Destination::receive: decrypted data: " + plaintext.toHex());
if (plaintext) {
if (packet.packet_type() == RNS::Packet::DATA) {
if (packet.packet_type() == Type::Packet::DATA) {
if (_object->_callbacks._packet) {
try {
_object->_callbacks._packet(plaintext, packet);
@ -293,10 +294,10 @@ void Destination::receive(const Packet &packet) {
void Destination::incoming_link_request(const Bytes &data, const Packet &packet) {
assert(_object);
if (_object->_accept_link_requests) {
//zlink = RNS::Link::validate_request(data, packet);
//zif (link) {
//z link = Link::validate_request(data, packet);
//z if (link) {
//z _links.append(link);
//z}
//z }
}
}
@ -310,16 +311,16 @@ Bytes Destination::encrypt(const Bytes &data) {
assert(_object);
debug("Destination::encrypt: encrypting data...");
if (_object->_type == Destination::PLAIN) {
if (_object->_type == PLAIN) {
return data;
}
if (_object->_type == Destination::SINGLE && _object->_identity) {
if (_object->_type == SINGLE && _object->_identity) {
return _object->_identity.encrypt(data);
}
/*
if (_object->_type == Destination::GROUP {
if (_object->_type == GROUP {
if hasattr(self, "prv") and self.prv != None:
try:
return self.prv.encrypt(plaintext)
@ -331,7 +332,7 @@ Bytes Destination::encrypt(const Bytes &data) {
}
*/
// MOCK
return Bytes::NONE;
return {Bytes::NONE};
}
/*
@ -344,16 +345,16 @@ Bytes Destination::decrypt(const Bytes &data) {
assert(_object);
debug("Destination::decrypt: decrypting data...");
if (_object->_type == Destination::PLAIN) {
if (_object->_type == PLAIN) {
return data;
}
if (_object->_type == Destination::SINGLE && _object->_identity) {
if (_object->_type == SINGLE && _object->_identity) {
return _object->_identity.decrypt(data);
}
/*
if (_object->_type == Destination::GROUP) {
if (_object->_type == GROUP) {
if hasattr(self, "prv") and self.prv != None:
try:
return self.prv.decrypt(ciphertext)
@ -365,7 +366,7 @@ Bytes Destination::decrypt(const Bytes &data) {
}
*/
// MOCK
return Bytes::NONE;
return {Bytes::NONE};
}
/*
@ -376,8 +377,8 @@ Signs information for ``RNS.Destination.SINGLE`` type destination.
*/
Bytes Destination::sign(const Bytes &message) {
assert(_object);
if (_object->_type == Destination::SINGLE && _object->_identity) {
if (_object->_type == SINGLE && _object->_identity) {
return _object->_identity.sign(message);
}
return Bytes::NONE;
return {Bytes::NONE};
}

View File

@ -4,7 +4,7 @@
#include "Link.h"
#include "Identity.h"
#include "Bytes.h"
#include "None.h"
#include "Type.h"
#include <memory>
#include <string>
@ -54,48 +54,14 @@ namespace RNS {
using PathResponse = std::pair<time_t, Bytes>;
//using PathResponse = std::pair<time_t, std::vector<uint8_t>>;
enum NoneConstructor {
NONE
};
// Constants
enum types {
SINGLE = 0x00,
GROUP = 0x01,
PLAIN = 0x02,
LINK = 0x03,
};
enum proof_strategies {
PROVE_NONE = 0x21,
PROVE_APP = 0x22,
PROVE_ALL = 0x23,
};
enum request_policies {
ALLOW_NONE = 0x00,
ALLOW_ALL = 0x01,
ALLOW_LIST = 0x02,
};
enum directions {
IN = 0x11,
OUT = 0x12,
};
const uint8_t PR_TAG_WINDOW = 30;
public:
Destination(NoneConstructor none) {
extreme("Destination NONE object created");
}
Destination(RNS::NoneConstructor none) {
Destination(Type::NoneConstructor none) {
extreme("Destination NONE object created");
}
Destination(const Destination &destination) : _object(destination._object) {
extreme("Destination object copy created");
}
Destination(const Identity &identity, const directions direction, const types type, const char* app_name, const char *aspects);
Destination(const Identity &identity, const Type::Destination::directions direction, const Type::Destination::types type, const char* app_name, const char *aspects);
virtual ~Destination() {
extreme("Destination object destroyed");
}
@ -165,7 +131,7 @@ namespace RNS {
: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(proof_strategies proof_strategy) {
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");
@ -181,14 +147,14 @@ namespace RNS {
Bytes sign(const Bytes &message);
// getters/setters
inline types type() const { assert(_object); return _object->_type; }
inline directions direction() const { assert(_object); return _object->_direction; }
inline proof_strategies proof_strategy() const { assert(_object); return _object->_proof_strategy; }
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 Bytes hash() const { assert(_object); return _object->_hash; }
inline Bytes link_id() const { assert(_object); return _object->_link_id; }
inline uint16_t mtu() const { assert(_object); return _object->_mtu; }
inline void mtu(uint16_t mtu) { assert(_object); _object->_mtu = mtu; }
inline Link::status status() const { assert(_object); return _object->_status; }
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; }
@ -203,9 +169,9 @@ namespace RNS {
bool _accept_link_requests = true;
Callbacks _callbacks;
//z_request_handlers = {}
types _type;
directions _direction;
proof_strategies _proof_strategy = PROVE_NONE;
Type::Destination::types _type;
Type::Destination::directions _direction;
Type::Destination::proof_strategies _proof_strategy = Type::Destination::PROVE_NONE;
uint16_t _mtu = 0;
//std::vector<PathResponse> _path_responses;
@ -229,7 +195,7 @@ namespace RNS {
// CBA TODO determine if Link needs to inherit from Destination or vice-versa
Bytes _link_id;
Link::status _status;
Type::Link::status _status;
friend class Destination;
};

View File

@ -11,6 +11,7 @@
#include <string.h>
using namespace RNS;
using namespace RNS::Type::Identity;
Identity::Identity(bool create_keys) : _object(new Object()) {
if (create_keys) {
@ -177,14 +178,14 @@ Bytes Identity::decrypt(const Bytes &ciphertext_token) {
if (!_object->_prv) {
throw std::runtime_error("Decryption failed because identity does not hold a private key");
}
if (ciphertext_token.size() <= Identity::KEYSIZE/8/2) {
if (ciphertext_token.size() <= Type::Identity::KEYSIZE/8/2) {
debug("Decryption failed because the token size " + std::to_string(ciphertext_token.size()) + " was invalid.");
return Bytes::NONE;
return {Bytes::NONE};
}
Bytes plaintext;
try {
//peer_pub_bytes = ciphertext_token[:Identity.KEYSIZE//8//2]
Bytes peer_pub_bytes = ciphertext_token.left(Identity::KEYSIZE/8/2);
Bytes peer_pub_bytes = ciphertext_token.left(Type::Identity::KEYSIZE/8/2);
//peer_pub = X25519PublicKey.from_public_bytes(peer_pub_bytes)
//Cryptography::X25519PublicKey::Ptr peer_pub = Cryptography::X25519PublicKey::from_public_bytes(peer_pub_bytes);
debug("Identity::decrypt: peer public key: " + peer_pub_bytes.toHex());
@ -204,7 +205,7 @@ Bytes Identity::decrypt(const Bytes &ciphertext_token) {
Cryptography::Fernet fernet(derived_key);
//ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:]
Bytes ciphertext(ciphertext_token.mid(Identity::KEYSIZE/8/2));
Bytes ciphertext(ciphertext_token.mid(Type::Identity::KEYSIZE/8/2));
debug("Identity::decrypt: Fernet decrypting data of length " + std::to_string(ciphertext.size()));
extreme("Identity::decrypt: ciphertext: " + ciphertext.toHex());
plaintext = fernet.decrypt(ciphertext);
@ -263,7 +264,7 @@ bool Identity::validate(const Bytes &signature, const Bytes &message) {
}
}
void Identity::prove(const Packet &packet, const Destination &destination /*= Destination::NONE*/) {
void Identity::prove(const Packet &packet, const Destination &destination /*= {Destination::NONE}*/) {
assert(_object);
Bytes signature(sign(packet.packet_hash()));
Bytes proof_data;
@ -278,6 +279,6 @@ void Identity::prove(const Packet &packet, const Destination &destination /*= De
//z destination = packet.generate_proof_destination();
//z}
Packet proof(destination, packet.receiving_interface(), proof_data, RNS::Packet::PROOF);
Packet proof(destination, packet.receiving_interface(), proof_data, Type::Packet::PROOF);
proof.send();
}

View File

@ -1,15 +1,14 @@
#pragma once
#include "Reticulum.h"
// CBA TODO determine why including Destination.h here causes build errors
//#include "Destination.h"
#include "Log.h"
#include "Bytes.h"
#include "None.h"
#include "Cryptography/Hashes.h"
#include "Cryptography/Ed25519.h"
#include "Cryptography/X25519.h"
#include "Cryptography/Fernet.h"
#include "Type.h"
#include <memory>
@ -23,33 +22,7 @@ namespace RNS {
class Identity {
public:
enum NoneConstructor {
NONE
};
//static const char CURVE[] = "Curve25519";
static constexpr const char* CURVE = "Curve25519";
// The curve used for Elliptic Curve DH key exchanges
static const uint16_t KEYSIZE = 256*2;
// X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.
// Non-configurable constants
static const uint8_t FERNET_OVERHEAD = RNS::Cryptography::Fernet::FERNET_OVERHEAD;
static const uint8_t AES128_BLOCKSIZE = 16; // In bytes
static const uint16_t HASHLENGTH = Reticulum::HASHLENGTH; // In bits
static const uint16_t SIGLENGTH = KEYSIZE; // In bits
static const uint8_t NAME_HASH_LENGTH = 80;
static const uint16_t TRUNCATED_HASHLENGTH = Reticulum::TRUNCATED_HASHLENGTH; // In bits
// Constant specifying the truncated hash length (in bits) used by Reticulum
// for addressable hashes and other purposes. Non-configurable.
public:
Identity(NoneConstructor none) {
extreme("Identity NONE object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Identity(RNS::NoneConstructor none) {
Identity(Type::NoneConstructor none) {
extreme("Identity NONE object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
}
Identity(const Identity &identity) : _object(identity._object) {
@ -105,7 +78,7 @@ namespace RNS {
*/
static inline Bytes truncated_hash(const Bytes &data) {
//return Identity.full_hash(data)[:(Identity.TRUNCATED_HASHLENGTH//8)]
return full_hash(data).left(TRUNCATED_HASHLENGTH/8);
return full_hash(data).left(Type::Identity::TRUNCATED_HASHLENGTH/8);
}
/*
Get a random SHA-256 hash.
@ -114,19 +87,19 @@ namespace RNS {
:returns: Truncated SHA-256 hash of random data as *bytes*
*/
static inline Bytes get_random_hash() {
return truncated_hash(Cryptography::random(Identity::TRUNCATED_HASHLENGTH/8));
return truncated_hash(Cryptography::random(Type::Identity::TRUNCATED_HASHLENGTH/8));
}
static bool validate_announce(const Packet &packet);
inline Bytes get_salt() { assert(_object); return _object->_hash; }
inline Bytes get_context() { return Bytes::NONE; }
inline Bytes get_context() { return {Bytes::NONE}; }
Bytes encrypt(const Bytes &plaintext);
Bytes decrypt(const Bytes &ciphertext_token);
Bytes sign(const Bytes &message);
bool validate(const Bytes &signature, const Bytes &message);
//void prove(const Packet &packet, const Destination &destination = Destination::NONE);
//void prove(const Packet &packet, const Destination &destination = {Destination::NONE});
void prove(const Packet &packet, const Destination &destination);
// getters/setters

View File

@ -3,7 +3,7 @@
#include "../Transport.h"
using namespace RNS;
using namespace RNS::Type::Interface;
/*virtual*/ inline void Interface::processIncoming(const Bytes &data) {
extreme("Interface::processIncoming: data: " + data.toHex());

View File

@ -2,7 +2,7 @@
#include "../Log.h"
#include "../Bytes.h"
#include "../None.h"
#include "../Type.h"
#include <list>
#include <memory>
@ -31,31 +31,12 @@ namespace RNS {
};
public:
enum NoneConstructor {
NONE
};
public:
// Interface mode definitions
enum modes {
MODE_NONE = 0x00,
MODE_FULL = 0x01,
MODE_POINT_TO_POINT = 0x04,
MODE_ACCESS_POINT = 0x08,
MODE_ROAMING = 0x10,
MODE_BOUNDARY = 0x20,
MODE_GATEWAY = 0x40,
};
// Which interface modes a Transport Node
// should actively discover paths for.
uint8_t DISCOVER_PATHS_FOR = MODE_ACCESS_POINT | MODE_GATEWAY;
uint8_t DISCOVER_PATHS_FOR = Type::Interface::MODE_ACCESS_POINT | Type::Interface::MODE_GATEWAY;
public:
Interface(NoneConstructor none) {
extreme("Interface object NONE created");
}
Interface(RNS::NoneConstructor none) {
Interface(Type::NoneConstructor none) {
extreme("Interface object NONE created");
}
Interface(const Interface &interface) : _object(interface._object) {
@ -107,7 +88,7 @@ namespace RNS {
inline bool RPT() const { assert(_object); return _object->_RPT; }
inline std::string name() const { assert(_object); return _object->_name; }
inline Bytes ifac_identity() const { assert(_object); return _object->_ifac_identity; }
inline modes mode() const { assert(_object); return _object->_mode; }
inline Type::Interface::modes mode() const { assert(_object); return _object->_mode; }
inline uint32_t bitrate() const { assert(_object); return _object->_bitrate; }
inline uint64_t announce_allowed_at() const { assert(_object); return _object->_announce_allowed_at; }
inline void announce_allowed_at(uint64_t announce_allowed_at) { assert(_object); _object->_announce_allowed_at = announce_allowed_at; }
@ -132,7 +113,7 @@ namespace RNS {
size_t _txb = 0;
bool online = false;
Bytes _ifac_identity;
modes _mode = MODE_NONE;
Type::Interface::modes _mode = Type::Interface::MODE_NONE;
uint32_t _bitrate = 0;
uint64_t _announce_allowed_at = 0;
float _announce_cap = 0.0;

View File

@ -4,6 +4,7 @@
#include "Log.h"
using namespace RNS;
using namespace RNS::Type::Link;
Link::Link() : _object(new Object()) {
assert(_object);

View File

@ -5,7 +5,7 @@
// CBA TODO resolve circular dependency with following header file
//#include "Packet.h"
#include "Bytes.h"
#include "None.h"
#include "Type.h"
#include <memory>
@ -20,63 +20,8 @@ namespace RNS {
typedef void (*closed)(Link *link);
};
enum NoneConstructor {
NONE
};
static constexpr const char* CURVE = Identity::CURVE;
// The curve used for Elliptic Curve DH key exchanges
static const uint16_t ECPUBSIZE = 32+32;
static const uint8_t KEYSIZE = 32;
//static const uint16_t MDU = floor((Reticulum::MTU-Reticulum::IFAC_MIN_SIZE-Reticulum::HEADER_MINSIZE-Identity::FERNET_OVERHEAD)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1;
static const uint16_t MDU = ((Reticulum::MTU-Reticulum::IFAC_MIN_SIZE-Reticulum::HEADER_MINSIZE-Identity::FERNET_OVERHEAD)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1;
static const uint8_t ESTABLISHMENT_TIMEOUT_PER_HOP = Reticulum::DEFAULT_PER_HOP_TIMEOUT;
// Timeout for link establishment in seconds per hop to destination.
static const uint16_t TRAFFIC_TIMEOUT_FACTOR = 6;
static const uint16_t KEEPALIVE_TIMEOUT_FACTOR = 4;
// RTT timeout factor used in link timeout calculation.
static const uint8_t STALE_GRACE = 2;
// Grace period in seconds used in link timeout calculation.
static const uint16_t KEEPALIVE = 360;
// Interval for sending keep-alive packets on established links in seconds.
static const uint16_t STALE_TIME = 2*KEEPALIVE;
/*
If no traffic or keep-alive packets are received within this period, the
link will be marked as stale, and a final keep-alive packet will be sent.
If after this no traffic or keep-alive packets are received within ``RTT`` *
``KEEPALIVE_TIMEOUT_FACTOR`` + ``STALE_GRACE``, the link is considered timed out,
and will be torn down.
*/
enum status {
PENDING = 0x00,
HANDSHAKE = 0x01,
ACTIVE = 0x02,
STALE = 0x03,
CLOSED = 0x04
};
enum teardown_reasons {
TIMEOUT = 0x01,
INITIATOR_CLOSED = 0x02,
DESTINATION_CLOSED = 0x03,
};
enum resource_strategies {
ACCEPT_NONE = 0x00,
ACCEPT_APP = 0x01,
ACCEPT_ALL = 0x02,
};
public:
Link(NoneConstructor none) {
extreme("Link NONE object created");
}
Link(RNS::NoneConstructor none) {
Link(Type::NoneConstructor none) {
extreme("Link NONE object created");
}
Link(const Link &link) : _object(link._object) {

View File

@ -1,10 +0,0 @@
#pragma once
namespace RNS {
// generic empty object constructor type
enum NoneConstructor {
NONE
};
}

View File

@ -7,14 +7,16 @@
#include <stdexcept>
using namespace RNS;
using namespace RNS::Type::PacketReceipt;
using namespace RNS::Type::Packet;
Packet::Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type /*= DATA*/, context_types context /*= CONTEXT_NONE*/, Transport::types transport_type /*= Transport::BROADCAST*/, header_types header_type /*= HEADER_1*/, const Bytes &transport_id /*= Bytes::NONE*/, bool create_receipt /*= true*/) : _object(new Object(destination, attached_interface)) {
Packet::Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type /*= DATA*/, context_types context /*= CONTEXT_NONE*/, Type::Transport::types transport_type /*= Type::Transport::BROADCAST*/, header_types header_type /*= HEADER_1*/, const Bytes &transport_id /*= {Bytes::NONE}*/, bool create_receipt /*= true*/) : _object(new Object(destination, attached_interface)) {
if (_object->_destination) {
extreme("Creating packet with destination...");
// CBA TODO handle NONE
if (transport_type == -1) {
transport_type = Transport::BROADCAST;
transport_type = Type::Transport::BROADCAST;
}
// following moved to object constructor to avoid extra NONE object
//_destination = destination;
@ -50,7 +52,7 @@ uint8_t Packet::get_packed_flags() {
assert(_object);
uint8_t packed_flags = 0;
if (_object->_context == LRPROOF) {
packed_flags = (_object->_header_type << 6) | (_object->_transport_type << 4) | (Destination::LINK << 2) | _object->_packet_type;
packed_flags = (_object->_header_type << 6) | (_object->_transport_type << 4) | (Type::Destination::LINK << 2) | _object->_packet_type;
}
else {
packed_flags = (_object->_header_type << 6) | (_object->_transport_type << 4) | (_object->_destination.type() << 2) | _object->_packet_type;
@ -61,8 +63,8 @@ uint8_t Packet::get_packed_flags() {
void Packet::unpack_flags(uint8_t flags) {
assert(_object);
_object->_header_type = static_cast<header_types>((flags & 0b01000000) >> 6);
_object->_transport_type = static_cast<Transport::types>((flags & 0b00110000) >> 4);
_object->_destination_type = static_cast<Destination::types>((flags & 0b00001100) >> 2);
_object->_transport_type = static_cast<Type::Transport::types>((flags & 0b00110000) >> 4);
_object->_destination_type = static_cast<Type::Destination::types>((flags & 0b00001100) >> 2);
_object->_packet_type = static_cast<types>(flags & 0b00000011);
}
@ -267,7 +269,7 @@ void Packet::pack() {
// Resource proofs are not encrypted
_object->_raw << _object->_data;
}
else if (_object->_packet_type == PROOF && _object->_destination.type() == Destination::LINK) {
else if (_object->_packet_type == PROOF && _object->_destination.type() == Type::Destination::LINK) {
// Packet proofs over links are not encrypted
_object->_raw << _object->_data;
}
@ -321,8 +323,8 @@ bool Packet::unpack() {
assert(_object);
debug("Packet::unpack: unpacking packet...");
try {
if (_object->_raw.size() < Reticulum::HEADER_MINSIZE) {
throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Reticulum::HEADER_MINSIZE) +" bytes");
if (_object->_raw.size() < Type::Reticulum::HEADER_MINSIZE) {
throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Type::Reticulum::HEADER_MINSIZE) +" bytes");
}
const uint8_t *raw = _object->_raw.data();
@ -340,21 +342,21 @@ bool Packet::unpack() {
}
if (_object->_header_type == HEADER_2) {
if (_object->_raw.size() < Reticulum::HEADER_MAXSIZE) {
throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Reticulum::HEADER_MAXSIZE) +" bytes");
if (_object->_raw.size() < Type::Reticulum::HEADER_MAXSIZE) {
throw std::length_error("Packet size of " + std::to_string(_object->_raw.size()) + " does not meet minimum header size of " + std::to_string(Type::Reticulum::HEADER_MAXSIZE) +" bytes");
}
_object->_transport_id.assign(raw+2, Reticulum::DESTINATION_LENGTH);
_object->_destination_hash.assign(raw+Reticulum::DESTINATION_LENGTH+2, Reticulum::DESTINATION_LENGTH);
_object->_context = static_cast<context_types>(raw[2*Reticulum::DESTINATION_LENGTH+2]);
_object->_data.assign(raw+2*Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(2*Reticulum::DESTINATION_LENGTH+3));
_object->_transport_id.assign(raw+2, Type::Reticulum::DESTINATION_LENGTH);
_object->_destination_hash.assign(raw+Type::Reticulum::DESTINATION_LENGTH+2, Type::Reticulum::DESTINATION_LENGTH);
_object->_context = static_cast<context_types>(raw[2*Type::Reticulum::DESTINATION_LENGTH+2]);
_object->_data.assign(raw+2*Type::Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(2*Type::Reticulum::DESTINATION_LENGTH+3));
// uknown at this point whether data is encrypted or not
_object->_encrypted = true;
}
else {
_object->_transport_id.clear();
_object->_destination_hash.assign(raw+2, Reticulum::DESTINATION_LENGTH);
_object->_context = static_cast<context_types>(raw[Reticulum::DESTINATION_LENGTH+2]);
_object->_data.assign(raw+Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(Reticulum::DESTINATION_LENGTH+3));
_object->_destination_hash.assign(raw+2, Type::Reticulum::DESTINATION_LENGTH);
_object->_context = static_cast<context_types>(raw[Type::Reticulum::DESTINATION_LENGTH+2]);
_object->_data.assign(raw+Type::Reticulum::DESTINATION_LENGTH+3, _object->_raw.size()-(Type::Reticulum::DESTINATION_LENGTH+3));
// uknown at this point whether data is encrypted or not
_object->_encrypted = true;
}
@ -383,7 +385,7 @@ bool Packet::send() {
}
/*
if (_destination->type == RNS::Destination::LINK) {
if (_destination->status == RNS::Link::CLOSED) {
if (_destination->status == Type::Link::CLOSED) {
throw std::runtime_error("Attempt to transmit over a closed link");
}
else {
@ -398,7 +400,7 @@ bool Packet::send() {
pack();
}
if (RNS::Transport::outbound(*this)) {
if (Transport::outbound(*this)) {
debug("Packet::send: successfully sent packet!!!");
//zreturn self.receipt
// MOCK
@ -427,7 +429,7 @@ bool Packet::resend() {
// encrypted destinations
pack();
if (RNS::Transport::outbound(*this)) {
if (Transport::outbound(*this)) {
debug("Packet::resend: successfully sent packet!!!");
//zreturn self.receipt
// MOCK
@ -441,7 +443,7 @@ bool Packet::resend() {
}
}
void Packet::prove(const Destination &destination /*= {Destination::NONE}*/) {
void Packet::prove(const Destination &destination /*= {Type::NONE}*/) {
/*
assert(_object);
if (_object->_fromPacked && _object->_destination) {
@ -479,9 +481,9 @@ const Bytes Packet::get_hashable_part() const {
assert(_object);
Bytes hashable_part;
hashable_part << (uint8_t)(_object->_raw.data()[0] & 0b00001111);
if (_object->_header_type == Packet::HEADER_2) {
if (_object->_header_type == HEADER_2) {
//hashable_part += self.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:]
hashable_part << _object->_raw.mid((Identity::TRUNCATED_HASHLENGTH/8)+2);
hashable_part << _object->_raw.mid((Type::Identity::TRUNCATED_HASHLENGTH/8)+2);
}
else {
//hashable_part += self.raw[2:];
@ -517,14 +519,14 @@ std::string Packet::debugString() const {
dump += "data: " + _object->_data.toHex() + "\n";
dump += " length: " + std::to_string(_object->_data.size()) + "\n";
if (_object->_encrypted && _object->_raw.size() > 0) {
size_t header_len = Reticulum::HEADER_MINSIZE;
size_t header_len = Type::Reticulum::HEADER_MINSIZE;
if (_object->_header_type == HEADER_2) {
header_len = Reticulum::HEADER_MAXSIZE;
header_len = Type::Reticulum::HEADER_MAXSIZE;
}
dump += "encrypted:\n";
dump += " header: " + _object->_raw.left(header_len).toHex() + "\n";
dump += " key: " + _object->_raw.mid(header_len, Identity::KEYSIZE/8/2).toHex() + "\n";
Bytes ciphertext(_object->_raw.mid(header_len+Identity::KEYSIZE/8/2));
dump += " key: " + _object->_raw.mid(header_len, Type::Identity::KEYSIZE/8/2).toHex() + "\n";
Bytes ciphertext(_object->_raw.mid(header_len+Type::Identity::KEYSIZE/8/2));
dump += " ciphertext: " + ciphertext.toHex() + "\n";
dump += " length: " + std::to_string(ciphertext.size()) + "\n";
dump += " iv: " + ciphertext.left(16).toHex() + "\n";

View File

@ -2,12 +2,12 @@
#include "Transport.h"
#include "Reticulum.h"
#include "Link.h"
//#include "Link.h"
#include "Identity.h"
#include "Destination.h"
#include "None.h"
#include "Interfaces/Interface.h"
#include "Utilities/OS.h"
#include "Type.h"
#include <memory>
#include <stdint.h>
@ -43,23 +43,8 @@ namespace RNS {
friend class PacketReceipt;
};
enum NoneConstructor {
NONE
};
// Receipt status constants
enum Status {
FAILED = 0x00,
SENT = 0x01,
DELIVERED = 0x02,
CULLED = 0xFF
};
static const uint16_t EXPL_LENGTH = Identity::HASHLENGTH / 8 + Identity::SIGLENGTH / 8;
static const uint16_t IMPL_LENGTH = Identity::SIGLENGTH / 8;
public:
PacketReceipt(NoneConstructor none) {}
PacketReceipt(Type::NoneConstructor none) {}
PacketReceipt(const PacketReceipt &packet_receipt) : _object(packet_receipt._object) {}
PacketReceipt() : _object(new Object()) {}
PacketReceipt(const Packet &packet) {}
@ -122,11 +107,11 @@ namespace RNS {
bool _sent = true;
uint64_t _sent_at = Utilities::OS::time();
bool _proved = false;
Status _status = SENT;
Destination _destination = Destination::NONE;
Type::PacketReceipt::Status _status = Type::PacketReceipt::SENT;
Destination _destination = {Type::NONE};
Callbacks _callbacks;
uint64_t _concluded_at = 0;
//zPacket _proof_packet;
//z Packet _proof_packet;
int16_t _timeout = 0;
friend class PacketReceipt;
};
@ -138,81 +123,18 @@ namespace RNS {
class Packet {
public:
enum NoneConstructor {
NONE
};
// Packet types
enum types {
DATA = 0x00, // Data packets
ANNOUNCE = 0x01, // Announces
LINKREQUEST = 0x02, // Link requests
PROOF = 0x03, // Proofs
};
// Header types
enum header_types {
HEADER_1 = 0x00, // Normal header format
HEADER_2 = 0x01, // Header format used for packets in transport
};
// Packet context types
enum context_types {
CONTEXT_NONE = 0x00, // Generic data packet
RESOURCE = 0x01, // Packet is part of a resource
RESOURCE_ADV = 0x02, // Packet is a resource advertisement
RESOURCE_REQ = 0x03, // Packet is a resource part request
RESOURCE_HMU = 0x04, // Packet is a resource hashmap update
RESOURCE_PRF = 0x05, // Packet is a resource proof
RESOURCE_ICL = 0x06, // Packet is a resource initiator cancel message
RESOURCE_RCL = 0x07, // Packet is a resource receiver cancel message
CACHE_REQUEST = 0x08, // Packet is a cache request
REQUEST = 0x09, // Packet is a request
RESPONSE = 0x0A, // Packet is a response to a request
PATH_RESPONSE = 0x0B, // Packet is a response to a path request
COMMAND = 0x0C, // Packet is a command
COMMAND_STATUS = 0x0D, // Packet is a status of an executed command
CHANNEL = 0x0E, // Packet contains link channel data
KEEPALIVE = 0xFA, // Packet is a keepalive packet
LINKIDENTIFY = 0xFB, // Packet is a link peer identification proof
LINKCLOSE = 0xFC, // Packet is a link close message
LINKPROOF = 0xFD, // Packet is a link packet proof
LRRTT = 0xFE, // Packet is a link request round-trip time measurement
LRPROOF = 0xFF, // Packet is a link request proof
};
// This is used to calculate allowable
// payload sizes
static const uint16_t HEADER_MAXSIZE = Reticulum::HEADER_MAXSIZE;
static const uint16_t MDU = Reticulum::MDU;
// With an MTU of 500, the maximum of data we can
// send in a single encrypted packet is given by
// the below calculation; 383 bytes.
//static const uint16_t ENCRYPTED_MDU = floor((Reticulum::MDU-Identity::FERNET_OVERHEAD-Identity::KEYSIZE/16)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1;
//static const uint16_t ENCRYPTED_MDU;
static const uint16_t ENCRYPTED_MDU = ((Reticulum::MDU-Identity::FERNET_OVERHEAD-Identity::KEYSIZE/16)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1;
// The maximum size of the payload data in a single encrypted packet
static const uint16_t PLAIN_MDU = MDU;
// The maximum size of the payload data in a single unencrypted packet
static const uint8_t TIMEOUT_PER_HOP = Reticulum::DEFAULT_PER_HOP_TIMEOUT;
//static constexpr const uint8_t EMPTY_DESTINATION[Reticulum::DESTINATION_LENGTH] = {0};
uint8_t EMPTY_DESTINATION[Reticulum::DESTINATION_LENGTH] = {0};
//static constexpr const uint8_t EMPTY_DESTINATION[Type::Reticulum::DESTINATION_LENGTH] = {0};
uint8_t EMPTY_DESTINATION[Type::Reticulum::DESTINATION_LENGTH] = {0};
public:
Packet(NoneConstructor none) {
extreme("Packet NONE object created");
}
Packet(RNS::NoneConstructor none) {
Packet(Type::NoneConstructor none) {
extreme("Packet NONE object created");
}
Packet(const Packet &packet) : _object(packet._object) {
extreme("Packet object copy created");
}
Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const Bytes &transport_id = Bytes::NONE, bool create_receipt = true);
Packet(const Destination &destination, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const Bytes &transport_id = Bytes::NONE, bool create_receipt = true) : Packet(destination, Interface::NONE, data, packet_type, context, transport_type, header_type, transport_id, create_receipt) {}
Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, Type::Packet::types packet_type = Type::Packet::DATA, Type::Packet::context_types context = Type::Packet::CONTEXT_NONE, Type::Transport::types transport_type = Type::Transport::BROADCAST, Type::Packet::header_types header_type = Type::Packet::HEADER_1, const Bytes &transport_id = {Bytes::NONE}, bool create_receipt = true);
Packet(const Destination &destination, const Bytes &data, Type::Packet::types packet_type = Type::Packet::DATA, Type::Packet::context_types context = Type::Packet::CONTEXT_NONE, Type::Transport::types transport_type = Type::Transport::BROADCAST, Type::Packet::header_types header_type = Type::Packet::HEADER_1, const Bytes &transport_id = {Bytes::NONE}, bool create_receipt = true) : Packet(destination, {Type::NONE}, data, packet_type, context, transport_type, header_type, transport_id, create_receipt) {}
virtual ~Packet();
inline Packet& operator = (const Packet &packet) {
@ -242,7 +164,7 @@ namespace RNS {
bool unpack();
bool send();
bool resend();
void prove(const Destination &destination = Destination::NONE);
void prove(const Destination &destination = {Type::NONE});
void update_hash();
const Bytes get_hash() const;
const Bytes getTruncatedHash() const;
@ -257,11 +179,11 @@ namespace RNS {
inline const Interface &attached_interface() const { assert(_object); return _object->_attached_interface; }
inline const Interface &receiving_interface() const { assert(_object); return _object->_receiving_interface; }
inline void receiving_interface(const Interface &receiving_interface) { assert(_object); _object->_receiving_interface = receiving_interface; }
inline header_types header_type() const { assert(_object); return _object->_header_type; }
inline Transport::types transport_type() const { assert(_object); return _object->_transport_type; }
inline Destination::types destination_type() const { assert(_object); return _object->_destination_type; }
inline types packet_type() const { assert(_object); return _object->_packet_type; }
inline context_types context() const { assert(_object); return _object->_context; }
inline Type::Packet::header_types header_type() const { assert(_object); return _object->_header_type; }
inline Type::Transport::types transport_type() const { assert(_object); return _object->_transport_type; }
inline Type::Destination::types destination_type() const { assert(_object); return _object->_destination_type; }
inline Type::Packet::types packet_type() const { assert(_object); return _object->_packet_type; }
inline Type::Packet::context_types context() const { assert(_object); return _object->_context; }
inline bool sent() const { assert(_object); return _object->_sent; }
inline void sent(bool sent) { assert(_object); _object->_sent = sent; }
inline time_t sent_at() const { assert(_object); return _object->_sent_at; }
@ -289,17 +211,17 @@ namespace RNS {
Object(const Destination &destination, const Interface &attached_interface) : _destination(destination), _attached_interface(attached_interface) {}
virtual ~Object() {}
private:
Destination _destination = {Destination::NONE};
Link _link = {Link::NONE};
Destination _destination = {Type::NONE};
Link _link = {Type::NONE};
Interface _attached_interface = {Interface::NONE};
Interface _receiving_interface = {Interface::NONE};
Interface _attached_interface = {Type::NONE};
Interface _receiving_interface = {Type::NONE};
header_types _header_type = HEADER_1;
Transport::types _transport_type = Transport::BROADCAST;
Destination::types _destination_type = Destination::SINGLE;
types _packet_type = DATA;
context_types _context = CONTEXT_NONE;
Type::Packet::header_types _header_type = Type::Packet::HEADER_1;
Type::Transport::types _transport_type = Type::Transport::BROADCAST;
Type::Destination::types _destination_type = Type::Destination::SINGLE;
Type::Packet::types _packet_type = Type::Packet::DATA;
Type::Packet::context_types _context = Type::Packet::CONTEXT_NONE;
uint8_t _flags = 0;
uint8_t _hops = 0;
@ -312,7 +234,7 @@ namespace RNS {
bool _encrypted = false; // whether data is encrytpted
PacketReceipt _receipt;
uint16_t _mtu = Reticulum::MTU;
uint16_t _mtu = Type::Reticulum::MTU;
time_t _sent_at = 0;
float _rssi = 0.0;

View File

@ -6,6 +6,12 @@
#include <RNG.h>
using namespace RNS;
using namespace RNS::Type::Reticulum;
/*static*/ bool Reticulum::__transport_enabled = false;
/*static*/ bool Reticulum::__use_implicit_proof = true;
/*static*/ bool Reticulum::__allow_probes = false;
/*static*/ bool Reticulum::panic_on_interface_error = false;
/*
Initialises and starts a Reticulum instance. This must be

View File

@ -1,7 +1,7 @@
#pragma once
#include "Log.h"
#include "None.h"
#include "Type.h"
#include <vector>
#include <memory>
@ -12,85 +12,13 @@ namespace RNS {
class Reticulum {
public:
enum NoneConstructor {
NONE
};
// Future minimum will probably be locked in at 251 bytes to support
// networks with segments of different MTUs. Absolute minimum is 219.
static const uint16_t MTU = 500;
/*
The MTU that Reticulum adheres to, and will expect other peers to
adhere to. By default, the MTU is 507 bytes. In custom RNS network
implementations, it is possible to change this value, but doing so will
completely break compatibility with all other RNS networks. An identical
MTU is a prerequisite for peers to communicate in the same network.
Unless you really know what you are doing, the MTU should be left at
the default value.
*/
static const uint16_t MAX_QUEUED_ANNOUNCES = 16384;
static const uint32_t QUEUED_ANNOUNCE_LIFE = 60*60*24;
static const uint8_t ANNOUNCE_CAP = 2;
/*
The maximum percentage of interface bandwidth that, at any given time,
may be used to propagate announces. If an announce was scheduled for
broadcasting on an interface, but doing so would exceed the allowed
bandwidth allocation, the announce will be queued for transmission
when there is bandwidth available.
Reticulum will always prioritise propagating announces with fewer
hops, ensuring that distant, large networks with many peers on fast
links don't overwhelm the capacity of smaller networks on slower
mediums. If an announce remains queued for an extended amount of time,
it will eventually be dropped.
This value will be applied by default to all created interfaces,
but it can be configured individually on a per-interface basis.
*/
static const uint16_t MINIMUM_BITRATE = 500;
// TODO: To reach the 300bps level without unreasonably impacting
// performance on faster links, we need a mechanism for setting
// this value more intelligently. One option could be inferring it
// from interface speed, but a better general approach would most
// probably be to let Reticulum somehow continously build a map of
// per-hop latencies and use this map for the timeout calculation.
static const uint8_t DEFAULT_PER_HOP_TIMEOUT = 6;
static const uint16_t HASHLENGTH = 256; // In bits
// Length of truncated hashes in bits.
static const uint16_t TRUNCATED_HASHLENGTH = 128; // In bits
static const uint16_t HEADER_MINSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*1; // In bytes
static const uint16_t HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*2; // In bytes
static const uint16_t IFAC_MIN_SIZE = 1;
//zIFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8")
static const uint16_t MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE;
static const uint32_t RESOURCE_CACHE = 24*60*60;
static const uint16_t JOB_INTERVAL = 5*60;
static const uint16_t CLEAN_INTERVAL = 15*60;
static const uint16_t PERSIST_INTERVAL = 60*60*12;
static const uint16_t GRACIOUS_PERSIST_INTERVAL = 60*5;
static const uint8_t DESTINATION_LENGTH = TRUNCATED_HASHLENGTH/8; // In bytes
static const bool __transport_enabled = false;
static const bool __use_implicit_proof = true;
static const bool __allow_probes = false;
static const bool panic_on_interface_error = false;
static bool __transport_enabled;
static bool __use_implicit_proof;
static bool __allow_probes;
static bool panic_on_interface_error;
public:
Reticulum(NoneConstructor none) {
extreme("Reticulum NONE object created");
}
Reticulum(RNS::NoneConstructor none) {
Reticulum(Type::NoneConstructor none) {
extreme("Reticulum NONE object created");
}
Reticulum(const Reticulum &reticulum) : _object(reticulum._object) {

View File

@ -183,7 +183,7 @@ void testBytes() {
// test creating bytes from NONE
{
RNS::Bytes bytes(RNS::Bytes::NONE);
RNS::Bytes bytes({RNS::Bytes::NONE});
assert(!bytes);
assert(bytes.size() == 0);
assert(bytes.data() == nullptr);

View File

@ -18,7 +18,7 @@ void testCrypto() {
RNS::Identity identity;
RNS::Destination destination(identity, RNS::Destination::IN, RNS::Destination::SINGLE, "appname", "aspects");
RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "appname", "aspects");
//assert(encryptionPrivateKey().toHex().compare("") == );
//assert(signingPrivateKey().toHex().compare("") == );
//assert(encryptionPublicKey().toHex().compare("") == );

View File

@ -10,7 +10,7 @@ void testReference() {
RNS::Reticulum reticulum_default;
assert(reticulum_default);
RNS::Reticulum reticulum_none(RNS::Reticulum::NONE);
RNS::Reticulum reticulum_none({RNS::Type::NONE});
assert(!reticulum_none);
RNS::Reticulum reticulum_default_copy(reticulum_default);

View File

@ -54,8 +54,8 @@ using namespace RNS::Utilities;
/*static*/ uint64_t Transport::_tables_last_culled = 0;
/*static*/ uint32_t Transport::_tables_cull_interval = 5000;
/*static*/ Reticulum Transport::_owner(Reticulum::NONE);
/*static*/ Identity Transport::_identity(Identity::NONE);
/*static*/ Reticulum Transport::_owner({Type::NONE});
/*static*/ Identity Transport::_identity({Type::NONE});
/*static*/ void Transport::start(const Reticulum &reticulum_instance) {
_jobs_running = true;
@ -634,7 +634,7 @@ using namespace RNS::Utilities;
// Check if we have a known path for the destination in the path table
//if packet.packet_type != RNS.Packet.ANNOUNCE and packet.destination.type != RNS.Destination.PLAIN and packet.destination.type != RNS.Destination.GROUP and packet.destination_hash in Transport.destination_table:
if (packet.packet_type() != Packet::ANNOUNCE && packet.destination().type() != Destination::PLAIN && packet.destination().type() != Destination::GROUP && _destination_table.find(packet.destination_hash()) != _destination_table.end()) {
if (packet.packet_type() != Type::Packet::ANNOUNCE && packet.destination().type() != Type::Destination::PLAIN && packet.destination().type() != Type::Destination::GROUP && _destination_table.find(packet.destination_hash()) != _destination_table.end()) {
extreme("Transport::outbound: Path to destination is known");
//outbound_interface = Transport.destination_table[packet.destination_hash][5]
DestinationEntry destination_entry = (*_destination_table.find(packet.destination_hash())).second;
@ -648,10 +648,10 @@ using namespace RNS::Utilities;
//if Transport.destination_table[packet.destination_hash][2] > 1:
if (destination_entry._hops > 1) {
extreme("Forwarding packet to next closest interface...");
if (packet.header_type() == Packet::HEADER_1) {
if (packet.header_type() == Type::Packet::HEADER_1) {
// Insert packet into transport
//new_flags = (RNS.Packet.HEADER_2) << 6 | (Transport.TRANSPORT) << 4 | (packet.flags & 0b00001111)
uint8_t new_flags = (Packet::HEADER_2) << 6 | (Transport::TRANSPORT) << 4 | (packet.flags() & 0b00001111);
uint8_t new_flags = (Type::Packet::HEADER_2) << 6 | (Type::Transport::TRANSPORT) << 4 | (packet.flags() & 0b00001111);
Bytes new_raw;
//new_raw = struct.pack("!B", new_flags)
new_raw << new_flags;
@ -678,10 +678,10 @@ using namespace RNS::Utilities;
//elif Transport.destination_table[packet.destination_hash][2] == 1 and Transport.owner.is_connected_to_shared_instance:
else if (destination_entry._hops == 1 && _owner.is_connected_to_shared_instance()) {
extreme("Transport::outbound: Sending packet for directly connected interface to shared instance...");
if (packet.header_type() == Packet::HEADER_1) {
if (packet.header_type() == Type::Packet::HEADER_1) {
// Insert packet into transport
//new_flags = (RNS.Packet.HEADER_2) << 6 | (Transport.TRANSPORT) << 4 | (packet.flags & 0b00001111)
uint8_t new_flags = (Packet::HEADER_2) << 6 | (Transport::TRANSPORT) << 4 | (packet.flags() & 0b00001111);
uint8_t new_flags = (Type::Packet::HEADER_2) << 6 | (Type::Transport::TRANSPORT) << 4 | (packet.flags() & 0b00001111);
Bytes new_raw;
//new_raw = struct.pack("!B", new_flags)
new_raw << new_flags;
@ -719,8 +719,8 @@ using namespace RNS::Utilities;
if (interface.OUT()) {
bool should_transmit = true;
if (packet.destination().type() == Destination::LINK) {
if (packet.destination().status() == Link::CLOSED) {
if (packet.destination().type() == Type::Destination::LINK) {
if (packet.destination().status() == Type::Link::CLOSED) {
should_transmit = false;
}
// CBA Destination has no member attached_interface
@ -733,16 +733,16 @@ using namespace RNS::Utilities;
should_transmit = false;
}
if (packet.packet_type() == Packet::ANNOUNCE) {
if (packet.packet_type() == Type::Packet::ANNOUNCE) {
if (!packet.attached_interface()) {
extreme("Transport::outbound: Packet has no attached interface");
if (interface.mode() == Interface::MODE_ACCESS_POINT) {
if (interface.mode() == Type::Interface::MODE_ACCESS_POINT) {
extreme("Blocking announce broadcast on " + interface.toString() + " due to AP mode");
should_transmit = false;
}
else if (interface.mode() == Interface::MODE_ROAMING) {
else if (interface.mode() == Type::Interface::MODE_ROAMING) {
//local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None)
//Destination local_destination(Destination::NONE);
//Destination local_destination({Type::NONE});
bool found_local = false;
for (auto &destination : _destinations) {
if (destination.hash() == packet.destination_hash()) {
@ -759,34 +759,34 @@ using namespace RNS::Utilities;
else {
const Interface &from_interface = next_hop_interface(packet.destination_hash());
//if from_interface == None or not hasattr(from_interface, "mode"):
if (!from_interface || from_interface.mode() == Interface::MODE_NONE) {
if (!from_interface || from_interface.mode() == Type::Interface::MODE_NONE) {
should_transmit = false;
if (!from_interface) {
extreme("Blocking announce broadcast on " + interface.toString() + " since next hop interface doesn't exist");
}
else if (from_interface.mode() == Interface::MODE_NONE) {
else if (from_interface.mode() == Type::Interface::MODE_NONE) {
extreme("Blocking announce broadcast on " + interface.toString() + " since next hop interface has no mode configured");
}
}
else {
if (from_interface.mode() == Interface::MODE_ROAMING) {
if (from_interface.mode() == Type::Interface::MODE_ROAMING) {
extreme("Blocking announce broadcast on " + interface.toString() + " due to roaming-mode next-hop interface");
should_transmit = false;
}
else if (from_interface.mode() == Interface::MODE_BOUNDARY) {
else if (from_interface.mode() == Type::Interface::MODE_BOUNDARY) {
extreme("Blocking announce broadcast on " + interface.toString() + " due to boundary-mode next-hop interface");
should_transmit = false;
}
}
}
}
else if (interface.mode() == Interface::MODE_BOUNDARY) {
else if (interface.mode() == Type::Interface::MODE_BOUNDARY) {
//local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None)
// next and filter pattern?
// next(iterable, default)
// list comprehension: [x for x in xyz if x in a]
// CBA TODO confirm that above pattern just selects the first matching destination
//Destination local_destination(Destination::NONE);
//Destination local_destination({Typeestination::NONE});
bool found_local = false;
for (auto &destination : _destinations) {
if (destination.hash() == packet.destination_hash()) {
@ -802,17 +802,17 @@ using namespace RNS::Utilities;
}
else {
const Interface &from_interface = next_hop_interface(packet.destination_hash());
if (!from_interface || from_interface.mode() == Interface::MODE_NONE) {
if (!from_interface || from_interface.mode() == Type::Interface::MODE_NONE) {
should_transmit = false;
if (!from_interface) {
extreme("Blocking announce broadcast on " + interface.toString() + " since next hop interface doesn't exist");
}
else if (from_interface.mode() == Interface::MODE_NONE) {
else if (from_interface.mode() == Type::Interface::MODE_NONE) {
extreme("Blocking announce broadcast on " + interface.toString() + " since next hop interface has no mode configured");
}
}
else {
if (from_interface.mode() == Interface::MODE_ROAMING) {
if (from_interface.mode() == Type::Interface::MODE_ROAMING) {
extreme("Blocking announce broadcast on " + interface.toString() + " due to roaming-mode next-hop interface");
should_transmit = false;
}
@ -844,7 +844,7 @@ using namespace RNS::Utilities;
}
else {
should_transmit = false;
if (interface.announce_queue().size() < Reticulum::MAX_QUEUED_ANNOUNCES) {
if (interface.announce_queue().size() < Type::Reticulum::MAX_QUEUED_ANNOUNCES) {
bool should_queue = true;
for (auto &entry : interface.announce_queue()) {
if (entry._destination == packet.destination_hash()) {
@ -947,13 +947,13 @@ using namespace RNS::Utilities;
// Don't generate receipt if it has been explicitly disabled
if (packet.create_receipt() &&
// Only generate receipts for DATA packets
packet.packet_type() == Packet::DATA &&
packet.packet_type() == Type::Packet::DATA &&
// Don't generate receipts for PLAIN destinations
packet.destination().type() != Destination::PLAIN &&
packet.destination().type() != Type::Destination::PLAIN &&
// Don't generate receipts for link-related packets
!(packet.context() >= Packet::KEEPALIVE && packet.context() <= Packet::LRPROOF) &&
!(packet.context() >= Type::Packet::KEEPALIVE && packet.context() <= Type::Packet::LRPROOF) &&
// Don't generate receipts for resource packets
!(packet.context() >= Packet::RESOURCE && packet.context() <= Packet::RESOURCE_RCL)) {
!(packet.context() >= Type::Packet::RESOURCE && packet.context() <= Type::Packet::RESOURCE_RCL)) {
PacketReceipt receipt(packet);
packet.receipt(receipt);
@ -971,27 +971,27 @@ using namespace RNS::Utilities;
// TODO: Think long and hard about this.
// Is it even strictly necessary with the current
// transport rules?
if (packet.context() == Packet::KEEPALIVE) {
if (packet.context() == Type::Packet::KEEPALIVE) {
return true;
}
if (packet.context() == Packet::RESOURCE_REQ) {
if (packet.context() == Type::Packet::RESOURCE_REQ) {
return true;
}
if (packet.context() == Packet::RESOURCE_PRF) {
if (packet.context() == Type::Packet::RESOURCE_PRF) {
return true;
}
if (packet.context() == Packet::RESOURCE) {
if (packet.context() == Type::Packet::RESOURCE) {
return true;
}
if (packet.context() == Packet::CACHE_REQUEST) {
if (packet.context() == Type::Packet::CACHE_REQUEST) {
return true;
}
if (packet.context() == Packet::CHANNEL) {
if (packet.context() == Type::Packet::CHANNEL) {
return true;
}
if (packet.destination_type() == Destination::PLAIN) {
if (packet.packet_type() != Packet::ANNOUNCE) {
if (packet.destination_type() == Type::Destination::PLAIN) {
if (packet.packet_type() != Type::Packet::ANNOUNCE) {
if (packet.hops() > 1) {
debug("Dropped PLAIN packet " + packet.packet_hash().toHex() + " with " + std::to_string(packet.hops()) + " hops");
return false;
@ -1006,8 +1006,8 @@ using namespace RNS::Utilities;
}
}
if (packet.destination_type() == Destination::GROUP) {
if (packet.packet_type() != Packet::ANNOUNCE) {
if (packet.destination_type() == Type::Destination::GROUP) {
if (packet.packet_type() != Type::Packet::ANNOUNCE) {
if (packet.hops() > 1) {
debug("Dropped GROUP packet " + packet.packet_hash().toHex() + " with " + std::to_string(packet.hops()) + " hops");
return false;
@ -1026,8 +1026,8 @@ using namespace RNS::Utilities;
return true;
}
else {
if (packet.packet_type() == Packet::ANNOUNCE) {
if (packet.destination_type() == Destination::SINGLE) {
if (packet.packet_type() == Type::Packet::ANNOUNCE) {
if (packet.destination_type() == Type::Destination::SINGLE) {
return true;
}
else {
@ -1041,7 +1041,7 @@ using namespace RNS::Utilities;
return false;
}
/*static*/ void Transport::inbound(const Bytes &raw, const Interface &interface /*= Interface::NONE*/) {
/*static*/ void Transport::inbound(const Bytes &raw, const Interface &interface /*= {Type::NONE}*/) {
extreme("Transport::inbound()");
/*
// If interface access codes are enabled,
@ -1122,7 +1122,7 @@ using namespace RNS::Utilities;
_jobs_locked = true;
Packet packet(Destination::NONE, raw);
Packet packet({Type::NONE}, raw);
if (!packet.unpack()) {
warning("Transport::inbound: Pscket unpack failed!");
return;
@ -1178,7 +1178,7 @@ using namespace RNS::Utilities;
//for_local_client_link |= (packet.packet_type != RNS.Packet.ANNOUNCE) and (packet.destination_hash in Transport.link_table and Transport.link_table[packet.destination_hash][2] in Transport.local_client_interfaces)
bool for_local_client = false;
bool for_local_client_link = false;
if (packet.packet_type() != Packet::ANNOUNCE) {
if (packet.packet_type() != Type::Packet::ANNOUNCE) {
auto destination_iter = _destination_table.find(packet.destination_hash());
if (destination_iter != _destination_table.end()) {
DestinationEntry destination_entry = (*destination_iter).second;
@ -1211,7 +1211,7 @@ using namespace RNS::Utilities;
// directly on all attached interfaces, since they are
// never injected into transport.
if (_control_hashes.find(packet.destination_hash()) == _control_hashes.end()) {
if (packet.destination_type() == Destination::PLAIN && packet.transport_type() == Transport::BROADCAST) {
if (packet.destination_type() == Type::Destination::PLAIN && packet.transport_type() == Type::Transport::BROADCAST) {
// Send to all interfaces except the originator
if (from_local_client) {
for (const Interface &interface : _interfaces) {
@ -1252,7 +1252,7 @@ using namespace RNS::Utilities;
// If this is a cache request, and we can fullfill
// it, do so and stop processing. Otherwise resume
// normal processing.
if (packet.context() == Packet::CACHE_REQUEST) {
if (packet.context() == Type::Packet::CACHE_REQUEST) {
if (cache_request_packet(packet)) {
extreme("Transport::inbound: Cached packet");
return;
@ -1262,7 +1262,7 @@ using namespace RNS::Utilities;
// If the packet is in transport, check whether we
// are the designated next hop, and process it
// accordingly if we are.
if (packet.transport_id() && packet.packet_type() != Packet::ANNOUNCE) {
if (packet.transport_id() && packet.packet_type() != Type::Packet::ANNOUNCE) {
if (packet.transport_id() == _identity.hash()) {
auto destination_iter = _destination_table.find(packet.destination_hash());
if (destination_iter != _destination_table.end()) {
@ -1280,18 +1280,18 @@ using namespace RNS::Utilities;
//new_raw += next_hop
new_raw << next_hop;
//new_raw += packet.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:]
new_raw << packet.raw().mid((Identity::TRUNCATED_HASHLENGTH/8)+2);
new_raw << packet.raw().mid((Type::Identity::TRUNCATED_HASHLENGTH/8)+2);
}
else if (remaining_hops == 1) {
// Strip transport headers and transmit
//new_flags = (RNS.Packet.HEADER_1) << 6 | (Transport.BROADCAST) << 4 | (packet.flags & 0b00001111)
uint8_t new_flags = (Packet::HEADER_1) << 6 | (Transport::BROADCAST) << 4 | (packet.flags() & 0b00001111);
uint8_t new_flags = (Type::Packet::HEADER_1) << 6 | (Type::Transport::BROADCAST) << 4 | (packet.flags() & 0b00001111);
//new_raw = struct.pack("!B", new_flags)
new_raw << new_flags;
//new_raw += struct.pack("!B", packet.hops)
new_raw << packet.hops();
//new_raw += packet.raw[(RNS.Identity.TRUNCATED_HASHLENGTH//8)+2:]
new_raw << packet.raw().mid((Identity::TRUNCATED_HASHLENGTH/8)+2);
new_raw << packet.raw().mid((Type::Identity::TRUNCATED_HASHLENGTH/8)+2);
}
else if (remaining_hops == 0) {
// Just increase hop count and transmit
@ -1305,9 +1305,9 @@ using namespace RNS::Utilities;
Interface &outbound_interface = destination_entry._receiving_interface;
if (packet.packet_type() == Packet::LINKREQUEST) {
if (packet.packet_type() == Type::Packet::LINKREQUEST) {
uint64_t now = OS::time();
uint64_t proof_timeout = now + Link::ESTABLISHMENT_TIMEOUT_PER_HOP*1000 * std::max((uint8_t)1, remaining_hops);
uint64_t proof_timeout = now + Type::Link::ESTABLISHMENT_TIMEOUT_PER_HOP*1000 * std::max((uint8_t)1, remaining_hops);
LinkEntry link_entry(
now,
next_hop,
@ -1343,14 +1343,14 @@ using namespace RNS::Utilities;
// Link transport handling. Directs packets according
// to entries in the link tables
if (packet.packet_type() != Packet::ANNOUNCE && packet.packet_type() != Packet::LINKREQUEST && packet.context() == Packet::LRPROOF) {
if (packet.packet_type() != Type::Packet::ANNOUNCE && packet.packet_type() != Type::Packet::LINKREQUEST && packet.context() == Type::Packet::LRPROOF) {
auto link_iter = _link_table.find(packet.destination_hash());
if (link_iter != _link_table.end()) {
LinkEntry link_entry = (*link_iter).second;
// If receiving and outbound interface is
// the same for this link, direction doesn't
// matter, and we simply send the packet on.
Interface outbound_interface(Interface::NONE);
Interface outbound_interface({Type::NONE});
if (link_entry._outbound_interface == link_entry._receiving_interface) {
// But check that taken hops matches one
// of the expectede values.
@ -1397,11 +1397,11 @@ using namespace RNS::Utilities;
// Announce handling. Handles logic related to incoming
// announces, queueing rebroadcasts of these, and removal
// of queued announce rebroadcasts once handed to the next node.
if (packet.packet_type() == Packet::ANNOUNCE) {
if (packet.packet_type() == Type::Packet::ANNOUNCE) {
extreme("Transport::inbound: Packet is ANNOUNCE");
Bytes received_from;
//p local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None)
//Destination local_destination(Destination::NONE);
//Destination local_destination({Type::NONE});
bool found_local = false;
for (auto &destination : _destinations) {
if (destination.hash() == packet.destination_hash()) {
@ -1585,15 +1585,15 @@ using namespace RNS::Utilities;
uint8_t announce_hops = packet.hops();
uint8_t local_rebroadcasts = 0;
bool block_rebroadcasts = false;
Interface attached_interface = Interface::NONE;
Interface attached_interface = {Type::NONE};
uint64_t retransmit_timeout = now + (RNS::Cryptography::random() * Transport::PATHFINDER_RW);
uint64_t expires;
if (packet.receiving_interface().mode() == Interface::MODE_ACCESS_POINT) {
if (packet.receiving_interface().mode() == Type::Interface::MODE_ACCESS_POINT) {
expires = now + Transport::AP_PATH_TIME;
}
else if (packet.receiving_interface().mode() == Interface::MODE_ROAMING) {
else if (packet.receiving_interface().mode() == Type::Interface::MODE_ROAMING) {
expires = now + Transport::ROAMING_PATH_TIME;
}
else {
@ -1603,7 +1603,7 @@ using namespace RNS::Utilities;
std::set<Bytes> random_blobs;
random_blobs.insert(random_blob);
if (Reticulum::transport_enabled() || from_local_client(packet) && packet.context() != Packet::PATH_RESPONSE) {
if (Reticulum::transport_enabled() || from_local_client(packet) && packet.context() != Type::Packet::PATH_RESPONSE) {
// Insert announce into announce table for retransmission
if (rate_blocked) {
@ -1630,7 +1630,7 @@ using namespace RNS::Utilities;
}
}
// TODO: Check from_local_client once and store result
else if (from_local_client(packet) && packet.context() == Packet::PATH_RESPONSE) {
else if (from_local_client(packet) && packet.context() == Type::Packet::PATH_RESPONSE) {
// If this is a path response from a local client,
// check if any external interfaces have pending
// path requests.
@ -1661,7 +1661,7 @@ using namespace RNS::Utilities;
announce_destination = Destination(announce_identity, Destination.OUT, Destination.SINGLE, "unknown", "unknown");
announce_destination.hash(packet.destination_hash());
announce_destination.hexhash = announce_destination.hash().toHex();
announce_context = Packet::NONE;
announce_context = {Type::NONE};
announce_data = packet.data();
// TODO: Shouldn't the context be PATH_RESPONSE in the first case here?
@ -1671,7 +1671,7 @@ using namespace RNS::Utilities;
Packet new_announce(
announce_destination,
announce_data,
Packet::ANNOUNCE,
Type::Packet::ANNOUNCE,
context = announce_context,
header_type = RNS.Packet.HEADER_2,
transport_type = Transport.TRANSPORT,
@ -1690,7 +1690,7 @@ using namespace RNS::Utilities;
Packet new_announce(
announce_destination,
announce_data,
Packet::ANNOUNCE,
Type::Packet::ANNOUNCE,
context = announce_context,
header_type = RNS.Packet.HEADER_2,
transport_type = Transport.TRANSPORT,
@ -1720,16 +1720,16 @@ using namespace RNS::Utilities;
Destination announce_destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown");
announce_destination.hash(packet.destination_hash());
announce_destination.hexhash = announce_destination.hash().toHex();
announce_context = Packet::NONE;
announce_context = {Type::NONE};
announce_data = packet.data();
Packet new_announce(
announce_destination,
announce_data,
Packet::ANNOUNCE,
context = Packet::PATH_RESPONSE,
header_type = Packet::HEADER_2,
transport_type = Transport::TRANSPORT,
Type::Packet::ANNOUNCE,
context = Type::Packet::PATH_RESPONSE,
header_type = Type::Packet::HEADER_2,
transport_type = Type::Transport::TRANSPORT,
transport_id = _identity.hash(),
attached_interface = attached_interface
);
@ -1763,7 +1763,7 @@ using namespace RNS::Utilities;
// Call externally registered callbacks from apps
// wanting to know when an announce arrives
if (packet.context() != Packet::PATH_RESPONSE) {
if (packet.context() != Type::Packet::PATH_RESPONSE) {
for (auto &handler : Transport.announce_handlers) {
try {
// Check that the announced destination matches
@ -1808,7 +1808,7 @@ using namespace RNS::Utilities;
}
// Handling for link requests to local destinations
else if (packet.packet_type() == Packet::LINKREQUEST) {
else if (packet.packet_type() == Type::Packet::LINKREQUEST) {
extreme("Transport::inbound: Packet is LINKREQUEST");
if (!packet.transport_id() || packet.transport_id() == _identity.hash()) {
for (auto &destination : _destinations) {
@ -1823,9 +1823,9 @@ using namespace RNS::Utilities;
}
// Handling for local data packets
else if (packet.packet_type() == Packet::DATA) {
else if (packet.packet_type() == Type::Packet::DATA) {
extreme("Transport::inbound: Packet is DATA");
if (packet.destination_type() == Destination::LINK) {
if (packet.destination_type() == Type::Destination::LINK) {
for (auto &link : _active_links) {
if (link.link_id() == packet.destination_hash()) {
packet.link(link);
@ -1839,10 +1839,10 @@ using namespace RNS::Utilities;
packet.destination(destination);
const_cast<Destination&>(destination).receive(packet);
if (destination.proof_strategy() == Destination::PROVE_ALL) {
if (destination.proof_strategy() == Type::Destination::PROVE_ALL) {
packet.prove();
}
else if (destination.proof_strategy() == Destination::PROVE_APP) {
else if (destination.proof_strategy() == Type::Destination::PROVE_APP) {
if (destination.callbacks()._proof_requested) {
try {
if (destination.callbacks()._proof_requested(packet)) {
@ -1860,7 +1860,7 @@ using namespace RNS::Utilities;
}
// Handling for proofs and link-request proofs
else if (packet.packet_type() == Packet::PROOF) {
else if (packet.packet_type() == Type::Packet::PROOF) {
extreme("Transport::inbound: Packet is PROOF");
/*
if packet.context == RNS.Packet.LRPROOF:
@ -2080,8 +2080,8 @@ using namespace RNS::Utilities;
/*static*/ void Transport::register_destination(Destination &destination) {
extreme("Transport: Registering destination " + destination.toString());
destination.mtu(Reticulum::MTU);
if (destination.direction() == Destination::IN) {
destination.mtu(Type::Reticulum::MTU);
if (destination.direction() == Type::Destination::IN) {
for (auto &registered_destination : _destinations) {
if (destination.hash() == registered_destination.hash()) {
//raise KeyError("Attempt to register an already registered destination.")
@ -2092,7 +2092,7 @@ using namespace RNS::Utilities;
_destinations.insert(destination);
if (_owner.is_connected_to_shared_instance()) {
if (destination.type() == Destination::SINGLE) {
if (destination.type() == Type::Destination::SINGLE) {
destination.announce({}, true);
}
}
@ -2122,12 +2122,12 @@ using namespace RNS::Utilities;
/*
extreme("Transport: Activating link " + link.toString());
if (_pending_links.find(link) != _pending_links.end()) {
if (link.status() != Link::ACTIVE) {
if (link.status() != Type::Link::ACTIVE) {
throw std::runtime_error("Invalid link state for link activation: " + link.status_string());
}
_pending_links.erase(link);
_active_links.insert(link);
link.status(Link::ACTIVE);
link.status(Type::Link::ACTIVE);
}
else {
error("Attempted to activate a link that was not in the pending table");
@ -2166,7 +2166,7 @@ Deregisters an announce handler.
}
}
return {Interface::NONE};
return {Type::NONE};
}
/*static*/ bool Transport::should_cache(const Packet &packet) {
@ -2236,11 +2236,11 @@ Deregisters an announce handler.
}
*/
// MOCK
return {Packet::NONE};
return {Type::NONE};
}
/*static*/ bool Transport::cache_request_packet(const Packet &packet) {
if (packet.data().size() == Identity::HASHLENGTH/8) {
if (packet.data().size() == Type::Identity::HASHLENGTH/8) {
const Packet &cached_packet = get_cached_packet(packet.data());
if (cached_packet) {
@ -2270,7 +2270,7 @@ Deregisters an announce handler.
else {
// The packet is not in the local cache,
// query the network.
Packet request(destination, packet_hash, Packet::DATA, Packet::CACHE_REQUEST);
Packet request(destination, packet_hash, Type::Packet::DATA, Type::Packet::CACHE_REQUEST);
request.send();
}
}
@ -2329,7 +2329,7 @@ Deregisters an announce handler.
return destination_entry._receiving_interface;
}
else {
return {Interface::NONE};
return {Type::NONE};
}
}
@ -2354,7 +2354,7 @@ will announce it.
:param destination_hash: A destination hash as *bytes*.
:param on_interface: If specified, the path request will only be sent on this interface. In normal use, Reticulum handles this automatically, and this parameter should not be used.
*/
/*static*/ void Transport::request_path(const Bytes &destination_hash, const Interface &on_interface /*= {Interface::NONE}*/, const Bytes &tag /*= {}*/, bool recursive /*= false*/) {
/*static*/ void Transport::request_path(const Bytes &destination_hash, const Interface &on_interface /*= {Type::NONE}*/, const Bytes &tag /*= {}*/, bool recursive /*= false*/) {
/*
if tag == None:
request_tag = RNS.Identity.get_random_hash()
@ -2474,7 +2474,7 @@ will announce it.
Transport.pending_local_path_requests[destination_hash] = attached_interface
//local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None)
Destination local_destination(Destination::NONE);
Destination local_destination({Type::NONE});
for (auto &destination : _destinations) {
if (destination.hash() == destination_hash) {
local_destination = destination;

View File

@ -3,10 +3,10 @@
#include "Reticulum.h"
#include "Link.h"
// CBA TODO resolve circular dependency with following header file
//#include "Packet.h"
#include "Packet.h"
#include "Bytes.h"
#include "None.h"
#include "Interfaces/Interface.h"
#include "Type.h"
#include <memory>
#include <vector>
@ -133,6 +133,7 @@ namespace RNS {
public:
// Constants
/*
enum types {
BROADCAST = 0x00,
TRANSPORT = 0x01,
@ -140,6 +141,7 @@ namespace RNS {
TUNNEL = 0x03,
NONE = 0xFF,
};
*/
enum reachabilities {
REACHABILITY_UNREACHABLE = 0x00,
@ -168,7 +170,7 @@ namespace RNS {
static const uint8_t PATH_REQUEST_RW = 2; // Path request random window
static const uint8_t PATH_REQUEST_MI = 5; // Minimum interval in seconds for automated path requests
static constexpr const float LINK_TIMEOUT = Link::STALE_TIME * 1.25;
static constexpr const float LINK_TIMEOUT = Type::Link::STALE_TIME * 1.25;
static const uint16_t REVERSE_TIMEOUT = 30*60; // Reverse table entries are removed after 30 minutes
static const uint32_t DESTINATION_TIMEOUT = 60*60*24*7; // Destination table entries are removed if unused for one week
static const uint16_t MAX_RECEIPTS = 1024; // Maximum number of receipts to keep track of
@ -181,7 +183,7 @@ namespace RNS {
static void transmit(Interface &interface, const Bytes &raw);
static bool outbound(Packet &packet);
static bool packet_filter(const Packet &packet);
static void inbound(const Bytes &raw, const Interface &interface = Interface::NONE);
static void inbound(const Bytes &raw, const Interface &interface = {Type::NONE});
static void synthesize_tunnel(const Interface &interface);
static void tunnel_synthesize_handler(const Bytes &data, const Packet &packet);
static void handle_tunnel(const Bytes &tunnel_id, const Interface &interface);
@ -204,7 +206,7 @@ namespace RNS {
static Bytes next_hop(const Bytes &destination_hash);
static Interface next_hop_interface(const Bytes &destination_hash);
static bool expire_path(const Bytes &destination_hash);
static void request_path(const Bytes &destination_hash, const Interface &on_interface = {Interface::NONE}, const Bytes &tag = {}, bool recursive = false);
static void request_path(const Bytes &destination_hash, const Interface &on_interface = {Type::NONE}, const Bytes &tag = {}, bool recursive = false);
static void path_request_handler(const Bytes &data, const Packet &packet);
static void path_request(const Bytes &destination_hash, bool is_from_local_client, const Interface &attached_interface, const Bytes &requestor_transport_id = {}, const Bytes &tag = {});
static bool from_local_client(const Packet &packet);

321
src/Type.h Normal file
View File

@ -0,0 +1,321 @@
#pragma once
#include "Cryptography/Fernet.h"
#include <stdint.h>
namespace RNS { namespace Type {
// generic empty object constructor type
enum NoneConstructor {
NONE
};
namespace Reticulum {
// Future minimum will probably be locked in at 251 bytes to support
// networks with segments of different MTUs. Absolute minimum is 219.
static const uint16_t MTU = 500;
/*
The MTU that Reticulum adheres to, and will expect other peers to
adhere to. By default, the MTU is 507 bytes. In custom RNS network
implementations, it is possible to change this value, but doing so will
completely break compatibility with all other RNS networks. An identical
MTU is a prerequisite for peers to communicate in the same network.
Unless you really know what you are doing, the MTU should be left at
the default value.
*/
static const uint16_t MAX_QUEUED_ANNOUNCES = 16384;
static const uint32_t QUEUED_ANNOUNCE_LIFE = 60*60*24;
static const uint8_t ANNOUNCE_CAP = 2;
/*
The maximum percentage of interface bandwidth that, at any given time,
may be used to propagate announces. If an announce was scheduled for
broadcasting on an interface, but doing so would exceed the allowed
bandwidth allocation, the announce will be queued for transmission
when there is bandwidth available.
Reticulum will always prioritise propagating announces with fewer
hops, ensuring that distant, large networks with many peers on fast
links don't overwhelm the capacity of smaller networks on slower
mediums. If an announce remains queued for an extended amount of time,
it will eventually be dropped.
This value will be applied by default to all created interfaces,
but it can be configured individually on a per-interface basis.
*/
static const uint16_t MINIMUM_BITRATE = 500;
// TODO: To reach the 300bps level without unreasonably impacting
// performance on faster links, we need a mechanism for setting
// this value more intelligently. One option could be inferring it
// from interface speed, but a better general approach would most
// probably be to let Reticulum somehow continously build a map of
// per-hop latencies and use this map for the timeout calculation.
static const uint8_t DEFAULT_PER_HOP_TIMEOUT = 6;
static const uint16_t HASHLENGTH = 256; // In bits
// Length of truncated hashes in bits.
static const uint16_t TRUNCATED_HASHLENGTH = 128; // In bits
static const uint16_t HEADER_MINSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*1; // In bytes
static const uint16_t HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*2; // In bytes
static const uint16_t IFAC_MIN_SIZE = 1;
//zIFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8")
static const uint16_t MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE;
static const uint32_t RESOURCE_CACHE = 24*60*60;
static const uint16_t JOB_INTERVAL = 5*60;
static const uint16_t CLEAN_INTERVAL = 15*60;
static const uint16_t PERSIST_INTERVAL = 60*60*12;
static const uint16_t GRACIOUS_PERSIST_INTERVAL = 60*5;
static const uint8_t DESTINATION_LENGTH = TRUNCATED_HASHLENGTH/8; // In bytes
}
namespace Identity {
//static const char CURVE[] = "Curve25519";
static constexpr const char* CURVE = "Curve25519";
// The curve used for Elliptic Curve DH key exchanges
static const uint16_t KEYSIZE = 256*2;
// X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.
// Non-configurable constants
static const uint8_t FERNET_OVERHEAD = Cryptography::Fernet::FERNET_OVERHEAD;
static const uint8_t AES128_BLOCKSIZE = 16; // In bytes
static const uint16_t HASHLENGTH = Reticulum::HASHLENGTH; // In bits
static const uint16_t SIGLENGTH = KEYSIZE; // In bits
static const uint8_t NAME_HASH_LENGTH = 80;
static const uint16_t TRUNCATED_HASHLENGTH = Reticulum::TRUNCATED_HASHLENGTH; // In bits
// Constant specifying the truncated hash length (in bits) used by Reticulum
// for addressable hashes and other purposes. Non-configurable.
}
namespace Destination {
enum types {
SINGLE = 0x00,
GROUP = 0x01,
PLAIN = 0x02,
LINK = 0x03,
};
enum proof_strategies {
PROVE_NONE = 0x21,
PROVE_APP = 0x22,
PROVE_ALL = 0x23,
};
enum request_policies {
ALLOW_NONE = 0x00,
ALLOW_ALL = 0x01,
ALLOW_LIST = 0x02,
};
enum directions {
IN = 0x11,
OUT = 0x12,
};
const uint8_t PR_TAG_WINDOW = 30;
}
namespace Link {
static constexpr const char* CURVE = Identity::CURVE;
// The curve used for Elliptic Curve DH key exchanges
static const uint16_t ECPUBSIZE = 32+32;
static const uint8_t KEYSIZE = 32;
//static const uint16_t MDU = floor((Reticulum::MTU-Reticulum::IFAC_MIN_SIZE-Reticulum::HEADER_MINSIZE-Identity::FERNET_OVERHEAD)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1;
static const uint16_t MDU = ((Reticulum::MTU-Reticulum::IFAC_MIN_SIZE-Reticulum::HEADER_MINSIZE-Identity::FERNET_OVERHEAD)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1;
static const uint8_t ESTABLISHMENT_TIMEOUT_PER_HOP = Reticulum::DEFAULT_PER_HOP_TIMEOUT;
// Timeout for link establishment in seconds per hop to destination.
static const uint16_t TRAFFIC_TIMEOUT_FACTOR = 6;
static const uint16_t KEEPALIVE_TIMEOUT_FACTOR = 4;
// RTT timeout factor used in link timeout calculation.
static const uint8_t STALE_GRACE = 2;
// Grace period in seconds used in link timeout calculation.
static const uint16_t KEEPALIVE = 360;
// Interval for sending keep-alive packets on established links in seconds.
static const uint16_t STALE_TIME = 2*KEEPALIVE;
/*
If no traffic or keep-alive packets are received within this period, the
link will be marked as stale, and a final keep-alive packet will be sent.
If after this no traffic or keep-alive packets are received within ``RTT`` *
``KEEPALIVE_TIMEOUT_FACTOR`` + ``STALE_GRACE``, the link is considered timed out,
and will be torn down.
*/
enum status {
PENDING = 0x00,
HANDSHAKE = 0x01,
ACTIVE = 0x02,
STALE = 0x03,
CLOSED = 0x04
};
enum teardown_reasons {
TIMEOUT = 0x01,
INITIATOR_CLOSED = 0x02,
DESTINATION_CLOSED = 0x03,
};
enum resource_strategies {
ACCEPT_NONE = 0x00,
ACCEPT_APP = 0x01,
ACCEPT_ALL = 0x02,
};
}
namespace Interface {
// Interface mode definitions
enum modes {
MODE_NONE = 0x00,
MODE_FULL = 0x01,
MODE_POINT_TO_POINT = 0x04,
MODE_ACCESS_POINT = 0x08,
MODE_ROAMING = 0x10,
MODE_BOUNDARY = 0x20,
MODE_GATEWAY = 0x40,
};
}
namespace Packet {
// Packet types
enum types {
DATA = 0x00, // Data packets
ANNOUNCE = 0x01, // Announces
LINKREQUEST = 0x02, // Link requests
PROOF = 0x03, // Proofs
};
// Header types
enum header_types {
HEADER_1 = 0x00, // Normal header format
HEADER_2 = 0x01, // Header format used for packets in transport
};
// Packet context types
enum context_types {
CONTEXT_NONE = 0x00, // Generic data packet
RESOURCE = 0x01, // Packet is part of a resource
RESOURCE_ADV = 0x02, // Packet is a resource advertisement
RESOURCE_REQ = 0x03, // Packet is a resource part request
RESOURCE_HMU = 0x04, // Packet is a resource hashmap update
RESOURCE_PRF = 0x05, // Packet is a resource proof
RESOURCE_ICL = 0x06, // Packet is a resource initiator cancel message
RESOURCE_RCL = 0x07, // Packet is a resource receiver cancel message
CACHE_REQUEST = 0x08, // Packet is a cache request
REQUEST = 0x09, // Packet is a request
RESPONSE = 0x0A, // Packet is a response to a request
PATH_RESPONSE = 0x0B, // Packet is a response to a path request
COMMAND = 0x0C, // Packet is a command
COMMAND_STATUS = 0x0D, // Packet is a status of an executed command
CHANNEL = 0x0E, // Packet contains link channel data
KEEPALIVE = 0xFA, // Packet is a keepalive packet
LINKIDENTIFY = 0xFB, // Packet is a link peer identification proof
LINKCLOSE = 0xFC, // Packet is a link close message
LINKPROOF = 0xFD, // Packet is a link packet proof
LRRTT = 0xFE, // Packet is a link request round-trip time measurement
LRPROOF = 0xFF, // Packet is a link request proof
};
// This is used to calculate allowable
// payload sizes
static const uint16_t HEADER_MAXSIZE = Reticulum::HEADER_MAXSIZE;
static const uint16_t MDU = Reticulum::MDU;
// With an MTU of 500, the maximum of data we can
// send in a single encrypted packet is given by
// the below calculation; 383 bytes.
//static const uint16_t ENCRYPTED_MDU = floor((Reticulum::MDU-Identity::FERNET_OVERHEAD-Identity::KEYSIZE/16)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1;
//static const uint16_t ENCRYPTED_MDU;
static const uint16_t ENCRYPTED_MDU = ((Reticulum::MDU-Identity::FERNET_OVERHEAD-Identity::KEYSIZE/16)/Identity::AES128_BLOCKSIZE)*Identity::AES128_BLOCKSIZE - 1;
// The maximum size of the payload data in a single encrypted packet
static const uint16_t PLAIN_MDU = MDU;
// The maximum size of the payload data in a single unencrypted packet
static const uint8_t TIMEOUT_PER_HOP = Reticulum::DEFAULT_PER_HOP_TIMEOUT;
}
namespace PacketReceipt {
// Receipt status constants
enum Status {
FAILED = 0x00,
SENT = 0x01,
DELIVERED = 0x02,
CULLED = 0xFF
};
static const uint16_t EXPL_LENGTH = Identity::HASHLENGTH / 8 + Identity::SIGLENGTH / 8;
static const uint16_t IMPL_LENGTH = Identity::SIGLENGTH / 8;
}
namespace Transport {
enum types {
BROADCAST = 0x00,
TRANSPORT = 0x01,
RELAY = 0x02,
TUNNEL = 0x03,
NONE = 0xFF,
};
enum reachabilities {
REACHABILITY_UNREACHABLE = 0x00,
REACHABILITY_DIRECT = 0x01,
REACHABILITY_TRANSPORT = 0x02,
};
static constexpr const char* APP_NAME = "rnstransport";
static const uint8_t PATHFINDER_M = 128; // Max hops
// Maximum amount of hops that Reticulum will transport a packet.
static const uint8_t PATHFINDER_R = 1; // Retransmit retries
static const uint8_t PATHFINDER_G = 5; // Retry grace period
static constexpr const float PATHFINDER_RW = 0.5; // Random window for announce rebroadcast
static const uint32_t PATHFINDER_E = 60*60*24*7; // Path expiration of one week
static const uint32_t AP_PATH_TIME = 60*60*24; // Path expiration of one day for Access Point paths
static const uint32_t ROAMING_PATH_TIME = 60*60*6; // Path expiration of 6 hours for Roaming paths
// TODO: Calculate an optimal number for this in
// various situations
static const uint8_t LOCAL_REBROADCASTS_MAX = 2; // How many local rebroadcasts of an announce is allowed
static const uint8_t PATH_REQUEST_TIMEOUT = 15; // Default timuout for client path requests in seconds
static constexpr const float PATH_REQUEST_GRACE = 0.35; // Grace time before a path announcement is made, allows directly reachable peers to respond first
static const uint8_t PATH_REQUEST_RW = 2; // Path request random window
static const uint8_t PATH_REQUEST_MI = 5; // Minimum interval in seconds for automated path requests
static constexpr const float LINK_TIMEOUT = Link::STALE_TIME * 1.25;
static const uint16_t REVERSE_TIMEOUT = 30*60; // Reverse table entries are removed after 30 minutes
static const uint32_t DESTINATION_TIMEOUT = 60*60*24*7; // Destination table entries are removed if unused for one week
static const uint16_t MAX_RECEIPTS = 1024; // Maximum number of receipts to keep track of
static const uint8_t MAX_RATE_TIMESTAMPS = 16; // Maximum number of announce timestamps to keep per destination
}
} }

View File

@ -175,7 +175,7 @@ void setup() {
// 22.6% (+0.7%)
RNS::head("Creating Destination instance...", RNS::LOG_EXTREME);
RNS::Destination destination(identity, RNS::Destination::IN, RNS::Destination::SINGLE, "test", "context");
RNS::Destination destination(identity, RNS::Type::Destination::IN, RNS::Type::Destination::SINGLE, "test", "context");
// 23.0% (+0.4%)
/*
@ -197,7 +197,7 @@ void setup() {
}
*/
destination.set_proof_strategy(RNS::Destination::PROVE_ALL);
destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL);
//zRNS::head("Registering announce handler with Transport...", RNS::LOG_EXTREME);
//zannounce_handler = ExampleAnnounceHandler(
@ -213,7 +213,7 @@ void setup() {
destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
// 23.9% (+0.8%)
/*
/**/
// test data send packet
RNS::head("Creating send packet...", RNS::LOG_EXTREME);
RNS::Packet send_packet(destination, "The quick brown fox jumps over the lazy dog");
@ -227,13 +227,13 @@ void setup() {
destination.set_packet_callback(onPacket);
RNS::head("Creating recv packet...", RNS::LOG_EXTREME);
RNS::Packet recv_packet(RNS::Destination::NONE, send_packet.raw());
RNS::Packet recv_packet({RNS::Type::NONE}, send_packet.raw());
recv_packet.unpack();
RNS::extreme("Test recv_packet: " + recv_packet.debugString());
RNS::head("Spoofing recv packet to destination...", RNS::LOG_EXTREME);
destination.receive(recv_packet);
*/
/**/
}
catch (std::exception& e) {