mirror of
https://github.com/markqvist/reticulum-cpp.git
synced 2024-10-01 02:55:46 -04:00
WIP: Collection optimizations and Transport
Tested and optimized collections used in Transport. Additional Transport implementation.
This commit is contained in:
parent
263f589801
commit
8d943318a6
@ -26,6 +26,22 @@ lib_deps =
|
||||
rweather/Crypto@^0.4.0
|
||||
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]
|
||||
platform = espressif32
|
||||
board = ttgo-t-beam
|
||||
|
@ -74,6 +74,26 @@ Destination::Destination(const Identity& identity, const directions direction, c
|
||||
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.
|
||||
*/
|
||||
|
@ -79,8 +79,10 @@ namespace RNS {
|
||||
}
|
||||
|
||||
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 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:
|
||||
//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::proof_strategies proof_strategy() const { assert(_object); return _object->_proof_strategy; }
|
||||
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 uint16_t mtu() const { assert(_object); return _object->_mtu; }
|
||||
inline void mtu(uint16_t mtu) { assert(_object); _object->_mtu = mtu; }
|
||||
|
227
src/Identity.cpp
227
src/Identity.cpp
@ -1,8 +1,10 @@
|
||||
#include "Identity.h"
|
||||
|
||||
#include "Reticulum.h"
|
||||
#include "Transport.h"
|
||||
#include "Packet.h"
|
||||
#include "Log.h"
|
||||
#include "Utilities/OS.h"
|
||||
#include "Cryptography/X25519.h"
|
||||
#include "Cryptography/HKDF.h"
|
||||
#include "Cryptography/Fernet.h"
|
||||
@ -12,6 +14,9 @@
|
||||
|
||||
using namespace RNS;
|
||||
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()) {
|
||||
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()));
|
||||
}
|
||||
|
||||
|
||||
void Identity::createKeys() {
|
||||
assert(_object);
|
||||
|
||||
@ -49,6 +53,215 @@ void Identity::createKeys() {
|
||||
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) {
|
||||
/*
|
||||
@ -132,7 +345,7 @@ Encrypts information for the identity.
|
||||
:returns: Ciphertext token as *bytes*.
|
||||
: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);
|
||||
debug("Identity::encrypt: encrypting data...");
|
||||
if (!_object->_pub) {
|
||||
@ -172,7 +385,7 @@ Decrypts information for the identity.
|
||||
:returns: Plaintext as *bytes*, or *None* if decryption fails.
|
||||
: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);
|
||||
debug("Identity::decrypt: decrypting data...");
|
||||
if (!_object->_prv) {
|
||||
@ -226,7 +439,7 @@ Signs information by the identity.
|
||||
:returns: Signature as *bytes*.
|
||||
: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);
|
||||
if (!_object->_sig_prv) {
|
||||
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.
|
||||
: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);
|
||||
if (_object->_pub) {
|
||||
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);
|
||||
Bytes signature(sign(packet.packet_hash()));
|
||||
Bytes proof_data;
|
||||
@ -283,6 +496,6 @@ void Identity::prove(const Packet& packet, const Destination& destination /*= {T
|
||||
proof.send();
|
||||
}
|
||||
|
||||
void Identity::prove(const Packet& packet) {
|
||||
void Identity::prove(const Packet& packet) const {
|
||||
prove(packet, {Type::NONE});
|
||||
}
|
||||
|
@ -8,9 +8,9 @@
|
||||
#include "Cryptography/X25519.h"
|
||||
#include "Cryptography/Fernet.h"
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace RNS {
|
||||
|
||||
@ -19,6 +19,23 @@ namespace RNS {
|
||||
|
||||
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:
|
||||
Identity(Type::NoneConstructor none) {
|
||||
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:
|
||||
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*
|
||||
*/
|
||||
inline const Bytes get_public_key() {
|
||||
inline const Bytes get_public_key() const {
|
||||
assert(_object);
|
||||
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() {
|
||||
assert(_object);
|
||||
_object->_hash = truncated_hash(get_public_key());
|
||||
debug("Identity::update_hashes: hash: " + _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.
|
||||
|
||||
@ -75,7 +120,7 @@ namespace RNS {
|
||||
:returns: Truncated SHA-256 hash as *bytes*
|
||||
*/
|
||||
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);
|
||||
}
|
||||
/*
|
||||
@ -90,24 +135,14 @@ namespace RNS {
|
||||
|
||||
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
|
||||
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& encryptionPublicKey() const { assert(_object); return _object->_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& 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 toString() const { assert(_object); return "{Identity:" + _object->_hash.toHex() + "}"; }
|
||||
@ -134,10 +169,14 @@ namespace RNS {
|
||||
Bytes _hash;
|
||||
std::string _hexhash;
|
||||
|
||||
Bytes _app_data;
|
||||
|
||||
friend class Identity;
|
||||
};
|
||||
std::shared_ptr<Object> _object;
|
||||
|
||||
static std::map<Bytes, IdentityEntry> _known_destinations;
|
||||
|
||||
};
|
||||
|
||||
}
|
23
src/Packet.h
23
src/Packet.h
@ -129,8 +129,27 @@ namespace RNS {
|
||||
Packet(const Packet& packet) : _object(packet._object) {
|
||||
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(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) {}
|
||||
Packet(
|
||||
const Destination& destination,
|
||||
const Interface& attached_interface,
|
||||
const Bytes& data,
|
||||
Type::Packet::types packet_type = Type::Packet::DATA,
|
||||
Type::Packet::context_types context = Type::Packet::CONTEXT_NONE,
|
||||
Type::Transport::types transport_type = Type::Transport::BROADCAST,
|
||||
Type::Packet::header_types header_type = Type::Packet::HEADER_1,
|
||||
const Bytes& transport_id = {Bytes::NONE},
|
||||
bool create_receipt = true
|
||||
);
|
||||
Packet(
|
||||
const Destination& destination,
|
||||
const Bytes& data,
|
||||
Type::Packet::types packet_type = Type::Packet::DATA,
|
||||
Type::Packet::context_types context = Type::Packet::CONTEXT_NONE,
|
||||
Type::Transport::types transport_type = Type::Transport::BROADCAST,
|
||||
Type::Packet::header_types header_type = Type::Packet::HEADER_1,
|
||||
const Bytes& transport_id = {Bytes::NONE},
|
||||
bool create_receipt = true
|
||||
) : Packet(destination, {Type::NONE}, data, packet_type, context, transport_type, header_type, transport_id, create_receipt) {}
|
||||
virtual ~Packet();
|
||||
|
||||
inline Packet& operator = (const Packet& packet) {
|
||||
|
@ -14,11 +14,22 @@
|
||||
#include <time.h>
|
||||
|
||||
using namespace RNS;
|
||||
using namespace RNS::Type::Transport;
|
||||
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<Interface>, std::less<Interface>> Transport::_interfaces;
|
||||
#elif defined(INTERFACES_LIST)
|
||||
/*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;
|
||||
#elif defined(DESTINATIONS_MAP)
|
||||
/*static*/ std::map<Bytes, Destination> Transport::_destinations;
|
||||
#endif
|
||||
/*static*/ std::set<Link> Transport::_pending_links;
|
||||
/*static*/ std::set<Link> Transport::_active_links;
|
||||
/*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<Bytes> Transport::_path_requests;
|
||||
|
||||
/*static*/ std::map<Bytes, Transport::PathRequestEntry> Transport::_discovery_path_requests;
|
||||
/*static*/ uint16_t Transport::_max_pr_taXgxs = 32000;
|
||||
|
||||
/*static*/ std::set<Destination> Transport::_control_destinations;
|
||||
/*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;
|
||||
|
||||
@ -714,7 +729,13 @@ using namespace RNS::Utilities;
|
||||
else {
|
||||
extreme("Transport::outbound: Path to destination is unknown");
|
||||
bool stored_hash = false;
|
||||
#if defined(INTERFACES_SET)
|
||||
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());
|
||||
if (interface.OUT()) {
|
||||
bool should_transmit = true;
|
||||
@ -743,6 +764,7 @@ using namespace RNS::Utilities;
|
||||
else if (interface.mode() == Type::Interface::MODE_ROAMING) {
|
||||
//local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None)
|
||||
//Destination local_destination({Type::NONE});
|
||||
#if defined(DESTINATIONS_SET)
|
||||
bool found_local = false;
|
||||
for (auto& destination : _destinations) {
|
||||
if (destination.hash() == packet.destination_hash()) {
|
||||
@ -754,6 +776,13 @@ using namespace RNS::Utilities;
|
||||
//if local_destination != None:
|
||||
//if (local_destination) {
|
||||
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");
|
||||
}
|
||||
else {
|
||||
@ -786,6 +815,7 @@ using namespace RNS::Utilities;
|
||||
// next(iterable, default)
|
||||
// list comprehension: [x for x in xyz if x in a]
|
||||
// CBA TODO confirm that above pattern just selects the first matching destination
|
||||
#if defined(DESTINATIONS_SET)
|
||||
//Destination local_destination({Typeestination::NONE});
|
||||
bool found_local = false;
|
||||
for (auto& destination : _destinations) {
|
||||
@ -798,6 +828,10 @@ using namespace RNS::Utilities;
|
||||
//if local_destination != None:
|
||||
//if (local_destination) {
|
||||
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");
|
||||
}
|
||||
else {
|
||||
@ -840,7 +874,11 @@ using namespace RNS::Utilities;
|
||||
if (!queued_announces && outbound_time > interface.announce_allowed_at()) {
|
||||
uint16_t tx_time = (packet.raw().size() * 8) / interface.bitrate();
|
||||
uint16_t wait_time = (tx_time / interface.announce_cap());
|
||||
#if defined(INTERFACES_SET)
|
||||
const_cast<Interface&>(interface).announce_allowed_at(outbound_time + wait_time);
|
||||
#else
|
||||
interface.announce_allowed_at(outbound_time + wait_time);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
should_transmit = false;
|
||||
@ -869,7 +907,11 @@ using namespace RNS::Utilities;
|
||||
);
|
||||
|
||||
queued_announces = (interface.announce_queue().size() > 0);
|
||||
#if defined(INTERFACES_SET)
|
||||
const_cast<Interface&>(interface).add_announce(entry);
|
||||
#else
|
||||
interface.add_announce(entry);
|
||||
#endif
|
||||
|
||||
if (!queued_announces) {
|
||||
uint64_t wait_time = std::max(interface.announce_allowed_at() - OS::time(), (uint64_t)0);
|
||||
@ -925,12 +967,16 @@ using namespace RNS::Utilities;
|
||||
|
||||
// TODO: Re-evaluate potential for blocking
|
||||
// def send_packet():
|
||||
// Transport.transmit(const_cast<Interface&>(interface), packet.raw)
|
||||
// Transport.transmit(interface, packet.raw)
|
||||
// thread = threading.Thread(target=send_packet)
|
||||
// thread.daemon = True
|
||||
// thread.start()
|
||||
|
||||
#if defined(INTERFACES_SET)
|
||||
transmit(const_cast<Interface&>(interface), packet.raw());
|
||||
#else
|
||||
transmit(interface, packet.raw());
|
||||
#endif
|
||||
sent = true;
|
||||
}
|
||||
else {
|
||||
@ -1214,17 +1260,27 @@ using namespace RNS::Utilities;
|
||||
if (packet.destination_type() == Type::Destination::PLAIN && packet.transport_type() == Type::Transport::BROADCAST) {
|
||||
// Send to all interfaces except the originator
|
||||
if (from_local_client) {
|
||||
#if defined(INTERFACES_SET)
|
||||
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()) {
|
||||
extreme("Transport::inbound: Broadcasting packet on " + interface.toString());
|
||||
#if defined(INTERFACES_SET)
|
||||
transmit(const_cast<Interface&>(interface), packet.raw());
|
||||
#else
|
||||
transmit(interface, packet.raw());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the packet was not from a local client, send
|
||||
// it directly to all local clients
|
||||
else {
|
||||
for (auto& interface : _local_client_interfaces) {
|
||||
for (const Interface& interface : _local_client_interfaces) {
|
||||
extreme("Transport::inbound: Broadcasting packet on " + interface.toString());
|
||||
transmit(const_cast<Interface&>(interface), packet.raw());
|
||||
}
|
||||
@ -1329,7 +1385,11 @@ using namespace RNS::Utilities;
|
||||
);
|
||||
_reverse_table.insert({packet.getTruncatedHash(), reverse_entry});
|
||||
}
|
||||
#if defined(INTERFACES_SET)
|
||||
transmit(const_cast<Interface&>(outbound_interface), new_raw);
|
||||
#else
|
||||
transmit(outbound_interface, new_raw);
|
||||
#endif
|
||||
destination_entry._timestamp = OS::time();
|
||||
}
|
||||
else {
|
||||
@ -1401,6 +1461,7 @@ using namespace RNS::Utilities;
|
||||
extreme("Transport::inbound: Packet is ANNOUNCE");
|
||||
Bytes received_from;
|
||||
//p local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None)
|
||||
#if defined(DESTINATIONS_SET)
|
||||
//Destination local_destination({Type::NONE});
|
||||
bool found_local = false;
|
||||
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 && 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...");
|
||||
if (packet.transport_id()) {
|
||||
received_from = packet.transport_id();
|
||||
@ -1427,7 +1492,7 @@ using namespace RNS::Utilities;
|
||||
if ((packet.hops() - 1) == announce_entry._hops) {
|
||||
debug("Heard a local rebroadcast of announce for " + packet.destination_hash().toHex());
|
||||
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");
|
||||
_announce_table.erase(packet.destination_hash());
|
||||
}
|
||||
@ -1453,6 +1518,7 @@ using namespace RNS::Utilities;
|
||||
// First, check that the announce is not for a destination
|
||||
// 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 defined(DESTINATIONS_SET)
|
||||
bool found_local = false;
|
||||
for (auto& destination : _destinations) {
|
||||
if (destination.hash() == packet.destination_hash()) {
|
||||
@ -1460,18 +1526,24 @@ using namespace RNS::Utilities;
|
||||
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...");
|
||||
/*
|
||||
uint64_t announce_emitted = Transport::announce_emitted(packet);
|
||||
|
||||
//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);
|
||||
//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());
|
||||
if (iter != _destination_table.end()) {
|
||||
DestinationEntry destination_entry = (*iter).second;
|
||||
//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
|
||||
// destination, but the hop count is equal or
|
||||
@ -1483,7 +1555,7 @@ using namespace RNS::Utilities;
|
||||
// TODO: Check whether this approach works
|
||||
// under all circumstances
|
||||
//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;
|
||||
}
|
||||
else {
|
||||
@ -1499,9 +1571,9 @@ using namespace RNS::Utilities;
|
||||
uint64_t path_expires = destination_entry._expires;
|
||||
|
||||
uint64_t path_announce_emitted = 0;
|
||||
for (const Bytes& path_random_blob : destination_entry._random_blobs) {
|
||||
//path_announce_emitted = std::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"))
|
||||
for (const Bytes& path_random_blob : random_blobs) {
|
||||
//p path_announce_emitted = 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) {
|
||||
break;
|
||||
}
|
||||
@ -1511,7 +1583,7 @@ using namespace RNS::Utilities;
|
||||
// We also check that the announce is
|
||||
// different from ones we've already heard,
|
||||
// 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
|
||||
// works under all circumstances
|
||||
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 {
|
||||
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");
|
||||
should_add = true;
|
||||
}
|
||||
@ -1534,7 +1606,6 @@ using namespace RNS::Utilities;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// If this destination is unknown in our table
|
||||
// we should add it
|
||||
@ -1546,7 +1617,7 @@ using namespace RNS::Utilities;
|
||||
|
||||
bool rate_blocked = false;
|
||||
|
||||
|
||||
/*
|
||||
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:
|
||||
rate_entry = { "last": now, "rate_violations": 0, "blocked_until": 0, "timestamps": [now]}
|
||||
@ -1579,7 +1650,7 @@ using namespace RNS::Utilities;
|
||||
|
||||
else:
|
||||
rate_blocked = True
|
||||
|
||||
*/
|
||||
|
||||
uint8_t retries = 0;
|
||||
uint8_t announce_hops = packet.hops();
|
||||
@ -1587,36 +1658,35 @@ using namespace RNS::Utilities;
|
||||
bool block_rebroadcasts = false;
|
||||
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;
|
||||
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) {
|
||||
expires = now + Transport::ROAMING_PATH_TIME;
|
||||
expires = now + ROAMING_PATH_TIME;
|
||||
}
|
||||
else {
|
||||
expires = now + Transport::PATHFINDER_E;
|
||||
expires = now + PATHFINDER_E;
|
||||
}
|
||||
|
||||
std::set<Bytes> random_blobs;
|
||||
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
|
||||
|
||||
if (rate_blocked) {
|
||||
debug("Blocking rebroadcast of announce from " + packet.destination_hash().toHex() + " due to excessive announce rate");
|
||||
}
|
||||
else {
|
||||
if (from_local_client(packet)) {
|
||||
if (Transport::from_local_client(packet)) {
|
||||
// If the announce is from a local client,
|
||||
// it is announced immediately, but only one time.
|
||||
retransmit_timeout = now;
|
||||
retries = Transport::PATHFINDER_R;
|
||||
retries = PATHFINDER_R;
|
||||
}
|
||||
_announce_table[packet.destination_hash] = [
|
||||
AnnounceEntry announce_entry(
|
||||
now,
|
||||
retransmit_timeout,
|
||||
retries,
|
||||
@ -1626,23 +1696,24 @@ using namespace RNS::Utilities;
|
||||
local_rebroadcasts,
|
||||
block_rebroadcasts,
|
||||
attached_interface
|
||||
];
|
||||
);
|
||||
_announce_table.insert({packet.destination_hash(), announce_entry});
|
||||
}
|
||||
}
|
||||
// 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,
|
||||
// check if any external interfaces have pending
|
||||
// path requests.
|
||||
//p if packet.destination_hash in Transport.pending_local_path_requests:
|
||||
auto iter = pending_local_path_requests.find(packet.destination_hash());
|
||||
if (iter != _destination_table.end()) {
|
||||
DestinationEntry destination_entry = (*iter).second;
|
||||
desiring_interface = _pending_local_path_requests.pop(packet.destination_hash());
|
||||
auto iter = _pending_local_path_requests.find(packet.destination_hash());
|
||||
if (iter != _pending_local_path_requests.end()) {
|
||||
//p desiring_interface = Transport.pending_local_path_requests.pop(packet.destination_hash)
|
||||
//const Interface& desiring_interface = (*iter).second;
|
||||
retransmit_timeout = now;
|
||||
retries = Transport::PATHFINDER_R;
|
||||
retries = PATHFINDER_R;
|
||||
|
||||
Transport.announce_table[packet.destination_hash] = [
|
||||
AnnounceEntry announce_entry(
|
||||
now,
|
||||
retransmit_timeout,
|
||||
retries,
|
||||
@ -1652,50 +1723,53 @@ using namespace RNS::Utilities;
|
||||
local_rebroadcasts,
|
||||
block_rebroadcasts,
|
||||
attached_interface
|
||||
];
|
||||
);
|
||||
_announce_table.insert({packet.destination_hash(), announce_entry});
|
||||
}
|
||||
}
|
||||
|
||||
// If we have any local clients connected, we re-
|
||||
// transmit the announce to them immediately
|
||||
if (_local_client_interfaces.size() > 0) {
|
||||
announce_identity = Identity::recall(packet.destination_hash());
|
||||
announce_destination = Destination(announce_identity, Destination.OUT, Destination.SINGLE, "unknown", "unknown");
|
||||
Identity announce_identity(Identity::recall(packet.destination_hash()));
|
||||
Destination announce_destination(announce_identity, Type::Destination::OUT, Type::Destination::SINGLE, "unknown", "unknown");
|
||||
announce_destination.hash(packet.destination_hash());
|
||||
announce_destination.hexhash = announce_destination.hash().toHex();
|
||||
announce_context = {Type::NONE};
|
||||
announce_data = packet.data();
|
||||
//announce_destination.hexhash(announce_destination.hash().toHex());
|
||||
Type::Packet::context_types announce_context = Type::Packet::CONTEXT_NONE;
|
||||
Bytes announce_data = packet.data();
|
||||
|
||||
// TODO: Shouldn't the context be PATH_RESPONSE in the first case here?
|
||||
if (from_local_client(packet) && packet.context() == Packet.PATH_RESPONSE) {
|
||||
for (auto& local_interface : _local_client_interfaces) {
|
||||
if packet.receiving_interface() != local_interface) {
|
||||
if (Transport::from_local_client(packet) && packet.context() == Type::Packet::PATH_RESPONSE) {
|
||||
for (const Interface& local_interface : _local_client_interfaces) {
|
||||
if (packet.receiving_interface() != local_interface) {
|
||||
Packet new_announce(
|
||||
announce_destination,
|
||||
local_interface,
|
||||
announce_data,
|
||||
Type::Packet::ANNOUNCE,
|
||||
context = announce_context,
|
||||
header_type = RNS.Packet.HEADER_2,
|
||||
transport_type = Transport.TRANSPORT,
|
||||
transport_id = Transport.identity.hash,
|
||||
attached_interface = local_interface
|
||||
announce_context,
|
||||
Type::Transport::TRANSPORT,
|
||||
Type::Packet::HEADER_2,
|
||||
_identity.hash()
|
||||
);
|
||||
|
||||
new_announce.hops(packet.hops);
|
||||
new_announce.hops(packet.hops());
|
||||
new_announce.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto& local_interface : _local_client_interfaces) {
|
||||
for (const Interface& local_interface : _local_client_interfaces) {
|
||||
if (packet.receiving_interface() != local_interface) {
|
||||
Packet new_announce(
|
||||
announce_destination,
|
||||
local_interface,
|
||||
announce_data,
|
||||
Type::Packet::ANNOUNCE,
|
||||
context = announce_context,
|
||||
header_type = RNS.Packet.HEADER_2,
|
||||
transport_type = Transport.TRANSPORT,
|
||||
transport_id = Transport.identity.hash,
|
||||
attached_interface = local_interface
|
||||
announce_context,
|
||||
Type::Transport::TRANSPORT,
|
||||
Type::Packet::HEADER_2,
|
||||
_identity.hash()
|
||||
);
|
||||
|
||||
new_announce.hops(packet.hops());
|
||||
@ -1710,28 +1784,26 @@ using namespace RNS::Utilities;
|
||||
// interface immediately
|
||||
auto iter = _discovery_path_requests.find(packet.destination_hash());
|
||||
if (iter != _discovery_path_requests.end()) {
|
||||
PathRequestEntry pr_entry = (*iter).second;
|
||||
PathRequestEntry& pr_entry = (*iter).second;
|
||||
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() + interface_str);
|
||||
announce_identity = Identity::recall(packet.destination_hash());
|
||||
Destination announce_destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown");
|
||||
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()));
|
||||
Destination announce_destination(announce_identity, Type::Destination::OUT, Type::Destination::SINGLE, "unknown", "unknown");
|
||||
announce_destination.hash(packet.destination_hash());
|
||||
announce_destination.hexhash = announce_destination.hash().toHex();
|
||||
announce_context = {Type::NONE};
|
||||
announce_data = packet.data();
|
||||
//announce_destination.hexhash(announce_destination.hash().toHex());
|
||||
Type::Packet::context_types announce_context = Type::Packet::CONTEXT_NONE;
|
||||
Bytes announce_data = packet.data();
|
||||
|
||||
Packet new_announce(
|
||||
announce_destination,
|
||||
attached_interface,
|
||||
announce_data,
|
||||
Type::Packet::ANNOUNCE,
|
||||
context = Type::Packet::PATH_RESPONSE,
|
||||
header_type = Type::Packet::HEADER_2,
|
||||
transport_type = Type::Transport::TRANSPORT,
|
||||
transport_id = _identity.hash(),
|
||||
attached_interface = attached_interface
|
||||
Type::Packet::PATH_RESPONSE,
|
||||
Type::Transport::TRANSPORT,
|
||||
Type::Packet::HEADER_2,
|
||||
_identity.hash()
|
||||
);
|
||||
|
||||
new_announce.hops(packet.hops());
|
||||
@ -1744,59 +1816,62 @@ using namespace RNS::Utilities;
|
||||
announce_hops,
|
||||
expires,
|
||||
random_blobs,
|
||||
packet.receiving_interface(),
|
||||
//packet.receiving_interface(),
|
||||
const_cast<Interface&>(packet.receiving_interface()),
|
||||
packet
|
||||
);
|
||||
_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());
|
||||
|
||||
/*
|
||||
// If the receiving interface is a tunnel, we add the
|
||||
// announce to the tunnels table
|
||||
if (packet.receiving_interface().tunnel_id()) {
|
||||
tunnel_entry = Transport.tunnels[packet.receiving_interface.tunnel_id];
|
||||
paths = tunnel_entry[2]
|
||||
paths[packet.destination_hash] = destination_table_entry
|
||||
paths = tunnel_entry[2];
|
||||
paths[packet.destination_hash] = destination_table_entry;
|
||||
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());
|
||||
}
|
||||
*/
|
||||
|
||||
// Call externally registered callbacks from apps
|
||||
// wanting to know when an announce arrives
|
||||
if (packet.context() != Type::Packet::PATH_RESPONSE) {
|
||||
for (auto& handler : Transport.announce_handlers) {
|
||||
for (auto& handler : _announce_handlers) {
|
||||
try {
|
||||
// Check that the announced destination matches
|
||||
// the handlers aspect filter
|
||||
execute_callback = false;
|
||||
announce_identity = Identity::recall(packet.destination_hash());
|
||||
if (handler.aspect_filter == None) {
|
||||
bool execute_callback = false;
|
||||
Identity announce_identity(Identity::recall(packet.destination_hash()));
|
||||
if (handler->aspect_filter().empty()) {
|
||||
// If the handlers aspect filter is set to
|
||||
// None, we execute the callback in all cases
|
||||
execute_callback = true;
|
||||
}
|
||||
else {
|
||||
handler_expected_hash = RNS.Destination.hash_from_name_and_identity(handler.aspect_filter, announce_identity)
|
||||
if (packet.destination_hash() == handler_expected_hash() ) {
|
||||
Bytes handler_expected_hash = Destination::hash_from_name_and_identity(handler->aspect_filter().c_str(), announce_identity);
|
||||
if (packet.destination_hash() == handler_expected_hash) {
|
||||
execute_callback = true;
|
||||
}
|
||||
}
|
||||
if (execute_callback) {
|
||||
handler.received_announce(
|
||||
destination_hash=packet.destination_hash(),
|
||||
announced_identity=announce_identity,
|
||||
app_data=Identity::recall_app_data(packet.destination_hash())
|
||||
handler->received_announce(
|
||||
packet.destination_hash(),
|
||||
announce_identity,
|
||||
Identity::recall_app_data(packet.destination_hash())
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
error("Error while processing external announce callback.");
|
||||
error("The contained exception was: " + e.what();
|
||||
error("The contained exception was: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
else {
|
||||
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) {
|
||||
extreme("Transport::inbound: Packet is LINKREQUEST");
|
||||
if (!packet.transport_id() || packet.transport_id() == _identity.hash()) {
|
||||
#if defined(DESTINATIONS_SET)
|
||||
for (auto& destination : _destinations) {
|
||||
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);
|
||||
// CBA iterator over std::set is always const so need to make temporarily mutable
|
||||
//destination.receive(packet);
|
||||
#if defined(DESTINATIONS_SET)
|
||||
const_cast<Destination&>(destination).receive(packet);
|
||||
#else
|
||||
destination.receive(packet);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1834,10 +1920,21 @@ using namespace RNS::Utilities;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if defined(DESTINATIONS_SET)
|
||||
for (auto& destination : _destinations) {
|
||||
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);
|
||||
#if defined(DESTINATIONS_SET)
|
||||
const_cast<Destination&>(destination).receive(packet);
|
||||
#else
|
||||
destination.receive(packet);
|
||||
#endif
|
||||
|
||||
if (destination.proof_strategy() == Type::Destination::PROVE_ALL) {
|
||||
packet.prove();
|
||||
@ -2057,31 +2154,54 @@ using namespace RNS::Utilities;
|
||||
|
||||
/*static*/ void Transport::register_interface(Interface& interface) {
|
||||
extreme("Transport: Registering interface " + interface.toString());
|
||||
#if defined(INTERFACES_SET)
|
||||
_interfaces.insert(interface);
|
||||
#elif defined(INTERFACES_LIST)
|
||||
_interfaces.push_back(interface);
|
||||
extreme("Transport: Listing all registered interfaces...");
|
||||
for (Interface& found_interface : _interfaces) {
|
||||
extreme("Transport: Found interface " + found_interface.toString());
|
||||
}
|
||||
#elif defined(INTERFACES_MAP)
|
||||
_interfaces.insert({interface.get_hash(), interface});
|
||||
#endif
|
||||
// CBA TODO set or add transport as listener on interface to receive incoming packets
|
||||
}
|
||||
|
||||
/*static*/ void Transport::deregister_interface(const Interface& interface) {
|
||||
extreme("Transport: Deregistering interface " + interface.toString());
|
||||
//if (_interfaces.find(interface) != _interfaces.end()) {
|
||||
// _interfaces.erase(interface);
|
||||
#if defined(INTERFACES_SET)
|
||||
//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) {
|
||||
if ((*iter).get() == interface) {
|
||||
_interfaces.erase(iter);
|
||||
extreme("Transport::deregister_interface: Found and removed interface " + (*iter).get().toString());
|
||||
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) {
|
||||
extreme("Transport: Registering destination " + destination.toString());
|
||||
destination.mtu(Type::Reticulum::MTU);
|
||||
if (destination.direction() == Type::Destination::IN) {
|
||||
#if defined(DESTINATIONS_SET)
|
||||
for (auto& registered_destination : _destinations) {
|
||||
if (destination.hash() == registered_destination.hash()) {
|
||||
//raise KeyError("Attempt to register an already registered destination.")
|
||||
@ -2090,6 +2210,15 @@ using namespace RNS::Utilities;
|
||||
}
|
||||
|
||||
_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 (destination.type() == Type::Destination::SINGLE) {
|
||||
@ -2101,9 +2230,16 @@ using namespace RNS::Utilities;
|
||||
|
||||
/*static*/ void Transport::deregister_destination(const Destination& destination) {
|
||||
extreme("Transport: Deregistering destination " + destination.toString());
|
||||
#if defined(DESTINATIONS_SET)
|
||||
if (_destinations.find(destination) != _destinations.end()) {
|
||||
_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) {
|
||||
@ -2141,9 +2277,7 @@ 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.
|
||||
*/
|
||||
/*static*/ void Transport::register_announce_handler(HAnnounceHandler handler) {
|
||||
extreme("Transport: Transport::register_announce_handler()");
|
||||
//if hasattr(handler, "received_announce") and callable(handler.received_announce):
|
||||
//if hasattr(handler, "aspect_filter"):
|
||||
extreme("Transport: Registering announce handler " + handler->aspect_filter());
|
||||
_announce_handlers.insert(handler);
|
||||
}
|
||||
|
||||
@ -2153,18 +2287,32 @@ Deregisters an announce handler.
|
||||
:param handler: The announce handler to be deregistered.
|
||||
*/
|
||||
/*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()) {
|
||||
_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) {
|
||||
#if defined(INTERFACES_SET)
|
||||
for (const Interface& interface : _interfaces) {
|
||||
if (interface.get_hash() == interface_hash) {
|
||||
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};
|
||||
}
|
||||
@ -2299,7 +2447,7 @@ Deregisters an announce handler.
|
||||
return destination_entry._hops;
|
||||
}
|
||||
else {
|
||||
return Transport::PATHFINDER_M;
|
||||
return PATHFINDER_M;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2479,6 +2627,7 @@ will announce it.
|
||||
Transport.pending_local_path_requests[destination_hash] = attached_interface
|
||||
|
||||
//local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None)
|
||||
#if defined(DESTINATIONS_SET)
|
||||
Destination local_destination({Type::NONE});
|
||||
for (auto& destination : _destinations) {
|
||||
if (destination.hash() == destination_hash) {
|
||||
@ -2488,11 +2637,15 @@ will announce it.
|
||||
}
|
||||
//if local_destination != None:
|
||||
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);
|
||||
debug("Answering path request for " + destination_hash.toHex() + interface_str + ", destination is local to this system");
|
||||
}
|
||||
|
||||
elif (RNS.Reticulum.transport_enabled() or is_from_local_client) and (destination_hash in Transport.destination_table):
|
||||
else if ((RNS.Reticulum.transport_enabled() || is_from_local_client) && destination_table.find(destination_hash) != _destination_table.ends()) {
|
||||
packet = Transport.destination_table[destination_hash][6]
|
||||
next_hop = Transport.destination_table[destination_hash][1]
|
||||
received_from = Transport.destination_table[destination_hash][5]
|
||||
@ -2892,3 +3045,20 @@ will announce it.
|
||||
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};
|
||||
}
|
||||
|
110
src/Transport.h
110
src/Transport.h
@ -11,6 +11,13 @@
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
|
||||
//#define INTERFACES_SET
|
||||
//#define INTERFACES_LIST
|
||||
#define INTERFACES_MAP
|
||||
|
||||
//#define DESTINATIONS_SET
|
||||
#define DESTINATIONS_MAP
|
||||
|
||||
namespace RNS {
|
||||
|
||||
class Reticulum;
|
||||
@ -23,10 +30,18 @@ namespace RNS {
|
||||
|
||||
class AnnounceHandler {
|
||||
public:
|
||||
AnnounceHandler(const std::string& aspect_filter) {
|
||||
_aspect_filter = aspect_filter;
|
||||
}
|
||||
// The initialisation method takes the optional
|
||||
// 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;
|
||||
std::string& aspect_filter() { return _aspect_filter; }
|
||||
private:
|
||||
std::string _aspect_filter;
|
||||
};
|
||||
@ -39,9 +54,11 @@ namespace RNS {
|
||||
class Transport {
|
||||
|
||||
private:
|
||||
// CBA TODO Analyze safety of using Inrerface references here
|
||||
// CBA TODO Analyze safety of using Packet references here
|
||||
class DestinationEntry {
|
||||
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),
|
||||
_received_from(received_from),
|
||||
_hops(announce_hops),
|
||||
@ -61,9 +78,11 @@ namespace RNS {
|
||||
const Packet& _packet;
|
||||
};
|
||||
|
||||
// CBA TODO Analyze safety of using Inrerface references here
|
||||
// CBA TODO Analyze safety of using Packet references here
|
||||
class AnnounceEntry {
|
||||
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),
|
||||
_retransmit_timeout(retransmit_timeout),
|
||||
_retries(retries),
|
||||
@ -87,6 +106,7 @@ namespace RNS {
|
||||
const Interface& _attached_interface;
|
||||
};
|
||||
|
||||
// CBA TODO Analyze safety of using Inrerface references here
|
||||
class LinkEntry {
|
||||
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) :
|
||||
@ -113,6 +133,7 @@ namespace RNS {
|
||||
uint64_t _proof_timeout = 0;
|
||||
};
|
||||
|
||||
// CBA TODO Analyze safety of using Inrerface references here
|
||||
class ReverseEntry {
|
||||
public:
|
||||
ReverseEntry(const Interface& receiving_interface, const Interface& outbound_interface, uint64_t timestamp) :
|
||||
@ -127,50 +148,20 @@ namespace RNS {
|
||||
uint64_t _timestamp = 0;
|
||||
};
|
||||
|
||||
// CBA TODO Analyze safety of using Inrerface references here
|
||||
class PathRequestEntry {
|
||||
public:
|
||||
// Constants
|
||||
/*
|
||||
enum types {
|
||||
BROADCAST = 0x00,
|
||||
TRANSPORT = 0x01,
|
||||
RELAY = 0x02,
|
||||
TUNNEL = 0x03,
|
||||
NONE = 0xFF,
|
||||
PathRequestEntry(const Bytes& destination_hash, uint64_t timeout, const Interface& requesting_interface) :
|
||||
_destination_hash(destination_hash),
|
||||
_timeout(timeout),
|
||||
_requesting_interface(requesting_interface)
|
||||
{
|
||||
}
|
||||
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:
|
||||
static void start(const Reticulum& reticulum_instance);
|
||||
@ -223,12 +214,26 @@ namespace RNS {
|
||||
static void persist_data();
|
||||
static void exit_handler();
|
||||
|
||||
static Destination find_destination_from_hash(const Bytes& destination_hash);
|
||||
|
||||
private:
|
||||
// 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<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
|
||||
#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::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> _active_links; // Links that are active
|
||||
static std::set<Bytes> _packet_hashlist; // A list of packet hashes for duplicate detection
|
||||
@ -248,7 +253,7 @@ namespace RNS {
|
||||
//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
|
||||
|
||||
//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
|
||||
static uint16_t _max_pr_taXgxs; // Maximum amount of unique path request tags to remember
|
||||
|
||||
@ -260,14 +265,15 @@ namespace RNS {
|
||||
// Interfaces for communicating with
|
||||
// local clients connected to a shared
|
||||
// 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;
|
||||
|
||||
static std::map<Bytes, const Interface&> _pending_local_path_requests;
|
||||
|
||||
//z _local_client_rssi_cache = []
|
||||
//z _local_client_snr_cache = []
|
||||
static uint16_t _LOCAL_CLIENT_CACHE_MAXSIZE;
|
||||
|
||||
std::map<Bytes, Interface> _pending_local_path_requests;
|
||||
|
||||
static uint64_t _start_time;
|
||||
static bool _jobs_locked;
|
||||
static bool _jobs_running;
|
||||
|
46
src/main.cpp
46
src/main.cpp
@ -115,16 +115,34 @@ public:
|
||||
name("(deleted)");
|
||||
}
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
RNS::head("onPacket: data: " + data.toHex(), RNS::LOG_EXTREME);
|
||||
RNS::head("onPacket: data string: \"" + data.toString() + "\"", RNS::LOG_EXTREME);
|
||||
RNS::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
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::info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
}
|
||||
|
||||
void setup() {
|
||||
@ -202,11 +220,10 @@ void setup() {
|
||||
|
||||
destination.set_proof_strategy(RNS::Type::Destination::PROVE_ALL);
|
||||
|
||||
//zRNS::head("Registering announce handler with Transport...", RNS::LOG_EXTREME);
|
||||
//zannounce_handler = ExampleAnnounceHandler(
|
||||
//z aspect_filter="example_utilities.announcesample.fruits";
|
||||
//z)
|
||||
//zRNS::Transport.register_announce_handler(announce_handler);
|
||||
RNS::head("Registering announce handler with Transport...", RNS::LOG_EXTREME);
|
||||
RNS::HAnnounceHandler announce_handler(new ExampleAnnounceHandler("example_utilities.announcesample.fruits"));
|
||||
//ExampleAnnounceHandler announce_handler((const char*)"example_utilities.announcesample.fruits");
|
||||
RNS::Transport::register_announce_handler(announce_handler);
|
||||
|
||||
RNS::head("Announcing destination...", RNS::LOG_EXTREME);
|
||||
//destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
|
||||
@ -216,7 +233,7 @@ void setup() {
|
||||
destination.announce(RNS::bytesFromString(fruits[rand() % 7]));
|
||||
// 23.9% (+0.8%)
|
||||
|
||||
/**/
|
||||
/*
|
||||
// test data send packet
|
||||
RNS::head("Creating send packet...", RNS::LOG_EXTREME);
|
||||
RNS::Packet send_packet(destination, "The quick brown fox jumps over the lazy dog");
|
||||
@ -236,7 +253,16 @@ void setup() {
|
||||
|
||||
RNS::head("Spoofing recv packet to destination...", RNS::LOG_EXTREME);
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user