WIP: Collection optimizations and Transport

Tested and optimized collections used in Transport.
Additional Transport implementation.
This commit is contained in:
attermann 2023-11-21 06:21:03 -07:00
parent 263f589801
commit 8d943318a6
14 changed files with 742 additions and 230 deletions

View File

@ -26,6 +26,22 @@ lib_deps =
rweather/Crypto@^0.4.0 rweather/Crypto@^0.4.0
lib_compat_mode = off lib_compat_mode = off
[env:native17]
platform = native
build_unflags = -std=gnu++11
build_flags =
-std=c++17
-Wall
-Wextra
-Wno-missing-field-initializers
-Wno-format
-Wno-unused-parameter
-Isrc
-DNATIVE
lib_deps =
rweather/Crypto@^0.4.0
lib_compat_mode = off
[env:ttgo-t-beam] [env:ttgo-t-beam]
platform = espressif32 platform = espressif32
board = ttgo-t-beam board = ttgo-t-beam

View File

@ -240,7 +240,7 @@ namespace RNS {
inline Bytes bytesFromChunk(const uint8_t *ptr, size_t len) { return {ptr, len}; } inline Bytes bytesFromChunk(const uint8_t *ptr, size_t len) { return {ptr, len}; }
//inline Bytes bytesFromString(const char *str) { return Bytes((uint8_t*)str, strlen(str)); } //inline Bytes bytesFromString(const char *str) { return Bytes((uint8_t*)str, strlen(str)); }
inline Bytes bytesFromString(const char *str) { return {(uint8_t*)str, strlen(str)}; } inline Bytes bytesFromString(const char *str) { return {(uint8_t*)str, strlen(str)}; }
//zinline Bytes bytesFromInt(const int) { return {(uint8_t*)str, strlen(str)}; } //z inline Bytes bytesFromInt(const int) { return {(uint8_t*)str, strlen(str)}; }
inline std::string stringFromBytes(const Bytes& bytes) { return bytes.toString(); } inline std::string stringFromBytes(const Bytes& bytes) { return bytes.toString(); }
inline std::string hexFromBytes(const Bytes& bytes) { return bytes.toHex(); } inline std::string hexFromBytes(const Bytes& bytes) { return bytes.toHex(); }

View File

@ -85,7 +85,7 @@ namespace RNS { namespace Cryptography {
} }
inline const Bytes sign(const Bytes& message) { inline const Bytes sign(const Bytes& message) {
//zreturn _sk.sign(message); //z return _sk.sign(message);
Bytes signature; Bytes signature;
Ed25519::sign(signature.writable(64), _privateKey.data(), _publicKey.data(), message.data(), message.size()); Ed25519::sign(signature.writable(64), _privateKey.data(), _publicKey.data(), message.data(), message.size());
return signature; return signature;

View File

@ -59,7 +59,7 @@ namespace RNS { namespace Cryptography {
const float MAX_EXEC_TIME = 500; // in milliseconds const float MAX_EXEC_TIME = 500; // in milliseconds
const uint8_t DELAY_WINDOW = 10; const uint8_t DELAY_WINDOW = 10;
//zT_CLEAR = None //z T_CLEAR = None
const uint8_t T_MAX = 0; const uint8_t T_MAX = 0;
public: public:

View File

@ -74,6 +74,26 @@ Destination::Destination(const Identity& identity, const directions direction, c
return Identity::truncated_hash(addr_hash_material); return Identity::truncated_hash(addr_hash_material);
} }
/*
:returns: A tuple containing the app name and a list of aspects, for a full-name string.
*/
/*static*/ Bytes Destination::app_and_aspects_from_name(const char* full_name) {
//z components = full_name.split(".")
//z return (components[0], components[1:])
// MOCK
return {Bytes::NONE};
}
/*
:returns: A destination name in adressable hash form, for a full name string and Identity instance.
*/
/*static*/ Bytes Destination::hash_from_name_and_identity(const char* full_name, const Identity& identity) {
//z app_name, aspects = Destination.app_and_aspects_from_name(full_name)
//z return Destination.hash(identity, app_name, *aspects)
// MOCK
return {Bytes::NONE};
}
/* /*
:returns: A string containing the full human-readable name of the destination, for an app_name and a number of aspects. :returns: A string containing the full human-readable name of the destination, for an app_name and a number of aspects.
*/ */
@ -169,7 +189,7 @@ Packet Destination::announce(const Bytes& app_data, bool path_response, const In
// received via multiple paths. The difference in reception time will // received via multiple paths. The difference in reception time will
// potentially also be useful in determining characteristics of the // potentially also be useful in determining characteristics of the
// multiple available paths, and to choose the best one. // multiple available paths, and to choose the best one.
//zextreme("Using cached announce data for answering path request with tag "+RNS.prettyhexrep(tag)); //z extreme("Using cached announce data for answering path request with tag "+RNS.prettyhexrep(tag));
announce_data << _object->_path_responses[tag].second; announce_data << _object->_path_responses[tag].second;
} }
else { else {

View File

@ -79,8 +79,10 @@ namespace RNS {
} }
public: public:
static Bytes hash(const Identity& identity, const char *app_name, const char *aspects);
static std::string expand_name(const Identity& identity, const char *app_name, const char *aspects); 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 app_and_aspects_from_name(const char* full_name);
static Bytes hash_from_name_and_identity(const char* full_name, const Identity& identity);
public: 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 = false, const Interface& attached_interface = {Type::NONE}, const Bytes& tag = {}, bool send = true);
@ -153,6 +155,7 @@ namespace RNS {
inline Type::Destination::directions direction() const { assert(_object); return _object->_direction; } 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 Type::Destination::proof_strategies proof_strategy() const { assert(_object); return _object->_proof_strategy; }
inline const Bytes& hash() const { assert(_object); return _object->_hash; } inline const Bytes& hash() const { assert(_object); return _object->_hash; }
inline void hash(const Bytes& hash) { assert(_object); _object->_hash = hash; _object->_hexhash = _object->_hash.toHex(); }
inline const Bytes& link_id() const { assert(_object); return _object->_link_id; } inline const Bytes& link_id() const { assert(_object); return _object->_link_id; }
inline uint16_t mtu() const { assert(_object); return _object->_mtu; } inline uint16_t mtu() const { assert(_object); return _object->_mtu; }
inline void mtu(uint16_t mtu) { assert(_object); _object->_mtu = mtu; } inline void mtu(uint16_t mtu) { assert(_object); _object->_mtu = mtu; }
@ -170,7 +173,7 @@ namespace RNS {
private: private:
bool _accept_link_requests = true; bool _accept_link_requests = true;
Callbacks _callbacks; Callbacks _callbacks;
//z_request_handlers = {} //z _request_handlers = {}
Type::Destination::types _type; Type::Destination::types _type;
Type::Destination::directions _direction; Type::Destination::directions _direction;
Type::Destination::proof_strategies _proof_strategy = Type::Destination::PROVE_NONE; Type::Destination::proof_strategies _proof_strategy = Type::Destination::PROVE_NONE;
@ -178,7 +181,7 @@ namespace RNS {
//std::vector<PathResponse> _path_responses; //std::vector<PathResponse> _path_responses;
std::map<Bytes, PathResponse> _path_responses; std::map<Bytes, PathResponse> _path_responses;
//z_links = [] //z _links = []
Identity _identity; Identity _identity;
std::string _name; std::string _name;
@ -190,8 +193,8 @@ namespace RNS {
// CBA TODO when is _default_app_data a "callable"? // CBA TODO when is _default_app_data a "callable"?
Bytes _default_app_data; Bytes _default_app_data;
//z_callback = None //z _callback = None
//z_proofcallback = None //z _proofcallback = None
// CBA _link_id is expected by packet but only present in 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 // CBA TODO determine if Link needs to inherit from Destination or vice-versa

View File

@ -1,8 +1,10 @@
#include "Identity.h" #include "Identity.h"
#include "Reticulum.h" #include "Reticulum.h"
#include "Transport.h"
#include "Packet.h" #include "Packet.h"
#include "Log.h" #include "Log.h"
#include "Utilities/OS.h"
#include "Cryptography/X25519.h" #include "Cryptography/X25519.h"
#include "Cryptography/HKDF.h" #include "Cryptography/HKDF.h"
#include "Cryptography/Fernet.h" #include "Cryptography/Fernet.h"
@ -12,6 +14,9 @@
using namespace RNS; using namespace RNS;
using namespace RNS::Type::Identity; using namespace RNS::Type::Identity;
using namespace RNS::Utilities;
/*static*/ std::map<Bytes, Identity::IdentityEntry> Identity::_known_destinations;
Identity::Identity(bool create_keys) : _object(new Object()) { Identity::Identity(bool create_keys) : _object(new Object()) {
if (create_keys) { if (create_keys) {
@ -20,7 +25,6 @@ Identity::Identity(bool create_keys) : _object(new Object()) {
extreme("Identity object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get())); extreme("Identity object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
} }
void Identity::createKeys() { void Identity::createKeys() {
assert(_object); assert(_object);
@ -49,6 +53,215 @@ void Identity::createKeys() {
verbose("Identity keys created for " + _object->_hash.toHex()); verbose("Identity keys created for " + _object->_hash.toHex());
} }
/*
Load a private key into the instance.
:param prv_bytes: The private key as *bytes*.
:returns: True if the key was loaded, otherwise False.
*/
bool Identity::load_private_key(const Bytes& prv_bytes) {
/*
assert(_object);
try {
//p self.prv_bytes = prv_bytes[:Identity.KEYSIZE//8//2]
_object->_prv_bytes = prv_bytes.left(Type::Identity::KEYSIZE/8/2);
_object->_prv = X25519PrivateKey::from_private_bytes(_object->_prv_bytes);
//p self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:]
_object->_sig_prv_bytes = prv_bytes.mid(Type::Identity::KEYSIZE/8/2);
_object->_sig_prv = Ed25519PrivateKey::from_private_bytes(_object->_sig_prv_bytes);
_object->_pub = _object->_prv.public_key();
_object->_pub_bytes = _object->_pub.public_bytes();
_object->_sig_pub = _object->_sig_prv.public_key();
_object->_sig_pub_bytes = _object->_sig_pub.public_bytes();
update_hashes();
return true;
}
catch (std::exception& e) {
//p raise e
error("Failed to load identity key";
error("The contained exception was: " + e.what());
return false;
}
*/
// MOCK
return true;
}
/*
Load a public key into the instance.
:param pub_bytes: The public key as *bytes*.
:returns: True if the key was loaded, otherwise False.
*/
void Identity::load_public_key(const Bytes& pub_bytes) {
/*
assert(_object);
try {
//_pub_bytes = pub_bytes[:Identity.KEYSIZE//8//2]
_object->_pub_bytes = pub_bytes.left(Type::Identity::KEYSIZE/8/2);
//_sig_pub_bytes = pub_bytes[Identity.KEYSIZE//8//2:]
_object->_sig_pub_bytes = pub_bytes.mid(Type::Identity::KEYSIZE/8/2);
_object->_pub = X25519PublicKey::from_public_bytes(_object->_pub_bytes)
_object->_sig_pub = Ed25519PublicKey::from_public_bytes(_object->_sig_pub_bytes)
update_hashes();
}
catch (std::exception& e) {
error("Error while loading public key, the contained exception was: " + e.what());
}
*/
}
bool Identity::load(const char* path) {
/*
try:
with open(path, "rb") as key_file:
prv_bytes = key_file.read()
return self.load_private_key(prv_bytes)
return False
except Exception as e:
RNS.log("Error while loading identity from "+str(path), RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
*/
// MOCK
return true;
}
/*static*/ void Identity::remember(const Bytes& packet_hash, const Bytes& destination_hash, const Bytes& public_key, const Bytes& app_data /*= {Bytes::NONE}*/) {
if (public_key.size() != Type::Identity::KEYSIZE/8) {
throw std::invalid_argument("Can't remember " + destination_hash.toHex() + ", the public key size of " + std::to_string(public_key.size()) + " is not valid.");
}
else {
//_known_destinations[destination_hash] = {OS::time(), packet_hash, public_key, app_data};
_known_destinations.insert({destination_hash, {OS::time(), packet_hash, public_key, app_data}});
}
}
/*
Recall identity for a destination hash.
:param destination_hash: Destination hash as *bytes*.
:returns: An :ref:`RNS.Identity<api-identity>` instance that can be used to create an outgoing :ref:`RNS.Destination<api-destination>`, or *None* if the destination is unknown.
*/
/*static*/ Identity Identity::recall(const Bytes& destination_hash) {
auto iter = _known_destinations.find(destination_hash);
if (iter != _known_destinations.end()) {
const IdentityEntry& identity_data = (*iter).second;
Identity identity(false);
identity.load_public_key(identity_data._public_key);
identity.app_data(identity_data._app_data);
return identity;
}
else {
Destination registered_destination(Transport::find_destination_from_hash(destination_hash));
if (registered_destination) {
Identity identity(false);
identity.load_public_key(registered_destination.identity().get_public_key());
identity.app_data({Bytes::NONE});
return identity;
}
return {Type::NONE};
}
}
/*
Recall last heard app_data for a destination hash.
:param destination_hash: Destination hash as *bytes*.
:returns: *Bytes* containing app_data, or *None* if the destination is unknown.
*/
/*static*/ Bytes Identity::recall_app_data(const Bytes& destination_hash) {
auto iter = _known_destinations.find(destination_hash);
if (iter != _known_destinations.end()) {
const IdentityEntry& identity_data = (*iter).second;
return identity_data._app_data;
}
else {
return {Bytes::NONE};
}
}
/*static*/ void Identity::save_known_destinations() {
/*
// TODO: Improve the storage method so we don't have to
// deserialize and serialize the entire table on every
// save, but the only changes. It might be possible to
// simply overwrite on exit now that every local client
// disconnect triggers a data persist.
try:
if hasattr(Identity, "saving_known_destinations"):
wait_interval = 0.2
wait_timeout = 5
wait_start = time.time()
while Identity.saving_known_destinations:
time.sleep(wait_interval)
if time.time() > wait_start+wait_timeout:
RNS.log("Could not save known destinations to storage, waiting for previous save operation timed out.", RNS.LOG_ERROR)
return False
Identity.saving_known_destinations = True
save_start = time.time()
storage_known_destinations = {}
if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"):
try:
file = open(RNS.Reticulum.storagepath+"/known_destinations","rb")
storage_known_destinations = umsgpack.load(file)
file.close()
except:
pass
for destination_hash in storage_known_destinations:
if not destination_hash in Identity.known_destinations:
Identity.known_destinations[destination_hash] = storage_known_destinations[destination_hash]
RNS.log("Saving "+str(len(Identity.known_destinations))+" known destinations to storage...", RNS.LOG_DEBUG)
file = open(RNS.Reticulum.storagepath+"/known_destinations","wb")
umsgpack.dump(Identity.known_destinations, file)
file.close()
save_time = time.time() - save_start
if save_time < 1:
time_str = str(round(save_time*1000,2))+"ms"
else:
time_str = str(round(save_time,2))+"s"
RNS.log("Saved known destinations to storage in "+time_str, RNS.LOG_DEBUG)
except Exception as e:
RNS.log("Error while saving known destinations to disk, the contained exception was: "+str(e), RNS.LOG_ERROR)
Identity.saving_known_destinations = False
*/
}
/*static*/ void Identity::load_known_destinations() {
/*
if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"):
try:
file = open(RNS.Reticulum.storagepath+"/known_destinations","rb")
loaded_known_destinations = umsgpack.load(file)
file.close()
Identity.known_destinations = {}
for known_destination in loaded_known_destinations:
if len(known_destination) == RNS.Reticulum.TRUNCATED_HASHLENGTH//8:
Identity.known_destinations[known_destination] = loaded_known_destinations[known_destination]
RNS.log("Loaded "+str(len(Identity.known_destinations))+" known destination from storage", RNS.LOG_VERBOSE)
except:
RNS.log("Error loading known destinations from disk, file will be recreated on exit", RNS.LOG_ERROR)
else:
RNS.log("Destinations file does not exist, no known destinations loaded", RNS.LOG_VERBOSE)
*/
}
/*static*/ bool Identity::validate_announce(const Packet& packet) { /*static*/ bool Identity::validate_announce(const Packet& packet) {
/* /*
@ -132,7 +345,7 @@ Encrypts information for the identity.
:returns: Ciphertext token as *bytes*. :returns: Ciphertext token as *bytes*.
:raises: *KeyError* if the instance does not hold a public key. :raises: *KeyError* if the instance does not hold a public key.
*/ */
const Bytes Identity::encrypt(const Bytes& plaintext) { const Bytes Identity::encrypt(const Bytes& plaintext) const {
assert(_object); assert(_object);
debug("Identity::encrypt: encrypting data..."); debug("Identity::encrypt: encrypting data...");
if (!_object->_pub) { if (!_object->_pub) {
@ -172,7 +385,7 @@ Decrypts information for the identity.
:returns: Plaintext as *bytes*, or *None* if decryption fails. :returns: Plaintext as *bytes*, or *None* if decryption fails.
:raises: *KeyError* if the instance does not hold a private key. :raises: *KeyError* if the instance does not hold a private key.
*/ */
const Bytes Identity::decrypt(const Bytes& ciphertext_token) { const Bytes Identity::decrypt(const Bytes& ciphertext_token) const {
assert(_object); assert(_object);
debug("Identity::decrypt: decrypting data..."); debug("Identity::decrypt: decrypting data...");
if (!_object->_prv) { if (!_object->_prv) {
@ -226,7 +439,7 @@ Signs information by the identity.
:returns: Signature as *bytes*. :returns: Signature as *bytes*.
:raises: *KeyError* if the instance does not hold a private key. :raises: *KeyError* if the instance does not hold a private key.
*/ */
const Bytes Identity::sign(const Bytes& message) { const Bytes Identity::sign(const Bytes& message) const {
assert(_object); assert(_object);
if (!_object->_sig_prv) { if (!_object->_sig_prv) {
throw std::runtime_error("Signing failed because identity does not hold a private key"); throw std::runtime_error("Signing failed because identity does not hold a private key");
@ -248,7 +461,7 @@ Validates the signature of a signed message.
:returns: True if the signature is valid, otherwise False. :returns: True if the signature is valid, otherwise False.
:raises: *KeyError* if the instance does not hold a public key. :raises: *KeyError* if the instance does not hold a public key.
*/ */
bool Identity::validate(const Bytes& signature, const Bytes& message) { bool Identity::validate(const Bytes& signature, const Bytes& message) const {
assert(_object); assert(_object);
if (_object->_pub) { if (_object->_pub) {
try { try {
@ -264,7 +477,7 @@ bool Identity::validate(const Bytes& signature, const Bytes& message) {
} }
} }
void Identity::prove(const Packet& packet, const Destination& destination /*= {Type::NONE}*/) { void Identity::prove(const Packet& packet, const Destination& destination /*= {Type::NONE}*/) const {
assert(_object); assert(_object);
Bytes signature(sign(packet.packet_hash())); Bytes signature(sign(packet.packet_hash()));
Bytes proof_data; Bytes proof_data;
@ -283,6 +496,6 @@ void Identity::prove(const Packet& packet, const Destination& destination /*= {T
proof.send(); proof.send();
} }
void Identity::prove(const Packet& packet) { void Identity::prove(const Packet& packet) const {
prove(packet, {Type::NONE}); prove(packet, {Type::NONE});
} }

View File

@ -8,9 +8,9 @@
#include "Cryptography/X25519.h" #include "Cryptography/X25519.h"
#include "Cryptography/Fernet.h" #include "Cryptography/Fernet.h"
#include <map>
#include <memory>
#include <string> #include <string>
#include <memory>
namespace RNS { namespace RNS {
@ -19,6 +19,23 @@ namespace RNS {
class Identity { class Identity {
private:
class IdentityEntry {
public:
IdentityEntry(uint64_t timestamp, const Bytes& packet_hash, const Bytes& public_key, const Bytes& app_data) :
_timestamp(timestamp),
_packet_hash(packet_hash),
_public_key(public_key),
_app_data(app_data)
{
}
public:
uint64_t _timestamp = 0;
Bytes _packet_hash;
Bytes _public_key;
Bytes _app_data;
};
public: public:
Identity(Type::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())); extreme("Identity NONE object created, this: " + std::to_string((uintptr_t)this) + ", data: " + std::to_string((uintptr_t)_object.get()));
@ -45,20 +62,48 @@ namespace RNS {
public: public:
void createKeys(); void createKeys();
/*
:returns: The private key as *bytes*
*/
inline const Bytes get_private_key() const {
assert(_object);
return _object->_prv_bytes + _object->_sig_prv_bytes;
}
/* /*
:returns: The public key as *bytes* :returns: The public key as *bytes*
*/ */
inline const Bytes get_public_key() { inline const Bytes get_public_key() const {
assert(_object); assert(_object);
return _object->_pub_bytes + _object->_sig_pub_bytes; return _object->_pub_bytes + _object->_sig_pub_bytes;
} }
bool load_private_key(const Bytes& prv_bytes);
void load_public_key(const Bytes& pub_bytes);
inline void update_hashes() { inline void update_hashes() {
assert(_object); assert(_object);
_object->_hash = truncated_hash(get_public_key()); _object->_hash = truncated_hash(get_public_key());
debug("Identity::update_hashes: hash: " + _object->_hash.toHex()); debug("Identity::update_hashes: hash: " + _object->_hash.toHex());
_object->_hexhash = _object->_hash.toHex(); _object->_hexhash = _object->_hash.toHex();
}; };
bool load(const char* path);
inline const Bytes get_salt() const { assert(_object); return _object->_hash; }
inline const Bytes get_context() const { return {Bytes::NONE}; }
const Bytes encrypt(const Bytes& plaintext) const;
const Bytes decrypt(const Bytes& ciphertext_token) const;
const Bytes sign(const Bytes& message) const;
bool validate(const Bytes& signature, const Bytes& message) const;
// CBA following default for reference value requires inclusiion of header
//void prove(const Packet& packet, const Destination& destination = {Type::NONE}) const;
void prove(const Packet& packet, const Destination& destination) const;
void prove(const Packet& packet) const;
static void remember(const Bytes& packet_hash, const Bytes& destination_hash, const Bytes& public_key, const Bytes& app_data = {Bytes::NONE});
static Identity recall(const Bytes& destination_hash);
static Bytes recall_app_data(const Bytes& destination_hash);
static void save_known_destinations();
static void load_known_destinations();
/* /*
Get a SHA-256 hash of passed data. Get a SHA-256 hash of passed data.
@ -75,7 +120,7 @@ namespace RNS {
:returns: Truncated SHA-256 hash as *bytes* :returns: Truncated SHA-256 hash as *bytes*
*/ */
static inline const Bytes truncated_hash(const Bytes& data) { static inline const Bytes truncated_hash(const Bytes& data) {
//return Identity.full_hash(data)[:(Identity.TRUNCATED_HASHLENGTH//8)] //p return Identity.full_hash(data)[:(Identity.TRUNCATED_HASHLENGTH//8)]
return full_hash(data).left(Type::Identity::TRUNCATED_HASHLENGTH/8); return full_hash(data).left(Type::Identity::TRUNCATED_HASHLENGTH/8);
} }
/* /*
@ -90,24 +135,14 @@ namespace RNS {
static bool validate_announce(const Packet& packet); static bool validate_announce(const Packet& packet);
inline const Bytes get_salt() { assert(_object); return _object->_hash; }
inline const Bytes get_context() { return {Bytes::NONE}; }
const Bytes encrypt(const Bytes& plaintext);
const Bytes decrypt(const Bytes& ciphertext_token);
const Bytes sign(const Bytes& message);
bool validate(const Bytes& signature, const Bytes& message);
// CBA following default for reference value requires inclusiion of header
//void prove(const Packet& packet, const Destination& destination = {Type::NONE});
void prove(const Packet& packet, const Destination& destination);
void prove(const Packet& packet);
// getters/setters // getters/setters
inline const Bytes& encryptionPrivateKey() const { assert(_object); return _object->_prv_bytes; } inline const Bytes& encryptionPrivateKey() const { assert(_object); return _object->_prv_bytes; }
inline const Bytes& signingPrivateKey() const { assert(_object); return _object->_sig_prv_bytes; } inline const Bytes& signingPrivateKey() const { assert(_object); return _object->_sig_prv_bytes; }
inline const Bytes& encryptionPublicKey() const { assert(_object); return _object->_prv_bytes; } inline const Bytes& encryptionPublicKey() const { assert(_object); return _object->_prv_bytes; }
inline const Bytes& signingPublicKey() const { assert(_object); return _object->_sig_prv_bytes; } inline const Bytes& signingPublicKey() const { assert(_object); return _object->_sig_prv_bytes; }
inline const Bytes& hash() const { assert(_object); return _object->_hash; } inline const Bytes& hash() const { assert(_object); return _object->_hash; }
inline const Bytes& app_data() const { assert(_object); return _object->_app_data; }
inline void app_data(const Bytes& app_data) { assert(_object); _object->_app_data = app_data; }
inline std::string hexhash() const { assert(_object); return _object->_hexhash; } inline std::string hexhash() const { assert(_object); return _object->_hexhash; }
inline std::string toString() const { assert(_object); return "{Identity:" + _object->_hash.toHex() + "}"; } inline std::string toString() const { assert(_object); return "{Identity:" + _object->_hash.toHex() + "}"; }
@ -134,10 +169,14 @@ namespace RNS {
Bytes _hash; Bytes _hash;
std::string _hexhash; std::string _hexhash;
Bytes _app_data;
friend class Identity; friend class Identity;
}; };
std::shared_ptr<Object> _object; std::shared_ptr<Object> _object;
static std::map<Bytes, IdentityEntry> _known_destinations;
}; };
} }

View File

@ -403,14 +403,14 @@ bool Packet::send() {
if (Transport::outbound(*this)) { if (Transport::outbound(*this)) {
debug("Packet::send: successfully sent packet!!!"); debug("Packet::send: successfully sent packet!!!");
//zreturn self.receipt //z return self.receipt
// MOCK // MOCK
return true; return true;
} }
else { else {
error("No interfaces could process the outbound packet"); error("No interfaces could process the outbound packet");
_object->_sent = false; _object->_sent = false;
//z_receipt = None; //z _receipt = None;
return false; return false;
} }
} }
@ -432,14 +432,14 @@ bool Packet::resend() {
if (Transport::outbound(*this)) { if (Transport::outbound(*this)) {
debug("Packet::resend: successfully sent packet!!!"); debug("Packet::resend: successfully sent packet!!!");
//zreturn self.receipt //z return self.receipt
// MOCK // MOCK
return true; return true;
} }
else { else {
error("No interfaces could process the outbound packet"); error("No interfaces could process the outbound packet");
_object->_sent = false; _object->_sent = false;
//zself.receipt = None; //z self.receipt = None;
return false; return false;
} }
} }
@ -552,9 +552,9 @@ void PacketReceipt::check_timeout() {
_object->_concluded_at = Utilities::OS::time(); _object->_concluded_at = Utilities::OS::time();
if (_object->_callbacks._timeout) { if (_object->_callbacks._timeout) {
//zthread = threading.Thread(target=self.callbacks.timeout, args=(self,)) //z thread = threading.Thread(target=self.callbacks.timeout, args=(self,))
//zthread.daemon = True //z thread.daemon = True
//zthread.start(); //z thread.start();
} }
} }
} }

View File

@ -129,8 +129,27 @@ namespace RNS {
Packet(const Packet& packet) : _object(packet._object) { Packet(const Packet& packet) : _object(packet._object) {
extreme("Packet object copy created"); extreme("Packet object copy created");
} }
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(
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) {} 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(); virtual ~Packet();
inline Packet& operator = (const Packet& packet) { inline Packet& operator = (const Packet& packet) {
@ -165,7 +184,7 @@ namespace RNS {
const Bytes get_hash() const; const Bytes get_hash() const;
const Bytes getTruncatedHash() const; const Bytes getTruncatedHash() const;
const Bytes get_hashable_part() const; const Bytes get_hashable_part() const;
//zProofDestination& generate_proof_destination(); //z ProofDestination& generate_proof_destination();
// getters/setters // getters/setters
inline const Destination& destination() const { assert(_object); return _object->_destination; } inline const Destination& destination() const { assert(_object); return _object->_destination; }

View File

@ -14,11 +14,22 @@
#include <time.h> #include <time.h>
using namespace RNS; using namespace RNS;
using namespace RNS::Type::Transport;
using namespace RNS::Utilities; using namespace RNS::Utilities;
#if defined(INTERFACES_SET)
///*static*/ std::set<std::reference_wrapper<const Interface>, std::less<const Interface>> Transport::_interfaces; ///*static*/ std::set<std::reference_wrapper<const Interface>, std::less<const Interface>> Transport::_interfaces;
/*static*/ std::set<std::reference_wrapper<Interface>, std::less<Interface>> Transport::_interfaces;
#elif defined(INTERFACES_LIST)
/*static*/ std::list<std::reference_wrapper<Interface>> Transport::_interfaces; /*static*/ std::list<std::reference_wrapper<Interface>> Transport::_interfaces;
#elif defined(INTERFACES_MAP)
/*static*/ std::map<Bytes, Interface&> Transport::_interfaces;
#endif
#if defined(DESTINATIONS_SET)
/*static*/ std::set<Destination> Transport::_destinations; /*static*/ std::set<Destination> Transport::_destinations;
#elif defined(DESTINATIONS_MAP)
/*static*/ std::map<Bytes, Destination> Transport::_destinations;
#endif
/*static*/ std::set<Link> Transport::_pending_links; /*static*/ std::set<Link> Transport::_pending_links;
/*static*/ std::set<Link> Transport::_active_links; /*static*/ std::set<Link> Transport::_active_links;
/*static*/ std::set<Bytes> Transport::_packet_hashlist; /*static*/ std::set<Bytes> Transport::_packet_hashlist;
@ -31,12 +42,16 @@ using namespace RNS::Utilities;
/*static*/ std::set<HAnnounceHandler> Transport::_announce_handlers; /*static*/ std::set<HAnnounceHandler> Transport::_announce_handlers;
/*static*/ std::set<Bytes> Transport::_path_requests; /*static*/ std::set<Bytes> Transport::_path_requests;
/*static*/ std::map<Bytes, Transport::PathRequestEntry> Transport::_discovery_path_requests;
/*static*/ uint16_t Transport::_max_pr_taXgxs = 32000; /*static*/ uint16_t Transport::_max_pr_taXgxs = 32000;
/*static*/ std::set<Destination> Transport::_control_destinations; /*static*/ std::set<Destination> Transport::_control_destinations;
/*static*/ std::set<Bytes> Transport::_control_hashes; /*static*/ std::set<Bytes> Transport::_control_hashes;
/*static*/ std::set<Interface> Transport::_local_client_interfaces; ///*static*/ std::set<Interface> Transport::_local_client_interfaces;
/*static*/ std::set<std::reference_wrapper<const Interface>, std::less<const Interface>> Transport::_local_client_interfaces;
/*static*/ std::map<Bytes, const Interface&> Transport::_pending_local_path_requests;
/*static*/ uint16_t Transport::_LOCAL_CLIENT_CACHE_MAXSIZE = 512; /*static*/ uint16_t Transport::_LOCAL_CLIENT_CACHE_MAXSIZE = 512;
@ -62,15 +77,15 @@ using namespace RNS::Utilities;
_owner = reticulum_instance; _owner = reticulum_instance;
if (!_identity) { if (!_identity) {
//ztransport_identity_path = Reticulum::storagepath+"/transport_identity" //z transport_identity_path = Reticulum::storagepath+"/transport_identity"
//zif (os.path.isfile(transport_identity_path)) { //z if (os.path.isfile(transport_identity_path)) {
//z identity = Identity.from_file(transport_identity_path); //z identity = Identity.from_file(transport_identity_path);
//z} //z }
if (!_identity) { if (!_identity) {
verbose("No valid Transport Identity in storage, creating..."); verbose("No valid Transport Identity in storage, creating...");
_identity = new Identity(); _identity = new Identity();
//z_identity.to_file(transport_identity_path); //z _identity.to_file(transport_identity_path);
} }
else { else {
verbose("Loaded Transport Identity from storage"); verbose("Loaded Transport Identity from storage");
@ -714,7 +729,13 @@ using namespace RNS::Utilities;
else { else {
extreme("Transport::outbound: Path to destination is unknown"); extreme("Transport::outbound: Path to destination is unknown");
bool stored_hash = false; bool stored_hash = false;
#if defined(INTERFACES_SET)
for (const Interface& interface : _interfaces) { for (const Interface& interface : _interfaces) {
#elif defined(INTERFACES_LIST)
for (Interface& interface : _interfaces) {
#elif defined(INTERFACES_MAP)
for (auto& [hash, interface] : _interfaces) {
#endif
extreme("Transport::outbound: Checking interface " + interface.toString()); extreme("Transport::outbound: Checking interface " + interface.toString());
if (interface.OUT()) { if (interface.OUT()) {
bool should_transmit = true; bool should_transmit = true;
@ -724,9 +745,9 @@ using namespace RNS::Utilities;
should_transmit = false; should_transmit = false;
} }
// CBA Destination has no member attached_interface // CBA Destination has no member attached_interface
//zif (interface != packet.destination().attached_interface()) { //z if (interface != packet.destination().attached_interface()) {
//z should_transmit = false; //z should_transmit = false;
//z} //z }
} }
if (packet.attached_interface() && interface != packet.attached_interface()) { if (packet.attached_interface() && interface != packet.attached_interface()) {
@ -743,6 +764,7 @@ using namespace RNS::Utilities;
else if (interface.mode() == Type::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) //local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None)
//Destination local_destination({Type::NONE}); //Destination local_destination({Type::NONE});
#if defined(DESTINATIONS_SET)
bool found_local = false; bool found_local = false;
for (auto& destination : _destinations) { for (auto& destination : _destinations) {
if (destination.hash() == packet.destination_hash()) { if (destination.hash() == packet.destination_hash()) {
@ -754,6 +776,13 @@ using namespace RNS::Utilities;
//if local_destination != None: //if local_destination != None:
//if (local_destination) { //if (local_destination) {
if (found_local) { if (found_local) {
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(packet.destination_hash());
//if (iter != _destinations.end()) {
// local_destination = (*iter).second;
//}
if (iter != _destinations.end()) {
#endif
//extreme("Allowing announce broadcast on roaming-mode interface from instance-local destination"); //extreme("Allowing announce broadcast on roaming-mode interface from instance-local destination");
} }
else { else {
@ -786,6 +815,7 @@ using namespace RNS::Utilities;
// next(iterable, default) // next(iterable, default)
// list comprehension: [x for x in xyz if x in a] // list comprehension: [x for x in xyz if x in a]
// CBA TODO confirm that above pattern just selects the first matching destination // CBA TODO confirm that above pattern just selects the first matching destination
#if defined(DESTINATIONS_SET)
//Destination local_destination({Typeestination::NONE}); //Destination local_destination({Typeestination::NONE});
bool found_local = false; bool found_local = false;
for (auto& destination : _destinations) { for (auto& destination : _destinations) {
@ -798,6 +828,10 @@ using namespace RNS::Utilities;
//if local_destination != None: //if local_destination != None:
//if (local_destination) { //if (local_destination) {
if (found_local) { if (found_local) {
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(packet.destination_hash());
if (iter != _destinations.end()) {
#endif
//extreme("Allowing announce broadcast on boundary-mode interface from instance-local destination"); //extreme("Allowing announce broadcast on boundary-mode interface from instance-local destination");
} }
else { else {
@ -840,7 +874,11 @@ using namespace RNS::Utilities;
if (!queued_announces && outbound_time > interface.announce_allowed_at()) { if (!queued_announces && outbound_time > interface.announce_allowed_at()) {
uint16_t tx_time = (packet.raw().size() * 8) / interface.bitrate(); uint16_t tx_time = (packet.raw().size() * 8) / interface.bitrate();
uint16_t wait_time = (tx_time / interface.announce_cap()); uint16_t wait_time = (tx_time / interface.announce_cap());
#if defined(INTERFACES_SET)
const_cast<Interface&>(interface).announce_allowed_at(outbound_time + wait_time); const_cast<Interface&>(interface).announce_allowed_at(outbound_time + wait_time);
#else
interface.announce_allowed_at(outbound_time + wait_time);
#endif
} }
else { else {
should_transmit = false; should_transmit = false;
@ -869,13 +907,17 @@ using namespace RNS::Utilities;
); );
queued_announces = (interface.announce_queue().size() > 0); queued_announces = (interface.announce_queue().size() > 0);
#if defined(INTERFACES_SET)
const_cast<Interface&>(interface).add_announce(entry); const_cast<Interface&>(interface).add_announce(entry);
#else
interface.add_announce(entry);
#endif
if (!queued_announces) { if (!queued_announces) {
uint64_t wait_time = std::max(interface.announce_allowed_at() - OS::time(), (uint64_t)0); uint64_t wait_time = std::max(interface.announce_allowed_at() - OS::time(), (uint64_t)0);
// CBA TODO THREAD? // CBA TODO THREAD?
//ztimer = threading.Timer(wait_time, interface.process_announce_queue) //z timer = threading.Timer(wait_time, interface.process_announce_queue)
//ztimer.start() //z timer.start()
std::string wait_time_str; std::string wait_time_str;
if (wait_time < 1000) { if (wait_time < 1000) {
@ -925,12 +967,16 @@ using namespace RNS::Utilities;
// TODO: Re-evaluate potential for blocking // TODO: Re-evaluate potential for blocking
// def send_packet(): // def send_packet():
// Transport.transmit(const_cast<Interface&>(interface), packet.raw) // Transport.transmit(interface, packet.raw)
// thread = threading.Thread(target=send_packet) // thread = threading.Thread(target=send_packet)
// thread.daemon = True // thread.daemon = True
// thread.start() // thread.start()
#if defined(INTERFACES_SET)
transmit(const_cast<Interface&>(interface), packet.raw()); transmit(const_cast<Interface&>(interface), packet.raw());
#else
transmit(interface, packet.raw());
#endif
sent = true; sent = true;
} }
else { else {
@ -1197,7 +1243,7 @@ using namespace RNS::Utilities;
} }
} }
} }
//proof_for_local_client = (packet.destination_hash in Transport.reverse_table) and (Transport.reverse_table[packet.destination_hash][0] in Transport.local_client_interfaces) //p roof_for_local_client = (packet.destination_hash in Transport.reverse_table) and (Transport.reverse_table[packet.destination_hash][0] in Transport.local_client_interfaces)
bool proof_for_local_client = false; bool proof_for_local_client = false;
auto reverse_iter = _reverse_table.find(packet.destination_hash()); auto reverse_iter = _reverse_table.find(packet.destination_hash());
if (reverse_iter != _reverse_table.end()) { if (reverse_iter != _reverse_table.end()) {
@ -1214,17 +1260,27 @@ using namespace RNS::Utilities;
if (packet.destination_type() == Type::Destination::PLAIN && packet.transport_type() == Type::Transport::BROADCAST) { if (packet.destination_type() == Type::Destination::PLAIN && packet.transport_type() == Type::Transport::BROADCAST) {
// Send to all interfaces except the originator // Send to all interfaces except the originator
if (from_local_client) { if (from_local_client) {
#if defined(INTERFACES_SET)
for (const Interface& interface : _interfaces) { for (const Interface& interface : _interfaces) {
#elif defined(INTERFACES_LIST)
for (Interface& interface : _interfaces) {
#elif defined(INTERFACES_MAP)
for (auto& [hash, interface] : _interfaces) {
#endif
if (interface != packet.receiving_interface()) { if (interface != packet.receiving_interface()) {
extreme("Transport::inbound: Broadcasting packet on " + interface.toString()); extreme("Transport::inbound: Broadcasting packet on " + interface.toString());
#if defined(INTERFACES_SET)
transmit(const_cast<Interface&>(interface), packet.raw()); transmit(const_cast<Interface&>(interface), packet.raw());
#else
transmit(interface, packet.raw());
#endif
} }
} }
} }
// If the packet was not from a local client, send // If the packet was not from a local client, send
// it directly to all local clients // it directly to all local clients
else { else {
for (auto& interface : _local_client_interfaces) { for (const Interface& interface : _local_client_interfaces) {
extreme("Transport::inbound: Broadcasting packet on " + interface.toString()); extreme("Transport::inbound: Broadcasting packet on " + interface.toString());
transmit(const_cast<Interface&>(interface), packet.raw()); transmit(const_cast<Interface&>(interface), packet.raw());
} }
@ -1329,7 +1385,11 @@ using namespace RNS::Utilities;
); );
_reverse_table.insert({packet.getTruncatedHash(), reverse_entry}); _reverse_table.insert({packet.getTruncatedHash(), reverse_entry});
} }
#if defined(INTERFACES_SET)
transmit(const_cast<Interface&>(outbound_interface), new_raw); transmit(const_cast<Interface&>(outbound_interface), new_raw);
#else
transmit(outbound_interface, new_raw);
#endif
destination_entry._timestamp = OS::time(); destination_entry._timestamp = OS::time();
} }
else { else {
@ -1401,6 +1461,7 @@ using namespace RNS::Utilities;
extreme("Transport::inbound: Packet is ANNOUNCE"); extreme("Transport::inbound: Packet is ANNOUNCE");
Bytes received_from; Bytes received_from;
//p local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None) //p local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None)
#if defined(DESTINATIONS_SET)
//Destination local_destination({Type::NONE}); //Destination local_destination({Type::NONE});
bool found_local = false; bool found_local = false;
for (auto& destination : _destinations) { for (auto& destination : _destinations) {
@ -1413,6 +1474,10 @@ using namespace RNS::Utilities;
//if local_destination == None and RNS.Identity.validate_announce(packet): //if local_destination == None and RNS.Identity.validate_announce(packet):
//if (!local_destination && Identity::validate_announce(packet)) { //if (!local_destination && Identity::validate_announce(packet)) {
if (!found_local && Identity::validate_announce(packet)) { if (!found_local && Identity::validate_announce(packet)) {
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(packet.destination_hash());
if (iter == _destinations.end() && Identity::validate_announce(packet)) {
#endif
extreme("Transport::inbound: Packet is announce for non-local destination, processing..."); extreme("Transport::inbound: Packet is announce for non-local destination, processing...");
if (packet.transport_id()) { if (packet.transport_id()) {
received_from = packet.transport_id(); received_from = packet.transport_id();
@ -1427,7 +1492,7 @@ using namespace RNS::Utilities;
if ((packet.hops() - 1) == announce_entry._hops) { if ((packet.hops() - 1) == announce_entry._hops) {
debug("Heard a local rebroadcast of announce for " + packet.destination_hash().toHex()); debug("Heard a local rebroadcast of announce for " + packet.destination_hash().toHex());
announce_entry._local_rebroadcasts += 1; announce_entry._local_rebroadcasts += 1;
if (announce_entry._local_rebroadcasts >= Transport::LOCAL_REBROADCASTS_MAX) { if (announce_entry._local_rebroadcasts >= LOCAL_REBROADCASTS_MAX) {
debug("Max local rebroadcasts of announce for " + packet.destination_hash().toHex() + " reached, dropping announce from our table"); debug("Max local rebroadcasts of announce for " + packet.destination_hash().toHex() + " reached, dropping announce from our table");
_announce_table.erase(packet.destination_hash()); _announce_table.erase(packet.destination_hash());
} }
@ -1453,6 +1518,7 @@ using namespace RNS::Utilities;
// First, check that the announce is not for a destination // First, check that the announce is not for a destination
// local to this system, and that hops are less than the max // local to this system, and that hops are less than the max
//if (not any(packet.destination_hash == d.hash for d in Transport.destinations) and packet.hops < Transport.PATHFINDER_M+1): //if (not any(packet.destination_hash == d.hash for d in Transport.destinations) and packet.hops < Transport.PATHFINDER_M+1):
#if defined(DESTINATIONS_SET)
bool found_local = false; bool found_local = false;
for (auto& destination : _destinations) { for (auto& destination : _destinations) {
if (destination.hash() == packet.destination_hash()) { if (destination.hash() == packet.destination_hash()) {
@ -1460,18 +1526,24 @@ using namespace RNS::Utilities;
break; break;
} }
} }
if (!found_local && packet.hops() < (Transport::PATHFINDER_M+1)) { if (!found_local && packet.hops() < (PATHFINDER_M+1)) {
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(packet.destination_hash());
if (iter == _destinations.end() && packet.hops() < (PATHFINDER_M+1)) {
#endif
extreme("Transport::inbound: Packet is announce for non-local destination, processing..."); extreme("Transport::inbound: Packet is announce for non-local destination, processing...");
/*
uint64_t announce_emitted = Transport::announce_emitted(packet); uint64_t announce_emitted = Transport::announce_emitted(packet);
//prandom_blob = packet.data[RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8+10] //p random_blob = packet.data[RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8+10]
Bytes random_blob = packet.data().mid(Identity::KEYSIZE/8 + Identity::NAME_HASH_LENGTH/8, 10); Bytes random_blob = packet.data().mid(Type::Identity::KEYSIZE/8 + Type::Identity::NAME_HASH_LENGTH/8, 10);
//prandom_blobs = [] //p random_blobs = []
std::set<Bytes> empty_random_blobs;
std::set<Bytes>& random_blobs = empty_random_blobs;
auto iter = _destination_table.find(packet.destination_hash()); auto iter = _destination_table.find(packet.destination_hash());
if (iter != _destination_table.end()) { if (iter != _destination_table.end()) {
DestinationEntry destination_entry = (*iter).second; DestinationEntry destination_entry = (*iter).second;
//prandom_blobs = Transport.destination_table[packet.destination_hash][4] //p random_blobs = Transport.destination_table[packet.destination_hash][4]
random_blobs = destination_entry._random_blobs;
// If we already have a path to the announced // If we already have a path to the announced
// destination, but the hop count is equal or // destination, but the hop count is equal or
@ -1482,8 +1554,8 @@ using namespace RNS::Utilities;
// replayed to forge paths. // replayed to forge paths.
// TODO: Check whether this approach works // TODO: Check whether this approach works
// under all circumstances // under all circumstances
//pif not random_blob in random_blobs: //p if not random_blob in random_blobs:
if (destination_entry._random_blobs.find(random_blob) == destination_entry._random_blobs.end()) { if (random_blobs.find(random_blob) == random_blobs.end()) {
should_add = true; should_add = true;
} }
else { else {
@ -1499,9 +1571,9 @@ using namespace RNS::Utilities;
uint64_t path_expires = destination_entry._expires; uint64_t path_expires = destination_entry._expires;
uint64_t path_announce_emitted = 0; uint64_t path_announce_emitted = 0;
for (const Bytes& path_random_blob : destination_entry._random_blobs) { for (const Bytes& path_random_blob : random_blobs) {
//path_announce_emitted = std::max(path_announce_emitted, int.from_bytes(path_random_blob[5:10], "big")) //p path_announce_emitted = max(path_announce_emitted, int.from_bytes(path_random_blob[5:10], "big"))
//zpath_announce_emitted = std::max(path_announce_emitted, int.from_bytes(path_random_blob[5:10], "big")) //z path_announce_emitted = std::max(path_announce_emitted, int.from_bytes(path_random_blob[5:10], "big"));
if (path_announce_emitted >= announce_emitted) { if (path_announce_emitted >= announce_emitted) {
break; break;
} }
@ -1511,7 +1583,7 @@ using namespace RNS::Utilities;
// We also check that the announce is // We also check that the announce is
// different from ones we've already heard, // different from ones we've already heard,
// to avoid loops in the network // to avoid loops in the network
if (destination_entry._random_blobs.find(random_blob) == destination_entry._random_blobs.end()) { if (random_blobs.find(random_blob) == random_blobs.end()) {
// TODO: Check that this ^ approach actually // TODO: Check that this ^ approach actually
// works under all circumstances // works under all circumstances
debug("Replacing destination table entry for " + packet.destination_hash().toHex() + " with new announce due to expired path"); debug("Replacing destination table entry for " + packet.destination_hash().toHex() + " with new announce due to expired path");
@ -1523,7 +1595,7 @@ using namespace RNS::Utilities;
} }
else { else {
if (announce_emitted > path_announce_emitted) { if (announce_emitted > path_announce_emitted) {
if (destination_entry._random_blobs.find(random_blob) == destination_entry._random_blobs.end()) { if (random_blobs.find(random_blob) == random_blobs.end()) {
debug("Replacing destination table entry for " + packet.destination_hash().toHex() + " with new announce, since it was more recently emitted"); debug("Replacing destination table entry for " + packet.destination_hash().toHex() + " with new announce, since it was more recently emitted");
should_add = true; should_add = true;
} }
@ -1534,7 +1606,6 @@ using namespace RNS::Utilities;
} }
} }
} }
else { else {
// If this destination is unknown in our table // If this destination is unknown in our table
// we should add it // we should add it
@ -1546,7 +1617,7 @@ using namespace RNS::Utilities;
bool rate_blocked = false; bool rate_blocked = false;
/*
if packet.context != RNS.Packet.PATH_RESPONSE and packet.receiving_interface.announce_rate_target != None: if packet.context != RNS.Packet.PATH_RESPONSE and packet.receiving_interface.announce_rate_target != None:
if not packet.destination_hash in Transport.announce_rate_table: if not packet.destination_hash in Transport.announce_rate_table:
rate_entry = { "last": now, "rate_violations": 0, "blocked_until": 0, "timestamps": [now]} rate_entry = { "last": now, "rate_violations": 0, "blocked_until": 0, "timestamps": [now]}
@ -1579,7 +1650,7 @@ using namespace RNS::Utilities;
else: else:
rate_blocked = True rate_blocked = True
*/
uint8_t retries = 0; uint8_t retries = 0;
uint8_t announce_hops = packet.hops(); uint8_t announce_hops = packet.hops();
@ -1587,36 +1658,35 @@ using namespace RNS::Utilities;
bool block_rebroadcasts = false; bool block_rebroadcasts = false;
Interface attached_interface = {Type::NONE}; Interface attached_interface = {Type::NONE};
uint64_t retransmit_timeout = now + (RNS::Cryptography::random() * Transport::PATHFINDER_RW); uint64_t retransmit_timeout = now + (RNS::Cryptography::random() * PATHFINDER_RW);
uint64_t expires; uint64_t expires;
if (packet.receiving_interface().mode() == Type::Interface::MODE_ACCESS_POINT) { if (packet.receiving_interface().mode() == Type::Interface::MODE_ACCESS_POINT) {
expires = now + Transport::AP_PATH_TIME; expires = now + AP_PATH_TIME;
} }
else if (packet.receiving_interface().mode() == Type::Interface::MODE_ROAMING) { else if (packet.receiving_interface().mode() == Type::Interface::MODE_ROAMING) {
expires = now + Transport::ROAMING_PATH_TIME; expires = now + ROAMING_PATH_TIME;
} }
else { else {
expires = now + Transport::PATHFINDER_E; expires = now + PATHFINDER_E;
} }
std::set<Bytes> random_blobs;
random_blobs.insert(random_blob); random_blobs.insert(random_blob);
if (Reticulum::transport_enabled() || from_local_client(packet) && packet.context() != Type::Packet::PATH_RESPONSE) { if ((Reticulum::transport_enabled() || Transport::from_local_client(packet)) && packet.context() != Type::Packet::PATH_RESPONSE) {
// Insert announce into announce table for retransmission // Insert announce into announce table for retransmission
if (rate_blocked) { if (rate_blocked) {
debug("Blocking rebroadcast of announce from " + packet.destination_hash().toHex() + " due to excessive announce rate"); debug("Blocking rebroadcast of announce from " + packet.destination_hash().toHex() + " due to excessive announce rate");
} }
else { else {
if (from_local_client(packet)) { if (Transport::from_local_client(packet)) {
// If the announce is from a local client, // If the announce is from a local client,
// it is announced immediately, but only one time. // it is announced immediately, but only one time.
retransmit_timeout = now; retransmit_timeout = now;
retries = Transport::PATHFINDER_R; retries = PATHFINDER_R;
} }
_announce_table[packet.destination_hash] = [ AnnounceEntry announce_entry(
now, now,
retransmit_timeout, retransmit_timeout,
retries, retries,
@ -1626,23 +1696,24 @@ using namespace RNS::Utilities;
local_rebroadcasts, local_rebroadcasts,
block_rebroadcasts, block_rebroadcasts,
attached_interface attached_interface
]; );
_announce_table.insert({packet.destination_hash(), announce_entry});
} }
} }
// TODO: Check from_local_client once and store result // TODO: Check from_local_client once and store result
else if (from_local_client(packet) && packet.context() == Type::Packet::PATH_RESPONSE) { else if (Transport::from_local_client(packet) && packet.context() == Type::Packet::PATH_RESPONSE) {
// If this is a path response from a local client, // If this is a path response from a local client,
// check if any external interfaces have pending // check if any external interfaces have pending
// path requests. // path requests.
//pif packet.destination_hash in Transport.pending_local_path_requests: //p if packet.destination_hash in Transport.pending_local_path_requests:
auto iter = pending_local_path_requests.find(packet.destination_hash()); auto iter = _pending_local_path_requests.find(packet.destination_hash());
if (iter != _destination_table.end()) { if (iter != _pending_local_path_requests.end()) {
DestinationEntry destination_entry = (*iter).second; //p desiring_interface = Transport.pending_local_path_requests.pop(packet.destination_hash)
desiring_interface = _pending_local_path_requests.pop(packet.destination_hash()); //const Interface& desiring_interface = (*iter).second;
retransmit_timeout = now; retransmit_timeout = now;
retries = Transport::PATHFINDER_R; retries = PATHFINDER_R;
Transport.announce_table[packet.destination_hash] = [ AnnounceEntry announce_entry(
now, now,
retransmit_timeout, retransmit_timeout,
retries, retries,
@ -1652,50 +1723,53 @@ using namespace RNS::Utilities;
local_rebroadcasts, local_rebroadcasts,
block_rebroadcasts, block_rebroadcasts,
attached_interface attached_interface
]; );
_announce_table.insert({packet.destination_hash(), announce_entry});
}
}
// If we have any local clients connected, we re- // If we have any local clients connected, we re-
// transmit the announce to them immediately // transmit the announce to them immediately
if (_local_client_interfaces.size() > 0) { if (_local_client_interfaces.size() > 0) {
announce_identity = Identity::recall(packet.destination_hash()); Identity announce_identity(Identity::recall(packet.destination_hash()));
announce_destination = Destination(announce_identity, Destination.OUT, Destination.SINGLE, "unknown", "unknown"); Destination announce_destination(announce_identity, Type::Destination::OUT, Type::Destination::SINGLE, "unknown", "unknown");
announce_destination.hash(packet.destination_hash()); announce_destination.hash(packet.destination_hash());
announce_destination.hexhash = announce_destination.hash().toHex(); //announce_destination.hexhash(announce_destination.hash().toHex());
announce_context = {Type::NONE}; Type::Packet::context_types announce_context = Type::Packet::CONTEXT_NONE;
announce_data = packet.data(); Bytes announce_data = packet.data();
// TODO: Shouldn't the context be PATH_RESPONSE in the first case here? // TODO: Shouldn't the context be PATH_RESPONSE in the first case here?
if (from_local_client(packet) && packet.context() == Packet.PATH_RESPONSE) { if (Transport::from_local_client(packet) && packet.context() == Type::Packet::PATH_RESPONSE) {
for (auto& local_interface : _local_client_interfaces) { for (const Interface& local_interface : _local_client_interfaces) {
if packet.receiving_interface() != local_interface) { if (packet.receiving_interface() != local_interface) {
Packet new_announce( Packet new_announce(
announce_destination, announce_destination,
local_interface,
announce_data, announce_data,
Type::Packet::ANNOUNCE, Type::Packet::ANNOUNCE,
context = announce_context, announce_context,
header_type = RNS.Packet.HEADER_2, Type::Transport::TRANSPORT,
transport_type = Transport.TRANSPORT, Type::Packet::HEADER_2,
transport_id = Transport.identity.hash, _identity.hash()
attached_interface = local_interface
); );
new_announce.hops(packet.hops); new_announce.hops(packet.hops());
new_announce.send(); new_announce.send();
} }
} }
} }
else { else {
for (auto& local_interface : _local_client_interfaces) { for (const Interface& local_interface : _local_client_interfaces) {
if (packet.receiving_interface() != local_interface) { if (packet.receiving_interface() != local_interface) {
Packet new_announce( Packet new_announce(
announce_destination, announce_destination,
local_interface,
announce_data, announce_data,
Type::Packet::ANNOUNCE, Type::Packet::ANNOUNCE,
context = announce_context, announce_context,
header_type = RNS.Packet.HEADER_2, Type::Transport::TRANSPORT,
transport_type = Transport.TRANSPORT, Type::Packet::HEADER_2,
transport_id = Transport.identity.hash, _identity.hash()
attached_interface = local_interface
); );
new_announce.hops(packet.hops()); new_announce.hops(packet.hops());
@ -1710,28 +1784,26 @@ using namespace RNS::Utilities;
// interface immediately // interface immediately
auto iter = _discovery_path_requests.find(packet.destination_hash()); auto iter = _discovery_path_requests.find(packet.destination_hash());
if (iter != _discovery_path_requests.end()) { if (iter != _discovery_path_requests.end()) {
PathRequestEntry pr_entry = (*iter).second; PathRequestEntry& pr_entry = (*iter).second;
attached_interface = pr_entry._requesting_interface; attached_interface = pr_entry._requesting_interface;
interface_str = " on " + attached_interface.toString(); debug("Got matching announce, answering waiting discovery path request for " + packet.destination_hash().toHex() + " on " + attached_interface.toString());
Identity announce_identity(Identity::recall(packet.destination_hash()));
debug("Got matching announce, answering waiting discovery path request for " + packet.destination_hash().toHex() + interface_str); Destination announce_destination(announce_identity, Type::Destination::OUT, Type::Destination::SINGLE, "unknown", "unknown");
announce_identity = Identity::recall(packet.destination_hash());
Destination announce_destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown");
announce_destination.hash(packet.destination_hash()); announce_destination.hash(packet.destination_hash());
announce_destination.hexhash = announce_destination.hash().toHex(); //announce_destination.hexhash(announce_destination.hash().toHex());
announce_context = {Type::NONE}; Type::Packet::context_types announce_context = Type::Packet::CONTEXT_NONE;
announce_data = packet.data(); Bytes announce_data = packet.data();
Packet new_announce( Packet new_announce(
announce_destination, announce_destination,
attached_interface,
announce_data, announce_data,
Type::Packet::ANNOUNCE, Type::Packet::ANNOUNCE,
context = Type::Packet::PATH_RESPONSE, Type::Packet::PATH_RESPONSE,
header_type = Type::Packet::HEADER_2, Type::Transport::TRANSPORT,
transport_type = Type::Transport::TRANSPORT, Type::Packet::HEADER_2,
transport_id = _identity.hash(), _identity.hash()
attached_interface = attached_interface
); );
new_announce.hops(packet.hops()); new_announce.hops(packet.hops());
@ -1744,59 +1816,62 @@ using namespace RNS::Utilities;
announce_hops, announce_hops,
expires, expires,
random_blobs, random_blobs,
packet.receiving_interface(), //packet.receiving_interface(),
const_cast<Interface&>(packet.receiving_interface()),
packet packet
); );
_destination_table.insert({packet.destination_hash(), destination_table_entry}); _destination_table.insert({packet.destination_hash(), destination_table_entry});
debug("Destination " + packet.destination_hash().toHex() + " is now " + std::to_string(announce_hops) + " hops away via " + received_from.toHex() + " on " + packet.receiving_interface().toString()); debug("Destination " + packet.destination_hash().toHex() + " is now " + std::to_string(announce_hops) + " hops away via " + received_from.toHex() + " on " + packet.receiving_interface().toString());
/*
// If the receiving interface is a tunnel, we add the // If the receiving interface is a tunnel, we add the
// announce to the tunnels table // announce to the tunnels table
if (packet.receiving_interface().tunnel_id()) { if (packet.receiving_interface().tunnel_id()) {
tunnel_entry = Transport.tunnels[packet.receiving_interface.tunnel_id]; tunnel_entry = Transport.tunnels[packet.receiving_interface.tunnel_id];
paths = tunnel_entry[2] paths = tunnel_entry[2];
paths[packet.destination_hash] = destination_table_entry paths[packet.destination_hash] = destination_table_entry;
expires = OS::time() + Transport::DESTINATION_TIMEOUT; expires = OS::time() + Transport::DESTINATION_TIMEOUT;
tunnel_entry[3] = expires tunnel_entry[3] = expires;
debug("Path to " + packet.destination_hash().toHex() + " associated with tunnel " + packet.receiving_interface().tunnel_id().toHex()); debug("Path to " + packet.destination_hash().toHex() + " associated with tunnel " + packet.receiving_interface().tunnel_id().toHex());
} }
*/
// Call externally registered callbacks from apps // Call externally registered callbacks from apps
// wanting to know when an announce arrives // wanting to know when an announce arrives
if (packet.context() != Type::Packet::PATH_RESPONSE) { if (packet.context() != Type::Packet::PATH_RESPONSE) {
for (auto& handler : Transport.announce_handlers) { for (auto& handler : _announce_handlers) {
try { try {
// Check that the announced destination matches // Check that the announced destination matches
// the handlers aspect filter // the handlers aspect filter
execute_callback = false; bool execute_callback = false;
announce_identity = Identity::recall(packet.destination_hash()); Identity announce_identity(Identity::recall(packet.destination_hash()));
if (handler.aspect_filter == None) { if (handler->aspect_filter().empty()) {
// If the handlers aspect filter is set to // If the handlers aspect filter is set to
// None, we execute the callback in all cases // None, we execute the callback in all cases
execute_callback = true; execute_callback = true;
} }
else { else {
handler_expected_hash = RNS.Destination.hash_from_name_and_identity(handler.aspect_filter, announce_identity) Bytes handler_expected_hash = Destination::hash_from_name_and_identity(handler->aspect_filter().c_str(), announce_identity);
if (packet.destination_hash() == handler_expected_hash() ) { if (packet.destination_hash() == handler_expected_hash) {
execute_callback = true; execute_callback = true;
} }
} }
if (execute_callback) { if (execute_callback) {
handler.received_announce( handler->received_announce(
destination_hash=packet.destination_hash(), packet.destination_hash(),
announced_identity=announce_identity, announce_identity,
app_data=Identity::recall_app_data(packet.destination_hash()) Identity::recall_app_data(packet.destination_hash())
); );
} }
} }
catch (std::exception& e) { catch (std::exception& e) {
error("Error while processing external announce callback."); error("Error while processing external announce callback.");
error("The contained exception was: " + e.what(); error("The contained exception was: " + std::string(e.what()));
} }
} }
} }
} }
*/
} }
else { else {
extreme("Transport::inbound: Packet is announce for local destination, not processing"); extreme("Transport::inbound: Packet is announce for local destination, not processing");
@ -1811,12 +1886,23 @@ using namespace RNS::Utilities;
else if (packet.packet_type() == Type::Packet::LINKREQUEST) { else if (packet.packet_type() == Type::Packet::LINKREQUEST) {
extreme("Transport::inbound: Packet is LINKREQUEST"); extreme("Transport::inbound: Packet is LINKREQUEST");
if (!packet.transport_id() || packet.transport_id() == _identity.hash()) { if (!packet.transport_id() || packet.transport_id() == _identity.hash()) {
#if defined(DESTINATIONS_SET)
for (auto& destination : _destinations) { for (auto& destination : _destinations) {
if (destination.hash() == packet.destination_hash() && destination.type() == packet.destination_type()) { if (destination.hash() == packet.destination_hash() && destination.type() == packet.destination_type()) {
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(packet.destination_hash());
if (iter != _destinations.end()) {
auto& destination = (*iter).second;
if (destination.type() == packet.destination_type()) {
#endif
packet.destination(destination); packet.destination(destination);
// CBA iterator over std::set is always const so need to make temporarily mutable // CBA iterator over std::set is always const so need to make temporarily mutable
//destination.receive(packet); //destination.receive(packet);
#if defined(DESTINATIONS_SET)
const_cast<Destination&>(destination).receive(packet); const_cast<Destination&>(destination).receive(packet);
#else
destination.receive(packet);
#endif
} }
} }
} }
@ -1834,10 +1920,21 @@ using namespace RNS::Utilities;
} }
} }
else { else {
#if defined(DESTINATIONS_SET)
for (auto& destination : _destinations) { for (auto& destination : _destinations) {
if (destination.hash() == packet.destination_hash() && destination.type() == packet.destination_type()) { if (destination.hash() == packet.destination_hash() && destination.type() == packet.destination_type()) {
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(packet.destination_hash());
if (iter != _destinations.end()) {
auto& destination = (*iter).second;
if (destination.type() == packet.destination_type()) {
#endif
packet.destination(destination); packet.destination(destination);
#if defined(DESTINATIONS_SET)
const_cast<Destination&>(destination).receive(packet); const_cast<Destination&>(destination).receive(packet);
#else
destination.receive(packet);
#endif
if (destination.proof_strategy() == Type::Destination::PROVE_ALL) { if (destination.proof_strategy() == Type::Destination::PROVE_ALL) {
packet.prove(); packet.prove();
@ -2057,39 +2154,71 @@ using namespace RNS::Utilities;
/*static*/ void Transport::register_interface(Interface& interface) { /*static*/ void Transport::register_interface(Interface& interface) {
extreme("Transport: Registering interface " + interface.toString()); extreme("Transport: Registering interface " + interface.toString());
#if defined(INTERFACES_SET)
_interfaces.insert(interface);
#elif defined(INTERFACES_LIST)
_interfaces.push_back(interface); _interfaces.push_back(interface);
extreme("Transport: Listing all registered interfaces..."); #elif defined(INTERFACES_MAP)
for (Interface& found_interface : _interfaces) { _interfaces.insert({interface.get_hash(), interface});
extreme("Transport: Found interface " + found_interface.toString()); #endif
}
// CBA TODO set or add transport as listener on interface to receive incoming packets // CBA TODO set or add transport as listener on interface to receive incoming packets
} }
/*static*/ void Transport::deregister_interface(const Interface& interface) { /*static*/ void Transport::deregister_interface(const Interface& interface) {
extreme("Transport: Deregistering interface " + interface.toString()); extreme("Transport: Deregistering interface " + interface.toString());
//if (_interfaces.find(interface) != _interfaces.end()) { #if defined(INTERFACES_SET)
// _interfaces.erase(interface); //for (auto iter = _interfaces.begin(); iter != _interfaces.end(); ++iter) {
// if ((*iter).get() == interface) {
// _interfaces.erase(iter);
// extreme("Transport::deregister_interface: Found and removed interface " + (*iter).get().toString());
// break;
// }
//} //}
//auto iter = _interfaces.find(interface);
auto iter = _interfaces.find(const_cast<Interface&>(interface));
if (iter != _interfaces.end()) {
_interfaces.erase(iter);
extreme("Transport::deregister_interface: Found and removed interface " + (*iter).get().toString());
}
#elif defined(INTERFACES_LIST)
for (auto iter = _interfaces.begin(); iter != _interfaces.end(); ++iter) { for (auto iter = _interfaces.begin(); iter != _interfaces.end(); ++iter) {
if ((*iter).get() == interface) { if ((*iter).get() == interface) {
_interfaces.erase(iter); _interfaces.erase(iter);
extreme("Transport::deregister_interface: Found and removed interface " + (*iter).get().toString());
break; break;
} }
} }
#elif defined(INTERFACES_MAP)
auto iter = _interfaces.find(interface.get_hash());
if (iter != _interfaces.end()) {
extreme("Transport::deregister_interface: Found and removing interface " + (*iter).second.toString());
_interfaces.erase(iter);
}
#endif
} }
/*static*/ void Transport::register_destination(Destination& destination) { /*static*/ void Transport::register_destination(Destination& destination) {
extreme("Transport: Registering destination " + destination.toString()); extreme("Transport: Registering destination " + destination.toString());
destination.mtu(Type::Reticulum::MTU); destination.mtu(Type::Reticulum::MTU);
if (destination.direction() == Type::Destination::IN) { if (destination.direction() == Type::Destination::IN) {
#if defined(DESTINATIONS_SET)
for (auto& registered_destination : _destinations) { for (auto& registered_destination : _destinations) {
if (destination.hash() == registered_destination.hash()) { if (destination.hash() == registered_destination.hash()) {
//raise KeyError("Attempt to register an already registered destination.") //raise KeyError("Attempt to register an already registered destination.")
throw std::runtime_error("Attempt to register an already registered destination."); throw std::runtime_error("Attempt to register an already registered destination.");
} }
} }
_destinations.insert(destination); _destinations.insert(destination);
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(destination.hash());
if (iter != _destinations.end()) {
//raise KeyError("Attempt to register an already registered destination.")
throw std::runtime_error("Attempt to register an already registered destination.");
}
_destinations.insert({destination.hash(), destination});
#endif
if (_owner.is_connected_to_shared_instance()) { if (_owner.is_connected_to_shared_instance()) {
if (destination.type() == Type::Destination::SINGLE) { if (destination.type() == Type::Destination::SINGLE) {
@ -2101,9 +2230,16 @@ using namespace RNS::Utilities;
/*static*/ void Transport::deregister_destination(const Destination& destination) { /*static*/ void Transport::deregister_destination(const Destination& destination) {
extreme("Transport: Deregistering destination " + destination.toString()); extreme("Transport: Deregistering destination " + destination.toString());
#if defined(DESTINATIONS_SET)
if (_destinations.find(destination) != _destinations.end()) { if (_destinations.find(destination) != _destinations.end()) {
_destinations.erase(destination); _destinations.erase(destination);
} }
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(destination.hash());
if (iter != _destinations.end()) {
_destinations.erase(iter);
}
#endif
} }
/*static*/ void Transport::register_link(const Link& link) { /*static*/ void Transport::register_link(const Link& link) {
@ -2141,10 +2277,8 @@ Registers an announce handler.
:param handler: Must be an object with an *aspect_filter* attribute and a *received_announce(destination_hash, announced_identity, app_data)* callable. See the :ref:`Announce Example<example-announce>` for more info. :param handler: Must be an object with an *aspect_filter* attribute and a *received_announce(destination_hash, announced_identity, app_data)* callable. See the :ref:`Announce Example<example-announce>` for more info.
*/ */
/*static*/ void Transport::register_announce_handler(HAnnounceHandler handler) { /*static*/ void Transport::register_announce_handler(HAnnounceHandler handler) {
extreme("Transport: Transport::register_announce_handler()"); extreme("Transport: Registering announce handler " + handler->aspect_filter());
//if hasattr(handler, "received_announce") and callable(handler.received_announce): _announce_handlers.insert(handler);
//if hasattr(handler, "aspect_filter"):
_announce_handlers.insert(handler);
} }
/* /*
@ -2153,18 +2287,32 @@ Deregisters an announce handler.
:param handler: The announce handler to be deregistered. :param handler: The announce handler to be deregistered.
*/ */
/*static*/ void Transport::deregister_announce_handler(HAnnounceHandler handler) { /*static*/ void Transport::deregister_announce_handler(HAnnounceHandler handler) {
extreme("Transport: Transport::deregister_announce_handler()"); extreme("Transport: Deregistering announce handler " + handler->aspect_filter());
if (_announce_handlers.find(handler) != _announce_handlers.end()) { if (_announce_handlers.find(handler) != _announce_handlers.end()) {
_announce_handlers.erase(handler); _announce_handlers.erase(handler);
extreme("Transport::deregister_announce_handler: Found and removed handler" + handler->aspect_filter());
} }
} }
/*static*/ Interface Transport::find_interface_from_hash(const Bytes& interface_hash) { /*static*/ Interface Transport::find_interface_from_hash(const Bytes& interface_hash) {
#if defined(INTERFACES_SET)
for (const Interface& interface : _interfaces) { for (const Interface& interface : _interfaces) {
if (interface.get_hash() == interface_hash) { if (interface.get_hash() == interface_hash) {
return interface; return interface;
} }
} }
#elif defined(INTERFACES_LIST)
for (Interface& interface : _interfaces) {
if (interface.get_hash() == interface_hash) {
return interface;
}
}
#elif defined(INTERFACES_MAP)
auto iter = _interfaces.find(interface_hash);
if (iter != _interfaces.end()) {
return (*iter).second;
}
#endif
return {Type::NONE}; return {Type::NONE};
} }
@ -2299,7 +2447,7 @@ Deregisters an announce handler.
return destination_entry._hops; return destination_entry._hops;
} }
else { else {
return Transport::PATHFINDER_M; return PATHFINDER_M;
} }
} }
@ -2479,6 +2627,7 @@ will announce it.
Transport.pending_local_path_requests[destination_hash] = attached_interface Transport.pending_local_path_requests[destination_hash] = attached_interface
//local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None) //local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None)
#if defined(DESTINATIONS_SET)
Destination local_destination({Type::NONE}); Destination local_destination({Type::NONE});
for (auto& destination : _destinations) { for (auto& destination : _destinations) {
if (destination.hash() == destination_hash) { if (destination.hash() == destination_hash) {
@ -2488,11 +2637,15 @@ will announce it.
} }
//if local_destination != None: //if local_destination != None:
if (local_destination) { if (local_destination) {
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(destination_hash);
if (iter != _destinations.end()) {
auto& local_destination = (*iter).second;
#endif
local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface); local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface);
debug("Answering path request for " + destination_hash.toHex() + interface_str + ", destination is local to this system"); debug("Answering path request for " + destination_hash.toHex() + interface_str + ", destination is local to this system");
} }
else if ((RNS.Reticulum.transport_enabled() || is_from_local_client) && destination_table.find(destination_hash) != _destination_table.ends()) {
elif (RNS.Reticulum.transport_enabled() or is_from_local_client) and (destination_hash in Transport.destination_table):
packet = Transport.destination_table[destination_hash][6] packet = Transport.destination_table[destination_hash][6]
next_hop = Transport.destination_table[destination_hash][1] next_hop = Transport.destination_table[destination_hash][1]
received_from = Transport.destination_table[destination_hash][5] received_from = Transport.destination_table[destination_hash][5]
@ -2892,3 +3045,20 @@ will announce it.
persist_data(); persist_data();
} }
} }
/*static*/ Destination Transport::find_destination_from_hash(const Bytes& destination_hash) {
#if defined(DESTINATIONS_SET)
for (const Destination& destination : _destinations) {
if (destination.get_hash() == destination_hash) {
return destination;
}
}
#elif defined(DESTINATIONS_MAP)
auto iter = _destinations.find(destination_hash);
if (iter != _destinations.end()) {
return (*iter).second;
}
#endif
return {Type::NONE};
}

View File

@ -11,6 +11,13 @@
#include <functional> #include <functional>
#include <stdint.h> #include <stdint.h>
//#define INTERFACES_SET
//#define INTERFACES_LIST
#define INTERFACES_MAP
//#define DESTINATIONS_SET
#define DESTINATIONS_MAP
namespace RNS { namespace RNS {
class Reticulum; class Reticulum;
@ -23,10 +30,18 @@ namespace RNS {
class AnnounceHandler { class AnnounceHandler {
public: public:
AnnounceHandler(const std::string& aspect_filter) { // The initialisation method takes the optional
_aspect_filter = aspect_filter; // aspect_filter argument. If aspect_filter is set to
} // None, all announces will be passed to the instance.
// If only some announces are wanted, it can be set to
// an aspect string.
AnnounceHandler(const char* aspect_filter) { _aspect_filter = aspect_filter; }
// This method will be called by Reticulums Transport
// system when an announce arrives that matches the
// configured aspect filter. Filters must be specific,
// and cannot use wildcards.
virtual void received_announce(const Bytes& destination_hash, const Identity& announced_identity, const Bytes& app_data) = 0; virtual void received_announce(const Bytes& destination_hash, const Identity& announced_identity, const Bytes& app_data) = 0;
std::string& aspect_filter() { return _aspect_filter; }
private: private:
std::string _aspect_filter; std::string _aspect_filter;
}; };
@ -39,9 +54,11 @@ namespace RNS {
class Transport { class Transport {
private: private:
// CBA TODO Analyze safety of using Inrerface references here
// CBA TODO Analyze safety of using Packet references here
class DestinationEntry { class DestinationEntry {
public: public:
DestinationEntry(uint64_t time, Bytes received_from, uint8_t announce_hops, uint64_t expires, std::set<Bytes> random_blobs, Interface& receiving_interface, const Packet& packet) : DestinationEntry(uint64_t time, const Bytes& received_from, uint8_t announce_hops, uint64_t expires, const std::set<Bytes>& random_blobs, Interface& receiving_interface, const Packet& packet) :
_timestamp(time), _timestamp(time),
_received_from(received_from), _received_from(received_from),
_hops(announce_hops), _hops(announce_hops),
@ -61,9 +78,11 @@ namespace RNS {
const Packet& _packet; const Packet& _packet;
}; };
// CBA TODO Analyze safety of using Inrerface references here
// CBA TODO Analyze safety of using Packet references here
class AnnounceEntry { class AnnounceEntry {
public: public:
AnnounceEntry(uint64_t timestamp, uint16_t retransmit_timeout, uint8_t retries, Bytes received_from, uint8_t hops, const Packet& packet, uint8_t local_rebroadcasts, bool block_rebroadcasts, const Interface& attached_interface) : AnnounceEntry(uint64_t timestamp, uint16_t retransmit_timeout, uint8_t retries, const Bytes& received_from, uint8_t hops, const Packet& packet, uint8_t local_rebroadcasts, bool block_rebroadcasts, const Interface& attached_interface) :
_timestamp(timestamp), _timestamp(timestamp),
_retransmit_timeout(retransmit_timeout), _retransmit_timeout(retransmit_timeout),
_retries(retries), _retries(retries),
@ -87,9 +106,10 @@ namespace RNS {
const Interface& _attached_interface; const Interface& _attached_interface;
}; };
// CBA TODO Analyze safety of using Inrerface references here
class LinkEntry { class LinkEntry {
public: public:
LinkEntry(uint64_t timestamp, const Bytes& next_hop, const Interface& outbound_interface, uint8_t remaining_hops, const Interface& receiving_interface, uint8_t hops, const Bytes& destination_hash, bool validated, uint64_t proof_timeout) : LinkEntry(uint64_t timestamp, const Bytes& next_hop, const Interface& outbound_interface, uint8_t remaining_hops, const Interface& receiving_interface, uint8_t hops, const Bytes& destination_hash, bool validated, uint64_t proof_timeout) :
_timestamp(timestamp), _timestamp(timestamp),
_next_hop(next_hop), _next_hop(next_hop),
_outbound_interface(outbound_interface), _outbound_interface(outbound_interface),
@ -113,9 +133,10 @@ namespace RNS {
uint64_t _proof_timeout = 0; uint64_t _proof_timeout = 0;
}; };
// CBA TODO Analyze safety of using Inrerface references here
class ReverseEntry { class ReverseEntry {
public: public:
ReverseEntry(const Interface& receiving_interface, const Interface& outbound_interface, uint64_t timestamp) : ReverseEntry(const Interface& receiving_interface, const Interface& outbound_interface, uint64_t timestamp) :
_receiving_interface(receiving_interface), _receiving_interface(receiving_interface),
_outbound_interface(outbound_interface), _outbound_interface(outbound_interface),
_timestamp(timestamp) _timestamp(timestamp)
@ -127,50 +148,20 @@ namespace RNS {
uint64_t _timestamp = 0; uint64_t _timestamp = 0;
}; };
public: // CBA TODO Analyze safety of using Inrerface references here
// Constants class PathRequestEntry {
/* public:
enum types { PathRequestEntry(const Bytes& destination_hash, uint64_t timeout, const Interface& requesting_interface) :
BROADCAST = 0x00, _destination_hash(destination_hash),
TRANSPORT = 0x01, _timeout(timeout),
RELAY = 0x02, _requesting_interface(requesting_interface)
TUNNEL = 0x03, {
NONE = 0xFF, }
public:
Bytes _destination_hash;
uint64_t _timeout = 0;
const Interface& _requesting_interface;
}; };
*/
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 = 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
static const uint8_t MAX_RATE_TIMESTAMPS = 16; // Maximum number of announce timestamps to keep per destination
public: public:
static void start(const Reticulum& reticulum_instance); static void start(const Reticulum& reticulum_instance);
@ -223,12 +214,26 @@ namespace RNS {
static void persist_data(); static void persist_data();
static void exit_handler(); static void exit_handler();
static Destination find_destination_from_hash(const Bytes& destination_hash);
private: private:
// CBA MUST use references to interfaces here in order for virtul overrides for send/receive to work // CBA MUST use references to interfaces here in order for virtul overrides for send/receive to work
#if defined(INTERFACES_SET)
// set sorted, can use find
//static std::set<std::reference_wrapper<const Interface>, std::less<const Interface>> _interfaces; // All active interfaces //static std::set<std::reference_wrapper<const Interface>, std::less<const Interface>> _interfaces; // All active interfaces
static std::set<std::reference_wrapper<Interface>, std::less<Interface>> _interfaces; // All active interfaces
#elif defined(INTERFACES_LIST)
// list is unsorted, can't use find
static std::list<std::reference_wrapper<Interface>> _interfaces; // All active interfaces static std::list<std::reference_wrapper<Interface>> _interfaces; // All active interfaces
#elif defined(INTERFACES_MAP)
// map is sorted, can use find
static std::map<Bytes, Interface&> _interfaces; // All active interfaces
#endif
#if defined(DESTINATIONS_SET)
static std::set<Destination> _destinations; // All active destinations static std::set<Destination> _destinations; // All active destinations
//static std::map<Bytes, Destination> _destinations; // All active destinations #elif defined(DESTINATIONS_MAP)
static std::map<Bytes, Destination> _destinations; // All active destinations
#endif
static std::set<Link> _pending_links; // Links that are being established static std::set<Link> _pending_links; // Links that are being established
static std::set<Link> _active_links; // Links that are active static std::set<Link> _active_links; // Links that are active
static std::set<Bytes> _packet_hashlist; // A list of packet hashes for duplicate detection static std::set<Bytes> _packet_hashlist; // A list of packet hashes for duplicate detection
@ -244,12 +249,12 @@ namespace RNS {
static std::map<Bytes, LinkEntry> _link_table; // A lookup table containing hops for links static std::map<Bytes, LinkEntry> _link_table; // A lookup table containing hops for links
static std::map<Bytes, AnnounceEntry> _held_announces; // A table containing temporarily held announce-table entries static std::map<Bytes, AnnounceEntry> _held_announces; // A table containing temporarily held announce-table entries
static std::set<HAnnounceHandler> _announce_handlers; // A table storing externally registered announce handlers static std::set<HAnnounceHandler> _announce_handlers; // A table storing externally registered announce handlers
//z_tunnels = {} // A table storing tunnels to other transport instances //z _tunnels = {} // A table storing tunnels to other transport instances
//z_announce_rate_table = {} // A table for keeping track of announce rates //z _announce_rate_table = {} // A table for keeping track of announce rates
static std::set<Bytes> _path_requests; // A table for storing path request timestamps static std::set<Bytes> _path_requests; // A table for storing path request timestamps
//z_discovery_path_requests = {} // A table for keeping track of path requests on behalf of other nodes static std::map<Bytes, PathRequestEntry> _discovery_path_requests; // A table for keeping track of path requests on behalf of other nodes
//z_discovery_pr_tags = [] // A table for keeping track of tagged path requests //z _discovery_pr_tags = [] // A table for keeping track of tagged path requests
static uint16_t _max_pr_taXgxs; // Maximum amount of unique path request tags to remember static uint16_t _max_pr_taXgxs; // Maximum amount of unique path request tags to remember
// Transport control destinations are used // Transport control destinations are used
@ -260,14 +265,15 @@ namespace RNS {
// Interfaces for communicating with // Interfaces for communicating with
// local clients connected to a shared // local clients connected to a shared
// Reticulum instance // Reticulum instance
static std::set<Interface> _local_client_interfaces; //static std::set<Interface> _local_client_interfaces;
static std::set<std::reference_wrapper<const Interface>, std::less<const Interface>> _local_client_interfaces;
//z_local_client_rssi_cache = [] static std::map<Bytes, const Interface&> _pending_local_path_requests;
//z_local_client_snr_cache = []
//z _local_client_rssi_cache = []
//z _local_client_snr_cache = []
static uint16_t _LOCAL_CLIENT_CACHE_MAXSIZE; static uint16_t _LOCAL_CLIENT_CACHE_MAXSIZE;
std::map<Bytes, Interface> _pending_local_path_requests;
static uint64_t _start_time; static uint64_t _start_time;
static bool _jobs_locked; static bool _jobs_locked;
static bool _jobs_running; static bool _jobs_running;

View File

@ -65,7 +65,7 @@ namespace RNS { namespace Type {
static const uint16_t HEADER_MINSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*1; // In bytes 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 HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH/8)*2; // In bytes
static const uint16_t IFAC_MIN_SIZE = 1; static const uint16_t IFAC_MIN_SIZE = 1;
//zIFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8") //z IFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8")
static const uint16_t MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE; static const uint16_t MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE;

View File

@ -115,16 +115,34 @@ public:
name("(deleted)"); name("(deleted)");
} }
virtual void processIncoming(const RNS::Bytes& data) { virtual void processIncoming(const RNS::Bytes& data) {
RNS::head("TestInInterface.processIncoming: data: " + data.toHex(), RNS::LOG_EXTREME); RNS::head("TestInInterface.processIncoming: data: " + data.toHex(), RNS::LOG_INFO);
RNS::Interface::processIncoming(data); RNS::Interface::processIncoming(data);
} }
virtual inline std::string toString() const { return "TestInInterface[" + name() + "]"; } virtual inline std::string toString() const { return "TestInInterface[" + name() + "]"; }
}; };
// Test AnnounceHandler
class ExampleAnnounceHandler : public RNS::AnnounceHandler {
public:
ExampleAnnounceHandler(const char* aspect_filter) : AnnounceHandler(aspect_filter) {}
virtual void received_announce(const RNS::Bytes& destination_hash, const RNS::Identity& announced_identity, const RNS::Bytes& app_data) {
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
RNS::info("ExampleAnnounceHandler: destination hash: " + destination_hash.toHex());
RNS::info("ExampleAnnounceHandler: destination hash: " + destination_hash.toHex());
if (app_data) {
RNS::info("ExampleAnnounceHandler: app data: " + app_data.toString());
}
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
};
// Test packet receive callback
void onPacket(const RNS::Bytes& data, const RNS::Packet& packet) { void onPacket(const RNS::Bytes& data, const RNS::Packet& packet) {
RNS::head("onPacket: data: " + data.toHex(), RNS::LOG_EXTREME); RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
RNS::head("onPacket: data string: \"" + data.toString() + "\"", RNS::LOG_EXTREME); RNS::head("onPacket: data: " + data.toHex(), RNS::LOG_INFO);
RNS::head("onPacket: data string: \"" + data.toString() + "\"", RNS::LOG_INFO);
//RNS::head("onPacket: " + packet.debugString(), RNS::LOG_EXTREME); //RNS::head("onPacket: " + packet.debugString(), RNS::LOG_EXTREME);
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
} }
void setup() { void setup() {
@ -202,11 +220,10 @@ void setup() {
destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL); destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL);
//zRNS::head("Registering announce handler with Transport...", RNS::LOG_EXTREME); RNS::head("Registering announce handler with Transport...", RNS::LOG_EXTREME);
//zannounce_handler = ExampleAnnounceHandler( RNS::HAnnounceHandler announce_handler(new ExampleAnnounceHandler("example_utilities.announcesample.fruits"));
//z aspect_filter="example_utilities.announcesample.fruits"; //ExampleAnnounceHandler announce_handler((const char*)"example_utilities.announcesample.fruits");
//z) RNS::Transport::register_announce_handler(announce_handler);
//zRNS::Transport.register_announce_handler(announce_handler);
RNS::head("Announcing destination...", RNS::LOG_EXTREME); RNS::head("Announcing destination...", RNS::LOG_EXTREME);
//destination.announce(RNS::bytesFromString(fruits[rand() % 7])); //destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
@ -216,7 +233,7 @@ void setup() {
destination.announce(RNS::bytesFromString(fruits[rand() % 7])); destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
// 23.9% (+0.8%) // 23.9% (+0.8%)
/**/ /*
// test data send packet // test data send packet
RNS::head("Creating send packet...", RNS::LOG_EXTREME); RNS::head("Creating send packet...", RNS::LOG_EXTREME);
RNS::Packet send_packet(destination, "The quick brown fox jumps over the lazy dog"); RNS::Packet send_packet(destination, "The quick brown fox jumps over the lazy dog");
@ -236,7 +253,16 @@ void setup() {
RNS::head("Spoofing recv packet to destination...", RNS::LOG_EXTREME); RNS::head("Spoofing recv packet to destination...", RNS::LOG_EXTREME);
destination.receive(recv_packet); destination.receive(recv_packet);
/**/ */
RNS::head("Deregistering announce handler with Transport...", RNS::LOG_EXTREME);
RNS::Transport::deregister_announce_handler(announce_handler);
RNS::head("Deregistering Interface instances with Transport...", RNS::LOG_EXTREME);
RNS::Transport::deregister_interface(loopinterface);
RNS::Transport::deregister_interface(ininterface);
RNS::Transport::deregister_interface(outinterface);
//RNS::Transport::deregister_interface(interface);
} }
catch (std::exception& e) { catch (std::exception& e) {